├── CMakeLists.txt ├── COPYING ├── ChangeLog ├── Ck.cpp ├── Ck.h ├── INSTALL ├── PAM.cpp ├── PAM.h ├── README ├── THEMES ├── TODO ├── app.cpp ├── app.h ├── cfg.cpp ├── cfg.h ├── cmake └── modules │ ├── FONTCONFIGConfig.cmake │ ├── FindCkConnector.cmake │ ├── FindDBus.cmake │ └── FindPAM.cmake ├── const.h ├── image.cpp ├── image.h ├── jpeg.c ├── log.cpp ├── log.h ├── main.cpp ├── numlock.cpp ├── numlock.h ├── pam.sample ├── panel.cpp ├── panel.h ├── png.c ├── slim.1 ├── slim.conf ├── slim.service ├── slimlock.1 ├── slimlock.conf ├── slimlock.cpp ├── slimlock.pam ├── switchuser.cpp ├── switchuser.h ├── themes ├── CMakeLists.txt └── default │ ├── CMakeLists.txt │ ├── COPYRIGHT.background │ ├── COPYRIGHT.panel │ ├── LICENSE.panel │ ├── background.jpg │ ├── panel.png │ └── slim.theme ├── util.cpp ├── util.h └── xinitrc.sample /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.6.0 FATAL_ERROR) 2 | 3 | set(PROJECT_NAME slim) 4 | project(${PROJECT_NAME}) 5 | 6 | #Pretty colors 7 | set(CMAKE_COLOR_MAKEFILE ON) 8 | #Dont force verbose 9 | set(CMAKE_VERBOSE_MAKEFILE ON) 10 | #Include current dir 11 | set(CMAKE_INCLUDE_CURRENT_DIR TRUE) 12 | 13 | INCLUDE(CheckIncludeFile) 14 | INCLUDE(CheckCCompilerFlag) 15 | INCLUDE(CheckCXXCompilerFlag) 16 | INCLUDE(CheckTypeSize) 17 | 18 | # Version 19 | set(SLIM_VERSION_MAJOR "1") 20 | set(SLIM_VERSION_MINOR "3") 21 | set(SLIM_VERSION_PATCH "6") 22 | set(SLIM_VERSION "${SLIM_VERSION_MAJOR}.${SLIM_VERSION_MINOR}.${SLIM_VERSION_PATCH}") 23 | 24 | set(CMAKE_INSTALL_PREFIX "/usr/local" CACHE PATH "Installation Directory") 25 | set(PKGDATADIR "${CMAKE_INSTALL_PREFIX}/share/slim") 26 | set(SYSCONFDIR "/etc") 27 | set(LIBDIR "/lib") 28 | set(MANDIR "${CMAKE_INSTALL_PREFIX}/share/man") 29 | 30 | set(SLIM_DEFINITIONS) 31 | if(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD" OR 32 | ${CMAKE_SYSTEM_NAME} MATCHES "NetBSD" OR 33 | ${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD" 34 | ) 35 | set(SLIM_DEFINITIONS ${SLIM_DEFINITIONS} "-DNEEDS_BASENAME") 36 | else() 37 | set(SLIM_DEFINITIONS ${SLIM_DEFINITIONS} "-DHAVE_SHADOW") 38 | endif() 39 | 40 | set(SLIM_DEFINITIONS ${SLIM_DEFINITIONS} "-DPACKAGE=\"slim\"") 41 | set(SLIM_DEFINITIONS ${SLIM_DEFINITIONS} "-DVERSION=\"${SLIM_VERSION}\"") 42 | set(SLIM_DEFINITIONS ${SLIM_DEFINITIONS} "-DPKGDATADIR=\"${PKGDATADIR}\"") 43 | set(SLIM_DEFINITIONS ${SLIM_DEFINITIONS} "-DSYSCONFDIR=\"${SYSCONFDIR}\"") 44 | 45 | # Flags 46 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -g -O2") 47 | set(CMAKE_CPP_FLAGS "${CMAKE_CPP_FLAGS} -Wall -g -O2") 48 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -g -O2") 49 | 50 | # source 51 | set(slim_srcs 52 | main.cpp 53 | app.cpp 54 | numlock.cpp 55 | switchuser.cpp 56 | png.c 57 | jpeg.c 58 | ) 59 | 60 | set(slimlock_srcs 61 | slimlock.cpp 62 | ) 63 | 64 | set(common_srcs 65 | cfg.cpp 66 | image.cpp 67 | log.cpp 68 | panel.cpp 69 | util.cpp 70 | ) 71 | if(USE_PAM) 72 | set(common_srcs ${common_srcs} PAM.cpp) 73 | # for now, only build slimlock if we are using PAM. 74 | set(BUILD_SLIMLOCK 1) 75 | endif(USE_PAM) 76 | 77 | # Build common library 78 | set(BUILD_SHARED_LIBS ON CACHE BOOL "Build shared libraries") 79 | 80 | if (BUILD_SHARED_LIBS) 81 | message(STATUS "Enable shared library building") 82 | add_library(libslim ${common_srcs}) 83 | else(BUILD_SHARED_LIBS) 84 | message(STATUS "Disable shared library building") 85 | add_library(libslim STATIC ${common_srcs}) 86 | endif(BUILD_SHARED_LIBS) 87 | 88 | if(USE_CONSOLEKIT) 89 | set(slim_srcs ${slim_srcs} Ck.cpp) 90 | endif(USE_CONSOLEKIT) 91 | 92 | add_executable(${PROJECT_NAME} ${slim_srcs}) 93 | if(BUILD_SLIMLOCK) 94 | add_executable(slimlock ${slimlock_srcs}) 95 | endif(BUILD_SLIMLOCK) 96 | 97 | #Set the custom CMake module directory where our include/lib finders are 98 | set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules") 99 | 100 | find_package(X11 REQUIRED) 101 | find_package(Freetype REQUIRED) 102 | find_package(JPEG REQUIRED) 103 | find_package(PNG REQUIRED) 104 | find_package(ZLIB REQUIRED) 105 | 106 | # Fontconfig 107 | set(FONTCONFIG_DIR ${CMAKE_MODULE_PATH}) 108 | find_package(FONTCONFIG REQUIRED) 109 | if(FONTCONFIG_FOUND) 110 | message("\tFontConfig Found") 111 | target_link_libraries(${PROJECT_NAME} ${FONTCONFIG_LIBRARY}) 112 | include_directories(${FONTCONFIG_INCLUDE_DIR}) 113 | endif(FONTCONFIG_FOUND) 114 | 115 | # PAM 116 | if(USE_PAM) 117 | message("\tPAM Enabled") 118 | find_package(PAM) 119 | if(PAM_FOUND) 120 | message("\tPAM Found") 121 | set(SLIM_DEFINITIONS ${SLIM_DEFINITIONS} "-DUSE_PAM") 122 | target_link_libraries(${PROJECT_NAME} ${PAM_LIBRARY}) 123 | target_link_libraries(slimlock ${PAM_LIBRARY}) 124 | include_directories(${PAM_INCLUDE_DIR}) 125 | else(PAM_FOUND) 126 | message("\tPAM Not Found") 127 | endif(PAM_FOUND) 128 | else(USE_PAM) 129 | message("\tPAM disabled") 130 | endif(USE_PAM) 131 | 132 | # ConsoleKit 133 | if(USE_CONSOLEKIT) 134 | find_package(CkConnector) 135 | message("\tConsoleKit Enabled") 136 | if(CKCONNECTOR_FOUND) 137 | message("\tConsoleKit Found") 138 | # DBus check 139 | find_package(DBus REQUIRED) 140 | if(DBUS_FOUND) 141 | message("\tDBus Found") 142 | target_link_libraries(${PROJECT_NAME} ${DBUS_LIBRARIES}) 143 | include_directories(${DBUS_ARCH_INCLUDE_DIR}) 144 | include_directories(${DBUS_INCLUDE_DIR}) 145 | set(SLIM_DEFINITIONS ${SLIM_DEFINITIONS} "-DUSE_CONSOLEKIT") 146 | target_link_libraries(${PROJECT_NAME} ${CKCONNECTOR_LIBRARIES}) 147 | include_directories(${CKCONNECTOR_INCLUDE_DIR}) 148 | else(DBUS_FOUND) 149 | message("\tDBus Not Found") 150 | endif(DBUS_FOUND) 151 | else(CKCONNECTOR_FOUND) 152 | message("\tConsoleKit Not Found") 153 | message("\tConsoleKit disabled") 154 | endif(CKCONNECTOR_FOUND) 155 | else(USE_CONSOLEKIT) 156 | message("\tConsoleKit disabled") 157 | endif(USE_CONSOLEKIT) 158 | 159 | # system librarys 160 | find_library(M_LIB m) 161 | find_library(RT_LIB rt) 162 | find_library(CRYPTO_LIB crypt) 163 | find_package(Threads) 164 | 165 | add_definitions(${SLIM_DEFINITIONS}) 166 | 167 | #Set up include dirs with all found packages 168 | include_directories( 169 | ${X11_INCLUDE_DIR} 170 | ${X11_Xft_INCLUDE_PATH} 171 | ${X11_Xrender_INCLUDE_PATH} 172 | ${X11_Xrandr_INCLUDE_PATH} 173 | ${FREETYPE_INCLUDE_DIR_freetype2} 174 | ${X11_Xmu_INCLUDE_PATH} 175 | ${ZLIB_INCLUDE_DIR} 176 | ${JPEG_INCLUDE_DIR} 177 | ${PNG_INCLUDE_DIR} 178 | ) 179 | 180 | target_link_libraries(libslim 181 | ${JPEG_LIBRARIES} 182 | ${PNG_LIBRARIES} 183 | ) 184 | 185 | #Set up library with all found packages for slim 186 | target_link_libraries(${PROJECT_NAME} 187 | ${M_LIB} 188 | ${RT_LIB} 189 | ${CRYPTO_LIB} 190 | ${X11_X11_LIB} 191 | ${X11_Xft_LIB} 192 | ${X11_Xrender_LIB} 193 | ${X11_Xrandr_LIB} 194 | ${X11_Xmu_LIB} 195 | ${FREETYPE_LIBRARY} 196 | ${JPEG_LIBRARIES} 197 | ${PNG_LIBRARIES} 198 | libslim 199 | ) 200 | 201 | if(BUILD_SLIMLOCK) 202 | #Set up library with all found packages for slimlock 203 | target_link_libraries(slimlock 204 | ${M_LIB} 205 | ${RT_LIB} 206 | ${CRYPTO_LIB} 207 | ${X11_X11_LIB} 208 | ${X11_Xft_LIB} 209 | ${X11_Xrender_LIB} 210 | ${X11_Xrandr_LIB} 211 | ${X11_Xmu_LIB} 212 | ${X11_Xext_LIB} 213 | ${FREETYPE_LIBRARY} 214 | ${JPEG_LIBRARIES} 215 | ${PNG_LIBRARIES} 216 | ${CMAKE_THREAD_LIBS_INIT} 217 | libslim 218 | ) 219 | endif(BUILD_SLIMLOCK) 220 | 221 | ####### install 222 | # slim 223 | install(TARGETS slim RUNTIME DESTINATION bin) 224 | install(TARGETS slimlock RUNTIME DESTINATION bin) 225 | 226 | if (BUILD_SHARED_LIBS) 227 | set_target_properties(libslim PROPERTIES 228 | OUTPUT_NAME slim 229 | SOVERSION ${SLIM_VERSION}) 230 | 231 | install(TARGETS libslim 232 | LIBRARY DESTINATION lib 233 | ARCHIVE DESTINATION lib 234 | ) 235 | endif (BUILD_SHARED_LIBS) 236 | 237 | # man file 238 | install(FILES slim.1 DESTINATION ${MANDIR}/man1/) 239 | install(FILES slimlock.1 DESTINATION ${MANDIR}/man1/) 240 | # configure 241 | install(FILES slim.conf DESTINATION ${SYSCONFDIR}) 242 | # systemd service file 243 | if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") 244 | install(FILES slim.service DESTINATION ${LIBDIR}/systemd/system) 245 | endif (${CMAKE_SYSTEM_NAME} MATCHES "Linux") 246 | # themes directory 247 | subdirs(themes) 248 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 675 Mass Ave, Cambridge, MA 02139, USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | Appendix: How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 19yy 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) 19yy name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Library General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | 1.3.6 - 2013.10.01 2 | * Merge slimlock. 3 | * Add support ^H (like backspace). 4 | * And fix some bugs. 5 | 6 | 1.3.5 - 2012.12.31 7 | * Support UTF8 string. 8 | * Add systemd service. 9 | * And fix some bugs. 10 | 11 | 1.3.4 - 2012.06.26 12 | * Replaced stderr writes function. 13 | * Fix numlock control. 14 | * Fix build with GLUT. 15 | * Fix PAM authentication. 16 | 17 | 1.3.3 - 2012.02.22 18 | * Change build system to CMake. 19 | * Add support ConsoleKit. 20 | * Fix some bugs.... 21 | 22 | 1.3.2 - 2010.07.08 23 | * Add support xauth secret. 24 | * Add xnest_debug mode. 25 | 26 | 1.3.1 - 2008.09.26 27 | * Added focus_password config option for focusing password 28 | automatically when default_user is enabled 29 | * Added auto_login option 30 | * Fixed uninitialized daemonmode, see 31 | http://www.freebsd.org/cgi/query-pr.cgi?pr=114366 32 | * Fixed maximum length for password 33 | * Introduced customization options for session text: 34 | font, colors, position, shadows. 35 | 36 | 1.3.0 - 2006.07.14 37 | * Added PAM support by Martin Parm 38 | * Fixed segfault on exit when testing themes. Thanks 39 | to Darren Salt & Mike Massonnet 40 | * Fixed vt argument detection, thanks to Henrik Brix Andersen 41 | * Corrected reference to input_color in the default theme 42 | * Fixed default shell setting 43 | * Fix segfault when calling XCloseDisplay(NULL); thanks Uli Schlachter 44 | 45 | 1.2.6 - 2006.09.15 46 | * Bug #008167: Update pid when in daemon mode 47 | * Fixed warnings when compiling with -Wall. Thanks to 48 | KIMURA Masaru 49 | * Fixed major memory leaks with repeated login (bug #007535) 50 | 51 | 1.2.5 - 2006.07.24 52 | * hiding of the cursor is now an option (disabled 53 | by default) since some WMs does not re-initialize 54 | the root window cursor. 55 | * The X server is restarted when the user logs out. 56 | This fixes potential security issues with user-launched 57 | apps staying attached to the root window after logout. 58 | * Bug #7432 : Added proper Xauth authentication: the X server 59 | is started with the -auth option and the user who logs 60 | in has his .Xauthority file initializated. 61 | 62 | 1.2.4 - 2006.01.18 63 | * Added commands for session start and stop 64 | (i.e. for session registering) 65 | * Added automatic numlock on/off option 66 | * Support for numpad Enter key 67 | * Restored support for daemon option in the config 68 | file. 69 | * Lock file now uses process id, no more false 70 | locking (thanks to Tobias Roth) 71 | 72 | 1.2.3 - 2005.09.11 73 | * Added FreeBSD, NetBSD, OpenBSD support 74 | * Replaced autotools with plain makefile(s) 75 | * Added 'suspend' command (untested, we don't use it) 76 | * Added support for %theme variable in login command 77 | 78 | 1.2.2 - 2005.05.21 79 | * fix panel drawing on screens <= 1024x768 80 | * Don't start X server unless valid theme found 81 | * revert to 'default' of invalid theme specified 82 | * try all themes from a set if one doesn't work 83 | 84 | 1.2.1 - 2005.05.17 85 | * draw input directly on panel 86 | 87 | 1.2.0 - 2005.05.16 88 | * added theme preview (slim -p /path/to/theme) 89 | * added JPEG support for panel image 90 | * added 'center' background type and 'background_color' option 91 | * added text shadow 92 | * added warning when execution of login command fails 93 | * Fix login failure when no shell specified in /etc/passwd 94 | * Print error when login command execution fails 95 | * add XNEST_DEBUG ifdef's to allow for easy debugging 96 | * Add support for Ctrl-u and Ctrl-w 97 | * Add 'vt07' to server arguments if not already specified 98 | * Removes daemon option from the config file. Use slim -d 99 | * Allow 'current_theme' to be a set of themes, choose randomly 100 | * Change default theme 101 | 102 | 1.1.0 - 2004.12.09 103 | * error messages for X11 apps are no longer redirected 104 | to the log file 105 | * fixed text position for default theme 106 | * added configurable shutdown and reboot messages 107 | * separated 'Enter username' and 'Enter password' messages 108 | position. 109 | * due to the previous two points, the theme format has 110 | slightly changed 111 | 112 | 1.0.0 - 2004.12.07 113 | * First public SLiM release 114 | -------------------------------------------------------------------------------- /Ck.cpp: -------------------------------------------------------------------------------- 1 | /* SLiM - Simple Login Manager 2 | * Copyright (C) 2011 David Hauweele 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | */ 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "Ck.h" 19 | 20 | namespace Ck { 21 | Exception::Exception(const std::string &func, 22 | const std::string &errstr): 23 | func(func), 24 | errstr(errstr) 25 | {} 26 | 27 | dbus_bool_t 28 | Session::ck_connector_open_graphic_session( 29 | const std::string &display, 30 | uid_t uid) 31 | { 32 | dbus_bool_t local = true; 33 | const char *session_type = "x11"; 34 | const char *x11_display = display.c_str(); 35 | const char *x11_device = get_x11_device(display); 36 | const char *remote_host = ""; 37 | const char *display_dev = ""; 38 | 39 | return ck_connector_open_session_with_parameters(ckc, &error, 40 | "unix-user", &uid, 41 | "session-type", &session_type, 42 | "x11-display", &x11_display, 43 | "x11-display-device", &x11_device, 44 | "display-device", &display_dev, 45 | "remote-host-name", &remote_host, 46 | "is-local", &local, 47 | NULL); 48 | } 49 | 50 | const char * Session::get_x11_device(const std::string &display) 51 | { 52 | static char device[32]; 53 | 54 | Display *xdisplay = XOpenDisplay(display.c_str()); 55 | 56 | if(!xdisplay) 57 | throw Exception(__func__, "cannot open display"); 58 | 59 | Window root; 60 | Atom xfree86_vt_atom; 61 | Atom return_type_atom; 62 | int return_format; 63 | unsigned long return_count; 64 | unsigned long bytes_left; 65 | unsigned char *return_value; 66 | long vt; 67 | 68 | xfree86_vt_atom = XInternAtom(xdisplay, "XFree86_VT", true); 69 | 70 | if(xfree86_vt_atom == None) 71 | throw Exception(__func__, "cannot get XFree86_VT"); 72 | 73 | root = DefaultRootWindow(xdisplay); 74 | 75 | if(XGetWindowProperty(xdisplay, root, xfree86_vt_atom, 76 | 0L, 1L, false, XA_INTEGER, 77 | &return_type_atom, &return_format, 78 | &return_count, &bytes_left, 79 | &return_value) != Success) 80 | throw Exception(__func__, "cannot get root window property"); 81 | 82 | if(return_type_atom != XA_INTEGER) 83 | throw Exception(__func__, "bad atom type"); 84 | 85 | if(return_format != 32) 86 | throw Exception(__func__, "invalid return format"); 87 | 88 | if(return_count != 1) 89 | throw Exception(__func__, "invalid count"); 90 | 91 | if(bytes_left != 0) 92 | throw Exception(__func__, "invalid bytes left"); 93 | 94 | vt = *((long *)return_value); 95 | 96 | std::snprintf(device, 32, "/dev/tty%ld", vt); 97 | 98 | if(return_value) 99 | XFree(return_value); 100 | 101 | return device; 102 | } 103 | 104 | void Session::open_session(const std::string &display, uid_t uid) 105 | { 106 | ckc = ck_connector_new(); 107 | 108 | if(!ckc) 109 | throw Exception(__func__, "error setting up connection to ConsoleKit"); 110 | 111 | if (!ck_connector_open_graphic_session(display, uid)) { 112 | if(dbus_error_is_set(&error)) 113 | throw Exception(__func__, error.message); 114 | else 115 | throw Exception(__func__, "cannot open ConsoleKit session: OOM," 116 | " DBus system bus not available or insufficient" 117 | " privileges"); 118 | } 119 | } 120 | 121 | const char * Session::get_xdg_session_cookie() 122 | { 123 | return ck_connector_get_cookie(ckc); 124 | } 125 | 126 | void Session::close_session() 127 | { 128 | if(!ck_connector_close_session(ckc, &error)) { 129 | if(dbus_error_is_set(&error)) 130 | throw Exception(__func__, error.message); 131 | else 132 | throw Exception(__func__, "cannot close ConsoleKit session: OOM," 133 | " DBus system bus not available or insufficient" 134 | " privileges"); 135 | } 136 | } 137 | 138 | Session::Session() 139 | { 140 | dbus_error_init(&error); 141 | } 142 | 143 | Session::~Session() 144 | { 145 | dbus_error_free(&error); 146 | } 147 | } 148 | 149 | std::ostream& operator<<( std::ostream& os, const Ck::Exception& e) 150 | { 151 | os << e.func << ": " << e.errstr; 152 | return os; 153 | } 154 | -------------------------------------------------------------------------------- /Ck.h: -------------------------------------------------------------------------------- 1 | /* SLiM - Simple Login Manager 2 | * Copyright (C) 2007 Martin Parm 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | *(at your option) any later version. 8 | */ 9 | 10 | #ifndef _CK_H_ 11 | #define _CK_H_ 12 | 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | namespace Ck { 19 | class Exception { 20 | public: 21 | std::string func; 22 | std::string errstr; 23 | Exception(const std::string &func, const std::string &errstr); 24 | }; 25 | 26 | class Session { 27 | private: 28 | CkConnector *ckc; 29 | DBusError error; 30 | 31 | const char *get_x11_device(const std::string &display); 32 | dbus_bool_t ck_connector_open_graphic_session(const std::string &display, 33 | uid_t uid); 34 | public: 35 | const char *get_xdg_session_cookie(); 36 | void open_session(const std::string &display, uid_t uid); 37 | void close_session(); 38 | 39 | Session(); 40 | ~Session(); 41 | }; 42 | } 43 | 44 | std::ostream &operator<<(std::ostream &os, const Ck::Exception &e); 45 | 46 | #endif /* _CK_H_ */ 47 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | INSTALL file for SLiM 2 | 3 | 0. Prerequisites: 4 | - cmake 5 | - X.org or XFree86 6 | - libxmu 7 | - libpng 8 | - libjpeg 9 | 10 | 1. to build and install the program: 11 | - edit the Makefile to adjust libraries and paths to your OS (if needed) 12 | - mkdir build ; cd build ; cmake .. 13 | or 14 | - mkdir build ; cd build ; cmake .. -DUSE_PAM=yes to enable PAM support 15 | or 16 | - mkdir build ; cd build ; cmake .. -DUSE_CONSOLEKIT=yes 17 | to enable CONSOLEKIT support 18 | - make && make install 19 | 20 | 2. automatic startup 21 | Edit the init scripts according to your OS/Distribution. 22 | -------------------------------------------------------------------------------- /PAM.cpp: -------------------------------------------------------------------------------- 1 | /* SLiM - Simple Login Manager 2 | * Copyright (C) 2007 Martin Parm 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | */ 9 | 10 | #include 11 | #include 12 | #include "PAM.h" 13 | 14 | namespace PAM { 15 | Exception::Exception(pam_handle_t* _pam_handle, 16 | const std::string& _func_name, 17 | int _errnum): 18 | errnum(_errnum), 19 | errstr(pam_strerror(_pam_handle, _errnum)), 20 | func_name(_func_name) 21 | {} 22 | 23 | Exception::~Exception(void) {} 24 | 25 | Auth_Exception::Auth_Exception(pam_handle_t* _pam_handle, 26 | const std::string& _func_name, 27 | int _errnum): 28 | Exception(_pam_handle, _func_name, _errnum) {} 29 | 30 | Cred_Exception::Cred_Exception(pam_handle_t* _pam_handle, 31 | const std::string& _func_name, 32 | int _errnum): 33 | Exception(_pam_handle, _func_name, _errnum) {} 34 | 35 | int Authenticator::_end (void) 36 | { 37 | int result=pam_end(pam_handle, last_result); 38 | pam_handle=0; 39 | return result; 40 | } 41 | 42 | Authenticator::Authenticator(conversation* conv, void* data): 43 | pam_handle(0), 44 | last_result(PAM_SUCCESS) 45 | { 46 | pam_conversation.conv=conv; 47 | pam_conversation.appdata_ptr=data; 48 | } 49 | 50 | Authenticator::~Authenticator(void) 51 | { 52 | if (pam_handle) 53 | _end(); 54 | } 55 | 56 | void Authenticator::start(const std::string& service) 57 | { 58 | switch ((last_result=pam_start(service.c_str(), NULL, &pam_conversation, &pam_handle))) { 59 | default: 60 | throw Exception(pam_handle, "pam_start()", last_result); 61 | 62 | case PAM_SUCCESS: 63 | break; 64 | } 65 | return; 66 | } 67 | 68 | void Authenticator::end(void) 69 | { 70 | switch ((last_result=_end())) { 71 | default: 72 | throw Exception(pam_handle, "pam_end()", last_result); 73 | 74 | case PAM_SUCCESS: 75 | break; 76 | } 77 | return; 78 | } 79 | 80 | void Authenticator::set_item(const Authenticator::ItemType item, const void* value) 81 | { 82 | switch ((last_result=pam_set_item(pam_handle, item, value))) { 83 | default: 84 | _end(); 85 | throw Exception(pam_handle, "pam_set_item()", last_result); 86 | 87 | case PAM_SUCCESS: 88 | break; 89 | } 90 | return; 91 | } 92 | 93 | const void* Authenticator::get_item(const Authenticator::ItemType item) 94 | { 95 | const void* data; 96 | switch ((last_result=pam_get_item(pam_handle, item, &data))) { 97 | default: 98 | case PAM_SYSTEM_ERR: 99 | #ifdef __LIBPAM_VERSION 100 | case PAM_BAD_ITEM: 101 | #endif 102 | _end(); 103 | throw Exception(pam_handle, "pam_get_item()", last_result); 104 | 105 | case PAM_PERM_DENIED: /* The value of item was NULL */ 106 | case PAM_SUCCESS: 107 | break; 108 | } 109 | return data; 110 | } 111 | 112 | #ifdef __LIBPAM_VERSION 113 | void Authenticator::fail_delay(const unsigned int micro_sec) 114 | { 115 | switch ((last_result=pam_fail_delay(pam_handle, micro_sec))) { 116 | default: 117 | _end(); 118 | throw Exception(pam_handle, "fail_delay()", last_result); 119 | 120 | case PAM_SUCCESS: 121 | break; 122 | } 123 | return; 124 | } 125 | #endif 126 | 127 | void Authenticator::authenticate(void) 128 | { 129 | switch ((last_result=pam_authenticate(pam_handle, 0))) { 130 | default: 131 | case PAM_ABORT: 132 | case PAM_AUTHINFO_UNAVAIL: 133 | _end(); 134 | throw Exception(pam_handle, "pam_authenticate()", last_result); 135 | 136 | case PAM_USER_UNKNOWN: 137 | case PAM_MAXTRIES: 138 | case PAM_CRED_INSUFFICIENT: 139 | case PAM_AUTH_ERR: 140 | throw Auth_Exception(pam_handle, "pam_authentication()", last_result); 141 | 142 | case PAM_SUCCESS: 143 | break; 144 | } 145 | 146 | switch ((last_result=pam_acct_mgmt(pam_handle, PAM_SILENT))) { 147 | /* The documentation and implementation of Linux PAM differs: 148 | PAM_NEW_AUTHTOKEN_REQD is described in the documentation but 149 | don't exists in the actual implementation. This issue needs 150 | to be fixes at some point. */ 151 | 152 | default: 153 | /* case PAM_NEW_AUTHTOKEN_REQD: */ 154 | case PAM_ACCT_EXPIRED: 155 | case PAM_USER_UNKNOWN: 156 | _end(); 157 | throw Exception(pam_handle, "pam_acct_mgmt()", last_result); 158 | 159 | case PAM_AUTH_ERR: 160 | case PAM_PERM_DENIED: 161 | throw Auth_Exception(pam_handle, "pam_acct_mgmt()", last_result); 162 | 163 | case PAM_SUCCESS: 164 | break; 165 | } 166 | return; 167 | } 168 | 169 | void Authenticator::open_session(void) 170 | { 171 | switch ((last_result=pam_setcred(pam_handle, PAM_ESTABLISH_CRED))) { 172 | default: 173 | case PAM_CRED_ERR: 174 | case PAM_CRED_UNAVAIL: 175 | _end(); 176 | throw Exception(pam_handle, "pam_setcred()", last_result); 177 | 178 | case PAM_CRED_EXPIRED: 179 | case PAM_USER_UNKNOWN: 180 | throw Cred_Exception(pam_handle, "pam_setcred()", last_result); 181 | 182 | case PAM_SUCCESS: 183 | break; 184 | } 185 | 186 | switch ((last_result=pam_open_session(pam_handle, 0))) { 187 | /* The documentation and implementation of Linux PAM differs: 188 | PAM_SESSION_ERROR is described in the documentation but 189 | don't exists in the actual implementation. This issue needs 190 | to be fixes at some point. */ 191 | 192 | default: 193 | /* case PAM_SESSION_ERROR: */ 194 | pam_setcred(pam_handle, PAM_DELETE_CRED); 195 | _end(); 196 | throw Exception(pam_handle, "pam_open_session()", last_result); 197 | 198 | case PAM_SUCCESS: 199 | break; 200 | } 201 | return; 202 | } 203 | 204 | void Authenticator::close_session(void) 205 | { 206 | switch ((last_result=pam_close_session(pam_handle, 0))) { 207 | /* The documentation and implementation of Linux PAM differs: 208 | PAM_SESSION_ERROR is described in the documentation but 209 | don't exists in the actual implementation. This issue needs 210 | to be fixes at some point. */ 211 | 212 | default: 213 | /* case PAM_SESSION_ERROR: */ 214 | pam_setcred(pam_handle, PAM_DELETE_CRED); 215 | _end(); 216 | throw Exception(pam_handle, "pam_close_session", last_result); 217 | 218 | case PAM_SUCCESS: 219 | break; 220 | } 221 | switch ((last_result=pam_setcred(pam_handle, PAM_DELETE_CRED))) { 222 | default: 223 | case PAM_CRED_ERR: 224 | case PAM_CRED_UNAVAIL: 225 | case PAM_CRED_EXPIRED: 226 | case PAM_USER_UNKNOWN: 227 | _end(); 228 | throw Exception(pam_handle, "pam_setcred()", last_result); 229 | 230 | case PAM_SUCCESS: 231 | break; 232 | } 233 | return; 234 | } 235 | 236 | void Authenticator::setenv(const std::string& key, const std::string& value) 237 | { 238 | std::string name_value = key+"="+value; 239 | switch ((last_result = pam_putenv(pam_handle, name_value.c_str()))) { 240 | default: 241 | case PAM_PERM_DENIED: 242 | case PAM_ABORT: 243 | case PAM_BUF_ERR: 244 | #ifdef __LIBPAM_VERSION 245 | case PAM_BAD_ITEM: 246 | #endif 247 | _end(); 248 | throw Exception(pam_handle, "pam_putenv()", last_result); 249 | 250 | case PAM_SUCCESS: 251 | break; 252 | } 253 | return; 254 | } 255 | 256 | void Authenticator::delenv(const std::string& key) 257 | { 258 | switch ((last_result = pam_putenv(pam_handle, key.c_str()))) { 259 | default: 260 | case PAM_PERM_DENIED: 261 | case PAM_ABORT: 262 | case PAM_BUF_ERR: 263 | #ifdef __LIBPAM_VERSION 264 | case PAM_BAD_ITEM: 265 | #endif 266 | _end(); 267 | throw Exception(pam_handle, "pam_putenv()", last_result); 268 | 269 | case PAM_SUCCESS: 270 | break; 271 | } 272 | return; 273 | } 274 | 275 | const char* Authenticator::getenv(const std::string& key) 276 | { 277 | return pam_getenv(pam_handle, key.c_str()); 278 | } 279 | 280 | char** Authenticator::getenvlist(void) 281 | { 282 | return pam_getenvlist(pam_handle); 283 | } 284 | } 285 | 286 | std::ostream& operator<<( std::ostream& os, const PAM::Exception& e) 287 | { 288 | os << e.func_name << ": " << e.errstr; 289 | return os; 290 | } 291 | -------------------------------------------------------------------------------- /PAM.h: -------------------------------------------------------------------------------- 1 | /* SLiM - Simple Login Manager 2 | Copyright (C) 2007 Martin Parm 3 | 4 | This program is free software; you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation; either version 2 of the License, or 7 | (at your option) any later version. 8 | */ 9 | 10 | #ifndef _PAM_H_ 11 | #define _PAM_H_ 12 | #include 13 | #include 14 | 15 | #ifdef __LIBPAM_VERSION 16 | #include 17 | #endif 18 | 19 | namespace PAM { 20 | class Exception { 21 | public: 22 | int errnum; 23 | std::string errstr; 24 | std::string func_name; 25 | Exception(pam_handle_t* _pam_handle, 26 | const std::string& _func_name, 27 | int _errnum); 28 | virtual ~Exception(void); 29 | }; 30 | 31 | class Auth_Exception: public Exception { 32 | public: 33 | Auth_Exception(pam_handle_t* _pam_handle, 34 | const std::string& _func_name, 35 | int _errnum); 36 | }; 37 | 38 | class Cred_Exception: public Exception { 39 | public: 40 | Cred_Exception(pam_handle_t* _pam_handle, 41 | const std::string& _func_name, 42 | int _errnum); 43 | }; 44 | 45 | 46 | class Authenticator { 47 | private: 48 | struct pam_conv pam_conversation; 49 | pam_handle_t* pam_handle; 50 | int last_result; 51 | 52 | int _end(void); 53 | public: 54 | typedef int (conversation)(int num_msg, 55 | const struct pam_message **msg, 56 | struct pam_response **resp, 57 | void *appdata_ptr); 58 | 59 | enum ItemType { 60 | Service = PAM_SERVICE, 61 | User = PAM_USER, 62 | User_Prompt = PAM_USER_PROMPT, 63 | TTY = PAM_TTY, 64 | Requestor = PAM_RUSER, 65 | Host = PAM_RHOST, 66 | Conv = PAM_CONV, 67 | #ifdef __LIBPAM_VERSION 68 | /* Fail_Delay = PAM_FAIL_DELAY */ 69 | #endif 70 | }; 71 | 72 | public: 73 | Authenticator(conversation* conv, void* data=0); 74 | ~Authenticator(void); 75 | 76 | void start(const std::string& service); 77 | void end(void); 78 | void set_item(const ItemType item, const void* value); 79 | const void* get_item(const ItemType item); 80 | #ifdef __LIBPAM_VERSION 81 | void fail_delay(const unsigned int micro_sec); 82 | #endif 83 | void authenticate(void); 84 | void open_session(void); 85 | void close_session(void); 86 | void setenv(const std::string& key, const std::string& value); 87 | void delenv(const std::string& key); 88 | const char* getenv(const std::string& key); 89 | char** getenvlist(void); 90 | 91 | private: 92 | /* Explicitly disable copy constructor and copy assignment */ 93 | Authenticator(const PAM::Authenticator&); 94 | Authenticator& operator=(const PAM::Authenticator&); 95 | }; 96 | } 97 | 98 | std::ostream& operator<<( std::ostream& os, const PAM::Exception& e); 99 | #endif /* _PAM_H_ */ 100 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iwamatsu/slim/4a40caff34b52c9b9bcf8cbb83775ade9398d179/README -------------------------------------------------------------------------------- /THEMES: -------------------------------------------------------------------------------- 1 | Quick THEME howto for SLiM 2 | 3 | Some basic information regarding the slim theme format. 4 | Read this file if you plan to make some theme for 5 | the program, and of course have a look at the included themes 6 | 7 | GENERAL CONCEPT 8 | A SLiM theme essentially consists of: 9 | - a background image (background.png or background.jpg) 10 | - a panel image (panel.png or panel.jpg) 11 | - input box(es) and messages and their placement 12 | and properties (slim.theme) 13 | 14 | The panel and background images can be a PNG or JPEG file. 15 | The panel is blended into the background image, 16 | taking care of alpha transparency. 17 | 18 | SUPPORTED FORMATS 19 | - fonts: use the xft font specs, ie: Verdana:size=16:bold 20 | - colors: use html hex format, ie #0066CC 21 | - positions: can be either absolute in pixels, ie 350 22 | or relative to the container, ie 50% is in the middle 23 | of the screen. 24 | 25 | OPTIONS 26 | The following is an example slim.theme file 27 | ---------------------------------------------------------------------- 28 | # Color, font, position for the messages (ie: shutting down) 29 | msg_color #FFFFFF 30 | msg_font Verdana:size=16:bold 31 | msg_x 50% 32 | msg_y 30 33 | 34 | # Color, font, position for the session list 35 | session_color #FFFFFF 36 | session_font Verdana:size=16:bold 37 | session_x 50% 38 | session_y 90% 39 | 40 | # style of background: 'stretch', 'tile', 'center', 'color' 41 | background_style stretch 42 | background_color #FF0033 43 | 44 | # Horizonatal and vertical position for the panel. 45 | input_panel_x 50% 46 | input_panel_y 40% 47 | 48 | # input controls horizontal and vertical positions. 49 | # IMPORTANT! set input_pass_x and input_pass_y to -1 50 | # to use a single input box for username/password (GDM Style). 51 | # Note that this fields only accept absolute values. 52 | input_name_x 40 53 | input_name_y 100 54 | input_pass_x 40 55 | input_pass_y 120 56 | 57 | # Input controls font and color 58 | input_font Verdana:size=12 59 | input_color #000000 60 | 61 | # Welcome message position. (relative to the panel) 62 | # use -1 for both values or comment the options to disable 63 | # the welcome message 64 | welcome_x 50% 65 | welcome_y 38 66 | 67 | # Font and color for the welcome message 68 | welcome_font Verdana:size=16:bold:slant=italic 69 | welcome_color #d7dde8 70 | 71 | # 'Enter username' font and foreground/background color 72 | username_font Verdana:size=12 73 | username_color #d7dde8 74 | 75 | # 'Enter username' and 'Enter password' position (relative to the panel) 76 | # use -1 for both values to disable the message 77 | # note that in case of single inputbox the password values are ignored. 78 | username_x 50% 79 | username_y 146 80 | password_x 50% 81 | password_y 146 82 | 83 | # The message to be displayed. Leave blank if no message 84 | # is needed (ie, when already present in the panel image) 85 | username_msg Please enter your username 86 | password_msg Please enter your password 87 | ---------------------------------------------------------------------- 88 | 89 | SHADOWS 90 | 91 | The 'msg', 'input', 'welcome', 'session' and 'username' sections 92 | support shadows; three values can be configured: 93 | - color: the shadow color 94 | - x offset: the offset in x direction, relative to the normal text 95 | - y offset: the offset in y direction, relative to the normal text 96 | 97 | So to add a text shadow to the welcome message, add the following 98 | to slim.conf: 99 | ---------------------------------------------------------------------- 100 | welcome_shadow_xoffset -2 101 | welcome_shadow_yoffset 2 102 | welcome_shadow_color #ff0000 103 | ---------------------------------------------------------------------- 104 | 105 | The other keys are analogue: 106 | ---------------------------------------------------------------------- 107 | # for username and password label 108 | username_shadow_xoffset 2 109 | username_shadow_yoffset -2 110 | username_shadow_color #ff0000 111 | 112 | # for the input fields 113 | input_shadow_xoffset 1 114 | input_shadow_yoffset 1 115 | input_shadow_color #0000ff 116 | 117 | # for the messages: 118 | msg_shadow_xoffset 1 119 | msg_shadow_yoffset 1 120 | msg_shadow_color #ff00ff 121 | 122 | # For the session: 123 | session_shadow_xoffset 1 124 | session_shadow_yoffset 1 125 | session_shadow_color #ff00ff 126 | ---------------------------------------------------------------------- 127 | 128 | 129 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | 1.2.2 2 | ----- 3 | - drawing problem on screens <= 1024x768 (implemented) 4 | - Don't start X server if theme's not found 5 | 6 | 1.2.x 7 | ----- 8 | - i18n 9 | - don't choose a non-existing theme in random selection 10 | - think about multi-line configuration: 11 | current_theme = t1, t2, t3 12 | current_theme = t4, t5 13 | or 14 | current_theme = t1, t2, t3 \ 15 | t4, t5 16 | - FreeBSD fixes 17 | 18 | 2.0.x 19 | ----- 20 | - restart X server on ctrl-alt-backspace 21 | - allow switching theme on the fly if a set is specified in slim.conf 22 | - text alignment, to allow to center texts of unknown length (e.g. %host) 23 | -------------------------------------------------------------------------------- /app.h: -------------------------------------------------------------------------------- 1 | /* SLiM - Simple Login Manager 2 | * Copyright (C) 1997, 1998 Per Liden 3 | * Copyright (C) 2004-06 Simone Rota 4 | * Copyright (C) 2004-06 Johannes Winkelmann 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | */ 11 | 12 | #ifndef _APP_H_ 13 | #define _APP_H_ 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include "panel.h" 25 | #include "cfg.h" 26 | #include "image.h" 27 | 28 | #ifdef USE_PAM 29 | #include "PAM.h" 30 | #endif 31 | #ifdef USE_CONSOLEKIT 32 | #include "Ck.h" 33 | #endif 34 | 35 | class App { 36 | public: 37 | App(int argc, char **argv); 38 | ~App(); 39 | void Run(); 40 | int GetServerPID(); 41 | void RestartServer(); 42 | void StopServer(); 43 | 44 | /* Lock functions */ 45 | void GetLock(); 46 | void RemoveLock(); 47 | 48 | bool isServerStarted(); 49 | 50 | private: 51 | void Login(); 52 | void Reboot(); 53 | void Halt(); 54 | void Suspend(); 55 | void Console(); 56 | void Exit(); 57 | void KillAllClients(Bool top); 58 | void ReadConfig(); 59 | void OpenLog(); 60 | void CloseLog(); 61 | void HideCursor(); 62 | void CreateServerAuth(); 63 | char *StrConcat(const char *str1, const char *str2); 64 | void UpdatePid(); 65 | 66 | bool AuthenticateUser(bool focuspass); 67 | 68 | static std::string findValidRandomTheme(const std::string &set); 69 | static void replaceVariables(std::string &input, 70 | const std::string &var, 71 | const std::string &value); 72 | 73 | /* Server functions */ 74 | int StartServer(); 75 | int ServerTimeout(int timeout, char *string); 76 | int WaitForServer(); 77 | 78 | /* Private data */ 79 | Window Root; 80 | Display *Dpy; 81 | int Scr; 82 | Panel *LoginPanel; 83 | int ServerPID; 84 | const char *DisplayName; 85 | bool serverStarted; 86 | 87 | #ifdef USE_PAM 88 | PAM::Authenticator pam; 89 | #endif 90 | #ifdef USE_CONSOLEKIT 91 | Ck::Session ck; 92 | #endif 93 | 94 | /* Options */ 95 | char *DispName; 96 | 97 | Cfg *cfg; 98 | 99 | Pixmap BackgroundPixmap; 100 | 101 | void blankScreen(); 102 | Image *image; 103 | Atom BackgroundPixmapId; 104 | void setBackground(const std::string &themedir); 105 | 106 | bool firstlogin; 107 | bool daemonmode; 108 | bool force_nodaemon; 109 | /* For testing themes */ 110 | char *testtheme; 111 | bool testing; 112 | 113 | std::string themeName; 114 | std::string mcookie; 115 | 116 | const int mcookiesize; 117 | }; 118 | 119 | #endif /* _APP_H_ */ 120 | -------------------------------------------------------------------------------- /cfg.cpp: -------------------------------------------------------------------------------- 1 | /* SLiM - Simple Login Manager 2 | Copyright (C) 2004-06 Simone Rota 3 | Copyright (C) 2004-06 Johannes Winkelmann 4 | Copyright (C) 2012-13 Nobuhiro Iwamatsu 5 | 6 | This program is free software; you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation; either version 2 of the License, or 9 | (at your option) any later version. 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #include "cfg.h" 23 | 24 | using namespace std; 25 | 26 | typedef pair option; 27 | 28 | Cfg::Cfg() 29 | : currentSession(-1) 30 | { 31 | /* Configuration options */ 32 | options.insert(option("default_path","/bin:/usr/bin:/usr/local/bin")); 33 | options.insert(option("default_xserver","/usr/bin/X")); 34 | options.insert(option("xserver_arguments","")); 35 | options.insert(option("numlock","")); 36 | options.insert(option("daemon","")); 37 | options.insert(option("xauth_path","/usr/bin/xauth")); 38 | options.insert(option("login_cmd","exec /bin/bash -login ~/.xinitrc %session")); 39 | options.insert(option("halt_cmd","/sbin/shutdown -h now")); 40 | options.insert(option("reboot_cmd","/sbin/shutdown -r now")); 41 | options.insert(option("suspend_cmd","")); 42 | options.insert(option("sessionstart_cmd","")); 43 | options.insert(option("sessionstop_cmd","")); 44 | options.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""")); 45 | options.insert(option("screenshot_cmd","import -window root /slim.png")); 46 | options.insert(option("welcome_msg","Welcome to %host")); 47 | options.insert(option("session_msg","Session:")); 48 | options.insert(option("default_user","")); 49 | options.insert(option("focus_password","no")); 50 | options.insert(option("auto_login","no")); 51 | options.insert(option("current_theme","default")); 52 | options.insert(option("lockfile","/var/run/slim.lock")); 53 | options.insert(option("logfile","/var/log/slim.log")); 54 | options.insert(option("authfile","/var/run/slim.auth")); 55 | options.insert(option("shutdown_msg","The system is halting...")); 56 | options.insert(option("reboot_msg","The system is rebooting...")); 57 | options.insert(option("sessiondir","")); 58 | options.insert(option("hidecursor","false")); 59 | 60 | /* Theme stuff */ 61 | options.insert(option("input_panel_x","50%")); 62 | options.insert(option("input_panel_y","40%")); 63 | options.insert(option("input_name_x","200")); 64 | options.insert(option("input_name_y","154")); 65 | options.insert(option("input_pass_x","-1")); /* default is single inputbox */ 66 | options.insert(option("input_pass_y","-1")); 67 | options.insert(option("input_font","Verdana:size=11")); 68 | options.insert(option("input_color", "#000000")); 69 | options.insert(option("input_cursor_height","20")); 70 | options.insert(option("input_maxlength_name","20")); 71 | options.insert(option("input_maxlength_passwd","20")); 72 | options.insert(option("input_shadow_xoffset", "0")); 73 | options.insert(option("input_shadow_yoffset", "0")); 74 | options.insert(option("input_shadow_color","#FFFFFF")); 75 | 76 | options.insert(option("welcome_font","Verdana:size=14")); 77 | options.insert(option("welcome_color","#FFFFFF")); 78 | options.insert(option("welcome_x","-1")); 79 | options.insert(option("welcome_y","-1")); 80 | options.insert(option("welcome_shadow_xoffset", "0")); 81 | options.insert(option("welcome_shadow_yoffset", "0")); 82 | options.insert(option("welcome_shadow_color","#FFFFFF")); 83 | 84 | options.insert(option("intro_msg","")); 85 | options.insert(option("intro_font","Verdana:size=14")); 86 | options.insert(option("intro_color","#FFFFFF")); 87 | options.insert(option("intro_x","-1")); 88 | options.insert(option("intro_y","-1")); 89 | 90 | options.insert(option("background_style","stretch")); 91 | options.insert(option("background_color","#CCCCCC")); 92 | 93 | options.insert(option("username_font","Verdana:size=12")); 94 | options.insert(option("username_color","#FFFFFF")); 95 | options.insert(option("username_x","-1")); 96 | options.insert(option("username_y","-1")); 97 | options.insert(option("username_msg","Please enter your username")); 98 | options.insert(option("username_shadow_xoffset", "0")); 99 | options.insert(option("username_shadow_yoffset", "0")); 100 | options.insert(option("username_shadow_color","#FFFFFF")); 101 | 102 | options.insert(option("password_x","-1")); 103 | options.insert(option("password_y","-1")); 104 | options.insert(option("password_msg","Please enter your password")); 105 | 106 | options.insert(option("msg_color","#FFFFFF")); 107 | options.insert(option("msg_font","Verdana:size=16:bold")); 108 | options.insert(option("msg_x","40")); 109 | options.insert(option("msg_y","40")); 110 | options.insert(option("msg_shadow_xoffset", "0")); 111 | options.insert(option("msg_shadow_yoffset", "0")); 112 | options.insert(option("msg_shadow_color","#FFFFFF")); 113 | 114 | options.insert(option("session_color","#FFFFFF")); 115 | options.insert(option("session_font","Verdana:size=16:bold")); 116 | options.insert(option("session_x","50%")); 117 | options.insert(option("session_y","90%")); 118 | options.insert(option("session_shadow_xoffset", "0")); 119 | options.insert(option("session_shadow_yoffset", "0")); 120 | options.insert(option("session_shadow_color","#FFFFFF")); 121 | 122 | // slimlock-specific options 123 | options.insert(option("dpms_standby_timeout", "60")); 124 | options.insert(option("dpms_off_timeout", "600")); 125 | options.insert(option("wrong_passwd_timeout", "2")); 126 | options.insert(option("passwd_feedback_x", "50%")); 127 | options.insert(option("passwd_feedback_y", "10%")); 128 | options.insert(option("passwd_feedback_msg", "Authentication failed")); 129 | options.insert(option("passwd_feedback_capslock", "Authentication failed (CapsLock is on)")); 130 | options.insert(option("show_username", "1")); 131 | options.insert(option("show_welcome_msg", "0")); 132 | options.insert(option("tty_lock", "1")); 133 | options.insert(option("bell", "1")); 134 | 135 | error = ""; 136 | } 137 | 138 | Cfg::~Cfg() { 139 | options.clear(); 140 | } 141 | /* 142 | * Creates the Cfg object and parses 143 | * known options from the given configfile / themefile 144 | */ 145 | bool Cfg::readConf(string configfile) { 146 | int n = -1; 147 | size_t pos = 0; 148 | string line, next, op, fn(configfile); 149 | map::iterator it; 150 | ifstream cfgfile(fn.c_str()); 151 | 152 | if (!cfgfile) { 153 | error = "Cannot read configuration file: " + configfile; 154 | return false; 155 | } 156 | while (getline(cfgfile, line)) { 157 | if ((pos = line.find('\\')) != string::npos) { 158 | if (line.length() == pos + 1) { 159 | line.replace(pos, 1, " "); 160 | next = next + line; 161 | continue; 162 | } else 163 | line.replace(pos, line.length() - pos, " "); 164 | } 165 | 166 | if (!next.empty()) { 167 | line = next + line; 168 | next = ""; 169 | } 170 | it = options.begin(); 171 | while (it != options.end()) { 172 | op = it->first; 173 | n = line.find(op); 174 | if (n == 0) 175 | options[op] = parseOption(line, op); 176 | ++it; 177 | } 178 | } 179 | cfgfile.close(); 180 | 181 | fillSessionList(); 182 | 183 | return true; 184 | } 185 | 186 | /* Returns the option value, trimmed */ 187 | string Cfg::parseOption(string line, string option ) { 188 | return Trim( line.substr(option.size(), line.size() - option.size())); 189 | } 190 | 191 | const string& Cfg::getError() const { 192 | return error; 193 | } 194 | 195 | string& Cfg::getOption(string option) { 196 | return options[option]; 197 | } 198 | 199 | /* return a trimmed string */ 200 | string Cfg::Trim( const string& s ) { 201 | if ( s.empty() ) { 202 | return s; 203 | } 204 | int pos = 0; 205 | string line = s; 206 | int len = line.length(); 207 | while ( pos < len && isspace( line[pos] ) ) { 208 | ++pos; 209 | } 210 | line.erase( 0, pos ); 211 | pos = line.length()-1; 212 | while ( pos > -1 && isspace( line[pos] ) ) { 213 | --pos; 214 | } 215 | if ( pos != -1 ) { 216 | line.erase( pos+1 ); 217 | } 218 | return line; 219 | } 220 | 221 | /* Return the welcome message with replaced vars */ 222 | string Cfg::getWelcomeMessage(){ 223 | string s = getOption("welcome_msg"); 224 | int n = s.find("%host"); 225 | if (n >= 0) { 226 | string tmp = s.substr(0, n); 227 | char host[40]; 228 | gethostname(host,40); 229 | tmp = tmp + host; 230 | tmp = tmp + s.substr(n+5, s.size() - n); 231 | s = tmp; 232 | } 233 | n = s.find("%domain"); 234 | if (n >= 0) { 235 | string tmp = s.substr(0, n);; 236 | char domain[40]; 237 | getdomainname(domain,40); 238 | tmp = tmp + domain; 239 | tmp = tmp + s.substr(n+7, s.size() - n); 240 | s = tmp; 241 | } 242 | return s; 243 | } 244 | 245 | int Cfg::string2int(const char* string, bool* ok) { 246 | char* err = 0; 247 | int l = (int)strtol(string, &err, 10); 248 | if (ok) { 249 | *ok = (*err == 0); 250 | } 251 | return (*err == 0) ? l : 0; 252 | } 253 | 254 | int Cfg::getIntOption(std::string option) { 255 | return string2int(options[option].c_str()); 256 | } 257 | 258 | /* Get absolute position */ 259 | int Cfg::absolutepos(const string& position, int max, int width) { 260 | int n = position.find("%"); 261 | if (n>0) { /* X Position expressed in percentage */ 262 | int result = (max*string2int(position.substr(0, n).c_str())/100) - (width / 2); 263 | return result < 0 ? 0 : result ; 264 | } else { /* Absolute X position */ 265 | return string2int(position.c_str()); 266 | } 267 | } 268 | 269 | /* split a comma separated string into a vector of strings */ 270 | void Cfg::split(vector& v, const string& str, char c, bool useEmpty) { 271 | v.clear(); 272 | string::const_iterator s = str.begin(); 273 | string tmp; 274 | while (true) { 275 | string::const_iterator begin = s; 276 | while (*s != c && s != str.end()) { ++s; } 277 | tmp = string(begin, s); 278 | if (useEmpty || tmp.size() > 0) 279 | v.push_back(tmp); 280 | if (s == str.end()) { 281 | break; 282 | } 283 | if (++s == str.end()) { 284 | if (useEmpty) 285 | v.push_back(""); 286 | break; 287 | } 288 | } 289 | } 290 | 291 | void Cfg::fillSessionList(){ 292 | string strSessionDir = getOption("sessiondir"); 293 | 294 | sessions.clear(); 295 | 296 | if( !strSessionDir.empty() ) { 297 | DIR *pDir = opendir(strSessionDir.c_str()); 298 | 299 | if (pDir != NULL) { 300 | struct dirent *pDirent = NULL; 301 | 302 | while ((pDirent = readdir(pDir)) != NULL) { 303 | string strFile(strSessionDir); 304 | strFile += "/"; 305 | strFile += pDirent->d_name; 306 | 307 | struct stat oFileStat; 308 | 309 | if (stat(strFile.c_str(), &oFileStat) == 0) { 310 | if (S_ISREG(oFileStat.st_mode) && 311 | access(strFile.c_str(), R_OK) == 0){ 312 | ifstream desktop_file(strFile.c_str()); 313 | if (desktop_file){ 314 | string line, session_name = "", session_exec = ""; 315 | while (getline( desktop_file, line )) { 316 | if (line.substr(0, 5) == "Name=") { 317 | session_name = line.substr(5); 318 | if (!session_exec.empty()) 319 | break; 320 | } else 321 | if (line.substr(0, 5) == "Exec=") { 322 | session_exec = line.substr(5); 323 | if (!session_name.empty()) 324 | break; 325 | } 326 | } 327 | desktop_file.close(); 328 | pair session(session_name,session_exec); 329 | sessions.push_back(session); 330 | cout << session_exec << " - " << session_name << endl; 331 | } 332 | 333 | } 334 | } 335 | } 336 | closedir(pDir); 337 | } 338 | } 339 | 340 | if (sessions.empty()){ 341 | pair session("",""); 342 | sessions.push_back(session); 343 | } 344 | } 345 | 346 | pair Cfg::nextSession() { 347 | currentSession = (currentSession + 1) % sessions.size(); 348 | return sessions[currentSession]; 349 | } 350 | -------------------------------------------------------------------------------- /cfg.h: -------------------------------------------------------------------------------- 1 | /* SLiM - Simple Login Manager 2 | Copyright (C) 2004-06 Simone Rota 3 | Copyright (C) 2004-06 Johannes Winkelmann 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | */ 10 | 11 | #ifndef _CFG_H_ 12 | #define _CFG_H_ 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | #define INPUT_MAXLENGTH_NAME 30 19 | #define INPUT_MAXLENGTH_PASSWD 50 20 | 21 | #define CFGFILE SYSCONFDIR"/slim.conf" 22 | #define THEMESDIR PKGDATADIR"/themes" 23 | #define THEMESFILE "/slim.theme" 24 | 25 | class Cfg { 26 | 27 | public: 28 | Cfg(); 29 | ~Cfg(); 30 | 31 | bool readConf(std::string configfile); 32 | std::string parseOption(std::string line, std::string option); 33 | const std::string& getError() const; 34 | std::string& getOption(std::string option); 35 | int getIntOption(std::string option); 36 | std::string getWelcomeMessage(); 37 | 38 | static int absolutepos(const std::string &position, int max, int width); 39 | static int string2int(const char *string, bool *ok = 0); 40 | static void split(std::vector &v, const std::string &str, 41 | char c, bool useEmpty=true); 42 | static std::string Trim(const std::string &s); 43 | 44 | std::pair nextSession(); 45 | 46 | private: 47 | void fillSessionList(); 48 | 49 | private: 50 | std::map options; 51 | std::vector > sessions; 52 | int currentSession; 53 | std::string error; 54 | }; 55 | 56 | #endif /* _CFG_H_ */ 57 | -------------------------------------------------------------------------------- /cmake/modules/FONTCONFIGConfig.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Find the native FONTCONFIG includes and library 3 | # 4 | 5 | # This module defines 6 | # FONTCONFIG_INCLUDE_DIR, where to find art*.h etc 7 | # FONTCONFIG_LIBRARY, the libraries to link against to use FONTCONFIG. 8 | # FONTCONFIG_FOUND, If false, do not try to use FONTCONFIG. 9 | # LIBFONTCONFIG_LIBS, link information 10 | # LIBFONTCONFIG_CFLAGS, cflags for include information 11 | 12 | IF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} LESS 2.5) 13 | INCLUDE(UsePkgConfig) 14 | PKGCONFIG(fontconfig _fontconfigIncDir _fontconfigLinkDir _fontconfigLinkFlags _fontconfigCflags) 15 | SET(FONTCONFIG_LIBS ${_fontconfigCflags}) 16 | ELSE (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} LESS 2.5) 17 | INCLUDE(FindPkgConfig) 18 | pkg_search_module(FONTCONFIG REQUIRED fontconfig) 19 | ENDIF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} LESS 2.5) 20 | 21 | #INCLUDE(UsePkgConfig) 22 | 23 | # use pkg-config to get the directories and then use these values 24 | # in the FIND_PATH() and FIND_LIBRARY() calls 25 | #PKGCONFIG(fontconfig _fontconfigIncDir _fontconfigLinkDir _fontconfigLinkFlags _fontconfigCflags) 26 | 27 | #SET(FONTCONFIG_LIBS ${_fontconfigCflags}) 28 | 29 | IF(BUILD_OSX_BUNDLE) 30 | FIND_PATH(FONTCONFIG_INCLUDE_DIR 31 | NAMES fontconfig/fontconfig.h 32 | PATHS ${FONTCONFIG_INCLUDE_DIRS} /opt/local/include 33 | NO_DEFAULT_PATH 34 | ) 35 | FIND_LIBRARY(FONTCONFIG_LIBRARY 36 | NAMES fontconfig 37 | PATHS ${FONTCONFIG_LIBRARY_DIRS} /opt/local/lib 38 | NO_DEFAULT_PATH 39 | ) 40 | ELSE(BUILD_OSX_BUNDLE) 41 | FIND_PATH(FONTCONFIG_INCLUDE_DIR 42 | NAMES fontconfig/fontconfig.h 43 | PATHS ${FONTCONFIG_INCLUDE_DIRS} 44 | ${_fontconfigIncDir} 45 | /usr/include 46 | /usr/local/include 47 | PATH_SUFFIXES fontconfig 48 | ) 49 | # quick hack as the above finds it nicely but our source includes the libart_lgpl text at the moment 50 | #STRING(REGEX REPLACE "/libart_lgpl" "" FONTCONFIG_INCLUDE_DIR ${FONTCONFIG_INCLUDE_DIR}) 51 | FIND_LIBRARY(FONTCONFIG_LIBRARY NAMES fontconfig 52 | PATHS ${FONTCONFIG_LIBRARY_DIRS} /usr/lib /usr/local/lib 53 | ) 54 | ENDIF(BUILD_OSX_BUNDLE) 55 | 56 | 57 | # MESSAGE(STATUS "fclib ${FONTCONFIG_LIBRARY}") 58 | # MESSAGE(STATUS "fcinclude ${FONTCONFIG_INCLUDE_DIR}") 59 | 60 | 61 | IF (FONTCONFIG_LIBRARY) 62 | IF (FONTCONFIG_INCLUDE_DIR) 63 | SET( FONTCONFIG_FOUND "YES" ) 64 | SET( FONTCONFIG_LIBRARIES ${FONTCONFIG_LIBRARY} ) 65 | FIND_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) 66 | # EXEC_PROGRAM(${FONTCONFIG_CONFIG} ARGS --libs OUTPUT_VARIABLE FONTCONFIG_LIBS) 67 | # EXEC_PROGRAM(${FONTCONFIG_CONFIG} ARGS --cflags OUTPUT_VARIABLE FONTCONFIG_CFLAGS) 68 | # MESSAGE(STATUS ${FONTCONFIG_LIBS}) 69 | # MESSAGE(STATUS ${FONTCONFIG_CFLAGS}) 70 | ENDIF (FONTCONFIG_INCLUDE_DIR) 71 | ENDIF (FONTCONFIG_LIBRARY) 72 | -------------------------------------------------------------------------------- /cmake/modules/FindCkConnector.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find the ConsoleKit connector library (libck-connector) 2 | # Once done this will define 3 | # 4 | # CKCONNECTOR_FOUND - system has the CK Connector 5 | # CKCONNECTOR_INCLUDE_DIR - the CK Connector include directory 6 | # CKCONNECTOR_LIBRARIES - the libraries needed to use CK Connector 7 | 8 | # Copyright (c) 2008, Kevin Kofler, 9 | # modeled after FindLibArt.cmake: 10 | # Copyright (c) 2006, Alexander Neundorf, 11 | # 12 | # Redistribution and use is allowed according to the terms of the BSD license. 13 | # For details see the accompanying COPYING-CMAKE-SCRIPTS file. 14 | 15 | 16 | if (CKCONNECTOR_INCLUDE_DIR AND CKCONNECTOR_LIBRARIES) 17 | 18 | # in cache already 19 | SET(CKCONNECTOR_FOUND TRUE) 20 | 21 | else (CKCONNECTOR_INCLUDE_DIR AND CKCONNECTOR_LIBRARIES) 22 | 23 | IF (NOT WIN32) 24 | FIND_PACKAGE(PkgConfig) 25 | IF (PKG_CONFIG_FOUND) 26 | # use pkg-config to get the directories and then use these values 27 | # in the FIND_PATH() and FIND_LIBRARY() calls 28 | pkg_check_modules(_CKCONNECTOR_PC QUIET ck-connector) 29 | ENDIF (PKG_CONFIG_FOUND) 30 | ENDIF (NOT WIN32) 31 | 32 | FIND_PATH(CKCONNECTOR_INCLUDE_DIR ck-connector.h 33 | ${_CKCONNECTOR_PC_INCLUDE_DIRS} 34 | ) 35 | 36 | FIND_LIBRARY(CKCONNECTOR_LIBRARIES NAMES ck-connector 37 | PATHS 38 | ${_CKCONNECTOR_PC_LIBDIR} 39 | ) 40 | 41 | 42 | if (CKCONNECTOR_INCLUDE_DIR AND CKCONNECTOR_LIBRARIES) 43 | set(CKCONNECTOR_FOUND TRUE) 44 | endif (CKCONNECTOR_INCLUDE_DIR AND CKCONNECTOR_LIBRARIES) 45 | 46 | 47 | if (CKCONNECTOR_FOUND) 48 | if (NOT CkConnector_FIND_QUIETLY) 49 | message(STATUS "Found ck-connector: ${CKCONNECTOR_LIBRARIES}") 50 | endif (NOT CkConnector_FIND_QUIETLY) 51 | else (CKCONNECTOR_FOUND) 52 | if (CkConnector_FIND_REQUIRED) 53 | message(FATAL_ERROR "Could NOT find ck-connector") 54 | endif (CkConnector_FIND_REQUIRED) 55 | endif (CKCONNECTOR_FOUND) 56 | 57 | MARK_AS_ADVANCED(CKCONNECTOR_INCLUDE_DIR CKCONNECTOR_LIBRARIES) 58 | 59 | endif (CKCONNECTOR_INCLUDE_DIR AND CKCONNECTOR_LIBRARIES) 60 | -------------------------------------------------------------------------------- /cmake/modules/FindDBus.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find the low-level D-Bus library 2 | # Once done this will define 3 | # 4 | # DBUS_FOUND - system has D-Bus 5 | # DBUS_INCLUDE_DIR - the D-Bus include directory 6 | # DBUS_ARCH_INCLUDE_DIR - the D-Bus architecture-specific include directory 7 | # DBUS_LIBRARIES - the libraries needed to use D-Bus 8 | 9 | # Copyright (c) 2008, Kevin Kofler, 10 | # modeled after FindLibArt.cmake: 11 | # Copyright (c) 2006, Alexander Neundorf, 12 | # 13 | # Redistribution and use is allowed according to the terms of the BSD license. 14 | # For details see the accompanying COPYING-CMAKE-SCRIPTS file. 15 | 16 | if (DBUS_INCLUDE_DIR AND DBUS_ARCH_INCLUDE_DIR AND DBUS_LIBRARIES) 17 | 18 | # in cache already 19 | SET(DBUS_FOUND TRUE) 20 | 21 | else (DBUS_INCLUDE_DIR AND DBUS_ARCH_INCLUDE_DIR AND DBUS_LIBRARIES) 22 | 23 | IF (NOT WIN32) 24 | FIND_PACKAGE(PkgConfig) 25 | IF (PKG_CONFIG_FOUND) 26 | # use pkg-config to get the directories and then use these values 27 | # in the FIND_PATH() and FIND_LIBRARY() calls 28 | pkg_check_modules(_DBUS_PC QUIET dbus-1) 29 | ENDIF (PKG_CONFIG_FOUND) 30 | ENDIF (NOT WIN32) 31 | 32 | FIND_PATH(DBUS_INCLUDE_DIR dbus/dbus.h 33 | ${_DBUS_PC_INCLUDE_DIRS} 34 | /usr/include 35 | /usr/include/dbus-1.0 36 | /usr/local/include 37 | ) 38 | 39 | FIND_PATH(DBUS_ARCH_INCLUDE_DIR dbus/dbus-arch-deps.h 40 | ${_DBUS_PC_INCLUDE_DIRS} 41 | /usr/lib${LIB_SUFFIX}/include 42 | /usr/lib${LIB_SUFFIX}/dbus-1.0/include 43 | /usr/lib64/include 44 | /usr/lib64/dbus-1.0/include 45 | /usr/lib/include 46 | /usr/lib/dbus-1.0/include 47 | ) 48 | 49 | FIND_LIBRARY(DBUS_LIBRARIES NAMES dbus-1 dbus 50 | PATHS 51 | ${_DBUS_PC_LIBDIR} 52 | ) 53 | 54 | 55 | if (DBUS_INCLUDE_DIR AND DBUS_ARCH_INCLUDE_DIR AND DBUS_LIBRARIES) 56 | set(DBUS_FOUND TRUE) 57 | endif (DBUS_INCLUDE_DIR AND DBUS_ARCH_INCLUDE_DIR AND DBUS_LIBRARIES) 58 | 59 | 60 | if (DBUS_FOUND) 61 | if (NOT DBus_FIND_QUIETLY) 62 | message(STATUS "Found D-Bus: ${DBUS_LIBRARIES}") 63 | endif (NOT DBus_FIND_QUIETLY) 64 | else (DBUS_FOUND) 65 | if (DBus_FIND_REQUIRED) 66 | message(FATAL_ERROR "Could NOT find D-Bus") 67 | endif (DBus_FIND_REQUIRED) 68 | endif (DBUS_FOUND) 69 | 70 | MARK_AS_ADVANCED(DBUS_INCLUDE_DIR DBUS_ARCH_INCLUDE_DIR DBUS_LIBRARIES) 71 | 72 | endif (DBUS_INCLUDE_DIR AND DBUS_ARCH_INCLUDE_DIR AND DBUS_LIBRARIES) 73 | -------------------------------------------------------------------------------- /cmake/modules/FindPAM.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find the PAM libraries 2 | # Once done this will define 3 | # 4 | # PAM_FOUND - system has pam 5 | # PAM_INCLUDE_DIR - the pam include directory 6 | # PAM_LIBRARIES - libpam library 7 | 8 | if (PAM_INCLUDE_DIR AND PAM_LIBRARY) 9 | # Already in cache, be silent 10 | set(PAM_FIND_QUIETLY TRUE) 11 | endif (PAM_INCLUDE_DIR AND PAM_LIBRARY) 12 | 13 | find_path(PAM_INCLUDE_DIR NAMES security/pam_appl.h pam/pam_appl.h) 14 | find_library(PAM_LIBRARY pam) 15 | find_library(DL_LIBRARY dl) 16 | 17 | if (PAM_INCLUDE_DIR AND PAM_LIBRARY) 18 | set(PAM_FOUND TRUE) 19 | if (DL_LIBRARY) 20 | set(PAM_LIBRARIES ${PAM_LIBRARY} ${DL_LIBRARY}) 21 | else (DL_LIBRARY) 22 | set(PAM_LIBRARIES ${PAM_LIBRARY}) 23 | endif (DL_LIBRARY) 24 | 25 | if (EXISTS ${PAM_INCLUDE_DIR}/pam/pam_appl.h) 26 | # darwin claims to be something special 27 | set(HAVE_PAM_PAM_APPL_H 1) 28 | endif (EXISTS ${PAM_INCLUDE_DIR}/pam/pam_appl.h) 29 | 30 | if (NOT DEFINED PAM_MESSAGE_CONST) 31 | include(CheckCXXSourceCompiles) 32 | # XXX does this work with plain c? 33 | check_cxx_source_compiles(" 34 | #if ${HAVE_PAM_PAM_APPL_H}+0 35 | # include 36 | #else 37 | # include 38 | #endif 39 | 40 | static int PAM_conv( 41 | int num_msg, 42 | const struct pam_message **msg, /* this is the culprit */ 43 | struct pam_response **resp, 44 | void *ctx) 45 | { 46 | return 0; 47 | } 48 | 49 | int main(void) 50 | { 51 | struct pam_conv PAM_conversation = { 52 | &PAM_conv, /* this bombs out if the above does not match */ 53 | 0 54 | }; 55 | 56 | return 0; 57 | } 58 | " PAM_MESSAGE_CONST) 59 | endif (NOT DEFINED PAM_MESSAGE_CONST) 60 | set(PAM_MESSAGE_CONST ${PAM_MESSAGE_CONST} CACHE BOOL "PAM expects a conversation function with const pam_message") 61 | 62 | endif (PAM_INCLUDE_DIR AND PAM_LIBRARY) 63 | 64 | if (PAM_FOUND) 65 | if (NOT PAM_FIND_QUIETLY) 66 | message(STATUS "Found PAM: ${PAM_LIBRARIES}") 67 | endif (NOT PAM_FIND_QUIETLY) 68 | else (PAM_FOUND) 69 | if (PAM_FIND_REQUIRED) 70 | message(FATAL_ERROR "PAM was not found") 71 | endif(PAM_FIND_REQUIRED) 72 | endif (PAM_FOUND) 73 | 74 | mark_as_advanced(PAM_INCLUDE_DIR PAM_LIBRARY DL_LIBRARY PAM_MESSAGE_CONST) -------------------------------------------------------------------------------- /const.h: -------------------------------------------------------------------------------- 1 | /* SLiM - Simple Login Manager 2 | Copyright (C) 1997, 1998 Per Liden 3 | Copyright (C) 2004-06 Simone Rota 4 | Copyright (C) 2004-06 Johannes Winkelmann 5 | 6 | This program is free software; you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation; either version 2 of the License, or 9 | (at your option) any later version. 10 | */ 11 | 12 | #ifndef _CONST_H_ 13 | #define _CONST_H_ 14 | 15 | #define APPNAME "slim" 16 | #define DISPLAY ":0.0" 17 | 18 | #define CONSOLE_STR "console" 19 | #define HALT_STR "halt" 20 | #define REBOOT_STR "reboot" 21 | #define EXIT_STR "exit" 22 | #define SUSPEND_STR "suspend" 23 | 24 | #define HIDE 0 25 | #define SHOW 1 26 | 27 | #define GET_NAME 0 28 | #define GET_PASSWD 1 29 | 30 | #define OK_EXIT 0 31 | #define ERR_EXIT 1 32 | 33 | /* duration for showing error messages, 34 | * as "login command failed", in seconds 35 | */ 36 | #define ERROR_DURATION 5 37 | 38 | /* variables replaced in login_cmd */ 39 | #define SESSION_VAR "%session" 40 | #define THEME_VAR "%theme" 41 | 42 | /* variables replaced in pre-session_cmd and post-session_cmd */ 43 | #define USER_VAR "%user" 44 | 45 | /* max height/width for images */ 46 | #define MAX_DIMENSION 10000 47 | 48 | #endif /* _CONST_H_ */ 49 | -------------------------------------------------------------------------------- /image.cpp: -------------------------------------------------------------------------------- 1 | /* SLiM - Simple Login Manager 2 | Copyright (C) 2004-06 Simone Rota 3 | Copyright (C) 2004-06 Johannes Winkelmann 4 | Copyright (C) 2012 Nobuhiro Iwamatsu 5 | 6 | This program is free software; you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation; either version 2 of the License, or 9 | (at your option) any later version. 10 | 11 | The following code has been adapted and extended from 12 | xplanet 1.0.1, Copyright (C) 2002-04 Hari Nair 13 | */ 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | using namespace std; 23 | 24 | #include "image.h" 25 | 26 | extern "C" { 27 | #include 28 | #include 29 | } 30 | 31 | Image::Image() : width(0), height(0), area(0), 32 | rgb_data(NULL), png_alpha(NULL), quality_(80) {} 33 | 34 | Image::Image(const int w, const int h, const unsigned char *rgb, const unsigned char *alpha) : 35 | width(w), height(h), area(w*h), quality_(80) { 36 | width = w; 37 | height = h; 38 | area = w * h; 39 | 40 | rgb_data = (unsigned char *) malloc(3 * area); 41 | memcpy(rgb_data, rgb, 3 * area); 42 | 43 | if (alpha == NULL) { 44 | png_alpha = NULL; 45 | } else { 46 | png_alpha = (unsigned char *) malloc(area); 47 | memcpy(png_alpha, alpha, area); 48 | } 49 | } 50 | 51 | Image::~Image() { 52 | free(rgb_data); 53 | free(png_alpha); 54 | } 55 | 56 | bool 57 | Image::Read(const char *filename) { 58 | char buf[4]; 59 | unsigned char *ubuf = (unsigned char *) buf; 60 | int success = 0; 61 | 62 | FILE *file; 63 | file = fopen(filename, "rb"); 64 | if (file == NULL) 65 | return(false); 66 | 67 | /* see what kind of file we have */ 68 | 69 | fread(buf, 1, 4, file); 70 | fclose(file); 71 | 72 | if ((ubuf[0] == 0x89) && !strncmp("PNG", buf+1, 3)) 73 | success = readPng(filename, &width, &height, &rgb_data, &png_alpha); 74 | else if ((ubuf[0] == 0xff) && (ubuf[1] == 0xd8)) 75 | success = readJpeg(filename, &width, &height, &rgb_data); 76 | else { 77 | fprintf(stderr, "Unknown image format\n"); 78 | success = 0; 79 | } 80 | return(success == 1); 81 | } 82 | 83 | void 84 | Image::Reduce(const int factor) { 85 | if (factor < 1) 86 | return; 87 | 88 | int scale = 1; 89 | for (int i = 0; i < factor; i++) 90 | scale *= 2; 91 | 92 | double scale2 = scale*scale; 93 | 94 | int w = width / scale; 95 | int h = height / scale; 96 | int new_area = w * h; 97 | 98 | unsigned char *new_rgb = (unsigned char *) malloc(3 * new_area); 99 | memset(new_rgb, 0, 3 * new_area); 100 | 101 | unsigned char *new_alpha = NULL; 102 | if (png_alpha != NULL) { 103 | new_alpha = (unsigned char *) malloc(new_area); 104 | memset(new_alpha, 0, new_area); 105 | } 106 | 107 | int ipos = 0; 108 | for (int j = 0; j < height; j++) { 109 | int js = j / scale; 110 | for (int i = 0; i < width; i++) { 111 | int is = i/scale; 112 | for (int k = 0; k < 3; k++) 113 | new_rgb[3*(js * w + is) + k] += static_cast ((rgb_data[3*ipos + k] + 0.5) / scale2); 114 | 115 | if (png_alpha != NULL) 116 | new_alpha[js * w + is] += static_cast (png_alpha[ipos]/scale2); 117 | ipos++; 118 | } 119 | } 120 | 121 | free(rgb_data); 122 | free(png_alpha); 123 | 124 | rgb_data = new_rgb; 125 | png_alpha = new_alpha; 126 | width = w; 127 | height = h; 128 | 129 | area = w * h; 130 | } 131 | 132 | void 133 | Image::Resize(const int w, const int h) { 134 | 135 | if (width==w && height==h){ 136 | return; 137 | } 138 | 139 | int new_area = w * h; 140 | 141 | unsigned char *new_rgb = (unsigned char *) malloc(3 * new_area); 142 | unsigned char *new_alpha = NULL; 143 | if (png_alpha != NULL) 144 | new_alpha = (unsigned char *) malloc(new_area); 145 | 146 | const double scale_x = ((double) w) / width; 147 | const double scale_y = ((double) h) / height; 148 | 149 | int ipos = 0; 150 | for (int j = 0; j < h; j++) { 151 | const double y = j / scale_y; 152 | for (int i = 0; i < w; i++) { 153 | const double x = i / scale_x; 154 | if (new_alpha == NULL) 155 | getPixel(x, y, new_rgb + 3*ipos); 156 | else 157 | getPixel(x, y, new_rgb + 3*ipos, new_alpha + ipos); 158 | ipos++; 159 | } 160 | } 161 | 162 | free(rgb_data); 163 | free(png_alpha); 164 | 165 | rgb_data = new_rgb; 166 | png_alpha = new_alpha; 167 | width = w; 168 | height = h; 169 | 170 | area = w * h; 171 | } 172 | 173 | /* Find the color of the desired point using bilinear interpolation. */ 174 | /* Assume the array indices refer to the denter of the pixel, so each */ 175 | /* pixel has corners at (i - 0.5, j - 0.5) and (i + 0.5, j + 0.5) */ 176 | void 177 | Image::getPixel(double x, double y, unsigned char *pixel) { 178 | getPixel(x, y, pixel, NULL); 179 | } 180 | 181 | void 182 | Image::getPixel(double x, double y, unsigned char *pixel, unsigned char *alpha) { 183 | if (x < -0.5) 184 | x = -0.5; 185 | if (x >= width - 0.5) 186 | x = width - 0.5; 187 | 188 | if (y < -0.5) 189 | y = -0.5; 190 | if (y >= height - 0.5) 191 | y = height - 0.5; 192 | 193 | int ix0 = (int) (floor(x)); 194 | int ix1 = ix0 + 1; 195 | if (ix0 < 0) 196 | ix0 = width - 1; 197 | if (ix1 >= width) 198 | ix1 = 0; 199 | 200 | int iy0 = (int) (floor(y)); 201 | int iy1 = iy0 + 1; 202 | if (iy0 < 0) 203 | iy0 = 0; 204 | if (iy1 >= height) 205 | iy1 = height - 1; 206 | 207 | const double t = x - floor(x); 208 | const double u = 1 - (y - floor(y)); 209 | 210 | double weight[4]; 211 | weight[1] = t * u; 212 | weight[0] = u - weight[1]; 213 | weight[2] = 1 - t - u + weight[1]; 214 | weight[3] = t - weight[1]; 215 | 216 | unsigned char *pixels[4]; 217 | pixels[0] = rgb_data + 3 * (iy0 * width + ix0); 218 | pixels[1] = rgb_data + 3 * (iy0 * width + ix1); 219 | pixels[2] = rgb_data + 3 * (iy1 * width + ix0); 220 | pixels[3] = rgb_data + 3 * (iy1 * width + ix1); 221 | 222 | memset(pixel, 0, 3); 223 | for (int i = 0; i < 4; i++) { 224 | for (int j = 0; j < 3; j++) 225 | pixel[j] += (unsigned char) (weight[i] * pixels[i][j]); 226 | } 227 | 228 | if (alpha != NULL) { 229 | unsigned char pixels[4]; 230 | pixels[0] = png_alpha[iy0 * width + ix0]; 231 | pixels[1] = png_alpha[iy0 * width + ix1]; 232 | pixels[2] = png_alpha[iy0 * width + ix0]; 233 | pixels[3] = png_alpha[iy1 * width + ix1]; 234 | 235 | for (int i = 0; i < 4; i++) 236 | *alpha = (unsigned char) (weight[i] * pixels[i]); 237 | } 238 | } 239 | 240 | /* Merge the image with a background, taking care of the 241 | * image Alpha transparency. (background alpha is ignored). 242 | * The images is merged on position (x, y) on the 243 | * background, the background must contain the image. 244 | */ 245 | void Image::Merge(Image* background, const int x, const int y) { 246 | 247 | if (x + width > background->Width()|| y + height > background->Height()) 248 | return; 249 | 250 | if (background->Width()*background->Height() != width*height) 251 | background->Crop(x, y, width, height); 252 | 253 | double tmp; 254 | unsigned char *new_rgb = (unsigned char *) malloc(3 * width * height); 255 | memset(new_rgb, 0, 3 * width * height); 256 | const unsigned char *bg_rgb = background->getRGBData(); 257 | 258 | int ipos = 0; 259 | if (png_alpha != NULL){ 260 | for (int j = 0; j < height; j++) { 261 | for (int i = 0; i < width; i++) { 262 | for (int k = 0; k < 3; k++) { 263 | tmp = rgb_data[3*ipos + k]*png_alpha[ipos]/255.0 264 | + bg_rgb[3*ipos + k]*(1-png_alpha[ipos]/255.0); 265 | new_rgb[3*ipos + k] = static_cast (tmp); 266 | } 267 | ipos++; 268 | } 269 | } 270 | } else { 271 | for (int j = 0; j < height; j++) { 272 | for (int i = 0; i < width; i++) { 273 | for (int k = 0; k < 3; k++) { 274 | tmp = rgb_data[3*ipos + k]; 275 | new_rgb[3*ipos + k] = static_cast (tmp); 276 | } 277 | ipos++; 278 | } 279 | } 280 | } 281 | 282 | free(rgb_data); 283 | free(png_alpha); 284 | rgb_data = new_rgb; 285 | png_alpha = NULL; 286 | 287 | } 288 | 289 | /* Merge the image with a background, taking care of the 290 | * image Alpha transparency. (background alpha is ignored). 291 | * The images is merged on position (x, y) on the 292 | * background, the background must contain the image. 293 | */ 294 | #define IMG_POS_RGB(p, x) (3 * p + x) 295 | void Image::Merge_non_crop(Image* background, const int x, const int y) 296 | { 297 | int bg_w = background->Width(); 298 | int bg_h = background->Height(); 299 | 300 | if (x + width > bg_w || y + height > bg_h) 301 | return; 302 | 303 | double tmp; 304 | unsigned char *new_rgb = (unsigned char *)malloc(3 * bg_w * bg_h); 305 | const unsigned char *bg_rgb = background->getRGBData(); 306 | int pnl_pos = 0; 307 | int bg_pos = 0; 308 | int pnl_w_end = x + width; 309 | int pnl_h_end = y + height; 310 | 311 | memcpy(new_rgb, bg_rgb, 3 * bg_w * bg_h); 312 | 313 | for (int j = 0; j < bg_h; j++) { 314 | for (int i = 0; i < bg_w; i++) { 315 | if (j >= y && i >= x && j < pnl_h_end && i < pnl_w_end ) { 316 | for (int k = 0; k < 3; k++) { 317 | if (png_alpha != NULL) 318 | tmp = rgb_data[IMG_POS_RGB(pnl_pos, k)] 319 | * png_alpha[pnl_pos]/255.0 320 | + bg_rgb[IMG_POS_RGB(bg_pos, k)] 321 | * (1 - png_alpha[pnl_pos]/255.0); 322 | else 323 | tmp = rgb_data[IMG_POS_RGB(pnl_pos, k)]; 324 | 325 | new_rgb[IMG_POS_RGB(bg_pos, k)] = static_cast(tmp); 326 | } 327 | pnl_pos++; 328 | } 329 | bg_pos++; 330 | } 331 | } 332 | 333 | width = bg_w; 334 | height = bg_h; 335 | 336 | free(rgb_data); 337 | free(png_alpha); 338 | rgb_data = new_rgb; 339 | png_alpha = NULL; 340 | } 341 | 342 | /* Tile the image growing its size to the minimum entire 343 | * multiple of w * h. 344 | * The new dimensions should be > of the current ones. 345 | * Note that this flattens image (alpha removed) 346 | */ 347 | void Image::Tile(const int w, const int h) { 348 | 349 | if (w < width || h < height) 350 | return; 351 | 352 | int nx = w / width; 353 | if (w % width > 0) 354 | nx++; 355 | int ny = h / height; 356 | if (h % height > 0) 357 | ny++; 358 | 359 | int newwidth = nx*width; 360 | int newheight=ny*height; 361 | 362 | unsigned char *new_rgb = (unsigned char *) malloc(3 * newwidth * newheight); 363 | memset(new_rgb, 0, 3 * width * height * nx * ny); 364 | 365 | int ipos = 0; 366 | int opos = 0; 367 | 368 | for (int r = 0; r < ny; r++) { 369 | for (int c = 0; c < nx; c++) { 370 | for (int j = 0; j < height; j++) { 371 | for (int i = 0; i < width; i++) { 372 | opos = j*width + i; 373 | ipos = r*width*height*nx + j*newwidth + c*width +i; 374 | for (int k = 0; k < 3; k++) { 375 | new_rgb[3*ipos + k] = static_cast (rgb_data[3*opos + k]); 376 | } 377 | } 378 | } 379 | } 380 | } 381 | 382 | free(rgb_data); 383 | free(png_alpha); 384 | rgb_data = new_rgb; 385 | png_alpha = NULL; 386 | width = newwidth; 387 | height = newheight; 388 | area = width * height; 389 | Crop(0,0,w,h); 390 | 391 | } 392 | 393 | /* Crop the image 394 | */ 395 | void Image::Crop(const int x, const int y, const int w, const int h) { 396 | 397 | if (x+w > width || y+h > height) { 398 | return; 399 | } 400 | 401 | int x2 = x + w; 402 | int y2 = y + h; 403 | unsigned char *new_rgb = (unsigned char *) malloc(3 * w * h); 404 | memset(new_rgb, 0, 3 * w * h); 405 | unsigned char *new_alpha = NULL; 406 | if (png_alpha != NULL) { 407 | new_alpha = (unsigned char *) malloc(w * h); 408 | memset(new_alpha, 0, w * h); 409 | } 410 | 411 | int ipos = 0; 412 | int opos = 0; 413 | 414 | for (int j = 0; j < height; j++) { 415 | for (int i = 0; i < width; i++) { 416 | if (j>=y && i>=x && j (rgb_data[3*opos + k]); 419 | } 420 | if (png_alpha != NULL) 421 | new_alpha[ipos] = static_cast (png_alpha[opos]); 422 | ipos++; 423 | } 424 | opos++; 425 | } 426 | } 427 | 428 | free(rgb_data); 429 | free(png_alpha); 430 | rgb_data = new_rgb; 431 | if (png_alpha != NULL) 432 | png_alpha = new_alpha; 433 | width = w; 434 | height = h; 435 | area = w * h; 436 | 437 | 438 | } 439 | 440 | /* Center the image in a rectangle of given width and height. 441 | * Fills the remaining space (if any) with the hex color 442 | */ 443 | void Image::Center(const int w, const int h, const char *hex) { 444 | 445 | unsigned long packed_rgb; 446 | sscanf(hex, "%lx", &packed_rgb); 447 | 448 | unsigned long r = packed_rgb>>16; 449 | unsigned long g = packed_rgb>>8 & 0xff; 450 | unsigned long b = packed_rgb & 0xff; 451 | 452 | unsigned char *new_rgb = (unsigned char *) malloc(3 * w * h); 453 | memset(new_rgb, 0, 3 * w * h); 454 | 455 | int x = (w - width) / 2; 456 | int y = (h - height) / 2; 457 | 458 | if (x<0) { 459 | Crop((width - w)/2,0,w,height); 460 | x = 0; 461 | } 462 | if (y<0) { 463 | Crop(0,(height - h)/2,width,h); 464 | y = 0; 465 | } 466 | int x2 = x + width; 467 | int y2 = y + height; 468 | 469 | int ipos = 0; 470 | int opos = 0; 471 | double tmp; 472 | 473 | area = w * h; 474 | for (int i = 0; i < area; i++) { 475 | new_rgb[3*i] = r; 476 | new_rgb[3*i+1] = g; 477 | new_rgb[3*i+2] = b; 478 | } 479 | 480 | if (png_alpha != NULL) { 481 | for (int j = 0; j < h; j++) { 482 | for (int i = 0; i < w; i++) { 483 | if (j>=y && i>=x && j (tmp); 489 | } 490 | opos++; 491 | } 492 | 493 | } 494 | } 495 | } else { 496 | for (int j = 0; j < h; j++) { 497 | for (int i = 0; i < w; i++) { 498 | if (j>=y && i>=x && j (tmp); 503 | } 504 | opos++; 505 | } 506 | 507 | } 508 | } 509 | } 510 | 511 | free(rgb_data); 512 | free(png_alpha); 513 | rgb_data = new_rgb; 514 | png_alpha = NULL; 515 | width = w; 516 | height = h; 517 | 518 | } 519 | 520 | /* Fill the image with the given color and adjust its dimensions 521 | * to passed values. 522 | */ 523 | void Image::Plain(const int w, const int h, const char *hex) { 524 | 525 | unsigned long packed_rgb; 526 | sscanf(hex, "%lx", &packed_rgb); 527 | 528 | unsigned long r = packed_rgb>>16; 529 | unsigned long g = packed_rgb>>8 & 0xff; 530 | unsigned long b = packed_rgb & 0xff; 531 | 532 | unsigned char *new_rgb = (unsigned char *) malloc(3 * w * h); 533 | memset(new_rgb, 0, 3 * w * h); 534 | 535 | area = w * h; 536 | for (int i = 0; i < area; i++) { 537 | new_rgb[3*i] = r; 538 | new_rgb[3*i+1] = g; 539 | new_rgb[3*i+2] = b; 540 | } 541 | 542 | free(rgb_data); 543 | free(png_alpha); 544 | rgb_data = new_rgb; 545 | png_alpha = NULL; 546 | width = w; 547 | height = h; 548 | } 549 | 550 | void 551 | Image::computeShift(unsigned long mask, 552 | unsigned char &left_shift, 553 | unsigned char &right_shift) { 554 | left_shift = 0; 555 | right_shift = 8; 556 | if (mask != 0) { 557 | while ((mask & 0x01) == 0) { 558 | left_shift++; 559 | mask >>= 1; 560 | } 561 | while ((mask & 0x01) == 1) { 562 | right_shift--; 563 | mask >>= 1; 564 | } 565 | } 566 | } 567 | 568 | Pixmap 569 | Image::createPixmap(Display* dpy, int scr, Window win) { 570 | int i, j; /* loop variables */ 571 | 572 | const int depth = DefaultDepth(dpy, scr); 573 | Visual *visual = DefaultVisual(dpy, scr); 574 | Colormap colormap = DefaultColormap(dpy, scr); 575 | 576 | Pixmap tmp = XCreatePixmap(dpy, win, width, height, 577 | depth); 578 | 579 | char *pixmap_data = NULL; 580 | switch (depth) { 581 | case 32: 582 | case 24: 583 | pixmap_data = new char[4 * width * height]; 584 | break; 585 | case 16: 586 | case 15: 587 | pixmap_data = new char[2 * width * height]; 588 | break; 589 | case 8: 590 | pixmap_data = new char[width * height]; 591 | break; 592 | default: 593 | break; 594 | } 595 | 596 | XImage *ximage = XCreateImage(dpy, visual, depth, ZPixmap, 0, 597 | pixmap_data, width, height, 598 | 8, 0); 599 | 600 | int entries; 601 | XVisualInfo v_template; 602 | v_template.visualid = XVisualIDFromVisual(visual); 603 | XVisualInfo *visual_info = XGetVisualInfo(dpy, VisualIDMask, 604 | &v_template, &entries); 605 | 606 | unsigned long ipos = 0; 607 | switch (visual_info->c_class) { 608 | case PseudoColor: { 609 | XColor xc; 610 | xc.flags = DoRed | DoGreen | DoBlue; 611 | 612 | int num_colors = 256; 613 | XColor *colors = new XColor[num_colors]; 614 | for (i = 0; i < num_colors; i++) 615 | colors[i].pixel = (unsigned long) i; 616 | XQueryColors(dpy, colormap, colors, num_colors); 617 | 618 | int *closest_color = new int[num_colors]; 619 | 620 | for (i = 0; i < num_colors; i++) { 621 | xc.red = (i & 0xe0) << 8; /* highest 3 bits */ 622 | xc.green = (i & 0x1c) << 11; /* middle 3 bits */ 623 | xc.blue = (i & 0x03) << 14; /* lowest 2 bits */ 624 | 625 | /* find the closest color in the colormap */ 626 | double distance, distance_squared, min_distance = 0; 627 | for (int ii = 0; ii < num_colors; ii++) { 628 | distance = colors[ii].red - xc.red; 629 | distance_squared = distance * distance; 630 | distance = colors[ii].green - xc.green; 631 | distance_squared += distance * distance; 632 | distance = colors[ii].blue - xc.blue; 633 | distance_squared += distance * distance; 634 | 635 | if ((ii == 0) || (distance_squared <= min_distance)) { 636 | min_distance = distance_squared; 637 | closest_color[i] = ii; 638 | } 639 | } 640 | } 641 | 642 | for (j = 0; j < height; j++) { 643 | for (i = 0; i < width; i++) { 644 | xc.red = (unsigned short) (rgb_data[ipos++] & 0xe0); 645 | xc.green = (unsigned short) (rgb_data[ipos++] & 0xe0); 646 | xc.blue = (unsigned short) (rgb_data[ipos++] & 0xc0); 647 | 648 | xc.pixel = xc.red | (xc.green >> 3) | (xc.blue >> 6); 649 | XPutPixel(ximage, i, j, 650 | colors[closest_color[xc.pixel]].pixel); 651 | } 652 | } 653 | delete [] colors; 654 | delete [] closest_color; 655 | } 656 | break; 657 | case TrueColor: { 658 | unsigned char red_left_shift; 659 | unsigned char red_right_shift; 660 | unsigned char green_left_shift; 661 | unsigned char green_right_shift; 662 | unsigned char blue_left_shift; 663 | unsigned char blue_right_shift; 664 | 665 | computeShift(visual_info->red_mask, red_left_shift, 666 | red_right_shift); 667 | computeShift(visual_info->green_mask, green_left_shift, 668 | green_right_shift); 669 | computeShift(visual_info->blue_mask, blue_left_shift, 670 | blue_right_shift); 671 | 672 | unsigned long pixel; 673 | unsigned long red, green, blue; 674 | for (j = 0; j < height; j++) { 675 | for (i = 0; i < width; i++) { 676 | red = (unsigned long) 677 | rgb_data[ipos++] >> red_right_shift; 678 | green = (unsigned long) 679 | rgb_data[ipos++] >> green_right_shift; 680 | blue = (unsigned long) 681 | rgb_data[ipos++] >> blue_right_shift; 682 | 683 | pixel = (((red << red_left_shift) & visual_info->red_mask) 684 | | ((green << green_left_shift) 685 | & visual_info->green_mask) 686 | | ((blue << blue_left_shift) 687 | & visual_info->blue_mask)); 688 | 689 | XPutPixel(ximage, i, j, pixel); 690 | } 691 | } 692 | } 693 | break; 694 | default: { 695 | logStream << "Login.app: could not load image" << endl; 696 | return(tmp); 697 | } 698 | } 699 | 700 | GC gc = XCreateGC(dpy, win, 0, NULL); 701 | XPutImage(dpy, tmp, gc, ximage, 0, 0, 0, 0, width, height); 702 | 703 | XFreeGC(dpy, gc); 704 | 705 | XFree(visual_info); 706 | 707 | delete [] pixmap_data; 708 | 709 | /* Set ximage data to NULL since pixmap data was deallocated above */ 710 | ximage->data = NULL; 711 | XDestroyImage(ximage); 712 | 713 | return(tmp); 714 | } 715 | 716 | int 717 | Image::readJpeg(const char *filename, int *width, int *height, 718 | unsigned char **rgb) 719 | { 720 | int ret = 0; 721 | struct jpeg_decompress_struct cinfo; 722 | struct jpeg_error_mgr jerr; 723 | unsigned char *ptr = NULL; 724 | 725 | FILE *infile = fopen(filename, "rb"); 726 | if (infile == NULL) { 727 | logStream << APPNAME << "Cannot fopen file: " << filename << endl; 728 | return ret; 729 | } 730 | 731 | cinfo.err = jpeg_std_error(&jerr); 732 | jpeg_create_decompress(&cinfo); 733 | jpeg_stdio_src(&cinfo, infile); 734 | jpeg_read_header(&cinfo, TRUE); 735 | jpeg_start_decompress(&cinfo); 736 | 737 | /* Prevent against integer overflow */ 738 | if(cinfo.output_width >= MAX_DIMENSION 739 | || cinfo.output_height >= MAX_DIMENSION) 740 | { 741 | logStream << APPNAME << "Unreasonable dimension found in file: " 742 | << filename << endl; 743 | goto close_file; 744 | } 745 | 746 | *width = cinfo.output_width; 747 | *height = cinfo.output_height; 748 | 749 | rgb[0] = (unsigned char*) 750 | malloc(3 * cinfo.output_width * cinfo.output_height); 751 | if (rgb[0] == NULL) { 752 | logStream << APPNAME << ": Can't allocate memory for JPEG file." 753 | << endl; 754 | goto close_file; 755 | } 756 | 757 | if (cinfo.output_components == 3) { 758 | ptr = rgb[0]; 759 | while (cinfo.output_scanline < cinfo.output_height) { 760 | jpeg_read_scanlines(&cinfo, &ptr, 1); 761 | ptr += 3 * cinfo.output_width; 762 | } 763 | } else if (cinfo.output_components == 1) { 764 | ptr = (unsigned char*) malloc(cinfo.output_width); 765 | if (ptr == NULL) { 766 | logStream << APPNAME << ": Can't allocate memory for JPEG file." 767 | << endl; 768 | goto rgb_free; 769 | } 770 | 771 | unsigned int ipos = 0; 772 | while (cinfo.output_scanline < cinfo.output_height) { 773 | jpeg_read_scanlines(&cinfo, &ptr, 1); 774 | 775 | for (unsigned int i = 0; i < cinfo.output_width; i++) { 776 | memset(rgb[0] + ipos, ptr[i], 3); 777 | ipos += 3; 778 | } 779 | } 780 | 781 | free(ptr); 782 | } 783 | 784 | jpeg_finish_decompress(&cinfo); 785 | 786 | ret = 1; 787 | goto close_file; 788 | 789 | rgb_free: 790 | free(rgb[0]); 791 | 792 | close_file: 793 | jpeg_destroy_decompress(&cinfo); 794 | fclose(infile); 795 | 796 | return(ret); 797 | } 798 | 799 | int 800 | Image::readPng(const char *filename, int *width, int *height, 801 | unsigned char **rgb, unsigned char **alpha) 802 | { 803 | int ret = 0; 804 | 805 | png_structp png_ptr; 806 | png_infop info_ptr; 807 | png_bytepp row_pointers; 808 | 809 | unsigned char *ptr = NULL; 810 | png_uint_32 w, h; 811 | int bit_depth, color_type, interlace_type; 812 | int i; 813 | 814 | FILE *infile = fopen(filename, "rb"); 815 | if (infile == NULL) { 816 | logStream << APPNAME << "Can not fopen file: " << filename << endl; 817 | return ret; 818 | } 819 | 820 | png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 821 | (png_voidp) NULL, 822 | (png_error_ptr) NULL, 823 | (png_error_ptr) NULL); 824 | if (!png_ptr) { 825 | goto file_close; 826 | } 827 | 828 | info_ptr = png_create_info_struct(png_ptr); 829 | if (!info_ptr) { 830 | png_destroy_read_struct(&png_ptr, (png_infopp) NULL, 831 | (png_infopp) NULL); 832 | } 833 | 834 | #if PNG_LIBPNG_VER_MAJOR >= 1 && PNG_LIBPNG_VER_MINOR >= 4 835 | if (setjmp(png_jmpbuf((png_ptr)))) { 836 | #else 837 | if (setjmp(png_ptr->jmpbuf)) { 838 | #endif 839 | goto png_destroy; 840 | } 841 | 842 | png_init_io(png_ptr, infile); 843 | png_read_info(png_ptr, info_ptr); 844 | 845 | png_get_IHDR(png_ptr, info_ptr, &w, &h, &bit_depth, &color_type, 846 | &interlace_type, (int *) NULL, (int *) NULL); 847 | 848 | /* Prevent against integer overflow */ 849 | if(w >= MAX_DIMENSION || h >= MAX_DIMENSION) { 850 | logStream << APPNAME << "Unreasonable dimension found in file: " 851 | << filename << endl; 852 | goto png_destroy; 853 | } 854 | 855 | *width = (int) w; 856 | *height = (int) h; 857 | 858 | if (color_type == PNG_COLOR_TYPE_RGB_ALPHA 859 | || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) 860 | { 861 | alpha[0] = (unsigned char *) malloc(*width * *height); 862 | if (alpha[0] == NULL) { 863 | logStream << APPNAME 864 | << ": Can't allocate memory for alpha channel in PNG file." 865 | << endl; 866 | goto png_destroy; 867 | } 868 | } 869 | 870 | /* Change a paletted/grayscale image to RGB */ 871 | if (color_type == PNG_COLOR_TYPE_PALETTE && bit_depth <= 8) 872 | { 873 | png_set_expand(png_ptr); 874 | } 875 | 876 | /* Change a grayscale image to RGB */ 877 | if (color_type == PNG_COLOR_TYPE_GRAY 878 | || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) 879 | { 880 | png_set_gray_to_rgb(png_ptr); 881 | } 882 | 883 | /* If the PNG file has 16 bits per channel, strip them down to 8 */ 884 | if (bit_depth == 16) { 885 | png_set_strip_16(png_ptr); 886 | } 887 | 888 | /* use 1 byte per pixel */ 889 | png_set_packing(png_ptr); 890 | 891 | row_pointers = (png_byte **) malloc(*height * sizeof(png_bytep)); 892 | if (row_pointers == NULL) { 893 | logStream << APPNAME << ": Can't allocate memory for PNG file." << endl; 894 | goto png_destroy; 895 | } 896 | 897 | for (i = 0; i < *height; i++) { 898 | row_pointers[i] = (png_byte*) malloc(4 * *width); 899 | if (row_pointers == NULL) { 900 | logStream << APPNAME << ": Can't allocate memory for PNG file." 901 | << endl; 902 | goto rows_free; 903 | } 904 | } 905 | 906 | png_read_image(png_ptr, row_pointers); 907 | 908 | rgb[0] = (unsigned char *) malloc(3 * (*width) * (*height)); 909 | if (rgb[0] == NULL) { 910 | logStream << APPNAME << ": Can't allocate memory for PNG file." << endl; 911 | goto rows_free; 912 | } 913 | 914 | if (alpha[0] == NULL) { 915 | ptr = rgb[0]; 916 | for (i = 0; i < *height; i++) { 917 | memcpy(ptr, row_pointers[i], 3 * (*width)); 918 | ptr += 3 * (*width); 919 | } 920 | } else { 921 | ptr = rgb[0]; 922 | for (i = 0; i < *height; i++) { 923 | unsigned int ipos = 0; 924 | for (int j = 0; j < *width; j++) { 925 | *ptr++ = row_pointers[i][ipos++]; 926 | *ptr++ = row_pointers[i][ipos++]; 927 | *ptr++ = row_pointers[i][ipos++]; 928 | alpha[0][i * (*width) + j] = row_pointers[i][ipos++]; 929 | } 930 | } 931 | } 932 | 933 | ret = 1; /* data reading is OK */ 934 | 935 | rows_free: 936 | for (i = 0; i < *height; i++) { 937 | if (row_pointers[i] != NULL ) { 938 | free(row_pointers[i]); 939 | } 940 | } 941 | 942 | free(row_pointers); 943 | 944 | png_destroy: 945 | png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL); 946 | 947 | file_close: 948 | fclose(infile); 949 | return(ret); 950 | } 951 | 952 | -------------------------------------------------------------------------------- /image.h: -------------------------------------------------------------------------------- 1 | /* SLiM - Simple Login Manager 2 | Copyright (C) 2004-06 Simone Rota 3 | Copyright (C) 2004-06 Johannes Winkelmann 4 | Copyright (C) 2012 Nobuhiro Iwamatsu 5 | 6 | This program is free software; you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation; either version 2 of the License, or 9 | (at your option) any later version. 10 | 11 | The following code has been adapted and extended from 12 | xplanet 1.0.1, Copyright (C) 2002-04 Hari Nair 13 | */ 14 | 15 | #ifndef _IMAGE_H_ 16 | #define _IMAGE_H_ 17 | 18 | #include 19 | #include 20 | #include "log.h" 21 | 22 | class Image { 23 | public: 24 | Image(); 25 | Image(const int w, const int h, const unsigned char *rgb, 26 | const unsigned char *alpha); 27 | 28 | ~Image(); 29 | 30 | const unsigned char *getPNGAlpha() const { 31 | return(png_alpha); 32 | }; 33 | const unsigned char *getRGBData() const { 34 | return(rgb_data); 35 | }; 36 | 37 | void getPixel(double px, double py, unsigned char *pixel); 38 | void getPixel(double px, double py, unsigned char *pixel, 39 | unsigned char *alpha); 40 | 41 | int Width() const { 42 | return(width); 43 | }; 44 | int Height() const { 45 | return(height); 46 | }; 47 | void Quality(const int q) { 48 | quality_ = q; 49 | }; 50 | 51 | bool Read(const char *filename); 52 | 53 | void Reduce(const int factor); 54 | void Resize(const int w, const int h); 55 | void Merge(Image *background, const int x, const int y); 56 | void Merge_non_crop(Image* background, const int x, const int y); 57 | void Crop(const int x, const int y, const int w, const int h); 58 | void Tile(const int w, const int h); 59 | void Center(const int w, const int h, const char *hex); 60 | void Plain(const int w, const int h, const char *hex); 61 | 62 | void computeShift(unsigned long mask, unsigned char &left_shift, 63 | unsigned char &right_shift); 64 | 65 | Pixmap createPixmap(Display *dpy, int scr, Window win); 66 | 67 | private: 68 | int width, height, area; 69 | unsigned char *rgb_data; 70 | unsigned char *png_alpha; 71 | 72 | int quality_; 73 | 74 | int readJpeg(const char *filename, int *width, int *height, 75 | unsigned char **rgb); 76 | int readPng(const char *filename, int *width, int *height, 77 | unsigned char **rgb, unsigned char **alpha); 78 | }; 79 | 80 | #endif /* _IMAGE_H_ */ 81 | -------------------------------------------------------------------------------- /jpeg.c: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | jpeg.c - read and write jpeg images using libjpeg routines 3 | Copyright (C) 2002 Hari Nair 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | ****************************************************************************/ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | #include "const.h" 26 | 27 | int 28 | read_jpeg(const char *filename, int *width, int *height, unsigned char **rgb) 29 | { 30 | int ret = 0; 31 | struct jpeg_decompress_struct cinfo; 32 | struct jpeg_error_mgr jerr; 33 | unsigned char *ptr = NULL; 34 | unsigned int i, ipos; 35 | 36 | FILE *infile = fopen(filename, "rb"); 37 | if (infile == NULL) { 38 | fprintf(stderr, "Can not fopen file: %s\n",filename); 39 | return ret; 40 | } 41 | 42 | cinfo.err = jpeg_std_error(&jerr); 43 | jpeg_create_decompress(&cinfo); 44 | jpeg_stdio_src(&cinfo, infile); 45 | jpeg_read_header(&cinfo, TRUE); 46 | jpeg_start_decompress(&cinfo); 47 | 48 | /* Prevent against integer overflow */ 49 | if(cinfo.output_width >= MAX_DIMENSION || cinfo.output_height >= MAX_DIMENSION) { 50 | fprintf(stderr, "Unreasonable dimension found in file: %s\n",filename); 51 | goto close_file; 52 | } 53 | 54 | *width = cinfo.output_width; 55 | *height = cinfo.output_height; 56 | 57 | rgb[0] = malloc(3 * cinfo.output_width * cinfo.output_height); 58 | if (rgb[0] == NULL) { 59 | fprintf(stderr, "Can't allocate memory for JPEG file.\n"); 60 | goto close_file; 61 | } 62 | 63 | if (cinfo.output_components == 3) { 64 | ptr = rgb[0]; 65 | while (cinfo.output_scanline < cinfo.output_height) { 66 | jpeg_read_scanlines(&cinfo, &ptr, 1); 67 | ptr += 3 * cinfo.output_width; 68 | } 69 | } else if (cinfo.output_components == 1) { 70 | ptr = malloc(cinfo.output_width); 71 | if (ptr == NULL) { 72 | fprintf(stderr, "Can't allocate memory for JPEG file.\n"); 73 | goto rgb_free; 74 | } 75 | 76 | ipos = 0; 77 | while (cinfo.output_scanline < cinfo.output_height) { 78 | jpeg_read_scanlines(&cinfo, &ptr, 1); 79 | 80 | for (i = 0; i < cinfo.output_width; i++) { 81 | memset(rgb[0] + ipos, ptr[i], 3); 82 | ipos += 3; 83 | } 84 | } 85 | 86 | free(ptr); 87 | } 88 | 89 | jpeg_finish_decompress(&cinfo); 90 | 91 | ret = 1; 92 | goto close_file; 93 | 94 | rgb_free: 95 | free(rgb[0]); 96 | 97 | close_file: 98 | jpeg_destroy_decompress(&cinfo); 99 | fclose(infile); 100 | 101 | return(ret); 102 | } 103 | -------------------------------------------------------------------------------- /log.cpp: -------------------------------------------------------------------------------- 1 | #include "log.h" 2 | #include 3 | 4 | bool 5 | LogUnit::openLog(const char * filename) 6 | { 7 | if (logFile.is_open()) { 8 | cerr << APPNAME 9 | << ": opening a new Log file, while another is already open" 10 | << endl; 11 | logFile.close(); 12 | } 13 | logFile.open(filename, ios_base::app); 14 | 15 | return !(logFile.fail()); 16 | } 17 | 18 | void 19 | LogUnit::closeLog() 20 | { 21 | if (logFile.is_open()) 22 | logFile.close(); 23 | } 24 | -------------------------------------------------------------------------------- /log.h: -------------------------------------------------------------------------------- 1 | #ifndef _LOG_H_ 2 | #define _LOG_H_ 3 | 4 | #ifdef USE_CONSOLEKIT 5 | #include "Ck.h" 6 | #endif 7 | #ifdef USE_PAM 8 | #include "PAM.h" 9 | #endif 10 | #include "const.h" 11 | #include 12 | 13 | using namespace std; 14 | 15 | static class LogUnit { 16 | ofstream logFile; 17 | public: 18 | bool openLog(const char * filename); 19 | void closeLog(); 20 | 21 | ~LogUnit() { closeLog(); } 22 | 23 | template 24 | LogUnit & operator<<(const Type & text) { 25 | logFile << text; logFile.flush(); 26 | return *this; 27 | } 28 | 29 | LogUnit & operator<<(ostream & (*fp)(ostream&)) { 30 | logFile << fp; logFile.flush(); 31 | return *this; 32 | } 33 | 34 | LogUnit & operator<<(ios_base & (*fp)(ios_base&)) { 35 | logFile << fp; logFile.flush(); 36 | return *this; 37 | } 38 | } logStream; 39 | 40 | #endif /* _LOG_H_ */ 41 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | /* SLiM - Simple Login Manager 2 | Copyright (C) 1997, 1998 Per Liden 3 | Copyright (C) 2004-06 Simone Rota 4 | Copyright (C) 2004-06 Johannes Winkelmann 5 | 6 | This program is free software; you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation; either version 2 of the License, or 9 | (at your option) any later version. 10 | */ 11 | 12 | #include "app.h" 13 | #include "const.h" 14 | 15 | App* LoginApp = 0; 16 | 17 | int main(int argc, char** argv) 18 | { 19 | LoginApp = new App(argc, argv); 20 | LoginApp->Run(); 21 | return 0; 22 | } 23 | 24 | -------------------------------------------------------------------------------- /numlock.cpp: -------------------------------------------------------------------------------- 1 | /* SLiM - Simple Login Manager 2 | Copyright (C) 2004-06 Simone Rota 3 | Copyright (C) 2004-06 Johannes Winkelmann 4 | Copyright (C) 2012 Nobuhiro Iwamatsu 5 | 6 | This program is free software; you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation; either version 2 of the License, or 9 | (at your option) any later version. 10 | 11 | Code adapted from NumLockX, look at the end of this file for 12 | the original Copyright information. 13 | 14 | */ 15 | 16 | #include "numlock.h" 17 | #include 18 | 19 | NumLock::NumLock() { 20 | } 21 | 22 | int NumLock::xkb_init(Display* dpy) { 23 | int xkb_opcode, xkb_event, xkb_error; 24 | int xkb_lmaj = XkbMajorVersion; 25 | int xkb_lmin = XkbMinorVersion; 26 | 27 | return XkbLibraryVersion( &xkb_lmaj, &xkb_lmin ) 28 | && XkbQueryExtension( dpy, &xkb_opcode, &xkb_event, &xkb_error, 29 | &xkb_lmaj, &xkb_lmin ); 30 | } 31 | 32 | unsigned int NumLock::xkb_mask_modifier( XkbDescPtr xkb, const char *name ) { 33 | int i; 34 | if( !xkb || !xkb->names ) 35 | return 0; 36 | 37 | for( i = 0; i < XkbNumVirtualMods; i++ ) { 38 | char* modStr = XGetAtomName( xkb->dpy, xkb->names->vmods[i] ); 39 | if( modStr != NULL && strcmp(name, modStr) == 0 ) { 40 | unsigned int mask; 41 | XkbVirtualModsToReal( xkb, 1 << i, &mask ); 42 | return mask; 43 | } 44 | } 45 | return 0; 46 | } 47 | 48 | unsigned int NumLock::xkb_numlock_mask(Display* dpy) { 49 | XkbDescPtr xkb; 50 | 51 | xkb = XkbGetKeyboard( dpy, XkbAllComponentsMask, XkbUseCoreKbd ); 52 | if( xkb != NULL ) { 53 | unsigned int mask = xkb_mask_modifier( xkb, "NumLock" ); 54 | XkbFreeKeyboard( xkb, 0, True ); 55 | return mask; 56 | } 57 | return 0; 58 | } 59 | 60 | void NumLock::control_numlock(Display *dpy, bool flag) { 61 | unsigned int mask; 62 | 63 | if( !xkb_init(dpy) ) 64 | return; 65 | 66 | mask = xkb_numlock_mask(dpy); 67 | if( mask == 0 ) 68 | return; 69 | 70 | if( flag == true ) 71 | XkbLockModifiers ( dpy, XkbUseCoreKbd, mask, mask); 72 | else 73 | XkbLockModifiers ( dpy, XkbUseCoreKbd, mask, 0); 74 | } 75 | 76 | void NumLock::setOn(Display *dpy) { 77 | control_numlock(dpy, true); 78 | } 79 | 80 | void NumLock::setOff(Display *dpy) { 81 | control_numlock(dpy, false); 82 | } 83 | 84 | /* 85 | Copyright (C) 2000-2001 Lubos Lunak 86 | Copyright (C) 2001 Oswald Buddenhagen 87 | 88 | Permission is hereby granted, free of charge, to any person obtaining a 89 | copy of this software and associated documentation files (the "Software"), 90 | to deal in the Software without restriction, including without limitation 91 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 92 | and/or sell copies of the Software, and to permit persons to whom the 93 | Software is furnished to do so, subject to the following conditions: 94 | 95 | The above copyright notice and this permission notice shall be included in 96 | all copies or substantial portions of the Software. 97 | 98 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 99 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 100 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 101 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 102 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 103 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 104 | DEALINGS IN THE SOFTWARE. 105 | 106 | */ 107 | -------------------------------------------------------------------------------- /numlock.h: -------------------------------------------------------------------------------- 1 | /* SLiM - Simple Login Manager 2 | Copyright (C) 2004-06 Simone Rota 3 | Copyright (C) 2004-06 Johannes Winkelmann 4 | Copyright (C) 2012 Nobuhiro Iwamatsu 5 | 6 | This program is free software; you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation; either version 2 of the License, or 9 | (at your option) any later version. 10 | */ 11 | 12 | #ifndef _NUMLOCK_H_ 13 | #define _NUMLOCK_H_ 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | class NumLock { 20 | 21 | public: 22 | NumLock(); 23 | static void setOn(Display *dpy); 24 | static void setOff(Display *dpy); 25 | 26 | private: 27 | static int xkb_init(Display *dpy); 28 | static unsigned int xkb_mask_modifier(XkbDescPtr xkb, const char *name); 29 | static unsigned int xkb_numlock_mask(Display *dpy); 30 | static void control_numlock(Display *dpy, bool flag); 31 | }; 32 | 33 | #endif /* _NUMLOCK_H_ */ 34 | -------------------------------------------------------------------------------- /pam.sample: -------------------------------------------------------------------------------- 1 | #%PAM-1.0 2 | auth requisite pam_nologin.so 3 | auth required pam_env.so 4 | auth required pam_unix.so 5 | account required pam_unix.so 6 | password required pam_unix.so 7 | session required pam_limits.so 8 | session required pam_unix.so 9 | session optional pam_loginuid.so 10 | session optional pam_ck_connector.so 11 | -------------------------------------------------------------------------------- /panel.cpp: -------------------------------------------------------------------------------- 1 | /* SLiM - Simple Login Manager 2 | Copyright (C) 1997, 1998 Per Liden 3 | Copyright (C) 2004-06 Simone Rota 4 | Copyright (C) 2004-06 Johannes Winkelmann 5 | 6 | This program is free software; you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation; either version 2 of the License, or 9 | (at your option) any later version. 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | #include "panel.h" 16 | 17 | using namespace std; 18 | 19 | Panel::Panel(Display* dpy, int scr, Window root, Cfg* config, 20 | const string& themedir, PanelType panel_mode) { 21 | /* Set display */ 22 | Dpy = dpy; 23 | Scr = scr; 24 | Root = root; 25 | cfg = config; 26 | mode = panel_mode; 27 | 28 | session_name = ""; 29 | session_exec = ""; 30 | if (mode == Mode_Lock) { 31 | Win = root; 32 | viewport = GetPrimaryViewport(); 33 | } 34 | 35 | /* Init GC */ 36 | XGCValues gcv; 37 | unsigned long gcm; 38 | gcm = GCForeground|GCBackground|GCGraphicsExposures; 39 | gcv.foreground = GetColor("black"); 40 | gcv.background = GetColor("white"); 41 | gcv.graphics_exposures = False; 42 | if (mode == Mode_Lock) 43 | TextGC = XCreateGC(Dpy, Win, gcm, &gcv); 44 | else 45 | TextGC = XCreateGC(Dpy, Root, gcm, &gcv); 46 | 47 | if (mode == Mode_Lock) { 48 | gcm = GCGraphicsExposures; 49 | gcv.graphics_exposures = False; 50 | WinGC = XCreateGC(Dpy, Win, gcm, &gcv); 51 | if (WinGC < 0) { 52 | cerr << APPNAME 53 | << ": failed to create pixmap\n."; 54 | exit(ERR_EXIT); 55 | } 56 | } 57 | 58 | font = XftFontOpenName(Dpy, Scr, cfg->getOption("input_font").c_str()); 59 | welcomefont = XftFontOpenName(Dpy, Scr, cfg->getOption("welcome_font").c_str()); 60 | introfont = XftFontOpenName(Dpy, Scr, cfg->getOption("intro_font").c_str()); 61 | enterfont = XftFontOpenName(Dpy, Scr, cfg->getOption("username_font").c_str()); 62 | msgfont = XftFontOpenName(Dpy, Scr, cfg->getOption("msg_font").c_str()); 63 | 64 | Visual* visual = DefaultVisual(Dpy, Scr); 65 | Colormap colormap = DefaultColormap(Dpy, Scr); 66 | /* NOTE: using XftColorAllocValue() would be a better solution. Lazy me. */ 67 | XftColorAllocName(Dpy, visual, colormap, cfg->getOption("input_color").c_str(), &inputcolor); 68 | XftColorAllocName(Dpy, visual, colormap, cfg->getOption("input_shadow_color").c_str(), &inputshadowcolor); 69 | XftColorAllocName(Dpy, visual, colormap, cfg->getOption("welcome_color").c_str(), &welcomecolor); 70 | XftColorAllocName(Dpy, visual, colormap, cfg->getOption("welcome_shadow_color").c_str(), &welcomeshadowcolor); 71 | XftColorAllocName(Dpy, visual, colormap, cfg->getOption("username_color").c_str(), &entercolor); 72 | XftColorAllocName(Dpy, visual, colormap, cfg->getOption("username_shadow_color").c_str(), &entershadowcolor); 73 | XftColorAllocName(Dpy, visual, colormap, cfg->getOption("msg_color").c_str(), &msgcolor); 74 | XftColorAllocName(Dpy, visual, colormap, cfg->getOption("msg_shadow_color").c_str(), &msgshadowcolor); 75 | XftColorAllocName(Dpy, visual, colormap, cfg->getOption("intro_color").c_str(), &introcolor); 76 | XftColorAllocName(Dpy, visual, colormap, 77 | cfg->getOption("session_color").c_str(), &sessioncolor); 78 | XftColorAllocName(Dpy, visual, colormap, 79 | cfg->getOption("session_shadow_color").c_str(), &sessionshadowcolor); 80 | 81 | /* Load properties from config / theme */ 82 | input_name_x = cfg->getIntOption("input_name_x"); 83 | input_name_y = cfg->getIntOption("input_name_y"); 84 | input_pass_x = cfg->getIntOption("input_pass_x"); 85 | input_pass_y = cfg->getIntOption("input_pass_y"); 86 | inputShadowXOffset = cfg->getIntOption("input_shadow_xoffset"); 87 | inputShadowYOffset = cfg->getIntOption("input_shadow_yoffset"); 88 | 89 | if (input_pass_x < 0 || input_pass_y < 0){ /* single inputbox mode */ 90 | input_pass_x = input_name_x; 91 | input_pass_y = input_name_y; 92 | } 93 | 94 | /* Load panel and background image */ 95 | string panelpng = ""; 96 | panelpng = panelpng + themedir +"/panel.png"; 97 | image = new Image; 98 | bool loaded = image->Read(panelpng.c_str()); 99 | if (!loaded) { /* try jpeg if png failed */ 100 | panelpng = themedir + "/panel.jpg"; 101 | loaded = image->Read(panelpng.c_str()); 102 | if (!loaded) { 103 | logStream << APPNAME 104 | << ": could not load panel image for theme '" 105 | << basename((char*)themedir.c_str()) << "'" 106 | << endl; 107 | exit(ERR_EXIT); 108 | } 109 | } 110 | 111 | Image* bg = new Image(); 112 | string bgstyle = cfg->getOption("background_style"); 113 | if (bgstyle != "color") { 114 | panelpng = themedir +"/background.png"; 115 | loaded = bg->Read(panelpng.c_str()); 116 | if (!loaded) { /* try jpeg if png failed */ 117 | panelpng = themedir + "/background.jpg"; 118 | loaded = bg->Read(panelpng.c_str()); 119 | if (!loaded){ 120 | logStream << APPNAME 121 | << ": could not load background image for theme '" 122 | << basename((char*)themedir.c_str()) << "'" 123 | << endl; 124 | exit(ERR_EXIT); 125 | } 126 | } 127 | } 128 | 129 | if (mode == Mode_Lock) { 130 | if (bgstyle == "stretch") 131 | bg->Resize(viewport.width, viewport.height); 132 | //bg->Resize(XWidthOfScreen(ScreenOfDisplay(Dpy, Scr)), 133 | // XHeightOfScreen(ScreenOfDisplay(Dpy, Scr))); 134 | else if (bgstyle == "tile") 135 | bg->Tile(viewport.width, viewport.height); 136 | else if (bgstyle == "center") { 137 | string hexvalue = cfg->getOption("background_color"); 138 | hexvalue = hexvalue.substr(1,6); 139 | bg->Center(viewport.width, 140 | viewport.height, 141 | hexvalue.c_str()); 142 | } else { // plain color or error 143 | string hexvalue = cfg->getOption("background_color"); 144 | hexvalue = hexvalue.substr(1,6); 145 | bg->Center(viewport.width, 146 | viewport.height, 147 | hexvalue.c_str()); 148 | } 149 | } else { 150 | if (bgstyle == "stretch") { 151 | bg->Resize(XWidthOfScreen(ScreenOfDisplay(Dpy, Scr)), 152 | XHeightOfScreen(ScreenOfDisplay(Dpy, Scr))); 153 | } else if (bgstyle == "tile") { 154 | bg->Tile(XWidthOfScreen(ScreenOfDisplay(Dpy, Scr)), 155 | XHeightOfScreen(ScreenOfDisplay(Dpy, Scr))); 156 | } else if (bgstyle == "center") { 157 | string hexvalue = cfg->getOption("background_color"); 158 | hexvalue = hexvalue.substr(1,6); 159 | bg->Center(XWidthOfScreen(ScreenOfDisplay(Dpy, Scr)), 160 | XHeightOfScreen(ScreenOfDisplay(Dpy, Scr)), 161 | hexvalue.c_str()); 162 | } else { /* plain color or error */ 163 | string hexvalue = cfg->getOption("background_color"); 164 | hexvalue = hexvalue.substr(1,6); 165 | bg->Center(XWidthOfScreen(ScreenOfDisplay(Dpy, Scr)), 166 | XHeightOfScreen(ScreenOfDisplay(Dpy, Scr)), 167 | hexvalue.c_str()); 168 | } 169 | } 170 | 171 | string cfgX = cfg->getOption("input_panel_x"); 172 | string cfgY = cfg->getOption("input_panel_y"); 173 | 174 | if (mode == Mode_Lock) { 175 | X = Cfg::absolutepos(cfgX, viewport.width, image->Width()); 176 | Y = Cfg::absolutepos(cfgY, viewport.height, image->Height()); 177 | 178 | input_name_x += X; 179 | input_name_y += Y; 180 | input_pass_x += X; 181 | input_pass_y += Y; 182 | } else { 183 | X = Cfg::absolutepos(cfgX, XWidthOfScreen(ScreenOfDisplay(Dpy, Scr)), image->Width()); 184 | Y = Cfg::absolutepos(cfgY, XHeightOfScreen(ScreenOfDisplay(Dpy, Scr)), image->Height()); 185 | } 186 | 187 | if (mode == Mode_Lock) { 188 | /* Merge image into background without crop */ 189 | image->Merge_non_crop(bg, X, Y); 190 | PanelPixmap = image->createPixmap(Dpy, Scr, Win); 191 | } else { 192 | /* Merge image into background */ 193 | image->Merge(bg, X, Y); 194 | PanelPixmap = image->createPixmap(Dpy, Scr, Root); 195 | } 196 | delete bg; 197 | 198 | /* Read (and substitute vars in) the welcome message */ 199 | welcome_message = cfg->getWelcomeMessage(); 200 | intro_message = cfg->getOption("intro_msg"); 201 | 202 | if (mode == Mode_Lock) { 203 | SetName(getenv("USER")); 204 | field = Get_Passwd; 205 | OnExpose(); 206 | } 207 | } 208 | 209 | Panel::~Panel() { 210 | Visual* visual = DefaultVisual(Dpy, Scr); 211 | Colormap colormap = DefaultColormap(Dpy, Scr); 212 | 213 | XftColorFree(Dpy, visual, colormap, &inputcolor); 214 | XftColorFree(Dpy, visual, colormap, &inputshadowcolor); 215 | XftColorFree(Dpy, visual, colormap, &welcomecolor); 216 | XftColorFree(Dpy, visual, colormap, &welcomeshadowcolor); 217 | XftColorFree(Dpy, visual, colormap, &entercolor); 218 | XftColorFree(Dpy, visual, colormap, &entershadowcolor); 219 | XftColorFree(Dpy, visual, colormap, &msgcolor); 220 | XftColorFree(Dpy, visual, colormap, &msgshadowcolor); 221 | XftColorFree(Dpy, visual, colormap, &introcolor); 222 | XftColorFree(Dpy, visual, colormap, &sessioncolor); 223 | XftColorFree(Dpy, visual, colormap, &sessionshadowcolor); 224 | 225 | XFreeGC(Dpy, TextGC); 226 | XftFontClose(Dpy, font); 227 | XftFontClose(Dpy, msgfont); 228 | XftFontClose(Dpy, introfont); 229 | XftFontClose(Dpy, welcomefont); 230 | XftFontClose(Dpy, enterfont); 231 | 232 | if (mode == Mode_Lock) 233 | XFreeGC(Dpy, WinGC); 234 | 235 | delete image; 236 | } 237 | 238 | void Panel::OpenPanel() { 239 | /* Create window */ 240 | Win = XCreateSimpleWindow(Dpy, Root, X, Y, 241 | image->Width(), 242 | image->Height(), 243 | 0, GetColor("white"), GetColor("white")); 244 | 245 | /* Events */ 246 | XSelectInput(Dpy, Win, ExposureMask | KeyPressMask); 247 | 248 | /* Set background */ 249 | XSetWindowBackgroundPixmap(Dpy, Win, PanelPixmap); 250 | 251 | /* Show window */ 252 | XMapWindow(Dpy, Win); 253 | XMoveWindow(Dpy, Win, X, Y); /* override wm positioning (for tests) */ 254 | 255 | /* Grab keyboard */ 256 | XGrabKeyboard(Dpy, Win, False, GrabModeAsync, GrabModeAsync, CurrentTime); 257 | 258 | XFlush(Dpy); 259 | } 260 | 261 | void Panel::ClosePanel() { 262 | XUngrabKeyboard(Dpy, CurrentTime); 263 | XUnmapWindow(Dpy, Win); 264 | XDestroyWindow(Dpy, Win); 265 | XFlush(Dpy); 266 | } 267 | 268 | void Panel::ClearPanel() { 269 | session_name = ""; 270 | session_exec = ""; 271 | Reset(); 272 | XClearWindow(Dpy, Root); 273 | XClearWindow(Dpy, Win); 274 | Cursor(SHOW); 275 | ShowText(); 276 | XFlush(Dpy); 277 | } 278 | 279 | void Panel::WrongPassword(int timeout) { 280 | string message; 281 | XGlyphInfo extents; 282 | 283 | #if 0 284 | if (CapsLockOn) 285 | message = cfg->getOption("passwd_feedback_capslock"); 286 | else 287 | #endif 288 | message = cfg->getOption("passwd_feedback_msg"); 289 | 290 | XftDraw *draw = XftDrawCreate(Dpy, Win, 291 | DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr)); 292 | XftTextExtents8(Dpy, msgfont, reinterpret_cast(message.c_str()), 293 | message.length(), &extents); 294 | 295 | string cfgX = cfg->getOption("passwd_feedback_x"); 296 | string cfgY = cfg->getOption("passwd_feedback_y"); 297 | int shadowXOffset = cfg->getIntOption("msg_shadow_xoffset"); 298 | int shadowYOffset = cfg->getIntOption("msg_shadow_yoffset"); 299 | int msg_x = Cfg::absolutepos(cfgX, XWidthOfScreen(ScreenOfDisplay(Dpy, Scr)), extents.width); 300 | int msg_y = Cfg::absolutepos(cfgY, XHeightOfScreen(ScreenOfDisplay(Dpy, Scr)), extents.height); 301 | 302 | OnExpose(); 303 | SlimDrawString8(draw, &msgcolor, msgfont, msg_x, msg_y, message, 304 | &msgshadowcolor, shadowXOffset, shadowYOffset); 305 | 306 | if (cfg->getOption("bell") == "1") 307 | XBell(Dpy, 100); 308 | 309 | XFlush(Dpy); 310 | sleep(timeout); 311 | ResetPasswd(); 312 | OnExpose(); 313 | // The message should stay on the screen even after the password field is 314 | // cleared, methinks. I don't like this solution, but it works. 315 | SlimDrawString8(draw, &msgcolor, msgfont, msg_x, msg_y, message, 316 | &msgshadowcolor, shadowXOffset, shadowYOffset); 317 | XSync(Dpy, True); 318 | XftDrawDestroy(draw); 319 | } 320 | 321 | void Panel::Message(const string& text) { 322 | string cfgX, cfgY; 323 | XGlyphInfo extents; 324 | XftDraw *draw; 325 | 326 | if (mode == Mode_Lock) 327 | draw = XftDrawCreate(Dpy, Win, 328 | DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr)); 329 | else 330 | draw = XftDrawCreate(Dpy, Root, 331 | DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr)); 332 | 333 | XftTextExtents8(Dpy, msgfont, 334 | reinterpret_cast(text.c_str()), 335 | text.length(), &extents); 336 | cfgX = cfg->getOption("msg_x"); 337 | cfgY = cfg->getOption("msg_y"); 338 | int shadowXOffset = cfg->getIntOption("msg_shadow_xoffset"); 339 | int shadowYOffset = cfg->getIntOption("msg_shadow_yoffset"); 340 | int msg_x, msg_y; 341 | 342 | if (mode == Mode_Lock) { 343 | msg_x = Cfg::absolutepos(cfgX, viewport.width, extents.width); 344 | msg_y = Cfg::absolutepos(cfgY, viewport.height, extents.height); 345 | } else { 346 | msg_x = Cfg::absolutepos(cfgX, XWidthOfScreen(ScreenOfDisplay(Dpy, Scr)), extents.width); 347 | msg_y = Cfg::absolutepos(cfgY, XHeightOfScreen(ScreenOfDisplay(Dpy, Scr)), extents.height); 348 | } 349 | 350 | SlimDrawString8 (draw, &msgcolor, msgfont, msg_x, msg_y, 351 | text, 352 | &msgshadowcolor, 353 | shadowXOffset, shadowYOffset); 354 | XFlush(Dpy); 355 | XftDrawDestroy(draw); 356 | } 357 | 358 | void Panel::Error(const string& text) { 359 | ClosePanel(); 360 | Message(text); 361 | sleep(ERROR_DURATION); 362 | OpenPanel(); 363 | ClearPanel(); 364 | } 365 | 366 | unsigned long Panel::GetColor(const char* colorname) { 367 | XColor color; 368 | XWindowAttributes attributes; 369 | 370 | if (mode == Mode_Lock) 371 | XGetWindowAttributes(Dpy, Win, &attributes); 372 | else 373 | XGetWindowAttributes(Dpy, Root, &attributes); 374 | 375 | color.pixel = 0; 376 | 377 | if(!XParseColor(Dpy, attributes.colormap, colorname, &color)) 378 | logStream << APPNAME << ": can't parse color " << colorname << endl; 379 | else if(!XAllocColor(Dpy, attributes.colormap, &color)) 380 | logStream << APPNAME << ": can't allocate color " << colorname << endl; 381 | 382 | return color.pixel; 383 | } 384 | 385 | void Panel::Cursor(int visible) { 386 | const char* text = NULL; 387 | int xx = 0, yy = 0, y2 = 0, cheight = 0; 388 | const char* txth = "Wj"; /* used to get cursor height */ 389 | 390 | if (mode == Mode_Lock) { 391 | text = HiddenPasswdBuffer.c_str(); 392 | xx = input_pass_x; 393 | yy = input_pass_y; 394 | } else { 395 | switch(field) { 396 | case Get_Passwd: 397 | text = HiddenPasswdBuffer.c_str(); 398 | xx = input_pass_x; 399 | yy = input_pass_y; 400 | break; 401 | 402 | case Get_Name: 403 | text = NameBuffer.c_str(); 404 | xx = input_name_x; 405 | yy = input_name_y; 406 | break; 407 | } 408 | } 409 | 410 | XGlyphInfo extents; 411 | XftTextExtents8(Dpy, font, (XftChar8*)txth, strlen(txth), &extents); 412 | cheight = extents.height; 413 | y2 = yy - extents.y + extents.height; 414 | XftTextExtents8(Dpy, font, (XftChar8*)text, strlen(text), &extents); 415 | xx += extents.width; 416 | 417 | if(visible == SHOW) { 418 | if (mode == Mode_Lock) { 419 | xx += viewport.x; 420 | yy += viewport.y; 421 | y2 += viewport.y; 422 | } 423 | XSetForeground(Dpy, TextGC, 424 | GetColor(cfg->getOption("input_color").c_str())); 425 | 426 | XDrawLine(Dpy, Win, TextGC, 427 | xx+1, yy-cheight, 428 | xx+1, y2); 429 | } else { 430 | if (mode == Mode_Lock) 431 | ApplyBackground(Rectangle(xx+1, yy-cheight, 432 | 1, y2-(yy-cheight)+1)); 433 | else 434 | XClearArea(Dpy, Win, xx+1, yy-cheight, 435 | 1, y2-(yy-cheight)+1, false); 436 | } 437 | } 438 | 439 | void Panel::EventHandler(const Panel::FieldType& curfield) { 440 | XEvent event; 441 | field = curfield; 442 | bool loop = true; 443 | 444 | if (mode == Mode_DM) 445 | OnExpose(); 446 | 447 | struct pollfd x11_pfd = {0}; 448 | x11_pfd.fd = ConnectionNumber(Dpy); 449 | x11_pfd.events = POLLIN; 450 | 451 | while (loop) { 452 | if (XPending(Dpy) || poll(&x11_pfd, 1, -1) > 0) { 453 | while(XPending(Dpy)) { 454 | XNextEvent(Dpy, &event); 455 | switch(event.type) { 456 | case Expose: 457 | OnExpose(); 458 | break; 459 | 460 | case KeyPress: 461 | loop=OnKeyPress(event); 462 | break; 463 | } 464 | } 465 | } 466 | } 467 | 468 | return; 469 | } 470 | 471 | void Panel::OnExpose(void) { 472 | XftDraw *draw = XftDrawCreate(Dpy, Win, 473 | DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr)); 474 | 475 | if (mode == Mode_Lock) 476 | ApplyBackground(); 477 | else 478 | XClearWindow(Dpy, Win); 479 | 480 | if (input_pass_x != input_name_x || input_pass_y != input_name_y){ 481 | SlimDrawString8 (draw, &inputcolor, font, input_name_x, input_name_y, 482 | NameBuffer, 483 | &inputshadowcolor, 484 | inputShadowXOffset, inputShadowYOffset); 485 | SlimDrawString8 (draw, &inputcolor, font, input_pass_x, input_pass_y, 486 | HiddenPasswdBuffer, 487 | &inputshadowcolor, 488 | inputShadowXOffset, inputShadowYOffset); 489 | } else { /*single input mode */ 490 | switch(field) { 491 | case Get_Passwd: 492 | SlimDrawString8 (draw, &inputcolor, font, 493 | input_pass_x, input_pass_y, 494 | HiddenPasswdBuffer, 495 | &inputshadowcolor, 496 | inputShadowXOffset, inputShadowYOffset); 497 | break; 498 | case Get_Name: 499 | SlimDrawString8 (draw, &inputcolor, font, 500 | input_name_x, input_name_y, 501 | NameBuffer, 502 | &inputshadowcolor, 503 | inputShadowXOffset, inputShadowYOffset); 504 | break; 505 | } 506 | } 507 | 508 | XftDrawDestroy (draw); 509 | Cursor(SHOW); 510 | ShowText(); 511 | } 512 | 513 | void Panel::EraseLastChar(string &formerString) { 514 | switch(field) { 515 | case GET_NAME: 516 | if (! NameBuffer.empty()) { 517 | formerString=NameBuffer; 518 | NameBuffer.erase(--NameBuffer.end()); 519 | } 520 | break; 521 | 522 | case GET_PASSWD: 523 | if (!PasswdBuffer.empty()) { 524 | formerString=HiddenPasswdBuffer; 525 | PasswdBuffer.erase(--PasswdBuffer.end()); 526 | HiddenPasswdBuffer.erase(--HiddenPasswdBuffer.end()); 527 | } 528 | break; 529 | } 530 | } 531 | 532 | bool Panel::OnKeyPress(XEvent& event) { 533 | char ascii; 534 | KeySym keysym; 535 | XComposeStatus compstatus; 536 | int xx = 0; 537 | int yy = 0; 538 | string text; 539 | string formerString = ""; 540 | 541 | XLookupString(&event.xkey, &ascii, 1, &keysym, &compstatus); 542 | switch(keysym){ 543 | case XK_F1: 544 | SwitchSession(); 545 | return true; 546 | 547 | case XK_F11: 548 | /* Take a screenshot */ 549 | system(cfg->getOption("screenshot_cmd").c_str()); 550 | return true; 551 | 552 | case XK_Return: 553 | case XK_KP_Enter: 554 | if (field==Get_Name){ 555 | /* Don't allow an empty username */ 556 | if (NameBuffer.empty()) return true; 557 | 558 | if (NameBuffer==CONSOLE_STR){ 559 | action = Console; 560 | } else if (NameBuffer==HALT_STR){ 561 | action = Halt; 562 | } else if (NameBuffer==REBOOT_STR){ 563 | action = Reboot; 564 | } else if (NameBuffer==SUSPEND_STR){ 565 | action = Suspend; 566 | } else if (NameBuffer==EXIT_STR){ 567 | action = Exit; 568 | } else{ 569 | if (mode == Mode_DM) 570 | action = Login; 571 | else 572 | action = Lock; 573 | } 574 | }; 575 | return false; 576 | default: 577 | break; 578 | }; 579 | 580 | Cursor(HIDE); 581 | switch(keysym){ 582 | case XK_Delete: 583 | case XK_BackSpace: 584 | EraseLastChar(formerString); 585 | break; 586 | 587 | case XK_w: 588 | case XK_u: 589 | if (reinterpret_cast(event).state & ControlMask) { 590 | switch(field) { 591 | case Get_Passwd: 592 | formerString = HiddenPasswdBuffer; 593 | HiddenPasswdBuffer.clear(); 594 | PasswdBuffer.clear(); 595 | break; 596 | case Get_Name: 597 | formerString = NameBuffer; 598 | NameBuffer.clear(); 599 | break; 600 | } 601 | break; 602 | } 603 | case XK_h: 604 | if (reinterpret_cast(event).state & ControlMask) { 605 | EraseLastChar(formerString); 606 | break; 607 | } 608 | /* Deliberate fall-through */ 609 | 610 | default: 611 | if (isprint(ascii) && (keysym < XK_Shift_L || keysym > XK_Hyper_R)){ 612 | switch(field) { 613 | case GET_NAME: 614 | formerString=NameBuffer; 615 | if (NameBuffer.length() < INPUT_MAXLENGTH_NAME-1){ 616 | NameBuffer.append(&ascii,1); 617 | }; 618 | break; 619 | case GET_PASSWD: 620 | formerString=HiddenPasswdBuffer; 621 | if (PasswdBuffer.length() < INPUT_MAXLENGTH_PASSWD-1){ 622 | PasswdBuffer.append(&ascii,1); 623 | HiddenPasswdBuffer.append("*"); 624 | }; 625 | break; 626 | }; 627 | } 628 | else { 629 | return true; //nodraw if notchange 630 | }; 631 | break; 632 | }; 633 | 634 | XGlyphInfo extents; 635 | XftDraw *draw = XftDrawCreate(Dpy, Win, 636 | DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr)); 637 | 638 | switch(field) { 639 | case Get_Name: 640 | text = NameBuffer; 641 | xx = input_name_x; 642 | yy = input_name_y; 643 | break; 644 | 645 | case Get_Passwd: 646 | text = HiddenPasswdBuffer; 647 | xx = input_pass_x; 648 | yy = input_pass_y; 649 | break; 650 | } 651 | 652 | if (!formerString.empty()){ 653 | const char* txth = "Wj"; /* get proper maximum height ? */ 654 | XftTextExtents8(Dpy, font, 655 | reinterpret_cast(txth), strlen(txth), &extents); 656 | int maxHeight = extents.height; 657 | 658 | XftTextExtents8(Dpy, font, 659 | reinterpret_cast(formerString.c_str()), 660 | formerString.length(), &extents); 661 | int maxLength = extents.width; 662 | 663 | if (mode == Mode_Lock) 664 | ApplyBackground(Rectangle(input_pass_x - 3, 665 | input_pass_y - maxHeight - 3, 666 | maxLength + 6, maxHeight + 6)); 667 | else 668 | XClearArea(Dpy, Win, xx - 3, yy-maxHeight - 3, 669 | maxLength + 6, maxHeight + 6, false); 670 | } 671 | 672 | if (!text.empty()) { 673 | SlimDrawString8 (draw, &inputcolor, font, xx, yy, 674 | text, 675 | &inputshadowcolor, 676 | inputShadowXOffset, inputShadowYOffset); 677 | } 678 | 679 | XftDrawDestroy (draw); 680 | Cursor(SHOW); 681 | return true; 682 | } 683 | 684 | /* Draw welcome and "enter username" message */ 685 | void Panel::ShowText(){ 686 | string cfgX, cfgY; 687 | XGlyphInfo extents; 688 | 689 | bool singleInputMode = 690 | input_name_x == input_pass_x && 691 | input_name_y == input_pass_y; 692 | 693 | XftDraw *draw = XftDrawCreate(Dpy, Win, 694 | DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr)); 695 | /* welcome message */ 696 | XftTextExtents8(Dpy, welcomefont, (XftChar8*)welcome_message.c_str(), 697 | strlen(welcome_message.c_str()), &extents); 698 | cfgX = cfg->getOption("welcome_x"); 699 | cfgY = cfg->getOption("welcome_y"); 700 | int shadowXOffset = cfg->getIntOption("welcome_shadow_xoffset"); 701 | int shadowYOffset = cfg->getIntOption("welcome_shadow_yoffset"); 702 | 703 | welcome_x = Cfg::absolutepos(cfgX, image->Width(), extents.width); 704 | welcome_y = Cfg::absolutepos(cfgY, image->Height(), extents.height); 705 | if (welcome_x >= 0 && welcome_y >= 0) { 706 | SlimDrawString8 (draw, &welcomecolor, welcomefont, 707 | welcome_x, welcome_y, 708 | welcome_message, 709 | &welcomeshadowcolor, shadowXOffset, shadowYOffset); 710 | } 711 | 712 | /* Enter username-password message */ 713 | string msg; 714 | if ((!singleInputMode|| field == Get_Passwd) && mode == Mode_DM) { 715 | msg = cfg->getOption("password_msg"); 716 | XftTextExtents8(Dpy, enterfont, (XftChar8*)msg.c_str(), 717 | strlen(msg.c_str()), &extents); 718 | cfgX = cfg->getOption("password_x"); 719 | cfgY = cfg->getOption("password_y"); 720 | int shadowXOffset = cfg->getIntOption("username_shadow_xoffset"); 721 | int shadowYOffset = cfg->getIntOption("username_shadow_yoffset"); 722 | password_x = Cfg::absolutepos(cfgX, image->Width(), extents.width); 723 | password_y = Cfg::absolutepos(cfgY, image->Height(), extents.height); 724 | if (password_x >= 0 && password_y >= 0){ 725 | SlimDrawString8 (draw, &entercolor, enterfont, password_x, password_y, 726 | msg, &entershadowcolor, shadowXOffset, shadowYOffset); 727 | } 728 | } 729 | 730 | if (!singleInputMode|| field == Get_Name) { 731 | msg = cfg->getOption("username_msg"); 732 | XftTextExtents8(Dpy, enterfont, (XftChar8*)msg.c_str(), 733 | strlen(msg.c_str()), &extents); 734 | cfgX = cfg->getOption("username_x"); 735 | cfgY = cfg->getOption("username_y"); 736 | int shadowXOffset = cfg->getIntOption("username_shadow_xoffset"); 737 | int shadowYOffset = cfg->getIntOption("username_shadow_yoffset"); 738 | username_x = Cfg::absolutepos(cfgX, image->Width(), extents.width); 739 | username_y = Cfg::absolutepos(cfgY, image->Height(), extents.height); 740 | if (username_x >= 0 && username_y >= 0){ 741 | SlimDrawString8 (draw, &entercolor, enterfont, username_x, username_y, 742 | msg, &entershadowcolor, shadowXOffset, shadowYOffset); 743 | } 744 | } 745 | XftDrawDestroy(draw); 746 | 747 | if (mode == Mode_Lock) { 748 | // If only the password box is visible, draw the user name somewhere too 749 | string user_msg = "User: " + GetName(); 750 | int show_username = cfg->getIntOption("show_username"); 751 | if (singleInputMode && show_username) { 752 | Message(user_msg); 753 | } 754 | } 755 | } 756 | 757 | string Panel::getSession() { 758 | return session_exec; 759 | } 760 | 761 | /* choose next available session type */ 762 | void Panel::SwitchSession() { 763 | pair ses = cfg->nextSession(); 764 | session_name = ses.first; 765 | session_exec = ses.second; 766 | if (session_name.size() > 0) { 767 | ShowSession(); 768 | } 769 | } 770 | 771 | /* Display session type on the screen */ 772 | void Panel::ShowSession() { 773 | string msg_x, msg_y; 774 | XClearWindow(Dpy, Root); 775 | string currsession = cfg->getOption("session_msg") + " " + session_name; 776 | XGlyphInfo extents; 777 | 778 | sessionfont = XftFontOpenName(Dpy, Scr, cfg->getOption("session_font").c_str()); 779 | 780 | XftDraw *draw = XftDrawCreate(Dpy, Root, 781 | DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr)); 782 | XftTextExtents8(Dpy, sessionfont, reinterpret_cast(currsession.c_str()), 783 | currsession.length(), &extents); 784 | msg_x = cfg->getOption("session_x"); 785 | msg_y = cfg->getOption("session_y"); 786 | int x = Cfg::absolutepos(msg_x, XWidthOfScreen(ScreenOfDisplay(Dpy, Scr)), extents.width); 787 | int y = Cfg::absolutepos(msg_y, XHeightOfScreen(ScreenOfDisplay(Dpy, Scr)), extents.height); 788 | int shadowXOffset = cfg->getIntOption("session_shadow_xoffset"); 789 | int shadowYOffset = cfg->getIntOption("session_shadow_yoffset"); 790 | 791 | SlimDrawString8(draw, &sessioncolor, sessionfont, x, y, 792 | currsession, 793 | &sessionshadowcolor, 794 | shadowXOffset, shadowYOffset); 795 | XFlush(Dpy); 796 | XftDrawDestroy(draw); 797 | } 798 | 799 | 800 | void Panel::SlimDrawString8(XftDraw *d, XftColor *color, XftFont *font, 801 | int x, int y, const string& str, 802 | XftColor* shadowColor, 803 | int xOffset, int yOffset) 804 | { 805 | int calc_x = 0; 806 | int calc_y = 0; 807 | if (mode == Mode_Lock) { 808 | calc_x = viewport.x; 809 | calc_y = viewport.y; 810 | } 811 | 812 | if (xOffset && yOffset) { 813 | XftDrawStringUtf8(d, shadowColor, font, 814 | x + xOffset + calc_x, 815 | y + yOffset + calc_y, 816 | reinterpret_cast(str.c_str()), 817 | str.length()); 818 | } 819 | 820 | XftDrawStringUtf8(d, color, font, 821 | x + calc_x, 822 | y + calc_y, 823 | reinterpret_cast(str.c_str()), 824 | str.length()); 825 | } 826 | 827 | Panel::ActionType Panel::getAction(void) const{ 828 | return action; 829 | } 830 | 831 | void Panel::Reset(void){ 832 | ResetName(); 833 | ResetPasswd(); 834 | } 835 | 836 | void Panel::ResetName(void){ 837 | NameBuffer.clear(); 838 | } 839 | 840 | void Panel::ResetPasswd(void){ 841 | PasswdBuffer.clear(); 842 | HiddenPasswdBuffer.clear(); 843 | } 844 | 845 | void Panel::SetName(const string& name){ 846 | NameBuffer=name; 847 | if (mode == Mode_DM) 848 | action = Login; 849 | else 850 | action = Lock; 851 | } 852 | 853 | const string& Panel::GetName(void) const{ 854 | return NameBuffer; 855 | } 856 | 857 | const string& Panel::GetPasswd(void) const{ 858 | return PasswdBuffer; 859 | } 860 | 861 | Rectangle Panel::GetPrimaryViewport() { 862 | Rectangle fallback; 863 | Rectangle result; 864 | 865 | RROutput primary; 866 | XRROutputInfo *primary_info; 867 | XRRScreenResources *resources; 868 | XRRCrtcInfo *crtc_info; 869 | 870 | int crtc; 871 | 872 | fallback.x = 0; 873 | fallback.y = 0; 874 | fallback.width = DisplayWidth(Dpy, Scr); 875 | fallback.height = DisplayHeight(Dpy, Scr); 876 | 877 | primary = XRRGetOutputPrimary(Dpy, Win); 878 | if (!primary) { 879 | return fallback; 880 | } 881 | resources = XRRGetScreenResources(Dpy, Win); 882 | if (!resources) 883 | return fallback; 884 | 885 | primary_info = XRRGetOutputInfo(Dpy, resources, primary); 886 | if (!primary_info) { 887 | XRRFreeScreenResources(resources); 888 | return fallback; 889 | } 890 | 891 | // Fixes bug with multiple monitors. Just pick first monitor if 892 | // XRRGetOutputInfo gives returns bad into for crtc. 893 | if (primary_info->crtc < 1) { 894 | if (primary_info->ncrtc > 0) { 895 | crtc = primary_info->crtcs[0]; 896 | } else { 897 | cerr << "Cannot get crtc from xrandr.\n"; 898 | exit(EXIT_FAILURE); 899 | } 900 | } else { 901 | crtc = primary_info->crtc; 902 | } 903 | 904 | crtc_info = XRRGetCrtcInfo(Dpy, resources, crtc); 905 | 906 | if (!crtc_info) { 907 | XRRFreeOutputInfo(primary_info); 908 | XRRFreeScreenResources(resources); 909 | return fallback; 910 | } 911 | 912 | result.x = crtc_info->x; 913 | result.y = crtc_info->y; 914 | result.width = crtc_info->width; 915 | result.height = crtc_info->height; 916 | 917 | XRRFreeCrtcInfo(crtc_info); 918 | XRRFreeOutputInfo(primary_info); 919 | XRRFreeScreenResources(resources); 920 | 921 | return result; 922 | } 923 | 924 | void Panel::ApplyBackground(Rectangle rect) { 925 | int ret = 0; 926 | 927 | if (rect.is_empty()) { 928 | rect.x = 0; 929 | rect.y = 0; 930 | rect.width = viewport.width; 931 | rect.height = viewport.height; 932 | } 933 | 934 | ret = XCopyArea(Dpy, PanelPixmap, Win, WinGC, 935 | rect.x, rect.y, rect.width, rect.height, 936 | viewport.x + rect.x, viewport.y + rect.y); 937 | 938 | if (!ret) 939 | cerr << APPNAME << ": failed to put pixmap on the screen\n."; 940 | } 941 | -------------------------------------------------------------------------------- /panel.h: -------------------------------------------------------------------------------- 1 | /* SLiM - Simple Login Manager 2 | Copyright (C) 1997, 1998 Per Liden 3 | Copyright (C) 2004-06 Simone Rota 4 | Copyright (C) 2004-06 Johannes Winkelmann 5 | Copyright (C) 2013 Nobuhiro Iwamatsu 6 | 7 | This program is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation; either version 2 of the License, or 10 | (at your option) any later version. 11 | */ 12 | 13 | #ifndef _PANEL_H_ 14 | #define _PANEL_H_ 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #ifdef NEEDS_BASENAME 28 | #include 29 | #endif 30 | 31 | #include "switchuser.h" 32 | #include "log.h" 33 | #include "image.h" 34 | 35 | struct Rectangle { 36 | int x; 37 | int y; 38 | unsigned int width; 39 | unsigned int height; 40 | 41 | Rectangle() : x(0), y(0), width(0), height(0) {}; 42 | Rectangle(int x, int y, unsigned int width, 43 | unsigned int height) : 44 | x(x), y(y), width(width), height(height) {}; 45 | bool is_empty() const { 46 | return width == 0 || height == 0; 47 | } 48 | }; 49 | 50 | class Panel { 51 | public: 52 | enum ActionType { 53 | Login, 54 | Lock, 55 | Console, 56 | Reboot, 57 | Halt, 58 | Exit, 59 | Suspend 60 | }; 61 | 62 | enum FieldType { 63 | Get_Name, 64 | Get_Passwd 65 | }; 66 | 67 | enum PanelType { 68 | Mode_DM, 69 | Mode_Lock 70 | }; 71 | 72 | Panel(Display *dpy, int scr, Window root, Cfg *config, 73 | const std::string& themed, PanelType panel_mode); 74 | ~Panel(); 75 | void OpenPanel(); 76 | void ClosePanel(); 77 | void ClearPanel(); 78 | void WrongPassword(int timeout); 79 | void Message(const std::string &text); 80 | void Error(const std::string &text); 81 | void EventHandler(const FieldType &curfield); 82 | std::string getSession(); 83 | ActionType getAction(void) const; 84 | 85 | void Reset(void); 86 | void ResetName(void); 87 | void ResetPasswd(void); 88 | void SetName(const std::string &name); 89 | const std::string& GetName(void) const; 90 | const std::string& GetPasswd(void) const; 91 | void SwitchSession(); 92 | private: 93 | Panel(); 94 | void Cursor(int visible); 95 | unsigned long GetColor(const char *colorname); 96 | void OnExpose(void); 97 | void EraseLastChar(string &formerString); 98 | bool OnKeyPress(XEvent& event); 99 | void ShowText(); 100 | void ShowSession(); 101 | 102 | void SlimDrawString8(XftDraw *d, XftColor *color, XftFont *font, 103 | int x, int y, const std::string &str, 104 | XftColor *shadowColor, 105 | int xOffset, int yOffset); 106 | 107 | Rectangle GetPrimaryViewport(); 108 | void ApplyBackground(Rectangle = Rectangle()); 109 | 110 | /* Private data */ 111 | PanelType mode; /* work mode */ 112 | Cfg *cfg; 113 | Window Win; 114 | Window Root; 115 | Display *Dpy; 116 | int Scr; 117 | int X, Y; 118 | GC TextGC; 119 | GC WinGC; 120 | XftFont *font; 121 | XftColor inputshadowcolor; 122 | XftColor inputcolor; 123 | XftColor msgcolor; 124 | XftColor msgshadowcolor; 125 | XftFont *msgfont; 126 | XftColor introcolor; 127 | XftFont *introfont; 128 | XftFont *welcomefont; 129 | XftColor welcomecolor; 130 | XftFont *sessionfont; 131 | XftColor sessioncolor; 132 | XftColor sessionshadowcolor; 133 | XftColor welcomeshadowcolor; 134 | XftFont *enterfont; 135 | XftColor entercolor; 136 | XftColor entershadowcolor; 137 | ActionType action; 138 | FieldType field; 139 | //Pixmap background; 140 | 141 | /* Username/Password */ 142 | std::string NameBuffer; 143 | std::string PasswdBuffer; 144 | std::string HiddenPasswdBuffer; 145 | 146 | /* screen stuff */ 147 | Rectangle viewport; 148 | 149 | /* Configuration */ 150 | int input_name_x; 151 | int input_name_y; 152 | int input_pass_x; 153 | int input_pass_y; 154 | int inputShadowXOffset; 155 | int inputShadowYOffset; 156 | int input_cursor_height; 157 | int welcome_x; 158 | int welcome_y; 159 | int welcome_shadow_xoffset; 160 | int welcome_shadow_yoffset; 161 | int session_shadow_xoffset; 162 | int session_shadow_yoffset; 163 | int intro_x; 164 | int intro_y; 165 | int username_x; 166 | int username_y; 167 | int username_shadow_xoffset; 168 | int username_shadow_yoffset; 169 | int password_x; 170 | int password_y; 171 | std::string welcome_message; 172 | std::string intro_message; 173 | 174 | /* Pixmap data */ 175 | Pixmap PanelPixmap; 176 | 177 | Image *image; 178 | 179 | /* For thesting themes */ 180 | bool testing; 181 | std::string themedir; 182 | 183 | /* Session handling */ 184 | std::string session_name; 185 | std::string session_exec; 186 | }; 187 | 188 | #endif /* _PANEL_H_ */ 189 | -------------------------------------------------------------------------------- /png.c: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | png.c - read and write png images using libpng routines. 3 | Distributed with Xplanet. 4 | Copyright (C) 2002 Hari Nair 5 | 6 | This program is free software; you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation; either version 2 of the License, or 9 | (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program; if not, write to the Free Software 18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 | ****************************************************************************/ 20 | 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include "const.h" 29 | 30 | int 31 | read_png(const char *filename, int *width, int *height, unsigned char **rgb, 32 | unsigned char **alpha) 33 | { 34 | int ret = 0; 35 | 36 | png_structp png_ptr; 37 | png_infop info_ptr; 38 | png_bytepp row_pointers; 39 | 40 | unsigned char *ptr = NULL; 41 | png_uint_32 w, h; 42 | int bit_depth, color_type, interlace_type; 43 | int i; 44 | 45 | FILE *infile = fopen(filename, "rb"); 46 | if (infile == NULL) { 47 | fprintf(stderr, "Can not fopen file: %s\n", filename); 48 | return ret; 49 | } 50 | 51 | png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 52 | (png_voidp)NULL, 53 | (png_error_ptr)NULL, 54 | (png_error_ptr)NULL); 55 | if (!png_ptr) 56 | goto file_close; 57 | 58 | info_ptr = png_create_info_struct(png_ptr); 59 | if (!info_ptr) { 60 | png_destroy_read_struct(&png_ptr, 61 | (png_infopp)NULL, 62 | (png_infopp)NULL); 63 | } 64 | 65 | #if PNG_LIBPNG_VER_MAJOR >= 1 && PNG_LIBPNG_VER_MINOR >= 4 66 | if (setjmp(png_jmpbuf((png_ptr)))) 67 | #else 68 | if (setjmp(png_ptr->jmpbuf)) 69 | #endif 70 | goto png_destroy; 71 | 72 | png_init_io(png_ptr, infile); 73 | png_read_info(png_ptr, info_ptr); 74 | 75 | png_get_IHDR(png_ptr, info_ptr, &w, &h, &bit_depth, &color_type, 76 | &interlace_type, (int *) NULL, (int *) NULL); 77 | 78 | /* Prevent against integer overflow */ 79 | if (w >= MAX_DIMENSION || h >= MAX_DIMENSION) { 80 | fprintf(stderr, 81 | "Unreasonable dimension found in file: %s\n", filename); 82 | goto png_destroy; 83 | } 84 | 85 | *width = (int) w; 86 | *height = (int) h; 87 | 88 | if (color_type == PNG_COLOR_TYPE_RGB_ALPHA 89 | || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { 90 | alpha[0] = malloc(*width * *height); 91 | if (alpha[0] == NULL) { 92 | fprintf(stderr, 93 | "Can't allocate memory for alpha channel in PNG file.\n"); 94 | goto png_destroy; 95 | } 96 | } 97 | 98 | /* Change a paletted/grayscale image to RGB */ 99 | if (color_type == PNG_COLOR_TYPE_PALETTE && bit_depth <= 8) 100 | png_set_expand(png_ptr); 101 | 102 | /* Change a grayscale image to RGB */ 103 | if (color_type == PNG_COLOR_TYPE_GRAY || 104 | color_type == PNG_COLOR_TYPE_GRAY_ALPHA) 105 | png_set_gray_to_rgb(png_ptr); 106 | 107 | /* If the PNG file has 16 bits per channel, strip them down to 8 */ 108 | if (bit_depth == 16) 109 | png_set_strip_16(png_ptr); 110 | 111 | /* use 1 byte per pixel */ 112 | png_set_packing(png_ptr); 113 | 114 | row_pointers = malloc(*height * sizeof(png_bytep)); 115 | if (row_pointers == NULL) { 116 | fprintf(stderr, "Can't allocate memory for PNG file.\n"); 117 | goto png_destroy; 118 | } 119 | 120 | for (i = 0; i < *height; i++) { 121 | row_pointers[i] = malloc(4 * *width); 122 | if (row_pointers == NULL) { 123 | fprintf(stderr, 124 | "Can't allocate memory for PNG line.\n"); 125 | goto rows_free; 126 | } 127 | } 128 | 129 | png_read_image(png_ptr, row_pointers); 130 | 131 | rgb[0] = malloc(3 * *width * *height); 132 | if (rgb[0] == NULL) { 133 | fprintf(stderr, "Can't allocate memory for PNG file.\n"); 134 | goto rows_free; 135 | } 136 | 137 | if (alpha[0] == NULL) { 138 | ptr = rgb[0]; 139 | for (i = 0; i < *height; i++) { 140 | memcpy(ptr, row_pointers[i], 3 * *width); 141 | ptr += 3 * *width; 142 | } 143 | } else { 144 | int j; 145 | ptr = rgb[0]; 146 | for (i = 0; i < *height; i++) { 147 | int ipos = 0; 148 | for (j = 0; j < *width; j++) { 149 | *ptr++ = row_pointers[i][ipos++]; 150 | *ptr++ = row_pointers[i][ipos++]; 151 | *ptr++ = row_pointers[i][ipos++]; 152 | alpha[0][i * *width + j] 153 | = row_pointers[i][ipos++]; 154 | } 155 | } 156 | } 157 | 158 | ret = 1; /* data reading is OK */ 159 | 160 | rows_free: 161 | for (i = 0; i < *height; i++) { 162 | if (row_pointers[i] != NULL) 163 | free(row_pointers[i]); 164 | } 165 | 166 | free(row_pointers); 167 | 168 | png_destroy: 169 | png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL); 170 | 171 | file_close: 172 | fclose(infile); 173 | return ret; 174 | } 175 | -------------------------------------------------------------------------------- /slim.1: -------------------------------------------------------------------------------- 1 | " Text automatically generated by txt2man-1.4.7 2 | .TH slim 1 "October 03, 2013" "" "" 3 | .SH NAME 4 | \fBslim \fP- Simple LogIn Manager 5 | \fB 6 | .SH SYNOPSIS 7 | .nf 8 | .fam C 9 | \fBslim\fP [\fIoptions\fP] [] 10 | .fam T 11 | .fi 12 | .SH DESCRIPTION 13 | SLiM is a lightweight login manager for X11, allowing the initialization 14 | of a graphical session by entring username and password in a login screen. 15 | .SH OPTIONS 16 | .TP 17 | .B 18 | \fB-d\fP 19 | run as a daemon 20 | .TP 21 | .B 22 | \fB-p\fP /path/to/theme 23 | display a preview of the theme. An already running X11 session 24 | is required for theme preview. 25 | .TP 26 | .B 27 | \fB-h\fP 28 | display a brief help message 29 | .TP 30 | .B 31 | \fB-v\fP 32 | display version information 33 | .SH EXAMPLES 34 | .TP 35 | .B 36 | \fBslim\fP \fB-d\fP 37 | run \fBslim\fP in daemon mode 38 | .TP 39 | .B 40 | \fBslim\fP \fB-p\fP /usr/share/\fBslim\fP/themes/default 41 | preview of the default theme 42 | .SH STARTING SLIM AT BOOT 43 | Please refer to documentation of your Operating System to make \fBslim\fP 44 | automatically startup after the system boots. 45 | .SH CONFIGURATION 46 | Global configuration is stored in the /etc/slim.conf file. See the comments 47 | inside the file for a detailed explanation of the \fIoptions\fP. 48 | .SH USAGE AND SPECIAL USERNAMES 49 | When started, \fBslim\fP will show a login panel; enter the username and 50 | password of the user you want to login as. 51 | .PP 52 | Special usernames: 53 | .TP 54 | .B 55 | console 56 | open a xterm console 57 | .TP 58 | .B 59 | exit 60 | quit \fBslim\fP 61 | .TP 62 | .B 63 | halt 64 | shutdown the machine 65 | .TP 66 | .B 67 | reboot 68 | reboot the machine 69 | .TP 70 | .B 71 | suspend 72 | power-suspend the machine 73 | .PP 74 | See the configuration file for customizing the above commands. 75 | The 'halt' and 'reboot' commands need the root password, this may 76 | change in future releases. 77 | .PP 78 | Shortcuts: 79 | .TP 80 | .B 81 | F11 82 | executes a custom command (by default takes a screenshot) 83 | .TP 84 | .B 85 | F1 86 | choose session type from session list. 87 | .SH AUTHORS 88 | Nobuhiro Iwamatsu 89 | .SH SEE ALSO 90 | See the online documentation at the SLiM web site for further information 91 | on themes, FAQs, etc. 92 | -------------------------------------------------------------------------------- /slim.conf: -------------------------------------------------------------------------------- 1 | # Path, X server and arguments (if needed) 2 | # Note: -xauth $authfile is automatically appended 3 | default_path /bin:/usr/bin:/usr/local/bin 4 | default_xserver /usr/bin/X 5 | #xserver_arguments -dpi 75 6 | 7 | # Commands for halt, login, etc. 8 | halt_cmd /sbin/shutdown -h now 9 | reboot_cmd /sbin/shutdown -r now 10 | console_cmd /usr/bin/xterm -C -fg white -bg black +sb -T "Console login" -e /bin/sh -c "/bin/cat /etc/issue; exec /bin/login" 11 | #suspend_cmd /usr/sbin/suspend 12 | 13 | # Full path to the xauth binary 14 | xauth_path /usr/bin/xauth 15 | 16 | # Xauth file for server 17 | authfile /var/run/slim.auth 18 | 19 | 20 | # Activate numlock when slim starts. Valid values: on|off 21 | # numlock on 22 | 23 | # Hide the mouse cursor (note: does not work with some WMs). 24 | # Valid values: true|false 25 | # hidecursor false 26 | 27 | # This command is executed after a succesful login. 28 | # you can place the %session and %theme variables 29 | # to handle launching of specific commands in .xinitrc 30 | # depending of chosen session and slim theme 31 | # 32 | # NOTE: if your system does not have bash you need 33 | # to adjust the command according to your preferred shell, 34 | # i.e. for freebsd use: 35 | # login_cmd exec /bin/sh - ~/.xinitrc %session 36 | login_cmd exec /bin/bash -login ~/.xinitrc %session 37 | 38 | # Commands executed when starting and exiting a session. 39 | # They can be used for registering a X11 session with 40 | # sessreg. You can use the %user variable 41 | # 42 | # sessionstart_cmd some command 43 | # sessionstop_cmd some command 44 | 45 | # Start in daemon mode. Valid values: yes | no 46 | # Note that this can be overriden by the command line 47 | # options "-d" and "-nodaemon" 48 | # daemon yes 49 | 50 | # Set directory that contains the xsessions. 51 | # slim reads xsesion from this directory, and be able to select. 52 | sessiondir /usr/share/xsessions/ 53 | 54 | # Executed when pressing F11 (requires imagemagick) 55 | screenshot_cmd import -window root /slim.png 56 | 57 | # welcome message. Available variables: %host, %domain 58 | welcome_msg Welcome to %host 59 | 60 | # Session message. Prepended to the session name when pressing F1 61 | # session_msg Session: 62 | 63 | # shutdown / reboot messages 64 | shutdown_msg The system is halting... 65 | reboot_msg The system is rebooting... 66 | 67 | # default user, leave blank or remove this line 68 | # for avoid pre-loading the username. 69 | #default_user simone 70 | 71 | # Focus the password field on start when default_user is set 72 | # Set to "yes" to enable this feature 73 | #focus_password no 74 | 75 | # Automatically login the default user (without entering 76 | # the password. Set to "yes" to enable this feature 77 | #auto_login no 78 | 79 | 80 | # current theme, use comma separated list to specify a set to 81 | # randomly choose from 82 | current_theme default 83 | 84 | # Lock file 85 | lockfile /var/run/slim.lock 86 | 87 | # Log file 88 | logfile /var/log/slim.log 89 | 90 | -------------------------------------------------------------------------------- /slim.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=SLiM Simple Login Manager 3 | After=systemd-user-sessions.service 4 | 5 | [Service] 6 | ExecStart=/usr/bin/slim -nodaemon 7 | 8 | [Install] 9 | Alias=display-manager.service 10 | -------------------------------------------------------------------------------- /slimlock.1: -------------------------------------------------------------------------------- 1 | .TH slimlock 1 "June 10, 2011" "version 0.8" 2 | .SH NAME 3 | \fBslimlock\fP - Unholy Screen Locker 4 | \fB 5 | .SH SYNOPSIS 6 | .nf 7 | .fam C 8 | \fBslimlock\fP [-v] 9 | .fam T 10 | .fi 11 | .SH DESCRIPTION 12 | The Frankenstein's monster of screen lockers. Grafting SLiM and slock together 13 | leads to blood, tears, and locked screens. 14 | .SH OPTIONS 15 | .TP 16 | .B 17 | \fB-v\fP 18 | display version information 19 | .SH CONFIGURATION 20 | Slimlock 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. 21 | 22 | slimlock.conf contains the following settings: 23 | 24 | .TP 25 | .B dpms_standby_timeout 26 | number of seconds of inactivity before the screen blanks. 27 | .BI "Default: " 60 28 | .TP 29 | .B dpms_off_timeout 30 | number of seconds of inactivity before the screen is turned off. 31 | .BI "Default: " 600 32 | .TP 33 | .B wrong_passwd_timeout 34 | delay in seconds after an incorrect password is entered. 35 | .BI "Default: " 2 36 | .TP 37 | .B passwd_feedback_msg 38 | message to display after a failed authentication attempt. 39 | .BI "Default: " "Authentication failed" 40 | .TP 41 | .B passwd_feedback_capslock 42 | message to display after a failed authentication attempt if the CapsLock is on. 43 | .BI "Default: " "Authentication failed (CapsLock is on)" 44 | .TP 45 | .B show_username 46 | 1 to show username on themes with single input field; 0 to disable. 47 | .BI "Default: " 1 48 | .TP 49 | .B show_welcome_msg 50 | 1 to show SLiM's welcome message; 0 to disable. 51 | .BI "Default: " 0 52 | .TP 53 | .B tty_lock 54 | 1 to disallow virtual terminals switching; 0 to allow. 55 | .BI "Default: " 1 56 | .TP 57 | .B bell 58 | 1 to enable the bell on authentication failure; 0 to disable. 59 | .BI "Default: " 1 60 | .SH "SEE ALSO" 61 | .BR slim (1) 62 | -------------------------------------------------------------------------------- /slimlock.conf: -------------------------------------------------------------------------------- 1 | dpms_standby_timeout 60 2 | dpms_off_timeout 600 3 | 4 | wrong_passwd_timeout 2 5 | passwd_feedback_x 50% 6 | passwd_feedback_y 10% 7 | passwd_feedback_msg Authentication failed 8 | passwd_feedback_capslock Authentication failed (CapsLock is on) 9 | show_username 1 10 | show_welcome_msg 0 11 | tty_lock 0 12 | -------------------------------------------------------------------------------- /slimlock.cpp: -------------------------------------------------------------------------------- 1 | /* slimlock 2 | * Copyright (c) 2010-2012 Joel Burget 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "cfg.h" 32 | #include "util.h" 33 | #include "panel.h" 34 | 35 | #undef APPNAME 36 | #define APPNAME "slimlock" 37 | #define SLIMLOCKCFG SYSCONFDIR"/slimlock.conf" 38 | 39 | using namespace std; 40 | 41 | void setBackground(const string& themedir); 42 | void HideCursor(); 43 | bool AuthenticateUser(); 44 | static int ConvCallback(int num_msgs, const struct pam_message **msg, 45 | struct pam_response **resp, void *appdata_ptr); 46 | string findValidRandomTheme(const string& set); 47 | void HandleSignal(int sig); 48 | void *RaiseWindow(void *data); 49 | 50 | // I really didn't wanna put these globals here, but it's the only way... 51 | Display* dpy; 52 | int scr; 53 | Window win; 54 | Cfg* cfg; 55 | Panel* loginPanel; 56 | string themeName = ""; 57 | 58 | pam_handle_t *pam_handle; 59 | struct pam_conv conv = {ConvCallback, NULL}; 60 | 61 | CARD16 dpms_standby, dpms_suspend, dpms_off, dpms_level; 62 | BOOL dpms_state, using_dpms; 63 | int term; 64 | 65 | static void 66 | die(const char *errstr, ...) { 67 | va_list ap; 68 | 69 | va_start(ap, errstr); 70 | vfprintf(stderr, errstr, ap); 71 | va_end(ap); 72 | exit(EXIT_FAILURE); 73 | } 74 | 75 | int main(int argc, char **argv) { 76 | if((argc == 2) && !strcmp("-v", argv[1])) 77 | die(APPNAME"-"VERSION", © 2010-2012 Joel Burget\n"); 78 | else if(argc != 1) 79 | die("usage: "APPNAME" [-v]\n"); 80 | 81 | void (*prev_fn)(int); 82 | 83 | // restore DPMS settings should slimlock be killed in the line of duty 84 | prev_fn = signal(SIGTERM, HandleSignal); 85 | if (prev_fn == SIG_IGN) signal(SIGTERM, SIG_IGN); 86 | 87 | // create a lock file to solve mutliple instances problem 88 | // /var/lock used to be the place to put this, now it's /run/lock 89 | // ...i think 90 | struct stat statbuf; 91 | int lock_file; 92 | 93 | // try /run/lock first, since i believe it's preferred 94 | if (!stat("/run/lock", &statbuf)) 95 | lock_file = open("/run/lock/"APPNAME".lock", O_CREAT | O_RDWR, 0666); 96 | else 97 | lock_file = open("/var/lock/"APPNAME".lock", O_CREAT | O_RDWR, 0666); 98 | 99 | int rc = flock(lock_file, LOCK_EX | LOCK_NB); 100 | 101 | if(rc) { 102 | if(EWOULDBLOCK == errno) 103 | die(APPNAME" already running\n"); 104 | } 105 | 106 | unsigned int cfg_passwd_timeout; 107 | // Read user's current theme 108 | cfg = new Cfg; 109 | cfg->readConf(CFGFILE); 110 | cfg->readConf(SLIMLOCKCFG); 111 | string themebase = ""; 112 | string themefile = ""; 113 | string themedir = ""; 114 | themeName = ""; 115 | themebase = string(THEMESDIR) + "/"; 116 | themeName = cfg->getOption("current_theme"); 117 | string::size_type pos; 118 | if ((pos = themeName.find(",")) != string::npos) { 119 | themeName = findValidRandomTheme(themeName); 120 | } 121 | 122 | bool loaded = false; 123 | while (!loaded) { 124 | themedir = themebase + themeName; 125 | themefile = themedir + THEMESFILE; 126 | if (!cfg->readConf(themefile)) { 127 | if (themeName == "default") { 128 | cerr << APPNAME << ": Failed to open default theme file " 129 | << themefile << endl; 130 | exit(ERR_EXIT); 131 | } else { 132 | cerr << APPNAME << ": Invalid theme in config: " 133 | << themeName << endl; 134 | themeName = "default"; 135 | } 136 | } else { 137 | loaded = true; 138 | } 139 | } 140 | 141 | const char *display = getenv("DISPLAY"); 142 | if (!display) 143 | display = DISPLAY; 144 | 145 | if(!(dpy = XOpenDisplay(display))) 146 | die(APPNAME": cannot open display\n"); 147 | scr = DefaultScreen(dpy); 148 | 149 | XSetWindowAttributes wa; 150 | wa.override_redirect = 1; 151 | wa.background_pixel = BlackPixel(dpy, scr); 152 | 153 | // Create a full screen window 154 | Window root = RootWindow(dpy, scr); 155 | win = XCreateWindow(dpy, 156 | root, 157 | 0, 158 | 0, 159 | DisplayWidth(dpy, scr), 160 | DisplayHeight(dpy, scr), 161 | 0, 162 | DefaultDepth(dpy, scr), 163 | CopyFromParent, 164 | DefaultVisual(dpy, scr), 165 | CWOverrideRedirect | CWBackPixel, 166 | &wa); 167 | XMapWindow(dpy, win); 168 | 169 | XFlush(dpy); 170 | for (int len = 1000; len; len--) { 171 | if(XGrabKeyboard(dpy, root, True, GrabModeAsync, GrabModeAsync, CurrentTime) 172 | == GrabSuccess) 173 | break; 174 | usleep(1000); 175 | } 176 | XSelectInput(dpy, win, ExposureMask | KeyPressMask); 177 | 178 | // This hides the cursor if the user has that option enabled in their 179 | // configuration 180 | HideCursor(); 181 | 182 | loginPanel = new Panel(dpy, scr, win, cfg, themedir, Panel::Mode_Lock); 183 | 184 | int ret = pam_start(APPNAME, loginPanel->GetName().c_str(), &conv, &pam_handle); 185 | // If we can't start PAM, just exit because slimlock won't work right 186 | if (ret != PAM_SUCCESS) 187 | die("PAM: %s\n", pam_strerror(pam_handle, ret)); 188 | 189 | // disable tty switching 190 | if(cfg->getOption("tty_lock") == "1") { 191 | if ((term = open("/dev/console", O_RDWR)) == -1) 192 | perror("error opening console"); 193 | 194 | if ((ioctl(term, VT_LOCKSWITCH)) == -1) 195 | perror("error locking console"); 196 | } 197 | 198 | // Set up DPMS 199 | unsigned int cfg_dpms_standby, cfg_dpms_off; 200 | cfg_dpms_standby = Cfg::string2int(cfg->getOption("dpms_standby_timeout").c_str()); 201 | cfg_dpms_off = Cfg::string2int(cfg->getOption("dpms_off_timeout").c_str()); 202 | using_dpms = DPMSCapable(dpy) && (cfg_dpms_standby > 0); 203 | if (using_dpms) { 204 | DPMSGetTimeouts(dpy, &dpms_standby, &dpms_suspend, &dpms_off); 205 | 206 | DPMSSetTimeouts(dpy, cfg_dpms_standby, 207 | cfg_dpms_standby, cfg_dpms_off); 208 | 209 | DPMSInfo(dpy, &dpms_level, &dpms_state); 210 | if (!dpms_state) 211 | DPMSEnable(dpy); 212 | } 213 | 214 | // Get password timeout 215 | cfg_passwd_timeout = Cfg::string2int(cfg->getOption("wrong_passwd_timeout").c_str()); 216 | // Let's just make sure it has a sane value 217 | cfg_passwd_timeout = cfg_passwd_timeout > 60 ? 60 : cfg_passwd_timeout; 218 | 219 | pthread_t raise_thread; 220 | pthread_create(&raise_thread, NULL, RaiseWindow, NULL); 221 | 222 | // Main loop 223 | while (true) 224 | { 225 | loginPanel->ResetPasswd(); 226 | 227 | // AuthenticateUser returns true if authenticated 228 | if (AuthenticateUser()) 229 | break; 230 | 231 | loginPanel->WrongPassword(cfg_passwd_timeout); 232 | } 233 | 234 | // kill thread before destroying the window that it's supposed to be raising 235 | pthread_cancel(raise_thread); 236 | 237 | loginPanel->ClosePanel(); 238 | delete loginPanel; 239 | 240 | // Get DPMS stuff back to normal 241 | if (using_dpms) { 242 | DPMSSetTimeouts(dpy, dpms_standby, dpms_suspend, dpms_off); 243 | // turn off DPMS if it was off when we entered 244 | if (!dpms_state) 245 | DPMSDisable(dpy); 246 | } 247 | 248 | XCloseDisplay(dpy); 249 | 250 | close(lock_file); 251 | 252 | if(cfg->getOption("tty_lock") == "1") { 253 | if ((ioctl(term, VT_UNLOCKSWITCH)) == -1) { 254 | perror("error unlocking console"); 255 | } 256 | } 257 | close(term); 258 | 259 | return 0; 260 | } 261 | 262 | void HideCursor() 263 | { 264 | if (cfg->getOption("hidecursor") == "true") { 265 | XColor black; 266 | char cursordata[1]; 267 | Pixmap cursorpixmap; 268 | Cursor cursor; 269 | cursordata[0] = 0; 270 | cursorpixmap = XCreateBitmapFromData(dpy, win, cursordata, 1, 1); 271 | black.red = 0; 272 | black.green = 0; 273 | black.blue = 0; 274 | cursor = XCreatePixmapCursor(dpy, cursorpixmap, cursorpixmap, 275 | &black, &black, 0, 0); 276 | XFreePixmap(dpy, cursorpixmap); 277 | XDefineCursor(dpy, win, cursor); 278 | } 279 | } 280 | 281 | static int ConvCallback(int num_msgs, const struct pam_message **msg, 282 | struct pam_response **resp, void *appdata_ptr) 283 | { 284 | loginPanel->EventHandler(Panel::Get_Passwd); 285 | 286 | // PAM expects an array of responses, one for each message 287 | if (num_msgs == 0 || 288 | (*resp = (pam_response*) calloc(num_msgs, sizeof(struct pam_message))) == NULL) 289 | return PAM_BUF_ERR; 290 | 291 | for (int i = 0; i < num_msgs; i++) { 292 | if (msg[i]->msg_style != PAM_PROMPT_ECHO_OFF && 293 | msg[i]->msg_style != PAM_PROMPT_ECHO_ON) 294 | continue; 295 | 296 | // return code is currently not used but should be set to zero 297 | resp[i]->resp_retcode = 0; 298 | if ((resp[i]->resp = strdup(loginPanel->GetPasswd().c_str())) == NULL) { 299 | free(*resp); 300 | return PAM_BUF_ERR; 301 | } 302 | } 303 | 304 | return PAM_SUCCESS; 305 | } 306 | 307 | bool AuthenticateUser() 308 | { 309 | return(pam_authenticate(pam_handle, 0) == PAM_SUCCESS); 310 | } 311 | 312 | string findValidRandomTheme(const string& set) 313 | { 314 | // extract random theme from theme set; return empty string on error 315 | string name = set; 316 | struct stat buf; 317 | 318 | if (name[name.length() - 1] == ',') { 319 | name.erase(name.length() - 1); 320 | } 321 | 322 | Util::srandom(Util::makeseed()); 323 | 324 | vector themes; 325 | string themefile; 326 | Cfg::split(themes, name, ','); 327 | do { 328 | int sel = Util::random() % themes.size(); 329 | 330 | name = Cfg::Trim(themes[sel]); 331 | themefile = string(THEMESDIR) +"/" + name + THEMESFILE; 332 | if (stat(themefile.c_str(), &buf) != 0) { 333 | themes.erase(find(themes.begin(), themes.end(), name)); 334 | cerr << APPNAME << ": Invalid theme in config: " 335 | << name << endl; 336 | name = ""; 337 | } 338 | } while (name == "" && themes.size()); 339 | return name; 340 | } 341 | 342 | void HandleSignal(int sig) 343 | { 344 | // Get DPMS stuff back to normal 345 | if (using_dpms) { 346 | DPMSSetTimeouts(dpy, dpms_standby, dpms_suspend, dpms_off); 347 | // turn off DPMS if it was off when we entered 348 | if (!dpms_state) 349 | DPMSDisable(dpy); 350 | } 351 | 352 | if ((ioctl(term, VT_UNLOCKSWITCH)) == -1) { 353 | perror("error unlocking console"); 354 | } 355 | close(term); 356 | 357 | loginPanel->ClosePanel(); 358 | delete loginPanel; 359 | 360 | die(APPNAME": Caught signal; dying\n"); 361 | } 362 | 363 | void* RaiseWindow(void *data) { 364 | while(1) { 365 | XRaiseWindow(dpy, win); 366 | sleep(1); 367 | } 368 | 369 | return (void *)0; 370 | } 371 | -------------------------------------------------------------------------------- /slimlock.pam: -------------------------------------------------------------------------------- 1 | #%PAM-1.0 2 | auth required pam_unix.so nodelay nullok 3 | -------------------------------------------------------------------------------- /switchuser.cpp: -------------------------------------------------------------------------------- 1 | /* SLiM - Simple Login Manager 2 | Copyright (C) 1997, 1998 Per Liden 3 | Copyright (C) 2004-06 Simone Rota 4 | Copyright (C) 2004-06 Johannes Winkelmann 5 | 6 | This program is free software; you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation; either version 2 of the License, or 9 | (at your option) any later version. 10 | */ 11 | 12 | #include 13 | #include "switchuser.h" 14 | #include "util.h" 15 | 16 | using namespace std; 17 | 18 | SwitchUser::SwitchUser(struct passwd *pw, Cfg *c, const string& display, 19 | char** _env) 20 | : cfg(c), 21 | Pw(pw), 22 | displayName(display), 23 | env(_env) 24 | { 25 | } 26 | 27 | SwitchUser::~SwitchUser() { 28 | /* Never called */ 29 | } 30 | 31 | void SwitchUser::Login(const char* cmd, const char* mcookie) { 32 | SetUserId(); 33 | SetClientAuth(mcookie); 34 | Execute(cmd); 35 | } 36 | 37 | void SwitchUser::SetUserId() { 38 | if( (Pw == 0) || 39 | (initgroups(Pw->pw_name, Pw->pw_gid) != 0) || 40 | (setgid(Pw->pw_gid) != 0) || 41 | (setuid(Pw->pw_uid) != 0) ) { 42 | logStream << APPNAME << ": could not switch user id" << endl; 43 | exit(ERR_EXIT); 44 | } 45 | } 46 | 47 | void SwitchUser::Execute(const char* cmd) { 48 | chdir(Pw->pw_dir); 49 | execle(Pw->pw_shell, Pw->pw_shell, "-c", cmd, NULL, env); 50 | logStream << APPNAME << ": could not execute login command" << endl; 51 | } 52 | 53 | void SwitchUser::SetClientAuth(const char* mcookie) { 54 | string home = string(Pw->pw_dir); 55 | string authfile = home + "/.Xauthority"; 56 | remove(authfile.c_str()); 57 | Util::add_mcookie(mcookie, ":0", cfg->getOption("xauth_path"), 58 | authfile); 59 | } 60 | -------------------------------------------------------------------------------- /switchuser.h: -------------------------------------------------------------------------------- 1 | /* SLiM - Simple Login Manager 2 | Copyright (C) 1997, 1998 Per Liden 3 | Copyright (C) 2004-06 Simone Rota 4 | Copyright (C) 2004-06 Johannes Winkelmann 5 | 6 | This program is free software; you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation; either version 2 of the License, or 9 | (at your option) any later version. 10 | */ 11 | 12 | #ifndef _SWITCHUSER_H_ 13 | #define _SWITCHUSER_H_ 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include "log.h" 24 | #include "cfg.h" 25 | 26 | 27 | class SwitchUser { 28 | public: 29 | SwitchUser(struct passwd *pw, Cfg *c, const std::string& display, 30 | char** _env); 31 | ~SwitchUser(); 32 | void Login(const char* cmd, const char* mcookie); 33 | 34 | private: 35 | SwitchUser(); 36 | void SetEnvironment(); 37 | void SetUserId(); 38 | void Execute(const char* cmd); 39 | void SetClientAuth(const char* mcookie); 40 | Cfg* cfg; 41 | struct passwd *Pw; 42 | 43 | std::string displayName; 44 | char** env; 45 | }; 46 | 47 | #endif /* _SWITCHUSER_H_ */ 48 | -------------------------------------------------------------------------------- /themes/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | subdirs (default) 2 | -------------------------------------------------------------------------------- /themes/default/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set (THEMES "themes/default") 2 | 3 | install(FILES slim.theme DESTINATION ${PKGDATADIR}/${THEMES}) 4 | install(FILES panel.png DESTINATION ${PKGDATADIR}/${THEMES}) 5 | install(FILES background.jpg DESTINATION ${PKGDATADIR}/${THEMES}) 6 | -------------------------------------------------------------------------------- /themes/default/COPYRIGHT.background: -------------------------------------------------------------------------------- 1 | Text. 04 is copyright (c) 2005 by rafael nascimento 2 | http://darkevil.deviantart.com 3 | -------------------------------------------------------------------------------- /themes/default/COPYRIGHT.panel: -------------------------------------------------------------------------------- 1 | Lila SVG Icon and Theme Artwork 2 | Copyright (C) 2004 Lila Community 3 | 4 | This program is free software; you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation; either version 2 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program; if not, write to the Free Software 16 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -------------------------------------------------------------------------------- /themes/default/LICENSE.panel: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 309 | 310 | 311 | Also add information on how to contact you by electronic and paper mail. 312 | 313 | If the program is interactive, make it output a short notice like this 314 | when it starts in an interactive mode: 315 | 316 | Gnomovision version 69, Copyright (C) year name of author 317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 318 | This is free software, and you are welcome to redistribute it 319 | under certain conditions; type `show c' for details. 320 | 321 | The hypothetical commands `show w' and `show c' should show the appropriate 322 | parts of the General Public License. Of course, the commands you use may 323 | be called something other than `show w' and `show c'; they could even be 324 | mouse-clicks or menu items--whatever suits your program. 325 | 326 | You should also get your employer (if you work as a programmer) or your 327 | school, if any, to sign a "copyright disclaimer" for the program, if 328 | necessary. Here is a sample; alter the names: 329 | 330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 332 | 333 | , 1 April 1989 334 | Ty Coon, President of Vice 335 | 336 | This General Public License does not permit incorporating your program into 337 | proprietary programs. If your program is a subroutine library, you may 338 | consider it more useful to permit linking proprietary applications with the 339 | library. If this is what you want to do, use the GNU Library General 340 | Public License instead of this License. 341 | -------------------------------------------------------------------------------- /themes/default/background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iwamatsu/slim/4a40caff34b52c9b9bcf8cbb83775ade9398d179/themes/default/background.jpg -------------------------------------------------------------------------------- /themes/default/panel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iwamatsu/slim/4a40caff34b52c9b9bcf8cbb83775ade9398d179/themes/default/panel.png -------------------------------------------------------------------------------- /themes/default/slim.theme: -------------------------------------------------------------------------------- 1 | # text04 theme for SLiM 2 | # by Johannes Winkelmann 3 | 4 | # Messages (ie: shutdown) 5 | msg_color #FFFFFF 6 | msg_font Verdana:size=18:bold:dpi=75 7 | msg_x 50% 8 | msg_y 40% 9 | msg_shadow_color #702342 10 | msg_shadow_xoffset 1 11 | msg_shadow_yoffset 1 12 | 13 | # valid values: stretch, tile 14 | background_style stretch 15 | background_color #eedddd 16 | 17 | # Input controls 18 | input_panel_x 25% 19 | input_panel_y 65% 20 | input_name_x 394 21 | input_name_y 181 22 | input_font Verdana:size=12:dpi=75 23 | input_color #000000 24 | 25 | # Username / password request 26 | username_font Verdana:size=14:bold:dpi=75 27 | username_color #f9f9f9 28 | username_x 280 29 | username_y 183 30 | password_x 50% 31 | password_y 183 32 | username_shadow_color #702342 33 | username_shadow_xoffset 1 34 | username_shadow_yoffset 1 35 | 36 | username_msg Username: 37 | password_msg Password: 38 | -------------------------------------------------------------------------------- /util.cpp: -------------------------------------------------------------------------------- 1 | /* SLiM - Simple Login Manager 2 | Copyright (C) 2009 Eygene Ryabinkin 3 | 4 | This program is free software; you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation; either version 2 of the License, or 7 | (at your option) any later version. 8 | */ 9 | 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "util.h" 18 | 19 | /* 20 | * Adds the given cookie to the specified Xauthority file. 21 | * Returns true on success, false on fault. 22 | */ 23 | bool Util::add_mcookie(const std::string &mcookie, const char *display, 24 | const std::string &xauth_cmd, const std::string &authfile) 25 | { 26 | FILE *fp; 27 | std::string cmd = xauth_cmd + " -f " + authfile + " -q"; 28 | 29 | fp = popen(cmd.c_str(), "w"); 30 | if (!fp) 31 | return false; 32 | fprintf(fp, "remove %s\n", display); 33 | fprintf(fp, "add %s %s %s\n", display, ".", mcookie.c_str()); 34 | fprintf(fp, "exit\n"); 35 | 36 | pclose(fp); 37 | return true; 38 | } 39 | 40 | /* 41 | * Interface for random number generator. Just now it uses ordinary 42 | * random/srandom routines and serves as a wrapper for them. 43 | */ 44 | void Util::srandom(unsigned long seed) 45 | { 46 | ::srandom(seed); 47 | } 48 | 49 | long Util::random(void) 50 | { 51 | return ::random(); 52 | } 53 | 54 | /* 55 | * Makes seed for the srandom() using "random" values obtained from 56 | * getpid(), time(NULL) and others. 57 | */ 58 | long Util::makeseed(void) 59 | { 60 | struct timespec ts; 61 | long pid = getpid(); 62 | long tm = time(NULL); 63 | 64 | if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) { 65 | ts.tv_sec = ts.tv_nsec = 0; 66 | } 67 | 68 | return pid + tm + (ts.tv_sec ^ ts.tv_nsec); 69 | } 70 | -------------------------------------------------------------------------------- /util.h: -------------------------------------------------------------------------------- 1 | /* SLiM - Simple Login Manager 2 | Copyright (C) 2009 Eygene Ryabinkin 3 | 4 | This program is free software; you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation; either version 2 of the License, or 7 | (at your option) any later version. 8 | */ 9 | #ifndef _UTIL_H__ 10 | #define _UTIL_H__ 11 | 12 | #include 13 | 14 | namespace Util { 15 | bool add_mcookie(const std::string &mcookie, const char *display, 16 | const std::string &xauth_cmd, const std::string &authfile); 17 | 18 | void srandom(unsigned long seed); 19 | long random(void); 20 | 21 | long makeseed(void); 22 | } 23 | 24 | #endif /* _UTIL_H__ */ 25 | -------------------------------------------------------------------------------- /xinitrc.sample: -------------------------------------------------------------------------------- 1 | # the following variable defines the session which is started if the user 2 | # doesn't explicitely select a session 3 | DEFAULT_SESSION=twm 4 | 5 | case $1 in 6 | xfce4) 7 | exec startxfce4 8 | ;; 9 | icewm) 10 | icewmbg & 11 | icewmtray & 12 | exec icewm 13 | ;; 14 | wmaker) 15 | exec wmaker 16 | ;; 17 | blackbox) 18 | exec blackbox 19 | ;; 20 | *) 21 | exec $DEFAULT_SESSION 22 | ;; 23 | esac 24 | --------------------------------------------------------------------------------