pax_global_header00006660000000000000000000000064137475650440014531gustar00rootroot0000000000000052 comment=652238da5071d68d02c5228494940f2c1e724f8b pekwm-release-0.1.18/000077500000000000000000000000001374756504400143615ustar00rootroot00000000000000pekwm-release-0.1.18/.gitignore000066400000000000000000000004661374756504400163570ustar00rootroot00000000000000aclocal.m4 autom4te.cache config.guess config.h /config.h.in config.log config.status config.sub configure compile depcomp install-sh missing stamp-h1 Makefile Makefile.in build src/.deps/ src/pekwm data/scripts/pekwm_themeset.sh data/scripts/pekwm_ws_menu.sh doc/fin/ doc/index.xml doc/logs/ *.o *.a *~ pekwm-release-0.1.18/AUTHORS000066400000000000000000000017331374756504400154350ustar00rootroot00000000000000-- AUTHORS for pekwm Author: * Claes Nasten Patchers: * Andreas - Bug fixing. - Code cleanup. * Jyri Jokinen - Documentation since 0.1.3. * Rando Christensen - Autoconf scripts. - Documentation since 0.1.1. - Ideas, bug reports and moral support. * Lurene Frenier - Make file patches. Moral support: * Alexandra Walford - Moral support. - English and CSS support. * Christoph Strake - Default Theme author. - WWW design consultant. Testers and Requsters: * Ashwin - Beta testing, many good bug reports. * Michael ? - GCC-3.1.0 compile verification. -- AUTHORS for aewm++ 1.0.16 Author: * Frank Hale -- AUTHORS for aewm Author: * Decklin Foster pekwm-release-0.1.18/CMake/000077500000000000000000000000001374756504400153415ustar00rootroot00000000000000pekwm-release-0.1.18/CMake/Makefile.am000066400000000000000000000001521374756504400173730ustar00rootroot00000000000000AUTOMAKE_OPTIONS = foreign SUBDIRS = Modules EXTRA_DIST = config.h.in distclean-local: rm -f *\~ .\#* pekwm-release-0.1.18/CMake/Modules/000077500000000000000000000000001374756504400167515ustar00rootroot00000000000000pekwm-release-0.1.18/CMake/Modules/FindIconv.cmake000066400000000000000000000030421374756504400216310ustar00rootroot00000000000000# - Try to find Iconv # Once done this will define # # ICONV_FOUND - system has Iconv # ICONV_INCLUDE_DIR - the Iconv include directory # ICONV_LIBRARIES - Link these to use Iconv # ICONV_CONST - the second argument for iconv() is const # HAVE_ICONVCTL - iconvctl is available # include(CheckFunctionExists) include(CheckCXXSourceCompiles) IF (ICONV_INCLUDE_DIR AND ICONV_LIBRARIES) # Already in cache, be silent SET(ICONV_FIND_QUIETLY TRUE) ENDIF (ICONV_INCLUDE_DIR AND ICONV_LIBRARIES) FIND_PATH(ICONV_INCLUDE_DIR iconv.h) FIND_LIBRARY(ICONV_LIBRARIES NAMES iconv libiconv libiconv-2 c) IF(ICONV_INCLUDE_DIR AND ICONV_LIBRARIES) SET(ICONV_FOUND TRUE) ENDIF(ICONV_INCLUDE_DIR AND ICONV_LIBRARIES) set(CMAKE_REQUIRED_INCLUDES ${ICONV_INCLUDE_DIR}) set(CMAKE_REQUIRED_LIBRARIES ${ICONV_LIBRARIES}) IF(ICONV_FOUND) check_cxx_source_compiles(" #include int main(){ iconv_t conv = 0; const char* in = 0; size_t ilen = 0; char* out = 0; size_t olen = 0; iconv(conv, &in, &ilen, &out, &olen); return 0; } " ICONV_CONST ) ENDIF(ICONV_FOUND) set(CMAKE_REQUIRED_INCLUDES) set(CMAKE_REQUIRED_LIBRARIES) check_function_exists(iconvctrl HAVE_ICONVCTL) IF(ICONV_FOUND) IF(NOT ICONV_FIND_QUIETLY) MESSAGE(STATUS "Found Iconv: ${ICONV_LIBRARIES}") ENDIF(NOT ICONV_FIND_QUIETLY) ELSE(ICONV_FOUND) IF(Iconv_FIND_REQUIRED) MESSAGE(FATAL_ERROR "Could not find Iconv") ENDIF(Iconv_FIND_REQUIRED) ENDIF(ICONV_FOUND) MARK_AS_ADVANCED( ICONV_INCLUDE_DIR ICONV_LIBRARIES ICONV_CONST ) pekwm-release-0.1.18/CMake/Modules/Makefile.am000066400000000000000000000001331374756504400210020ustar00rootroot00000000000000AUTOMAKE_OPTIONS = foreign EXTRA_DIST = FindIconv.cmake distclean-local: rm -f *\~ .\#* pekwm-release-0.1.18/CMake/config.h.in000066400000000000000000000006511374756504400173660ustar00rootroot00000000000000#ifndef _CONFIG_H_ #define _CONFIG_H_ #cmakedefine DEBUG #cmakedefine HAVE_SWPRINTF #cmakedefine HAVE_SETENV #cmakedefine HAVE_UNSETENV #cmakedefine HAVE_TIMERSUB #cmakedefine HAVE_SHAPE #cmakedefine HAVE_XINERAMA #cmakedefine HAVE_XFT #cmakedefine HAVE_XRANDR #cmakedefine HAVE_IMAGE_PNG #cmakedefine HAVE_IMAGE_JPEG #cmakedefine HAVE_IMAGE_XPM #cmakedefine HAVE_ICONVCTL #cmakedefine ICONV_CONST #endif // _CONFIG_H_ pekwm-release-0.1.18/CMakeLists.txt000066400000000000000000000054021374756504400171220ustar00rootroot00000000000000cmake_minimum_required(VERSION 2.8) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/CMake/Modules/") include(CheckSymbolExists) include(CheckCXXCompilerFlag) project(pekwm) set(pekwm_VERSION_MAJOR 0) set(pekwm_VERSION_MINOR 1) set(pekwm_VERSION_PATCH 18) set(pekwm_VERSION "${pekwm_VERSION_MAJOR}.${pekwm_VERSION_MINOR}.${pekwm_VERSION_PATCH}") # Check for C++11 check_cxx_compiler_flag(-std=c++11 HAS_CXX11) if (HAS_CXX11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") else (HAS_CXX11) message(FATAL_ERROR "Compiler with C++11 support is required") endif (HAS_CXX11) # Look for dependencies find_package(X11 REQUIRED) find_package(Iconv REQUIRED) find_package(Freetype) find_package(JPEG) find_package(PNG) # Look for platform specific methods check_function_exists(swprintf HAVE_SWPRINTF) check_function_exists(setenv HAVE_SETENV) check_function_exists(unsetenv HAVE_UNSETENV) check_symbol_exists(timersub sys/time.h HAVE_TIMERSUB) # Look for platform specific tools find_program(GSED gsed /usr/bin /usr/local/bin /usr/pkg/bin) if (GSED) set(SED ${GSED}) else (GSED) find_program(SED sed /usr/bin /usr/local/bin /usr/pkg/bin) endif (GSED) find_program(SH sh /usr/xpg4/bin/sh /bin/sh /usr/xpg4/bin) # Optons option(DEBUG "include verbose debugging code") option(PEDANTIC "turn on strict compile-time warnings") # Compilation if (X11_Xshape_FOUND) set(pekwm_FEATURES "${pekwm_FEATURES} XShape") set(HAVE_SHAPE 1) endif (X11_Xshape_FOUND) if (X11_Xinerama_FOUND) set(pekwm_FEATURES "${pekwm_FEATURES} Xinerama") set(HAVE_XINERAMA 1) endif (X11_Xinerama_FOUND) if (X11_Xft_FOUND AND FREETYPE_FOUND) set(pekwm_FEATURES "${pekwm_FEATURES} Xft") set(HAVE_XFT 1) endif (X11_Xft_FOUND AND FREETYPE_FOUND) if (PNG_FOUND) set(pekwm_FEATURES "${pekwm_FEATURES} image-png") set(HAVE_IMAGE_PNG 1) endif (PNG_FOUND) if (JPEG_FOUND) set(pekwm_FEATURES "${pekwm_FEATURES} image-jpeg") set(HAVE_IMAGE_JPEG 1) endif (JPEG_FOUND) if (X11_Xpm_FOUND) set(pekwm_FEATURES "${pekwm_FEATURES} image-xpm") set(HAVE_IMAGE_XPM 1) endif (X11_Xpm_FOUND) if (X11_Xrandr_FOUND) set(pekwm_FEATURES "${pekwm_FEATURES} Xrandr") set(HAVE_XRANDR 1) endif (X11_Xrandr_FOUND) if (DEBUG) set(pekwm_FEATURES "${pekwm_FEATURES} debug") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0") endif (DEBUG) if (PEDANTIC) set(pekwm_FEATURES "${pekwm_FEATURES} pedantic") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror -pedantic") endif (PEDANTIC) add_definitions(-DVERSION="${pekwm_VERSION}" -DFEATURES="${pekwm_FEATURES}" -DDATADIR="${CMAKE_INSTALL_PREFIX}/share" -DSYSCONFDIR="${CMAKE_INSTALL_PREFIX}/etc/pekwm") set(CMAKE_INSTALL_RPATH_USE_LINK_PATH True) # Subdirectories add_subdirectory(contrib) add_subdirectory(data) add_subdirectory(doc) add_subdirectory(src) pekwm-release-0.1.18/ChangeLog000066400000000000000000003577731374756504400161610ustar00rootroot00000000000000commit 4c838a40db929800e224c35b042d73d24266fbd0 Author: Andreas Schlick Date: Fri May 8 19:59:46 2009 +0200 Revert the session code. Rationale: Claes ran successfully pekwm under gnome without the session management code. The session code didn't actually load/save the session and therefore it is removed for 0.1.11. Should it cause any regressions under gnome I'll re-add it. commit e61768094f5ac329ed1341015afab16c11d96902 Author: Andreas Schlick Date: Fri May 8 17:19:51 2009 +0200 Add missing #ifdef to make --disable-session compile. commit d431299511ea4a2dbbc2238d1fc7dfda99494068 Author: Andreas Schlick Date: Thu May 7 23:45:02 2009 +0200 Remove unused _fd member from PScreen. commit cf2659d7048fd1a14e47787d7b8286c0f714f516 Author: Claes Nästén Date: Thu May 7 22:30:11 2009 +0200 A not so beautiful patch for making session shutdown work ok. With this logging out from Gnome also shuts down pekwm successfully, and it's possible to start it by setting the window manager gconf value. In the future file descriptors probably should be possible to match with event handlers or similar to simplify this logic. commit 71ab91eeb2d56f7e2f2732b57c53ae7c0ec0911a Author: Claes Nästén Date: Fri May 1 20:14:32 2009 +0200 Ops, did not include the scripts directory when fixing for BSD make. commit 38f050fe74136ca570acda9812f3d7fc9452c996 Author: Claes Nästén Date: Fri May 1 10:26:43 2009 +0200 make Makefile less BSD hostile, seems to work with OpenBSD make now. commit 9f3e133cbc28a62c978891e3d533a1d96200733f Author: Claes Nästén Date: Wed Apr 29 09:06:42 2009 +0200 Add PKG_CONFIG macros, OpenBSD does not include this. OpenBSD does not include the pkg config macros, just a perl reimplementation of pkg-config. Add this to make autoconf play. commit 0e1077a366ec99fff9b45d758a3f3a432e013517 Author: Claes Nästén Date: Sun Apr 26 22:27:37 2009 +0200 Make default keybindgs handle multi-row workspace layouts. Navigating vertically has not been supported with the default keybindings, changed the up/down to with shift modifier. Also increased the default workspace count to 9. commit 6349e8b1743081b957ad3a20720a45ee9ef14eb3 Author: Claes Nästén Date: Sun Apr 26 22:18:30 2009 +0200 Remove log file from repository, should not be there. commit c5aa19853cd3de1cd3a1588839dd07762b07901e Author: Claes Nästén Date: Sun Apr 26 22:15:57 2009 +0200 Add Nvidia FAQ entry and update mkdocs.sh with settings for Fedora. One of the worst FAQ entries ever, hopefully it is informative enough. Also, made sure the docs are building on Fedora 11. commit 755f5b0a4bdaf6f619c21c9bbf261280cd2f8032 Author: Claes Nästén Date: Sun Apr 26 20:23:38 2009 +0200 strtold doesn't exist on OpenBSD, use strtod instead. commit ead1a87154370ef8e798518545cb5b5d443f83d7 Author: Claes Nästén Date: Sat Apr 25 00:13:25 2009 +0200 Fix spelling of image in the theme documentation reported by markand. commit 44c17cd32cb3f0fa5c5c41d6735a4dca21477ca3 Author: Claes Nästén Date: Wed Apr 22 21:55:16 2009 +0200 Add --replace option to the man page. commit 6c8214b1306b92bbaf73ed3f36a7dc1c85f9dd36 Author: Andreas Schlick Date: Tue Apr 21 12:39:18 2009 +0200 Change some of the casts to use static_cast. commit c3058ddc13a5b5901b7e7d4cd908dc7768edab03 Author: Andreas Schlick Date: Mon Apr 20 23:56:44 2009 +0200 Reload the key-bindings when an input device changes (#173). Reported and fixed by Wallex. commit b2da3b96854856c29b661739a540d90bc9dbacf9 Author: Andreas Schlick Date: Mon Apr 20 23:25:56 2009 +0200 Add config option to disable support for aspect ratio. commit 0ed3b0a0bbe3f6b77f797f92252164c2c5069f90 Author: Andreas Schlick Date: Mon Apr 20 23:17:04 2009 +0200 Add support for XSizeHints' PAspect (aspect ratio of windows, see #171). commit cb1533f6adadc1c845bba3b0bd8be59018c9348c Author: Claes Nästén Date: Mon Apr 20 23:11:33 2009 +0200 Move error handler to PScreen and make it possible to replace current wm. Now pekwm is able to replace metacity in recent gnome releases and take over as the window manager, it still doesn't know how to give the session up when exiting though. commit 11ce948c8dd725ac6ef01ed4cd4e88ff36447d48 Author: Andreas Schlick Date: Mon Apr 20 00:49:35 2009 +0200 Change the default theme to use a smaller title bar (created by Adriano). commit ceab99812c016e01fd63b44576d7a5c9d0482e9c Author: Andreas Schlick Date: Sat Apr 18 23:04:03 2009 +0200 Fix the test in AM_CONDITIONAL([HAVE_SESSION], ..). commit 3c0d8e9dd414dbc6373d306bc47ab21a63283dd7 Author: Claes Nästén Date: Tue Apr 14 19:23:49 2009 +0200 Make session support a compile time option. It is now possible, per io-error's request, to disable session support when compiling pekwm. commit e5ac974192f2cea31755758f59e72de2d7bc4a3a Author: Claes Nästén Date: Tue Apr 14 19:07:54 2009 +0200 Alpha blending for different color depths, 15 and 16. commit ad0e50a080c3e6033c3b600d14c075e7d93ea5f9 Author: Claes Nästén Date: Tue Apr 14 18:22:38 2009 +0200 Fix invalid keys from causing BadAccess errors, and make Any work again. After fix for #142 Any did not work anymore as the key section identifying Any was never reached. commit d1aebc00406af0a3508f8bccaaa496765434a343 Author: Claes Nästén Date: Mon Apr 13 19:44:29 2009 +0200 Inline instead of static, make the compiler much happier. commit 300d481eadc1a4475ef8f1f45110f6441d245b7f Author: Claes Nästén Date: Mon Apr 13 19:43:30 2009 +0200 Move selection of root window input to RootWO. I think it makes more sense having as much as possible of the root window handling in RootWO and not in WindowManager which includes way to much stuff. commit b81e0e03004690a662d340609a2b8126c6866068 Author: Andreas Schlick Date: Sun Apr 12 23:04:20 2009 +0200 Move the body of Util::to_upper and Util::to_lower to the header file. commit 5c28eae032ac1bb4a1e178aafa46ec65708e388c Author: Andreas Schlick Date: Sun Apr 12 22:47:58 2009 +0200 Change Config::parseKey() to use the to_lower/to_upper functions from Util. commit 4acd0cf46f5e04705463d1a3398a1bd40ce16754 Author: Andreas Schlick Date: Sun Apr 12 15:27:15 2009 +0200 Change the keys configuration file to use "Prior" instead of "Prev". commit a2bd7da32898baab1c1f646def98fad62eb1d8e0 Author: Andreas Schlick Date: Sun Apr 12 15:02:19 2009 +0200 When parsing a key-string try different upper-/lowercase combinations (#142). commit 14d6e363a5d142e8cb93266a5e6db4e5cdeea879 Author: Andreas Schlick Date: Sat Mar 14 22:33:56 2009 +0100 Commit a experimental fix for #166. Please report if it breaks anything. The removed if-clause caused unfocusable windows to be ignored and thereby being put below windows of a lower layer. commit 7c2fc41442c5e0a6a5a67e83d00ad5cfbf8e4812 Author: Andreas Schlick Date: Sun Apr 5 18:58:46 2009 +0200 Fix a typo in the documentation that was reported by Rikard Lindsröm. commit 51cb6f37f80c00704afd0273657b81ed26b454b4 Author: Claes Nästén Date: Sat Apr 4 21:53:07 2009 +0200 More on session handling, cleans up a bit of the WindowManager destructor. This code is not yet working as it should, but it at least a start. commit e4f5c6ee880795be1254ecae550b96d8473d9d95 Author: Claes Nästén Date: Sat Apr 4 14:08:09 2009 +0200 Add start of session handling, just adding the non interfering. Start adding session handling code, not very functional, tested or working but a first step. commit 1c05fbd5116be94b872171b1835ad78c574ead5a Author: Claes Nästén Date: Wed Mar 11 06:53:04 2009 +0100 Add string, manager and wm_class hints. commit c3cb8c679611d46f339935d0309179804f50cb54 Author: Claes Nästén Date: Wed Mar 11 06:50:42 2009 +0100 Get username added to utility functions, to be used in session. commit 857326ff4bbfbab621c809cc28f4c3385d09bad1 Author: Claes Nästén Date: Tue Mar 10 23:04:33 2009 +0100 Make desktop and dock not focusable. To make pekwm behave better with gnome-panel and nautilus in sloppy focus mode, do not allow them to focus. Interaction is done with mouse anyway. commit d272889f689f8ff4ab2e1ab24124f69c8e0ec77e Author: Andreas Schlick Date: Mon Mar 9 20:37:16 2009 +0100 Fix Harbour::restack() to re-add its _strut if windows shouldn't maximise over the harbour (#156). commit aa3be5a350cea1c810ab00faca2151b3af21059c Author: Claes Nästén Date: Thu Feb 19 22:56:28 2009 +0100 Compile fixes for GCC on OpenSolaris 2008.11 It seems as if GCC complained more than CC under OpenSolaris with default compiler flags. While at it I updated the autogen.sh script to look for version 1.10 and not 1.9 of automake. commit c72ea308376c26ba7251bd041a7427688b82a7f0 Author: Andreas Schlick Date: Mon Feb 16 16:28:39 2009 +0100 Fix the spelling of the space binding (#142). commit 4e1890eee7d4ffca7912c7feed3fe27a5377f723 Author: Andreas Schlick Date: Tue Feb 10 16:20:47 2009 +0100 Update the copyright notes. commit 2777ec6b59fbd78c290fc72d6208293499f6876d Author: Daniel Moerner Date: Fri Jan 30 14:53:53 2009 -0800 Make .pekwm/themes dir on first run This patch makes a ~/.pekwm/themes directory if it doesn't already exist when pekwm is run, mimicking the behavior of other config files in ~/.pekwm. This is useful to prevent an ugly "No such directory $HOME/.pekwm/themes" when using the default menu in a fresh installation of pekwm. commit 3d048ad5f41664a7888080570a2d8ec9a538eca5 Author: Daniel Moerner Date: Fri Jan 30 01:26:54 2009 +0100 Properly handle empty theme directories in menu script This patch fixes two bugs: First, any arbitrary file in the theme directory will no longer be treated as a theme--only directories will be listed. Second, if the directory is empty and '*' is therefore passed as the theme_name, '*' will not be added to the theme list. Since we use sh and not bash, nullglob is not an option so a test must be used. commit 0f4e7059031b3ecea83ec64ea64afeab81c01398 Author: Andreas Schlick Date: Thu Jan 29 14:13:10 2009 +0100 Set version back to GIT. commit a677a4b62528531754f1541634df45464bf28b98 Author: Claes Nästén Date: Mon Jan 26 18:13:49 2009 +0100 Update to use templates fully, seems to be working ok now. commit fd54d2775b78874b6bdad98a3912af62dda5238e Author: Claes Nästén Date: Mon Jan 26 16:22:27 2009 +0100 Fix font and change indentation. commit fb1eca1dc601c09fbe6d6705f03a5765ed15c46e Author: Claes Nästén Date: Mon Jan 26 15:10:31 2009 +0100 Final changes to ChangeLog commit 720fefb20032ff2eade947d73744b6f90546342c Author: Claes Nästén Date: Mon Jan 26 15:08:51 2009 +0100 Fix destdir for default-plain file. commit 9eb00b48ddf37b59a9e54f6c5252f5209f277687 Author: Claes Nästén Date: Sun Jan 25 20:44:26 2009 +0100 Update ChangeLog and set version to 0.1.10 commit 41dbd72f529f79e9f809d0951ddea6e86970fc60 Author: Andreas Schlick Date: Sun Jan 25 14:44:31 2009 +0100 No change to the code, just some typos fixed. commit fbe63b8871d1e689adb15a6641c1d147c72fd3a1 Author: Claes Nästén Date: Sun Jan 25 18:42:07 2009 +0100 Ops, || is not the same as && The mouse configuration would not load if pekwm was not installed (system configuration files) was not installed and the system config would always be the "master" with this setup. commit 0f6cecf09129cc83b2fcc14f63abbc8b23d71c65 Author: Claes Nästén Date: Sun Jan 25 13:43:01 2009 +0100 Check included files when doing re-load. This will resolve issues with chaning ~/.pekwm/vars, doing a reload and nothing happens as the main configuration file had not changed. This patch does not cover graphics loaded, but I think the imagehandler should take care about that. commit c32b7923350c36288f985504f3ca0b963882a15b Author: Claes Nästén Date: Sun Jan 25 11:27:31 2009 +0100 Fix placement issue after the search dialog has been used. The PMenu showing results in the search dialog was included when placing windows causing windows being placed with an offset after the search dialog had been used. commit fe1b3c7501a671a7bc9db97e7c55d24485c47fc5 Author: Claes Nästén Date: Sat Jan 24 13:21:28 2009 +0100 Improve documentation generation to add actual warning messages. Documentation generation gives more helpful error messages now and does not hard-code platform dependant files in the XML anymore. Under NetBSD the following packages are required: * opensp * docbook-xml * dsssl-docbook-modular * perl And optionally: * tidy (nicer html) * tex-jadetex (pdf generation) * zip (zip files) commit 6a22affa43c10e50b5b9d510d1bd8efb9aead425 Author: Claes Nästén Date: Sat Jan 24 12:29:19 2009 +0100 Limit pointer warping to screen edge size + 2 instead of * 2. commit 31567e442925cf93c4e985cf6202952a7edf98fb Author: Claes Nästén Date: Sat Jan 24 12:29:02 2009 +0100 Avoid compile warnings, float to unsigned int casting. commit 8a6b7e47648d368eca46e25a211dc6b997823cb6 Author: Claes Nästén Date: Sat Jan 24 12:25:12 2009 +0100 Add include_empty parameter to splitString, default to false. When using separators such as space and tab when splitting strings it is not inituitive to include empty tokens (having two spaces after each other). However, using ; as a separator ;; should include an empty token. commit c511b0412cc0434ef8d4f3bc8c4e7ea03e179520 Author: Andreas Schlick Date: Mon Jan 19 22:59:39 2009 +0100 Updated documentation for mailing lists. commit cfe4fc43e6001337b6068726ed548e34759ba798 Author: Claes Nästén Date: Thu Jan 8 21:54:25 2009 +0100 Add autoconf dependencies to acinclude.m4 commit 2a637dfae019e57e70499af3300dbed4f226ac15 Author: Claes Nästén Date: Thu Jan 8 21:26:51 2009 +0100 Make pekwm_themeset.sh much faster avoiding a lot of forks. commit e01ba5a1cc3c5185b3d0a8a5320413998f1da85e Author: Andreas Schlick Date: Wed Jan 7 21:49:30 2009 +0100 A few cosmetic changes (indentation, spelling). commit a3925ad28d39f1af6fc1bb3bc33d0cfda94125af Author: Andreas Schlick Date: Wed Jan 7 21:42:09 2009 +0100 Bugfix for #131 ("Search dialog stops focusing selected client"). commit 7ddf51d751bedad65fa480cee2d74aa7c1b2b5f8 Author: Claes Nästén Date: Sun Jan 4 21:34:29 2009 +0100 Add new default theme, enabled only if png support is available. commit 316bb4ef3afe15071d40699d6f52c6ab2e455b94 Author: Claes Nästén Date: Sun Jan 4 21:06:39 2009 +0100 Rename PImageNative* to PImage*, there is no other type of image. commit 2c2c0ec4579d7df939a55b77a33275c81e8e974d Author: Claes Nästén Date: Sun Jan 4 12:46:03 2009 +0100 Fix potential crash bug (mis-placed error output) and make icons use alpha. commit 9ed2b874128d295f5f33a73956ea91eb9abf3ab2 Author: Claes Nästén Date: Sat Jan 3 22:13:19 2009 +0100 Ops, missing ~ and state modifiers was not stripped. This seems to be fixing #129, was missing a ~ in the stripping of state modifiers and when that function being ok and called in the handlers things seemt to be ok. commit 21bace12530b448e06a59b2aeb99b24c34d07838 Author: Claes Nästén Date: Sat Jan 3 02:27:00 2009 +0100 Start on rendering transperent images correctly, works ok in the menu. commit e49065442e5a990ca60e66165194b6aa778e923c Author: Claes Nästén Date: Sat Jan 3 02:25:40 2009 +0100 Introduced use_alpha to complement has_alpha. In order to avoid rendering with alpha composition even if the image is 100% solid use_alpha was introduced which is true if there are transparenet pixels in a image. commit 5afda71035954d271ffd5ab8db4ba64a5dd572fc Author: Claes Nästén Date: Sat Dec 27 11:36:51 2008 +0100 Fallback to XParseColor in xpm loading to support more than #ffffff formats. commit d032b5dd8cb05ba2d90fba3b6a645a79dae9ddd1 Author: Claes Nästén Date: Mon Dec 22 19:03:50 2008 +0100 Final fixes before 0.1.9a commit c2057b53d565674f45d8fd5058e1801052cdd81a Author: Claes Nästén Date: Mon Dec 22 15:46:47 2008 +0100 Fix crash issue end of list item not detected. commit b48fdd3c9dffbecc5e03e6a0ec5709d6b1cff60d Author: Andreas Schlick Date: Sun Dec 21 22:18:50 2008 +0100 Fix the bug that a lower-action produces a raise-action. commit 8019bbc60a011da24edde40910cbcfffefcdd2cb Author: Claes Nästén Date: Sun Dec 21 14:44:34 2008 +0100 Update ChangeLog before release. commit 84611e4ec1ac7b79d84ad3bb85cc695907f5a821 Author: Claes Nästén Date: Sun Dec 21 14:30:54 2008 +0100 Update configuration files for 0.1.9 commit e0c39871446a1ac31d6f1a933c6e75786809ff01 Author: Claes Nästén Date: Sun Dec 21 14:16:30 2008 +0100 Add link in README and update menu mouse events names. commit 16ad93bfdf56f9bf2d6eb2556f80615ab82365dd Author: Claes Nästén Date: Sun Dec 21 14:14:52 2008 +0100 Fix #119, make sure dock app gets placed on the screen edge after resize. commit 47014c960e33f9bda71b2d469932148570b32217 Author: Claes Nästén Date: Sun Dec 21 14:02:43 2008 +0100 Update documentation, missing updates since 0.1.8. commit 6bc1e56860f253f70c8761515f25a191b7aceea5 Author: Claes Nästén Date: Sun Dec 21 14:01:17 2008 +0100 Update default configuration file, introduce new features. commit 5ce58a637bc158327ddd6a019194bfe9f83f9850 Author: Claes Nästén Date: Sun Dec 21 12:45:18 2008 +0100 Re-work client restacking, select first element in search dialog. Now stacking seems to be working ok both with and without harbour enabled. SearchDialog also renders the first item as selected when it is mapped. commit a3b40e241064c142a6030710af3fe2e4aab9cb75 Author: Claes Nästén Date: Sat Dec 20 18:43:10 2008 +0100 Filter out non-focusable and skip focus toggle windows in SearchDialog. commit ca32fe2f28eafd534a7d154e994e76033ea65f37 Author: Claes Nästén Date: Sat Dec 20 18:27:49 2008 +0100 Make icon size limitations actually work. commit 0f779deaaa51d70daae6e31300ef00401d74c786 Author: Andreas Schlick Date: Thu Dec 18 00:26:31 2008 +0100 Set new default window type properties. commit a6eed5eaf8a847b1c31805dedb1ead23dcbf2c56 Author: Andreas Schlick Date: Thu Dec 18 00:21:21 2008 +0100 Bugfix for incorrectly set default window type properties. commit f9693c92c700c00ee0aa387d6c015399b502feba Author: Andreas Schlick Date: Thu Dec 18 00:19:48 2008 +0100 Small indentation and spelling fix. commit cd0ae893dd8ae6af7a075d2bfaff7d8ceaafa9f3 Author: Claes Nästén Date: Wed Dec 17 22:31:16 2008 +0100 Start on new limit on menu icon sizes. To have per-menu (class) icon size restrictions KoFish suggested to have a syntax like Menu { Icons = "ROOT" { Minimum = "32x32" Maximum = "64x64" } } Not tested, most likely not working. commit d8c77975f990b877a31f905bb2bd472ded82aaef Author: Claes Nästén Date: Wed Dec 17 19:35:52 2008 +0100 Make templates available in autoproperties only with require syntax. In order to support having templates overwriting in autoproperties file a Require section was added just as in the theme file. To enable templates overwriting add this to your autoproperties file: Require { Templates = "True" } To support defining title and role in the matching enabling templates also enables an extended autoproperties syntax. Example: Property = "name,class,role,title,apply on" { Sticky = "True" } Enjoy! commit 26466f1a8401607e5cdb741e23200405383c1682 Author: Claes Nästén Date: Wed Dec 17 19:35:07 2008 +0100 Bug fix in split string, it previously skipped empty elements. commit 156cd1b36ea817c6036836c9736592ed4b391084 Author: Claes Nästén Date: Wed Dec 17 18:38:55 2008 +0100 Only strip button modifiers in stripButtonModifiers. commit 760f90c42ac7bf55c4600f979285b54f7c0e65db Author: Claes Nästén Date: Tue Dec 16 09:42:56 2008 +0100 Tidying menu creation, code style changes. commit 496ec5ea9728313614ef858f0ac2efca5e549a01 Author: Claes Nästén Date: Tue Dec 16 09:42:38 2008 +0100 Remember position before completion on completion and restore on abort. commit e594c54131c6a75c71f3f7e0b93efbc5ee392c14 Author: Claes Nästén Date: Mon Dec 15 20:43:16 2008 +0100 Initial commit on tab completion for the command dialog. This is case sensitive and currently only does path completions, however it is a start. commit 8da517445d48c5af0419104f03f71da3c99a99d7 Author: Andreas Schlick Date: Fri Dec 12 11:45:32 2008 +0100 Fix the check for already loaded colors in FontHandler::getColor(.). commit 92cc32c8f4fd7d8aad57c5580c142ed65c07f22c Author: Andreas Schlick Date: Fri Dec 12 11:44:06 2008 +0100 Remove _free_on_return_{font,color} from FontHandler and related functions. returnColor() and returnFont() will now free the resources when no reference is hold anymore. commit 6bd1c36ef58f26418a84aba2c85629ad61a657ac Author: Andreas Schlick Date: Fri Dec 12 11:38:40 2008 +0100 Remove functions from FontHandler that are never used. commit 9b16978e5b8fde4f9cd3b7fb005583a4396ab82c Author: Andreas Schlick Date: Fri Dec 12 11:35:45 2008 +0100 Consolidate the different classes and enums for the atoms. commit 71f650ab7c43a1351dff14b7e2ef0e71a8d5c7b5 Author: Claes Nästén Date: Mon Dec 8 18:56:34 2008 +0100 Make use of gotoClient in ActionHandler to active found client. commit 2aef5ee05f4eaec136a21d94f31e1aee55ad2e8f Author: Claes Nästén Date: Mon Dec 8 18:38:47 2008 +0100 Ah, menu was cleared all the time. Now fixed and search dialog working ok. New action ShowSearchDialog seems to be working ok now, doing something nice when the menu grows too big etc is not yet implemented. Not sure what a sane strategy would be. commit af18fad44248cd495c2037b8dd1a200e9bc822fe Author: Claes Nästén Date: Mon Dec 8 18:31:00 2008 +0100 Cleanups in re-building menu code to support fixed with menus better. commit a43748d9b9f7efbf6ac58ab9d737edfaecc548e1 Author: Claes Nästén Date: Mon Dec 8 18:28:00 2008 +0100 Work on SearchDialog, results are found and displayed. Issues with next/prev. Now most basic issues that was around seems to have been resolved, still it is not possible to select previous/next item with the arrow keys. Seems to be an PMenu issue? commit 3ea3f4996a489036187c3d6cdc571b78b2f21ac2 Author: Claes Nästén Date: Sun Dec 7 22:20:46 2008 +0100 Add new sub folder to build system, where are all the files? commit adf17946458f665577ca740c57efc1c1b6afdda6 Author: Claes Nästén Date: Sun Dec 7 22:06:28 2008 +0100 Add scripts by Matt Hayes to contrib folder, autoprops and config menu. These scripts are also available at http://nxc.ath.cx/lobo/filez/pekwm/ and requires perl and thus is not part of the main distribution. Closing #64 to export autoprops. commit 8c3e239c4d07eb205ba0ea0525f9e8a319f7068f Author: Andreas Schlick Date: Sun Dec 7 18:59:54 2008 +0100 Remove PMenu::Item::_dynamic. commit 486fe28b9e6c19ce8d778bf3c864efbb17229f75 Author: Andreas Schlick Date: Sun Dec 7 18:56:06 2008 +0100 Fixing the still broken dynamic menus (#75). commit f18d7ba1f50495d5ccb45c2e0f360c8a093db1d7 Author: Andreas Schlick Date: Sun Dec 7 18:54:29 2008 +0100 Bugfix: Windowmanager must not delete _harbour after freeing _root_wo. commit 7c305fb24131f314a2919c9bb6034b0369722cae Author: Andreas Schlick Date: Sun Dec 7 18:53:30 2008 +0100 Bugfix: SearchDialog missed a destructor to free its _result_menu. commit af88e4d29e14e852f438a4d4a3ff2fd0a3793d64 Author: Andreas Schlick Date: Sun Dec 7 18:51:02 2008 +0100 Bugfix: Add missing initialising of CfgParser::_is_dynamic_content. commit 28c07f7dfa750bd6a4022c83345949c484eb340e Author: Claes Nästén Date: Sun Dec 7 18:24:06 2008 +0100 Do not add space for icons when there's no icon in the menu. commit 4ab86d2c6be0e3b2cfcc7a33e09ae7058f0b3953 Author: Claes Nästén Date: Sun Dec 7 18:23:41 2008 +0100 Ops, issues with button press/release handling. Hopefully ok now. commit b780a1ac2029d1fd1b2bd729346631a031f304e6 Author: Claes Nästén Date: Sat Dec 6 14:05:44 2008 +0100 More fixing for menu click menu selections, now works. Closing #13 commit 471f5e8113a353b9f68a50e2d68ecd35618383ca Author: Claes Nästén Date: Fri Dec 5 21:10:42 2008 +0100 Make it possible to select menu entries while holding mouse button. The start of nicer menu handling, not 100% there yet considering closing the menu and maybe interference with other actions. commit b2a09684531885540869a075d9b87a50d9ca9192 Author: Claes Nästén Date: Fri Dec 5 19:58:39 2008 +0100 Add regular expression syntax, a general formatting cleanup is required. commit 92b25c48b318800c0b234b722133f85dbc4c07b7 Author: Claes Nästén Date: Fri Dec 5 19:30:10 2008 +0100 Fix #104, make sure pointer is released on is the same as pressed. commit d5f010f8204bb7293bb4690d710128810d077569 Author: Claes Nästén Date: Thu Dec 4 21:56:06 2008 +0100 Include first 9 workspaces in goto/send-to actions. commit b68d07a0f12ee7c941097c722e77e6c0070c8e84 Merge: 014fac9... 241eef9... Author: Claes Nästén Date: Thu Dec 4 21:52:26 2008 +0100 Merge branch 'searchdialog' Conflicts: src/CmdDialog.cc src/Frame.cc src/PWinObj.hh src/WindowManager.cc commit 241eef99dee8ed2142c4a95d183704f70a109b12 Author: Claes Nästén Date: Thu Dec 4 21:43:03 2008 +0100 Where did these changes go, I'm not playing nice here it seems. commit f42c5cd376aea67ef4f5bb5eba90b387be5a0787 Merge: 433fb98... 4de33c1... Author: Claes Nästén Date: Thu Dec 4 21:24:58 2008 +0100 Merge branch 'searchdialog' of ssh://me@pekdon.net@projects.pekdon.net/srv/git/pekwm into searchdialog Conflicts: src/Client.cc src/CmdDialog.hh src/InputDialog.hh src/SearchDialog.cc src/SearchDialog.hh commit 014fac9c962696b99fb02400426d1eeb88218745 Author: Claes Nästén Date: Sun Nov 30 17:42:59 2008 +0100 Update default configuration with icon sizes. commit 91dc0997b86d78d7c685b0af8f9a067ca4f9fcc9 Author: Claes Nästén Date: Sun Nov 30 17:36:36 2008 +0100 Enable template overwriting for more configuration files. Closing #103 This enables templates in auto properties, mouse configuration and the keygrabber. It is not enabled in the menu as it is 100% valid to have multiple entries at each level with the same name. commit 320a5d3e8642df11b57ea3aa2ee2a92290a0679b Merge: 2015c1f... 05b470b... Author: Claes Nästén Date: Sun Nov 30 15:59:43 2008 +0100 Merge branch 'master' of ssh://me@pekdon.net@projects.pekdon.net/srv/git/pekwm commit 2015c1f5ac7f8d10c3e9245e52c7bb4d07e7293a Author: Claes Nästén Date: Sun Nov 30 15:59:24 2008 +0100 Ops, s/_NET_WM_VISIBLE_NAME/_NET_WM_VISIBLE_ICON_NAME/ commit db7359695afa9181e1d52eb36dbed299159ff743 Author: Claes Nästén Date: Sun Nov 30 15:59:03 2008 +0100 Start implementation of demands attention hint. commit f11081fb8e4d022bbba56cf3bdfb8a5f566f7eb3 Author: Claes Nästén Date: Sun Nov 30 15:57:10 2008 +0100 Icon can now specify ordinary texture, falls back on scaled image texture. Now Icon in menus first tries to load it as an full texture specification, if that fails it is loaded as an scaled image texture with the icon value as the image. commit 1e42384d2e6c682a40d6e67cfee38daac6a1381f Author: Claes Nästén Date: Sun Nov 30 15:55:38 2008 +0100 Implement new icon menu size restriction options. Now it is possible to set the following in the Menu section of the default configuration file. IconWidthMin, minimum width of icons, 0 to disable check. IconWidthMax, maximum width of icons, 0 to disable check. IconHeightMin, minimum width of icons, 0 to disable check. IconHeightMax, maximum height of icons, 0 to disable check. commit 0ee6821792013daf18017191b41ec1806d4f41ff Author: Claes Nästén Date: Sun Nov 30 15:54:32 2008 +0100 Replace CfgParserKeyInt with CfgParserKeyNumeric. commit 05b470b3c81f95c7e414cd4688321d1d6436fa00 Author: Jyri Jokinen Date: Sun Nov 30 06:55:33 2008 +0200 minor fixes to faq entries and language commit 9ae13ad3016bc24ba1302cce319d15682789fa44 Author: Claes Nästén Date: Fri Nov 28 22:55:15 2008 +0100 Fix #110, render resize/move information centered on the window being moved. This introduces a new option in the main configuration file under the Screen section, ShowWorkspaceCenteredOnRoot. When set to false, the WorkspaceIndicator is centered on the window being moved/resize and not the current head. commit 0f213782507697c79177b095da6a5dce3448c306 Author: Claes Nästén Date: Fri Nov 28 15:13:18 2008 +0100 Move windows inside screen when resizing screen size. This got lost somewhere, or was it ever supported? Anyway, changing screen resolution should now move windows inside visible range. commit 3c24847d340d9892a4965adf307f4443952754a3 Author: Claes Nästén Date: Tue Nov 25 22:03:37 2008 +0100 Work on EWMH support, _NET_WM_ICON_NAME and _NET_WM_VISIBLE_ICON_NAME. Currently pekwm does not do anything with the icon names, but now it is at least read correctly. commit f7c2cedb4f4450c21cd6e3beab3f146faf993e9b Author: Claes Nästén Date: Tue Nov 25 21:33:05 2008 +0100 Work on #72, add _NET_DESKTOP_GEOMETRY and_NET_WORKAREA hints. commit b237dcaa8203323d4607594c4ef37b416ab75ddf Author: Claes Nästén Date: Tue Nov 25 15:26:03 2008 +0100 Fix #109, do not fixup geometry if specified in autoprops. It is possible to specify size and position with autoprops, stay away from changing the geometry to fit the screen if that is done as we then assume the user know what he/she is doing. commit 3ed59886a8d7ea12c412891a83caa135945528e4 Author: Claes Nästén Date: Mon Nov 24 22:15:02 2008 +0100 Work on #109, export CLIENT_PID and CLIENT_WINDOW to environment. Now it is possible to grab client PID and Window from dynamic scripts, they are available as $CLIENT_PID and $CLIENT_WINDOW. Example dynamic script: #!/bin/bash cat << EOF Dynamic { Entry = "Info" { Actions = "Exec xmessage \"PID: $CLIENT_PID WINDOW: $CLIENT_WINDOW\"" } } EOF Put that in the window menu as this: Entry { Actions = "Dynamic /path/to/dynamic.sh" } And it should pop up PID: pid WINDOW: window in an xmessage. commit b6bc171b6aa9e24de8c418285d87248877e7779a Author: Claes Nästén Date: Mon Nov 24 21:43:37 2008 +0100 Big commit, move things away from WindowManger to ManagerWindows. EdgeWO and RootWO was moved into ManagerWindows and HintWO was created which handles setting hints etc. Move MWM hints into Atoms, should not have been in the WindowManager in the first place. commit e173e1bc75c7f2bf6483245d649b0cf01ea1e933 Author: Claes Nästén Date: Mon Nov 24 21:41:59 2008 +0100 Start rename inst to instance in WindowManager. commit 0175ac37b675a2c152745a30e4fc15ea10f4cc5d Author: Claes Nästén Date: Sat Nov 22 19:54:04 2008 +0100 Arg, missing , caused head-ache trying to figure why text property broke. "str1" "str2" is valid for creating one string "str1str2", this caused the atoms parsing offset incorrect. commit 80dcadb2a894f1f99262e40b2d36984fee3ceaba Author: Claes Nästén Date: Thu Nov 20 20:35:44 2008 +0100 Start detection of remote clients, should set the decor to REMOTE. Start reading the WM_CLIENT_MACHINE in order to detect wheter or not clients are remote also support this to group clients by pid, then grouping also needs to be done by host. commit 4a0629c1250cc922ca6d06dcf941760c3f147ae6 Author: Claes Nästén Date: Thu Nov 20 20:34:55 2008 +0100 Code style cleanups. commit b889e7b426b482acb9362d0161f1cc84af74f7e9 Author: Claes Nästén Date: Thu Nov 20 20:32:42 2008 +0100 Add AtomUtil::getTextProperty and use in client. Shorten down code reading client name and icon name by using common code now placed in AtomUtil namespace. commit 3f4d16f71070a1c703674e5c47deb706bdaafe9e Author: Claes Nästén Date: Tue Nov 18 19:50:16 2008 +0100 Scale menu icons and some small cleanups. commit ba0e513595264d6a003f811575c3f56d6d0f2afa Author: Claes Nästén Date: Mon Nov 17 21:52:03 2008 +0100 Add is_dynamic_content to CfgParser and re-set mtime to cfgs. To avoid re-load issues with configuaration files using COMMAND, this previously did not re-load on reloads. commit 96fe3f8d15b3cd6fcf670a9f56523bc5a8901fbb Author: Claes Nästén Date: Mon Nov 17 21:51:07 2008 +0100 Load icons correctly when building dynamic menus. commit 1732ad39efc14014b4e84b2c06d18e895a476e2d Author: Claes Nästén Date: Sun Nov 16 19:22:32 2008 +0100 Implement #98, add Icon to the Entry. This includes quite a few changes in order to support loading icons from a set of directories. Documentation updates included. commit 9e1f275854c76332c258a90d1922da4922ad1e25 Author: Claes Nästén Date: Sat Nov 15 19:03:28 2008 +0100 Start asymetric tab support based on patch from Justin Rebelo (hermit) This is not yet working, it seems to be partially shrinking tabs and it does not grow them properly at all. commit d02f51c4221f5f61e33ee5da737487d1a9d6ff95 Author: Claes Nästén Date: Fri Nov 14 17:43:20 2008 +0100 Add WorkspaceIndicator FAQ entry. commit ef7f7aba281747014355f813a9216f00875a6d89 Author: Daniel Moerner Date: Fri Nov 14 09:02:29 2008 +0100 Close #95, fix compile issues with gcc-4.4. pekwm currently fails to build with gcc-4.4 development snapshots. gcc-4.4 has stricter rules for includes, and indirectly including cstdio through other headers no longer works. I have applied the following to the Debian source to fix this problem. commit e939bbff3d90479e03b0fc8e930df79375267080 Author: Claes Nästén Date: Wed Nov 12 21:41:35 2008 +0100 Fix #82 having the workspace not being showed when changing workspace with pager commit 0b33e758b3bf5256ef3eb683cde7ceed36d12550 Author: Claes Nästén Date: Wed Nov 12 21:36:43 2008 +0100 Fix #80, CmdDialog backwards compatibility. InputDialog decorations was previously called CmdDialog, add compatibility code to support both names. commit 77a49b2cda0185382f175e173fcfc9478cbda71b Author: Claes Nästén Date: Wed Nov 12 21:23:03 2008 +0100 Update decor name documentation closing #89. commit 447c1dbb18884bc547d2afe886e5df8149c75698 Author: Claes Nästén Date: Wed Nov 12 21:15:31 2008 +0100 Small comments and style cleanups. commit 46a3798c456e8cc353dadff94a637f3828fb0079 Author: Matt Hayes Date: Wed Nov 12 21:13:01 2008 +0100 Patch closing #88 TitleRules on Pekwm generated menus. Apply adopted patch from Matt Hayes, using a ClassHint on the PMenu instead of creating a new one each time the rule is setup. To make this complete, setting of Role should be done on all menu types. commit 4bd180405c597b5d04ea2cddaf123cfd90f4ef15 Author: Claes Nästén Date: Wed Nov 12 21:08:31 2008 +0100 Update default configuration to have edgesize per edge configuration. In order to make it easier to "detect" that EdgeSize support per-edge configuration, set it in the default configuration. It is already in the documentation. commit 6f5b7dec551de536bf9475f2c3a4b6259c4b64e2 Author: Matt Hayes Date: Wed Nov 12 21:04:44 2008 +0100 Close #86 icons should be configurable in Focus Frame window. Patch from Matt Hayes, changed name and position of DisplayIcons. commit 0b617f56d573de0b686deaa9ee51eb10d56beccd Author: Claes Nästén Date: Wed Nov 12 20:41:38 2008 +0100 Add FAQ for multiple buttons in themes with template syntax. Closing #90. commit 7e3052621383d8682a0279fdd4cbb0edbfa0d709 Author: Claes Nästén Date: Wed Nov 12 20:39:36 2008 +0100 Start restructuring theme documentation with docbook syntax. Previously the theme documentation was text only, start structuring as a docbook document. Not near to being complete yet. commit 599361d25421da4ff435569656eaf93128c00654 Author: Claes Nästén Date: Wed Nov 12 14:34:30 2008 +0100 Close #91, s/Hoover/Hover/ also keeping backwards compatibility. commit 375a575d8f1c77692cf6931ceeeb2825a957db1e Author: Vladimir A. Pavlov Date: Tue Nov 4 11:57:18 2008 +0100 Close #84, unable to make mplayer window fullscreen. I installed pekwm-0.1.8 and when I started watching movie with mplayer and pressed 'f' (make mplayer fullscreen) the size of the window remains the same, not fullscreen, although its content changed so that I could see the top-left region of the movie in the small window. It looked like mplayer incorrectly "thought" the size of the window changed. The bug seems to be in the code introduced by the revision 7bd7afc250a9f7578de7e38b5ed5925af8860de1. When debugging I discovered that sometimes ev->value_mask includes CWStackMode and doesn't include CWY/X/Height/Width. In such case if the window had been already maximized earlier then the code sets fullscreen state to STATE_UNSET which is wrong. The obvious fix (the attached one) is to set fullscreen state only if one of CWY/X/Height/Width was found in ev->value_mask. But I guess the actual error is in another place where somebody passes ev->value_mask with anything unexpected (CWStackMode) althought it should not. What do you think? P.S. The bug appears only when FullscreenDetect is True or unset (since it defaults to True) commit 8aab298d86261f9cd489ebe22a102375755fd014 Author: Andreas Date: Tue Nov 4 01:54:52 2008 +0100 Implement #81 by loading local configuration files after copying them. commit 9d4691f304752e47fc0f0270d8c8efdca9a72a35 Author: Andreas Date: Thu Oct 30 00:18:13 2008 +0100 Fixes some spelling mistakes in the documentation. commit 85799c7d6be1c9194d3b0c7f5f7b9a2281922fcc Author: Claes Nästén Date: Wed Oct 29 22:12:12 2008 +0100 Changes to the configure script. commit ad5a586adccafcc84273713b46f87c05c2ae0db5 Author: Andreas Date: Wed Oct 29 20:29:27 2008 +0100 Fixes some spelling mistakes in the documentation. commit 7f0ef5c858700ba9580163c746f19df91d53ff91 Author: Claes Nästén Date: Mon Oct 27 09:27:33 2008 +0100 Add missing includes to Compat.hh commit a6944a1f21fd453f3d9dcee184f63904ce23e5ce Author: Claes Nästén Date: Sun Oct 26 15:48:51 2008 +0100 Add preliminary swprintf compat code for fixing OpenBSD compat. Noticed in the OpenBSD port of pekwm patches exist to work around use of swprintf, this implements partial swprintf support which should be enough to get things working. commit c032ac5fe2c231cf13e095dc32cd0605cf1bd5ff Author: Claes Nästén Date: Sun Oct 26 09:52:47 2008 +0100 Start on minimal pekwm manual page "pointing" to the web site. commit a1f32141eaf87fbd9bff175a71e74a2f3d92e0c1 Author: Claes Nästén Date: Sat Oct 25 19:13:19 2008 +0200 Change default of CfgParser::clear and use AtomUtils in desktop names reading. Changed the default parameter of CfgParser::clear to realloc by default as the only case when alloc will not be wanted is in the CfgParser destructor. Clean-up and make use of AtomUtils in new desktop name reading code, not sure if this works though. commit 062b5bf751a483576bbfd923d689b1c886e0c09e Author: Andreas Date: Wed Oct 22 18:10:44 2008 +0200 Call WindowManager::readDesktopNamesHint() when the hint is changed. commit affd012be56be675a56766afe241ea645691666e Author: Andreas Date: Wed Oct 22 18:10:16 2008 +0200 Add a function to WindowManager to read the _NET_DESKTOP_NAMES hint. commit 0a26ea4cddc3bc669b7c48ba78f2a671ced28353 Author: Andreas Date: Wed Oct 22 18:09:50 2008 +0200 Add a function to Config to set the workspace names from an utf8 string. commit d6f6618dc4ba5b5275981d1bc86e8c80d05fd246 Author: Claes Nästén Date: Thu Oct 23 16:09:38 2008 +0200 Force use of / as regexp separator, not the first character. commit 4c796b158c72a962cd6d4ad8024cf43111389ff6 Author: Andreas Date: Wed Oct 22 17:16:16 2008 +0200 Fix a wrong memory access. splitString() is sometimes (in Config.cc) called with a string str from its second parameter toks. str is therefore a reference to a sting object in vector but by changing vec later it invalidates this reference. The solution is to not pass str by reference or change all calls to splitString(). We do the former. commit 06085fcded1632d61b4f1bdf45bcc3c33fe4db84 Author: Andreas Date: Wed Oct 22 17:02:03 2008 +0200 Change return type of AtomUtil::getPropoerty to bool. commit 83d1c11d6935fb92cd153eb5fc43120930c2a1dc Author: Andreas Date: Wed Oct 22 17:00:28 2008 +0200 Fix compiling with --enable-pedantic. commit cd1e92b0a06ee7bdceb53d90dfa1e14506709ae5 Author: Andreas Date: Wed Oct 22 17:00:04 2008 +0200 Fix access to uninitialised memory. commit 95820d7830a6507afe81779b2bc142f261558a37 Author: Andreas Date: Wed Oct 22 16:59:31 2008 +0200 Fix access to already freed memory. commit 38c62e99bc0dae05dfa37de6dca44b606dbef67e Author: Andreas Date: Wed Oct 22 16:58:35 2008 +0200 Fix memory leak in CfgParser. commit 54b53a3134da9131b1cc0074c796b8e1c22e4d92 Author: Andreas Date: Wed Oct 22 14:33:49 2008 +0200 Change getDesktopNamesUTF8() to be const. commit 4aec7a1cb6e66efa4439d366e02175b1de09de92 Author: Claes Nästén Date: Wed Oct 22 11:37:48 2008 +0200 Fix overriding section values on section with values. :-O Hmm, to explain it a bit further here is an example: Define = "FOO" { Bar = "1" { Value = "1" } Bar = "2" { Value = "1" } } And you wanted to override the value of Value in Bar = "2", this was not possible before as the value "2" was never looked for. commit 28b0a0cf2eab89637bc01cba840180270d08ede3 Author: Aristotle Pagalztis Date: Wed Oct 22 00:28:34 2008 +0200 fix data Makefiles to allow out-of-tree build commit bbed3989edf7c546cb6728336e56e9f901562c2a Author: Claes Nästén Date: Tue Oct 21 20:29:41 2008 +0200 Add Require section to themes. To avoid breaking themes from pre 0.1.8 and to support detecting incompabilities before loading themes a require section has been added. This currently only supports Templates = "True" / "False" switch which enables/disables the new template syntax overriding. commit a68d7f8fb29272483439ec4f3fecaecaf8708845 Author: Claes Nästén Date: Mon Oct 20 18:20:31 2008 +0200 Cleanup of fix for #33 and re-load workspace name on reload. Less code and more C++ like, seems to be working fine here. commit 609d95179e51c2f49d6e4c98f721a4b0cf75f39e Author: Andreas Date: Sun Oct 19 23:33:59 2008 +0200 Add support for _NET_DESKTOP_NAMES (#33). commit 24736ee9b7d622b6e1d1e72c5381353e84402b90 Author: Andreas Date: Sun Oct 19 22:48:54 2008 +0200 Fix comments on string conversion functions. commit 85de360f19be513ecbb10f8e5fc696eb5b04cc6a Author: Claes Nästén Date: Sun Oct 19 17:20:17 2008 +0200 Enable decoration switching when activating client in a Frame. Previously decor properties was only matched on when the client updated it's title and not when you change active client in a Frame. commit 74d0a9eb3fac88d1bc0023654df416428030eab3 Author: Claes Nästén Date: Sun Oct 19 17:14:48 2008 +0200 Make use of Hoover state for buttons, closing #41 Parsing of button hoover state has been around for ages but has not actively been used. Added code hoovering buttons. commit 2f6a9ce662a39ca9e658bd451926debf5cce6659 Author: Claes Nästén Date: Sun Oct 19 16:46:06 2008 +0200 Support // style regexps by default and cleanup or_ naming. Now // style regexps are used by default if the first and last character in the regexp are the same. commit 202bf2a4137cf38152bca3bcc0faa24ec8ba3a7e Author: Claes Nästén Date: Sun Oct 19 11:10:21 2008 +0200 Fix copying of sections, thought this was already comitted. commit ddb8e8f9a2e5bc39a885c8df6bc38365045bf845 Author: Claes Nästén Date: Sat Oct 18 20:11:53 2008 +0200 Fix default configuration file when creating WindowManager. commit 35ef075b4d6f37928f92e409fba37905da4d536a Author: Claes Nästén Date: Sat Oct 18 19:54:02 2008 +0200 Style changes, s/NULL/0/. commit f16174d75ceb02b7a220b2dd79a4e01bf1b0374a Author: Claes Nästén Date: Sat Oct 18 19:32:16 2008 +0200 Remove un-used gettext code and fix include in main.cc General gettext support was not in place anyway, will re-write this when/if it becomes relevant. commit 965d19cedc7ae7d15c354e187fa12b3499d61a80 Author: Claes Nästén Date: Sat Oct 18 18:00:13 2008 +0200 Fix g++-4.3 compile warnings and replace NULL with 0 commit 43e69751395582ae6b6044c879d5ca674f0f0c6a Author: Claes Nästén Date: Sat Oct 18 16:41:42 2008 +0200 Make DecorRules reload on title change. Now it is possible to get different decors when changing titles on windows, this can be useful to get all your "root" terminals end up red so you do not poweroff the wrong machines. commit 94478b800a6c5d738af921bf41169493e801a200 Author: Claes Nästén Date: Sat Oct 18 12:13:58 2008 +0200 Add conditional re-loading of files, changing theme now only reloads 2 files. Before re-loading a check on mtime and path is done before reloading, this seems to be working fine but has two drawbacks (that I currently can see) which are: * Changing a theme image file will not make the theme to reload as the theme definition is left unchanged. * Updating an included file will not make the file including it reload. To avoid issues with the either touch the file, restart or wait for a force option to reload. commit f1a4273455032c01828046f2595d5df4af8f9770 Author: Claes Nästén Date: Fri Oct 17 19:41:44 2008 +0200 Limit when overwriting is ok due to unique vs non-unique sections. commit f552747ce6f1a2ce452669993e0e9fed5923af0b Author: Claes Nästén Date: Fri Oct 17 13:55:22 2008 +0200 Support overriding attributes in sub sections, closing #23. commit 1b27282359abc9ec33fa7aeaa39b8e0f3052ed23 Author: Claes Nästén Date: Thu Oct 16 16:34:16 2008 +0200 Fix ops in parsing after structure update, now border and edges should work. commit cc1ff4ed0be3210c039f4338fa629ff3b30e17ea Author: Andreas Date: Wed Oct 15 00:31:43 2008 +0200 Just a hack to allow the configuration of a resize for a mouse motion event. commit 3fa9c90154ff9de8a2012218165b021c94dd3062 Author: Andreas Date: Wed Oct 15 00:31:20 2008 +0200 Trigger ButtonRelease config even when ButtonPress does a resize (#60). commit 9c7e31bc969cef6e7694accbbbb953933fcd86ee Author: Andreas Date: Wed Oct 15 00:30:48 2008 +0200 Generally check event's window and event's subwindow member for a valid border window (similar to the last patch). commit 69f21a298b215e9c0d395886f28db4e6ed32f93a Author: Andreas Date: Wed Oct 15 00:27:12 2008 +0200 Allow ButtonRelease on the decor (see #60). However, if ButtonPress is configured to do a resize, this doesn't work, because Frame::doResize() eats the ButtonRelease event. commit 0eb33f36389242158e842f5844b63c1698eaaeb9 Author: Claes Nästén Date: Thu Oct 16 14:25:40 2008 +0200 Fix ops in autoprops parsing, update conifg and docs with small... commit bd0060b6e3b717b4f26d9b68d3d1cefa3b2edfa4 Author: Claes Nästén Date: Thu Oct 16 14:03:07 2008 +0200 Add HonourRandr option, fix issues with Xinerama vs Randr. Some drivers provide both randr and xinereama information, if you want xinerama should be used instead of randr set HonourRandr to False. commit d72f78ca0a5ad87e325a43887582041bbabcda49 Author: Claes Nästén Date: Thu Oct 16 10:59:14 2008 +0200 Add missing algorithm include, reported by smurfd. commit b240062e8df575c442671bc6d55ddec47ffa72ed Author: Claes Nästén Date: Wed Oct 15 22:40:11 2008 +0200 Work on #23, template in use for themes but loading of configuration not 100% Template code is starting to take shape, configuration loading is not 100% yet. commit d0ffaaa54d4864241a5711fafd126ef43fc3a776 Author: Claes Nästén Date: Wed Oct 15 13:49:12 2008 +0200 Re-work CfgParser structure, use list instead of homegrown list. First step in cleaning up the CfgParser structure, parsing code a bit updated but find_* should return iterators instead of actual elements. commit 433fb988d2003673423daa111e20ce5cf6239b0e Author: Claes Nästén Date: Sun Jul 20 18:04:41 2008 +0200 Start on fixed width menus to be used in searchdialog for displaying results. commit aa4c99c127462b1c6feebeffbfb4d0cdd0da83b4 Author: Claes Nästén Date: Sun Jul 20 17:54:11 2008 +0200 Move wo_ref from CmdDialog to InputDialog as it is to be used in SearchDialog commit 7261c762cd4a3f361700fad84ef015d7c8ee1a3a Author: Claes Nästén Date: Tue Oct 14 19:35:43 2008 +0200 Update default mouse configuration, Vertical workspace navigation. commit ca9b7e54f5db793016698d607b6c235847733f8d Author: Claes Nästén Date: Tue Oct 14 19:29:06 2008 +0200 Start cleaning of reload and actually reload InputDialog texture closing #67 commit 924f6fdaeae19c5456d5387efb093f72badb0032 Author: Andreas Date: Tue Oct 14 13:35:12 2008 +0200 Fix continuous-focus-switching bug. commit dbee6ff35bb5f21e704208203b473af110138580 Author: Andreas Date: Fri Oct 10 17:01:27 2008 +0200 This should probably fix #38 (vnc issue). Longer explanation (as far as I understand it): A client that uses the "Locally Active" input model (see ICCCM 2.0 §4.1.7) may delegate its input focus to one of its subwindows. If this happens, a FocusOut event for the top level window is generated but pekwm does not get the FocusIn event for the subwindow (because it is not managed by pekwm ?!). WindowManager::handleFocusOutEvent() then gives the input focus to the root window and thereby removing the input focus from the client completely. commit 96dbb189110eda75aa53a7e42c485ce940fe742e Author: Andreas Date: Fri Oct 10 16:36:58 2008 +0200 Call PScreen::setLastEventTime() for skipped events. commit 3b8e66840efe965aa7048146fecde8401876e28d Author: Andreas Date: Fri Oct 10 16:31:57 2008 +0200 Add Client::sendTakeFocusMessage() and call it from Client::giveInputFocus(). commit 6c54e7516ddefe14b6e90f159e88606de0352356 Author: Andreas Date: Mon Oct 6 16:47:43 2008 +0200 Change return value from giveInputFocus() from bool to void. The return value was never used anyway. commit dabc94342c6c6abfbfcaef5ac92536bee25382dd Author: Andreas Date: Thu Oct 9 16:02:21 2008 +0200 Change type of PScreen::_last_event_time to Time. commit 4631a0bf6d6fcc7f487fe9f91c89ca09a8c15e5b Author: Andreas Date: Mon Oct 6 16:46:24 2008 +0200 Fix a compile error when using ./configure --disable-harbour --enable-pedantic. commit 062ee33fbf5dd111581b4641bdff49df0a62d25e Author: Andreas Date: Wed Oct 8 17:35:14 2008 +0200 Initialise Theme::_harbour_texture correctly. This fixes a possible crash when pekwm is shutdown. commit 61ffb8939da7d77ef73346e7d7350ab717f66121 Author: Claes Nästén Date: Tue Oct 7 23:51:32 2008 +0200 Only find window to focus if menu had focus in HideAllMenus. Closing #65 commit 25db0c25df08f09ba06b58cf730d8c92f0a46dec Author: Andreas Date: Mon Oct 6 16:45:11 2008 +0200 Indentation clean up of Frame::handleConfigureRequestGeometry() with additional change of the if-clause. commit fe61e00a64ee9c2699ec7ce2167b355c60af2545 Author: Claes Nästén Date: Sun Oct 5 19:31:23 2008 +0200 Start on @template syntax for configuration files, not working yet. Data seems to be copied over just fine but overwriting does not work yet, should fine to use for things such as defining @BORDER for decors and the like. commit aa0a21844694ec0881ee5d3172ddd2ae811cb127 Author: Claes Nästén Date: Fri Oct 3 10:40:18 2008 +0200 Fixes for mkdocs script, now works on Ubuntu Hardy. commit 8307a4fbe7cf1e18a1bfe54bb811b52b48c9d1ba Author: Claes Nästén Date: Fri Oct 3 10:33:49 2008 +0200 Style cleanup of CfgParserSource. commit 93534951358ddfd36ded0ac687472ab824a38c1d Author: Claes Nästén Date: Thu Oct 2 08:47:47 2008 +0200 Cleanup of naming in CfgParser, first go. Start cleaning CfgParser before looking at templates in configuration. This code has not been tested much. commit ad511f0dd8de6e00781592084b99e7ad49495e79 Author: Andreas Date: Mon Sep 29 17:15:07 2008 +0200 Changes Config::getWorkspaceName() to a more concise form. commit 03eb26a686d2427308c68d030752a353520ddb16 Author: Andreas Date: Mon Sep 29 17:08:34 2008 +0200 Just code style cleaning (2/2). commit d21cbbb11611cbb7cb57071cf557742d85c762f3 Author: Andreas Date: Mon Sep 29 17:02:17 2008 +0200 Just code style cleaning (1/2). commit 7bd7afc250a9f7578de7e38b5ed5925af8860de1 Author: Claes Nästén Date: Mon Sep 29 22:36:28 2008 +0200 First try to get fullscreen detection, code has not yet been tested. This introcuses a new option, FullscreenDetect to be put in the Screen section. When True pekwm will try to detect non EWMH fullscreen requests and make the window go to real fullscreen mode (removing decoration and raising it). commit b15e00fea34232dba87226008328edcc67f93b6e Author: Claes Nästén Date: Mon Sep 29 22:17:51 2008 +0200 Remove some ifdefs around SHAPEing commit 33394a6b599c9205f4d6f032420c70b27ceaeec2 Author: Andreas Date: Mon Sep 29 15:22:12 2008 +0200 Makes the "raise true" action work on unselected tabs. Together with the last commit a01e05c18 this fixes task #59. commit a01e05c18316c84de86f2c5a09a15d7ec5065bb9 Author: Andreas Date: Thu Sep 25 15:13:43 2008 +0200 Removes 'static' keyword from a few variables in Config.cc and cleans up the initialisation of the Action class. commit f5395090cb7cfceaf94cab1ac8d2cc2a68ce2493 Author: Vladimir Marek Date: Wed Sep 24 11:28:58 2008 +0200 Fix compilation with SunStudio, missing std:: for find. commit 88eeb5c87a72e45c2083709000b79702e1903559 Author: Andreas Date: Tue Sep 23 14:43:18 2008 +0200 Handle top level windows with window gravity != NW correctly. commit 2ef821e253bcb144500e075a024f3693e65e117d Author: Andreas Date: Sun Sep 21 15:25:39 2008 +0200 Fix Client::moveResize(). It updates its geometry now. commit 2a501740b4e375bfc3e939c0549b2929bb912bcd Author: Claes Nästén Date: Mon Sep 22 10:12:49 2008 +0200 Convert ShowWorkspaceIndicator to milliseconds instead of seconds. The 1 second display of the WorkspaceIndicator is too long, make it configurable in milliseconds instead and set the default time to 0.5 seconds. commit 96b60f54821456bbe03691639ca3c18bf78e11c1 Author: Jyri Jokinen Date: Mon Sep 22 08:49:11 2008 +0200 Fix #63 above dialog issue. Looks like a brainfart. This trivial patch should fix it. commit c4527978b82174b3a43909c5618ee715d547325f Author: Claes Nästén Date: Sun Sep 21 12:36:01 2008 +0200 CmdDialog history persistance, now actually tested and with documentation. Now the code actually is tested minimally and documentation is in place, still needs more testing I would guess. commit 8bed7cf4b3a5fa4bfc8ec5ea94fb8768ac0032c4 Author: Claes Nästén Date: Sat Sep 20 20:06:26 2008 +0200 Start on CmdDialog history persistance. New CmdDialog section has been introduced to the main configuration file. The CmdDialog section currently only configures the history aspects of the CmdDialog. The default section looks like this: CmdDialog { HistoryUnique = "True" HistorySize = "1024" HistoryFile = "~/.pekwm/history" } commit 973f97b522e1a7dd278326a7e3b65e012f9a648b Author: Claes Nästén Date: Sat Sep 20 19:08:24 2008 +0200 Add file_backed_list for use in CmdDialog. List for use in the CmdDialog for persisintg configuration between sessions, untested code. commit 70988e8fe0e35382a324ecbdddd6e8c3fe2f4e83 Author: Claes Nästén Date: Sat Sep 20 18:51:59 2008 +0200 Make CfgParserKeyPath expand default value. commit e903c7b3bab44b578c43b5c438121d91bba6b768 Author: Nathan Howard Date: Tue Sep 16 20:48:06 2008 +0100 Fix fix for #56, use enableval rather than custom variable commit 891047b4f822ceaf483dc39e1d09ef4c8b1def15 Author: Nathan Howard Date: Mon Sep 15 23:48:42 2008 +0100 #56 Fix: make sure we test right variable commit 155e1c311d6a464ef9e44260a513b065e8d5b45b Author: Andreas Date: Sun Sep 14 14:47:24 2008 +0200 Fix small copy&paste error in Frame::Frame(). _non_fullscreen_decor_state was initialised with client->getLayer(). commit 4b129941c9e030a0c5b39ef221ee99965f84c433 Author: Claes Nästén Date: Tue Sep 9 22:06:09 2008 +0200 Add FullscreenAbove configuration option, closing #61 It is now configurable to make applications going to fullscreen mode being raised above other windows, this is set to true as default as I guess most users will want it even though I have turned off. commit 45797d285880fe181de0de17a3413c76e976ec06 Author: Jérôme Pigeot Date: Sat Aug 30 11:07:15 2008 +0200 Update theme explanation file to use docbook structure. commit 5ee205f63aa52c47c3a7ce74cff6e7d523bdb028 Author: Claes Nästén Date: Tue Aug 12 23:04:09 2008 +0200 Work-around #56, somehow xrandr interferes with png. Nathan reports doing --disable-xrandr also disabled png image support, moving the xrandr test further down makes it work but I wonder what is actually causing this. commit 5f39fa2d94ad5fc1d06cf0e1486c3b4b3cebd65a Author: Vladimir A. Pavlov Date: Sun Aug 10 12:58:58 2008 +0200 Fix strut reading on x86_64, use long and not CARD32, closing #51. The bug is that on x86 sizeof(long)==4 and sizeof(CARD32)==4 while on x86_64 sizeof(long)==8 and sizeof(CARD32)==4. So if I have pypanel at the bottom of the screen the strut array is { 0, 0, 0, 24 } each element being of 8 bytes length. But pekwm assumes them to be of type CARD32 that's only 4 bytes, and it sees only the first 16 (zero) bytes of the actual array and therefore it doesn't properly apply the strut cause windows overlap the panel. The fix is to replace all the arrays of CARD32 with arrays of long when working with Xlib. I looked through pekwm sources and found only two places where CARD32 arrays are used. commit 43e1201c8dbe15ce4aaec929a2e5267247bfc6d9 Author: Claes Nästén Date: Sat Aug 9 20:18:20 2008 +0200 Rename custom.dsl to pekwm.dsl to avoid conflicts. commit 8c6bfae31bdd9a81f69f2df452f806c6e64551a0 Author: Claes Nästén Date: Fri Aug 8 09:24:38 2008 +0200 Updates on themeset script, use SED found by configure, and find to find themes. Try to make things more correct and work on more variants of sed, it seems as if sed on NetBSD does not support the i flag (? is that true ?), also make sure there is a theme file in theme directories by using find. commit 3ea8a8c84136b87d22e89da64405b054d2535615 Author: Claes Nästén Date: Wed Aug 6 22:55:35 2008 +0200 Back to GIT version after 0.1.7 release and tag. commit 502bc44912bac628ead111c820c335941a99c979 Author: Claes Nästén Date: Wed Aug 6 22:35:20 2008 +0200 More updates before 0.1.7 release, missing files and version set. commit aec08f709f2488547abad7e0e075d4c8de3d4a55 Author: Claes Nästén Date: Wed Aug 6 22:19:27 2008 +0200 Fix typo in mkdocs.sh script for pdfjadetex script. commit c86cfc371fe5b28ea4dc6fb2cfa686a36f9dda2c Author: Claes Nästén Date: Wed Aug 6 18:29:10 2008 +0200 Add WorkspaceIndicator theme documentation. commit 3daa79cb89d40e42a3b484b538ba4f2b198bf7dd Author: Matt Hayes Date: Wed Aug 6 18:22:30 2008 +0200 Fix s/COLOR/FONT/ in WorkspaceIndicator themeing. commit 9fd7010503cac491beaa9051a19813d2fb6d6715 Author: Claes Nästén Date: Wed Aug 6 18:18:36 2008 +0200 Apply modified patch by Matt Hayes for WorkspaceIndicator Fixes in the padding of WorkspaceIndicator to take theme variables into account. commit 0d7caa41d3820cc13792cb2559cc77fc108e15bc Author: Claes Nästén Date: Wed Aug 6 18:15:07 2008 +0200 Start to clean up mkdocs.sh script, fix UTF-8 issues in name and set version. commit d42f9aaead355bad57be76a31c305799cb842f7b Author: Claes Nästén Date: Wed Aug 6 17:39:32 2008 +0200 Start cleaning of mkdocs.sh script, depend on bash and re-indent. commit 78d4b464edd2f31c089777012b8c6299c484e9cb Author: Claes Nästén Date: Wed Aug 6 17:37:31 2008 +0200 Add check for /usr/xpg4/bin/sh and use in menu scripts for Solaris. Fix scripts to run under solaris by default. Use AC_PROG_SED instead of AC_CHECK_PROGS to find a suitable sed command. commit 7aa268021094771fbb5db38b5d44b2e83a104993 Author: Claes Nästén Date: Wed Aug 6 15:15:48 2008 +0200 Use libpng12 instead of libpng in pkg-config check, works under Solaris. commit 0515284ff9a47ee570abccb5e4358381b08ef853 Author: Claes Nästén Date: Tue Aug 5 23:49:19 2008 +0200 Small documentation updates after looking at the ChangeLog. commit ddb01a228aeeb98d04b65c98ebc522c6b0a53fc2 Author: Claes Nästén Date: Tue Aug 5 23:06:24 2008 +0200 More references to the SearchDialog in the main branch, should not be there. commit a9f30650bf2f349eb327c0ef0d0363dd6bb4a8f7 Author: Claes Nästén Date: Tue Aug 5 23:04:02 2008 +0200 Update action documentation, added SendKey action, mostly order/indention. commit b3389f62ca87455befe337bf26021ee4519176ab Author: Claes Nästén Date: Tue Aug 5 23:03:27 2008 +0200 Remove more references to Viewports in the documentation. commit e9fffcdc5732636505ecac516a0061a92cd7ae6b Author: Claes Nästén Date: Tue Aug 5 21:39:14 2008 +0200 Update pekwm_themeset.sh script, hopefully sh compliant now. Fixed script to handle commented Theme lines and use _NET_WM_PID for reloading the correct pekwm instance. commit daeac773e8767272d5d96dea27edd31dd7d0ae44 Author: Claes Nästén Date: Tue Aug 5 18:44:43 2008 +0200 Remove perl scripts, start replacing with pure shell scripts. Removed both perl scripts used in menus and implemented pekwm_ws_menus as a .sh script. Old pekwm_themeset.sh script needs to be fixed so that it does not depend on bash. commit 1e1f83e5d573a4fa40b3d57e0f56aa7fb2be435a Author: Claes Nästén Date: Tue Aug 5 18:38:08 2008 +0200 Add PDF target in mkdocs.sh script. commit c33217aa62460063dca67ad9ee26ddef0ebf2e66 Author: Claes Nästén Date: Tue Aug 5 18:37:44 2008 +0200 Large ugly commit fixing indentation on most documentation. Mostly indentation fixes and typos, added a TypeRules section to the autoproperties but it is not complete. Actions not updated in this commit. commit 7217f54d25753a73509cff74de15da14951a5727 Author: Andreas Date: Tue Aug 5 01:57:26 2008 +0200 Fix the fix of task #21. :-) commit b2657d13447ed261d7daec0ad021223d6c5b7fe9 Author: Claes Nästén Date: Mon Aug 4 23:34:14 2008 +0200 Apply adopted patch from ioerror fixing dynamic issues, does it still work? commit e2bb8960f90b3c995da57203f028d56e06a24fa8 Author: Claes Nästén Date: Mon Aug 4 23:33:16 2008 +0200 Make _menu_parent protected instead of private, to be used in ActionMenu. Change to protected _menu_parent and also fix encoding issues. commit d56db052c62dd770c12ccc00e184ddb98f1a2f5d Author: Claes Nästén Date: Mon Aug 4 22:04:22 2008 +0200 Update documentation to generate fine now with Viewports. Removed final references to Viewports and update styling to not blink when clicking and use monospace fonts. commit 4a21778ab3d620610004f5a0362fd0b745ed1cbf Author: Claes Nästén Date: Mon Aug 4 20:50:33 2008 +0200 Cleanup in naming, drop op_ prefix on all but CfgParser* files. As ioerror started doing cleanups on naming and indentation I got motivated to continue. commit fb998c2cb07ec6a2192671ff0534ee7180c8e6ed Author: Claes Nästén Date: Sat Aug 2 11:09:24 2008 +0200 Remove SearchDialog from master branch, will not be included in 0.1.7 commit 9557fd6d12f0b0a409fa42057702dc9e0f253db7 Author: Andreas Date: Sat Aug 2 15:01:35 2008 +0200 Fix a stupid mistake I did with the clean up patch. commit 2b651238255abd485a8e159e3fdab2193535f5fc Author: Andreas Date: Fri Aug 1 16:25:13 2008 +0200 Corrects the interpretation of the motif windowmanager hints. commit 897bd82e3835db410cae477dcdfe632e6b546594 Author: Andreas Date: Fri Aug 1 12:55:49 2008 +0200 Fix the unshading can brake the decoration bug (#32). If a shaded PDecor loses focus, its borders are set to the size of the shaded window (PDecor::setFocused() calls setBorderShape()). Therefore PDecor::setShaded() must also call setBorderShape() to set the borders back to the original geometry. commit d6e5016ac9c24c4a9a80a6969814e71e26244caf Author: Claes Nästén Date: Fri Aug 1 08:12:01 2008 +0200 Update AUTHORS adding ioerror and fixing spacing. commit c0eb10497030f07a3b32ebd618c0c64f4161ff4f Author: Andreas Date: Fri Aug 1 01:11:58 2008 +0200 Spacing after exclamation marks in src/Config.cc corrected. commit 17a69fcc36d3bb9c999a712d8ab0e52fdc7ccc63 Author: Andreas Date: Fri Aug 1 01:10:14 2008 +0200 Spacing after exclamation marks in src/{InputDialog,KeyGrabber}.cc corrected. commit 0e860d7ae1ca93b34af799bb6fe6299d8410d8cf Author: Andreas Date: Fri Aug 1 01:09:36 2008 +0200 Spacing after exclamation marks in src/Client.cc corrected. commit 3bddde8cf05fed2cc0eb5b5d2953c46962c2adef Author: Andreas Date: Fri Aug 1 01:08:58 2008 +0200 Spacing around exclamation marks in src/{AutoProperties,CmdDialog,DecorMenu,DockApp,FrameListMenu,Harbour,HarbourMenu}.cc corrected. commit f597673dfc699575dc1d4d74937657c85145a74e Author: Andreas Date: Fri Aug 1 01:07:17 2008 +0200 Spacing after exclamation marks in src/Frame.cc corrected. commit a82dc8df3412a44494aa6d6ddc2fa362a636dff7 Author: Andreas Date: Fri Aug 1 01:06:09 2008 +0200 Spacing after exclamation marks in src/PDecor.{cc,hh} corrected. commit 9e9ff1195f85b3e797c2145ba587a1d5274891e8 Author: Andreas Date: Fri Aug 1 01:04:31 2008 +0200 Spacing after exclamation marks in src{PFont,PMenu,PScreen,PTexturePlain}.cc corrected. commit 41aa196bfecd25e22a073bb1fd5764c9ab067fba Author: Andreas Date: Fri Aug 1 01:01:26 2008 +0200 Spacing around exclamation marks in src/{PWinObj,RegexString,TextureHandler}.cc changed. commit 1002d54574087fad680badc906ba29264645a421 Author: Andreas Date: Fri Aug 1 01:00:21 2008 +0200 Spacing in src/Theme.{hh,cc} changed. commit 4ea15b03e7305966d59ca68c2d8ef7e3450c2499 Author: Andreas Date: Fri Aug 1 00:58:59 2008 +0200 Spacing around exclamation marks in src/Util.{cc,hh} changed. commit 35672ac0dd2defc10f8c2abc4d8a0859dab52aba Author: Andreas Date: Fri Aug 1 00:58:21 2008 +0200 Spacing in src/PImageNative{,LoaderJpeg,LoaderPng,LoaderXpm}.cc changed. commit 9ea8d6cd29937f5bcb1a605b8558e8a60b7d7975 Author: Andreas Date: Fri Aug 1 00:56:17 2008 +0200 Spacing around exclamation marks in src/CfgParser{,Key,Source}.cc changed. commit df56e0d67ad67951db0d0471c76db20e6017a327 Author: Andreas Date: Fri Aug 1 00:53:55 2008 +0200 Spacing around exclamation marks in src/Action{Handler,Menu}.cc changed. commit b727600f2e415f0820b21b3fa25762e082717da9 Author: Andreas Date: Fri Aug 1 00:52:53 2008 +0200 Spacing around exclamation marks added. commit 977c7448151d0fcadb67d3c0d42ed309496337ef Author: Andreas Date: Fri Aug 1 00:10:15 2008 +0200 Spacing around exclamation marks in src/WindowManager.cc changed. commit da3e7a8dfe0db22602331959f2c07919d1c6402d Author: Andreas Date: Fri Aug 1 00:03:31 2008 +0200 Spacing around exclamation marks in src/Workspaces.cc changed. commit 59d36cefadf8bfe669422c985407a83d9c9bf353 Author: Claes Nästén Date: Thu Jul 31 23:24:32 2008 +0200 Fixup compile warnings after patch from ioerror. commit ab4a8ba07be45962f417d009dbcb7cdc993ee3c1 Author: Andreas Date: Thu Jul 31 22:44:00 2008 +0200 Unified coding style. This patch should not change semantics. I really hope it doesn't. commit 09941fa60eec2083480c1712a8ababd9340db83d Author: Andreas Date: Thu Jul 31 19:05:52 2008 +0200 Fix compile issue when configured with --disable-shape. commit 17031110e1af0039004511ea03e8c192fa90ab06 Author: Claes Nästén Date: Thu Jul 31 21:05:20 2008 +0200 Always get child into place when adding into PDecor. Align and resize children as soon as they are reparented to a PDecor. Fix simple border offset bug not looking at borderTopRightLeft on right border. commit b001fdcbfa4c329ebc542c631b37e2e6d4a3417a Author: Andreas Date: Thu Jul 31 21:03:03 2008 +0200 Fix wrong length parameter for snprintf. commit e3e87205471d27a49cd1e41956ad298f8d063b86 Author: Andreas Date: Wed Jul 30 21:26:38 2008 +0200 Set Client's _gm.x and _gm.y in Client::reparent(PWinObj *parent, int x, int y). commit 2c70e61eaa694d542f3daa684bd203b469309328 Author: Andreas Date: Wed Jul 30 20:21:06 2008 +0200 Fix offset for reparenting child in Frame. commit 7a0dab4d6e97f83ef3b96da0d9b258172b536fdf Author: Claes Nästén Date: Wed Jul 30 08:15:54 2008 +0200 Add SendKey action to send key presses to applications. This is the response on #14 where nidan says: 12:18 < nidan> pekdon: So, Chain = "Ctrl t" { KeyPress "t" { Actions = "SendKey Ctrl t" } } would do it.. Now it is possible to send keys defined the same way they are parsed in the keys file with the modifiers first and then the key. commit 780148a08b0b0c8b4552293ce52586cecb8cbc7f Author: Claes Nästén Date: Wed Jul 30 08:14:02 2008 +0200 Move mask identifying code out to separate method, add getKeycodeFromMask. Cleaning up the code a bit and starting to make changes required for a SendKey action, split and add this. commit a94510235bb1511630f94afd0a975f79ee54fed1 Author: Claes Nästén Date: Mon Jul 28 22:52:23 2008 +0200 Finish off removal of viewports, remove VPOS atom and do_virtual flags. commit 82c5dcd7d636c23db8acd2406fb511454cbd2c7d Author: Andreas Date: Mon Jul 28 21:53:35 2008 +0200 End the name unifying series by updating a comment in RegexString.hh. commit f7647ac2f5af4b1441f48669428891d05f09da0b Author: Andreas Date: Mon Jul 28 21:48:52 2008 +0200 Unifies the attribute names of CfgParserSource (underscore prefix). commit d5ce1679032b06b6cf5195623ffc55c5d936dcde Author: Andreas Date: Mon Jul 28 21:48:22 2008 +0200 Unifies the attribute names of CfgParserKey (underscore prefix). commit bfe20c53ffa741a69a88de13a4ea5e72ffba9425 Author: Andreas Date: Mon Jul 28 21:32:24 2008 +0200 Unifies the attribute names of RegexString (underscore prefix). commit a261456a19c41a4ea8199330b837ebfe746d8bea Author: Andreas Date: Mon Jul 28 21:31:15 2008 +0200 First in a series to unify the names of the attributes to use a single underscore prefix. This patch changes CfgParser. commit f58a4ada9ac6af76e21cd7567d23f07df8da72fb Author: Andreas Date: Mon Jul 28 20:54:25 2008 +0200 Remove moveVirtual() functions because they are useless without viewports. commit a0a0845f35fcccd9542f7344e3f63d1dc553c39b Author: Andreas Date: Mon Jul 28 00:19:04 2008 +0200 Final patch in the remove-viewport-series. It removes the files src/Viewport.{cc,hh}. commit d12baa0b8b09b3ca6cdde8d15950fc422a322163 Author: Andreas Date: Mon Jul 28 00:18:36 2008 +0200 Remove viewport support in AutoProperties. commit 488839cf814b889ac56ac76a03d735cb833f5819 Author: Andreas Date: Mon Jul 28 00:17:26 2008 +0200 Remove (part of) the viewport documentation. commit 440d3802988546b0a550235d540fb81d3a232b67 Author: Andreas Date: Mon Jul 28 00:16:40 2008 +0200 Remove the viewport related lines from the example configuration files (data/{config.in,keys,mouse}). commit ba2f143a872cb1f0d1ec1496cd0adf4fa09eea91 Author: Andreas Date: Mon Jul 28 00:15:09 2008 +0200 Remove Viewport.{hh,cc} from src/Makefile.am. commit 3ff12fec2ae36ae349cc3432db729c0ef301e134 Author: Andreas Date: Mon Jul 28 00:14:59 2008 +0200 Remove Config::getViewportCols() and Config::getViewportRows(). commit a42c7dff36f206daf04d2cf477d712a6e2260424 Author: Andreas Date: Mon Jul 28 00:13:43 2008 +0200 Remove call to Config::getViewportCols()/Rows() from Viewport::reload(). commit 55b2ff768aca0ff5df3d86006160892f6a670658 Author: Andreas Date: Mon Jul 28 00:12:52 2008 +0200 Remove viewport support from Workspaces. commit 0f15d5b9cb0ec17dd7e4cf835f9950e73a60a702 Author: Andreas Date: Mon Jul 28 00:12:16 2008 +0200 Remove viewport support from WindowManager. commit 322340998a0e70ed3340834ee8236f86d1da3033 Author: Andreas Date: Mon Jul 28 00:11:19 2008 +0200 Remove viewport support from PDecor. commit d1c45c14d3c1f0eca496c2ccc254dae1826d61be Author: Andreas Date: Mon Jul 28 00:10:14 2008 +0200 Remove viewport support from FrameListMenu. commit 3a184d79bad85b50b33c2a2fa40790f2cb2a284b Author: Andreas Date: Mon Jul 28 00:09:39 2008 +0200 Remove viewport support from Frame. commit 0d6d9b1430e3c5928f0dccacdde531dc3e9f6d9f Author: Andreas Date: Mon Jul 28 00:08:11 2008 +0200 Remove viewport from Client. commit 6bdd8f05202b0f2fa2d780521d27872c3a05598e Author: Andreas Date: Mon Jul 28 00:07:51 2008 +0200 First patch in a series to remove viewport support. This removes the viewport related enums from ActionType and the code from ActionHandler and Config. commit 30fce123d106a9c154f640d92537ec79ab2511c0 Author: Andreas Date: Thu Jul 24 00:05:45 2008 +0200 Conforming to Extended Window Manager Hints 1.3. The window manager should remove _NET_WM_STATE from withdrawn windows. commit bd4a3b117a499c7407adbcdb50a7fe42c54acaba Author: Andreas Date: Thu Jul 24 00:04:26 2008 +0200 Fix: Unmapping an iconified window remapped it. commit 6c26320a9565116adcaa71c90b6a656c0da547bc Author: Claes Nästén Date: Wed Jul 23 22:09:03 2008 +0200 Make Frame constructor clearer by moving decor name lookup into a method. This was adapted from a patch from ioerror where the lookup had been put into a macro. commit 8e159bd5eff3d4e40bc7b088fbe1ec32df4214a0 Author: Andreas Date: Wed Jul 23 19:01:31 2008 +0200 Removed pointer to WindowManager from Frame. commit e245c6933397eab2c6064baa64f99ce0275a08f5 Author: Andreas Date: Wed Jul 23 19:00:55 2008 +0200 Removed pointer to WindowManager from ActionMenu. commit ea0c5a0ef2935faa4c9186d0a59af3f6d4c80fb9 Author: Andreas Date: Wed Jul 23 19:00:13 2008 +0200 Removed pointer to WindowManager from ActionHandler. commit 2f7c155c5f5871a86698b6dbb74a1b94c7fb0942 Author: Andreas Date: Wed Jul 23 18:59:10 2008 +0200 Removed pointer to WindowManager from Client. It uses WindowManager()::inst() now commit 4bb165814983c252de9d476954f519dd50c6c0b4 Author: Andreas Date: Wed Jul 23 18:55:47 2008 +0200 Started to model WindowManager after the singleton design pattern. WindowManager has a static member pointer to its only instance now. commit 00d4c0eae102d90ebd64a808b00282e9693e55db Author: Andreas (ioerror) Date: Mon Jul 21 23:24:41 2008 +0200 Fix map/unmap issue with QT programs. ICCCM 4.1.4 advices the window manager to trigger the transition to Withdrawn state on real and synthetic UnmapNotify events. commit 4de33c16cb96d5f1c8ff59c79e5cc9790d99de6a Author: Andreas (ioerror) Date: Mon Jul 21 23:24:41 2008 +0200 Fix map/unmap issue with QT programs. ICCCM 4.1.4 advices the window manager to trigger the transition to Withdrawn state on real and synthetic UnmapNotify events. commit 708893ab3d74a58840efa1690d7c393513ca93bc Author: Claes Nästén Date: Sun Jul 20 18:06:11 2008 +0200 Start on getting search results displayed in menu, this is buggy though commit 9967401614c01db781298518a3f077d99dceeb32 Author: Claes Nästén Date: Sun Jul 20 18:04:41 2008 +0200 Start on fixed width menus to be used in searchdialog for displaying results. commit 9f962fdc6467af33afeeb4cdeb764fd75372f41f Author: Claes Nästén Date: Sun Jul 20 17:54:11 2008 +0200 Move wo_ref from CmdDialog to InputDialog as it is to be used in SearchDialog commit 1e66925308a2555a698d511ac25cbc18ea039afe Author: Claes Nästén Date: Sun Jul 20 17:36:13 2008 +0200 Update keybindings with more emacs like bindings. commit 30694ca1c2491d082798b0e76bae991e216855cf Author: Andreas (ioerror) Date: Sun Jul 20 15:17:38 2008 +0200 Fix compile error with harbour being disabled. commit 518b2c158aa11fb82e7d2cfb60629dc0e61f3c87 Author: Claes Nästén Date: Thu Jul 17 10:41:24 2008 +0200 Fix panel raising issue #30 reported and fixed by Jyri Jokinen commit 73a359d0dc2a57473d7e3acfb3b17b4fa2735f55 Author: Claes Nästén Date: Thu Jul 17 10:38:36 2008 +0200 Fix following compile warning reported by Vladimir Marek source='ActionHandler.cc' object='ActionHandler.o' libtool=no \ DEPDIR=.deps depmode=none /bin/bash ../depcomp \ /usr/dist/share/sunstudio_i386/SUNWspro/bin/CC -DHAVE_CONFIG_H -I. -I.. -fast -xarch=generic -I/usr/openwin/include -DMYSYSCONFDIR=\"/opt/pekwm-vlad/etc/pekwm\" -DMYDATADIR=\"/opt/pekwm-vlad "ActionMenu.hh", line 70: Warning: ActionMenu::insert hides the virtual function PMenu::insert(const std::wstring &, const ActionEvent&, PWinObj*, PTexture*). 1 Warning(s) detected. commit cf16ba2af3e0e61c3abe6b77a6445eba4e071102 Author: Claes Nästén Date: Mon Jul 7 10:13:41 2008 +0200 Use pkg-config instead of hard-coded test for libpng. commit b61b31d0991dfb0a2780546f52d3822fb53b526e Author: Claes Nästén Date: Mon Jul 7 09:53:37 2008 +0200 Fix broken reload, reload just re-set reload instead of doing doReload. commit 32d274c8fa1ef063a5d43507535120eb5a40920b Author: Claes Nästén Date: Wed Jun 25 16:32:50 2008 +0200 Improve on Xmb font loading, still not perfect commit 19f469cfd93920571dc8d10bdbd4f2eddf4667d6 Author: Claes Nästén Date: Mon Jun 2 21:24:20 2008 +0200 Now it is possible to have font type as the first parameter to fonts. In order to support $FONT = "..." and then use $FONT#Center it is now possible to specify the font type as the first paramter to fonts closing ticket #22. commit 3c23a47f1043de63684bbce7945bed8f4c947450 Author: Claes Nästén Date: Mon Jun 2 20:50:01 2008 +0200 Introduce WorkspaceIndicatorScale option. WorkspaceIndicator should render in a nicer way for various head layouts now. To change the size of the indicator edit the WorkspaceIndicatorScale option in the Screen section of the main configuration. Higher value means smaller size. commit 71a06368d206941e3bff283f10d463feaa872bc7 Author: Claes Nästén Date: Mon Jun 2 20:34:28 2008 +0200 Change SVN to GIT in configure.ac commit efe2f71cb34805abcf371642d03cf1cd7934720f Author: Claes Nästén Date: Mon Jun 2 20:34:06 2008 +0200 Try to avoid warnings from Sun Studio compiler. Based on the reports from Vladimir Marek this tries to fix some compilation warnings. commit b026694cb86fdc2e7f95f3c7b76eab05e8939ffc Author: Claes Nästén Date: Wed May 28 23:14:37 2008 +0200 Enable xinerama by default when available. There's no point in not enabling Xinerama by default anymore as there is not single/multi-head specific code left after the introduction of Xrandr support. commit 52ce676b7d132a3364644a0d2a2a6abe839221e4 Author: Claes Nästén Date: Wed May 28 23:13:21 2008 +0200 Get InputDialog size from the current head and not the full screen. Previously the InputDialog became a bit silly in it's size being /4 of the screen width which on > 1 screen setup is very big. Currently using /3 of the head the dialog is being mapped on. commit 3f0a2d4a3b1c31dc3cccfb37c416868b5ec854d0 Author: Claes Nästén Date: Wed May 28 09:04:38 2008 +0200 Fix layer in default autoproperties and add workspace indicator decor to theme. Just adding some minor configuration tweaking, templates should be implemented and put in use before 0.1.7 though. commit 63947a4310cb5c0fd8b2391db1770fd651565e55 Author: Claes Nästén Date: Sun May 25 20:18:37 2008 +0200 Add Pager and Taskbar to the Skip option. In order to hide things from the pager and taskbar, now it is possible to add Pager and Taskbar to the Skip autoproperty. commit 08e6dcbf26df10bbc060748aae5c2231e76f4c84 Author: Florian Hoppe Date: Sun May 25 15:37:22 2008 +0200 Patch fixing typo/ops in atom names for _NET_WM_STATE commit 975484e1ab6d3893eab1a1e955bc704178cc2126 Author: Claes Nästén Date: Mon May 19 23:21:49 2008 +0200 Start implementing SearchDialog. Start of SearchDialog which will let you type in a name of a aclient and will then show a list of matches, selecting will give the client focus. commit e50493e87167fcb3fe71da6609410e79eaa19801 Author: Claes Nästén Date: Mon May 19 23:17:22 2008 +0200 Avoid looking for timeouts when alarm has not been signalled. commit 3021352e4793b2f84bec83149bb6b1bf207eef54 Author: Claes Nästén Date: Mon May 19 22:44:17 2008 +0200 Separate InputDialog more from CmdDialog Rename all CMD_D_ actions to INPUT_ actions. Change CmdDialog configuration to InputDialog, however legacy CmdDialog section name is still allowed. commit 9b19ab253c726a6d4a0d061753c3bc927b01646f Author: Claes Nästén Date: Mon May 19 16:47:33 2008 +0200 Use XPending instead of QLength to avoid issues waiting for events commit 96876272a554e578161bf65a8abeb465d1d54a87 Author: Vladimir Marek Date: Sun May 18 19:57:24 2008 +0200 Fix include of Xutil.h for Solaris 9 I tried to compile pekwm on Solaris 9 and hat to tweak few bits and pieces. First of all, X11/Xutil.h is not automatically included by other X headers. commit 36c965e05291d7a7b34a136df882a23921dcb806 Author: Vladimir Marek Date: Sun May 18 19:54:43 2008 +0200 Add check for timersub as it is not available on Solaris 9 I tried to compile pekwm on Solaris 9 and hat to tweak few bits and pieces... Second, Solaris does not have timersub function. commit 7a38ef69b4c4a3a7e4d869f45dfc635339fc41a8 Author: Claes Nästén Date: Fri May 16 09:18:32 2008 +0200 Small fixes, s/color/font_color/ and cleanup WorkspaceIndicator window commit 7ae00fb9507e06a97848166c134bb99138776cc0 Author: Claes Nästén Date: Fri May 16 09:17:05 2008 +0200 Fix button and arrow color in default theme commit 30737606e6fec76b3286dadf1e4b674949fe6aa6 Author: Claes Nästén Date: Fri May 16 09:12:41 2008 +0200 New even more minimalistic default theme commit 58b587a4837eb692b6b6b63e968dd93aa04e9bf1 Author: Claes Nästén Date: Fri May 16 08:50:54 2008 +0200 Add new workspace configuration options Added WorkspacesPerRow, WorkspaceNames and ShowWorkspaceIndicator options to default configuration file. commit 1e0a4d756929d1284266f51aec84c68226b815ca Author: Claes Nästén Date: Fri May 16 08:50:09 2008 +0200 Re-indent config.in and drop the tabs commit e917577820bb9dc34deb9fbafbfac2e5d0616c7c Author: Claes Nästén Date: Thu May 15 22:14:48 2008 +0200 Start splitting CmdDialog into CmdDialog and InputDialog commit e52c1a61d54a23e318d2c0bc30960ddf00a81d14 Author: Claes Nästén Date: Thu May 15 21:44:54 2008 +0200 WorkspaceIndicator for showing current workspace on workspace change. Initial commit getting a WorkspaceIndicator into place, this also introduces WorkspaceNames configuration parameter setting names of workspces. Will follow up with a more detailed description when configuration is done. commit 4ba8d3442ee0efa436cddd39748218de102242a9 Author: Claes Nästén Date: Wed May 14 19:30:53 2008 +0200 Fix bug in status window placement and move drag starting point commit b5b698cc7dae7b7238abbd06bf83b3f47bb8e4c0 Author: Claes Nästén Date: Wed May 14 19:29:56 2008 +0200 Bug fixes for the new Timer commit 6157610cc2dafebc54fd026b8ce2d8a98e2ef58c Author: Claes Nästén Date: Wed May 14 19:26:52 2008 +0200 Add HeightAdapt option to themes. In order to be able to have a sane height on titles a HeightAdapt option that is put in the Title section of Decors have been added which uses the height of the font to calculate the height of the titlebar. commit d5a97a09415c90f36d9404943f736ba3f2de0758 Author: Claes Nästén Date: Tue May 13 21:56:20 2008 +0200 Add action timer to window manager. Adding action performed timer into window manager main loop, preparing for timed out actions. commit c108eacc54001f7ddf9e47c67d7cb6269fbdd47a Author: Claes Nästén Date: Tue May 13 20:40:58 2008 +0200 Start on Timer class, initial going to be used to hide workspace indicator. commit 7322751b40d1e2b7e9b9eac12652d667cf9319a8 Author: Claes Nästén Date: Tue May 13 20:37:14 2008 +0200 Use signal interuptable event loop. Using own getNextEvent which waits for connection data with select in order to not block signals preparing for timers and fixing issue with pressing Ctrl-C/Reload and then having to generate an event before activating the changes. commit ec30ad6bfd59c42019f6803337799669d6b47dfe Author: Claes Nästén Date: Wed Apr 30 11:35:09 2008 +0200 Add index.in.xml, was not in previous doc commit. commit 5639e7023d4b14e4d7d0540e162f533576fcbba7 Author: Claes Nästén Date: Tue Apr 29 22:29:53 2008 +0200 Add current documentation to repository commit e4bcf09ad348cb06157d138049837407ca883dd2 Author: Claes Nästén Date: Sun Apr 27 16:13:53 2008 +0200 Fix issue with edge snapping and struts. commit 0b45810f97d2f3217919db563d904cd1f077a13f Author: Claes Nästén Date: Sun Apr 27 15:35:40 2008 +0200 Make EdgeSize support different sizes per edge. EdgeSize now supports the two following types of configurations making it possible to have an edge active only on one edge of the screen: EdgeSize All EdgeSize Top Bottom Left Right commit 3edd3961a303c13771179e87089d3123167019bc Author: Claes Nästén Date: Sun Apr 27 14:47:25 2008 +0200 Add EdgeIndent option to Screen section. The EdgeSize option sets the edge size for the display, in order to reserve this area one can set EdgeIndent option to True and windows will not maximize over the edge. commit 87221092dfda57acf0297ca9b36dcdae7ce7035f Author: Claes Nästén Date: Fri Apr 25 16:13:00 2008 +0200 Improved RandR support now unified with Xinerema support for multi head. Simple multi-head setup seems to be working fine with RandR support, have not yet tried shrinking the screens and compiled this on any other platform. Now configure depends on >= 1.2 version of xrandr. commit e66df78c316b16695c1b642beca05b4275e26676 Author: Claes Nästén Date: Fri Apr 25 15:47:52 2008 +0200 Remove PCRE support, distributions adds unneeded dependencies on this. commit 9a20eaac0053f3ab4dba562442daf9b4798fb36a Author: Claes Nästén Date: Fri Apr 25 14:39:59 2008 +0200 Left overs from previous commit, wrong year and dockapp.hh warnings. commit 10f2733dd0b4d2400e1cade1b6a92b6a6225fec5 Author: Claes Nästén Date: Fri Apr 25 14:32:44 2008 +0200 Compile fixes for g++ 4.3 Nothing major done here, just some missing includes and updates on copyright and include orders. commit dc804dfd11bc21e8df55f7cb42469143b0834635 Author: Claes Nästén Date: Fri Apr 25 11:23:32 2008 +0200 Apply patch from http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=474871 Apply patch from debian fixing GCC 4.3 compile issues, need to get a local installation of GCC 4.3 to verify compliance. commit c4395aeceaf3935afbb0fa027e7f8f0001d81bb0 Author: Mathias Gumz Date: Sun Feb 24 16:54:08 2008 +0100 Fixed a problem when reading _NET_WM_ICON on 64bit systems The actual data format coming back from XGetWindowProperty is 'long', even when the returned format suggests its 32. 'long' on 64bit is 64bit and thus casting the returned data to CARD32 does not work since it is 32bit. commit 5d5bbc1049c94c26e4eda2fbdfe3f2be1a1cf874 Author: Claes Nästén Date: Sun Jan 6 22:16:02 2008 +0100 Use pkg-config instead of xft-config for Xft detection. It seems as if xft-config script has been replaced with pkg-config configuration, use that instead. commit af457140647a7e3ee2631a26312cc05c79da6770 Author: Claes Nästén Date: Thu Dec 6 23:18:59 2007 +0100 Apply patch from neuron fixing includes on Solaris. Add Xlib.h on some files to make compilation work under Solaris with Sun Studio compiler. commit 68113dcffa208806461c1bae9fe12a1a0f74c27d Author: Claes Nästén Date: Tue Oct 23 13:25:27 2007 +0200 Add icon to goto next/prev menus. Added icon to goto next/prev menus after vr requested it in #pekwm. commit 950ac2bfd8e04ebe9b819c9be389486d9134c163 Author: Claes Nästén Date: Mon Oct 1 01:00:31 2007 +0200 Fix wrapping in workspace actions. Fix wrapping in up and down workspace actions. Fix compile error reported by Christian Bryn. commit 47e3ef5856781019a29ad34deb72f8d6d3ae17af Author: Claes Nästén Date: Sun Sep 30 17:06:47 2007 +0200 Add workspace rows to get more flexible workspace layout. Added WorkspacesPerRow parameter to the Screen section of config to support grid layouts for workspaces. To navigate workspaces the following actions parameters was added workspace actions (GotoWorkspace etc): * WorkspaceUp, up without wrapping. * WorkspacePrevV, up with wrapping. * WorkspaceDown, down without wrapping. * WorkspaceNextV, down with wrapping. Also actions taking a workspace as parameter now support ROWxCOL syntax. commit 49b4498642ec6fcc5b815f72e1a83fe532486666 Author: Jyri Jokinen Date: Fri Sep 7 15:27:29 2007 +0200 Hopefully fixed default themes font problems. No fonts in window titles/menus/anywhere on clean install. commit 989bfa147c3ef2e6d9e4af3afa441696d95839e2 Author: Claes Nästén Date: Sat Aug 18 19:27:40 2007 +0200 Start restructuring for alpha aware rendering. commit d21a3132a6a7c1697f92f53c07a8d70ecce19553 Author: Claes Nästén Date: Fri Jul 6 21:05:42 2007 +0200 Add reference counting to texture created outside of texture handler. Added referenceTexture to TextureHandler adding support for increasing reference counts of TextureHandler unowned textures and via owned pointers. Reference icon textures in PMenu::Item. commit 3b52fae9b88d3189648104b846c278aaa6d2d140 Author: Claes Nästén Date: Wed Jul 4 22:05:33 2007 +0200 Cleanup, memory leak in ImageHandler not freeing images. The ImageHandler did not handle return of images correctly, it did decrease the reference but it failed in deleting the entries as && and not || was used for _free_on_return check. commit 724bdd578c344831e2f204550a9897a515f851fe Author: Claes Nästén Date: Wed Jul 4 00:13:49 2007 +0200 Cleanup warnings identified with valgrind. Fix memory leak in Xft font handling, both font and font colors. Fix image handler info about leaked images on shutdown. Fix client failed icon loading memory leak. commit 0f917e947c42f87bda5317803a329323e06c7e9e Author: Claes Nästén Date: Tue Jul 3 07:27:12 2007 +0000 pekwm trunk Change font color alpha to percent. Change font color alpha to percent instead of absolute value. Fix compile warning in PMenu caused by incorrect order of members in constructor. Fix bug in ImageHandler checking != begin instead of != end. commit dfe361a442a9e0a504b1cf5a9cddd4488aa53076 Author: Claes Nästén Date: Mon Jun 25 18:44:35 2007 +0000 pekwm trunk Add initial icon support. Added support for rendering icons on menus and reading the _NET_WM_ICON property from clients. Currently there are some bugs related to reloading and drawing of transparent data. commit 2ec3e1b8813ebbd118c55974719e920359de3630 Author: Claes Nästén Date: Sun Jun 24 14:45:14 2007 +0000 pekwm trunk Improve xinerama strut handling and iconv autoconf check. Fix for strut handling and xinerama, previously ignored head specific struts. Add iconv check to autoconf. commit 71415163e01dcbf8dadb57b666679858a93c5304 Author: Claes Nästén Date: Sun Jun 24 12:55:39 2007 +0000 pekwm trunk Start using XMB fonts as default if no type is specified. Default to XMB style fonts and not X11 when not specifying font type, last step for fixing basic UTF-8 string rendering. Closing #15 commit b3306dfcc8f2ec55436e7900fe48bdfb4481b68d Author: Claes Nästén Date: Sun Jun 24 12:26:40 2007 +0000 pekwm trunk Add PWinObj::moveResize Add moveResize method to PWinObj to make maximize and fullscreen more efficient. commit 0c28297c218cc6e7c06e8f1f58ddceddccf99628 Author: Claes Nästén Date: Fri Jun 22 11:57:02 2007 +0000 pekwm trunk Fix issue with ShowFrameList parameter. Fixed issue with ShowFrameList paramter caused by re-drawing titles of window being destroyed. commit 64f5d4f06b1e962ba55f5310881a2c0a783349f1 Author: Claes Nästén Date: Tue Jun 19 15:37:52 2007 +0000 pekwm trunk Re-enable Xmb fonts. Added code for Xmb fonts back in using Xwc set of functions. commit 0ae82957c742c38e1276a643a0baa247d9c94857 Author: Claes Nästén Date: Tue Jun 19 08:25:18 2007 +0000 pekwm trunk Add read support of _NET_WM_NAME. Added _NET_WM_NAME read support for handling UTF-8 titles in Firefox etc. commit cb2b1acfaf6012e55ef7d3c83ad670c834a0805e Author: Claes Nästén Date: Mon Jun 18 22:22:35 2007 +0000 pekwm trunk Initial iconv support. Start using iconv in from and to utf8 string. commit de56e84c81fba58c30caf857b3de0e6ee1f0fb12 Author: Claes Nästén Date: Mon Jun 18 19:17:23 2007 +0000 pekwm trunk Start on wstringification. Started work on wstringificaton, seems to be mostly working when using an UTF-8 locale. Have not tested compilation on various platforms and iconv is still not used in to_utf8_str and from_utf8_str, also _NET_WM_NAME should be read for client titles. commit 5b58f3ae071be6512142b9859f1021f4f18bafac Author: Claes Nästén Date: Thu May 31 20:11:53 2007 +0000 pekwm trunk Add fix for broken iconified state. Add fix for broken iconified state after restart. Closing #38 (Thanks giuliani{.}blackfenix{@}gmail{.}com for reporting) commit ebdc6b2ef7196e0fb4617d9c45f1a95386d09e33 Author: Claes Nästén Date: Thu May 31 19:13:16 2007 +0000 pekwm trunk More work on autoproperties handling. Now 0 width/height in geometry auto properties mean to use the screen width/height. Added type autoproperties to autoproperites file together with removal of border and titlebar for mozilla firefox. commit 8d42d9143c4b9284a414baa560827ce0f1c8edc3 Author: Claes Nästén Date: Wed May 30 23:02:55 2007 +0000 pekwm trunk Made _NET_WM_WINDOW_TYPE configurable. Made the _NET_WM_WINDOW_TYPE handling configurable, still some small tweaks left in the auto properties for handling geometry expanding to the screen value. Fix bug in CfgParser causing data being parsed twice. commit e614871d6a67fd06dc85707f19609865ca55edd6 Author: Claes Nästén Date: Tue May 29 21:16:42 2007 +0000 pekwm trunk Add shaping of non-corner border windows. Closing #97 As requested by julien in #97 issue report shaping of non-corner windows has been added. commit 557fd7130b152ee07fa7aed296655c0da8ec6ace Author: Claes Nästén Date: Mon May 28 15:02:22 2007 +0000 pekwm trunk Make ready for 0.1.6 release. Just marking ChangeLog and configure.ac with 0.1.6 version. commit f9a0cda03104d4c861761208a3bb249983ca71aa Author: Claes Nästén Date: Mon May 28 13:36:34 2007 +0000 pekwm trunk WM_HINTS InitialState fix, closing #33. Add missing setWmState call if no WM_HINTS was set on window, closing #33. Fix bug in giveInputFocus forming invalid WM_PROTOCOLS WM_TAKE_FOCUS requst causing applications not following the focus model. commit 48890a5adfa0f8ddf6744285606cff45f6c20a50 Author: Claes Nästén Date: Mon May 28 11:41:30 2007 +0000 pekwm trunk Focus changes, WM_TAKE_FOCUS handling. Re-worked the focus handling to look at WM_TAKE_FOCUS and the input flag in the WM_HINTS not sending focus in events to clients that do not want them. This seems to have fixed focus issues with Java Swing applications and OpenOffice.org tool popups. commit 473f476ea3ffdd5c69845928b8480f46471dd7b9 Author: Claes Nästén Date: Thu Mar 29 05:22:37 2007 +0000 Fix compiling under solaris, lacked std:: for type name and missing return in bool function. If not HOST_NAME_MAX is define, define as 255. commit a518482cbf132d5e824fcafc757992e7e19edb07 Author: Claes Nästén Date: Wed Mar 28 11:39:25 2007 +0000 Added setting of _NET_WM_PID on the root window to support correct reloading of the window manager from another application. commit f911c694fa6aff30f72544648b51d2beb7b6e171 Author: Claes Nästén Date: Sat Mar 10 10:24:33 2007 +0000 Fix missing expansion of environment variables in configuration files, prefixed by $_. Fix missing std:: in PWinObj header file. commit a44751648b925e65760ea02b4e00c4ceae1c3625 Author: Claes Nästén Date: Wed Jan 31 22:07:37 2007 +0000 Add fix for #99 cause by broken optimisation introduced in r119 reported by okratis. Add shaping to titlebar buttons. commit c3b534c3c23d719b17a05457156a283ba28807a3 Author: Claes Nästén Date: Mon Nov 13 14:09:38 2006 +0000 Use UTF-8 draw on Xft fonts, should sanitize this. Fix dockapp size handling to properly center apps. commit cb184d75801787c153b7f602bccdff82e9ad3910 Author: Claes Nästén Date: Fri Sep 29 14:06:52 2006 +0000 Changed wo_list to vector from list. Added dirty_resized check in PDecor to reduce the amount of calls to the PixmapHandler. commit 75c1e5d04ddac56feeabaea517ff077335bd0016 Author: Claes Nästén Date: Wed Sep 27 15:47:11 2006 +0000 Added a map of Window to PWinObj for faster lookup as findPWinObj is a very frequent call. Updated to not create the list twice (one list and one array) as this is called everytime a window is created, removed, lowered and raised. Added skipping of menus and focus toggling for docks, works better together with gnome-panel. commit 7a6c7de601f95e1167e0da8411f6e7cb1ff7b61a Author: Claes Nästén Date: Thu Sep 21 13:32:41 2006 +0000 Use map instead of list in PixmapHandler and remove threshold parameter. commit 97bfb60c91fb0e98cd1f23369067611d00f2b962 Author: Claes Nästén Date: Mon Sep 11 14:18:55 2006 +0000 Updated FindClient action to match against the visible title and not the Client set one. Updated parse match to support parsing of // style regular expressions having flags set. Currently only i flag supported. This type of expressions is currently only possible on the FindClient action. commit 12ee025692dbeefce73a4fd4bec3babe2d3f3459 Author: Claes Nästén Date: Fri Sep 8 13:53:37 2006 +0000 Fix crash OPS in WindowManager introduced with new handling of focus and CmdDialog. Sort Client and Frame id lists. commit f67f33bc6d00565dde5b5594b1a5ae840aa1aeef Author: Claes Nästén Date: Thu Sep 7 19:49:48 2006 +0000 Fixed ops causing Client::findClient never finding a Client based on the parent (Frame) causing Frame::doGroupingDrag not to work. Thanks shared for reporting. commit 52b421805ef30c1a1f2abeadbafc9fcff1eaeef5 Author: Jyri Jokinen Date: Thu Sep 7 15:15:20 2006 +0000 Added ShowClientID (false) to default .pekwm/config. Added ShowCmdDialog GotoClientID to default .pekwm/keys. commit 9ea5b5de0213361dc8967451c52c5e5010fb4bee Author: Claes Nästén Date: Thu Sep 7 13:59:12 2006 +0000 Updated ShowCmdDialog action to support parameter setting initial value. Useful together with action such as GotoClientID binding a keybinding to ShowCmdDialog GotoClientID for quick navigation. Added GotoClientID action which goes to and focuses client with ID. Added boolean option ShowClientID under the Screen section of the main config file. This enable/disable display of Client ID in titles. Moved Frame and Client list related actions from WindowManager to Frame and Client. commit d4eb646686a5b265539a1659c2c20f88be93efc6 Author: Claes Nästén Date: Wed Sep 6 21:39:28 2006 +0000 Moved the Client list to Client. Added clientid list to Client so that it is possible to keep track of Client ids, preparation of number based navigation. commit ba4dffd8ccd1e2a8e212fbe4068643769625d898 Author: Claes Nästén Date: Wed Sep 6 20:18:09 2006 +0000 Extend PDecor::TitleItem with information to include client id. Moved the Frame list to Frame. commit 605c8bbd246f2b688a742747ef6bc90b62cb9c85 Author: Jyri Jokinen Date: Tue Sep 5 13:03:30 2006 +0000 Renamed KILL action in CmdDialog as ClearFromCursor. Added ClearFromCursor to default keys. commit 032a29e593486970993bab8bae6c00351a67c391 Author: Claes Nästén Date: Mon Sep 4 07:23:50 2006 +0000 Added KILL command to CmdDialog. Small cleanups in indenting. commit fbe2f8ec4113dd691b2bce3ca4c0bfece9c6c408 Author: Claes Nästén Date: Thu Aug 31 12:22:30 2006 +0000 Moved tagged information to Frame instead of extremely incorrect placed in WindowManager. commit 4c677f297a9a564d91018bd8b8108c9c877c32d2 Author: Claes Nästén Date: Wed Aug 30 15:17:31 2006 +0000 Created new _PEKWM_TITLE atom used to save titles between restarts. commit 4520186742e01c21467b8a2a166235d012def8f3 Author: Claes Nästén Date: Wed Aug 30 14:51:22 2006 +0000 Plug major memory leak in CfgParser and create saner error messages when parsed data has invalid syntax. commit 0c737d4ba146b08fa2fb30e115473c279a57becb Author: Claes Nästén Date: Wed Aug 30 12:06:58 2006 +0000 Update PDecor::doMove to only use the root position of the pointer to support more ways of initiating moving and then also keep correct position. Close #94 ( Thanks Jowi and shared for reporting ) Removed debug output from Client::configureRequestSend. commit 20338cd8d678084af0043c1aa3a71bc47c729cef Author: Claes Nästén Date: Wed Aug 30 07:41:36 2006 +0000 Start re-indenting code using spaces. commit 6a9025b237a510dad5681f33d540f7aa213a4486 Author: Claes Nästén Date: Mon Aug 28 06:36:32 2006 +0000 Fix issue in reload causing dangling pointer to custom menus hang around in the list of menus. Should improve on reload crash situation #92 and #96. commit 5b6372064c08748a9080f28f31676aba80cf96ef Author: Jyri Jokinen Date: Wed Aug 23 14:45:02 2006 +0000 data/keys, Added: KeyPress = "Mod4 T" { Actions = "Toggle Tagged False" } It is criminal there was no shortcut for (un)setting the Tag state. commit 7b5e4b0ca0b6178ba9095ff0e79b6c72bfe73fcc Author: Claes Nästén Date: Wed Aug 23 09:50:16 2006 +0000 Duplicate API for handling marked state on clients causing updates not being reflected when attaching marked clients. commit d0a2991e8a1e8c6628a56863a99c1af8c746e284 Author: Claes Nästén Date: Wed Aug 23 07:21:46 2006 +0000 Closing #47 "(request) rewrite titles of marked windows" Reworked PDecor::TitleItem to support holding extra information that can be modified independently from the real title content. Currently the only data supported is the marked info. commit ddc2d171582e1e7b62bf6accf6698a0bcc4771b2 Author: Claes Nästén Date: Thu Aug 10 20:41:00 2006 +0000 Moved dynamic flag to PMenu::Item from ActionMenu::DItem and remove ActionMenu::DItem. Rework hide submenus in PMenu. commit e327b2387e0a041612454253fead087edec5677a Author: Claes Nästén Date: Tue Aug 1 14:31:03 2006 +0000 Fix compile warnings in Atoms and Client. Moved skip attribute to PDecor from Frame, adding check to skip those PDecor's when checking snap. Closing #95 ( Thanks shared for reporting ) commit f190d0e8288ff813ac8512d983d0772372137fde Author: Jyri Jokinen Date: Sun Jul 30 13:52:23 2006 +0000 Made default window menu entrt names less cryptic. commit 49b14e9cc4a4feff0f12b63292a809cfb1984331 Author: Jyri Jokinen Date: Mon May 29 15:57:22 2006 +0000 Added "Toggle HarbourHidden" under Mod4+H (or Ctrl+Mod1+P-H), and moved HideAllMenus out of the way to Mod4+X (or Ctrl+Mod1+M-X). Mod4+X because Ctrl+X is Cut in many applications, and cutting makes things disappear from screen. Took some thinking, but it was way better than sticking with H and using two modifiers for it. commit 997ebc738c21e23a338cfd8391cedc5064cfff4c Author: Claes Nästén Date: Mon May 29 13:41:01 2006 +0000 Created new state action HarbourHidden. Closing #89 Removed ROOT command support. Closing #93 ( Thanks shared for reporting ) commit e332bd6657ef6041b7a70cc3d011d56cae55f160 Author: Claes Nästén Date: Mon May 29 06:28:30 2006 +0000 Removed ROOT command functionality. Closing #93 More paranoid code in PMenu commit 586899b9da132b482731ab79d866a39d02e51e6c Author: Jyri Jokinen Date: Thu May 25 14:02:25 2006 +0000 Added Mod1 with mouse button 1 to toggle maximized state. (Can someone tell what demons made me not realize it was missing before this?) commit 98262e459fd39206088b981d4acaa1a2789aa493 Author: Claes Nästén Date: Tue May 2 20:24:26 2006 +0000 Revert of changes, GCC is not a friend of them. commit a2b8c8866dd2dd1db9a7b2d595cbca72a36c9869 Author: Claes Nästén Date: Tue May 2 19:45:25 2006 +0000 Sun Studio compile warning fixes. Ops in PFont ignoring max_chars parameter (not in use). Split up CfgParser::load commit d3c7d0e36cb331f234084cdf5a8ba1420d969708 Author: Claes Nästén Date: Mon May 1 21:11:25 2006 +0000 Added boolean option to {Next,Prev}Frame set of actions to allow inclusion of iconified windows. Closing #59 (Thanks shared for request) Added SendToViewport Col Row action. It does not implement relative viewport sending. Closing #70 (Thanks Largon for request) Fixed ops in menu code in previous revision. Added PadType to differ between direction and pad. commit 3476ccca4f739cc038d1d4e711ce5d76fa37120c Author: Claes Nästén Date: Mon May 1 15:17:57 2006 +0000 Extended the ShowMenu functionality to include custom menus. Example, by adding the following to the menu configuration file: ExampleMenu = "Example Menu" { Entry = "Example Entry" { Actions = "Exec xmessage Example" } } And then issuing the action ShowMenu ExampleMenu it would pop up the menu defined. Closing #68 NOTE: The menus names are case insensitive, meaning it is NOT possible to have TestMenu and TESTMENU. This only applies for root level menus, and not submenus of a menu. (Thanks buk{@}nurfuerspam{.}de for request) commit ecc111f6ef162e7ba470ce0976cb810de56d6ad5 Author: Claes Nästén Date: Fri Apr 28 11:38:42 2006 +0000 Updated workspace switching and unmapping of window objects to avoid windows being rendered as focused when they are not. Closing #87 Fixed ops not handling sticky window value. Closing #86 ( Thanks Skot for reporting ) commit 23a46f91972c3d5c635166c77d68ad329b82f03c Author: Claes Nästén Date: Tue Apr 18 19:33:02 2006 +0000 Added missing man page target in Makefile.am. ( Thanks nice for reporting ) commit ab432e974899e232177c14b0be5719003f74b2b0 Author: Claes Nästén Date: Mon Apr 17 17:51:29 2006 +0000 Revert menu changes commit 308f549f80ac2dcc142eee2e9198d627669b1292 Author: Claes Nästén Date: Mon Apr 17 16:25:06 2006 +0000 Preparation for 0.1.5 release commit e921b6a259ffa3101c2cdad6a19eb7d704a543a8 Author: Claes Nästén Date: Mon Apr 17 13:52:49 2006 +0000 Re-enabled the use of ApplyOn = "Workspace" for autoproperties. Closing #55 ( Thanks nospaulatu{@}gmail{.}com for reporting ) commit 7b4021054fd75043aac3764e9a48648fb3d93e0d Author: Claes Nästén Date: Mon Apr 17 10:52:29 2006 +0000 Fixed ops distributing uneven pixels in tab calculation that caused pixels missing from the title. Updated menu rendering to properly honour padding and justification. Closing #46 and #74. ( Thanks shared and buk for reporting. ) commit ea6624c8067068cc1ac24086bf585c80a72a0c9b Author: Jyri Jokinen Date: Mon Apr 17 00:51:23 2006 +0000 Added OffsetX and OffsetY to default config. Fixed the hopefully last brainfart in def. menu. commit 13a4a8338d36cba63653421a5fe6c04e5aa31455 Author: Claes Nästén Date: Sun Apr 16 23:13:20 2006 +0000 Added Last parameter to GotoWorkspace and SendToWorkspace actions activating/sending to last active workspace. Closing #79 ( Thanks Tomas Dvorak for request. ) Fixed bug in parsing of # and // comments not parsing the content of the line in CfgParser. ( Thanks shared fore reporting. ) commit d6e5cb613f4c27cc932423f85e36f68290903592 Author: Claes Nästén Date: Sun Apr 16 22:13:41 2006 +0000 Switch position of row/col placement. Closing #60 ( Thanks koniu{@}sheket{.}org for reporting. ) Updated and applied patch from koniu{@}sheket{.}org to add OffsetX and OffsetY options to smart placement to pad with x/y pixels. Closing #61 ( Thanks koniu{@}sheket{.}org for patch. ) commit a5fb33d393ed6ca693071c9830f8598bdb3604ea Author: Claes Nästén Date: Sun Apr 16 21:15:39 2006 +0000 Remove max allowed WidthMin value check from theme parsing. Fixed dangling reference crash in configuration parser, triggered by the parse_key_value feature of the CfgParser. Closing #84 ( Thanks shared for reporting ) Removed size limiting in resize. Closing #73 ( Thanks shared for reporting and dvorakt1{@}fel{.}cvut{.}cz for proposed solution ) commit 7c70161a31645ef4a9318aabf45ac1e21d01f423 Author: Jyri Jokinen Date: Sat Apr 15 22:54:06 2006 +0000 One stupid typo. s/_/-/ on the menu filter script. *sigh* commit c1d89aa40ddffa7f7e53516cbfefcee11b7a1714 Author: Jyri Jokinen Date: Sat Apr 15 20:06:10 2006 +0000 More applications on the default menu. Also, a big fat reminder that people should now run the menu cleanup script to avoid confusion and usuless entries. Not a too big doff, have to commit or I'll forget. commit e4cddabf9fadd3431ed4556d43a146f8025b3fda Author: Jyri Jokinen Date: Sat Apr 15 17:32:08 2006 +0000 Removed pekwm_window_info.sh script. This was added too soon and had no actual support coded in and therefore could never function. Added pekwm-filter.sh, a tool to purge non-existant applications out from the users root menu. Also made it easily accessible from the default menu. Made default menu compatible with said filter script. commit 354633b39ed077acf13120beba01b86dbe7f46a0 Author: Jyri Jokinen Date: Wed Feb 22 21:57:42 2006 +0000 Manpage trac typo fixed. Make hitting kill harder in default window menu. commit 87ec7d2358981c84d6f1678fb974081635b95794 Author: Claes Nästén Date: Wed Feb 22 21:50:15 2006 +0000 Typo fixed in default theme. commit bbf5a368649c5782dd41f34292223728614db3ab Author: Claes Nästén Date: Wed Feb 22 21:33:48 2006 +0000 Reorganize subversion archive commit 40f502e9815fc0586b7cbec502e9fbcf3e3ca8b1 Author: Claes Nästén Date: Wed Feb 22 21:32:35 2006 +0000 Reorganize subversion archive pekwm-release-0.1.18/ChangeLog.aewm++000066400000000000000000000555531374756504400172260ustar00rootroot000000000000001.0.16 (6 Feb) * Remove key grab for escape key when we weren't using it. * Small focus issue change. * Fixed a function in windowmanager.cc which wasn't deallocating memory after it was used. 1.0.16-RC3 (2 Feb 2002) * Fixed problem with reverting focus under sloppy focus. * Merged in a patch from David Lawrence Ramsey which contains the manual page formatting fix, the new icon and rcfile change for appbar, the typo fix for setrootimage. Also added more support for NET_WM hints in fspanel, aewm++ has also been updated to add support for this. This changed involved hints for virtual desktops. Also in this patch is a minor change to windowmanager.cc where I accidentally left some code over when NET_WM hints were configurable. * Added a disclaimer to the README of fspanel so that it states that it is not the official version but an updated version with changes by me and others involved with this project. 1.0.16-RC2 (28 Jan 2002) * Fixed a focus problem when reverting to a previously focused client (ie. when you close a client it reverts focus to the next client in the stacking order). * Made a small change in appearance of unfocused windows. The line which separates the small box in the right corner is not painted. Its only painted on a focused window now. * Changed back the code which initially maps a window. I though withdrawn windows shouldn't be mapped. I think I am confused =) Withdrawn windows will now be mapped initially. * Changed default focus model to sloppy. * Got rid of -arch=686 in appbar's and setrootimages Makefiles. 1.0.16-RC1 (26 Jan 2002) * Added in David Lawrence Ramsey's hyperbolic gradient patch. This is added to appbar and to setrootimage. 1.0.16-pre11 (20 Jan 2002) * Changed the fork function in misc.cc to check the length of the command to execute if its zero length then obviously don't fork anything. * Hopefully squashed the bug which would cause aewm++ to lock up. * Badly needed updates to the manpage. * There are only 2 command line options to execute commands via button clicks they are -new1 and -new2 which coorespond to the left and right mouse buttons respectively. This is the best compromise I can come up with and still have the middle button pop up the icon menu. * Fixed -fn option. The user select font was not being used for unfocused windows. 1.0.16-pre10 (18 Jan 2002) * Fixes to LinkedListIterator * Iconifying clients with transients will correctly iconify all transients and vice versa. * Minor updates to appbar so that it disables always on top hint and strut when hidden. 1.0.16-pre9 (15 Jan 2002) * Merged in David Lawrence Ramsey's patch which fixes typos in the man page, Changelog and in windowmanager.cc. * Code cleanup, got rid of DEBUG code. It was hardly ever used anyway. * Clean up in client move code. * Window manager keeps track of the command line which started the window manager upon restart the same command line is used. 1.0.16-pre8 (13 Jan 2002) * More work on focus issues. Should be just about right now! * -fm click|sloppy|follow are the commandline options for focus model. 1.0.16-pre7 (12 Jan 2002) * Updated the commandline option -usage. * More clean ups in windowmanager.cc. 1.0.16-pre6 (12 Jan 2002) * Merged in David Lawrence Ramsey's focus policy patch. Seems pretty close to the code in pre5 however we will go with his. * Fixed problem with focus when switching desktops with the key combos. 1.0.16-pre5 (3 Jan 2002) * Initial support for sloppy focus and click to focus and configurable from the command line. 1.0.16-pre4 (31 Dec 2001) * Initial configuration handlers for sloppy focus, click to focus and focus follows mouse added but commented out. * Added LOOKING_FOR_HELP file which describes that this project is in need of help it provides contact information. 1.0.16-pre3 (29 Dec 2001) * Added a patch which changes the fspanel to have buttons for virtual desktops instead of arrows. I can't remember who sent me this patch. If it was you email me so I can give you credit. 1.0.16-pre2 (29 Dec 2001) * Updates to setrootimage in goodies subdirectory. It now takes advantage of all of the style options provided by the blackbox image code. 1.0.16-pre1 (29 Dec 2001) * Got rid of compile time option NET, the extended hints are compiled in automatically. There is no reason not to have them as they don't rely on any external libs or anything. * Some clean up in client.cc. * Clean ups in man page. 1.0.15 (28 Dec 2001) * Changing code which deals with window positioning and size. Trying to fix the bugs I introduced in earlier versions. * Fixed setting of the NET_WM_STATE property. * Clients now look for NET_WM_STATE when they are created and will set states appropriately. 1.0.15-pre2 (23 Dec 2001) * Changes to configure event handler and unmap handler and also strut positioning. 1.0.15-pre1 (22 Dec 2001) * MJ Ray's patches. 1.0.14 (8 Dec 2001) * Changes in configure event handler of client.cc fixing up a few issues dealing with width and position. * More changes to init_position in client.cc, trying to make it more aware of apps that set struts when windows are initially positioned. * Added key combo ctrl-alt-end to exit the window manager. * Added key combo ctrl-alt-delete to restart. * Set appbars position and size (XSizeHints). * Looks like I fixed the scan_wins problem. (time will tell) * Made transients not able to use the window menu. * Added an xsession directory to goodies, put xsession.c in it and added a README file explaining its usage and how to compile it and install it. * Update INSTALL file. * Added GenericMenu class, its purpose is to provide common functionality used in both the iconmenu and the windowmenu. * Changes to Makefile. * Fixed bug which caused some windows to stick around when closing aewm++ and starting another window manager. * Tweaked the struts for goodies/fspanel. * Added xsession.c from aewm/goodies to the goodies directory. * Code clean up in client.hh and client.cc. * Don't allow reparented transients to iconify themselves from the titlebar. I was disallowing this from the iconify function which was wrong because we still want to be able to iconify transients sometimes for instance if xmms is iconified we want its playlist or equalizer to iconify with it. * Added support for clients checking what desktop they want to start on. Thanks to Jeremy Naylor. * Changed invert_gc back to use GXinvert instead of GXxor, seems this wouldn't work on some versions of X but worked with 4.1. Go figure! * Small fix so that frame doesn't propagate some masks. * Put the titlebar in its own window, now aterm's transparency works. Probably other apps which use transparency work as well? Time will tell. * Fixed a couple header problems with goodies/appbar and goodies/setrootimage * Clean up in BaseMenu * Moved iconify to button press code instead of button release in client.cc * Fixed the buggy icon menu that I released yesterday (damn!). * Small fix in linkedlist.cc, I was using the function exit() but forgot to put #include . I am still wondering how gcc 2.95.3 fails to recognize this as an error. 1.0.13 (11 Nov 2001) * man page updates * README updates * A little clean up in the makefile * Added icon menu * Fixed a bug which caused a crash when an app called worker was closed * Fixed the KeyPressMask problem that globally grabbed the page up and page down keys * Fixed a few things which prevented it compiling cleanly with gcc 3.x It has a more strict C++ standard than gcc 2.95.3 which I use 1.0.12 (6 Nov 2001) * Code cleanup in basemenu * Initial window placement is now strut concious * Added appbar to goodies directory. * Added my patched fspanel to goodies directory. * Fix for slightly broken opaque move, window would jump slightly off on the y axis when grabbed for the first time. This was due to a change in send_config. * Fixed an annoyance which caused some windows to be movable, maximizable,etc from anywhere on them clicking/double clicking. * Fix a typo in aewm.hh and Makefile involving setenv. 1.0.11 (3 Nov 2001) * made it so transients can't be iconified. * fixed up _NET_WORKAREA to take into account _NET_WM_STRUT that have been set by clients. * made it so that transient windows can't be maximized. I haven't encountered a time yet when I needed to maximize one. =) * code clean up in client.hh and client.cc * fixed a bug in switching desktops which wouldn't take into account if a window was iconified and it set its state to Withdrawn. * added _NET_WM_STRUT support. * added a setenv() function for those Unix systems that don't have one. thanks to Jeremy Naylor for this patch! This is a compile time option. Edit the Makefile and uncomment #NEED_SETENV in the DEFINES line. * Fixed bug which involved Gimp starting and looking like it had the focus when it really didn't. * Tweaked click to raise window. * Tweaked the setFocus function. * Fixed motion handler to make sure button1 is the only button which can drag a window. * Small fix on _NET_ACTIVE_WINDOW, it wasn't actually setting the focus. * Added support for _NET_NUMBER_OF_DESKTOPS client messages. * Added support for _NET_CURRENT_DESKTOP client messages. * Added support for _NET_CLOSE_WINDOW client messages. * Added support for _NET_WM_DESKTOP client messages. * Clean ups in aewm.hh * added -es option for edge snapping. Used -es [true|false]. default is true. * Updates to the man page * Started adding support for net wm spec. * Reworked client move code. Added opaque move. * Added -wm (wire move) option for commandline. * Linked List clean ups. * Added check to maximize function so that clients don't get maximized past their max size if they set this property. * Added edge snapping, if a window is within 10 pixels of the edge it is snapped to the edge. * Tweaked client raise on click. 1.0.11-pre9 (2 Nov 2001) * made it so transients can't be iconified. * fixed up _NET_WORKAREA to take into account _NET_WM_STRUT that have been set by clients. 1.0.11-pre8 (1 Nov 2001) * made it so that transient windows can't be maximized. I haven't encountered a time yet when I needed to maximize one. =) * code clean up in client.hh and client.cc 1.0.11-pre7 (31 Oct 2001) * fixed a bug in switching desktops which wouldn't take into account if a window was iconified and it set its state to Withdrawn. 1.0.11-pre6 (30 Oct 2001) * added _NET_WM_STRUT support. * added a setenv() function for those Unix systems that don't have one. thanks to Jeremy Naylor for this patch! This is a compile time option. Edit the Makefile and uncomment #NEED_SETENV in the DEFINES line. 1.0.11-pre5 (28 Oct 2001) * Fixed bug which involved Gimp starting and looking like it had the focus when it really didn't. * Tweaked click to raise window. * Tweaked the setFocus function. 1.0.11-pre4 (23 Oct 2001) * Fixed motion handler to make sure button1 is the only button which can drag a window. * Small fix on _NET_ACTIVE_WINDOW, it wasn't actually setting the focus. 1.0.11-pre3 (22 Oct 2001) * Added support for _NET_NUMBER_OF_DESKTOPS client messages. * Added support for _NET_CURRENT_DESKTOP client messages. * Added support for _NET_CLOSE_WINDOW client messages. * Added support for _NET_WM_DESKTOP client messages. 1.0.11-pre2 (21 Oct 2001) * Clean ups in aewm.hh * added -es option for edge snapping. Used -es [true|false]. default is true. * Updates to the man page 1.0.11-pre1 (14 Oct 2001 - 20 Oct 2001) * Started adding support for net wm spec. * Reworked client move code. Added opaque move. * Added -wm (wire move) option for commandline. * Linked List clean ups. * Added check to maximize function so that clients don't get maximized past their max size if they set this property. * Added edge snapping, if a window is within 10 pixels of the edge it is snapped to the edge. * Tweaked client raise on click. 1.0.10 (Oct 13, 2001) * ICCCM fixes for setting focus on a client. * Code clean up in client.hh and client.cc * Got rid of compile time option of Motif hints. There was no real reason to have this as an option because it doesn't involve any external libs, and is simply checking Atoms on the X Server. * Fixed self inflicted bug which ignored windows which were already mapped when aewm++ started, this would cause servere problems and make the wm hang. 1.0.9: (Oct 11, 2001) * Small change in quit function in windowmanager.cc involving clearing of the client list. * Fixes in window state and mapping functionality. * Added a new goodies directory. Added a small app which lets you set your root background to a nice gradient. 1.0.8: (Oct 9, 2001) * updates to the README file. * Implemented always on top windows via the GNOME hint WIN_HINTS_DO_NOT_COVER. * The previous bug fix for the xpdf bug wasn't the correct fix. It wasn't getting the correct width and height so I had to call XGetGeometry to fix this. * Small bug in windowmanager.cc in the configure request handler. It didn't cause any errors that I saw but there was a small error in the code. 1.0.7: (Oct 7, 2001) * Added text justify option to commandline -tj pass it left, center or right to justify the window title in the titlebar. * Fixed window stacking order preservation when switching virtual desktops. * Did some code clean up in client.cc * The goodies which were part of aewm have been removed. If you want them download aewm. * Fixed the xpdf bug which caused it to not get reparented. * Makefile updates. * Tweaks to the mouse button handling. * Small bug in edge detection for menu's which caused the menu to be displayed with a (y) position which would put it out of range of being viewed. This manifested if you have a window low on the screen and tried to view its window menu. * A Window Menu has been added to allow for switching clients to different desktops. Also you can maximize/restore, shade/unshade, lower or close. (ISSUES: fspanel doesn't know when a window has changed desktops, I had to patch it to make it update the task list. I'll make that available soon.) 1.0.6: (July 28, 2001) * Fixed bug that made Xnest cause a BadAccess when trying to load it. * Added partial support for GNOME hints. Enough to get it working with fspanel. * Some code cleanups for virtual desktops. * Windows get raised after they are unshaded. * Fixed unmap bug which creeped up again. MJR's solution was indeed correct. this wasn't immediately obvious. You could see the bug if you used fspanel. some windows were being unmapped however they didn't need to be managed anymore and should have been deleted. This would manifest as extra tasks on the fspanel. * Clients with transients like xmms will unmap there transients when unmapped. (needs more testing) * You can click anywhere on a client to raise it. 1.0.5: (July 27, 2001) * Virtual Desktops * Focus highlight color - Window with focus has a different color from unfocused. * Added -md (max desktops) option to command line. * Added maximize and unmaximize functionality to clients by double clicking on titlebar. * Added shade and unshade functionality to clients by middle clicking on titlebar. 1.0.4: (July 22, 2001) * unmap bug fix. * a few small minor changes. 1.0.3: (C++ version by Frank Hale) * Converted aewm-1.0.3 to C++. All regular functionality is still the same as the C version. -- aewm (C version Changelog below) -- 1.0.3: * Backport new init_position, -version option, new man pages, and panel-misc.c crasher/overflow fixes. 1.0.2: * Backport -lXt fix and new documentation. 1.0.1: * Fix remove_client so that it compiles with -DDEBUG turned on. 1.0.0: * All right, I think we're stable now. New stuff will go into 1.1.x. * Changed init_position so that it doesn't cut off very large windows. This was merely annoying for regular windows, but it was downright buggy for incsized ones. * Fixed compilation bug when shape support was disabled. 0.9.19: * OK, I broke command line parsing again. Yes, I'm an idiot. * Fixed problem with exec()-ing a non-existent program. 0.9.18: * Fixed bug in init_position; we can safely use PPosition now. If windows start popping up in bad places, check their size hints before yelling at me. * Use fork/exec instead of system(3) to run programs. Fixed signal handlers to reflect this (we need POSIX sigaction(2)). * Cleaned up MWM hints/WM_SIZE hints code (they sort of match now), and only request the MWM atom at startup instead of for each call. * Started yet another goodies reorganization, and ended up reverting a lot of it. However what's changed should go a little ways towards cleaning things up. * Fix a build error where some goodies files that needed to be compiled against X were compiled without -I/use/X11R6/lib, failing on systems without a symlink from /usr/include/X11. * Tossed out historical 'iheight' junk in border calculation. 0.9.17: * Use ln -f to ignore overwriting previously installed manpage links. * If MWM hints are enabled, no-border windows will no longer get a border upon exiting. * The order of buttons in *-palette is no longer changed by title updates or unhiding windows. * xaw-palette was fixed to work with proper versions of Xaw (shame on me for testing with Xaw3d!), including the one in XF4. The new internals have ported over to gtk-palette. 0.9.16: * Fixed a shaping bug (which actually existed before changes made in 0.9.15) where a window that used to be shaped, but then became unshaped, wasn't updated properly. * MWM hints support can now be compiled in with -DMWM_HINTS, thanks to help from Adam Sampson . * Set the input focus upon entering a window frame, instead of on entering the child window. 0.9.15: * Display a titlebar for shaped windows. This also makes the bug where shaped windows were getting gravitated as if they had a titlebar irrelevant. * Tiny cleanups for the Debian package, including: * Man page for the goodies. * Typo in makefile fixed (tried to strip manpage, ah-reer-reer-reer). * Polished the main man page a bit. 0.9.14: * Free cursors and GCs in quit_nicely. * Switch order of objects and libraries in Makefile to placate Solaris cc. * Rename raise to raise_win -- raise is in signal.h of course (duh!) * Added copyright notice to all goodies and Makefiles due to someone ignoring my license (this has been worked out). * Bail out on lack of default font. You *should* be reading aewm.h first of course ;-) 0.9.13: * Fix really stupid thing I did while refactoring make_new_client, where a window that started as Withdrawn would stay that way instead of getting mapped. * Deal with withdrawing clients properly in *-palette, by watching for the WM_STATE property to be changed instead of looking at UnmapNotify events. 0.9.12: * Clean up clients on receipt of a DestroyNotify. This is needed when a client is already unmapped (i.e, the user iconified it) and it exits. * Preserve window stacking order on exit and restart. * Mucked about with the make_new_client logic; tell me if this breaks something. * Added gtk-*-menu clients contributed by Adam Sampson . 0.9.11: * Got rid of unneeded PropertyChangeMask on root window. Silly me. * Removed the ugly array/linked-list hack from xaw-palette, so that the internal workings of both palette clients are now basically identical. * static'd everything that should have been static. * Updated email, documentation, etc. * Got rid of handle_reparent_event, as a client call to XReparentWindow is taken care of by handle_unmap_event. * Backed out the 0.9.9 change to option-parsing macros, which were causing all options to fail miserably (argh). 0.9.10: * Handle withdrawing windows properly in xaw-palette. Both palette clients are a little saner now. * Updated goodies docs. * ungravitate when printing geometry for move/resize. * Moved more code from individual goodies to common-run.c. * Got rid of unhide() as we never use it. * Replaced GenericWidget typedef silliness with global variables. sometimes you just have to pick the lesser of two evils... 0.9.9: * Finally de-insanified handle_xerror. Instead of going through contortions in remove_client to avoid raising errors, we turn the error handler off during the server grab. * Both palette goodies now track iconification of clients and WM_NAME changes. * gtk-palette is now oriented horizontally, and includes a menu, providing lots more space for client buttons. * Made the parse_option macros reusable (thanks to the comp.lang.c folks for the reminder). * make sure get_wm_name in the goodies doesn't crash for windows that have no name. * Minor typo corrections and stuff. 0.9.8: * Brown paper bag: take debugging stupidity out of gtk-palette. * Overhaul the goodies' build system yet again. * Gtk-palette now gets the screen size correctly. * All switch/palette goodies now cut off long titles, use WM_NAME instead of WM_ICON_NAME, and place iconified titles in parenthesis. * No changes to aewm itself in this release. 0.9.7: * Added lots of comments. * General code cleanups, tweaks, reformats all over. * Fixed iconic state problem. * Plugged a memory leak in send_wm_delete. * Added -new3. * Fixed -new[123] allocation bug. * Made debug code considerably saner. * Print "80x25" and such when resizing xterms. * Replaced sprintf with snprintf. * Got rid of -display. set DISPLAY in your environment instead, so that it propagates to child processes. * Messed around with the goodies' build system. * Fixed gtk-palette; events are now filtered properly at the GDK level. * Replaced variable length arrays with malloc/free. * Added xsession, since I've been using it forever. 0.9.6: * Fix for handling inital window geometry. * A few memory leaks plugged. * Wrote a man page * More consistent borders for transient windows. 0.9.5: * Print window geometry while moving/resizing. * Added some WM_NORMAL_HINTS sanity checks * Set the keyboard focus on window enter (for rxvt, etc). 0.9.4: * Root menu replaced by another client. * Added -bw option. * Border-drawing fixes (only visible if you have very wide borders). * Got rid of mouse button exit. 0.9.3: * Put the root menu code back in. * Added more goodies and reorganized them. 0.9.2: * Minor ICCCM compliance fix regarding WM_STATE. 0.9.1: * A small fix to make the palette complain if no rc file exists. 0.9: * Initial public release. Before this, aewm was called 'swim' and was used by me as a school project. It was also rather unstable. pekwm-release-0.1.18/ChangeLog.until-0.1.6000066400000000000000000004322771374756504400177440ustar00rootroot00000000000000pekwm-0.1.6 released 2007-05-28 Claes Nästén * src/Client.cc (Client::giveInputFocus): Minor tweaks on focusing looking at WM_TAKE_FOCUS hint for handling Java Swing applications and OpenOffice.org better. Closing #98 (Thanks noizze for reporting.) * src/Client.cc (Client::Client): Add setWmState call to NormalState if no WM_HINTS was set on the application to fix issues with xprop on netwmpager. Closing #33. (Thanks tuncer{.}ayaz{@}gmail{.}com for reporting.) 2007-03-28 Claes Nästén * src/WindowManager.cc (WindowManager::RootWO::RootWO): Added setting of _NET_WM_PID and WM_CLIENT_MACHINE to the root window. 2007-03-10 Claes Nästén * src/CfgParser.cc (CfgParser::variable_expand): Fix missing expansion if environment variables. 2007-01-31 Claes Nästén * src/PDecor.cc (Button::setState): First commit in 2007, added shaping to buttons for stretched backgrounds. 2006-12-26 Claes Nästén * src/PDecor.cc (PDecor::renderTitle): Add fix for #99 cause by broken optimisation introduced in revision 119. Closing #99. ( Thanks okraits for reporting ) 2006-11-10 Claes Nästén * src/DockApp.cc (DockApp::validateSize): Do not validate on the clients size, but validate on the padded total size to get dockapps properly centered. 2006-09-27 Claes Nästén * src/PWinObj.hh (class PWinObj): Added a map of Window to PWinObj for faster lookup. * src/Workspaces.cc (Workspaces::updateClientStackingList): Updated to not create the list twice (one list and one array). * src/Client.cc (Client::readEwmhHints): Added skipping of menus and focus toggling for docks. 2006-09-21 Claes Nästén * src/PixmapHandler.cc (PixmapHandler::returnPixmap): Use map for pixmap handler instead of list. 2006-09-11 Claes Nästén * src/ActionHandler.cc (ActionHandler::findClientFromTitle): Updated FindClient action to match against the visible title and not the Client set one. * src/RegexString.cc (RegexString::parse_match): Updated parse match to support parsing of // style regular expressions having flags set. Currently only i flag supported. This type of expressions is currently only possible on the FindClient action. 2006-09-07 Claes Nästén * src/Config.cc (Config::parseAction): Updated ShowCmdDialog action to support parameter setting initial value. Useful together with action such as GotoClientID binding a keybinding to ShowCmdDialog GotoClientID for quick navigation. * src/ActionHandler.cc (ActionHandler::actionGotoClientID): Added GotoClientID action which goes to and focuses client with ID. * src/PDecor.cc: Added boolean option ShowClientID under the Screen section of the main config file. This enable/disable display of Client ID in titles. 2006-09-06 Claes Nästén * src/Client.cc (Client::Client): Moved the Client list to Client. Added clientid list to Client so that it is possible to keep track of Client ids, preparation of number based navigation. * src/PDecor.hh (PDecor::TitleItem): Extend PDecor::TitleItem with information to include client id. * src/Frame.cc (Frame::Frame): Moved the Frame list to Frame. 2006-09-03 Claes Nästén * src/CmdDialog.cc (CmdDialog::bufKill): Added action ClearFromCursor for CmdDialog to erase characters from current cursor position to the end of line. 2006-08-31 Claes Nästén * src/Frame.cc (Frame): Moved tagged frame information to Frame. 2006-08-30 Claes Nästén * src/Frame.cc (Frame::setStateTitle): Make custom set titles persist between restarts. * src/CfgParser.cc (CfgParser::Entry::free_tree): Plug major memory leak in CfgParser. * src/PDecor.cc (PDecor::doMove): Update moving to only use the root position of the pointer to support more ways of initiating moving and then also keep correct position. Close #94 ( Thanks Jowi and shared for reporting ) 2006-08-28 Claes Nästén * src/WindowManager.cc (WindowManager::updateMenus): Fix issue in reload causing dangling pointer to custom menus hang around in the list of menus. Should improve on reload crash situation #92 and #96. 2006-08-23 Claes Nästén * src/PDecor.cc (PDecor::TitleItem::updateVisible): Added info flag to title to store extra information in title such as marked state. Closing #47 ( Thanks shared for request ) 2006-08-10 Claes Nästén * src/PMenu.cc (PMenu::unmapSubmenus): Moved dynamic flag to menu items in PMenu. Update unmap code to skip traversing down dynamic menus. 2006-08-01 Claes Nästén * src/Atoms.cc (getLong): Fix compile warnings. * src/PDecor.cc (PDecor::doMove): Moved skip attribute to PDecor from Frame, adding check to skip those PDecor's when checking snap. Closing #95 ( Thanks shared for reporting ) 2006-05-29 Claes Nästén * src/Harbour.cc (setStateHidden): Created new state action HarbourHidden. Closing #89 * src/Theme.cc (load): Removed ROOT command support. Closing #93 ( Thanks shared for reporting ) 2006-05-01 Claes Nästén * src/ActionHandler.cc (actionFocusToggle): Added boolean option to {Next,Prev}Frame set of actions to allow inclusion of iconified windows. Closing #59 ( Thanks shared for request ) * src/ActionHandler.cc (actionSendToViewport): Added SendToViewport Col Row action. It does not implement relative viewport sending. Closing #70 (Thanks Largon for request) * src/WindowManager.cc (createMenus): Extended the ShowMenu functionality to include custom menus. Example, by adding the following to the menu configuration file: ExampleMenu = "Example Menu" { Entry = "Example Entry" { Actions = "Exec xmessage Example" } } And then issuing the action ShowMenu ExampleMenu it would pop up the menu defined. Closing #69 NOTE: The menus names are case insensitive, meaning it is NOT possible to have TestMenu and TESTMENU. This only applies for root level menus, and not submenus of a menu. (Thanks buk{@}nurfuerspam{.}de for request) * src/Util.cc (to_upper): Added to_upper and to_lower string utility methods. 2006-04-28 Claes Nästén * src/Workspaces.cc (setWorkspace): Updated workspace switching and unmapping of window objects to avoid windows being rendered as focused when they are not. Closing #87 * src/Frame.cc (setWorkspace): Fixed ops not handling sticky window value. Closing #86 ( Thanks Skot for reporting ) 2006-04-18 Claes Nästén * doc/Makefile.am: Added missing man page target in Makefile.am. ( Thanks nice for reporting ) pekwm-0.1.5 released 2006-04-17 Claes Nästén * src/Frame.cc (setWorkspace): Re-enabled the use of ApplyOn = "Workspace" for autoproperties. Closing #55 ( Thanks nospaulatu{@}gmail{.}com for reporting ) * src/PDecor.cc (calcTabsWidthSymetric): Fixed ops distributing uneven pixels in tab calculation that caused pixels missing from the title. * src/PMenu.cc (buildMenuRenderItem): Updated menu rendering to properly honour padding and justification. Closing #46 and #74. ( Thanks shared and buk for reporting. ) * src/ActionHandler.cc (actionSendToWorkspace): Added Last parameter to GotoWorkspace and SendToWorkspace actions activating/sending to last active workspace. Closing #79 ( Thanks Tomas Dvorak for request. ) * src/CfgParser.cc (parse_comment_line): Fixed bug in parsing of # and // comments not parsing the content of the line. ( Thanks shared fore reporting. ) 2006-04-16 Claes Nästén * src/Workspaces.cc (placeSmart): Switch position of row/col placement. Closing #60 ( Thanks koniu{@}sheket{.}org for reporting. ) * src/Config.cc (load): Updated and applied patch from koniu{@}sheket{.}org to add OffsetX and OffsetY options to smart placement to pad with x/y pixels. Closing #61 ( Thanks koniu{@}sheket{.}org for patch. ) * src/Theme.cc: Remove max allowed WidthMin value check. * src/CfgParser.cc: Fixed dangling reference crash in configuration parser, triggered by the parse_key_value feature of the CfgParser. Closing #84 ( Thanks shared for reporting ) * src/Frame.cc: Removed size limiting in resize. Closing #73 ( Thanks shared for reporting and dvorakt1{@}fel{.}cvut{.}cz for proposed solution ) pekwm-0.1.4 released 2006-02-22 Claes Nästén * data/themes/default/theme: Fixed typo COLOR_TAB_FS_HIGH instead of COLOR_TAB_FS_LIGHT. 2006-02-16 Claes Nästén * src/CfgParserSource.cc (close): Fix error causing signal handlers not beeing restored. 2006-02-15 Claes Nästén * data/scripts/pekwm_ws_menu.pl: Using updated pekwm_ws_menu.pl script from Aristotle Pagaltzis using COMMAND instead of Dynamic to speed up menus. Workspace can change at runtime using tools outside pekwm, to reflect the changes one will have to reload pekwm. To avoid having to do that one can replace COMMAND with Entry { Actions = "Dynamic path_to_script ..." } and skip the -n flag. ( Thanks Aristotle Pagaltzis for patch ) * src/CfgParser.cc (parse): Add missing popping of source name in name list, causing incorrect search path on includes. Do not print warning of INCLUDEs failing when path is not used, only print when path included. Fix parser error causing last line of buffer not beeing parsed. 2005-09-11 Claes Nasten * src/CfgParser.cc (parse): Fixed newline handling so now it's possible to start sections on a new line after the name of the section. Closing #64 ( Thanks for reporting ) * src/AutoProperties.cc (parseAutoGroup): Fixed incorrect parsing of Group name causing autogrouping not to work between different applicatiions. Closing #65 ( Thanks for reporting ) 2005-08-23 Claes Nasten * src/Frame.cc (getState): Client iconified state was beeing overridden by setWorkspace causing iconified autoproperty not alwasy working. Closing #56. ( Thanks for reporting ) 2005-08-22 Claes Nasten * src/RegexString.cc: Reimplemented RegexString class, now only updates matched part of the string, it's possible to reference 0 which is whole match. Reference syntax has changed from $1 to \1. Remember to escape \ in configuration files as the configuration file parser while escape it while parsing. 2005-08-17 Claes Nasten * src/CfgParser.cc: Reimplemented CfgParser class, now doesn't use stringstream that behave bad on various version of compilers and platforms. Resolves issues on PPC. More extensive error reporting of syntax errors and parsed values. INCLUDE "file" syntax changed to INCLUDE = "file". 2005-08-13 Claes Nasten * src/Config.cc: Changed ClientUniqueNames to UniqueNames and added bool SetUnique option. 2005-07-09 Claes Nasten * src/Frame.cc (handleClientMessage): Fixed incorrect handling of _NET_ACTIVE_WINDOW. Now the window will be shown, and if not on the current workspace the workspace is changed. 2005-06-23 Claes Nasten * src/CmdDialog.cc: Made CmdDialog and WindowMenu use the window object and not only the client associated with an action. Made CmdDialog obey stacking rules (were not inserted into the workspaces stacking list before.) * src/ActionHandler.cc: Added extra bool parameter to ShowMenu action settin the sticky state of windows when showing, defaults to false. Altered the behaviour of menus unsetting sticky state on close. Closing #54 ( Thanks Jyri Jokinen for request ) 2005-06-20 Claes Nasten * src/WindowManager.cc (doReload): Reordered loading of themes and loading of autoproperties on reload to fix issue with old theme data beeing used when setting geometry from autoproperties, which caused resize and redraw. Closing #53 ( Thanks Jyri Jokinen for reporting ) 2005-06-16 Claes Nasten * src/CmdDialog.cc (mapCenteredOnWORef): Added sanity checks to CmdDialog::mapCenteredOnWORef to make sure the CmdDialog gets mapped inside the nearest head. Closing #49 * src/PScreen.cc (getHeadInfoWithEdge): To unify strut and harbour edge handling harbour edge now is described by a strut wich greatly decreases complexity. Frame::fillHeadInfo was moved to PScreen::getHeadInfoWithEdge which now has replaced most of the calls to PScreen::getHeadInfo and thus makes things like MouseNotUnder placement respect the Harbour and Strut applications. Closing #50 2005-06-13 Claes Nasten * src/PTexturePlain.cc: Added 4 extra boolean parameters to SolidRaise for setting which corners to draw (Top Bottom Left Right). If omitted all are going to be drawn, aka old default behaviour. It now also possible to use line width of 0 to make sure lines are render completly out to the edges. 2005-06-10 Claes Nasten * src/ScreenResources.hh: Fixed CursorType enum issue causing invalid cursor beeing displayed when hoovering decor border. Closing #44 ( Thanks Jyri Jokinen for reporting ) * src/PDecor.cc (doMove): Added boolean ShowStatusWindow option to the Screen section of the main config file determing wheter to show the status window when doing Move, Resize and KeyboardMoveResize. Closing #41 ( Paul Seropian for request ) 2005-05-31 Claes Nasten * src/PDecor.cc (restackBorder): Updated PDecor::restackBorder to include titlebar and child when restacking. Now child will always appear ontop and windows are restacked with XRestackWindows instead of individual calls to raise and lower. Closing #34 * src/PMenu.cc (buildMenuRenderItem): Added padding of PMenu arrow texture so it won't go over menu entries text. Padding used is right padding from the text to the arrow and right padding from the arrow to the right border. Closing #37 ( Thanks angel2k{@}gmail{.}com for reporting ) * src/PImageNativeLoaderPng.cc (load): Added missing fclose to PImageNativeLoaderPng::load. Closing #36 ( Thanks dev{@}gim{.}name for reporting ) 2005-05-20 Claes Nasten * src/Client.cc (giveInputFocus): Removed WM_TAKE_FOCUS sending from Client::giveInputFocus. It's not beeing handled correctly thus disrupting focus. ICCCM and EWMH compliance should be reworked and verified in the future. 2005-05-19 Claes Nasten * src/WindowManager.cc (sigHandler): Changed WindowManager::reload to set a reload flag that will be handled from the main loop to get rid of evil race conditions. This isn't perfect yet as it needs a better main event loop, currently reload will wait until an event reaches the queue. * src/PMenu.cc (selectItem): Fixed BadDrawable error doing XCopyArea to non-mapped window. * src/WindowManager.cc (handleFocusOutEvent): Now making sure we have FocusIn events in the queue when getting FocusOut events on the currently focused PWinObj. Closing #32 ( Thanks for reporting ) * src/PImage.hh: New Image handling code with native backend supporting loading of JPG (libjpeg), PNG (libpng) and XPM (libXpm) or using Imlib2 as backend supporting its image formats. Now, pekwm also can be compiled without any Image support at all thus removing the libXpm dependency. This code is experimental and incomplete, there is no support for shaping and Imlib2 backend is still incomplete. Expect updates soon. 2005-05-15 Claes Nasten * src/DockApp.cc (readClassHint): DockApp::readClassHint were using effective (which can be the iconic) dock app window when searching for the hint but should instead use the client window. Fixing issues with harbour sorting. * src/PDecor.cc (activateChild): Removed restackBorder from PDecor::activateChild and now raising active child if any after restacking border. Closing #30 ( Thanks Juraj Ziegler for reporting ) 2005-05-14 Claes Nasten * src/Workspaces.cc (getTopWO): Now more carefull validation of what PWinObj to focus when changing workspace including fallback to root window if focusing fails. Added check for focusability in Workspaces::getTopWO so only mapped anf focusable PWinObjs are returned. 2005-05-11 Claes Nasten * src/Theme.cc (load): Improved theme validation, now pekwm manages to start with empty or nonexistent theme file. Closing #9 ( Thanks Jan Matejek for reporting ) * src/PDecor.cc (applyBorderShape): Changed shaped window behaviour, now shaped windows will appear to be borderless even if they didn't request so however titlebar is kept. This is basically the behaviour of TWM. Closing #3 ( Thanks Jyri Jokinen for reporting ) * src/PDecor.cc (getBorderSize): Added size validation in getBorderSize to fix issues with unsigned value wrap. 2005-05-09 Jyri Jokinen * data/keys: Fixed two typos, one that caused half the file not to be parsed and made it impossible to menu navigate or MoveResize with keys. ( Thanks agnitio and David Frey for reporting ) 2005-05-09 Claes Nasten * src/CmdDialog.cc (exec): Altered CmdDialog::exec behaviour, now when entering commands in the CmdDialog and it doesn't matches a valid Action we now assume it's an Exec action. * src/WindowManager.cc (handleFocusInEvent): Now flushing Enter and Leave events when found an usable FocusIn event to stop them from interfering with the focus policy. Closing #1 NOTE: This might have focusing side effects, please report if experiencing any weird focus behaviour. ( Thanks Jyri Jokinen for reporting ) * src/PDecor.cc (Button): Removed CWEventMask from PDecor::Button windows so that we can distinguish wheter or not the pointer were on the button on button release. Closing #10 ( Thanks dbertonus{@}yahoo{.}com for reporting ) 2005-05-08 Claes Nasten * src/Client.cc (getEwmhStates): Extend CfgDeny AutoProperty/StateAction with 7 new properties to ignore. * ActiveWindow, used to show and give input focus. * MaximizedVert, used to maximize window vertically. * MaximizedHorz, used to maximize window horizontally. * Hidden, used to show/hide window. * Fullscreen, used to set windot to fullscreen mode. * Above, used to make window (always) above other windows. * Below, used to make window (always) below other windows. * src/Frame.cc (getState): Fixed bug in Frame::getState caused initial fullscreen mode not to work properly by syncing titlebar and border state after setting fullscreen state and thus overriding the removal fullscreen caused. * src/Frame.cc (Frame): Added Client::setConfigureRequestLock which is used when doing multiple tasks (like unsetting border and titlebar decor) at the same time to minimize the number of ConfigureRequest events beeing sent. * src/PDecor.cc (PDecor): Resource usage fixes. Add missing returnPixmap for the title background on PDecors. 2005-05-07 Claes Nasten * src/Client.cc (Client): Modified the behaviour of ApplyOn Start autogrouping, now groups are preserved when doing restart in such a sense previously pekwm managed windows will remain in their groups. New clients however will be added to the groups if suitable. Closing #17 ( Thanks Anders Engstrom for reporting ) 2005-05-03 Claes Nasten * src/Frame.cc: (Frame) Applied parts of patch from Rob McDonald reenabling DecorRules and fixing some small errors. ( Thanks Rob McDonald for patch ) * src/PDecor.cc (resize): Now PDecor::resize doesn't unshade if shaded, just updates the real_height property so that it will unshade to the correct size. This fixes two known, and probably some unknown issues where decors have been unshaded unwillingly. * src/CfgParser.cc (parseCComment): Fixed infinte loop when garbage / (with no / or * following) were found in configuration files. 2005-05-02 Claes Nasten * src/Config.cc (copyConfigFiles): Added vars file to default set of config files. * src/CfgParser.cc (load): Now, the INCLUDE directive will first try the current working directory / absoulte path (old behaviour) and if that fails it will try to include the file relative from the directory the current file resides. Fixed broken testcase in Parser::safeSubstr. * src/CmdDialog.cc (handleKeyPress): Added two new actions for CmdDialog. CursBegin and CursEnd. Names beeing self explanatory. * src/CmdDialog.cc (bufChanged): Updated CmdDialog behaviour. HistNext and HistPrev actions now move the cursor to the end of the line. Also, scrolling of text behaves more naturally and a position at 0 bug was fixed. * src/PDecor.cc (PDecor): Added missing initializer of PDecor member _button. Fixing segfault caused by using _button pointing on undefined. Closing #22 ( Thanks Jyri Jokinen for reporting ) 2005-05-01 Claes Nasten * src/PDecor.cc (renderTitle): Initial work of having PWM like titlebars with the border below the titles. This introduces three new theme options: * WidthMin, minimum width of title in pixels. * WidthMax, maximum width of titles in percent relative to width. This value overides WidthMin if it's smaller. * WidthSymetric, symetric "tab" width. To make the title use the old and default style of handling the title set WidthMin to 0. * src/PDecor.cc (setFocused): PDecor::applyBorderShape to actually apply the shape beeing set on the individual border pieces in PDecor::setBorder. This caused shaped borders not beeing shaped for real until one resized the window. Closing #14 ( Thanks Jan Matejek for reporting ) 2005-04-27 Claes Nasten * src/Frame.cc (handleConfigureRequest): Added new AutoProperty and StateAction, CfgDeny. It takes one parameter which can be Position, Size or Stacking which decides wheter or not pekwm should listen on those parts of ConfigureRequest made on the client. Closing #19 Should be extended with overides of EWMH/ICCCM atoms in the future. * src/Frame.cc (updateInactiveChildInfo): Making sure all Clients in a Frame now get their state updated before shutting down pekwm to ensure geometry and state beeing preserved. * src/Harbour.cc (restack): Added setting of layer to restack before raise/lower to make harbour ontop setting be updated on reload. Closing #11 * src/PTexturePlain.cc (render): Fixed missing replacement of width/height 0 to texture specified size. This was noticed when trying to use plain textures (no image to set the size) as separators. Closing #20 ( Thanks Jyri Jokinen for reporting ) 2005-04-25 Claes Nasten * src/Config.cc (parseAction): Replaced MoveClient{Next,Prev} with MoveClientRel action taking a integer argument. MoveChildRel 1 equals MoveChildNext and MoveChildRel -1 equals MoveClientPrev. Replaced {Next,Prev}InFrame with ActivateClientRel action taking a integer argument. ActivateClientRel 1 equals NextInFrame and ActivateClientRel -1 equals PrevInFrame. * src/PDecor.cc (moveChildRel): Fixed broken behaviour of MoveClient{Next,Prev} not working correctly. Closing #21 ( Thanks Jyri Jokinen for reporting ) 2005-04-23 Claes Nasten * src/PScreen.cc (getNearestHead): Applied patch improving Frame handling in Xinerama mode by replacing getHead with getNearestHead. ( Thanks David Frey for patch ) 2005-04-10 Claes Nasten * src/Frame.cc (handleConfigureRequest): Now gravity is obeyd when handling configurerequests. 2005-03-29 Claes Nasten * src/CmdDialog.cc (loadTheme): Fixed issue with CmdDialogs font color not beeing correctly set. Closing #13 ( Thanks Jyri Jokinen for reporting ) * src/WindowManager.cc (screenEdgeMapUnmap): Now screen edge is disable if edge size equals 0. Closing #12 ( Thanks Aristotle Pagaltzis for reporting ) 2005-02-27 Claes Nasten * src/ColorHandler.cc (getColor): Now handling EMPTY colors without issuing a warning, they are indeed intentionally left empty. * src/Frame.cc: Added support for the Viewport keyword in autoproperties, it had been left dangling for quite some while now. Example: Viewport = "Col Row" ( Thanks Geir Isene * src/Client.cc (readEwmhHints): Added Splash and Dialog type to the handling of _NET_WM_WINDOW_TYPE hint, applications get completly decorless using that hint. Closing #8 ( Thanks Aristotle Pagaltzis for reporting ) 2005-02-09 Claes Nasten * src/WindowManager.cc (familyRaiseLower): Fixed typo causing {Raise,Lower} True not affecting parent window if issued on a child. Closing #4 ( Thanks Jyri Jokinen for reporting ) * src/PDecor.cc (setDecor,setDecorOverride): Changed decor name setting behaviour, now if one overrides used the decor with Set Decor action it won't change when toggling border and titlebar as before. Closing #6 ( Thanks Jyri Jokinen for request ) * src/Config.cc (parseActionState): Fixed Set Decor action, SetDecor failed to get updated to the new format. * src/Config.cc, src/PMenu.cc : Fixed issues with extra #ifdef MENUS causing compilation to fail. Closing #5 ( Thanks Fernando Serboncini for reporting ) 2005-01-30 Claes Nasten * src/Config.cc: Added more bounds checking in parser. * src/WindowManager.cc (familyRaiseLower): Fixed logic in {Raise,Lower} True actions, now parent window will lie under the child window as expected. ( Thanks Jyri Jokinen for request ) 2005-01-28 Claes Nasten * src/Action.hh, src/ActionHandler.cc, src/Config.cc: Applied patch removing {Raise,Lower}Family actions, instead using bool parameter. ( Thanks Matt Hayes for patch ) 2005-01-27 Claes Nasten * src/PDecor.cc (getChildFromPos): Fixed logic, didn't like weird values before causing clients to perform actions on not beeing executed. * src/Viewport.cc (moveToWO): Added sanity check making sure the PWinObj actually is inside the visible area of the screen. 2005-01-16 Claes Nasten * data/themes/default/theme: New default theme by Christoph Strake imported. ( Thanks Christoph Strake ) * src/Client.cc: Fixed ICCCM compliance issue causing windows not being drawn in fbpanel's pager when beeing on other than the current workspace. ( Thanks pooh for reporting ) * src/PDecor.cc: Fixed bug causing window to "jump" border + title height/width when initiating move. ( Thanks Jyri Jokinen for reporting ) 2005-01-06 Claes Nasten * src/Image.cc: Fixed ops causing incorrect alignment of images. Caused by missing GCTileStpYOrigin flag set. * src/PMenu.cc, src/Theme.cc, src/Theme.hh: Applied patch to add texture indicating submenus. To configure add Arrow parameter the different states in the Menu section of themes. Parameter is an ordinary Texture. ( Thanks Matt Hayes for patch ) 2004-12-29 Claes Nasten * src/PWinObj.hh, src/PDecor.cc, src/PDecor.hh, src/Viewport.cc: Added do_virtual option to PWinObj::move to control wheter or not to update virtual position of PWinObjs when moving. This was added to be able to control setting of _PEKWM_FRAME_VPOS hint needed when shutting down making all Clients appear inside the "real" screen. ( Thanks Magnus Holmgren for reporting ) 2004-12-23 Claes Nasten * src/*: Looked over setFocusedPWinObj and getFocusedPWinObj which should fix issues with FocusToggle action and FocusedFirst property of autogrouping always going to the same Frame. * src/FrameListMenu.cc: Changed the / | \ style group indication to using menu separators instead. 2004-12-22 Claes Nasten * src/ActionHandler.cc, src/WindowManager.cc: Moved FocusDirectional and FocusToggle actions over to ActionHandler where they belong. * src/PWinObj.cc, src/PWinObj.hh: Added new hidden state to PWinObjs for non-Frame PWinObjs so that they can be considered in stacking etc but not mapping/unmapping. Fixed bug that caused StatusWindow go under the menus. * src/PMenu.cc: Fixed bug caused menus beeing unmapped when dragged (WarpToWorkspace) to a new workspace. 2004-12-20 Claes Nasten * src/Client.cc: _NET_WM_STATE property should be correct now. * src/WindowManager.cc: _NET_ACTIVE_WINDOW wasn't set correctly on Frames with more than one Client. * src/Config.cc, src/Config.hh: Removed GrabWhenResize option as it used anymore. 2004-12-18 Claes Nasten * src/PDecor.cc, src/FontHandler.cc, src/PFont.hh: Fixed various compile-issues with old gcc-2.95. 2004-12-13 Claes Nasten * src/Config.cc: Renamed some sections in the mouse file, Frame now is FrameTitle and FrameBorder is Border. Added section OtherTitle ( actions for decors such as the menu or command dialog ) * src/PMenu.cc, Theme.cc: Implemented menu separators, texture in the theme file is named Separator and a separator currently is added to the menu by adding an empty section named Separator: Separator { } 2004-12-12 Claes Nasten * src/PDecor.cc, src/PDecor.hh, src/Frame.cc, src/Frame.cc: Moved handling of ButtonPress and ButtonRelease over to PDecor so that button presses on decor buttons works for menus and command dialog too. * src/Viewport.hh(isInside): Changed criteria to decide wheter or not a PWinObj is inside the viewport, should resolve some focus issues. * src/PDecor.cc(placeButtons,getChildFromPos): Fixed bug causing clicks on the titlebar not beeing applied on any client if width of the button was greater than the width of the decor. ( Thanks Jyri Jokinen for reporting ) 2004-12-02 Claes Nasten * src/PDecor.cc(setWorkspace), src/Client.cc(setWorkspace): Fixed bug causing infinite loop when client set sticky. ( Thanks Oliver Kraitschy for reporting ) * src/WindowManager.cc (handleButtonPressEvent, handleButtonReleaseEvent): Fixed bug causing Frames with more than Client in it not reacting on button press/release on decor buttons. ( Thanks Jyri Jokinen for reporting ) * src/WindowManager.cc, src/Client.hh: Overloaded handleButtonPress and handleButtonRelease for Client to unify handling of events in WindowManager. 2004-11-29 Claes Nasten * src/PDecor.cc: Using selected color on single client decors. ( Thanks Oliver Kraitschy for request ) 2004-11-28 Claes Nasten * src/ActionMenu.cc: Fixed crash issue with dynamic menus and submenus. ( Thanks Oliver Kraitschy for reporting ) * src/Frame.cc, src/Client.cc: Fixed issue with autorop geometry and workspace not beeing set correctly. ( Thanks Oliver Kraitschy for reporting ) 2004-11-27 Claes Nasten * src/Frame.cc, src/Client.cc, src/Config.cc: Added two new actions, SetTitle and UnsetTitle for setting titles on client windows. 2004-11-24 Claes Nasten * src/PDecor.cc, PDecor.hh, PMenu.cc, CmdDialog.cc, StatusWindow.cc: Added more standard decors than DEFAULT, now there also is MENU, CMDDIALOG and STATUSWINDOW. 2004-11-04 Claes Nasten * src/CmdDialog.cc, src/CmdDialog.hh, src/Config.cc, src/Action.hh: CmdDialog work, added three new actions Close, HistNext and HistPrev and renamed Add to Insert and {Next,Prev} to Curs{Next,Prev}. Hist{Next,Prev} lets you access the last issued commands. 2004-10-31 Claes Nasten * src/Workspaces.cc, src/Config.cc: Added new placementmodel MouseNotUnder placing the windows trying to make it not end up under the cursor instead it places the windows in the screen corners. 2004-10-25 Claes Nasten * src/Config.cc: Fixed two opses causing MoveVertical do resize instead of move and ViewportGoto not working correctly. ( Thanks Peter Nelson for reporting ) * src/Client.cc: Tweaked focus + autogroup (behind) behaviour as it caused trouble giving input focus on a non activated child. ( Thanks Jyri Jokinen for reporting ) 2004-10-24 Claes Nasten * src/PDecor.cc: Incorrect event_mask causing ConfigureRequest not beeing handled properly making applications like gkrellm and xmms behave weird. 2004-10-18 Claes Nasten * src/*: Renamed EnterMovingFrame to EnterMoving as it should apply on all PDecor derived objects. * src/PMenu.cc: Fixed bug causing columns other than the first beeing non-functional ( selecting, execing etc ) Fixed ops causing items in the Goto series of menus not to react on button presses. ( Thanks Jyri Jokinen for reporting ) * src/PDecor.cc: Fixed decor not beeing updated correctly when toggling titlebar/border. ( Thanks Jyri Jokinen for reporting ) * src/Client.cc, src/Frame.cc: Fixed autoproperties ClientGeometry and FrameGeometry not working as they should. ( Thanks Jyri Jokinen for reporting ) * src/FrameListMenu.cc: Fixed ops causing GotoClient menus not to do any actual work, just list clients. ( Thanks Jyri Jokinen for reporting ) * src/Config.cc: Fixed ops causing the Menu section in the main config file not beeing parsed properly. ( Thanks Jyri Jokinen for reporting ) 2004-10-17 Claes Nasten * src/PDecor.cc: Fixed crash bug caused when mapping title/border less applications. ( Thanks amongst others mh and okraits for reporting ) 2004-10-13 Claes Nasten * src/*: Removed optional compile of keygrabber as code is shared with the CmdDialog making it have very little effect. 2004-10-09 Claes Nasten * src/CmdDialog.cc, src/CmdDialog.hh, src/Config.cc, src/Config.hh: Added CmdDialog, simple text field that lets you enter pekwm commands and then execute them. Valid actions are currently all actions valid for the keygrabber. To configure the behaviour of the dialog one section in the keys file and one in the mouse file has been added. In the mouse file an Other section has been added mainly to control focus behaviour of all PDecor based objects with non reimplemented handle*Event methods. In the keys file an CmdDialog section has been added, valid actions are Add, Erase, Next ( move cursor ), Prev ( move cursor ), Clear, Exec. The way to use Add is to put it as the last action configured and make it support any mod/key to let you add text to box, example: KeyPress = "Any" { Actions = "Add" } Usefull actions are amongst other FindClient, Exec and RestartOther 2004-10-06 Claes Nasten * src/FontHandler.cc, src/FontHandler.hh, src/Theme.cc, src/Theme.hh: Changed Font syntax from the old section orientated to a string orientated. New format: "Font#Justify#Offset#Type" where Font is the only field needed, Type field need to be last. 2004-10-03 Claes Nasten * src/PWinObj.hh: Extended PWinObj event interface with KeyPress, KeyRelease and Expose. 2004-09-19 Claes Nasten * src/Harbour.cc, src/Harbour.hh, src/DockApp.cc, src/DockApp.hh: Added a new option to the Harbour section of the main config file named Sort. If set to true dockapps will be placed in order configured via the Harbour section of the autoproperties file. Position is a signed int and order goes as follows 1 2 3 0 0 0 -3 -2 -1 where numbers other than 0 are offset relative to the start and end of dockapps. Example of Harbour section of autoproperties file: Harbour { Property = "^obpager,^obpager" { Position = "-1"; } } * src/PMenu.cc, src/PMenu.hh, src/Config.cc, src/Config.hh: Made menu behaviour configurable, in the main config file a new Menu section has been added containing three keywords: Select, Enter and Exec which all can contain a space separate list of events that should trigger respective action. Example: Menu { Select = "Motion ButtonPress"; Enter = "ButtonPress"; Exec = "ButtonRelease"; } 2004-09-16 Claes Nasten * src/Config.cc, src/Config.hh: Renamed FrameAttract and FrameResist options in MoveResize section to WindowAttract and WindowResist. 2004-09-15 Claes Nasten * src/PScreen.cc, src/PScreen.hh, src/*: Made getHead, getCurrHead and getHeadInfo availible even when xinerama isn't enabled to reduce amount of #ifdef HAVE_XINERAMA in the code. 2004-09-10 Claes Nasten * src/WindowManager.cc: Made WindowManger::RooWO focusable by setting _mapped property to true. What does focus issues have to say about that? 2004-08-23 Claes Nasten * src/PFont.cc, src/PFont.hh, src/Theme.cc, src/Theme.hh: Added support for alpha with Xft fonts, add ,alpha value to the color. Alpha beeing a value between 0 to 65535. Example: #203040,30000 and rgb:20/30/50,60200 2004-08-21 Claes Nasten * src/CfgParser.cc, src/CfgParser.hh, *: Renamed BaseConfig.{cc,hh} to CfgParser. 2004-08-05 Claes Nasten * src/PScreen.cc, src/PScreen.hh: Renamed Screen.{cc,hh} to PScreen.{cc,hh} to match with PScreen class. * src/*: Updated Copyright years. 2004-07-28 Claes Nasten * src/PWinObj.cc, src/PWinObj.hh, *: Renamed WindowObject to PWinObj. 2004-07-14 Claes Nasten * src/FrameListMenu.cc (handleGotomenu): Applied patch from Alexandra Walford adding a new menu, GotoClient which acts like the Goto menu but lists all Clients instead of Frames. * src/ActionHandler.cc (actionFindClient): Applied patch from Alexandra Walford adding a new action, FindClient which searches the client list for a Client which has a matching title ( Using RegexString ). * src/WindowManager.cc (MATCH_GROUP): Fixed signed vs unsigned compile warning introducing together with infinte group size. 2004-07-13 Claes Nasten * src/Workspaces.cc: Applied one line patch from Walter Mundt closing #46. Walter Mundt's comment on the bug: "I think the problem is that when Workspaces gives input focus to the last-focused window in the new workspace, it forgets to tell the WindowObject class that it has done so. When the unmap events come through, WindowObject says there's no focused object, so WindowManager picks a new one -- the sticky window. Claes Nasten This patch fixes things." 2004-05-16 Jyri Jokinen * data/*: Continued reforming the configuration files. ( Thanks agnitio for testing and reporting oddities ) 2004-05-15 Jyri Jokinen * data/*: Brought some new features to config files, changing the mouse and keyboard config files most. 2004-04-27 Claes Nasten * src/Client.cc (Client): Fixed infinite grouping ( size = 0 ). 2004-04-04 Jyri Jokinen * autogen.sh: Added an autogen.sh script for generating configure&make stuff. 2004-02-21 Claes Nasten * src/ActionHandler.cc (handleStateAction): Fixed handling of menu sticky state. Closing #49 ( Thanks Jyri Jokinen for reporting ) 2004-02-01 Claes Nasten * data/themes/horizon/theme: Added new theme named horizon by Alexandra Walford. ( Thanks Alexandra Walford ) * src/BaseConfig.cc (parseCComment): Added support for C ( /* */ ) and C++ ( // ) style comments. 2004-01-30 Claes Nasten * src/AutoProperties.cc (parseAutoProperty): Added Focusable autoproperty. Closes #45 ( Thanks Frank Frejes for request ) * src/BaseConfig.cc (variableDefine,variableReplace): Added support for getting and setting variables from and to the environment in config files. To access or set a global variable use $_ instead of $ as a prefix. * src/Client.cc (giveInputFocus,close): Changed from WindowManager::getLastEventTime to CurrentTime as to fix gtk2 spinbutton issue. Closes #10 ( Thanks Frank Fejes for fix ) 2004-01-18 Claes Nasten * src/Util.cc (setenv): Rewrote setenv making parameters const and setting errno on errors. 2004-01-15 Claes Nasten * src/Config.cc (parseKey): Added support for specifying keys with keycodes instead of with XString format. No changes needs to be made to old keybindings, specifying keycodes is done by prefixing them with #. 2004-01-13 Claes Nasten * data/config.in: Added ConfigUniqueNames section. * src/Client.cc (titleFindID), src/Config.cc, src/Config.hh: Added support for configuring unique window names, this is done via a new sub-section in the Screen section of the config file named ClientUniqueNames. Sample: ClientUniqueNames = "True" { Pre = " <"; Post = ">"; } Would give: Title <2> * data/scripts/pekwm_themeset.sh: Fixed extra fi and made /bin/bash to /usr/bin/env bash to make it work on systems with bash in a nonstandard place. ( Thanks Leo Costela for reporting ) * src/WindowManager.cc (setupDisplay): Added support for old RANDR input selection to fix compilation issues with XFree86 < 4.3. ( Thanks Leo Costela for reporting ) 2004-01-12 Claes Nasten * src/Client.cc: Added support for unique window names with the help of <1> style indicators making them unique. * src/main.cc (main), data/scripts/pekwm_themeset.{pl,sh}: Added support for reading $PEKWM_CONFIG_FILE environment variable at startup and setting it on configuration file so that it reflects the active configuration file. Updated themeset scripts so that they take advantage of this. 2004-01-11 Claes Nasten * src/Workspaces.cc (setWorkspace,gotoWorkspace): Moved setWorkspace, gotoWorkspace ( and related ) methods over to Workspaces class where they belong. * src/FrameListMenu.cc: Changed parent class to WORefMenu instead of BaseMenu directly. Now Attach* and Goto menus don't display the currently focused Frame ( as this makes most sense, as you can't attach to yourself etc ) * src/ActionHandler.cc (handleAction): Fixed bug causing ShowMenu beeing issued from Frame title clicks referencing the incorrect Client. * src/WORefMenu.cc, src/WORefMenu.hh: Added new class which is used as a common interface for Window and Decor menus which adds functionality of showing the clients name in the title of the menu. 2004-01-09 Claes Nasten * src/WindowManager.cc (handleXRandrEvent): Added support for XRANDR extension, on resolution change things now should run smoothly. * debian/*: Removed debian/ directory as requested by Leo Costela. ( Thanks Leo Costela * src/ActionHandler.cc (handleStateAction): Replaced ToggleGrouping action with a new Set,Unset,Toggle state named GlobalGrouping. * src/Frame.cc (giveInputFocus): Added check to make sure the Frame is inside the viewport before giving it input focus. * src/WindowManager.cc (findGroup): Corrected the meaning of Global, previously it only skipped the check if the window was mapped but it didn't skip the test if the window was inside the viewport. Made a group size 0 mean unlimited size. * src/BaseMenu.cc (selectNextItem, selectPrevItem): Made selectNextItem and selectPrevItem not deselecting item if there's only one valid item in the list. Closes #40 ( Thanks Christofer for reporting ) * src/Config.cc (parseActionState): Fixed compile warning. ( Thanks Alaa Abd El Fatah for noting ) * src/BaseConfig.cc: Made $VARIABLES valid until the end of the file, so now it's possible to do INCLUDE = "variables" and use the variables in variables in the file where the INCLUDE was issued. * src/PFont.cc (trimMiddle): Tweaked the trimMiddle so that max_width shouldn't be overriden. 2004-01-02 Claes Nasten * src/BaseMenu.cc (selectNextItem,selectPrevItem): Fixed menu navigation with keyboard, before it had issues with dynamic menus ( stopping at the entries which are not visible ). * src/*: Three new actions has been introduced Set, Unset and Toggle. These actions are used to manipulate toggable properties of Frames and has been introduced instead of introducing actions like SetMaximized and UnsetShaded. Valid states are: Maximized bool bool, Fullscreen, Shaded, Sticky, AlwaysOntop, AlwaysBelow, DecorBorder, DecorTitlebar, Iconified, Tagged bool, Marked, Skip mask This change makes the following actions invalid: Maximize, Fullscreen, Shade, Stick, AlwaysOnTop, AlwaysBelow, ToggleBorder, ToggleTitleBar, ToggleDecor, Iconify, ToggleTag, ToggleTagBehind, MarkClient, ToggleSkip. Sorry for the inconvience, happy config file hacking. ;) 2004-01-01 Claes Nasten * src/Frame.cc (detachClient): Fixed issue with client beeing misplaced when issuing detach. 2003-12-29 Claes Nasten * data/scripts/pekwm_themeset.pl: Changed #!/usr/bin/perl to #!/usr/bin/env perl and now pkill -HUP is used instead of killall -HUP. * data/themes/minimal/theme: Updated the the minimal theme and added unfocused buttons. 2003-12-26 Claes Nasten * src/* (handleButtonRelease): Added support for DoubleClick actions on Menus, Root and Edges. * src/main.cc (main): Added --config option to pekwm which lets you select a custom config file instead of ~/.pekwm/config and SYSCONFDIR/config. ( Thanks "alot of persons" for request ) 2003-12-01 Claes Nasten * src/Frame.cc (maximize): Now checking if the frame is mapped instead of it's on the same workspace so that it takes sticky windows in account and doesn't take hidden windows in account. Closes #35 ( Thanks Aristotle Pagaltzis for reporting ) 2003-11-27 Claes Nasten * src/ActionHandler.cc (handleAction): Removed Frame::showWindowMenu and added the appropriate code in handleAction for use with DecorMenu too. 2003-11-24 Claes Nasten * src/FrameListMenu.cc (updateFrameListMenu): Removed printing of workspace if we only have one workspace. ( Thanks Peter Andersson for request ) * src/Frame.cc (maximize): Now MaxFill doesn't set maximized state. Closing #30 * src/PFont.cc (trimMiddle): Less wasting of title space using trimMiddle. Closing #21 2003-11-21 Claes Nasten * src/*: Applied patch from pv2b splitting {Edge,Frame}Snap into Attract and Resist. To get the old Snap behaviour one sets both Attract and Resist to the same value. ( Thanks Per von Zweigbergk * src/Frame.cc (calcSizeInCells): Fixed bug caused invalid reporting of size in cells ( 80x24 etc ). ( Thanks Jyrki Muukkonen for patch ) 2003-11-19 Claes Nasten * src/Theme.hh (getFrameData): Now decor name are case-insensitive. * src/Frame.cc (doMove,doResize,doKeyboardMoveResize): Fixed position reporting when moving and resizing frames when beeing on another viewport than the first. 2003-11-18 Claes Nasten * src/KeyGrabber.cc (findAction): Now one can execute global key-bindings while navigating the menu, however, menu-bindings match before global-bindings. * src/WindowManager.cc (handleKeyEvent), src/Frame.cc (doMove): Made handleKeyEvent a public method so that it can be used in Frame::doMove so one can execute key-bindings when moving frames. ( Thanks Za Ny for request ) * src/Config.cc: Made all actions valid for RootClick also valid for the ScreenEdge. 2003-11-17 Claes Nasten * src/*: Added two new actions, WarpFrameToWorkspace and WarpFrameToViewport valid in the ScreenEdge section of the mouse file. These are intended for use together with EnterMovingFrame to make workspace/viewport switching possible while moving frames. The actions take the standard GotoWorkspace and ViewportGoto parameter. 2003-11-16 Claes Nasten * src/Frame.cc (doMove): Added support for EnterMovingFrame actions, no actions are currently supported though but. * src/Client.cc (mapWindow,unmapWindow), src/Frame.cc (applyState): Now unmapping the client window and not only the parent window when unmapping. Required syncing of the mapped state in Frame::applyState to work correctly when attaching clients from non-active workspaces. Partially closes #29 2003-11-11 Claes Nasten * src/WindowManager.cc (handleXError): Yet another pekwm crash on restart fixed. XCloseDisplay issues XSync and if any errors exists the X11 error handler is called which was using the PScreen::instance, it has been replaced with standard X11 calls on the supplied Display. ( Thanks mh for reporting ) 2003-11-09 Claes Nasten * src/WindowManager.cc (cleanup): Moved XCloseDisplay to a proper place after everything has been cleaned up and deleted fixing pekwm crashing when shutting down / restarting. * src/PFont.cc (trim): Added characther chopping when using TrimMiddle as it's needed if the availible width is less than what the TrimMiddle string + 2 characters needs. * src/Frame.cc (maximize): Applied patch from Nathan Clegg creating a new action, MaxFill which acts as Maximize but considers the Frames around it. 2003-11-06 Claes Nasten * src/WindowManager.cc (~WindowManager): Added missing call to cleanup in ~WindowManager. Closing #16 * src/WindowManager.cc (familyRaiseLower): Added two new functions, RaiseFamily and LowerFamily. They restack a group ( via the TRANSIENT_FOR hint ) of windows. ( Thanks Armin for request ) * src/Viewport.cc (makeWOInsideVirtual, makeWOInsideReal): Added two new methods beeing called from the Frame constructor making sure that Frames doesn't place themself outside the screen. * src/main.cc (main): Added comments to all methods and added missing call to delete at the end of main. * src/DockApp.cc: Made DockApp utilize PixmapHandler and cleaned up constructor and destructor. 2003-11-05 Claes Nasten * src/Frame.cc (fillHeadInfo): Fixed bug caused by checking if Xinerama was enabled causing harbour beeing ignored when calculating valid screen area. * src/DockApp.cc (validateSize): Fixed ops that caused SideMin not to work on the height. Closing #27 ( Thanks Aristotle Pagaltzis * src/Util.hh: (isTrue): Now it's possible to use 1 and 0 instead of True and False. ( Thanks pfusch for request ) * src/WindowManager.cc (findWOAndFocus): Replaced findFrameAndFocus with findWOAndFocus, findWOAndFocus uses the MRU list instead of stacking list which findFrameAndFocus did. * src/Frame.cc (fillHeadInfo): Added new method now used used in fixGeometry and checkEdgeSnap to setup head/screen geometry removing strut and harbour areas. ( Fixing bug causing invalid position when maximizing ) 2003-10-23 Claes Nasten * src/Frame.cc (moveToEdge): Changed the behaviour of {Top,Bottom,Left,Right}Edge making them only modify one axis ( y for top and bottom, and x for left and right ). The old behaviour can be achived with {Top,Bottom,Left,Right}CenterEdge. ( Thanks David Frey for request ) * src/Config.cc (parseAction): Removed MaximizeHorizontal and MaximizeVertical actions as Maximize now take two bool paremters, first one decides if horizontal should be toggled, second vertical. * src/Config.cc (copyConfigFiles): Now bailing out if we are unable to open the source files when trying to copy the cfg files to ~/.pekwm 2003-10-10 Claes Nasten * src/Frame.cc (growDirection): Added new action GrowDirection which grows the frame in one of the directions ( Up, Down, Left and Right ) to the edge of the head. 2003-10-09 Claes Nasten * Makefile.am: Started converting the makefiles to automake. 2003-10-08 Claes Nasten * data/menu.in (RootMenu): Added ~/.pekwm/themes to the Themes dynamic menu. 2003-10-07 Claes Nasten * src/FrameListMenu.cc (buildName): Added viewport information to the FrameList series of menus. It only displays if either there's more than one viewport in X or Y direction. ( Thanks mh for request ) * src/Viewport.cc (moveToWO): Fixed bug causing the GoTo menu go to the incorrect viewport. Also tweaked the behaviour so that the windowobjects viewport is calculated from the windowobjets center and not the top left edge. ( Thanks Josh and mh for reporting the issue ) 2003-09-29 Claes Nasten * data/scripts/pekwm_themeset.pl: Now sorting theme-names lexically. * src/Client.cc (setSkip): Added _PEKWM_FRAME_SKIP hint so saving of windows skip state should be saved when restarting. * src/Client.cc (readPekwmHints): Added _PEKWM_FRAME_DECOR hint so saving of windows decor state should be saved when restarting. 2003-09-27 Claes Nasten * data/scripts/pekwm_themeset.sh: Added shell version of the pekwm_themeset.pl dynamic contributed by Michal Adamec which is nice for minimal linux installations lacking perl. ( Thanks Michal Adamec for script ) * src/WindowManager.cc (focusDirectional): Added new action, FocusDirectional that takes two paremeters ( only the first is obligatory ). FocusDirectional Direction Bool Where Direction is one of Up,Down,Left and Right and Bool decides wheter or not the focused window should be raised. 2003-09-24 Claes Nasten * src/*: Replaced all the old _cfg class member variables with the use of Config::instance(). * src/FrameWidget.cc (getTabWidth, getTitleWidth): Applied patch fixing broken tab-width calculation when title-width / num-clients != integer. ( Thanks for patch ) 2003-09-22 Claes Nasten * src/PFont.cc, src/PFont.hh: Cleaned up code minimizing code duplication. * src/PFont.cc, src/PFont.hh, Client.cc, Client.hh, FrameWidget.cc: Tuned the trimming, now only titles _not_ having any title rules applied get trimmed at the middle. 2003-09-21 Claes Nasten * src/PFont.cc, src/PFont.hh (trim): Added new option, TrimTitle which takes a string as parameter and makes the old obligatory ... type title shortening configurable. To achive the old behaviour set TrimTitle to ... in the Screen section of config. 2003-09-20 Claes Nasten * src/Workspaces.cc (placeCenteredOnParent): Added a new placement model, CenteredOnParent that causes transient windows to be placed centered on their parent ( transient for ). * src/AutoProperties.cc, src/Client.cc, src/Frame.cc: Added two new options with matching autoproperties. The new options are PlaceNew and FocusNew and they go under the Screen section of the main config file. And the autoproperties have the same name and are used to overide the defaults. 2003-09-19 Claes Nasten * src/AutoProperties.cc (parseAutoProperty): Added new autoproperty: Fullscreen. * src/PFont.cc, src/Theme.cc: Applied patch fixing two opses causing Xmb fonts not to work. ( Thanks Harashino Makoto for patch ) 2003-09-17 Claes Nasten * src/BaseMenu.cc, src/WindowObject.cc: Moved stick to WindowObject and made Stick an valid action for menus. * src/Frame.cc (fullscreen): Added new action Fullscreen, it's only valid from the keys file so you don't put yourself into trouble. * src/Frame.cc (handleClientMessage): Added support for toggling _NET_WM_STATE_ABOVE, _NET_WM_STATE_BELOW and _NET_WM_STATE_FULLSCREEN. * src/PFont.cc (trim, draw): Added a title shortening rule making too long titles skip the middle of the string replacing it with ... * src/WindowManager.cc (screenEdgeCreate): Fixed missing insertion of the screen edge to the workspace stacking list. 2003-09-16 Claes Nasten * src/BaseMenu.cc (updateMenu): Fixed broken size calculation of title fonts in menus. 2003-09-06 Claes Nasten * src/Atoms.cc, src/Client.cc, src/WindowManager.cc Applied patch from Etan Reisner adding more set* to the AtomUtil namespace. ( Thanks Etan Reisner for patch ) 2003-09-03 Claes Nasten * src/Config.cc: Enabled Mod2, Mod3 and Mod5 for actions. However, if ModX corresponds to a Lock key like Scroll Lock adding them won't make a difference to action matching. 2003-08-27 Claes Nasten * src/Config.cc (parseAction): Added support for {Next,Prev,Left,Right} in SendToWorkspace action. ( Thanks Konstantin Kletschke for request ) * src/ActionHandler.cc (handleAction): Removed the {Next,Prev,Left,Right}Workspace actions, instead using GotoWorkspace {Next,Prev,Left,Right,Num}. 2003-08-26 Claes Nasten * src/Config.cc: Changed masks for {Next,Prev,Left,Right}Workspace to include Frames. ( Thanks Lars-Erik Wessman for request ) * src/BaseMenu.cc (handleMotionEvent): Added support for Treshold in Menu section of the mouse file. * src/Viewport.cc (scroll, gotoColRow): Added three new actions, all of them taking two parameters: ViewportScroll X Y ( Move viewport X and Y from current position ) ViewportGoto Col Row ( Move viewport to Col Row ) ViewportMoveXY X Y ( Move viewport to X Y ) * src/WindowManager.cc (focusToggle): Added two frequently requested actions, NextFrameMRU and PrevFrameMRU. Takes the same options as NextFrame and PrevFrame. 2003-08-19 Claes Nasten * data/Makefile.in: Fixed broken --mandir option. ( Thanks Per Øyvind Karlsen for patch ) 2003-08-17 Claes Nasten * src/ActionHandler.cc (handleAction): Replaced the MENU_CLOSE action with the generic ACTION_CLOSE. 2003-08-16 Claes Nasten * src/PixmapHandler.cc: Added PixmapHandler class for caching Pixmap creations/frees for speed reasons. New option in the main config file in the Screen section named PixmapCacheSize determining how many unused pixmaps that should go into the cache is now availible. * src/WindowManager.cc (restart, shutdown): Moved shutdown/restarting code out from WindowManager, now only setting _restart_command from WindowManager and restarting from main() * src/Viewport.cc (moveToWO): Implemented moveToWO so that the Goto menu will work correctly if Frames are outside the current viewport. 2003-08-15 Claes Nasten * src/WindowObject.cc, WindowManger.cc (giveInputFocus): Added focusable property to WindowObjects. And made WindowManager::EdgeWO unfocusable. * configure.in, acinclude.m4: Added checks for Imlib2 ( image handling ) and Xft ( font support ) to the configure script. 2003-08-11 Claes Nasten * src/Client.cc (readAutoprops): Fixed silly error return data instead of NULL causing transient windows beeing autogrouped and having the geometry set as it's done outside Client::readAutoprops. * data/themes/default/theme.in: Updated the default theme so that it works together with pekwm. * src/Frame.cc (setupAPGeometry): Replaced the Geometry auto property with two new properties, FrameGeometry and ClientGeometry. It's valid to use both at the same time but the FrameGeometry overides the ClientGeometry. 2003-08-10 Claes Nasten * src/PFont.cc: Added PFontXmb type and move non-used code from PFontX11 to it. To use Xmb fonts append #XMB to the font name, just like one appends #XFT for Xft fonts. 2003-08-08 Claes Nasten * src/Theme.cc (loadFont): Changed the : to # used for specifying types as : conflicts with Xft font names. * src/Harbour.cc, src/Frame.cc, src/Config.cc, src/WindowManager.cc: Applied patch fixing Harbour+Xinerama behaviour. This also adds a Head keyword to the Harbour section of the config file which decides which head dockapps should be placed. ( Thanks Bryan Traywick for patch ) 2003-08-07 Claes Nasten * src/Image.cc: Started implementing Imlib2 support, to make pekwm support more file formats that Xpm and have much improved image-scaling performance. * src/ImageHandler.cc: Added ImageHandler class which caches image loading to make less resources beeing used. ( very usefull when having multiple decors ) * src/AutoProperties.cc (findDecorProperty): Added DecorRules section to the autoproperties file. This means one can have different types of frame decorations based on ordinary property rules. Sample section: DecorRules { Property = "^.term,^XTerm" { Decor = "TERM" } } Which will make terminals have the FrameDecor named TERM in the theme file ( if one exists ). * src/PFont.cc: Renamed PekwmFont.* to PFont.*. Reworked font support so now there's a PFont baseclass, and PFontX11 PFontXft derived classes. Also added to the fonts system is shadowed fonts which means you can have two colors per font with configurable offset. A Font section in the theme file now looks like this: Font = "Vera-12#XFT" { Justify = "Center" Offset = "1 1" } 2003-08-04 Claes Nasten * src/BaseConfig.cc (parseVariables): Now variable expansion ends at any non alpha numeric character instead of only spaces and new variables as before. The old behaviour caused: $OOo = "~/OpenOffice.org1.0.3/program" Entry = "Writer" {Actions = "Exec $OOo/swriter &"} Not to work because of the variable didn't end at the / but after swriter. ( Thanks Russell Wood for reporting ) 2003-08-03 Claes Nasten * src/Frame.cc (close): Added new action, CloseFrame which closes the Frame and all clients in it. ( Thanks gim for request ) 2003-08-02 Claes Nasten * src/Frame.cc (doGroupingDrag): Added check to see if global grouping is turned off when doing GroupingDrag. ( Makes it ungroup wherever the window is released ) 2003-08-01 Claes Nasten * src/BaseMenu.cc (setFocused): Added two new colors to theme, BackgroundFocused and TextFocused, that is used when the menu has input focus. (handle*): Now there's a Menu section of the mouse file, supported events currently are ButtonPress, ButtonRelease, Enter and Leave. * src/AutoProperties.cc (matchAutoClass): Added new method matchAutoClass now used in both AutoPropertis::findProperty and WindowManager::findGroup which should correct broken autogrouping matching rules. 2003-07-30 Claes Nasten * src/Client.cc (Client): Fixed misplaced initalisation of _shaped making compilation break if shaping support was absent. ( Thanks Chris Priestman for reporting ) * src/Config.cc (getMouseButton, getMod): Added Any to the list of valid mouse buttons and valid modifiers, this should be used when configuring enter and leave events * src/WindowManager.cc (cleanup): Now destroying the Screen Edge, might fix some shutdown issues. (RootWO) Added Root WindowObject so now root window actions and true focus follow mouse should be possible. * src/BaseConfig.cc (pipeFillBuffer): Now doing proper saving/restoring of the SIGCHLD action. 2003-07-19 Claes Nasten * src/ActionHandler.cc (handleAction): Added new action, ToggleGrouping, which toggles sets all kinds of grouping on/off. This I find usefull when I want to avoid autogrouping. * src/KeyGrabber.cc (load): Made the "couldn't load keyfile" error more informative. ( Thanks edgewalker for request ) 2003-07-18 Claes Nasten * src/* (*): Leave and Enter events are configurable, not everything is working yet but check data/mouse for example on how to configure pekwm now. This obsoletes the Focus section of the config file. 2003-07-16 Claes Nasten * src/BaseMenu.cc (selectItem): Applied patch fixing broken menu behaviour ( moving the mouse to the title didn't de-select the active menu item ) ( Thanks deryni for patch ) * src/Client.cc (Client): Started replacing the _frame (Frame) pointer with a _parent (WindowObject) pointer. 2003-07-14 Claes Nasten * src/WindowManager.cc (handleEnterNotify): Now it's possible to configure ScreenEdge Enter/Leave events. This obsoletes the WWMouse option. 2003-07-13 Claes Nasten * src/FrameWidget.cc (FrameWidget): Changed the event mask of the border to fix the "action beeing run twice" when having actions with modifiers on the frame's border. * src/Config.cc (loadMouseConfig): Added support for configuration FrameBorder. This is done via the new FrameBorder section in the mouse config. ButtonPress, ButtonRelease and Motion are valid event types. Example: FrameBorder { TopLeft { ButtonPress = "1" { Actions = "Resize TopLeft" } } } Valid position are TopLeft, Top, TopRight, Left, Right, BottomLeft Bottom and BottomRight. NOTE: If not adding any actions resizing the frame with the border will not work. 2003-07-12 Claes Nasten * src/Frame.cc (toggleSkip): Added new function, ToggleSkip which lets you modify the skip state of the current frame while running, before one only could access this feature with autoproperties. 2003-07-11 Claes Nasten * src/Viewport.hh, src/WindowManager.cc: (isInside) Fixed isInside method, now FocusNextPrev and FindGroup only includes windows that have their top-left corner visible on the current viewport. 2003-07-10 Claes Nasten * src/DockApp.cc (updateSize): Added a new section to the Harbour section in config, Dockapp which currently contains two values, MinSide and MaxSide. To get windowmaker like behaviour do MinSide = "64"; MaxSide = "64". Size excludes dockapp borders. 2003-07-09 Claes Nasten * src/Atoms.cc (getString): Fixed broken get string caused by not casting uchar to const char. ( Thanks deryni for fix ) 2003-07-08 Claes Nasten * src/ActionHandler.cc (handleAction): It's now possible to use the ViewportMoveDirection action. * src/WindowManager.cc (handleClientMessageEvent): Now listening to _NET_DESKTOP_VIEWPORT making it possible to move viewports with lets say a pager. 2003-07-07 Claes Nasten * src/AutoProperties.cc (parseAutoGroup): Added new keyword to the Group section of autoproperties "Raise" making autogrouped windows beeing raised upon grouping. ( Thanks shared for the request ) * src/Viewport.cc (Viewport): Started working on Viewports, still not very "mature" but they're working. * src/WindowManager.cc (handleMotionEvent): Added support for configuring root window motion events. * src/Screen.cc (getButtonFromState): Added getButtonFromState which reads state trying to figure out which button is pressed ( used in *::handleMotionEvent ) 2003-06-26 Claes Nasten * src/ActionHandler.cc (handleAction): Applied patch making Untag a valid action for root clicks. ( Thanks gim for patch ) 2003-06-24 Claes Nasten * src/Atoms.cc (getProperty): Fixed seriously broken atoms code. ( did I sleep while coding? ) 2003-06-22 Claes Nasten * src/Client.cc (handleUnmapEvent): Now there shouldn't be any more XErrors when client unmaps. * src/Workspaces.cc (placeSmart): Applied patch from Timo Hirvonen, quote from email: "this patch fixes a window placement bug (smart placement doesn't work if there's exactly window width/height pixels empty space)." ( Thanks Timo Hirvonen for patch ) * src/Frame.cc (updatePosition): Fixed invalid reporting of client position when moving clients, this caused Eterm background ( when semi-transparent ) to be misplaced. ( Thanks Tomas Green < tgr0217@student.skelleftea.se > for reporting ) 2003-06-20 Claes Nasten * data/scripts/pekwm_themeset.pl: Changed pkill to killall for reloading pekwm. ( Thanks Adam * src/*: Renamed ScreenInfo class to PScreen as it does more than only contain info. Made the PScreen class a singleton class. * src/Types.hh Added uint, ulong and uchar defines. * src/AutoProperties.cc (findProperty,parseProperty): Added support for the WM_WINDOW_ROLE hint, add Role keyword to the property for matching. NOTE: Changed matchign behaviour, for title or role matching one needs to specify a class hint, for the old behaviour use .*,.* * src/Config.cc: Made the GotoWorkspace action valid for use in the WindowMenu. 2003-06-08 Claes Nasten * data/scripts/pekwm_ws_menu.pl: Fixed SendToWorkspace typo. ( Thanks Jose A. Ortega Ruiz for reporting ) * debian/pekwm.menu-method: Updated for the new config format. ( Thanks Mohammed Sameer for fix ) pekwm-0.1.3 released 2003-06-05 Claes Nasten * configure.in, data/Makefile.in, data/scripts/Makfile.in: Patch adding scripts dir and fixes a typo in the makefiles. ( Thanks Jaster for patch ) 2003-06-02 Claes Nasten * src/WindowManager.cc (screenEdgeCreate): Added support for workspace warping by only using the mouse. To enable this set WWMouse to > 0 and if you want it to wrap set WWMouseWrap to True in the MoveResize section. The old WorkspaceWrap and WrapWorkspaceWrap options have been renamed to WWFrame and WWFrameWrap. ( Thanks mh for request ) * src/Frame.cc (doMove): Fixed redraw issues when warping workspaces while moving and using wireframe move mode. * src/Workspaces.cc (isEmptySpace): Now menus are ignored when searching for empty space. * src/Frame.cc (removeClient): Fixed issue with Frames having incorrect geometry after restart when grouping. ( Thanks shared for reporting ) 2003-06-01 Claes Nasten * src/Frame.cc (doGroupingDrag): Changed the GroupingDrag behaviour so that it groups the client beeing clicked on in the titlebar instead of the currently active one. ( Thanks shared for the request ) 2003-05-31 Claes Nasten * src/Client.cc (Client, mapWindow, unmapWindow): Fixed issue with map and unmap window causing the _NET_WM_STATE_HIDDEN state not beeing updated as it should. ( Thanks shared for reporting ) 2003-05-30 Claes Nasten * src/Atoms.cc (EwmhAtoms): Added support for _NET_WM_STATE_ABOVE and _NET_WM_STATE_BELOW * src/Client.cc (readAutoprops): Autoproperties Geometry directive now handles negative position in such a way that -0-0 will make the window appear in the bottom right corner but having the whole window visible. * src/Config.cc (parseActionEvent): Fixed ops causing keyless actions be reported as ok causing X11 weirdness. * src/WindowManager.cc (setEwmhSupported): Fixed mismatched new [] delete thanks to valgrind * src/ActionMenu.cc (unload): Fixed bug causing pekwm to crash when using dynamic menus and submenus by doing BaseMenu::remove and BaseMenu::removeAll virtual and replaced unload with that 2003-05-29 Claes Nasten * src/BaseConfig.cc (pipeFillBuffer): Yet another try making the pipeFillBuffer working and this time it seems as it's successfull. :) * src/Client.cc (readAutoprops): Fixed focus issue when having focus on new set to false and autogrouping windows. ( Thanks shared for reporting ) 2003-05-25 Claes Nasten * src/Client.cc (move, resize): Reworked code so that invalid geometry when autogrouping / applying geometry with autoproperties should happen less frequently. 2003-05-24 Claes Nasten * src/Frame.cc (doKeyboardMoveResize): Showing geometry while in moveresize mode. * src/WindowManager.cc (handleButton*Event): Now supporting separate configuration of button press and releases, keywords are ButtonPress and ButtonRelease. * src/*: Reworked the action system to support multiple actions per event and to make actions look the same in all cfg files. Some examples: Chain = "Mod1 X" { // keys KeyPress = "Mod1 X" { Actions = "ActivateClientNum 3; Exec xterm" } } ButtonPress = "1" { Actions = "Raise; Activate" } // mouse Left { // theme Pixmaps = "btn-close-fo.xpm btn-close-un.xpm btn-close-pr.xpm" ButtonPress = "1" { Actions = "Raise; Activate" } ButtonPress = "2" { Actions = "Maximize; Shade" } } Entry = "Xmms" { Actions = "Exec xmms &" } // menu * src/Config.cc (getMod): Renamed Alt to Mod1 2003-05-23 Claes Nasten * src/Util.cc (splitString): Fixed a bug when having sero size tokens making pekwm crash. Did some optimizations while at it. 2003-05-09 Claes Nasten * src/AutoProperties.cc (parseAutoGroup): Changed autogrouping syntax and introduced a new option, global, which makes grouping ignore the mapped state of the Frame so that grouping happens over all workspaces. Example of a new grouping rule: Property = "^xterm,^XTerm" { ApplyOn = "New" Group = "terminals" { Size = "3" Behind = "True" Global = "False" } } * src/AutoProperties.cc (parseTitleProperty, parseAutoProperty): Added support for title rewriting, rules for defining title rewriting are specified in the autoproperties file under a new section, TitleRules, here follows a sample TitleRules section: TitleRules { Property { Title = "pekwm" Rule = "/.*/pekwm, kickass window manager/" } Property = "^Mozilla,^navigator:browser" { Rule = "/(.*) - Mozilla/M: \$1/" } Property = "^dillo,^Dillo" { Rule = "/Dillo: (.*)/D: \$1/" } } Made a common base class for the Auto and Title properties so that matching and parsing code can be shared. * src/Client.cc: Went back to using strings for title and icon name, as a step to supporting title rules. * src/RegexString.cc (parse, replace): Rewrote RegexString to add more functionality, now it has a replace method to be used in title shortening. Example: /Title (.*)/$1/ 2003-05-03 Claes Nasten * src/Client.cc (readMwmHints): Fixed (?) incorrect reading of _MOTIF_WM_HINTS that made certain apps not beeing resizeable etc. ( Thanks Thomas Fletcher for reporting ) * src/Frame.cc (Frame): Fixed incorrect reparent position when the Client lacked either titlebar or border. ( Thanks Thomas Fletcher for reporting ) * src/WindowManager.cc (attachInNextPrevFrame): Now attach*In*Frame skips windows with Skip FocusToggle set. 2003-05-01 Claes Nasten * src/Frame.cc (insertFrame): Added insertFrame method replacing duplicate code in FrameListMenu and WindowManager * src/KeyGrabber.cc, src/KeyGrabber.hh: Added support for keychains. Config file syntax is. Chain { Mod = "Ctrl"; Key = "E" Action { Mod = "Mod"; Key = "Key"; Param = "Param" } Action { Mod = "Mod"; Key = "Key"; Param = "Param" } } * src/WindowManager.cc (attachInNextPrevFrame): Added four new actions: AttachClientInNextFrame, AttachClientInPrevFrame, AttachFrameInNexFrame and AttachFrameInPrevFrame And they do what it sounds like, attaches the current Client/Frame in the Next/Prev frame. ( Same order as FocusNextFrame ) ( Thanks yartz for request ) 2003-04-06 Claes Nasten * src/Atoms.cc, src/WindowManager.cc, src/Client.cc, src/Frame.cc: Moved the atoms into maps and made them private. * src/Atoms.cc (IcccmAtoms): Applied patch from Etan Reisner making Icccm atom creation use XInternAtoms instead of multiple XInterAtom's. 2003-03-21 Claes Nasten * src/Config.cc (copyConfigFiles): Renamed the autoprops to autoproperties trying to make the name a bit more self-explaining. * src/WindowObject.cc, WindowObject.hh (move,resize): Added move and resize to the WindowObject class. * src/FrameWidget.cc (resize): Fixed possible bug that would happen if resizing a shaded window making it beeing drawn unshaded. 2003-03-19 Claes Nasten * src/FrameWidget.cc, src/Button.cc (constructor): Changed window creation attributes of the border, titlebar and button windows. * src/WindowManager.cc (findFrameAndFocus): Rewrote findFrameAndFocus to be more WindowObject centric and actually work without crashing. * src/AutoProperties.cc (parseProperty): Changed the Layer parameter to be a string instead of a number: 0 - Desktop, 8 - Harbour, 2 - Below, 10 - AboveHarbour, 4 - Normal, 12 - Menu 6 - OnTop, * src/Config.cc (parseButtons): ShowMenu command defaults to WindowMenu if the parameter is invalid. 2003-03-17 Claes Nasten * src/Workspaces.cc, scr/config.cc, src/pekwm.hh: Added FrameSnap to the Skip list for the autoprops. 2003-03-13 Claes Nasten * src/frame.cc, src/frame.hh: Fixed issues with stacking and client list not beeing updated. Added layer to the state and optimized constructor a bit. 2003-03-12 Claes Nasten * src/workspaces.cc, workspaces.hh, frame.cc, frame.hh: Reworked Workspaces and Workspace classes. Now only using one list for keeping track of the stacking, this should resolv some stacking issues related to sticky windows. * src/actionmenu.cc: Workaround for broken DynamicMenus behaviour. 2003-03-07 Claes Nasten * src/*: Fixed issues related to harbour + strut together with snapping / maximization. ( Thanks shared for reporting ) pekwm-0.1.3pre2 released 2003-03-02 Claes Nasten * src/*: Added new keyword to the Rootmenu, Dynamic wich lets you specify a script that should output menu entries inside a Dynamic { } section which will be regenerated everytime the menu is shown. * src/client.cc, src/client.hh: Added extra checks to see if the clients die before they are constructed. Should fix lockups under Solaris. * src/frame.cc, src/frame.hh: Applied patch to report sizes in terms of cells for applications such as xterm that resize in increments greater than 1 pixel. ( Thanks Alexandra Walford ) * src/client.cc: Applied patch that checks for position, size changes before sending configure request which should minimize aterm blankings. ( Thanks Alexandra Walford ) 2003-03-01 Claes Nasten (frame.cc, frame.hh, config.cc, actionhandler.cc) * Added a parameter to the GroupingDrag action making it possible to make grouped windows not beeing activated by default. Parameter is bool, if it's true windows get grouped behind. 2003-02-19 Claes Nasten (*) * Added two new Actions, MarkClient and AttachMarked. ( Thanks Etan Reisner for patch. ) * Added a option to the Focus{Next,Prev} actions that lets you decide wheter or not the windows should be raised during or after the cycle. Valid parameters are, AlwaysRaise, EndRaise and NeverRaise. ( Thanks Etan Reisner for patch. ) 2003-02-18 Claes Nasten (*) * Fixed compile issues when keygrabber and menus were disabled. * Removed Xft font support. * Started working on Xmb support. * Moved the client name and icon name into char*'s instead of strings removing data duplication between Client and FrameWidget. 2003-02-14 Claes Nasten (actionhandler.cc, config.cc, pekwm.hh, frame.cc, frame.hh) * Added new Detach action. (*) * Replaced all Show*Menu actions with ShowMenu which takes one parameter that can have the following values: Window, Root, Goto, Icon, AttachClient, AttachFrame AttachClientInFrame, AttachFrameInFrame (screeninfo.cc, screeninfo.hh, windowmanager.cc, client.cc, frame.cc) * Created (un)grab{Server,Keyboard,Pointer} methods to screeninfo. (frame.cc, frame.hh, keys.cc, keys.hh, config.cc, config.hh, pekwm.hh) * Replaced the Nudge/Resize keybindings with one new action, MoveResize. For configuration details consult data/keys. 2003-02-12 Claes Nasten (frame.cc) * Fixed iconification bug. ( Thanks zipth for reporting ) (actionhandler.cc, config.cc, config.hh, frame.cc, frame.hh, pekwm.hh) * Changed the MoveToCorner action to MoveToEdge making it possible to place the frames in the center of each corner and in the center of the screen. ( Thanks Etan Reisner for patch. ) 2003-02-08 Claes Nasten (framewidget.cc) * We now only use the UnfocusedSelected and FocusedSelected pixmaps if they exist, else we use the Unfocused and Focused ones. ( Thanks Tomas Green < tgr0217@student.skelleftea.se > for idea ) 2003-02-05 Claes Nasten (baseconfig.cc baseconfig.hh) * Added COMMAND keyword to the parser. Which lets you execute an external command and the output gets parsed. ( Alaa ) 2003-02-04 Claes Nasten (data/keys) * Updated default keybindings for keyboard menu navigation support. (*) * Added keyboard navigation support to the menus. The menu related keybinds go in the Menu { section of the keys file and the other, "old" are moved into a Global section. (data/themes/minimal) * Updated the minimal theme for the new UnfocsedSelected theme changes. 2003-02-03 Claes Nasten (workspaces.cc) * Removed extra unnecessary padding that SmartPlacement shouldn't add. (gotomenu.cc) * Moved the * into the [] in the GotoMenu. (theme.cc, theme.hh, framewidget.cc) * Using the Selected pixmap if there's only one client in the frame. * Added UnfocusedSelected section to themes. ( Thanks Tobias Hintze for request ) (windowmanager.cc, windowmanager.hh, client.cc) * Fixed AutoGrouping + Workspace change bug. ( Thanks David Frey (windowmanager.cc) * Moved the status window and Alt+Tab menu to the center of the screen. (gotomenu.cc, gotomenu.hh) * Now showing wheter the frames are shaded ^, iconified ., above + and below - inside [] ( Thanks Rando Christensen for request ) pekwm-0.1.3-pre1 released 2003-01-31 Claes Nasten (data/config.in data/themes/minimal) * New default theme for pekwm named minimal. (frame.cc, frame.hh) * Readded autoprops reading when changing workspace. 2003-01-28 Claes Nasten (image.cc) * Added GCTileStipXOrigin to the image drawing so that tiles start at the correct position. Resolv separator weirdness. (basemenu.cc, theme.cc, theme.hh) * Added three new colors to colorize the menu with, TextColorSelected, TextColorTitle and BackgroundTitle. 2003-01-22 Claes Nasten (autoprops.cc, autoprops.hh, config.cc, pekwm.hh, client.cc) * Renamed the Tag and TagBehind to ToggleTag and ToggleTagBehind and made them toggle the tag to make it easier to use with the mouse. ( Thanks shared for request ) * Added new ApplyOn mask, TransientOnly, which makes properties match only on transient windows. * Added FocusedFirst property to the autprops. If set to true when searching for a group to autogroup with the focused frame is searched first. 2003-01-21 Claes Nasten (client.cc, windowmanager.cc, windowmanager.hh, config.cc, actionhandler.cc) * Added three new actions, Tag, TagBehind and UnTag. If you Tag a Frame all new Clients will become grouped into it as long as it's not hidden. ( Thanks shared for request ) (actionmenu.cc, actionmenu.hh, windowmanager.cc, windowmanager.hh, data/menu) * Removed the RootMenu and WindowMenu and replaced them both with ActionMenu, making the WindowMenu configurable. (frame.cc) * Altered (de)maximization behaviour. (baseconfig.cc) * Moved help methods for the parser into the namespace Parser. 2003-01-19 Claes Nasten (config.cc, frame.cc, data/mouse) * Added new keyword for motion events, THRESHOLD, that lets you specify how many pixels one needs to move the mouse before the action executes. 2003-01-16 Claes Nasten (baseconfig.cc, baseconfig.hh) * Cleaned and updated BaseConfig parser. ( Alaa ) (frame.cc, client.cc, client.hh) * Fixed autoprops position not beeing applied on windows with layer != 0. ( Thanks Daniel Johansson for reporting ) 2003-01-15 Claes Nasten (autoprops.cc, autoprops.hh, client.cc, frame.cc) * Merged the two autoprop keywords Size and Position into the keyword Geometry that takes a standard XGeometryString as argument. (frame.cc, frame.hh, windowmanager.hh) * Moved double click time info from the frame to the windowmanager. (windowmanager.cc, windowmanager.hh) * Added support for double clicks on the root window. ( Thanks Chris Doyle for request ) 2003-01-10 Claes Nasten (*) * Now the focusing code is more Frame centric, moved Client::giveInputFocus to Frame::giveFocus. (iconmenu.cc, iconmenu.hh, windowmanager.cc, client.cc) * Removed some uneccessary calls to add/remove client to the iconmenu from the windowmanager. (frame.cc) * Slimmed the Frame constructor a bit while make sure iconified applications become iconified when we restart pekwm. 2003-01-08 Claes Nasten (baseconfig.cc) * Fixed bug causing pekwm to crash if there was a unmatched pair of "" in the section name. Like Section = "Name { 2003-01-07 Claes Nasten (frame.cc) * Now EdgeSnap also snaps to applications in the harbour. 2003-01-06 Claes Nasten (config.cc, config.hh, data/mouse) * Instead of using Button = "ButtonX" in the mouse config we now use Button = "X" instead. (config.cc, config.hh, button.cc, button.hh, frame.cc, framewidget.cc) * Made it possible to use up to 7 mouse buttons for click actions, XFree86 won't let me use it for motion events. Also made it easy to change the number of supported button, only need to edit config.hh. ( Thanks Daniel Johansson for request ) 2003-01-05 Claes Nasten (*) * We now support the --sysconfdir configure option. Default is PREFIX/etc/pekwm ( Rando Christensen updated Makefile related files ) (windowmanager.cc, windowmanager.hh, atoms.cc, atoms.hh, frame.cc, frame.hh) * Added a new hint, _PEKWM_FRAME_ID which now is used for remembering groups when restarting pekwm. 2003-01-04 Claes Nasten (windowmanager.cc, windowmanager.hh, frame.cc, frame.hh) * Changed AutoProperties behaviour, now autogrouping is based on the initial clients class and reloading autoprops is also based on the original client. ( Thanks shared for request ) (workspaces.cc, config.cc, config.hh, data/config.in) * Made it possible to decide which direction smart placement is placing windows. LeftToRight and TopToBottom. This required a config file syntax change so go look in data/config.in for info on howto configure it. 2003-01-03 Claes Nasten (frame.cc, framewidget.cc, framewidget.hh) * Fixed bug in Frame::getClientFromPos and FrameWidget::draw causing the title clicks activated wrong client when alot of clients were grouped. ( Thanks shared for reporting ) 2003-01-01 Claes Nasten (workspaces.cc, workspaces.hh) * Cleaned Workspaces::checkEdgeSnap which now snaps to sticky and shaded frames too. 2002-12-31 Claes Nasten (windowmanager.cc) * Fixed bug causing the ~/.pekwm/start file not to execute under FreeBSD. ( Thanks Daniel Johansson for reporting ) 2002-12-30 Claes Nasten (basemenu.cc, basemenu.hh) * Cleaned up unused or unneeded variables. (config.cc, config.hh, workspaces.cc) * Removed the config option ReportOnlyFrames and made it the default behaviour. 2002-12-29 Claes Nasten (data/keys, data/menu, data/autoprops) * Uppdated the default config files to use the new more compact syntax. (*) * Big code restructuring, splitting Frame into Frame and Framewidget also slimming down the Client class. Not yet 100% done but it changes the behaviour of things and tries to be alot more Frame centric than Client centric. (autoprops.cc) * Changed the Class keyword to Name in the autoprops config file, which makes it possible to use the new syntax Property = "xterm,XTerm" { 2002-12-25 Claes Nasten (screeninfo.cc, screeninfo.hh, windowmanager.cc, windowmanager.hh) * Moved the Strut methods and getMousePosition class to ScreenInfo (baseconfig.cc) * Added support for variables inside config files $VAR = "value" Param = "Foo $VAR" * Added support for new section name syntax Section = "Name" { } ( Thanks Alaa Abd El Fatah for the work ) 2002-12-21 Claes Nasten (screeninfo.cc) * Fixed missing include to Xutil.h making it not compile under Solaris. ( Thanks Jeremy Naylor for reporting ) 2002-12-12 Claes Nasten (baseconfig.cc) * Fixed bug in parsing comments, added support for \" inside values and added conditional compiles for gcc 2.95 and 2.96. ( Thanks Alaa Abd El Fatah for the work ) 2002-12-11 Claes Nasten (actionhandler.cc, gotomenu.*, windowmanager.cc, windowmanager.hh) * Added a new action, ShowGotoMenu which pops up a menu with a list of all active clients on all workspaces. Lets you click one and then it goes to that workspace, raises the client and gives it focus. (frame.cc) * Changed grouping behavior, it's now possible to group a allready grouped client withouth having to ungroup it first. (baseconfig.cc, baseconfig.hh) * New parsing code, handles multiple sections per line and supports the INCLUDE keyword that makes it possible to include external files to be included. ( Thanks Alaa Abd El Fatah for the work ) 2002-12-07 Claes Nasten (basemenu.cc, basemenu.hh) * Various cleaning. (windowmanager.cc, windowmanager.hh, config.cc, config.hh) * Reworked FocusNextFrame action and added FocusPrevFrame while working on it. Also, added a new config option to the Screen section. ShowFrameList = "Bool" Which decides wheter or not to show a list of clients when doing Focus{Next/Prev}Frame. 2002-12-06 Claes Nasten (windowmanager.cc, windowmanager.hh, config.cc, config.hh) * Reworked focus code a bit and removed the old config models and replaced them with a new config section. Focus { Enter = "Bool"; Leave = "Bool"; Click = "Bool; New = "Bool" } 2002-12-04 Claes Nasten (baseconfig.cc) * Extended the parsing code so it now supports a more condensed format: Section { Param = "Value"; Param = "Value" } (*) * Cleaning 2002-12-01 Claes Nasten (client.cc, frame.cc) * Optimized Mapping/Unmapping of windows. ( Thanks Alaa and shared for info ) (frame.cc) * Cleaned the Maximize method and added support for ResizeIncremeter. (harbour.cc, harbour.hh, config.cc, config.hh, frame.cc, windowmanager.cc) * Added MaximizeOver option in the Harbour section of the config file. ( Thanks Alaa Abd El Fatah for patch ) 2002-11-30 Claes Nasten (frame.cc) * Reworked inserting and removing of Clients. Clients becomes inserted after the current one and when a client becomes removed the client left of it becomes focused. (windowmanager.cc) * Rewrote focusNextFrame so that it hopefully fixes the gcc-2.96 crash. 2002-11-29 Claes Nasten (windowmanager.cc, util.cc) * Fixed compile warnings associated with execlp(). ( Thanks Ted Unangst for info ) (frame.cc, frame.hh) * Fixed bug with unmapping of windows when using AutoGroup and GroupBehind. ( Thanks shared for reporting ) 2002-11-28 Claes Nasten (windowmanager.cc, actionhandler.cc, pekwm.hh, config.cc) * Added new mousebutton action, ActivateOrRaise which if the client isn't allready focused, gives it focus, and if it's focused raises it. (frame.cc, frame.hh, actionhandler.cc) * Resizing no longer Warps the pointer and lets the user resize in all directions when using ClientMotion resizing. (*) * Added new action, RaiseAndActivate which is Raise and ActivateClient combined into one action. ( Thanks shared for reporting ) * Cleaned up and reworked the Action system. * Now we are listening on the MWM Functions hint. 2002-11-23 Claes Nasten (windowmanager.cc, windowmanager.hh) * Fixed issue with root actions not caring about modifiers. ( Thanks shared for reporting ) 2002-11-21 Claes Nasten (client.cc, client.hh, windowmanager.cc) * Now Client button actions are reloaded when reloading. (frame.hh, client.cc, windowmanager.cc, workspaces.cc) * Added Frame::isActiveClient and cleaned up with it. (client.cc, frame.cc) * Fixed a redraw and stacking issue with GroupBehind. ( Thanks shared for reporting ) 2002-11-20 Claes Nasten (autoprops.cc, autoprops.hh, client.cc, config.cc, config.hh) * Added support for autogrouping into the background and the ApplyOn* are now replaced with: ApplyOn = "Start Transient" Also, WorkspaceChange has been renamed to Worksapce and a New keywoard has been introduced. Start now means the start of pekwm and new means the mapping of a new client. (client.cc) * Remove m_has_strut and added operator=(const CARD32*) for class Strut. (client.cc, client.hh, config.cc, config.hh) * Removed Client::construcClient and moved it to the constuctor and while I were at it made it possible to have 3 placement models. pekwm-0.1.2 released (*) * A _basic_ manual page and docs now reside in the docs dir. ( Thanks Rando Christensen for this work ) 2002-11-18 Claes Nasten (config.cc, config.hh) * Moved the mouseconfig out from config to a separate file called mouse. (theme.cc, basemenu.cc) * Fixed issue with text in the status window not beeing visible if pekwm was compiled withouth menu support. 2002-11-15 Claes Nasten (font.cc) * Fixed a typo making colors on Xft fonts behave weird. ( Thanks Rando Christensen for reporting ) 2002-11-14 Claes Nasten (harbour.cc, harbour.hh, config.cc, config.hh, pekwm.hh) * Added Placement and Orientation support for the harbour. Options: Placement = "Top | Bottom | Left | Right" Orientation = "TopToBottom | BottomToTop | LeftToRight | RightToLeft" This relods when reloading the config, also the stacking is uppdated. (frame.cc) Claes Nasten * Fixed a bug causing Client actions with modifiers be executed twice. ( Thanks shared for reporting. ) 2002-11-13 Claes Nasten (frame.cc) * Reverted the look of the WireFrame to only a rectangle to fix issues when moving/resizing borderless windows. ( Thanks Jeremy Naylor for reporting ) 2002-11-12 Claes Nasten (harbour.cc, harbuor.hh, workspaces.cc) * Reworked the stacking of the harbour so that it shouldn't flicker anymore. Still, changed harbour stacking from Above to Below requries a restart for changes to take full effect. (frame.cc) * Tuned the warping of the pointer when using WorkspaceWarp to make a bug not possible or atleast harder to reproduce. (frame.cc) * Fixed a redraw issue when resizing windows. ( Thanks shared for reporting. ) 2002-11-08 Claes Nasten (*) * Focus code rewritten, still not there yet, do expect glitches. * Cleanups. 2002-11-02 Claes Nasten (client.cc, client.hh, actionhandler.cc, config.cc, pekwm.hh) * We now have both a Close and a Kill action, the close one sends an WM_DELETE message if the client supports it, and the kill one kills it with XKillClient. (config.cc, keys.cc) * Changed the behaviour of mods on keygrabs and button actions, if you don't use the Mod keywoard it'll grab withouth any modifier making the None modifier keyword obsolete. (*) Config file parsing is rewritten, this included the most of Config and Theme to be rewritten too. The new base syntax is: Section { Name = "Value" } Which hopefully is alot easier to read. This also causes all configuration files _and_ themes not to work as they need to be rewritten to the new format. 2002-10-30 Claes Nasten (frame.cc, config.cc, config.hh) * Added two new options: WorkspaceWarpResistance* unsigned int; WrapWorkspaceWarp* bool; 2002-10-29 Claes Nasten (frame.cc) * Reworked moving of windows so that you'll now get the status window even if you move in Opaque mode. (config.cc, config.hh, frame.cc) * Added new option, OpaqueResize which will if it's set to true resize while showing it's content. Also, WireMove was removed and replaced with OpaqueMove, which is the same option but inverted. (keys.cc, config.cc, pekwm.hh, actionhandler.cc, frame.cc, frame.hh) * Added new keybinding, MoveToCorner which takes one parameter, which can be one of the following: TopLeft, TopRight, BottomLeft or BottomRight which moves the active window to that corner of the screen. (util.cc) * Added function trimLeadingBlanks for use in parsing code. 2002-10-27 Claes Nasten (baseconfig.cc, baseconfig.hh, config.cc, rootmenu.cc, keys.cc, autoprops.cc) * Cleaned up in BaseConfig and altered default constructor and load behaviour while adding support for loading configs from a FILE object. 2002-10-24 Claes Nasten (workspaces.cc, workspaces.hh, frame.cc, config.cc, config.hh) * Implemented Frame-to-Frame snapping and therefore added a new configuration option, FrameSnap which is amount of pixels between two frames before it snaps. If it's 0 no snapping occurs. NOTE: EdgeSnapWidth config option is replaced with the EdgeSnap config option which no longer is a bool, it's now a unsigned int. (client.cc, client.hh, config.cc, actionhandler.cc, pekwm.hh) * Added three new key grabber commands: ToggleBorder, ToggleTitlebar and ToggleDecor 2002-10-23 Claes Nasten (image.cc) * Fixed crash bug in getScaled. 2002-10-22 Claes Nasten (harbour.cc) * Fixed missing #include in harbour.cc. ( Thanks Rando Christensen for reporting ) 2002-10-20 Claes Nasten (*) * Basic DockApp support via the harbour, still it is in early stage of development. Enable via compile time option --enable-harbour (basemenu.cc, basemenu.hh, windowmanager.cc) * Altered the behaviour of menus, items are now selected if you enter a submenu. Also, the selected item has two lines on it, and it's possible to give the menus name with the MenuName keyword. 2002-10-19 Claes Nasten (genericmenu.hh) * Fixed missing include guard in genericmenu.hh (client.cc) * If a transient window unmaps, we only give the parent focus if the transient window was focused. (client.cc) * Fixed small issue in handleMapRequest, we didn't look wheter or not we were on the active workspace, causing mozilla to map where it shouldn't. 2002-10-17 Claes Nasten (client.cc, client.hh, frame.cc, frame.hh, workspaces.cc, windowmanager.cc) * Reworked hiding and unhiding of clients/frame as Rando Christensen reported that the switch-workspace-to-fast still existed but were really hard to replicate. (windowmanager.cc, windowmanager.hh, workspaces.hh) * Added method findClientToFocus in WindowManager which tries to find a client that can be focused. Also, using this the last focused client is remembered when you kill a client or whatever. (button.cc, button.hh, frame.cc, theme.cc) * Fixed a bug causing pekwm to segfault if you used button 4 or 5 ( usually the scroll wheel ) on the titlebar buttons. Also, while I were at it I added support for configuring all 5 buttons for each button. ( Thanks Holger Schibalsky ) 2002-10-16 Claes Nasten (frame.cc) * Fixed issue with the right border becoming covered with the non active clients in a frame. ( Jonas Lundqvist for reporting ) (client.cc, frame.cc, workspaces.cc) * Fixed some Xinerama compile issues. ( Thanks Matt Keadle for reporting ) 2002-10-14 Claes Nasten (frame.cc) * Cleaned checkEdgeSnap and updated the Xinerama part. (atoms.cc, atoms.hh, windowmanager.cc, windowmanager.hh, client.cc) * Dropped all support for the IMHO obsolete gnome atoms used by gnome-1.4. pekwm-0.1.1 released 2002-10-14 Claes Nasten (data/keys) * New default keys file for pekwm by Rando Christensen , flame or praise him for the changes. 2002-10-13 Claes Nasten (windowmanager.cc, windowmanager.hh, frame.cc) * Altered behaviour of resize, first we now have different cursors indicating what direction is going to be resized also resize will start as soon as Button1 is pressed. ( Thanks agnitio for request ) 2002-10-12 Claes Nasten (screeninfo.cc, screeninfo.hh, keys.cc, keys.hh, client.cc, frame.cc) * Started to use XGetModifierMapping ( after a peak in WindowMaker's source ) to figure out wich modifier Num and Scroll lock has. (image.cc) * Fixed issue in unload, as I weren't resetting the size of the image holders loading from a theme with border at the top one without caused troubles. 2002-10-11 Claes Nasten (client.cc, client.hh, frame.cc) * Reworked unmap handling, now we "filter" the unmap events we cause and then we can listen on the "real" events, wich hopefully resolvs the unmap issues of pekwm. Also, this rework seemed to resolv the to fast Workspace switching bug. (workspaces.cc) * Added check to make sure that the last focused client aren't hidden before activating it. 2002-10-10 Claes Nasten (basemenu.cc) * Fixed XErrors related to trying to set menu height to 0. (keys.cc, theme.cc, client.cc, frame.cc) * Fixed some compile warnings uncovered with -Wall. (theme.cc) * Fixed unmatched pair of XGrabServer / XUngrabServer causing pekwm not to start if there weren't any clients on the screen and menu support weren't compiled in. (*) * Renamed the USE_XFT and USE_MENUS defines to XFT and MENUS. 2002-10-09 Claes Nasten (windowmanager.cc) * Ignoring XCrossingEvents (EnterEvents) when they have a ButtonMask set. 2002-10-08 Claes Nasten (frame.cc, frame.hh) * Now I keep track of the current title pixmaps dimension and reuse the Pixmap if it has good dimensions. (*) * Uppdated the default theme, removed the what-took-so-long theme. (windowmanager.cc, windowmanager.hh, frame.cc, client.cc, client.hh) * Not using XSetInputFocus all over the place anymore, using WindowManager::focusClient which now takes care of that part. Also removed WindowManager::unfocusAllClients as it wasn't used anymore. (frame.cc) * When resizing with the keygrabber, we now make sure that the window isn't shaded. 2002-10-07 Claes Nasten (windowmanager.cc, client.cc) * Reordered the removeFromClientList in the Client destructor, also making sure that the m_focused_client get set to NULL in WindowManger::removeClient if it's beeing removed. (client.cc, client.hh, frame.cc) * Renamed sendConfig to sendConfigureRequest and removed all the calls from Frame and moved them into the appropiate places in Client. 2002-10-06 Claes Nasten (windowmanager.cc) * Reworked handleEnterNotify a bit, wich now is a bit smarter. (frame.cc, client.cc) * Fixed WIN_LAYER < WIN_LAYER_NORMAL stacking issue. (client.cc, workspaces.cc) * Now we also report transient windows to the client list. (windowmanager.cc) * Activating the active workspace no longer unfocus all clients. (Thanks digiwano for reporting) 2002-10-04 Claes Nasten (workspaces.cc, workspaces.hh, config.cc, config.hh, windowmanager.cc) * Added new configure option, ReportOnlyFrames wich will make pekwm only report the active clients in the frames. 2002-10-03 Claes Nasten (client.cc) * Not caring about struts in handleConfigureRequest anymore, resolves the issue with mplayer not beeing able to set itself to fullscreen mode because of it beeing resized because of struts. 2002-10-02 Claes Nasten (windowmanager.cc, windowmanager.hh, client.cc, keys.cc, keys.hh) * Added new compile time option, --enable/disable-keygrabber wich decides wheter or not keygrabber should be enabled. It defaults to true. ( Thanks ? for request ) This speeded things up alot, what's up with keygrabbing taking so much time? Needs investigation. (client.cc, windowmanager.cc) * Started to listen on _NET_WM_DESKTOP so that you can move clients between workspaces with gnome-panel etc. Also cleaned a little. (config.cc, config.hh, client.cc, client.hh) * Made window placement configurable. Syntax is: PlacementModel* Placement FallBackPlacement; The possible placement modes are: Smart, MouseCentered and MouseTopLeft. ( Thanks Dirk Busse for request ) 2002-10-01 Claes Nasten (windowmanager.cc, windowmanager.hh, client.cc) * Removed the grabbing and ungrabbing of keys when windows changed focus as this were causing _big_ slowdown. ( Thanks weird for reporting ) 2002-09-29 Claes Nasten (frame.cc, client.hh) * Fixed issue causing gnome-panels to move themselfs when restarting pekwm. (windowamanger.cc, workspaces.cc, workspaces.hh) * Now we are treating the _NET_CLIENT_LIST_STACKING hint with respect, while this were added _WIN_CLIENT_LIST ( old gnome ) support were dropped. (client.cc) * Fixed bug in handleConfigureRequest causing gnome-terminal get crazy shrinking itself very much. (frame.cc, client.cc, workspaces.cc, workspaces.hh) * Removed restackOnTopWindow and restackBelowWindows from the Workspace class as it now is handled correctly by raise/lower. 2002-09-26 Claes Nasten (autoprops.cc) * Changed the Workspace entry in the autoprops file, now workspace counting starts from 1 and not 0. (windowmanager.cc) * Trimmed off LeaveWindowMask and ButtonMotionMask from the rootwindow listening, as we shouldn't need them. 2002-09-25 Claes Nasten (windowmanager.cc, workspaces.cc, workspaces.hh) * When changing between workspaces the focused client is remembered. If it has been destroyed, the ontop window will become focused. (windowmanager.cc, client.cc) * Cleaned up focusing a bit more, no flickering when changing workspace and less work by pekwm required. 2002-09-24 Claes Nasten (frame.cc) * Fixed the separator / title justification issue when drawing the titlebar, thanks Steve Jacobs for reminding. (image.cc, image.hh, theme.cc, theme.hh, frame.cc) * Removed the Xpm class and replaced it with the Image class, they're pretty much the same class but Image is supposedly a bit speedier. 2002-09-20 Claes Nasten (frame.cc, client.cc, keys.cc, pekwm.hh) * Fixed grabbing of keys and handling of modifiers, so that now it should work under Sun OpenWindows by default when NumLock is pressed. 2002-09-18 Claes Nasten (button.cc) * Fixed ops, not setting values in the constructor of FrameButton. (windowmanager.cc, workspace.cc, workspace.hh) * When closing/grouping/ungrouping windows pekwm tries to focus a window. 2002-09-17 Claes Nasten (client.cc, client.hh, frame.cc) * Fixed some BadWindow errors associated to constructing/destrucing Clients. (windowmanager.cc) * Now handleXError outputs information about X errors when debugging is turned on. 2002-09-16 Claes Nasten (client.cc, frame.cc, workspace.cc, workspace.hh) * Raising and lowering of clients have been reworked and now shouldn't flicker when having always below/ontop windows. (client.cc, workspaces.cc, workspaces.hh) * Cleaned up Client::handleConfigureRequest while fixing bug reported by Ashwin causing sylpheed to move itself instead of becoming raised when execing it twice. (config.cc, config.hh, frame.cc) * Added new option, GrabWhenResize which defaults to true. Lets you decide wheter or not the server should get grabbed when resizing a window. ( Grabbing is the safe choise, but it can make xmms chop etc ) 2002-09-06 Claes Nasten (keys.cc, actionhandler.cc, frame.cc) * Added ResizeHorizontal and ResizeVertical keygrabs that resizes the active frame with X pixels, if the active client has the ResizeInc set it changes the size with one incremeter instead. ( Thanks weird for request) (keys.cc, actionhandler.cc, config.cc, frame.cc) * Added ActivateClientNum keygrab which lets you activate client number X in the activate frame. ( Thanks weird for request ) (frame.cc) * Fixed MaximizeVertical swapped MaximizHorizontal to actually maximize the right direction. ( Thanks weird,Xanix,digiwano for report ) 2002-09-03 Claes Nasten (frame.cc) * Fixed bug in moveClientNext and moveClientPrev causing a crash. 2002-08-31 Claes Nasten (atoms.cc, atoms.hh) * Moved atom structs out from the WindowManager and made classes wich initialises the atoms themselfs. 2002-08-30 Claes Nasten (windowmanager.cc, windowmanager.hh, keys.cc, keys.hh, frame.cc, frame.hh) * Cleanups in EventHandling/ActionHandling. 2002-08-29 Claes Nasten (client.cc) * Fixed small compile bug when compiling without menus. (Thanks Jonas Lundqvist for reporting) pekwm-0.1.1pre4 released. 2002-08-27 Claes Nasten (data/themes/what-took-so-long) * New default theme. (keys.cc) * The name for the Mod4 modifier has been changed back to Mod4. (keys.cc, autoprops.cc, config.cc, config.hh) * SendToWorkspace/GoToWorkspace (keybindings) and Workspace autoprop now start counting at 1 instead of 0 when defining workspace number. Also, MaxDesktop is renamed to NumWorkspaces. (actionhandler.cc, actionhandler.hh) * Now all actions wich include Desktop have Workspace instead. 2002-08-26 Claes Nasten (client.cc, windowmanager.cc) * Fixed Autogroup and Autoworkspace - AKA the Phantom Icon bug and De-Iconification on double click iconified under ROX bug. (Thanks Ashwin for bug report(s)) 2002-08-21 Claes Nasten (workspaces.cc, workpsaces.hh) * Now the number of workspaces will be correctly modified during runtime 2002-08-20 Claes Nasten (frame.cc) * Fixed _BIG_ ops in handleButtonEvent and handleMotionEvent, I had forgotten to remove Caps,Scroll and NumLock states so these event weren't matched when one of them were on. 2002-08-17 Claes Nasten (client.cc, frame.cc) * Now ClientClick actions without modifier will let the client get the event too. 2002-08-16 Claes Nasten (windowmanager.cc, config.cc, config.hh, util.cc, util.hh) * Added support for having a start script specified in the config file by the param StartFile which points to a regular sh script. (Thanks digiwano for request) 2002-08-15 Claes Nasten (windowmanager.cc) * Altered behaviour of focusNextFrame, it won't raise or warp pointer anymore. (config.cc, config.hh, theme.cc, theme.hh) * Changed the FocusModel config parameters to Follow, Sloppy and Click. Changed the {Menu,Win}.Text.Justfiy parameters to Left, Center and Right. (Thanks digiwano for request) * Added support for _NET_WM_STATE_HIDDEN atom, this let you restart pekwm and iconified windows will stay iconified after a restart. 2002-08-13 Claes Nasten (theme.cc, theme.hh) * Fixed a compile error when compiling error when having menus disabled. (Thanks digiwano for report) (font.cc) * When compiled with Xft support it is now possible to select fonts based on the Xft naming scheme by appending #xft to font name. times-12:bold becomes times-12:bold#xft 2002-08-12 Claes Nasten (client.cc) * Uppdated initPositionSmart to use the new Workspaces code. 2002-08-12 Claes Nasten (workspaces.cc, workspaces.hh, windowmanager.cc, client.cc, frame.cc) * Added Workspaces and Workspace classes to handle workspaces in a saner way. ( One step closer to client-to-client snapping ) (basemenu.cc, basemenu.hh, rootmenu.cc, iconmenu.cc, windowmenu.cc) * Removed basemenuitem.hh, moved it into basemenu.hh. Added accessors for BaseMenuItem and fixed a memory leak in basemenu.cc (configure.in's, Makefile.in's) * Applied autoconf patch from Rando Christensen wich adds a nice configure script 2002-08-11 Claes Nasten (frame.cc) * Changed a little ops in frame redrawing making separators misplaced. 2002-08-07 Claes Nasten (main.cc, windowmanager.cc, windowmanager.hh) * Moved command line parsing to main and renamed the -display and -version arguments to --display and --version, also --help was added. 2002-08-07 Claes Nasten (windowmanager.cc, windowmanager.hh, theme.cc, theme.hh, frame.cc) * Instead of using an invert gc and drawing size/position info on the screen there's an small "status" window instead to make it work together with Xft. 2002-08-06 Claes Nasten (util/showclasshint.cc, util/Makefile) * Added an util section which now holds the utility showclasshint which is usefull when configuring autoprops. 2002-07-30 Claes Nasten (actionhandler.cc, actionhandler.hh, config.cc, config.hh, client.cc, frame.cc) * Now it's possible to configure mousebutton actions with modifiers. NOTE: The old client.* are now representing the client window and are replaced with frame.* wich is titlebar. (font.cc, font.hh, frame.cc, basemenu.cc, basemenu.hh, theme.cc, theme.hh) * Added a new class for handling font stuff, this means xft support. 2002-07-27 Claes Nasten (actionhandler.cc, actionhandler.hh, frame.cc, frame.hh) * Added MoveClientNext and MoveClientPrev to the valid list of keygrabs and clientclick actions. ( Thanks Victor Sahlstedt for request ) 2002-07-19 Claes Nasten (actionhandler.cc, actionhandler.hh) * Added RightDesktop and LeftDesktop wich replaces NextDesktop and PrevDesktop as Prev,Next now wraps. ( Thanks mojumbo for request ) (autoprops.cc, autoprops.hh, frame.cc, client.cc, client.hh) * Instead of NoDecorations there are now NoBorder and NoTitlebar in the autoprops. pekwm-0.1.1-pre3 released 2002-07-17 Claes Nasten (config.cc) * Rewrote the copying of config files wich hopefully resolves some weird issues. (basemenu.cc) * Changed the booring empty square of the submenu indicator to a filled triangle. (Thanks Victor Sahlstedt for request) (actionhandler.cc, actionhandler.hh, frame.cc, frame.hh, client.cc, client.hh) * Added IconifyGroup action to actionhandler, it'll iconify all the windows in a group. Also, fixed so that when iconifying clients one by one the frame will be iconified when all the clients in the frame are iconified. (Thanks Victor Sahlstedt for request) 2002-07-12 Claes Nasten (autoprops.cc, autoprops.hh, windowmanager.cc, windowmanager.hh, client.cc, client.hh, frame.cc, frame.hh) * Added support for auto properties such as sticky, position and auto-grouping, read the documentation for more info. 2002-07-08 Claes Nasten (windowmanager.cc, windowmanager.hh) * More hint cleanups, now deskmenu works and also setting of desktop count. (keys.cc, keys.hh) * Added support for keygrabbing without modifier, modifier named None. (Thanks _name_ for request) pekwm-0.1.1-pre2 released 2002-07-06 Claes Nasten () * NOTE! This is just a panic cleanup release of 0.1.1-pre1 2002-07-06 Claes Nasten (windowmanager.cc) * Sloppy focus won't focus WIN_LAYER_DESKTOP windows when entering them now. 2002-07-05 Claes Nasten (windowmanager.cc) * Now setExtendedNetActiveWindow does reporting of the current active window correctly, so now gnome-deskguide shows the correct active window. 2002-07-05 Claes Nasten (Makefiles, keys.cc) * Applied patches from Lurene Grenier making the Makefiles saner and it also fixes an ops in keys.cc 2002-07-05 Claes Nasten () * Added USE_MENUS toggle to the config.mk file so that you can compile pekwm without any menu support, usefull when using pekwm together with an desktop enviorment. (client.cc) * More hint cleanups. 2002-07-04 Claes Nasten (client.cc) * The extended_net_wm_state toggles weren't working correclty, now close, iconfiy, maximize and shade works. (xpm.cc) * Fixed ops in memory management. pekwm-0.1.1-pre1 released 2002-07-03 () * NOTE! This is a development release, _alot_ of what's in it haven't been finished or tested much, use it at your own risk! Themes and Config files are _not_ compitable with those from pekwm-0.1.0, so the best thing to do is "rm -rf ~/.pekwm" and then restart pekwm. All themes I have created are uppdated and exist on http://pekdon.babblica.net/ for downloading 2002-07-03 Claes Nasten () * Added scaling support for themes, also themes can have separators (pixmaps) between them and the active client can have it's part of the titlebar with another pixmap. 2002-07-02 Claes Nasten (frame.cc) * Changed behaviour of edge snap, now it snaps to the strut edges and not the real edges and snaps from the outside of the screen now too. (client.cc, client.hh, hints.cc, pekwm.hh) * Added support for net_wm_type_desktop and net_wm_type_dock(more are coming soon) to make pekwm usable with gnome2. 2002-07-01 Claes Nasten (hints.cc, hints.hh, windowmanager.cc, windowmanager.hh, client.cc) * Moved the hints back to WindowManager class. (actionhandler.cc, actionhandler.hh, windowmanager.cc, windowmanager.hh, frame.cc, frame.hh) * Now titlebar motion events are configurable, tough only 2 actions are valid: Move & GroupingDrag. configuration syntax is: client.motion* Button:Action; (theme.cc, theme.hh, button.cc, button.hh) * Now titlebar buttons support shaping. 2002-06-30 Claes Nasten (hints.cc) * Now honouring the skip taskbar hint in updateClientList. 2002-06-29 Claes Nasten (actionhandler.cc, actionhandler.hh, rootmenu.cc) * Rewrote parsing of menus to use the getAction from actionhandler, replaced sub keyword with Submenu, end with SubmenuEnd, other with RestartOther and end with Exit. 2002-06-28 Claes Nasten () * Added commmon actionhandler for keygrabber, rootmenu, windowmenu, rootclicks, clientclicks and buttonclicks. Check in README for valid actions. 2002-06-27 Claes Nasten (windowmanager.cc, windowmanager.hh, frame.cc, frame.hh, config.cc, config.hh) * Now it's possible to configure mouse button actions, the configuration is put into the main config file (~/.pekwm/config) and the syntax follows root.click* Button:Action:Param; ( root window clicks ) client.click* Button:Action; ( client clicks ) client.click.double* Button:Action; ( double clicks on clients ) Valid root click actions are: ShowRootMenu ( toggles root menu visibility, and hides all other menus ) ShowIconMenu ( toggles icon menu visibility, and hides all other menus ) HideAllMenus ( hides all menus ) NextDesktop ( goes to the next(right) desktop ) PrevDesktop ( goes to the previous(left) desktop ) Exec ( executes a command ) Valid client click actions are: Raise ( raises the frame ) Lower ( lowers the frame ) Shade ( shades the frame ) Maximize ( maximizes the frame ) ShowWindowMenu ( toggles window menu visibility ) NextInFrame ( activates the next(right) client in the frame ) PrevInFrame ( activates the previous(left) client in the frame ) ActivateClient ( activates the client that is under the pointer ) (client.cc) * Now changed the layer (OnTop, Below) the property will stick on the windows. (keys.cc) * Added Raise and Lower to the keygrabber. () * Removed individual action enums for keys, buttons and basemenu and merged them all into one. 2002-06-26 Claes Nasten (frame.cc) * Changed look of wire frame draw. (frame.cc, frame.hh, theme.cc, theme.hh) * Borders are now pixmap themable. 2002-06-25 Claes Nasten (theme.cc) * Fixed ops in theme unloading not unloading title pixmaps. 2002-06-24 Claes Nasten (basemenu.cc) * Borders are now pixmap themable. 2002-06-25 Claes Nasten (theme.cc) * Fixed ops in theme unloading not unloading title pixmaps. 2002-06-24 Claes Nasten (basemenu.cc) * Fixed menu hide behaviour causing segfault when reloading config. (windowmananger.cc, client.cc) * Fixed focus issues, keygrabber or transients windoes doesn't steel focus neither does keygrabber. (frame.cc) * Fixed bug causing some transient windows showing buttons. (windowmanager.cc, windowmanager.hh, frame.cc) * Added a frame list, beeing used when reloading themes. (more places to use on left I guess) 2002-06-21 Claes Nasten (windowmanager.cc, windowmanager.hh, keys.cc, keys.hh, rootmenu.cc, rootmenu.hh basemenu.cc, basemenu.hh, frame.cc, frame.hh) * Added support for configuration file reloading, wich loads themes, config keygrabber and rootmenu. SIG_HUP, now reloads instead of restarts pekwm. Keygrabber action, Reload added. Rootmemu config option reload added. (Thanks digiwano for request) pekwm-0.1.0 released 2002-06-19 () * NOTE! the changelog from aewm++-1.0.16 to pekwm-0.1.0 isn't very detailed, alot more minor and major things have changed in the source that isn't documented here, and therefore you should _not_ blame the author of aewm++ for any bugs in the source. 2002-06-19 Claes Nasten (hints.cc, hints.hh) * Merged gnome_protocols bugfix from aewm++-1.0.17. (basemenu.cc, windowmanager.cc) * Changed the behaviour of basemenu, clicking a submenu will just toggle it's visible state, not hiding the whole menu. 2002-06-18 Claes Nasten (hints.cc, hints.hh, client.cc, frame.cc) * Mimimal support for GNOME_WIN_LAYER so now i.ex. nautilus will start on the desktop. (windowmanager.cc, client.cc, client.hh, keys.cc, keys.hh, windowmenu.cc) * Added always below toggle to clients, it's in the window menu and keygrabber(AlwaysBelow). (frame.cc, windowmenu.cc, basemenu.hh) * If you Alt+Mouse3 click windows they'll get lowered. Also, raise and lower is added to the windowmenu. (client.cc) * Fixed gnome (win_state_sticky) state togglling bug. (Thanks Frank Hale for info) 2002-06-14 Claes Nasten (frame.cc) * Fixed bug in fixGeometryBasedOnStrut making it impossible to get larger windows than the screen size. (Thanks Z3l3zT for bugreport) 2002-06-13 Claes Nasten (basemenu.cc, basemenu.hh) * Readded widgets for submenus, now the size are relateive to the font size. 2002-06-12 Claes Nasten (button.cc, button.hh, theme.cc, theme.hh, frame.cc) * Now buttons can han variable button width, tough the different states will will still have the same width tough. (baseconfig.cc, baseconfig.hh, keys.cc, theme.cc, rootmenu.cc) * Made it possible to have more than one char as separator when using BaseConfig::splitString (basemenu.cc, basemenu.hh) * Basemenu cleanups, better xinerama support and less code. 2002-06-11 Claes Nasten (windowmanager.cc, windowmanager.hh, keys.cc, keys.hh) * Added basic AltTabbing support (NextFrame) (client.cc, basemenu.cc) * Fixed some ops about position. 2002-06-10 Claes Nasten (client.cc, client.hh, frame.cc, frame.hh) * Added support for Alt dragging windows, so if you hold alt and press the clients window and drag the window should follow. 2002-06-07 Claes Nasten (windowmanager.cc, keys.cc) * m_focused_client = client; isn't used for setting the focused client anymore, now setFocusedClient is used instead pretty much eliminating the use of unfocusAllClients. Also, this resulted in less buggy focus code making the keygrabber use the focused client instead of the client wich were beneath the pointer. 2002-06-06 Claes Nasten (windowmanager.cc, windowmanager.hh) * Well, doEventLoop got split up in _smaller_ parts, all events except the shaping events got their own function, to get more overhead. 2002-06-05 Claes Nasten (frame.cc, frame.hh, client.cc, client.hh) * Reworked the constructors of the two classes, and changed back the initPositions to the Client(maybe should be in WindowManager) (client.cc) * Now handling the vertical and horizontal maximized hints separate. 2002-06-03 Claes Nasten (frame.cc) * Fixed bug when inserting a client with shade state != the frames shade state that made it necessary to double-click twice to unshade the frame. (windowmanager.cc) * Fixed bug in findTransientToMapOrUnmap causing the transient windows not unhiding if they were hidden on another desktop. (Thanks Z3l3zT for bugreport) 2002-06-02 Claes Nasten (windowmanager.cc) * Switching desktop will now focus the client that is ontop(focus click) or the client that the is under the mouse (focus {sloppy, follow}) (iconmenu.cc, windowmanager.cc) * Now it's possible to uniconify clients independt of where they were iconified, an item will have an appended after its name. (windowmanager.cc) * Fixed some focusing issues making it impossible to use keygrabber when iconifying windows and not having anyone left (Thanks Z3l3zT for bugreport) () * Not using LinkedList anymore, using std::vector now instead. 2002-06-01 Claes Nasten (config.cc, rootmenu.cc, keys.cc, theme.cc) * They now use DATADIR instead of PREFIX/share/pekwm for default data dir (*Makefile*, config.mk) * Rewrote the Makefiles and added makefiles for the config files and themes. Also added config.mk for easier configuration. (basemenu.cc, basemenu.hh, windowmenu.cc, rootmenu.cc, rootmenu.hh, windowmanager.cc) * Now it's possible to actually make use of the submenu functionality in the BaseMenu class. Therefore uppdated the windowmenu(Send To is now separate) and made it possible to have submenus in the rootmenu: sub* SubMenuTitle; will start a submenu with title SubMenuTitle end* ; Will end the current menu () * Cleaning headers and added some small functions to make life cleaner (windowmanager.cc) * Changed beahviour of windowmenu, now it'll hide showing another menu or clicking somewhere on the root window with mouse{1, 2, 3} 2002-05-31 Claes Nasten () * Now compiles nicely with Intel C++ 6.0. My bad it didn't! :/ 2002-05-30 Claes Nasten (frame.cc, frame.hh) * Window buttons behave more normal now, resize works when pressing it directly, and you won't be able to move windows by holding the button and draging anymore. (windowmanager.cc, basemenu.hh, windowmenu.hh) * Added "Always On Top" to the windowmenu, also if there are an ontop window in a frame-group the frame will only get raised if the active client is the one having AlwaysOnTop set. 2002-05-29 Claes Nasten (frame.cc, frame.hh, button.cc, button.hh) * Made frames think more of transient clients when there are more than one client per frame. (theme.cc, theme.hh, config.cc, config.hh) * Now we are using themedir instead of themefile in the config file, also the themes have all pixmaps relative to that dir in the theme files. 2002-05-27 Claes Nasten (frame.cc, frame.hh) * Now it's possible to resize windows by draging it's borders. 2002-05-26 Claes Nasten (button.cc, button.hh, theme.cc, frame.cc) * Added ShowMenu to the list of actions buttons can have. (button.cc, button.hh, theme.cc, frame.cc, frame.hh) * Changed button syntax, now it's possible to have buttons aligned either left or right, new syntax is. win.button.left* and win.button.right* (config.cc, config.hh) * Now config files are copied to the users home dir if the config file doesn't exist in the dir ~/.pekwm/ 2002-05-23 Claes Nasten (button.cc, button.hh, frame.cc, frame.hh, theme.cc, theme.hh) * Added basic pixmap themeing of titlebars (tiled pixmaps, focused, unfocused and selected(not yet done)) , also the button box isn't there anymore. It's been obsoleted by configurable buttons who also are pixmap themeable. Button config syntax goes like this: win.button* ActionB1 ActionB2 ActionB3 :FocusedXPM UnfocusedXPM PressedXPM; And possible actions are (Maximize, MaximizeVertical, MaximizeHorizontal, Resize, Shade, Iconify, Stick, AlwaysOnTop, Close, NextInGroup, PrevInGroup and NoAction) (frame.cc,frame.hh,keys.cc) * Now MaximizeVertical and MaximizeHorizontal actually works. 2002-05-17 Claes Nasten (keys.cc, keys.hh) * Parsing seems to work fine now, cfg file syntax is: Action* Mods Mods Key : Parameter; * Added more keybindings: NudgeHorizontal(int inc), NudgeVertical(int inc), NextInGroup, PrevInGroup and Stick. * As I added Stick I fixed so that clients in a sticky group(groups becomes if any client in it is sticky) are ungrouped they ungroup on the current desktop. 2002-05-16 Claes Nasten (keys.cc, keys.hh, baseconfig.cc, baseconfig.hh) * Partially working config file parser, also added function splitString to BaseConfig. 2002-05-16 Claes Nasten (keys.cc, keys.hh) * Added more keybindings: Maximize, Shade, Iconify, Close, SendToDesk GoToDesk and Exec. 2002-05-15 Claes Nasten (keys.cc, keys.hh) * Added Keys class wich handles keyaction, also rewrote the keygrabbing mechanism. What's still to do is add alot of action, only new so far is Exec. Also key config file parsing needs to be done. 2002-05-14 Claes Nasten (basemenu.cc) * Fixed ops in updateMenu causing the menus not acting to events as supposed after more than 1 updateMenu(). 2002-05-13 Claes Nasten (fram.cc, client.cc) * Well, now iconification works rather good, but expect some glitches here and there. 2002-05-09 Claes Nasten (windowmanager.cc, windowmanager.hh, misc.cc, misc.hh) * Moved the signal handler and X error handler to windowmanger.cc, also made SIGHUP restart the wm and not killing it. 2002-05-09 Claes Nasten (windowmanager.cc) * Keybindings work with modifiers(scroll-,num-,caps-lock) now. 2002-05-09 Claes Nasten (frame.cc, client.cc, client.hh) * Added m_is_hidden to Client and I'm now using m_ignore_unmap as a counter, that gets decreased everytime handleUnmapEvent is called. Seemed to resolv the ignore_unmap bug. :) 2002-05-07 Claes Nasten (frame.cc, frame.hh, client.cc, client.hh, windowmanager.cc) * Multiple clients per frame is working, probably are tons of bugs lurking tough. 2002-04-29 Claes Nasten (iconmenu.cc) * Fixed potential memory leak, creating unused BaseMenuItems 2002-04-26 Claes Nasten (*.cc, *.hh) * Removed all "Last Updtaded" as they didn't get updated! Also added changed for pekwm notices in the source files. 2002-04-25 Claes Nasten (frame.cc, client.cc, client.hh) * Fixed shape bug created when I split client into frame and client. 2002-04-23 Claes Nasten (*menu.cc, *menu.hh) * Changed names of handle_* to non _ names and renamed member variables to m_* (frame.cc, frame.hh, client.cc, client.hh) * Removed Client::fixupPositionBasedOnStrut and "replaced" it with Frame::fixGeometryBasedOnStrut wich also, as the name says handles strut geometry issues. 2002-04-21 Claes Nasten (linkedlist.hh) * set and get one line functions are now inline. 2002-04-20 Claes Nasten (all _except_ linkedlist) * The WindowManager wm isn't extern any more. 2002-04-20 Claes Nasten (basemenu.cc) * Fixed text justify of menus -> fixed BaseMenu::findMenuItem. 2002-04-20 Claes Nasten (windowmenu.cc, windowmenu.hh, client.cc, client.hh) * Renamed Client::sendWmDelete() to Client:kill and made it public, added {Maximize, Iconify, Shade & Close} to the windowmenu. 2002-04-18 Claes Nasten (frame.cc, frame.hh, client.cc, client.hh) * All member variables has m_ before themself, and theight has been moved to Frame and renamed to getTitleHeight. 2002-04-11 Claes Nasten (client.cc, client.hh, windowmanager.cc, windowmanager.hh, basemenu.hh) * Edited headers and function names, removed non existing functions and added inline to appropriate functions. Also changed width and height to unsigneds, also desktop functions are using unsigned now. 2002-04-06 Claes Nasten (windowmanager.cc, windowmanager.hh, client.cc, client.hh) * Changed the desktop variables to unsigned, except for belongsToDesktop (baseconfig.cc, baseconfig.hh, config.cc, theme.cc) * Added class BaseConfig to handle basic config parsing. 2002-04-06 Claes Nasten (client.cc) * Fixed bug not causing window frames not to unmap. Added check for valid desktop in set_desktop. 2002-04-04 Claes Nasten (windowmanager.cc) * Fixed text justification, removed old static values (windowmanager.cc, windowmanager.hh, rootmenu.cc, basemenu.hh) * Added restart-other functionality to the rootmenu (iconmenu.cc, windowmenu.cc, rootmenu.cc) * Moved the addToMenuList to the constructor, why were it in the updateMenus? 2002-04-03 Claes Nasten (basemenu.cc, basemenu.hh, theme.cc, theme.hh, rootmenu.cc) * Cleanup in Basemenu, text get's aligned correctly, it's themable and separator function is removed. Also added Restart and Exit functionality to the rootmenu. 2002-04-01 Claes Nasten (basemenu.cc, basemenu.hh, windowmanager.cc, rootmenu.cc, rootmenu.hh) * Added a rootmenu instead of NEW1 & NEW2, also the menus now use the menu font (config.cc, config.hh, windowanager.cc, windowmanager.hh, hints.cc, client.cc) * Added class Config wich should handle config options such as focus mode and max desktops (theme.cc, theme.hh, windowmanager.cc, windowmanager.hh, client.cc) * Added class Theme wich handles fonts and such, removed that part from Windowmanager and adapted client to the changes 2002-03-31 Claes Nasten (client.cc) * Removed member variables root, xres, yres. Added function checkEdgeSnap removing duplicate edgesnap checking (basemenu.cc, misc.cc, misc.hh) * Removed BaseMenu::execute, using forkExec instead also created misc.hh instead of having that part in aewm.hh 2002-03-29 Claes Nasten (client.cc) * New placement routines, first using PPosition||UPosition, then using smart placement and if that doesn't work fall back to place under the mouse. 2002-03-28 Claes Nasten (misc.cc) * Now using setsid() before execing commands in forkExec, exiting the windowmanager will now longer "kill" all clients started from it 2002-03-26 Claes Nasten (screeninfo.cc, screeinfo.hh, windowmanager.cc) * getColormap used from ScreenInfo class. Sane?? (basemenu.cc) * Now is Xinerama aware (hints.cc, hints.hh, client.cc, windowmanager.cc windowmanager.hh) * Moved atoms actions out from windowmanager and created class Hints wich takes care of them instead 2002-03-25 Claes Nasten (client.cc) * Now Maximize and EdgeSnap is Xinerama aware, also EdgeSnap snaps to the edge and _not_ 2 pixels outside. (screeninfo.cc, screeninfo.hh) * Added ScreenInfo class wich handles info about the screen and handles Xinerama functions (client.cc, windowmanager.cc, misc.cc) * Changed to usage of new class ScreenInfo instead of direct calls * Fixed intentation, using 1 tab width 2 now * Changed logic in do event loop * Changed the init of variables in windowmanager pekwm-release-0.1.18/INSTALL000066400000000000000000000001141374756504400154060ustar00rootroot00000000000000INSTALL ======= Visit http://www.pekwm.org/ for help on installing pekwm. pekwm-release-0.1.18/LICENSE000066400000000000000000000432541374756504400153760ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. pekwm-release-0.1.18/Makefile.am000066400000000000000000000003401374756504400164120ustar00rootroot00000000000000ACLOCAL_AMFLAGS = -I m4 AUTOMAKE_OPTIONS = foreign SUBDIRS = src data doc contrib CMake EXTRA_DIST = LICENSE ChangeLog.aewm++ ChangeLog.until-0.1.6 autogen.sh pekwm.spec.in CMakeLists.txt distclean-local: rm -f *\~ .\#* pekwm-release-0.1.18/NEWS000066400000000000000000000045541374756504400150700ustar00rootroot00000000000000NEWS pekwm-0.1.7 ================ Bugs fixed * #XX Several memory leaks identified with valgrind plugged. * #XX Fixed broken iconfied state reported by * #XX CfgParser parsed data twice. * #XX StatusWindow placement fixed. * #XX Fix for _NET_WM_NAME ops by Florian Hoppe * #22 Font type is now possible to define as the first argument in themes. * #30 Panel raise issues, reported and fixed by Jyri Jokinen * #21 Dynamic menu entries become unselectable after first visit. Reported by Lassi Pölönen and fixed by Andreas * #14 SendKey action requested by nidan. * #29 drag'n'drop requires the recieving window to be moved before working. Reported by Jyri Jokinen , fixed by Andreas * #32 Shaping issues after shading. Reported by Paulo Igor Barra Nascimento and fixed by Andreas * #XX Corrects the interpretation of the motif windowmanager hints by Andreas * #XX Remove perl scripts reducing dependencies on packages. User visible changes * UTF-8 support added for reading and rendering window titles. * _NET_WM_ICON is now read and rendered in menus. * RandR support for multi-screen configurations. * New default theme. * CmdDialog size is now calculated from the current head and not the whole display. Configuration changes * _NET_WM_WINDOW_TYPE handling configurable via autoproperties. * Width/Height 0 in autoproperties now means screen width/height. * WorkspacesPerRow and WorkspaceNames added with matching GotoWorkspace/SendToWorkspace parameters Up, PrevV, Down, NextV. * ShowWorkspaceIndicator * WorkspaceIndicatorScale * PCRE support remove. * EdgeIndent option added to Screen section of main configuration file. If true reserves space where the screen edge is. * EdgeSize now supports per edge configuration. Theme changes * Shaping suport for non-corner windows. * XMB type is used by default in favour of X11 type fonts. * Font alpha is now handles as % from 0-100 instead of previous Xft unsigned int value. * HeightAdapt option added to theme. * Font type is now possible to define as the first argument in themes. pekwm-release-0.1.18/README000066400000000000000000000006371374756504400152470ustar00rootroot00000000000000README ====== The Pekwm Window Manager is written by Claes Nästén. The code is based on the aewm++ window manager, but it has evolved enough that it no longer resembles aewm++ at all. It also has an expanded feature-set, including window grouping (similar to ion, pwm, or fluxbox), auto properties, xinerama and keygrabber that supports keychains, and much more. For more information visit http://www.pekwm.org/pekwm-release-0.1.18/README.aewm++000066400000000000000000000224321374756504400163220ustar00rootroot00000000000000aewm++ - The C++ version of aewm ====================================================================== Why was this done? This was done for the simple fact that the C version of aewm spawned many new window managers. In other words it is a great peice of code in which to hack. Hopefully by having a C++ version of it, it will inspire even more C++ programmers to hack it into yet more window managers. What does it do? The C++ version does everything the C version does and more. The programs in the goodies directory were discarded. The reason for this is they are obsolete if you use fspanel and appbar. If you want these programs then download the aewm source code. In the future I plan on starting my own goodies directory where I will distribute appbar, and other little goodies to complement aewm++. aewm++ provides window maximization, iconification, shading and virtual desktops in addition to the regular aewm features. By default aewm++ starts with 4 virtual desktops (or workspaces if you like). Switching is done via the page up and page down keys while mouse pointer is over the root window. You can specify more virtual desktops by passing the -md to aewm++ at runtime. aewm++ is designed for a 3 button mouse or a 2 button mouse with 3 button emulation on. Window maximization is done by double clicking with the first mouse button on the titlebar, double clicking on a maximized window restores it to its original position and size. Shading a window is done by middle clicking on the titlebar. Do this again and the window will become unshaded. To iconify a window simply press the first mouse button on the little box at the right edge of the titlebar. aewm++ doesn't provide any native way to uniconify windows. If used in conjunction with fspanel it works nicely. As of version 1.0.13 there is now an icon menu. If you middle click on the root window you will see the icon menu if you have clients that are iconified. If no clients are iconified you will see nothing. If you middle click on the root window again while the menu is open it will hide. Icons for the current desktop are the only ones that show. Once you switch desktops whatever icons on that desktop will show. More features will be added to aewm++ as needed. I want to get it to where all the standard things you'd expect in a window manager are supported. The focus is also to keep aewm++ as lite as possible. It also picks up development where aewm left off, it hasn't undergone any new development in quite a long time. Partial GNOME support was added, enough to get aewm++ working fully with fspanel. I highly recommend using fspanel with aewm++ as it fits together nicely! C++ version - Frank Hale ************************* **ORIGINAL README BELOW** ************************* aewm - An X11 Window Manager ====================================================================== aewm is a minimalistic window manager for X11. I wrote it mostly to learn about X and the ICCCM, but also to fight software bloat. Instead of expanding to fill your entire "desktop environment", aewm's main purpose is to get out of your way and allow you to use other programs to control things like menus, icons, backgrounds, cursors, root backgrounds, and so on. It doesn't do "themes", or have much in the way of configuration. This is a philosophical statement; it's better to do your work than distract yourself with pretty little borders around it. I myself haven't changed the default background color in, well, ever. Another goal I had in writing aewm was to create an easily readable and hackable implementation of the ICCCM. While I'm not 100% there yet, I think I've at least made the dense jungle of Xlib a bit more understandable. You are encouraged to take the code and do your own thing with it. For this reason I chose a liberal license that should allow you to add your favorite GPL or BSD flavour if you see fit. I was planning on using the name "swim" (Simple WIndow Manager), but someone snapped that up while I was getting the code ready for general consumption. "ae" doesn't really stand for anything, but I am a big fan of Autechre. ;-) The latest release is at http://www.red-bean.com/~decklin/aewm/. Installation ====================================================================== Before compiling, check the default (DEF_foo) options in aewm.h, and the defines in the Makefile. DEF_FONT is of particular interest; make sure that it is defined to something that exists on your system. You can turn -DSHAPE off if you don't have the Shape extension, and -DMWM_HINTS on if you have the Lesstif or Motif headers installed. "make" will compile everything, and "make install" will install it. The goodies/ directory must be compiled separately. I've decided not to use imake or autoconf because the Makefiles they generate are nearly impossible to read, and I wanted to learn how to do it myself. If you need to hack the Makefile in order to get it to work, please email me so I can take your configuration into account. Using It ====================================================================== aewm adds a titlebar with a small box on the right to each window. The availible commands are as follows: Button Titlebar Box ------ -------- -------- 1 Raise Hide 2 Move Resize 3 Lower Delete Each button will also start a different program when you click on the root window. These programs can be defined with the -new1, -new2, and -new3 options. aewm places new windows based on the position of the mouse. If your mouse is in the center of the the screen, a new window will be centered; as you move the mouse to a side or corner, the position of the window will move there. Please note that there is no `unhide' operation to undo the `hide' operation. You'll need one of the goodies for that. Goodies ====================================================================== The goodies directory has been deleted. All of the default aewm goodies have been deleted. If you want them download aewm source code. The reason for this is because I don't plan on changing any of them so its redundant to include them here. In the future a new goodies directory will be created with my own programs to complement aewm++. Caveats ====================================================================== aewm is really not meant for 2-button mice. If you are stuck with one, make sure you can emulate a third button by chording, and try running xmodmap -e 'pointer = 1 3 2'. This will make your right button be #2, and a chord #3. I have a few 3 button mice lying around so you can always ask me to mail you one. ;-) The Makefiles may cause problems with non-GNU or out-of-date versions of make. If you have problems, try upgrading first, or just substituting `gmake' for `make'. Acknowledgements ====================================================================== In case this sounds familiar, it is. This project would have been nearly impossible without the greatly appreciated work of David Hogan on 9wm, which I based my design on. I can't thank him enough. > The latest version of 9wm is held at ftp://ftp.cs.su.oz.au/dhog/9wm. > 9wm was written by David Hogan (dhog@cs.su.oz.au), a postgraduate > student at the Basser Department of Computer Science, University of > Sydney (http://www.cs.su.oz.au/basser_home.html). Thanks to Christophe Tronche for HTML-ifying the ICCCM and other essential X documentation (http://www.tronche.com/gui/x/). Adam Sampson wrote the initial code for MWM hints and menu-ified goodies. License - Below is the license aewm is under. I have gotten permission from Decklin to release my changes under the GNU GPL. ====================================================================== Copyright (c) 1998-2001 Decklin Foster. THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS", WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES OF ANY KIND. IN NO EVENT SHALL THE AUTHOR BE HELD LIABLE FOR ANY DAMAGES CONNECTED WITH THE USE OF THIS PROGRAM. You are granted permission to copy, publish, distribute, and/or sell copies of this program and any modified versions or derived works, provided that this copyright and notice are not removed or altered. Portions of the code were based on 9wm, which contains this license: > 9wm is free software, and is Copyright (c) 1994 by David Hogan. > Permission is granted to all sentient beings to use this software, > to make copies of it, and to distribute those copies, provided > that: > > (1) the copyright and licence notices are left intact > (2) the recipients are aware that it is free software > (3) any unapproved changes in functionality are either > (i) only distributed as patches > or (ii) distributed as a new program which is not called 9wm > and whose documentation gives credit where it is due > (4) the author is not held responsible for any defects > or shortcomings in the software, or damages caused by it. > > There is no warranty for this software. Have a nice day. Author ====================================================================== aewm is maintained by Decklin Foster . If you have bug reports, comments, flames, want permission to change the license, or are just bored, send me email. Your messages are appreciated (but do read the thing above about virtual desktops ;-). pekwm-release-0.1.18/acinclude.m4000066400000000000000000001337541374756504400165670ustar00rootroot00000000000000# lib-ld.m4 serial 3 (gettext-0.13) dnl Copyright (C) 1996-2003 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl Subroutines of libtool.m4, dnl with replacements s/AC_/AC_LIB/ and s/lt_cv/acl_cv/ to avoid collision dnl with libtool.m4. dnl From libtool-1.4. Sets the variable with_gnu_ld to yes or no. AC_DEFUN([AC_LIB_PROG_LD_GNU], [AC_CACHE_CHECK([if the linker ($LD) is GNU ld], acl_cv_prog_gnu_ld, [# I'd rather use --version here, but apparently some GNU ld's only accept -v. case `$LD -v 2>&1 conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. AC_MSG_CHECKING([for ld used by GCC]) case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [[\\/]* | [A-Za-z]:[\\/]*)] [re_direlt='/[^/][^/]*/\.\./'] # Canonicalize the path of ld ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then AC_MSG_CHECKING([for GNU ld]) else AC_MSG_CHECKING([for non-GNU ld]) fi AC_CACHE_VAL(acl_cv_path_LD, [if test -z "$LD"; then IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" for ac_dir in $PATH; do test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then acl_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some GNU ld's only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$acl_cv_path_LD" -v 2>&1 < /dev/null` in *GNU* | *'with BFD'*) test "$with_gnu_ld" != no && break ;; *) test "$with_gnu_ld" != yes && break ;; esac fi done IFS="$ac_save_ifs" else acl_cv_path_LD="$LD" # Let the user override the test with a path. fi]) LD="$acl_cv_path_LD" if test -n "$LD"; then AC_MSG_RESULT($LD) else AC_MSG_RESULT(no) fi test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH]) AC_LIB_PROG_LD_GNU ]) # lib-prefix.m4 serial 5 (gettext-0.15) dnl Copyright (C) 2001-2005 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. dnl AC_LIB_ARG_WITH is synonymous to AC_ARG_WITH in autoconf-2.13, and dnl similar to AC_ARG_WITH in autoconf 2.52...2.57 except that is doesn't dnl require excessive bracketing. ifdef([AC_HELP_STRING], [AC_DEFUN([AC_LIB_ARG_WITH], [AC_ARG_WITH([$1],[[$2]],[$3],[$4])])], [AC_DEFUN([AC_][LIB_ARG_WITH], [AC_ARG_WITH([$1],[$2],[$3],[$4])])]) dnl AC_LIB_PREFIX adds to the CPPFLAGS and LDFLAGS the flags that are needed dnl to access previously installed libraries. The basic assumption is that dnl a user will want packages to use other packages he previously installed dnl with the same --prefix option. dnl This macro is not needed if only AC_LIB_LINKFLAGS is used to locate dnl libraries, but is otherwise very convenient. AC_DEFUN([AC_LIB_PREFIX], [ AC_BEFORE([$0], [AC_LIB_LINKFLAGS]) AC_REQUIRE([AC_PROG_CC]) AC_REQUIRE([AC_CANONICAL_HOST]) AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) dnl By default, look in $includedir and $libdir. use_additional=yes AC_LIB_WITH_FINAL_PREFIX([ eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" ]) AC_LIB_ARG_WITH([lib-prefix], [ --with-lib-prefix[=DIR] search for libraries in DIR/include and DIR/lib --without-lib-prefix don't search for libraries in includedir and libdir], [ if test "X$withval" = "Xno"; then use_additional=no else if test "X$withval" = "X"; then AC_LIB_WITH_FINAL_PREFIX([ eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" ]) else additional_includedir="$withval/include" additional_libdir="$withval/$acl_libdirstem" fi fi ]) if test $use_additional = yes; then dnl Potentially add $additional_includedir to $CPPFLAGS. dnl But don't add it dnl 1. if it's the standard /usr/include, dnl 2. if it's already present in $CPPFLAGS, dnl 3. if it's /usr/local/include and we are using GCC on Linux, dnl 4. if it doesn't exist as a directory. if test "X$additional_includedir" != "X/usr/include"; then haveit= for x in $CPPFLAGS; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-I$additional_includedir"; then haveit=yes break fi done if test -z "$haveit"; then if test "X$additional_includedir" = "X/usr/local/include"; then if test -n "$GCC"; then case $host_os in linux* | gnu* | k*bsd*-gnu) haveit=yes;; esac fi fi if test -z "$haveit"; then if test -d "$additional_includedir"; then dnl Really add $additional_includedir to $CPPFLAGS. CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }-I$additional_includedir" fi fi fi fi dnl Potentially add $additional_libdir to $LDFLAGS. dnl But don't add it dnl 1. if it's the standard /usr/lib, dnl 2. if it's already present in $LDFLAGS, dnl 3. if it's /usr/local/lib and we are using GCC on Linux, dnl 4. if it doesn't exist as a directory. if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then haveit= for x in $LDFLAGS; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then if test -n "$GCC"; then case $host_os in linux*) haveit=yes;; esac fi fi if test -z "$haveit"; then if test -d "$additional_libdir"; then dnl Really add $additional_libdir to $LDFLAGS. LDFLAGS="${LDFLAGS}${LDFLAGS:+ }-L$additional_libdir" fi fi fi fi fi ]) dnl AC_LIB_PREPARE_PREFIX creates variables acl_final_prefix, dnl acl_final_exec_prefix, containing the values to which $prefix and dnl $exec_prefix will expand at the end of the configure script. AC_DEFUN([AC_LIB_PREPARE_PREFIX], [ dnl Unfortunately, prefix and exec_prefix get only finally determined dnl at the end of configure. if test "X$prefix" = "XNONE"; then acl_final_prefix="$ac_default_prefix" else acl_final_prefix="$prefix" fi if test "X$exec_prefix" = "XNONE"; then acl_final_exec_prefix='${prefix}' else acl_final_exec_prefix="$exec_prefix" fi acl_save_prefix="$prefix" prefix="$acl_final_prefix" eval acl_final_exec_prefix=\"$acl_final_exec_prefix\" prefix="$acl_save_prefix" ]) dnl AC_LIB_WITH_FINAL_PREFIX([statement]) evaluates statement, with the dnl variables prefix and exec_prefix bound to the values they will have dnl at the end of the configure script. AC_DEFUN([AC_LIB_WITH_FINAL_PREFIX], [ acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" $1 exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" ]) dnl AC_LIB_PREPARE_MULTILIB creates a variable acl_libdirstem, containing dnl the basename of the libdir, either "lib" or "lib64". AC_DEFUN([AC_LIB_PREPARE_MULTILIB], [ dnl There is no formal standard regarding lib and lib64. The current dnl practice is that on a system supporting 32-bit and 64-bit instruction dnl sets or ABIs, 64-bit libraries go under $prefix/lib64 and 32-bit dnl libraries go under $prefix/lib. We determine the compiler's default dnl mode by looking at the compiler's library search path. If at least dnl of its elements ends in /lib64 or points to a directory whose absolute dnl pathname ends in /lib64, we assume a 64-bit ABI. Otherwise we use the dnl default, namely "lib". acl_libdirstem=lib searchpath=`(LC_ALL=C $CC -print-search-dirs) 2>/dev/null | sed -n -e 's,^libraries: ,,p' | sed -e 's,^=,,'` if test -n "$searchpath"; then acl_save_IFS="${IFS= }"; IFS=":" for searchdir in $searchpath; do if test -d "$searchdir"; then case "$searchdir" in */lib64/ | */lib64 ) acl_libdirstem=lib64 ;; *) searchdir=`cd "$searchdir" && pwd` case "$searchdir" in */lib64 ) acl_libdirstem=lib64 ;; esac ;; esac fi done IFS="$acl_save_IFS" fi ]) # lib-link.m4 serial 13 (gettext-0.17) dnl Copyright (C) 2001-2007 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. AC_PREREQ(2.54) dnl AC_LIB_LINKFLAGS(name [, dependencies]) searches for libname and dnl the libraries corresponding to explicit and implicit dependencies. dnl Sets and AC_SUBSTs the LIB${NAME} and LTLIB${NAME} variables and dnl augments the CPPFLAGS variable. dnl Sets and AC_SUBSTs the LIB${NAME}_PREFIX variable to nonempty if libname dnl was found in ${LIB${NAME}_PREFIX}/$acl_libdirstem. AC_DEFUN([AC_LIB_LINKFLAGS], [ AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) AC_REQUIRE([AC_LIB_RPATH]) define([Name],[translit([$1],[./-], [___])]) define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) AC_CACHE_CHECK([how to link with lib[]$1], [ac_cv_lib[]Name[]_libs], [ AC_LIB_LINKFLAGS_BODY([$1], [$2]) ac_cv_lib[]Name[]_libs="$LIB[]NAME" ac_cv_lib[]Name[]_ltlibs="$LTLIB[]NAME" ac_cv_lib[]Name[]_cppflags="$INC[]NAME" ac_cv_lib[]Name[]_prefix="$LIB[]NAME[]_PREFIX" ]) LIB[]NAME="$ac_cv_lib[]Name[]_libs" LTLIB[]NAME="$ac_cv_lib[]Name[]_ltlibs" INC[]NAME="$ac_cv_lib[]Name[]_cppflags" LIB[]NAME[]_PREFIX="$ac_cv_lib[]Name[]_prefix" AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME) AC_SUBST([LIB]NAME) AC_SUBST([LTLIB]NAME) AC_SUBST([LIB]NAME[_PREFIX]) dnl Also set HAVE_LIB[]NAME so that AC_LIB_HAVE_LINKFLAGS can reuse the dnl results of this search when this library appears as a dependency. HAVE_LIB[]NAME=yes undefine([Name]) undefine([NAME]) ]) dnl AC_LIB_HAVE_LINKFLAGS(name, dependencies, includes, testcode) dnl searches for libname and the libraries corresponding to explicit and dnl implicit dependencies, together with the specified include files and dnl the ability to compile and link the specified testcode. If found, it dnl sets and AC_SUBSTs HAVE_LIB${NAME}=yes and the LIB${NAME} and dnl LTLIB${NAME} variables and augments the CPPFLAGS variable, and dnl #defines HAVE_LIB${NAME} to 1. Otherwise, it sets and AC_SUBSTs dnl HAVE_LIB${NAME}=no and LIB${NAME} and LTLIB${NAME} to empty. dnl Sets and AC_SUBSTs the LIB${NAME}_PREFIX variable to nonempty if libname dnl was found in ${LIB${NAME}_PREFIX}/$acl_libdirstem. AC_DEFUN([AC_LIB_HAVE_LINKFLAGS], [ AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) AC_REQUIRE([AC_LIB_RPATH]) define([Name],[translit([$1],[./-], [___])]) define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) dnl Search for lib[]Name and define LIB[]NAME, LTLIB[]NAME and INC[]NAME dnl accordingly. AC_LIB_LINKFLAGS_BODY([$1], [$2]) dnl Add $INC[]NAME to CPPFLAGS before performing the following checks, dnl because if the user has installed lib[]Name and not disabled its use dnl via --without-lib[]Name-prefix, he wants to use it. ac_save_CPPFLAGS="$CPPFLAGS" AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME) AC_CACHE_CHECK([for lib[]$1], [ac_cv_lib[]Name], [ ac_save_LIBS="$LIBS" LIBS="$LIBS $LIB[]NAME" AC_TRY_LINK([$3], [$4], [ac_cv_lib[]Name=yes], [ac_cv_lib[]Name=no]) LIBS="$ac_save_LIBS" ]) if test "$ac_cv_lib[]Name" = yes; then HAVE_LIB[]NAME=yes AC_DEFINE([HAVE_LIB]NAME, 1, [Define if you have the $1 library.]) AC_MSG_CHECKING([how to link with lib[]$1]) AC_MSG_RESULT([$LIB[]NAME]) else HAVE_LIB[]NAME=no dnl If $LIB[]NAME didn't lead to a usable library, we don't need dnl $INC[]NAME either. CPPFLAGS="$ac_save_CPPFLAGS" LIB[]NAME= LTLIB[]NAME= LIB[]NAME[]_PREFIX= fi AC_SUBST([HAVE_LIB]NAME) AC_SUBST([LIB]NAME) AC_SUBST([LTLIB]NAME) AC_SUBST([LIB]NAME[_PREFIX]) undefine([Name]) undefine([NAME]) ]) dnl Determine the platform dependent parameters needed to use rpath: dnl acl_libext, dnl acl_shlibext, dnl acl_hardcode_libdir_flag_spec, dnl acl_hardcode_libdir_separator, dnl acl_hardcode_direct, dnl acl_hardcode_minus_L. AC_DEFUN([AC_LIB_RPATH], [ dnl Tell automake >= 1.10 to complain if config.rpath is missing. m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([config.rpath])]) AC_REQUIRE([AC_PROG_CC]) dnl we use $CC, $GCC, $LDFLAGS AC_REQUIRE([AC_LIB_PROG_LD]) dnl we use $LD, $with_gnu_ld AC_REQUIRE([AC_CANONICAL_HOST]) dnl we use $host AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT]) dnl we use $ac_aux_dir AC_CACHE_CHECK([for shared library run path origin], acl_cv_rpath, [ CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \ ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh . ./conftest.sh rm -f ./conftest.sh acl_cv_rpath=done ]) wl="$acl_cv_wl" acl_libext="$acl_cv_libext" acl_shlibext="$acl_cv_shlibext" acl_libname_spec="$acl_cv_libname_spec" acl_library_names_spec="$acl_cv_library_names_spec" acl_hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec" acl_hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator" acl_hardcode_direct="$acl_cv_hardcode_direct" acl_hardcode_minus_L="$acl_cv_hardcode_minus_L" dnl Determine whether the user wants rpath handling at all. AC_ARG_ENABLE(rpath, [ --disable-rpath do not hardcode runtime library paths], :, enable_rpath=yes) ]) dnl AC_LIB_LINKFLAGS_BODY(name [, dependencies]) searches for libname and dnl the libraries corresponding to explicit and implicit dependencies. dnl Sets the LIB${NAME}, LTLIB${NAME} and INC${NAME} variables. dnl Also, sets the LIB${NAME}_PREFIX variable to nonempty if libname was found dnl in ${LIB${NAME}_PREFIX}/$acl_libdirstem. AC_DEFUN([AC_LIB_LINKFLAGS_BODY], [ AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) dnl Autoconf >= 2.61 supports dots in --with options. define([N_A_M_E],[m4_if(m4_version_compare(m4_defn([m4_PACKAGE_VERSION]),[2.61]),[-1],[translit([$1],[.],[_])],[$1])]) dnl By default, look in $includedir and $libdir. use_additional=yes AC_LIB_WITH_FINAL_PREFIX([ eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" ]) AC_LIB_ARG_WITH([lib]N_A_M_E[-prefix], [ --with-lib]N_A_M_E[-prefix[=DIR] search for lib$1 in DIR/include and DIR/lib --without-lib]N_A_M_E[-prefix don't search for lib$1 in includedir and libdir], [ if test "X$withval" = "Xno"; then use_additional=no else if test "X$withval" = "X"; then AC_LIB_WITH_FINAL_PREFIX([ eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" ]) else additional_includedir="$withval/include" additional_libdir="$withval/$acl_libdirstem" fi fi ]) dnl Search the library and its dependencies in $additional_libdir and dnl $LDFLAGS. Using breadth-first-seach. LIB[]NAME= LTLIB[]NAME= INC[]NAME= LIB[]NAME[]_PREFIX= rpathdirs= ltrpathdirs= names_already_handled= names_next_round='$1 $2' while test -n "$names_next_round"; do names_this_round="$names_next_round" names_next_round= for name in $names_this_round; do already_handled= for n in $names_already_handled; do if test "$n" = "$name"; then already_handled=yes break fi done if test -z "$already_handled"; then names_already_handled="$names_already_handled $name" dnl See if it was already located by an earlier AC_LIB_LINKFLAGS dnl or AC_LIB_HAVE_LINKFLAGS call. uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'` eval value=\"\$HAVE_LIB$uppername\" if test -n "$value"; then if test "$value" = yes; then eval value=\"\$LIB$uppername\" test -z "$value" || LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$value" eval value=\"\$LTLIB$uppername\" test -z "$value" || LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$value" else dnl An earlier call to AC_LIB_HAVE_LINKFLAGS has determined dnl that this library doesn't exist. So just drop it. : fi else dnl Search the library lib$name in $additional_libdir and $LDFLAGS dnl and the already constructed $LIBNAME/$LTLIBNAME. found_dir= found_la= found_so= found_a= eval libname=\"$acl_libname_spec\" # typically: libname=lib$name if test -n "$acl_shlibext"; then shrext=".$acl_shlibext" # typically: shrext=.so else shrext= fi if test $use_additional = yes; then dir="$additional_libdir" dnl The same code as in the loop below: dnl First look for a shared library. if test -n "$acl_shlibext"; then if test -f "$dir/$libname$shrext"; then found_dir="$dir" found_so="$dir/$libname$shrext" else if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then ver=`(cd "$dir" && \ for f in "$libname$shrext".*; do echo "$f"; done \ | sed -e "s,^$libname$shrext\\\\.,," \ | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ | sed 1q ) 2>/dev/null` if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then found_dir="$dir" found_so="$dir/$libname$shrext.$ver" fi else eval library_names=\"$acl_library_names_spec\" for f in $library_names; do if test -f "$dir/$f"; then found_dir="$dir" found_so="$dir/$f" break fi done fi fi fi dnl Then look for a static library. if test "X$found_dir" = "X"; then if test -f "$dir/$libname.$acl_libext"; then found_dir="$dir" found_a="$dir/$libname.$acl_libext" fi fi if test "X$found_dir" != "X"; then if test -f "$dir/$libname.la"; then found_la="$dir/$libname.la" fi fi fi if test "X$found_dir" = "X"; then for x in $LDFLAGS $LTLIB[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) case "$x" in -L*) dir=`echo "X$x" | sed -e 's/^X-L//'` dnl First look for a shared library. if test -n "$acl_shlibext"; then if test -f "$dir/$libname$shrext"; then found_dir="$dir" found_so="$dir/$libname$shrext" else if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then ver=`(cd "$dir" && \ for f in "$libname$shrext".*; do echo "$f"; done \ | sed -e "s,^$libname$shrext\\\\.,," \ | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ | sed 1q ) 2>/dev/null` if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then found_dir="$dir" found_so="$dir/$libname$shrext.$ver" fi else eval library_names=\"$acl_library_names_spec\" for f in $library_names; do if test -f "$dir/$f"; then found_dir="$dir" found_so="$dir/$f" break fi done fi fi fi dnl Then look for a static library. if test "X$found_dir" = "X"; then if test -f "$dir/$libname.$acl_libext"; then found_dir="$dir" found_a="$dir/$libname.$acl_libext" fi fi if test "X$found_dir" != "X"; then if test -f "$dir/$libname.la"; then found_la="$dir/$libname.la" fi fi ;; esac if test "X$found_dir" != "X"; then break fi done fi if test "X$found_dir" != "X"; then dnl Found the library. LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$found_dir -l$name" if test "X$found_so" != "X"; then dnl Linking with a shared library. We attempt to hardcode its dnl directory into the executable's runpath, unless it's the dnl standard /usr/lib. if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/$acl_libdirstem"; then dnl No hardcoding is needed. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" else dnl Use an explicit option to hardcode DIR into the resulting dnl binary. dnl Potentially add DIR to ltrpathdirs. dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. haveit= for x in $ltrpathdirs; do if test "X$x" = "X$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then ltrpathdirs="$ltrpathdirs $found_dir" fi dnl The hardcoding into $LIBNAME is system dependent. if test "$acl_hardcode_direct" = yes; then dnl Using DIR/libNAME.so during linking hardcodes DIR into the dnl resulting binary. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" else if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then dnl Use an explicit option to hardcode DIR into the resulting dnl binary. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" dnl Potentially add DIR to rpathdirs. dnl The rpathdirs will be appended to $LIBNAME at the end. haveit= for x in $rpathdirs; do if test "X$x" = "X$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then rpathdirs="$rpathdirs $found_dir" fi else dnl Rely on "-L$found_dir". dnl But don't add it if it's already contained in the LDFLAGS dnl or the already constructed $LIBNAME haveit= for x in $LDFLAGS $LIB[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-L$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir" fi if test "$acl_hardcode_minus_L" != no; then dnl FIXME: Not sure whether we should use dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" dnl here. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" else dnl We cannot use $acl_hardcode_runpath_var and LD_RUN_PATH dnl here, because this doesn't fit in flags passed to the dnl compiler. So give up. No hardcoding. This affects only dnl very old systems. dnl FIXME: Not sure whether we should use dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" dnl here. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" fi fi fi fi else if test "X$found_a" != "X"; then dnl Linking with a static library. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_a" else dnl We shouldn't come here, but anyway it's good to have a dnl fallback. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir -l$name" fi fi dnl Assume the include files are nearby. additional_includedir= case "$found_dir" in */$acl_libdirstem | */$acl_libdirstem/) basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'` LIB[]NAME[]_PREFIX="$basedir" additional_includedir="$basedir/include" ;; esac if test "X$additional_includedir" != "X"; then dnl Potentially add $additional_includedir to $INCNAME. dnl But don't add it dnl 1. if it's the standard /usr/include, dnl 2. if it's /usr/local/include and we are using GCC on Linux, dnl 3. if it's already present in $CPPFLAGS or the already dnl constructed $INCNAME, dnl 4. if it doesn't exist as a directory. if test "X$additional_includedir" != "X/usr/include"; then haveit= if test "X$additional_includedir" = "X/usr/local/include"; then if test -n "$GCC"; then case $host_os in linux* | gnu* | k*bsd*-gnu) haveit=yes;; esac fi fi if test -z "$haveit"; then for x in $CPPFLAGS $INC[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-I$additional_includedir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_includedir"; then dnl Really add $additional_includedir to $INCNAME. INC[]NAME="${INC[]NAME}${INC[]NAME:+ }-I$additional_includedir" fi fi fi fi fi dnl Look for dependencies. if test -n "$found_la"; then dnl Read the .la file. It defines the variables dnl dlname, library_names, old_library, dependency_libs, current, dnl age, revision, installed, dlopen, dlpreopen, libdir. save_libdir="$libdir" case "$found_la" in */* | *\\*) . "$found_la" ;; *) . "./$found_la" ;; esac libdir="$save_libdir" dnl We use only dependency_libs. for dep in $dependency_libs; do case "$dep" in -L*) additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` dnl Potentially add $additional_libdir to $LIBNAME and $LTLIBNAME. dnl But don't add it dnl 1. if it's the standard /usr/lib, dnl 2. if it's /usr/local/lib and we are using GCC on Linux, dnl 3. if it's already present in $LDFLAGS or the already dnl constructed $LIBNAME, dnl 4. if it doesn't exist as a directory. if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then haveit= if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then if test -n "$GCC"; then case $host_os in linux* | gnu* | k*bsd*-gnu) haveit=yes;; esac fi fi if test -z "$haveit"; then haveit= for x in $LDFLAGS $LIB[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_libdir"; then dnl Really add $additional_libdir to $LIBNAME. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$additional_libdir" fi fi haveit= for x in $LDFLAGS $LTLIB[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_libdir"; then dnl Really add $additional_libdir to $LTLIBNAME. LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$additional_libdir" fi fi fi fi ;; -R*) dir=`echo "X$dep" | sed -e 's/^X-R//'` if test "$enable_rpath" != no; then dnl Potentially add DIR to rpathdirs. dnl The rpathdirs will be appended to $LIBNAME at the end. haveit= for x in $rpathdirs; do if test "X$x" = "X$dir"; then haveit=yes break fi done if test -z "$haveit"; then rpathdirs="$rpathdirs $dir" fi dnl Potentially add DIR to ltrpathdirs. dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. haveit= for x in $ltrpathdirs; do if test "X$x" = "X$dir"; then haveit=yes break fi done if test -z "$haveit"; then ltrpathdirs="$ltrpathdirs $dir" fi fi ;; -l*) dnl Handle this in the next round. names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` ;; *.la) dnl Handle this in the next round. Throw away the .la's dnl directory; it is already contained in a preceding -L dnl option. names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` ;; *) dnl Most likely an immediate library name. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$dep" LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$dep" ;; esac done fi else dnl Didn't find the library; assume it is in the system directories dnl known to the linker and runtime loader. (All the system dnl directories known to the linker should also be known to the dnl runtime loader, otherwise the system is severely misconfigured.) LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-l$name" fi fi fi done done if test "X$rpathdirs" != "X"; then if test -n "$acl_hardcode_libdir_separator"; then dnl Weird platform: only the last -rpath option counts, the user must dnl pass all path elements in one option. We can arrange that for a dnl single library, but not when more than one $LIBNAMEs are used. alldirs= for found_dir in $rpathdirs; do alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$found_dir" done dnl Note: acl_hardcode_libdir_flag_spec uses $libdir and $wl. acl_save_libdir="$libdir" libdir="$alldirs" eval flag=\"$acl_hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" else dnl The -rpath options are cumulative. for found_dir in $rpathdirs; do acl_save_libdir="$libdir" libdir="$found_dir" eval flag=\"$acl_hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" done fi fi if test "X$ltrpathdirs" != "X"; then dnl When using libtool, the option that works for both libraries and dnl executables is -R. The -R options are cumulative. for found_dir in $ltrpathdirs; do LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-R$found_dir" done fi ]) dnl AC_LIB_APPENDTOVAR(VAR, CONTENTS) appends the elements of CONTENTS to VAR, dnl unless already present in VAR. dnl Works only for CPPFLAGS, not for LIB* variables because that sometimes dnl contains two or three consecutive elements that belong together. AC_DEFUN([AC_LIB_APPENDTOVAR], [ for element in [$2]; do haveit= for x in $[$1]; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X$element"; then haveit=yes break fi done if test -z "$haveit"; then [$1]="${[$1]}${[$1]:+ }$element" fi done ]) dnl For those cases where a variable contains several -L and -l options dnl referring to unknown libraries and directories, this macro determines the dnl necessary additional linker options for the runtime path. dnl AC_LIB_LINKFLAGS_FROM_LIBS([LDADDVAR], [LIBSVALUE], [USE-LIBTOOL]) dnl sets LDADDVAR to linker options needed together with LIBSVALUE. dnl If USE-LIBTOOL evaluates to non-empty, linking with libtool is assumed, dnl otherwise linking without libtool is assumed. AC_DEFUN([AC_LIB_LINKFLAGS_FROM_LIBS], [ AC_REQUIRE([AC_LIB_RPATH]) AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) $1= if test "$enable_rpath" != no; then if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then dnl Use an explicit option to hardcode directories into the resulting dnl binary. rpathdirs= next= for opt in $2; do if test -n "$next"; then dir="$next" dnl No need to hardcode the standard /usr/lib. if test "X$dir" != "X/usr/$acl_libdirstem"; then rpathdirs="$rpathdirs $dir" fi next= else case $opt in -L) next=yes ;; -L*) dir=`echo "X$opt" | sed -e 's,^X-L,,'` dnl No need to hardcode the standard /usr/lib. if test "X$dir" != "X/usr/$acl_libdirstem"; then rpathdirs="$rpathdirs $dir" fi next= ;; *) next= ;; esac fi done if test "X$rpathdirs" != "X"; then if test -n ""$3""; then dnl libtool is used for linking. Use -R options. for dir in $rpathdirs; do $1="${$1}${$1:+ }-R$dir" done else dnl The linker is used for linking directly. if test -n "$acl_hardcode_libdir_separator"; then dnl Weird platform: only the last -rpath option counts, the user dnl must pass all path elements in one option. alldirs= for dir in $rpathdirs; do alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$dir" done acl_save_libdir="$libdir" libdir="$alldirs" eval flag=\"$acl_hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" $1="$flag" else dnl The -rpath options are cumulative. for dir in $rpathdirs; do acl_save_libdir="$libdir" libdir="$dir" eval flag=\"$acl_hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" $1="${$1}${$1:+ }$flag" done fi fi fi fi fi AC_SUBST([$1]) ]) # PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], # [ACTION-IF-NOT-FOUND]) # # # Note that if there is a possibility the first call to # PKG_CHECK_MODULES might not happen, you should be sure to include an # explicit call to PKG_PROG_PKG_CONFIG in your configure.ac # # # -------------------------------------------------------------- AC_DEFUN([PKG_CHECK_MODULES], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl pkg_failed=no AC_MSG_CHECKING([for $1]) _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) _PKG_CONFIG([$1][_LIBS], [libs], [$2]) m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS and $1[]_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details.]) if test $pkg_failed = yes; then _PKG_SHORT_ERRORS_SUPPORTED if test $_pkg_short_errors_supported = yes; then $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "$2"` else $1[]_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"` fi # Put the nasty error message in config.log where it belongs echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD ifelse([$4], , [AC_MSG_ERROR(dnl [Package requirements ($2) were not met: $$1_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. _PKG_TEXT ])], [AC_MSG_RESULT([no]) $4]) elif test $pkg_failed = untried; then ifelse([$4], , [AC_MSG_FAILURE(dnl [The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. _PKG_TEXT To get pkg-config, see .])], [$4]) else $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS $1[]_LIBS=$pkg_cv_[]$1[]_LIBS AC_MSG_RESULT([yes]) ifelse([$3], , :, [$3]) fi[]dnl ])# PKG_CHECK_MODULES # pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- # # Copyright © 2004 Scott James Remnant . # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # PKG_PROG_PKG_CONFIG([MIN-VERSION]) # ---------------------------------- AC_DEFUN([PKG_PROG_PKG_CONFIG], [m4_pattern_forbid([^_?PKG_[A-Z_]+$]) m4_pattern_allow([^PKG_CONFIG(_PATH)?$]) AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])dnl if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) fi if test -n "$PKG_CONFIG"; then _pkg_min_version=m4_default([$1], [0.9.0]) AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) PKG_CONFIG="" fi fi[]dnl ])# PKG_PROG_PKG_CONFIG # PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) # # Check to see whether a particular set of modules exists. Similar # to PKG_CHECK_MODULES(), but does not set variables or print errors. # # # Similar to PKG_CHECK_MODULES, make sure that the first instance of # this or PKG_CHECK_MODULES is called, or make sure to call # PKG_CHECK_EXISTS manually # -------------------------------------------------------------- AC_DEFUN([PKG_CHECK_EXISTS], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl if test -n "$PKG_CONFIG" && \ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then m4_ifval([$2], [$2], [:]) m4_ifvaln([$3], [else $3])dnl fi]) # _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) # --------------------------------------------- m4_define([_PKG_CONFIG], [if test -n "$$1"; then pkg_cv_[]$1="$$1" elif test -n "$PKG_CONFIG"; then PKG_CHECK_EXISTS([$3], [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`], [pkg_failed=yes]) else pkg_failed=untried fi[]dnl ])# _PKG_CONFIG # _PKG_SHORT_ERRORS_SUPPORTED # ----------------------------- AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], [AC_REQUIRE([PKG_PROG_PKG_CONFIG]) if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi[]dnl ])# _PKG_SHORT_ERRORS_SUPPORTED # PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], # [ACTION-IF-NOT-FOUND]) # # # Note that if there is a possibility the first call to # PKG_CHECK_MODULES might not happen, you should be sure to include an # explicit call to PKG_PROG_PKG_CONFIG in your configure.ac # # # -------------------------------------------------------------- AC_DEFUN([PKG_CHECK_MODULES], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl pkg_failed=no AC_MSG_CHECKING([for $1]) _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) _PKG_CONFIG([$1][_LIBS], [libs], [$2]) m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS and $1[]_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details.]) if test $pkg_failed = yes; then _PKG_SHORT_ERRORS_SUPPORTED if test $_pkg_short_errors_supported = yes; then $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "$2" 2>&1` else $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors "$2" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD ifelse([$4], , [AC_MSG_ERROR(dnl [Package requirements ($2) were not met: $$1_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. _PKG_TEXT ])], [AC_MSG_RESULT([no]) $4]) elif test $pkg_failed = untried; then ifelse([$4], , [AC_MSG_FAILURE(dnl [The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. _PKG_TEXT To get pkg-config, see .])], [$4]) else $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS $1[]_LIBS=$pkg_cv_[]$1[]_LIBS AC_MSG_RESULT([yes]) ifelse([$3], , :, [$3]) fi[]dnl ])# PKG_CHECK_MODULES pekwm-release-0.1.18/autogen.sh000077500000000000000000000020751374756504400163660ustar00rootroot00000000000000#!/bin/sh # # As which and whereis behave different on various platforms, a simple # shell routine searching the split PATH is used instead. # Do this outside the routine for effiency PATH_SPLIT=`echo $PATH | awk -F ':' '{ for (i = 1; i < NF; i++) print $i}'` # Search for command in PATH_SPLIT, sets command_found find_command() { command_found='' for dir in $PATH_SPLIT; do if [ -x "$dir/$1" ]; then command_found="$dir/$1" break fi done } # Search fod command, print $1 and run command with arg find_fallback_and_execute() { find_command "$2" if [ -z "$command_found" ]; then command_found="$3" fi printf " $1" $command_found $4 } # Begin output echo "Generating build scripts, this might take a while." find_fallback_and_execute "aclocal" "aclocal" "aclocal-1.11" "-I m4" find_fallback_and_execute "autoheader" "autoheader" "autoheader-2.68" "" find_fallback_and_execute "autoconf" "autoconf" "autoconf-2.68" "" find_fallback_and_execute "automake" "automake" "automake-1.11" "-a" # End output echo "" echo "Done generating build scripts." pekwm-release-0.1.18/config.rpath000066400000000000000000000000001374756504400166540ustar00rootroot00000000000000pekwm-release-0.1.18/configure.ac000066400000000000000000000221641374756504400166540ustar00rootroot00000000000000m4_pattern_allow(AM_CONFIG_HEADERS) dnl init autotools AC_INIT(pekwm, 0.1.18) AC_CONFIG_SRCDIR(src/main.cc) AM_INIT_AUTOMAKE AC_CONFIG_HEADERS(config.h) dnl Check for programs AC_PROG_CXX AC_PROG_INSTALL AC_PROG_SED PKG_PROG_PKG_CONFIG AC_LANG([C++]) AX_CXX_COMPILE_STDCXX_11([noext],[mandatory]) dnl Check for /usr/xpg4/bin/sh and use that in scripts if it does dnl exist, Solaris /bin/sh does feel like behaving with the standard dnl scripts it seems. AC_CHECK_PROG([SH], [sh], [/usr/xpg4/bin/sh], [/bin/sh], [/usr/xpg4/bin]) dnl Check for iconv AM_ICONV if test "x$am_cv_func_iconv" != "xyes"; then AC_MSG_ERROR([Could not find iconv.]) fi LIBS="$LIBS $LIBICONV" CXXFLAGS="$CXXFLAGS $INCICONV" dnl Check for iconvctl AC_CHECK_FUNC(iconvctl, [AC_DEFINE(HAVE_ICONVCTL, [1], [Define to 1 if you the iconvctl call])], ) dnl add x11 to the env AC_PATH_X AC_PATH_XTRA CXXFLAGS="$CXXFLAGS $X_CFLAGS" LIBS="$LIBS $X_LIBS" LDFLAGS="$LDFLAGS $LIBS $X_PRE_LIBS" dnl Check for libraries AC_CHECK_LIB(X11, XOpenDisplay, LIBS="$LIBS -lX11", AC_MSG_ERROR([Could not find XOpenDisplay in -lX11.]) ) dnl Check for XShape extension support and proper library files enableval="yes" AC_MSG_CHECKING([whether to build support for the XShape extension]) AC_ARG_ENABLE(shape, AC_HELP_STRING([--enable-shape], [enable support of the XShape extension [default=yes]]), , [enableval=yes]) if test "x$enableval" = "xyes"; then AC_MSG_RESULT([yes]) AC_CHECK_LIB(Xext, XShapeCombineShape, AC_MSG_CHECKING([for X11/extensions/shape.h]) AC_TRY_COMPILE( #include #include #include , long foo = ShapeSet, AC_MSG_RESULT([yes]) AC_DEFINE(HAVE_SHAPE, [1], [Define to 1 if you have an XShape capable server]) LIBS="$LIBS -lXext" FEATURES="$FEATURES XShape", AC_MSG_RESULT([no]))) else AC_MSG_RESULT([no]) CONFIGOPTS="$CONFIGOPTS --disable-shape" fi dnl Check for Xinerama support AC_MSG_CHECKING([whether to build support for the Xinerama extension]) AC_ARG_ENABLE(xinerama, AC_HELP_STRING([--enable-xinerama], [enable xinerama extension [default=yes]]), , [enable_xinerama=yes]) if test "x$enable_xinerama" = "xyes"; then AC_MSG_RESULT([yes]) AC_CHECK_LIB(Xinerama, XineramaQueryScreens, AC_DEFINE(HAVE_XINERAMA, [1], [Define to 1 if you want Xinerama support to be]) LIBS="$LIBS -lXinerama" FEATURES="$FEATURES Xinerama") else AC_MSG_RESULT([no]) fi dnl Check for Xft support AC_MSG_CHECKING([whether to support Xft fonts]) AC_ARG_ENABLE(xft, AC_HELP_STRING([--enable-xft], [enable Xft font support [default=yes]]), , [enable_xft=yes]) if test "x$enable_xft" = "xyes"; then AC_MSG_RESULT([yes]) PKG_CHECK_MODULES([xft], [xft >= 2.0.0], HAVE_XFT=yes, HAVE_XFT=no) if test "x$HAVE_XFT" = "xyes" then AC_DEFINE(HAVE_XFT, [1], [Define to 1 if you want Xft2 font support]) LIBS="$LIBS $xft_LIBS" CXXFLAGS="$CXXFLAGS $xft_CFLAGS" FEATURES="$FEATURES Xft"; else AC_MSG_WARN([Couldn't find Xft >= 2.0.0]) fi else AC_MSG_RESULT([no]) fi dnl Check for PNG support AC_MSG_CHECKING([wheter to build support for PNG images]) AC_ARG_ENABLE(image-png, AC_HELP_STRING([--enable-image-png], [enable support for PNG images [default=yes]]), , [enable_image_png=yes]) if test "x$enable_image_png" = "xyes"; then AC_MSG_RESULT([yes]) PKG_CHECK_MODULES([libpng12], [libpng12 >= 1.2.0], HAVE_LIBPNG=yes, HAVE_LIBPNG=no) if test "x$HAVE_LIBPNG" = "xyes"; then AC_DEFINE(HAVE_IMAGE_PNG, [1], [Define to 1 if you have libpng12]) LIBS="$LIBS $libpng12_LIBS" CXXFLAGS="$CXXFLAGS $libpng12_CFLAGS" FEATURES="$FEATURES image-png" else PKG_CHECK_MODULES([libpng], [libpng >= 1.0.0], HAVE_LIBPNG=yes, HAVE_LIBPNG=no) if test "x$HAVE_LIBPNG" = "xyes"; then AC_DEFINE(HAVE_IMAGE_PNG, [1], [Define to 1 if you have libpng12]) LIBS="$LIBS $libpng_LIBS" CXXFLAGS="$CXXFLAGS $libpng_CFLAGS" FEATURES="$FEATURES image-png" else AC_MSG_RESULT([no]) fi fi else AC_MSG_RESULT([no]) fi dnl Check for default theme if test "x$HAVE_LIBPNG" = "xyes"; then THEME="default" else AC_MSG_ERROR([Could not find libpng.]) fi AC_SUBST([THEME]) dnl Check for JPEG support AC_MSG_CHECKING([wheter to build support for JPEG images]) AC_ARG_ENABLE(image-jpeg, AC_HELP_STRING([--enable-image-jpeg], [enable support for JPEG images [default=yes]]), , [enableval=yes]) if test "x$enableval" = "xyes"; then AC_MSG_RESULT([yes]) AC_CHECK_LIB(jpeg, jpeg_read_header, AC_MSG_CHECKING([for jpeglib.h]) AC_TRY_CPP([#include ], jpeg_ok=yes, jpeg_ok=no) AC_MSG_RESULT($jpeg_ok) if test "$jpeg_ok" = yes; then AC_DEFINE(HAVE_IMAGE_JPEG, [1], [Define to 1 if you have jpeg6b]) LIBS="$LIBS -ljpeg" FEATURES="$FEATURES image-jpeg" fi, AC_MSG_RESULT([no])) else AC_MSG_RESULT([no]) fi dnl Check for XPM support AC_MSG_CHECKING([wheter to build support XPM images]) AC_ARG_ENABLE(image-xpm, AC_HELP_STRING([--enable-image-xpm], [enable support for XPM images [default=yes]]), , [enableval=yes]) if test "x$enableval" = "xyes"; then AC_MSG_RESULT([yes]) AC_CHECK_LIB(Xpm, XpmReadFileToPixmap, AC_MSG_CHECKING([for X11/xpm.h]) AC_TRY_COMPILE( #include , int foo = XpmSuccess, AC_MSG_RESULT([yes]) AC_DEFINE(HAVE_IMAGE_XPM, [1], [Define to 1 if you libXpm]) LIBS="$LIBS -lXpm" FEATURES="$FEATURES image-xpm", AC_MSG_RESULT([no]))) else AC_MSG_RESULT([no]) fi dnl Check for XRANDR support AC_MSG_CHECKING([wheter to build support for the XRANDR extension]) AC_ARG_ENABLE(xrandr, AC_HELP_STRING([--enable-xrandr], [enable support for the XRANDR extension [default=yes]]), , [enable_xrandr=yes]) if test "x$enable_xrandr" = "xyes"; then AC_MSG_RESULT([yes]) PKG_CHECK_MODULES([xrandr], [xrandr >= 1.2.0], HAVE_XRANDR=yes, HAVE_XRANDR=no) if test "x$HAVE_XRANDR" = "xyes" then AC_DEFINE(HAVE_XRANDR, [1], [Define to 1 if you have an XRANDR capable server]) LIBS="$LIBS $xrandr_LIBS" CXXFLAGS="$CXXFLAGS $xrandr_CFLAGS" FEATURES="$FEATURES Xrandr" else AC_MSG_WARN([Couldn't find Xrandr >= 1.2.0]) fi else AC_MSG_RESULT([no]) fi dnl Check for header files AC_STDC_HEADERS AC_CHECK_HEADERS([limits]) dnl Check for library functions AC_CHECK_FUNC(setenv, [AC_DEFINE(HAVE_SETENV, [1], [Define to 1 if you the setenv systam call])], ) AC_CHECK_FUNC(unsetenv, [AC_DEFINE(HAVE_UNSETENV, [1], [Define to 1 if you the unsetenv systam call])], ) AC_CHECK_FUNC(swprintf, [AC_DEFINE(HAVE_SWPRINTF, [1], [Define to 1 if you have swprintf])], ) dnl Check whether time.h has timersub AC_MSG_CHECKING(for timersub in time.h) AC_LINK_IFELSE( [AC_LANG_PROGRAM([#include ], [struct timeval *a; timersub(a, a, a);])], AC_MSG_RESULT(yes) AC_DEFINE([HAVE_TIMERSUB], 1, [Define to 1 if your system defines timersub.]), AC_MSG_RESULT(no) ) dnl Check for required Xlib headers AC_CHECK_HEADERS([X11/Xutil.h], , AC_MSG_ERROR([Could not find X11/Xutil.h header file])) dnl Check for XkbKeycodeToKeysym replacing XKeycodeToKeysym AC_CHECK_HEADERS([X11/XKBlib.h]) dnl Check simple toggles ( no outer dependecies ) dnl Check whether to include debugging code AC_MSG_CHECKING([whether to include verbose debugging code]) AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug], [include verbose debugging code [default=no]]), , [enable_debug=no]) if test "x$enable_debug" = "xyes"; then AC_MSG_RESULT([yes]) AC_DEFINE(DEBUG, [1], [Define to 1 to compile in debug information]) FEATURES="$FEATURES debug" else AC_MSG_RESULT([no]) fi AM_CONDITIONAL([DEBUG_INFRASTRUCTURE], [test x"$enable_debug" = "xyes"]) dnl Check wheter to use strict warnings AC_MSG_CHECKING([whether to use strict compile-time warnings]) AC_ARG_ENABLE(pedantic, AC_HELP_STRING([--enable-pedantic], [turn on strict compile-time warnings [default=no]]), , [enable_pedantic=no]) if test "$enable_pedantic" = "yes"; then AC_MSG_RESULT([yes]) if test "x$GXX" = "xyes"; then CXXFLAGS="-Wall -Werror -pedantic $CXXFLAGS" fi FEATURES="$FEATURES pedantic" else AC_MSG_RESULT([no]) fi dnl define build info EVO=`date` AC_DEFINE_UNQUOTED(FEATURES, "$FEATURES", [Build info, do not touch]) dnl create the makefiles AC_OUTPUT(Makefile src/Makefile data/Makefile data/themes/Makefile data/themes/default/Makefile data/themes/default-plain/Makefile data/themes/pion/Makefile data/scripts/Makefile doc/Makefile contrib/Makefile contrib/lobo/Makefile CMake/Makefile CMake/Modules/Makefile) dnl print results AC_MSG_RESULT([*]) AC_MSG_RESULT([* $PACKAGE version $VERSION configured successfully.]) AC_MSG_RESULT([*]) AC_MSG_RESULT([* PREFIX: $prefix]) AC_MSG_RESULT([* FEATURES: $FEATURES]) AC_MSG_RESULT([* CXXFLAGS: $CXXFLAGS]) AC_MSG_RESULT([* LIBS: $LIBS]) AC_MSG_RESULT([*]) pekwm-release-0.1.18/contrib/000077500000000000000000000000001374756504400160215ustar00rootroot00000000000000pekwm-release-0.1.18/contrib/CMakeLists.txt000066400000000000000000000000731374756504400205610ustar00rootroot00000000000000cmake_minimum_required(VERSION 2.8) add_subdirectory(lobo)pekwm-release-0.1.18/contrib/Makefile.am000066400000000000000000000001501374756504400200510ustar00rootroot00000000000000AUTOMAKE_OPTIONS = foreign SUBDIRS = lobo EXTRA_DIST = CMakeLists.txt disclean-local: rm -f *\~ .\#* pekwm-release-0.1.18/contrib/lobo/000077500000000000000000000000001374756504400167545ustar00rootroot00000000000000pekwm-release-0.1.18/contrib/lobo/CMakeLists.txt000066400000000000000000000000431374756504400215110ustar00rootroot00000000000000cmake_minimum_required(VERSION 2.8)pekwm-release-0.1.18/contrib/lobo/Makefile.am000066400000000000000000000003011374756504400210020ustar00rootroot00000000000000AUTOMAKE_OPTIONS = foreign EXTRA_DIST = check.png pekwm_autoprop.pl \ pekwm_menu_config.pl.vars uncheck.png \ pekwm_menu_config.pl README \ CMakeLists.txt distclean-local: rm -f *\~ .\#* pekwm-release-0.1.18/contrib/lobo/README000066400000000000000000000035171374756504400176420ustar00rootroot00000000000000Official URL for these scripts is http://nxc.ath.cx/lobo/filez/pekwm/ ****** pekwm scripts ****** ***** pekwm autoprops generator ***** Required files: * pekwm_autoprop.pl If you upgrade to the latest version of pekwm, 0.1.9 and call this script from a pekwm window menu, an autoproperty will be generated for you without having to click the window with the crosshair. This script uses xprop and xwininfo to generate a 'Property' block for the pekwm autoproperties configuration file. Usage: a) If you would like to run this script manually from the console to produce the block, simply run the script with no parameters: ./pekwm_autoprop.pl Upon execution, you will be given a crosshair mouse cursor. This is simply 'xwininfo' prompting you to click your desired window. b) To generate the 'Property' block and write it to your ~/.pekwm/ autoproperties file, run the script with the '-w' switch: ./pekwm_autoprop.pl -w I like to add the following to my pekwm window menu: Submenu = "Autoprops" { Entry = "Save" { Actions = "Exec /home/matt/code/perl/pekwm_autoprop.pl -w" } } ***** pekwm menu config ***** Required files: * pekwm_menu_config.pl * pekwm_menu_config.pl.vars * check.png * uncheck.png Dependencies: * Perl * Zenity This script parses the pekwm config file and creates a dynamic menu showing all configuration options. When you click on an option the script will detect what type of variable is being edited and will pop up a corresponding zenity dialog. The config will then be rewritten and pekwm reloaded to reflect the change. Usage: Add the following to your pekwm menu: Submenu = "Config" { Entry { Actions = "Dynamic /home/matt/code/perl/pekwm_menu_config.pl -- genmenu" } } Also, place check.png and uncheck.png in your icons directory (usually ~/.pekwm/icons). pekwm-release-0.1.18/contrib/lobo/check.png000066400000000000000000000003231374756504400205350ustar00rootroot00000000000000PNG  IHDR PXsRGB pHYs  tIME 3#w&brtEXtCommentCreated with GIMPW@IDATӥQ Cgx==>!׃ۀ6@DJdfSU{GD4{Οϙ? zIENDB`pekwm-release-0.1.18/contrib/lobo/pekwm_autoprop.pl000077500000000000000000000100371374756504400223710ustar00rootroot00000000000000#!/usr/bin/env perl # pekwm_autoprop.pl # Written by: Matt Hayes # # Generates and adds a Property block to ~/.pekwm/autoproperties. # # Add a menu entry or run this script manually. You will notice # that upon running you get a crosshair cursor, use this to click on # the window you want autoproperties generated for. # # Usage: # Only generate: ./pekwm_autoprop.pl # Generate and write: ./pekwm_autoprop.pl -w use strict; use warnings; my ($_pekwm_frame_decor, $_net_wm_state, $_net_wm_desktop, $wm_class, $window_id, $wm_window_role, $win_x, $win_y, $win_w, $win_h, $one, $two, @wininfo, $prop, $info, $state, @states, $autoprops_file, $write, @props, $sticky); # Get xwininfo. @wininfo = get_xwininfo(); # Parse out window geometry info. foreach $info (@wininfo) { if ($info =~ /(.+):\s+([.\w]+)/) { $one = $1, $two = $2; if ($one =~ /xwininfo: Window id/) { $window_id = $two; } elsif ($one =~ /Absolute upper-left X/) { $win_x = $two; } elsif ($one =~ /Absolute upper-left Y/) { $win_y = $two; } elsif ($one =~ /Width/) { $win_w = $two; } elsif ($one =~ /Height/) { $win_h = $two; } } } # Get xprops. @props = get_xprops($window_id); # Parse out the properties we need. foreach $prop (@props) { if ($prop =~ /(.+) = (.+)/) { if ($1 eq "WM_WINDOW_ROLE(STRING)") { $wm_window_role = $2; } elsif ($1 eq "_PEKWM_FRAME_DECOR(CARDINAL)") { $_pekwm_frame_decor = $2; } elsif ($1 eq "_NET_WM_STATE(ATOM)") { $_net_wm_state = $2; } elsif ($1 eq "_NET_WM_DESKTOP(CARDINAL)") { $_net_wm_desktop = $2; } elsif ($1 eq "WM_CLASS(STRING)") { $wm_class = $2; } } elsif ($prop =~ /(.+): (.+)/) { $one = $1, $two = $2; if ($one =~ /window id \# of group leader/) { $window_id = $two; } } } $wm_class =~ /\"(.+)\", \"(.+)\"/; # Assemble write string. $write = "\n// Auto-generated autoproperty:\n". "// ".$1." ".$2."\n"; $write .= "Property = \"^".$1.",^".$2."\" {\n". "\tApplyOn = \"Start New Reload\"\n". "\tClientGeometry = \"".$win_w."x".$win_h."+".$win_x."+".$win_y."\"\n"; # Set decor options if (defined($_pekwm_frame_decor)) { # Titlebar false if ($_pekwm_frame_decor == 4 || $_pekwm_frame_decor == 0) { $write .= "\tTitlebar = \"False\"\n"; } # Border false if ($_pekwm_frame_decor == 2 || $_pekwm_frame_decor == 0) { $write .= "\tBorder = \"False\"\n"; } } # Add state booleans. if ($_net_wm_state) { @states = split(/, /, $_net_wm_state); foreach $state (@states) { if ($state eq "_NET_WM_STATE_STICKY") { $write .= "\tSticky = \"True\"\n"; $sticky = 1; } elsif ($state eq "_NET_WM_STATE_SHADED") { $write .= "\tShaded = \"True\"\n"; } } } # Set workspace if this window isn't sticky. if (!$sticky) { $write .= "\tWorkspace = \"".($_net_wm_desktop + 1)."\"\n"; } # Set role if ($wm_window_role) { $write .= "\tRole = ".$wm_window_role."\n"; } # End of section. $write .= "}\n"; # Write to autoproperties or to console. if ($ARGV[0] && $ARGV[0] eq "-w") { $autoprops_file = get_autoprops_file(); $autoprops_file =~ s/~/$ENV{'HOME'}/; open(OUTFILE, ">>".$autoprops_file) or die "Could not open ~/.pekwm/autoproperties for writing!\n"; print OUTFILE $write; close(OUTFILE); print "Successfully wrote autoproperty.\n"; } else { print $write; } # Find the autoprops file. sub get_autoprops_file { open(OUTFILE, "<".$ENV{'PEKWM_CONFIG_FILE'}) or die "Could not open pekwm config for reading!\n"; my $in_sec = 0; while () { if (!$in_sec && $_ =~ /Files\s+\{/) { $in_sec = 1; } elsif ($in_sec) { if ($_ =~ /AutoProps\s+=\s+\"(.+)\"/) { close(OUTFILE); return $1; } } } close(OUTFILE); return $ENV{HOME}."/.pekwm/autoproperties"; } # Create an xprops array. sub get_xprops { my $id = shift; my $xprop = `xprop -id $id`; my @xprops = split(/\n/, $xprop); return @xprops; } # Create an xwininfo array. sub get_xwininfo { my $xwininfo; if ($ENV{CLIENT_WINDOW}) { $xwininfo = `xwininfo -id $ENV{CLIENT_WINDOW}`; } else { $xwininfo = `xwininfo`; } my @xwininfos = split(/\n/, $xwininfo); return @xwininfos; } pekwm-release-0.1.18/contrib/lobo/pekwm_menu_config.pl000077500000000000000000000233121374756504400230110ustar00rootroot00000000000000#!/usr/bin/env perl # pekwm_menu_config.pl # Written by: Matt Hayes # # !!! Requires package 'zenity' for the GTK2 dialogs. # !!! Back up your config, this will rewrite it in alphabetical order. # Nothing usually goes wrong, but do it just to be safe. # # Generates a dynamic pekwm menu of all ~/.pekwm/config variables. # For boolean values, clicking on the menu entry will toggle between # 'True' or 'False'. Clicking on single integer values will pop up # a scale dialog which has a graphical slider to select a new value. # Any other values are treated as strings and will be edited by a # graphical entry box. # # Add to your menu an entry like so: # # Submenu = "Config" { # Entry { Actions = "Dynamic /path/to/pekwm_menu_config.pl --genmenu" } # } # # Put check.png and uncheck.png in your icons directory (~/.pekwm/icons/). use strict; use warnings; use Cwd qw(abs_path); # Path to this script. my $path = abs_path($0); my $vars_path = $path.".vars"; # Config file my $config_in = $ENV{'PEKWM_CONFIG_FILE'}; my $config_out = $config_in; # Check command line arguments. if ($ARGV[0] && $ARGV[0] eq "--genmenu") { my $h = hashify($config_in); print "Dynamic {\n"; gen_menu($h, ""); print "}\n"; } elsif ($ARGV[0] && $ARGV[1] && $ARGV[0] eq "--update") { edit_var($ARGV[1]); } else { exit 0; } # edit_var(arg) sub edit_var { my $arg = shift; my @sec = split(/\//, $arg); my $hashref = hashify($config_in); my $h = $hashref; my $did = 0; # Traverse to the needed section. foreach my $i (0..$#sec - 1) { $h = $h->{$sec[$i]}; } # Read through the variables file. open(INFILE, "<".$vars_path) or die "Could not find: ".$vars_path."\n"; while () { # int if ($_ =~ /int\|$arg\|(.+)\|(\d+)\|(\d+)/) { edit_int($sec[$#sec], $h, $1, $2, $3); $did = 1; # file } elsif ($_ =~ /file\|$arg\|(.+)/) { edit_file($sec[$#sec], $h, $1); $did = 1; # dir } elsif ($_ =~ /dir\|$arg\|(.+)/) { edit_dir($sec[$#sec], $h, $1); $did = 1; # bool } elsif ($_ =~ /bool\|$arg\|(.+)/) { edit_bool($sec[$#sec], $h, $1); $did = 1; # option } elsif ($_ =~ /option\|$arg\|(.+)\|(.+)\|(\d)/) { edit_option($sec[$#sec], $h, $1, $2, $3); $did = 1; # string } elsif ($_ =~ /string\|$arg\|(.+)/) { edit_string($sec[$#sec], $h, $1); $did = 1; } } close(INFILE); # If this variable does not have a vars entry, we will treat it # as a string. if (!$did) { edit_string($sec[$#sec], $h, "No description available."); } # Write updated hash to file. open my $fh, '>', $config_out or die "Could not open config for writing!\n"; write_hash($hashref, $fh, ""); close $fh; # Reload pekwm my $reload = `kill -HUP \$(xprop -root _NET_WM_PID | awk '/_NET_WM_PID/ { print \$3 }')`; } # edit_int(key, value, desc, min, max) sub edit_int { my ($key, $hashref, $desc, $min, $max) = @_; my $nval; my $value = $hashref->{$key}; # Check that we have the correct data type. If not, set the start # value to the min value. if (!($value =~ /\d+/)) { $value = $min; } $nval = `zenity --title=\"$key\" --scale --text=\"$desc\" --value=$value --min-value=$min --max-value=$max --step=1`; chomp($nval); # If cancel wasn't pressed... if ($nval) { # Set to the new value. $hashref->{$key} = $nval; } else { exit 0; } } # edit_string(key, value, desc) sub edit_string { my ($key, $hashref, $desc) = @_; my $nval = `zenity --title=\"$key\" --entry --text=\"$desc\" --entry-text=\"$hashref->{$key}\"`; chomp($nval); if ($nval) { # Set to the new value. $hashref->{$key} = $nval; } else { exit 0; } } # edit_file(key, value, desc) sub edit_file { my ($key, $hashref, $desc) = @_; my $nval = `zenity --title=\"$key\" --file-selection --text=\"$desc\" --filename=\"$hashref->{$key}\"`; chomp($nval); if ($nval) { # Set to the new value. $hashref->{$key} = $nval; } else { exit 0; } } # edit_dir(key, value, desc) sub edit_dir { my ($key, $hashref, $desc) = @_; my $nval = `zenity --title=\"$key\" --file-selection --directory --text=\"$desc\" --filename=\"$hashref->{$key}\"`; chomp($nval); if ($nval) { # Set to the new value. $hashref->{$key} = $nval; } else { exit 0; } } # edit_bool(key, value, desc) sub edit_bool { my ($key, $hashref, $desc) = @_; my ($TRUE, $FALSE); if ($hashref->{$key} eq "True") { $TRUE = "TRUE"; $FALSE = "FALSE"; } else { $TRUE = "FALSE"; $FALSE = "TRUE"; } my $nval = `zenity --title=\"$key\" --list --radiolist --text=\"$desc\" --column \"Check\" --column \"Option\" $TRUE True $FALSE False`; chomp($nval); if ($nval) { # Set to the new value. $hashref->{$key} = $nval; } else { exit 0; } } # edit_bool(key, value, desc) sub edit_option { my ($key, $hashref, $desc, $opt, $multi) = @_; my ($nval, $selstr, $tmp, $gotone, @multicur); my @opts = split(/:/, $opt); if (!$multi) { $selstr = ""; foreach (@opts) { if ($_ eq $hashref->{$key}) { $selstr .= "TRUE ".$_." "; } else { $selstr .= "FALSE ".$_." "; } } $nval = `zenity --title=\"$key\" --list --radiolist --text=\"$desc\" --column \"Check\" --column \"Option\" $selstr`; } else { $selstr = ""; @multicur = split(/ /, $hashref->{$key}); foreach my $tmp (@opts) { $gotone = 0; foreach (@multicur) { if ($tmp eq $_) { $selstr .= "TRUE ".$_." "; $gotone = 1; } } if (!$gotone) { $selstr .= "FALSE ".$tmp." " } } $nval = `zenity --title=\"$key\" --list --checklist --separator=\" \" --text=\"$desc\" --column \"Check\" --column \"Option\" $selstr`; } chomp($nval); if ($nval) { # Set to the new value. $hashref->{$key} = $nval; } else { exit 0; } } # write_hash(hash ref) # Write out the hash to config file format. sub write_hash { my ($hashref, $fh, $tabs) = @_; foreach my $key (sort(keys %$hashref)) { if (ref($hashref->{$key}) eq 'HASH') { print $fh $tabs.$key." {\n"; write_hash($hashref->{$key}, $fh, $tabs."\t"); print $fh $tabs."}\n"; } else { print $fh $tabs.$key." = \"".$hashref->{$key}."\"\n"; } } } # gen_menu(hash ref, location string) # This will generate the menu. sub gen_menu { my ($hashref, $loc) = @_; foreach my $key (sort(keys %$hashref)) { if (ref($hashref->{$key}) eq 'HASH') { print "Submenu = \" ".$key."\" {\n"; gen_menu($hashref->{$key}, $loc.$key."/"); print "}\n"; } else { gen_entry($key, $hashref->{$key}, $loc); } } } # gen_entry(key, value, location) sub gen_entry { my ($key, $value, $loc) = @_; # Boolean value if ($value eq "True") { print "Entry = \" ".$key."\" { Icon = \"check.png\"; Actions = \"Exec ".$path." --update ".$loc.$key."\" }\n"; } elsif ($value eq "False") { print "Entry = \" ".$key."\" { Icon = \"uncheck.png\"; Actions = \"Exec ".$path." --update ".$loc.$key."\" }\n"; } else { print "Entry = \" ".$key." [".$value."]\" { Actions = \"Exec ".$path." --update ".$loc.$key."\" }\n"; } } # hashify(file name) # This should read a valid config file and store all of it into # a logical hash table. sub hashify { # Filename parameter my $file = shift; # Replace ~ with home directory $file =~ s/^~/$ENV{'HOME'}/; my $comment = 0; my ($key, $value, $hval, $val); my @name_stack; my @hash_stack; push(@hash_stack, {}); # Open file for reading. open(INFILE, $file) or return pop(@hash_stack); # Read through file, line by line. while (my $line = ) { # Remove the new line character. chomp($line); # If we are currently within a comment, we need to check for # the end comment symbols. if ($comment) { # If we hit the end comment characters, we are done # commenting. if ($line =~ s<.*\*/><>) { $comment = 0; } # We are still commenting, so just skip the rest of this # code. else { next; } } # Remove /* bleh */ one liners. $line =~ s<>; # Remove /* bleh. This also means we have begun a multi-line # comment, so set $comment to 1. if ($line =~ s<>) { $comment = 1; next; } # If we're not currently in a multi-line comment, # remove // style comments. if (!$comment) { $line =~ s<>; } # If we have no line or this is a comment, skip the rest. if (!$line || $comment) { next; } # Is this a block? while ($line =~ s/(\w+)\s*\{// || $line =~ s/\"(.+)\"\s*\{//) { push(@name_stack, $1); push(@hash_stack, {}); # Is this a variable? # This, by the way, is needed for those one lined nested # blocks and variables. while ($line =~ s/^\s*(\w+)\s*=\s*\"(.*)\"// || $line =~ s/^\s*\"([\w\s]+)\"\s*=\s*\"(.*)\"//) { $hash_stack[$#hash_stack]->{$1} = $2; # Check if we have a bracket coming up, signifying # the end of a block. while ($line =~ s/^\s*\}//) { $val = pop(@name_stack); $hval = pop(@hash_stack); # Add each key/value pair to the section/subsection. while (($key, $value) = each(%$hval)) { $hash_stack[$#hash_stack]->{$val}->{$key} = $value; } } } } # Is this a variable? if ( $line =~ s/^\s*(\w+)\s*=\s*\"(.*)\"// || $line =~ s/^\s*\"([\w\s]+)\"\s*=\s*\"(.*)\"//) { $hash_stack[$#hash_stack]->{$1} = $2; # Check if we have a bracket coming up, signifying # the end of a block. while ($line =~ s/^\s*\}//) { $val = pop(@name_stack); $hval = pop(@hash_stack); # Add each key/value pair to the section/subsection. while (($key, $value) = each(%$hval)) { $hash_stack[$#hash_stack]->{$val}->{$key} = $value; } } } # End of block? while ($line =~ s/^\s*\}//) { $val = pop(@name_stack); $hval = pop(@hash_stack); # Add each key/value pair to the section/subsection. while (($key, $value) = each(%$hval)) { $hash_stack[$#hash_stack]->{$val}->{$key} = $value; } } } # Return fully assembled hash. return pop(@hash_stack); } pekwm-release-0.1.18/contrib/lobo/pekwm_menu_config.pl.vars000066400000000000000000000156611374756504400237700ustar00rootroot00000000000000' pekwm_menu_config.pl variable list ' this is a comment ' int|Section/VarName|Description|Minimum value|Maxiumum value int|CmdDialog/HistorySaveInterval|Defines how often the history file should be saved counting each time the CmdDialog finish a command. Default 16.|0|100 int|CmdDialog/HistorySize|Number of entries in the history that should be kept track of. Default 1024.|0|2000 int|Harbour/DockApp/SideMax|Controls the maximum size of dockapp clients. If a dockapp client is larger than the maximum, it gets resized down to the SideMax value. Integer is a number of pixels.|0|100 int|Harbour/DockApp/SideMin|Controls the minimum size of dockapp clients. If a dockapp client is smaller than the minimum, it gets resized up to the SideMin value. Integer is a number of pixels.|0|100 int|Harbour/Head|When RandR or Xinerama is on, decides on what head the harbour resides on. Integer is the head number.|0|20 int|MoveResize/EdgeAttract|The distance from screen edge required for the window to snap against it in pixels.|0|100 int|MoveResize/EdgeResist|The distance from screen edge required for the window moving to start being resisted in pixels.|0|100 int|MoveResize/WindowAttract|The distance from other clients that a window will snap against them to in pixels.|0|100 int|MoveResize/WindowResist|The distance from other clients that a window movement will start being resisted.|0|100 int|Screen/DoubleClickTime|Time, in milliseconds, between clicks to be counted as a doubleclick.|0|1000| int|Screen/Placement/Smart/OffsetX|Pixels to leave between new and old windows and screen edges. When 0, no space is reserved.|0|100 int|Screen/Placement/Smart/OffsetY|Pixels to leave between new and old windows and screen edges. When 0, no space is reserved.|0|100 int|Screen/ShowWorkspaceIndicator|Show WorkspaceIndicator for N milliseconds. If set to less than 1, the WorkspaceIndicator is disabled.|0|3000 int|Screen/Workspaces|Number of workspaces enabled.|0|20 int|Screen/WorkspaceIndicatorScale|Changes the size of the WorkspaceIndicator, higher value means smaller size.|0|100 int|Screen/WorkspacesPerRow|Number of workspaces on each row. Value less than 1 fits all workspaces on a single row.|0|20 ' string|Section/VarName|Description string|Screen/EdgeSize|How many pixels from the edge of the screen should screen edges be. Parameters correspond to the following edges: top bottom left right. A value of 0 disables edges. string|Screen/UniqueNames/Post|String to place after the unique client number. string|Screen/UniqueNames/Pre|String to place before the unique client number. string|Screen/TrimTitle|This string contains what pekwm uses to trim down overlong window titles. If it's empty, no trimming down is performed at all. string|Screen/WorkspaceNames|List of names for workspaces separated by ;. ' file|Section/VarName|Description file|CmdDialog/HistoryFile|Path to history file where history is persisted between session. Default ~/.pekwm/history file|Files/AutoProps|The location of the autoprops file file|Files/Keys|The location of the keys file file|Files/Menu|The location of the menu file file|Files/Mouse|The location of the mouse file file|Files/Start|The location of the start file ' dir|Section/VarName|Description dir|Files/Icons|The location of the icons directory dir|Files/Theme|The location of the Theme directory ' bool|Section/VarName|Description bool|CmdDialog/HistoryUnique|If true, identical items in the history will only appear once where the most recently used is the first item. Default true. bool|Harbour/MaximizeOver|Controls whether maximized clients will cover the harbour (true), or if they will stop at the edge of the harbour (false). bool|Harbour/OnTop|Whether or not the harbour is \"always on top\" bool|Menu/DisplayIcons|If true, turns on the drawing of application icons in menus. bool|MoveResize/OpaqueMove|If true, turns on opaque Moving bool|MoveResize/OpaqueResize|If true, turns on opaque Resizing bool|Screen/EdgeIndent|Toggles if the screen edge should be reserved space. bool|Screen/FocusNew|Toggles if new windows should be focused when they pop up. bool|Screen/FullscreenAbove|Toggles restacking of windows when going to and from fullscreen mode. Windows are restacked to the top of all windows when going to fullscreen and to the top of their layer when being restored from fullscreen. bool|Screen/FullscreenDetect|Toggles detection of broken fullscreen requests setting clients to fullscreen mode when requesting to be the size of the screen. Default true. bool|Screen/HonourRandr|Toggles reading of XRANDR information, this can be disabled if the display driver gives both Xinerama and Randr information and only of the two is correct. Default true. bool|Screen/PlaceNew|Toggles if new windows should be placed using the rules found in the Placement subsection, or just opened on the top left corner of your screen. bool|Screen/Placement/Smart/LeftToRight|If false, the window is placed starting from the right. bool|Screen/Placement/Smart/Row|Whether to use row or column placement, if true, uses row. bool|Screen/Placement/Smart/TopToBottom|If false, the window is placed starting from the bottom. bool|Screen/ShowClientID|Should Client IDs be displayed in window titles. bool|Screen/ShowFrameList|Controls whether a list of all available frames on the workspace is displayed during the NextFrame/PrevFrame actions. bool|Screen/ShowStatusWindow|Controls whether a size/position info window is shown when moving or resizing windows. bool|Screen/UniqueNames/SetUnique|Decides if the feature is used or not. False or True. ' option|Section/VarName|Description|Opt1:Opt2:Opt3|Single = 0 Multi = 1 option|Harbour/Orientation|From what to which direction the harbour expands. One of TopToBottom, BottomToTop, RightToLeft, LeftToRight.|TopToBottom:BottomToTop:RightToLeft:LeftToRight|0 option|Harbour/Placement|Which edge to place the harbour on. One of Right, Left, Top, or Bottom.|Right:Left:Top:Bottom|0 option|Menu/Enter|Decides on what mouse events to enter a submenu. String is one of \"ButtonPress, ButtonRelease, DoubleClick, Motion, MotionPressed\"|ButtonPress:ButtonRelease:DoubleClick:Motion:MotionPressed|0 option|Menu/Exec|Decides on what mouse events to execute an entry. String is one of \"ButtonPress, ButtonRelease, DoubleClick, Motion, MotionPressed\"|ButtonPress:ButtonRelease:DoubleClick:Motion:MotionPressed|0 option|Menu/Select|Decides on what mouse events to select a menu entry. String is one of \"ButtonPress, ButtonRelease, DoubleClick, Motion\"|ButtonPress:ButtonRelease:DoubleClick:Motion|0 option|Screen/Placement/Model|Smart - Tries to place windows where no other window is present\nMouseCentered - Places the center of the window underneath the current mouse pointer position\nMouseTopLeft - Places the top-left corner of the window under the pointer\nMouseNotUnder - Places windows on screen corners avoiding the current mouse cursor position.\nCenteredOnParent - Places transient windows at center of their parent window.|Smart:MouseCentered:MouseTopLeft:MouseNotUnder:CenteredOnParent|1 pekwm-release-0.1.18/contrib/lobo/uncheck.png000066400000000000000000000003041374756504400210770ustar00rootroot00000000000000PNG  IHDR PXsRGB pHYs  tIME 33tEXtCommentCreated with GIMPW1IDATc` |}}m޼ڴi~Rٝ$Pw7IENDB`pekwm-release-0.1.18/data/000077500000000000000000000000001374756504400152725ustar00rootroot00000000000000pekwm-release-0.1.18/data/CMakeLists.txt000066400000000000000000000004271374756504400200350ustar00rootroot00000000000000cmake_minimum_required(VERSION 2.8) add_subdirectory(themes) add_subdirectory(scripts) install(FILES autoproperties autoproperties_typerules config config_system keys menu mouse mouse_system mouse_click mouse_sloppy start vars DESTINATION etc/pekwm/) pekwm-release-0.1.18/data/Makefile.am000066400000000000000000000006731374756504400173340ustar00rootroot00000000000000AUTOMAKE_OPTIONS = foreign SUBDIRS = themes scripts EXTRA_DIST = autoproperties autoproperties_typerules \ config config_system \ keys menu \ mouse mouse_system mouse_click mouse_sloppy \ start vars \ CMakeLists.txt cfgdatadir = $(sysconfdir)/pekwm cfgdata_DATA = autoproperties autoproperties_typerules \ config config_system \ keys menu \ mouse mouse_system mouse_click mouse_sloppy \ start vars distclean-local: rm -f *\~ .\#* pekwm-release-0.1.18/data/autoproperties000066400000000000000000000154371374756504400203140ustar00rootroot00000000000000/* Autoproperties. The default template and simple course of autopropping to help you add your own autoproperties. See the documentation for more keywords and the rest of what is possible through this file. First, it's good to note that you can't just make up the property string, you need to use a program called 'xprop' to show it. Please conduct the documentation. Another good tip is to make sure you have an ApplyOn entry. The autoproperties you define won't do any good if you don't tell pekwm when to apply them! Third tip. You can't match a window with more than one property. The first one that matches will be used, the rest ignored (see the gimp example). Note that the default entries are commented out, don't comment out your own autoproperties. :) */ Require { Templates = "True" } /* Group terminal applications */ # Property = "(term|rxvt),(erm|xvt)" { # ApplyOn = "New" # Group = "term" { # Size = "5" # FocusedFirst = "True" # Raise = "True" # } # } /* Remove decor of customize toolbar window of mozilla firefox. */ Property = "^(gecko|Gecko|firefox-bin),^Firefox-bin,,^Customize Toolbar\$" { ApplyOn = "Start New TransientOnly" Border = "False" Titlebar = "False" } /* Auto-group up to 10 mozilla download windows to group you call "moz-dl", using a WM_CLASS and specifying the the download window using the begining of its title. Make the windows go to the top-left corner of your workspace and place them under other windows. Do this when new windows show up, also to so called transient windows. */ # Property = "^mozilla-bin,^Mozilla-bin,,^Saving" { # ApplyOn = "New Transient" # Group = "moz-dl" { Size = "10" } # FrameGeometry = "+0+0" # Layer = "Below" # } /* Group together up to two windows that have a WM_CLASS that matches the property. Start these windows on workspace two. */ # Property = "^Mozilla,^navigator:browser" { # ApplyOn = "Start New Workspace" # Workspace = "2" # } /* Group together an infinite number of windows that match the property. When new windows are opened to this group, never make them the active window of the group, but open them in the background. Make these autoproperties apply on every pekwm start or when a new window is opened. */ # Property = "^dillo,^Dillo" { # ApplyOn = "Start New" # Group = "dillo" { Size = "0"; Behind = "True" } # } /* Put property matching windows under other windows and make the window appear on every workspace. Do not show matching windows on the pekwm goto menus, do not include them in frame switching (mod1+tab) and do not let other windows snap to them. Do this on pekwm start or when new window is opened, also include transient windows (in the example, xmms playlist and equalizer are transients). */ # Property = ".*,^xmms" { # ApplyOn = "Start New Transient" # Layer = "Desktop" # Sticky = "True" # Skip = "Menus FocusToggle Snap" # } /* Remove Gimp windows from the menus, only show the main toolbox window. Use the WM_WINDOW_ROLE to tell the difference between gimp windows. First make sure the toolbox window doesn't get confused with the rest of the windows. This just tells pekwm to ignore any matches for the toolbox later on. Without this, the toolbox would match with "the rest of the windows" and get ignored from the pekwm menus! We don't want that. */ # Property = "^gimp,^Gimp,gimp-toolbox" { # ApplyOn = "Start New" # } /* The Crop dialog always gets in the way, put it in the corner but place it above other windows anyways. Don't show the window in pekwm menus. */ # Property = "^gimp,^Gimp,gimp-crop-tool" { # ApplyOn = "Start New" # Layer = "OnTop" # FrameGeometry = "+0+0" # Skip = "Menus" # } /* The rest of the gimp windows should not show in pekwm menus eather. */ # Property = ".gimp,^Gimp" { # ApplyOn = "Start New" # Skip = "Menus"; # } /* This should start making sense to you by now. */ # Property = "^gkrellm,^Gkrellm" { # ApplyOn = "Start New" # Sticky = "True" # Skip = "Menus FocusToggle" # Layer = "Desktop" # } /* Some useful standard application xclock xload and xbiff. This should be fairly clear to you. In addition to what you've allready learned, we make the windows appear without titlebars and borders. We are also using the geometry in all its glory, defining the windows size in addition to its position. */ # Property = "^xclock,^XClock" { # ApplyOn = "Start New" # ClientGeometry = "120x137+0-137" # Border = "False"; Titlebar = "False" # Sticky = "True" # Layer = "Desktop" # Skip = "Menus FocusToggle Snap" # } # # Property = "^xload,^XLoad" { # ApplyOn = "Start New" # ClientGeometry = "560x137+120-137" # Border = "False"; Titlebar = "False" # Sticky = "True" # Layer = "Desktop" # Skip = "Menus FocusToggle Snap" # } # # Property = "^xbiff,^XBiff" { # ApplyOn = "Start New" # ClientGeometry = "120x137-120-137" # Border = "False"; Titlebar = "False" # Sticky = "True" # Layer = "Desktop" # Skip = "Menus FocusToggle Snap" # } // End of autoproperties. ------------------------- TypeRules { INCLUDE = "$_PEKWM_ETC_PATH/autoproperties_typerules" } /* Next, we do some siple window title rewriting. To make it simple, you can automatically make some windows get their title edited. Cut out an annoying piece, add text, replace text. This all happens in it's own section "TitleRules {}". I don't like the way dillo uses its titlebar, it says "Dillo: webpage". I want that "Dillo:" part to not show in the beginning, instead I want to make it show as "webpage - dillo". Then again, the "webpage - Mozilla Firefox" is too long for my taste. I shorten it in the second titlerule. And I'll place the shortened text in the beginning of the title just as a show how. */ # TitleRules { # Property = "^dillo,^Dillo" { # Rule = "/Dillo: (.*)/\\1 - dillo/" # } # Property = "^firefox-bin,^Firefox-bin" { # Rule = "/(.*) - Mozilla Firefox/MF: \\1/" # } # } // End of titlerules. ----------------------------- /* Then for some harbour ordering done in it's own "Harbour {}" section. This is simple really, but you might want to check the documentation on how the positions work. Obpager is allways the last dockapp, the cpuload application is the first, and wmnd will get placed in the centre. */ # Harbour { # Property = "^obpager,^obpager" { # Position = "-1" # } # Property = ".*,.*cpuload" { # Position = "1" # } # Property = ".*,^wmnd" { # Position = "0" # } # } // End of harbour order rules. -------------------- /* Last, if you have a theme that supports it, or you have hacked one up yourself, you can use the "DecorRules {}" section to make windows show up with independent decorations. Here we tell our terminal windows to use the special TERM decoration section found from your theme. Note that this _needs_ a theme that supports it. */ # DecorRules { # Property = "^term,^xterm" { # Decor = "TERM" # } # } pekwm-release-0.1.18/data/autoproperties_typerules000066400000000000000000000015751374756504400224260ustar00rootroot00000000000000/* Desktop windows such as nautilus window in gnome. These should cover the root window and be below all other windows. Also they should not be included in the menu and in snapping. */ Property = "DESKTOP" { FrameGeometry = "0x0+0+0" Titlebar = "False" Border = "False" Sticky = "True" Skip = "FocusToggle Menus Snap" Layer = "Desktop" Focusable = "False" DisallowedActions = "Move" } Property = "DOCK" { Titlebar = "False" Border = "False" Sticky = "True" Layer = "Dock" Skip = "FocusToggle Menus" Focusable = "False" DisallowedActions = "Move" } Property = "TOOLBAR" { Skip = "FocusToggle Menus Snap" } Property = "MENU" { Titlebar = "False" Border = "False" Skip = "FocusToggle Menus Snap" } Property = "UTILITY" { } Property = "SPLASH" { Titlebar = "False" Border = "False" Layer = "OnTop" } Property = "DIALOG" { Layer = "OnTop" } Property = "NORMAL" { } pekwm-release-0.1.18/data/config000066400000000000000000000004331374756504400164620ustar00rootroot00000000000000INCLUDE = "$_PEKWM_ETC_PATH/config_system" Files { Theme = "$_PEKWM_THEME_PATH/default" } Screen { Workspaces = "9" WorkspacesPerRow = "3" WorkspaceNames = "01;02;03;04;05;06;07;08;09" Placement { Model = "CenteredOnParent Smart MouseNotUnder" } } pekwm-release-0.1.18/data/config_system000066400000000000000000000045771374756504400201030ustar00rootroot00000000000000Files { Keys = "~/.pekwm/keys" Mouse = "~/.pekwm/mouse" Menu = "~/.pekwm/menu" Start = "~/.pekwm/start" AutoProps = "~/.pekwm/autoproperties" Theme = "$_PEKWM_THEME_PATH/default" Icons = "~/.pekwm/icons/" } MoveResize { EdgeAttract = "10" EdgeResist = "10" WindowAttract = "5" WindowResist = "5" OpaqueMove = "True" OpaqueResize = "False" } Screen { Workspaces = "9" WorkspacesPerRow = "3" WorkspaceNames = "01;02;03;04;05;06;07;08;09" ShowFrameList = "True" ShowStatusWindow = "True" ShowStatusWindowCenteredOnRoot = "False" ShowClientID = "False" ShowWorkspaceIndicator = "500" PlaceNew = "True" FocusNew = "True" FocusStealProtect = "0" ReportAllClients = "False" TrimTitle = "..." FullscreenAbove = "True" FullscreenDetect = "True" HonourRandr = "True" HonourAspectRatio = "True" EdgeSize = "1 1 1 1" EdgeIndent = "False" DoubleClickTime = "250" Placement { Model = "CenteredOnParent Smart MouseNotUnder" Smart { Row = "True" TopToBottom = "True" LeftToRight = "True" OffsetX = "0" OffsetY = "0" } } UniqueNames { SetUnique = "False" Pre = " #" Post = "" } } Menu { DisplayIcons = "True" Icons = "DEFAULT" { Minimum = "16x16" Maximum = "16x16" } # To enable make separate window have other icon size restrictions, # for example wallpaper menu found in pekwm_menu_tools, set the following # for each menu you want to "free". # Icons = "Wallpaper" { # Minimum = "64x64" # Maximum = "64x64" # } # Defines how menus act on mouse input. # Possible values are: "ButtonPress ButtonRelease DoubleClick Motion" # To make submenus open on mouse over, comment the default Enter, # uncomment the alternative, and reload pekwm. Select = "Motion MotionPressed" Enter = "MotionPressed ButtonPress" # Enter = "Motion" Exec = "ButtonRelease" } CmdDialog { HistoryUnique = "True" HistorySize = "1024" HistoryFile = "~/.pekwm/history" HistorySaveInterval = "16" } Harbour { OnTop = "True" MaximizeOver = "False" Placement = "Right" Orientation = "TopToBottom" Head = "0" DockApp { SideMin = "64" SideMax = "0" } } pekwm-release-0.1.18/data/keys000066400000000000000000000355051374756504400162000ustar00rootroot00000000000000INCLUDE = "vars" Global { # - - ----------------------------------------------- - - # Simple bindings to most frequently used actions. # # Adding your own frequently used actions is easy - # just copy it over from CHAINS and edit the keypress! # Moving in frames KeyPress = "Mod1 Tab" { Actions = "NextFrame EndRaise" } KeyPress = "Mod1 Shift Tab" { Actions = "PrevFrame EndRaise" } KeyPress = "Mod1 Ctrl Tab" { Actions = "NextFrameMRU EndRaise" } KeyPress = "Mod1 Ctrl Shift Tab" { Actions = "PrevFrameMRU EndRaise" } KeyPress = "Mod4 Tab" { Actions = "ActivateClientRel 1" } KeyPress = "Mod4 Shift Tab" { Actions = "ActivateClientRel -1" } KeyPress = "Mod4 Ctrl Right" { Actions = "MoveClientRel 1" } KeyPress = "Mod4 Ctrl Left" { Actions = "MoveClientRel -1" } KeyPress = "Mod4 Left" { Actions = "FocusDirectional Left" } KeyPress = "Mod4 Right" { Actions = "FocusDirectional Right" } KeyPress = "Mod4 Up" { Actions = "FocusDirectional Up" } KeyPress = "Mod4 Down" { Actions = "FocusDirectional Down" } # Moving in workspaces KeyPress = "Ctrl Mod1 Left" { Actions = "GotoWorkspace Left" } KeyPress = "Ctrl Mod1 Right" { Actions = "GotoWorkspace Right" } KeyPress = "Ctrl Mod1 Up" { Actions = "GotoWorkspace Up" } KeyPress = "Ctrl Mod1 Down" { Actions = "GotoWorkspace Down" } KeyPress = "Ctrl Mod4 Shift Left" { Actions = "GotoWorkspace LeftN" } KeyPress = "Ctrl Mod4 Shift Right" { Actions = "GotoWorkspace RightN" } KeyPress = "Mod4 1" { Actions = "GotoWorkspace 1" } KeyPress = "Mod4 2" { Actions = "GotoWorkspace 2" } KeyPress = "Mod4 3" { Actions = "GotoWorkspace 3" } KeyPress = "Mod4 4" { Actions = "GotoWorkspace 4" } KeyPress = "Mod4 5" { Actions = "GotoWorkspace 5" } KeyPress = "Mod4 6" { Actions = "GotoWorkspace 6" } KeyPress = "Mod4 7" { Actions = "GotoWorkspace 7" } KeyPress = "Mod4 8" { Actions = "GotoWorkspace 8" } KeyPress = "Mod4 9" { Actions = "GotoWorkspace 9" } KeyPress = "Ctrl Mod1 Shift Left" { Actions = "SendToWorkspace Next; GoToWorkspace Next" } KeyPress = "Ctrl Mod1 Shift Right" { Actions = "SendToWorkspace Prev; GoToWorkspace Prev" } KeyPress = "Ctrl Mod1 Shift Up" { Actions = "SendToWorkspace NextV; GoToWorkspace NextV" } KeyPress = "Ctrl Mod1 Shift Down" { Actions = "SendToWorkspace PrevV; GoToWorkspace PrevV" } KeyPress = "Mod4 F1" { Actions = "SendToWorkspace 1" } KeyPress = "Mod4 F2" { Actions = "SendToWorkspace 2" } KeyPress = "Mod4 F3" { Actions = "SendToWorkspace 3" } KeyPress = "Mod4 F4" { Actions = "SendToWorkspace 4" } KeyPress = "Mod4 F5" { Actions = "SendToWorkspace 5" } KeyPress = "Mod4 F6" { Actions = "SendToWorkspace 6" } KeyPress = "Mod4 F7" { Actions = "SendToWorkspace 7" } KeyPress = "Mod4 F8" { Actions = "SendToWorkspace 8" } KeyPress = "Mod4 F9" { Actions = "SendToWorkspace 9" } # Simple window management KeyPress = "Mod4 M" { Actions = "Toggle Maximized True True" } KeyPress = "Mod4 G" { Actions = "Maxfill True True" } KeyPress = "Mod4 F" { Actions = "Toggle FullScreen" } KeyPress = "Mod4 Return" { Actions = "MoveResize" } KeyPress = "Mod4 Q" { Actions = "Close" } KeyPress = "Mod4 S" { Actions = "Toggle Shaded" } KeyPress = "Mod4 I" { Actions = "Toggle Iconified" } # Marking KeyPress = "Mod4 Z" { Actions = "Toggle Marked" } KeyPress = "Mod4 A" { Actions = "AttachMarked" } # Tagging KeyPress = "Mod4 T" { Actions = "Toggle Tagged False" } # Menus KeyPress = "Mod4 R" { Actions = "ShowMenu Root" } KeyPress = "Mod4 W" { Actions = "ShowMenu Window" } KeyPress = "Mod4 L" { Actions = "ShowMenu Goto" } KeyPress = "Mod4 C" { Actions = "ShowMenu GotoClient" } KeyPress = "Mod4 Shift I" { Actions = "ShowMenu Icon" } KeyPress = "Mod4 X" { Actions = "HideAllMenus" } # External Commands KeyPress = "Mod1 Print" { Actions = "Exec $_PEKWM_SCRIPT_PATH/pekwm_screenshot.sh" } KeyPress = "Mod4 E" { Actions = "Exec $TERM" } # Pekwm control KeyPress = "Ctrl Mod1 Delete" { Actions = "Reload" } KeyPress = "Mod4 D" { Actions = "ShowCmdDialog" } KeyPress = "Mod4 V" { Actions = "ShowSearchDialog" } KeyPress = "Mod4 H" { Actions = "Toggle HarbourHidden" } # - - ----------------------------------------------- - - # CHAINS. These give you access to just about everything. # Move to Corner Chain = "Ctrl Mod1 C" { KeyPress = "Q" { Actions = "MoveToEdge TopLeft" } KeyPress = "Y" { Actions = "MoveToEdge TopCenterEdge" } KeyPress = "W" { Actions = "MoveToEdge TopCenterEdge" } KeyPress = "Shift Y" { Actions = "MoveToEdge TopEdge" } KeyPress = "Shift W" { Actions = "MoveToEdge TopEdge" } KeyPress = "P" { Actions = "MoveToEdge TopRight" } KeyPress = "E" { Actions = "MoveToEdge TopRight" } KeyPress = "A" { Actions = "MoveToEdge LeftCenterEdge" } KeyPress = "Shift A" { Actions = "MoveToEdge LeftEdge" } KeyPress = "L" { Actions = "MoveToEdge RightCenterEdge" } KeyPress = "D" { Actions = "MoveToEdge RightCenterEdge" } KeyPress = "Shift L" { Actions = "MoveToEdge RightEdge" } KeyPress = "Shift D" { Actions = "MoveToEdge RightEdge" } KeyPress = "Z" { Actions = "MoveToEdge BottomLeft" } KeyPress = "B" { Actions = "MoveToEdge BottomCenterEdge" } KeyPress = "X" { Actions = "MoveToEdge BottomCenterEdge" } KeyPress = "Shift B" { Actions = "MoveToEdge BottomEdge" } KeyPress = "Shift X" { Actions = "MoveToEdge BottomEdge" } KeyPress = "M" { Actions = "MoveToEdge BottomRight" } KeyPress = "C" { Actions = "MoveToEdge BottomRight" } KeyPress = "H" { Actions = "MoveToEdge Center" } KeyPress = "S" { Actions = "MoveToEdge Center" } } # Menus Chain = "Ctrl Mod1 M" { KeyPress = "R" { Actions = "ShowMenu Root" } KeyPress = "W" { Actions = "ShowMenu Window" } KeyPress = "I" { Actions = "ShowMenu Icon" } KeyPress = "G" { Actions = "ShowMenu Goto" } KeyPress = "C" { Actions = "ShowMenu GotoClient" } KeyPress = "D" { Actions = "ShowMenu Decor" } KeyPress = "A" { Actions = "ShowMenu AttachClientInFrame" } KeyPress = "F" { Actions = "ShowMenu AttachFrameInFrame" } Keypress = "Shift A" { Actions = "ShowMenu AttachClient" } Keypress = "Shift F" { Actions = "ShowMenu AttachFrame" } KeyPress = "X" { Actions = "HideAllMenus" } } # Grouping Chain = "Ctrl Mod1 T" { KeyPress = "T" { Actions = "Toggle Tagged False" } KeyPress = "B" { Actions = "Toggle Tagged True" } KeyPress = "C" { Actions = "Unset Tagged" } KeyPress = "G" { Actions = "Toggle GlobalGrouping" } KeyPress = "M" { Actions = "Toggle Marked" } KeyPress = "A" { Actions = "AttachMarked" } KeyPress = "D" { Actions = "Detach" } Keypress = "P" { Actions = "AttachClientInNextFrame" } KeyPress = "O" { Actions = "AttachClientInPrevFrame" } Keypress = "I" { Actions = "AttachFrameInNextFrame" } KeyPress = "U" { Actions = "AttachFrameInPrevFrame" } } # Decor Toggles Chain = "Ctrl Mod1 D" { KeyPress = "B" { Actions = "Toggle DecorBorder" } KeyPress = "T" { Actions = "Toggle DecorTitlebar" } KeyPress = "D" { Actions = "Toggle DecorBorder; Toggle DecorTitlebar" } } # Window Actions Chain = "Ctrl Mod1 A" { Chain = "G" { KeyPress = "G" { Actions = "MaxFill True True" } KeyPress = "V" { Actions = "MaxFill False True" } KeyPress = "H" { Actions = "MaxFill True False" } } Chain = "M" { KeyPress = "M" { Actions = "Toggle Maximized True True" } KeyPress = "V" { Actions = "Toggle Maximized False True" } KeyPress = "H" { Actions = "Toggle Maximized True False" } } Chain = "Q" { KeyPress = "Q" { Actions = "Close" } KeyPress = "F" { Actions = "CloseFrame" } KeyPress = "K" { Actions = "Kill" } } KeyPress = "S" { Actions = "Toggle Shaded" } KeyPress = "A" { Actions = "Toggle Sticky" } KeyPress = "O" { Actions = "Toggle AlwaysOnTop" } KeyPress = "B" { Actions = "Toggle AlwaysBelow" } KeyPress = "I" { Actions = "Set Iconified" } KeyPress = "R" { Actions = "Raise" } KeyPress = "Shift R" { Actions = "Raise True" } KeyPress = "L" { Actions = "Lower" } KeyPress = "Shift L" { Actions = "Lower True" } KeyPress = "X" { Actions = "ActivateOrRaise" } KeyPress = "Return" { Actions = "MoveResize" } KeyPress = "F" { Actions = "Toggle Fullscreen" } KeyPress = "Left" { Actions = "GrowDirection Left" } KeyPress = "Right" { Actions = "GrowDirection Right" } KeyPress = "Up" { Actions = "GrowDirection Up" } KeyPress = "Down" { Actions = "GrowDirection Down" } } # Moving in Frames Chain = "Ctrl Mod1 F" { KeyPress = "P" { Actions = "NextFrame AlwaysRaise" } KeyPress = "O" { Actions = "PrevFrame AlwaysRaise" } KeyPress = "Shift P" { Actions = "NextFrameMRU EndRaise" } KeyPress = "Shift O" { Actions = "PrevFrameMRU EndRaise" } KeyPress = "I" { Actions = "ActivateClientRel 1" } KeyPress = "U" { Actions = "ActivateClientRel -1" } KeyPress = "Shift I" { Actions = "MoveClientRel 1" } KeyPress = "Shift U" { Actions = "MoveClientRel -1" } KeyPress = "Up" { Actions = "FocusDirectional Up" } KeyPress = "Down" { Actions = "FocusDirectional Down" } KeyPress = "Left" { Actions = "FocusDirectional Left" } Keypress = "Right" { Actions = "FocusDirectional Right" } KeyPress = "1" { Actions = "ActivateClientNum 1" } KeyPress = "2" { Actions = "ActivateClientNum 2" } KeyPress = "3" { Actions = "ActivateClientNum 3" } KeyPress = "4" { Actions = "ActivateClientNum 4" } KeyPress = "5" { Actions = "ActivateClientNum 5" } KeyPress = "6" { Actions = "ActivateClientNum 6" } KeyPress = "7" { Actions = "ActivateClientNum 7" } KeyPress = "8" { Actions = "ActivateClientNum 8" } KeyPress = "9" { Actions = "ActivateClientNum 9" } KeyPress = "0" { Actions = "ActivateClientNum 10" } KeyPress = "C" { Actions = "ShowCmdDialog GotoClientID " } } # Workspaces Chain = "Ctrl Mod1 W" { KeyPress = "Right" { Actions = "GoToWorkspace Right" } KeyPress = "Left" { Actions = "GoToWorkspace Left" } KeyPress = "N" { Actions = "GoToWorkspace Next" } KeyPress = "P" { Actions = "GoToWorkspace Prev" } KeyPress = "1" { Actions = "GoToWorkspace 1" } KeyPress = "2" { Actions = "GoToWorkspace 2" } KeyPress = "3" { Actions = "GoToWorkspace 3" } KeyPress = "4" { Actions = "GoToWorkspace 4" } KeyPress = "5" { Actions = "GoToWorkspace 5" } KeyPress = "6" { Actions = "GoToWorkspace 6" } KeyPress = "7" { Actions = "GoToWorkspace 7" } KeyPress = "8" { Actions = "GoToWorkspace 8" } KeyPress = "9" { Actions = "GoToWorkspace 9" } KeyPress = "Up" { Actions = "SendToWorkspace Next; GoToWorkspace Next" } KeyPress = "Down" { Actions = "SendToWorkspace Prev; GoToWorkspace Prev" } KeyPress = "F1" { Actions = "SendToWorkspace 1" } KeyPress = "F2" { Actions = "SendToWorkspace 2" } KeyPress = "F3" { Actions = "SendToWorkspace 3" } KeyPress = "F4" { Actions = "SendToWorkspace 4" } KeyPress = "F5" { Actions = "SendToWorkspace 5" } KeyPress = "F6" { Actions = "SendToWorkspace 6" } KeyPress = "F7" { Actions = "SendToWorkspace 7" } KeyPress = "F8" { Actions = "SendToWorkspace 8" } KeyPress = "F9" { Actions = "SendToWorkspace 9" } } # External commands Chain = "Ctrl Mod1 E" { KeyPress = "E" { Actions = "Exec $TERM" } KeyPress = "L" { Actions = "Exec xlock -mode blank &" } KeyPress = "S" { Actions = "Exec scrot &" } KeyPress = "C" { Actions = "ShowCmdDialog" } } # Wm actions Chain = "Ctrl Mod1 P" { KeyPress = "Delete" { Actions = "Reload" } KeyPress = "Next" { Actions = "Restart" } KeyPress = "End" { Actions = "Exit" } KeyPress = "Prior" { Actions = "RestartOther twm" } KeyPress = "D" { Actions = "ShowCmdDialog" } KeyPress = "H" { Actions = "Toggle HarbourHidden" } } # Skipping Chain = "Ctrl Mod1 S" { Keypress = "M" { Actions = "Toggle Skip Menus" } Keypress = "F" { Actions = "Toggle Skip FocusToggle" } Keypress = "S" { Actions = "Toggle Skip Snap" } } KeyPress = "Mod4 Space" { Actions = "SetPlacementOption SwitchGeometry 1" } } # Keys when MoveResize is active MoveResize { KeyPress = "Left" { Actions = "MoveHorizontal -10" } KeyPress = "Right" { Actions = "MoveHorizontal 10" } KeyPress = "Up" { Actions = "MoveVertical -10" } KeyPress = "Down" { Actions = "MoveVertical 10" } Keypress = "Shift Left" { Actions = "MoveHorizontal -1" } Keypress = "Shift Right" { Actions = "MoveHorizontal 1" } Keypress = "Shift Up" { Actions = "MoveVertical -1" } Keypress = "Shift Down" { Actions = "MoveVertical 1" } Keypress = "Mod4 Left" { Actions = "ResizeHorizontal -10" } Keypress = "Mod4 Right" { Actions = "ResizeHorizontal 10" } Keypress = "Mod4 Up" { Actions = "ResizeVertical -10" } Keypress = "Mod4 Down" { Actions = "ResizeVertical 10" } Keypress = "Mod1 Left" { Actions = "ResizeHorizontal -10" } Keypress = "Mod1 Right" { Actions = "ResizeHorizontal 10" } Keypress = "Mod1 Up" { Actions = "ResizeVertical -10" } Keypress = "Mod1 Down" { Actions = "ResizeVertical 10" } Keypress = "Shift Mod4 Left" { Actions = "ResizeHorizontal -1" } Keypress = "Shift Mod4 Right" { Actions = "ResizeHorizontal 1" } Keypress = "Shift Mod4 Up" { Actions = "ResizeVertical -1" } Keypress = "Shift Mod4 Down" { Actions = "ResizeVertical 1" } Keypress = "Shift Mod1 Left" { Actions = "ResizeHorizontal -1" } Keypress = "Shift Mod1 Right" { Actions = "ResizeHorizontal 1" } Keypress = "Shift Mod1 Up" { Actions = "ResizeVertical -1" } Keypress = "Shift Mod1 Down" { Actions = "ResizeVertical 1" } Keypress = "s" { Actions = "MoveSnap" } Keypress = "Escape" { Actions = "Cancel" } Keypress = "q" { Actions = "Cancel" } Keypress = "Return" { Actions = "End" } } # Keys for CmdDialog editing InputDialog { KeyPress = "Left" { Actions = "CursPrev" } KeyPress = "Right" { Actions = "CursNext" } KeyPress = "Ctrl A" { Actions = "CursBegin" } KeyPress = "Ctrl E" { Actions = "CursEnd" } KeyPress = "BackSpace" { Actions = "Erase;CompleteAbort" } KeyPress = "Ctrl K" { Actions = "ClearFromCursor" } KeyPress = "Ctrl C" { Actions = "Clear" } KeyPress = "Return" { Actions = "Exec" } KeyPress = "Escape" { Actions = "Close" } KeyPress = "Up" { Actions = "HistPrev" } KeyPress = "Down" { Actions = "HistNext" } KeyPress = "Ctrl P" { Actions = "HistPrev" } KeyPress = "Ctrl N" { Actions = "HistNext" } KeyPress = "Ctrl B" { Actions = "CursPrev" } KeyPress = "Ctrl F" { Actions = "CursNext" } KeyPress = "Tab" { Actions = "Complete" } KeyPress = "Any Any" { Actions = "Insert" } } # Keys working in menus Menu { KeyPress = "Down" { Actions = "NextItem" } KeyPress = "Up" { Actions = "PrevItem" } KeyPress = "Ctrl N" { Actions = "NextItem" } KeyPress = "Ctrl P" { Actions = "PrevItem" } KeyPress = "1" { Actions = "GotoItem 1" } KeyPress = "2" { Actions = "GotoItem 2" } KeyPress = "3" { Actions = "GotoItem 3" } KeyPress = "4" { Actions = "GotoItem 4" } KeyPress = "5" { Actions = "GotoItem 5" } KeyPress = "6" { Actions = "GotoItem 6" } KeyPress = "7" { Actions = "GotoItem 7" } KeyPress = "8" { Actions = "GotoItem 8" } KeyPress = "9" { Actions = "GotoItem 9" } KeyPress = "Left" { Actions = "LeaveSubmenu" } KeyPress = "Right" { Actions = "EnterSubmenu" } KeyPress = "Return" { Actions = "Select" } KeyPress = "space" { Actions = "Select" } KeyPress = "Escape" { Actions = "Close" } KeyPress = "Q" { Actions = "Close" } } pekwm-release-0.1.18/data/menu000066400000000000000000000153701374756504400161670ustar00rootroot00000000000000# Menu config for pekwm # Variables INCLUDE = "vars" RootMenu = "Pekwm" { Entry = "Terminal" { Actions = "Exec $TERM &" } Entry = "Run.." { Actions = "ShowCmdDialog" } Separator {} Submenu = "Editors" { Entry = "emacs" { Actions = "Exec emacs" } Entry = "emacs terminal" { Actions = "Exec $TERM -title emacs -e emacs -nw" } Entry = "gedit" { Actions = "Exec gedit" } Entry = "gvim" { Actions = "Exec gvim" } Entry = "kate" { Actions = "Exec kate" } Entry = "vim" { Actions = "Exec $TERM -title vim -e vim" } } Submenu = "eMail" { Entry = "claws-mail" { Actions = "Exec claws-mail" } Entry = "evolution" { Actions = "Exec evolution" } Entry = "kmail" { Actions = "Exec kmail" } Entry = "mutt" { Actions = "Exec $TERM -e mutt" } Entry = "thunderbird" { Actions = "Exec thunderbird" } } Submenu = "Filemanager" { Entry = "dolphin" { Actions = "Exec dolphin" } Entry = "mc" { Actions = "Exec $TERM -e mc" } Entry = "nautilus" { Actions = "Exec nautilus" } Entry = "pcmanfm" { Actions = "Exec pcmanfm" } Entry = "rox" { Actions = "Exec rox" } Entry = "thunar" { Actions = "Exec thunar" } } Submenu = "Graphics" { Entry = "gimp" { Actions = "Exec gimp" } Entry = "digikam" { Actions = "Exec digikam" } Entry = "display" { Actions = "Exec display" } Entry = "eog" { Actions = "Exec eog" } Entry = "gwenview" { Actions = "Exec gwenview" } Entry = "shotwell" { Actions = "Exec shotwell" } } Submenu = "IDE" { Entry = "anjuta" { Actions = "Exec anjuta" } Entry = "eclipse" { Actions = "Exec eclipse" } Entry = "kdevelop" { Actions = "Exec kdevelop" } } Submenu = "IM" { Entry = "empathy" { Actions = "Exec empathy" } Entry = "kopete" { Actions = "Exec kopete" } Entry = "pidgin" { Actions = "Exec pidgin" } Entry = "psi" { Actions = "Exec psi" } } Submenu = "Multimedia" { Entry = "vlc" { Actions = "Exec vlc" } Entry = "amarok" { Actions = "Exec amarok" } Entry = "banshee" { Actions = "Exec banshee" } Entry = "rhythmbox" { Actions = "Exec rhythmbox" } Entry = "smplayer" { Actions = "Exec smplayer" } Entry = "alsamixer" { Actions = "Exec $TERM -title alsamixer -e alsamixer" } } Submenu = "Office" { Entry = "LOffice - Calc" { Actions = "Exec libreoffice --calc" } Entry = "LOffice - Draw" { Actions = "Exec libreoffice --draw" } Entry = "LOffice - Impress" { Actions = "Exec libreoffice --impress" } Entry = "LOffice - Writer" { Actions = "Exec libreoffice --writer" } } Submenu = "VoIP" { Entry = "ekiga" { Actions = "Exec ekiga" } Entry = "jitsi" { Actions = "Exec jitsi" } Entry = "sflphone" { Actions = "Exec sflphone" } } Submenu = "WWW" { Entry = "firefox" { Actions = "Exec firefox" } Entry = "chromium" { Actions = "Exec chromium" } Entry = "opera" { Actions = "Exec opera" } } Separator {} Entry = "Take screenshot" { Actions = "Exec $_PEKWM_SCRIPT_PATH/pekwm_screenshot.sh" } Separator {} Submenu = "Go to" { SubMenu = "Workspace" { # Create goto menu once per pekwm config reload. The fast way that # will work for most if not all users. COMMAND = "$_PEKWM_SCRIPT_PATH/pekwm_ws_menu.sh goto" # Create goto menu every time the menu is opened. The slow way. # This is what you want if you are using external tools to make # the amount of workspaces something else than what you define in # ~/.pekwm/config. You will know if you want this. # Entry = "" { Actions = "Dynamic $_PEKWM_SCRIPT_PATH/pekwm_ws_menu.sh goto dynamic" } } Entry = "Window.." { Actions = "ShowMenu GotoClient True" } } Submenu = "Pekwm" { Submenu = "Themes" { Entry { Actions = "Dynamic $_PEKWM_SCRIPT_PATH/pekwm_themeset.sh $_PEKWM_THEME_PATH" } Entry { Actions = "Dynamic $_PEKWM_SCRIPT_PATH/pekwm_themeset.sh ~/.pekwm/themes" } } Entry = "Reload" { Actions = "Reload" } Entry = "Restart" { Actions = "Restart" } Entry = "Exit" { Actions = "Exit" } Submenu = "Exit to" { Entry = "Xterm" { Actions = "RestartOther xterm" } Entry = "TWM" { Actions = "RestartOther twm" } } } } WindowMenu = "Window Menu" { Entry = "(Un)Stick" { Actions = "Toggle Sticky" } Entry = "(Un)Shade" { Actions = "Toggle Shaded" } Entry = "Iconify" { Actions = "Set Iconified" } Entry = "Command.." { Actions = "ShowCmdDialog" } Submenu = "Maximize" { Entry = "Toggle Full" { Actions = "Toggle Maximized True True" } Entry = "Toggle Horizontal" { Actions = "Toggle Maximized True False" } Entry = "Toggle Vertical" { Actions = "Toggle Maximized False True" } } Submenu = "Fill" { Entry = "Full" { Actions = "MaxFill True True" } Entry = "Horizontal" { Actions = "MaxFill True False" } Entry = "Vertical" { Actions = "MaxFill False True" } } Submenu = "Stacking" { Entry = "Raise" { Actions = "Raise" } Entry = "Lower" { Actions = "Lower" } Entry = "Toggle Always On Top" { Actions = "Toggle AlwaysOnTop" } Entry = "Toggle Always Below" { Actions = "Toggle AlwaysBelow" } } Submenu = "Decorations" { Entry = "Toggle Decorations" { Actions = "Toggle DecorBorder; Toggle DecorTitlebar" } Entry = "Toggle Borders" { Actions = "Toggle DecorBorder" } Entry = "Toggle Titlebar" { Actions = "Toggle DecorTitlebar" } } Submenu = "Skip" { Entry = "Toggle showing this frame in menus" { Actions = "Toggle Skip Menus" } Entry = "Toggle including this frame in focus toggle" { Actions = "Toggle Skip FocusToggle" } Entry = "Toggle if this frame snaps to other windows" { Actions = "Toggle Skip Snap" } } SubMenu = "Send To" { # Create sendto menu once per pekwm config reload. The fast way that # will work for most if not all users. COMMAND = "$_PEKWM_SCRIPT_PATH/pekwm_ws_menu.sh send" # Create sendto menu every time the menu is opened. The slow way. # This is what you want if you are using external tools to make # the amount of workspaces something else than what you define in # ~/.pekwm/config. You will know if you want this. # Entry = "" { Actions = "Dynamic $_PEKWM_SCRIPT_PATH/pekwm_ws_menu.sh send dynamic" } } Separator {} Entry = "Close" { Actions = "Close" } Submenu = "Kill" { Entry = "Kill application" { Actions = "Kill" } } } LayoutMenu = "Layout" { Entry = "Smart" { Actions = "SetLayouter Smart" } Entry = "Mouse Not Under" { Actions = "SetLayouter MouseNotUnder" } Entry = "Mouse Centered" { Actions = "SetLayouter MouseCentered" } Entry = "Mouse Top Left" { Actions = "SetLayouter MouseTopLeft" } Separator {} Entry = "Layout Horizontal" { Actions = "SetLayouter TILE_Horizontal" } Entry = "Layout Vertical" { Actions = "SetLayouter TILE_Vertical" } Entry = "Layout Dwindle" { Actions = "SetLayouter TILE_Dwindle" } Entry = "Layout Stacked" { Actions = "SetLayouter TILE_Stacked" } Entry = "Layout Center One" { Actions = "SetLayouter TILE_CenterOne" } Entry = "Layout Boxed" { Actions = "SetLayouter TILE_Boxed" } Entry = "Layout Fib" { Actions = "SetLayouter TILE_Fib" } } pekwm-release-0.1.18/data/mouse000066400000000000000000000010211374756504400163370ustar00rootroot00000000000000# Swap comments on the two following lines to switch betwen # click does not raise and click to raise. $CLIENT_CLICK = "Focus" # $CLIENT_CLICK = "Focus; Raise" # Base mouse configuration INCLUDE = "$_PEKWM_ETC_PATH/mouse_system" # Swap comments on the two folling lines to switch between # sloppy and click to focus INCLUDE = "$_PEKWM_ETC_PATH/mouse_sloppy" # INCLUDE = "$_PEKWM_ETC_PATH/mouse_click" # Add configuration overrides here, it possible to add sections, # sub-section and values overriding/adding specific values. pekwm-release-0.1.18/data/mouse_click000066400000000000000000000000071374756504400175070ustar00rootroot00000000000000# Emptypekwm-release-0.1.18/data/mouse_sloppy000066400000000000000000000011571374756504400177570ustar00rootroot00000000000000FrameTitle { Enter = "Any Any" { Actions = "Focus" } } OtherTitle { Enter = "Any Any" { Actions = "Focus" } } Border { TopLeft { Enter = "Any Any" { Actions = "Focus" } } Top { Enter = "Any Any" { Actions = "Focus" } } TopRight { Enter = "Any Any" { Actions = "Focus" } } Left { Enter = "Any Any" { Actions = "Focus" } } Right { Enter = "Any Any" { Actions = "Focus" } } BottomLeft { Enter = "Any Any" { Actions = "Focus" } } Bottom { Enter = "Any Any" { Actions = "Focus" } } BottomRight { Enter = "Any Any" { Actions = "Focus" } } } Client { Enter = "Any Any" { Actions = "Focus" } }pekwm-release-0.1.18/data/mouse_system000066400000000000000000000165651374756504400177660ustar00rootroot00000000000000FrameTitle { ButtonRelease = "1" { Actions = "Raise; Focus; ActivateClient" } ButtonRelease = "Mod1 1" { Actions = "Focus; Raise" } ButtonRelease = "Mod4 1" { Actions = "Focus; Raise" } ButtonRelease = "2" { Actions = "ActivateClient" } ButtonRelease = "Mod4 3" { Actions = "Close" } ButtonRelease = "3" { Actions = "ShowMenu Window" } ButtonRelease = "4" { Actions = "ActivateClientRel 1" } ButtonRelease = "5" { Actions = "ActivateClientRel -1" } ButtonRelease = "Mod1 4" { Actions = "SendToWorkspace Next; GotoWorkspace Next" } ButtonRelease = "Mod1 5" { Actions = "SendToWorkspace Prev; GotoWorkspace Prev" } ButtonRelease = "Mod1 Shift 4" { Actions = "SendToWorkspace PrevV; GotoWorkspace PrevV" } ButtonRelease = "Mod1 Shift 5" { Actions = "SendToWorkspace NextV; GotoWorkspace NextV" } ButtonRelease = "Ctrl 4" { Actions = "MoveClientRel 1" } ButtonRelease = "Ctrl 5" { Actions = "MoveClientRel -1" } ButtonRelease = "Ctrl Mod1 1" { Actions = "Focus; Raise True" } DoubleClick = "2" { Actions = "Toggle Shaded" } DoubleClick = "Mod1 2" { Actions = "Toggle Shaded" } DoubleClick = "1" { Actions = "MaxFill True True" } DoubleClick = "Mod1 1" { Actions = "Toggle Maximized True True" } Motion = "1" { Threshold = "4"; Actions = "Raise; Move" } Motion = "Mod1 1" { Threshold = "4"; Actions = "Raise; Move" } Motion = "Mod4 1" { Threshold = "4"; Actions = "Raise; Move" } Motion = "2" { Threshold = "4"; Actions = "GroupingDrag True" } Motion = "Mod1 3" { Actions = "Resize" } } OtherTitle { ButtonRelease = "1" { Actions = "Raise; Focus" } ButtonRelease = "2" { Actions = "Focus" } ButtonRelease = "3" { Actions = "Close" } ButtonRelease = "Mod4 3" { Actions = "ShowMenu Window" } ButtonRelease = "Mod1 4" { Actions = "SendToWorkspace Next; GotoWorkspace Next" } ButtonRelease = "Mod1 5" { Actions = "SendToWorkspace Prev; GotoWorkspace Prev" } ButtonRelease = "Mod1 Shift 4" { Actions = "SendToWorkspace PrevV; GotoWorkspace PrevV" } ButtonRelease = "Mod1 Shift 5" { Actions = "SendToWorkspace NextV; GotoWorkspace NextV" } Motion = "1" { Threshold = "4"; Actions = "Raise; Move" } Motion = "Mod1 1" { Threshold = "4"; Actions = "Raise; Move" } Motion = "Mod4 1" { Threshold = "4"; Actions = "Raise; Move" } } Border { TopLeft { ButtonPress = "1" { Actions = "Focus; Resize TopLeft" } } Top { ButtonPress = "1" { Actions = "Focus; Resize Top" } } TopRight { ButtonPress = "1" { Actions = "Focus; Resize TopRight" } } Left { ButtonPress = "1" { Actions = "Focus; Resize Left" } } Right { ButtonPress = "1" { Actions = "Focus; Resize Right" } } BottomLeft { ButtonPress = "1" { Actions = "Focus; Resize BottomLeft" } } Bottom { ButtonPress = "1" { Actions = "Focus; Resize Bottom" } } BottomRight { ButtonPress = "1" { Actions = "Focus; Resize BottomRight" } } } ScreenEdge { Down { Enter = "Mod1 Any" { Actions = "GoToWorkspace Down" } ButtonRelease = "3" { Actions = "ShowMenu Root" } ButtonRelease = "2" { Actions = "ShowMenu Goto" } ButtonRelease = "1" { Actions = "GoToWorkspace Down" } ButtonRelease = "Mod4 2" { Actions = "ShowMenu GotoClient" } ButtonRelease = "4" { Actions = "GoToWorkspace Up" } ButtonRelease = "5" { Actions = "GoToWorkspace Down" } ButtonRelease = "Mod1 4" { Actions = "GoToWorkspace PrevV" } ButtonRelease = "Mod1 5" { Actions = "GoToWorkspace NextV" } EnterMoving = "Any Any" { Actions = "WarpToWorkspace Down" } } Up { Enter = "Mod1 Any" { Actions = "GoToWorkspace Up" } ButtonRelease = "3" { Actions = "ShowMenu Root" } ButtonRelease = "2" { Actions = "ShowMenu Goto" } ButtonRelease = "1" { Actions = "GoToWorkspace Up" } ButtonRelease = "Mod4 2" { Actions = "ShowMenu GotoClient" } ButtonRelease = "4" { Actions = "GoToWorkspace Up" } ButtonRelease = "5" { Actions = "GoToWorkspace Down" } ButtonRelease = "Mod1 4" { Actions = "GoToWorkspace PrevV" } ButtonRelease = "Mod1 5" { Actions = "GoToWorkspace NextV" } EnterMoving = "Any Any" { Actions = "WarpToWorkspace Up" } } Left { Enter = "Mod1 Any" { Actions = "GoToWorkspace Left" } ButtonRelease = "3" { Actions = "ShowMenu Root" } ButtonRelease = "1" { Actions = "GoToWorkspace Left" } DoubleClick = "1" { Actions = "GoToWorkspace Left" } ButtonRelease = "2" { Actions = "ShowMenu Goto" } ButtonRelease = "Mod4 2" { Actions = "ShowMenu GotoClient" } ButtonRelease = "4" { Actions = "GoToWorkspace Right" } ButtonRelease = "5" { Actions = "GoToWorkspace Left" } ButtonRelease = "Mod1 4" { Actions = "GoToWorkspace Next" } ButtonRelease = "Mod1 5" { Actions = "GoToWorkspace Prev" } EnterMoving = "Any Any" { Actions = "WarpToWorkspace Left" } } Right { Enter = "Mod1 Any" { Actions = "GoToWorkspace Right" } ButtonRelease = "3" { Actions = "ShowMenu Root" } ButtonRelease = "1" { Actions = "GoToWorkspace Right" } DoubleClick = "1" { Actions = "GoToWorkspace Right" } ButtonRelease = "2" { Actions = "ShowMenu Goto" } ButtonRelease = "Mod4 2" { Actions = "ShowMenu GotoClient" } ButtonRelease = "4" { Actions = "GoToWorkspace Right" } ButtonRelease = "5" { Actions = "GoToWorkspace Left" } ButtonRelease = "Mod1 4" { Actions = "GoToWorkspace Next" } ButtonRelease = "Mod1 5" { Actions = "GoToWorkspace Prev" } EnterMoving = "Any Any" { Actions = "WarpToWorkspace Right" } } } Client { ButtonPress = "1" { Actions = "$CLIENT_CLICK" } ButtonRelease = "Mod1 1" { Actions = "Focus; Raise" } ButtonRelease = "Mod4 1" { Actions = "Lower" } ButtonRelease = "Mod1 4" { Actions = "SendToWorkspace Next; GotoWorkspace Next" } ButtonRelease = "Mod1 5" { Actions = "SendToWorkspace Prev; GotoWorkspace Prev" } ButtonRelease = "Mod1 Shift 4" { Actions = "SendToWorkspace PrevV; GotoWorkspace PrevV" } ButtonRelease = "Mod1 Shift 5" { Actions = "SendToWorkspace NextV; GotoWorkspace NextV" } ButtonRelease = "Ctrl Mod1 1" { Actions = "Focus; Raise True" } Motion = "Mod1 1" { Threshold = "4"; Actions = "Focus; Raise; Move" } Motion = "Mod4 1" { Threshold = "4"; Actions = "Focus; Raise; Move" } Motion = "Mod1 2" { Threshold = "4"; Actions = "GroupingDrag True" } Motion = "Mod1 3" { Actions = "Resize" } } Root { ButtonRelease = "3" { Actions = "ShowMenu Root" } ButtonRelease = "2" { Actions = "ShowMenu Goto" } ButtonRelease = "Mod4 2" { Actions = "ShowMenu GotoClient" } # Horizontal movement ButtonRelease = "4" { Actions = "GoToWorkspace Right" } ButtonRelease = "5" { Actions = "GoToWorkspace Left" } ButtonRelease = "Mod1 4" { Actions = "GoToWorkspace Next" } ButtonRelease = "Mod1 5" { Actions = "GoToWorkspace Prev" } # Vertical movement ButtonRelease = "Shift 4" { Actions = "GoToWorkspace Up" } ButtonRelease = "Shift 5" { Actions = "GoToWorkspace Down" } ButtonRelease = "Mod1 Shift 4" { Actions = "GoToWorkspace NextV" } ButtonRelease = "Mod1 Shift 5" { Actions = "GoToWorkspace PrevV" } # "Number" movement ButtonRelease = "Mod4 4" { Actions = "GoToWorkspace RightN" } ButtonRelease = "Mod4 5" { Actions = "GoToWorkspace LeftN" } ButtonRelease = "Mod4 Shift 4" { Actions = "GoToWorkspace NextN" } ButtonRelease = "Mod4 Shift 5" { Actions = "GoToWorkspace PrevN" } ButtonRelease = "1" { Actions = "HideAllMenus" } } Menu { Enter = "Any Any" { Actions = "Focus" } Motion = "Mod1 1" { Threshold = "4"; Actions = "Focus; Raise; Move" } } Other { Enter = "Any Any" { Actions = "Focus" } ButtonRelease = "3" { Actions = "Close" } Motion = "1" { Actions = "Focus; Raise; Move" } Motion = "Mod1 1" { Threshold = "4"; Actions = "Focus; Raise; Move" } } pekwm-release-0.1.18/data/scripts/000077500000000000000000000000001374756504400167615ustar00rootroot00000000000000pekwm-release-0.1.18/data/scripts/CMakeLists.txt000066400000000000000000000010351374756504400215200ustar00rootroot00000000000000cmake_minimum_required(VERSION 2.8) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/pekwm_themeset.sh.in ${CMAKE_CURRENT_BINARY_DIR}/pekwm_themeset.sh @ONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/pekwm_ws_menu.sh.in ${CMAKE_CURRENT_BINARY_DIR}/pekwm_ws_menu.sh @ONLY) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/pekwm_ws_menu.sh ${CMAKE_CURRENT_BINARY_DIR}/pekwm_themeset.sh pekwm_screenshot.sh DESTINATION share/pekwm/scripts PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)pekwm-release-0.1.18/data/scripts/Makefile.am000066400000000000000000000006641374756504400210230ustar00rootroot00000000000000AUTOMAKE_OPTIONS = foreign scriptsdir = $(pkgdatadir)/scripts scripts_SCRIPTS = pekwm_ws_menu.sh pekwm_themeset.sh pekwm_screenshot.sh CLEANFILES = pekwm_ws_menu.sh pekwm_themeset.sh EXTRA_DIST = pekwm_ws_menu.sh.in pekwm_themeset.sh.in pekwm_screenshot.sh CMakeLists.txt all-local: $(scripts_SCRIPTS) %.sh: %.sh.in @SED@ -e 's:\@SH\@:$(SH):g' -e 's:\@SED\@:$(SED):g' $< > $@ $(scripts_SCRIPTS): distclean-local: rm -f *\~ .\#* pekwm-release-0.1.18/data/scripts/pekwm_screenshot.sh000077500000000000000000000062171374756504400227060ustar00rootroot00000000000000#!/bin/sh # # Copyright © 2013 the pekwm development team # screenshot_scrot() { scrot -z "$1" } screenshot_xwd_netpbm() { xwd -root | xwdtopnm 2>/dev/null | pnmtopng > "$1" } screenshot_imagemagick() { import -window root "$1" } is_in_path() { which $1 >/dev/null 2>&1 return $? } detect_command() { is_in_path "scrot" if test $? -eq 0; then command="scrot" return fi is_in_path "import" if test $? -eq 0; then command="magick" return fi is_in_path "xwd" && is_in_path "xwdtopnm" && is_in_path "pnmtopng" if test $? -eq 0; then command="netpbm" return fi } usage() { echo "usage: pekwm_screenshot.sh [-c scrot|netpbm|magick] [-d delay] [-o output.png]" echo "" echo " -c scrot|netpbm|magick (defaults to autodetect)" echo " Command to use when creating screenshot." echo " -d seconds (defaults to 0)" echo " Number of seconds to wait before taking screenshot" echo " -h" echo " Display this information" echo " -o output.png (defaults to ~/screenshot_YYYYMMDD_HHmmSS.png)" echo " Name of screenshot output file." echo "" exit 0 } usage_command() { if test -z "$command"; then echo "Unable to find any supported commands for taking screenshots" else echo "Unsupported screenshot command $command" fi echo "" echo "Supported screenshot commands are:" echo "" echo " * scrot, http://linuxbrit.co.uk/software/" echo " * imagemagick, http://www.imagemagick.org/" echo " * netpbm (+ xwd), http://netpbm.sourceforge.net/" echo "" exit 1 } main() { # Initialize for strict mode command="" delay="0" output="" # Parse options eval set -- "$OPTIONS" while true; do case "$1" in -c) command="$2" shift 2;; -d) delay=$((0 + $2)) shift 2;; -h) usage;; -o) output="$2" shift 2;; --) break;; esac done # No command specified, try autodetect if test -z "$command"; then detect_command if test -z "$command"; then usage_command fi fi # No output specified, format if test -z "$output"; then output="$HOME/screenshot_$(date '+%Y%m%d_%H%M%S').png" fi # Wait for N seconds if specified if test "$delay" -ne "0"; then echo "Taking screenshot in $delay seconds..." sleep $delay fi # Grab screenshot case "$command" in scrot) screenshot_scrot $output ;; magick) screenshot_imagemagick $output ;; netpbm) screenshot_xwd_netpbm $output ;; *) usage_command ;; esac if test $? -eq 0; then echo "Successfully captured screen to $output" else echo "Failed to capture screen to $output!" fi exit 0 } OPTIONS=$(getopt -o c:d:ho: -n 'pekwm_screenshot.sh' -- "$@") main pekwm-release-0.1.18/data/scripts/pekwm_themeset.sh.in000077500000000000000000000040041374756504400227440ustar00rootroot00000000000000#!@SH@ # # Copyright © 2003-2009 the pekwm development team # # Add this to your menu to use this script: # # SubMenu = "Themes" { # Entry { Actions = "Dynamic /path/to/this/file /path/to/themedir" } # } # # Check usage if test -z "${1}"; then echo "usage: $0 /path/to/themedir (theme)"; exit 1 fi if test -z "${2}"; then theme_dir="${1}" echo "Dynamic {" # Check that theme directory exists, if it does not exist create a # dummy entry that says the dir does not exist. if test -d "${theme_dir}"; then ( cd ${theme_dir}; for theme_name in *; do # Themes must be directories. This test also prevents * globbing # problems if theme_dir is empty. if test -d "${theme_name}"; then theme_path="${theme_dir}/${theme_name}" echo "Entry = \"${theme_name}\" { Actions = \"Exec ${0} ${1} ${theme_path}\" }" fi done ) else echo "Entry = \"No such directory ${theme_dir}\" { Actions = \"None\" }" fi echo "}" else # Check for configuration file, if the environment is not set the # script is not being run from pekwm, then exit with failure. if test -f "${PEKWM_CONFIG_FILE}"; then theme="$(echo "${2}" | @SED@ -e "s@^${HOME}@~@" | @SED@ -e 's/\//\\\//g')" # Get temporary file, not all platforms have mktemp though if test -x "/bin/mktemp"; then tmp_file=$(mktemp -t pekwm_themeset.XXXXXX) || exit 1; else tmp_file="/tmp/pekwm_themeset.${USER}" fi # Change theme # Literal tab-character, whitespace and double quote tab=" " wspc="\\([ $tab]*\\)" qq='\"' text='[Tt][Hh][Ee][Mm][Ee]' @SED@ -e "s/^\([^#]*\)$text$wspc=$wspc$qq[^$qq]*$qq/\1Theme\2=\3$qq${theme}$qq/" "${PEKWM_CONFIG_FILE}" > "${tmp_file}" mv "${tmp_file}" "${PEKWM_CONFIG_FILE}" # Reload pekwm kill -HUP $(xprop -root _NET_WM_PID | awk '/_NET_WM_PID/ { print $3 }') else exit 1 fi fi exit 0 pekwm-release-0.1.18/data/scripts/pekwm_ws_menu.sh.in000066400000000000000000000010471374756504400226040ustar00rootroot00000000000000#!@SH@ # # Copyright © 2009 the pekwm development team # if test "${1}" = "send"; then action="SendToWorkspace" elif test "${1}" = "goto"; then action="GotoWorkspace" else echo "usage: $0 goto|send dynamic" exit 1 fi if test "${2}" = "dynamic"; then echo "Dynamic {" fi num_workspaces="$(xprop -root _NET_NUMBER_OF_DESKTOPS | awk '{ print $3 }')" i=1; while test "${i}" -le "${num_workspaces}"; do echo "Entry = \"Workspace $i\" { Actions = \"${action} ${i}\" }" i=$(($i + 1)) done if test "${2}" = "dynamic"; then echo "}" fi pekwm-release-0.1.18/data/start000066400000000000000000000014471374756504400163600ustar00rootroot00000000000000#!/bin/sh # PekWM start file # This file is a simple shell script; It gets run on pekwm startup, after # the theme and all config has loaded if it is set executable # (chmod +x start). # # This is different from ~/.xinitrc because a normal configuration of # .xinitrc you'll run all commands, then launch the window manager last. # # It also gets re-run every time pekwm is restarted. # # As for it's usefulness, well, it's up to you. I actually set my background # from my start file; since it runs after the theme gets loaded, this # effectively overrides whatever's in the theme. # # There's probably a few other good uses for it, too. I mainly pushed for it # because when I was doing fluxbox's docs, people used to complain that there # wasn't one, and I wanted to avoid that for pekwm. ;) --eyez pekwm-release-0.1.18/data/themes/000077500000000000000000000000001374756504400165575ustar00rootroot00000000000000pekwm-release-0.1.18/data/themes/CMakeLists.txt000066400000000000000000000001651374756504400213210ustar00rootroot00000000000000cmake_minimum_required(VERSION 2.8) add_subdirectory(default) add_subdirectory(default-plain) add_subdirectory(pion)pekwm-release-0.1.18/data/themes/Makefile.am000066400000000000000000000001761374756504400206170ustar00rootroot00000000000000AUTOMAKE_OPTIONS = foreign SUBDIRS = default default-plain pion EXTRA_DIST = CMakeLists.txt disclean-local: rm -f *\~ .\#* pekwm-release-0.1.18/data/themes/default-plain/000077500000000000000000000000001374756504400213045ustar00rootroot00000000000000pekwm-release-0.1.18/data/themes/default-plain/CMakeLists.txt000066400000000000000000000001521374756504400240420ustar00rootroot00000000000000cmake_minimum_required(VERSION 2.8) install(FILES theme DESTINATION share/pekwm/themes/default-plain)pekwm-release-0.1.18/data/themes/default-plain/Makefile.am000066400000000000000000000002511374756504400233360ustar00rootroot00000000000000AUTOMAKE_OPTIONS = foreign themedir = $(pkgdatadir)/themes/default-plain theme_DATA = theme EXTRA_DIST = $(theme_DATA) CMakeLists.txt distclean-local: rm -f *\~ .\#* pekwm-release-0.1.18/data/themes/default-plain/theme000066400000000000000000000077451374756504400223460ustar00rootroot00000000000000# default theme for pekwm # # ChangeLog: # # * Update for 0.1.8 with templates enabled. # * Created for version 0.1.7 # Require { Templates = "True" } Define = "BaseDecor" { Height = "17" HeightAdapt = "True" # increase first number to bring title text downwards Pad = "2 0 2 0" Focused = "Empty" Unfocused = "Empty" Tab { Focused = "Solid #dddddd" FocusedSelected = "Solid #ffffff" Unfocused = "Solid #aaaaaa" UnfocusedSelected = "Solid #aaaaaa" } Separator { Focused = "Empty" Unfocused = "Empty" } Font { Focused = "Sans:size=12#CENTER#XFT" } FontColor { Focused = "#000000" FocusedSelected = "#000000" Unfocused = "#333333" UnfocusedSelected = "#333333" } Border { Focused { TopLeft = "Solid #000000 1x1" Top = "Solid #000000 1x1" TopRight = "Solid #000000 1x1" Left = "Solid #000000 1x1" Right = "Solid #000000 1x1" BottomLeft = "Solid #000000 1x1" Bottom = "Solid #000000 1x1" BottomRight = "Solid #000000 1x1" } Unfocused { TopLeft = "Solid #666666 1x1" Top = "Solid #666666 1x1" TopRight = "Solid #666666 1x1" Left = "Solid #666666 1x1" Right = "Solid #666666 1x1" BottomLeft = "Solid #666666 1x1" Bottom = "Solid #666666 1x1" BottomRight = "Solid #666666 1x1" } } } Define = "ButtonStates" { Focused = "Solid #ff790c 0x0" Unfocused = "Solid #999999 0x0" Pressed = "Solid #000000 0x0" Hover = "Solid #ffcea5 0x0" } Define = "ButtonStatesRemote" { @ButtonStates } Define = "ButtonStatesWarning" { @ButtonStates Focused = "Solid #ff0000 0x0" } Define = "BaseButtonDecor" { @BaseDecor Buttons { Left { @ButtonStates Button = "1" { Actions = "Close" } Button = "2" { Actions = "Kill" } } Right { @ButtonStates Button = "1" { Actions = "Toggle Maximized 1 1" } Button = "2" { Actions = "Toggle Maximized 0 1" } Button = "3" { Actions = "Toggle Maximized 1 0" } } } } PDecor { Decor = "DEFAULT" { Title { @BaseButtonDecor } } Decor = "REMOTE" { Title { @BaseButtonDecor Tab { Focused = "Solid #fffcec" FocusedSelected = "Solid #fff9d6" } Buttons { Left { @ButtonStatesRemote } Right { @ButtonStatesRemote } } } } Decor = "WARNING" { Title { @BaseButtonDecor Tab { Focused = "Solid #ee5454" FocusedSelected = "Solid #ff7474" } Buttons { Left { @ButtonStatesWarning } Right { @ButtonStatesWarning } } } } Decor = "MENU" { Title { @BaseDecor } } Decor = "WORKSPACEINDICATOR" { Title { @BaseDecor Height = "0" HeightAdapt = "False" } } } Harbour { Texture = "SolidRaised #ffffff #000000 #000000 1 0" } Menu { Pad = "2 2 2 2" Focused { Font = "Sans:size=12#XFT" Background = "Empty" Item = "Solid #ffffff 1 0" Separator = "Solid #aaaaaa 0x1" Arrow = "Solid #ff790c 4x4" Text = "#000000" } Unfocused { Font = "Sans:size=12#XFT" Background = "Empty" Item = "Solid #cccccc 1 0" Separator = "Solid #999999 0x2" Arrow = "Solid #999999 4x4" Text = "#000000" } Selected { Font = "Sans:size=12#XFT" Background = "Empty" Item = "Solid #eeeeee" Arrow = "Solid #ff790c 4x4" Text = "#000000" } } CmdDialog { Font = "Sans:size=12#CENTER#XFT" Texture = "Solid #ffffff" Text = "#000000" } Status { Font = "Sans:size=12#CENTER#XFT" Texture = "Solid #ffffff" Text = "#000000" } WorkspaceIndicator { Font = "Sans:size=12#XFT" Background = "Solid #ffffff" Workspace = "Solid #cccccc" WorkspaceActive = "Solid #aaaaaa" Text = "#000000" EdgePadding = "5" WorkspacePadding = "2" } pekwm-release-0.1.18/data/themes/default/000077500000000000000000000000001374756504400202035ustar00rootroot00000000000000pekwm-release-0.1.18/data/themes/default/CMakeLists.txt000066400000000000000000000002761374756504400227500ustar00rootroot00000000000000cmake_minimum_required(VERSION 2.8) file(GLOB default_png_files "${CMAKE_CURRENT_SOURCE_DIR}/*.png") install(FILES theme ${default_png_files} DESTINATION share/pekwm/themes/default) pekwm-release-0.1.18/data/themes/default/Makefile.am000066400000000000000000000016311374756504400222400ustar00rootroot00000000000000AUTOMAKE_OPTIONS = foreign themedir = $(pkgdatadir)/themes/default theme_DATA = theme arrow.png arrow_focus.png bottom-border.png bottom-border_unfocus.png bottom-left.png bottom-left_unfocus.png bottom-right.png bottom-right_unfocus.png button.png button_hover.png button_press.png button_unfocus.png button-close.png button-close_hover.png button-close_press.png button-max.png button-max_hover.png button-max_press.png button-min.png button-min_hover.png button-min_press.png item.png item_focus.png left-border.png left-border_unfocus.png menu-bottom.png menu-bottom_unfocus.png menuline.png right-border.png right-border_unfocus.png tab-separator.png tab-separator_unfocus.png title.png title_unfocus.png top-border.png top-border_unfocus.png top-left.png top-left_unfocus.png top-right.png top-right_unfocus.png top-right-no-buttons.png EXTRA_DIST = $(theme_DATA) CMakeLists.txt distclean-local: rm -f *\~ .\#* pekwm-release-0.1.18/data/themes/default/arrow.png000066400000000000000000000012471374756504400220470ustar00rootroot00000000000000PNG  IHDR sRGB pHYs B(xtIME #9IDAT(.yyy===hhhTTT444(((FFF+++ZZZΰrrrJJJ999BET܉IENDB`pekwm-release-0.1.18/data/themes/default/arrow_focus.png000066400000000000000000000012471374756504400232460ustar00rootroot00000000000000PNG  IHDR sRGB pHYs B(xtIME  499IDAT(.- 5 i"W ~Ak{,J!7Iw ͭSѳ ,H%=cx!6&>99eIENDB`pekwm-release-0.1.18/data/themes/default/bottom-border.png000066400000000000000000000003021374756504400234630ustar00rootroot00000000000000PNG  IHDRr $sRGBbKGD pHYs  tIME j";tEXtCommentCreated with GIMPWIDAT:?5TdwIENDB`pekwm-release-0.1.18/data/themes/default/bottom-border_unfocus.png000066400000000000000000000003021374756504400252250ustar00rootroot00000000000000PNG  IHDRr $sRGBbKGD pHYs  tIME #dtEXtCommentCreated with GIMPWIDATAyIENDB`pekwm-release-0.1.18/data/themes/default/bottom-left.png000066400000000000000000000003021374756504400231400ustar00rootroot00000000000000PNG  IHDRr $sRGBbKGD pHYs  tIME ~~ttEXtCommentCreated with GIMPWIDAT?,J2ڲIENDB`pekwm-release-0.1.18/data/themes/default/bottom-left_unfocus.png000066400000000000000000000003021374756504400247020ustar00rootroot00000000000000PNG  IHDRr $sRGBbKGD pHYs  tIME 6g׭tEXtCommentCreated with GIMPWIDATooo""""z8IENDB`pekwm-release-0.1.18/data/themes/default/bottom-right.png000066400000000000000000000002671374756504400233350ustar00rootroot00000000000000PNG  IHDRr $bKGDC pHYs  tIME*79fiTXtCommentCreated with GIMPd.eIDATc LWcuX F IENDB`pekwm-release-0.1.18/data/themes/default/bottom-right_unfocus.png000066400000000000000000000003021374756504400250650ustar00rootroot00000000000000PNG  IHDRr $sRGBbKGD pHYs  tIME uVtEXtCommentCreated with GIMPWIDAT"z^ 7IENDB`pekwm-release-0.1.18/data/themes/default/button-close.png000066400000000000000000000007721374756504400233350ustar00rootroot00000000000000PNG  IHDRmJbKGDC pHYs  tIMEDiTXtCommentCreated with GIMPd.e^IDAT8˭N0]QMi?Ve`deA0+Fh|]Ȑ?B'IENDB`pekwm-release-0.1.18/data/themes/default/button-close_hover.png000066400000000000000000000007321374756504400245340ustar00rootroot00000000000000PNG  IHDRmJbKGDC pHYs  tIME"iTXtCommentCreated with GIMPd.e>IDAT8˭N0(yQvOҽQȭQu`dbnL oLe l`(,5i6|dʣt5T&)(E,%(~z5 }|=w}y7$ `rEC Nwh3U;d+2RIXHFA(TwTH@Dx)i (D(X<~rR[C&clMJe X/:'d#7B{V#usnoRjPǏ9IENDB`pekwm-release-0.1.18/data/themes/default/button-close_press.png000066400000000000000000000007711374756504400245500ustar00rootroot00000000000000PNG  IHDRmJbKGDC pHYs  tIME9 J֮iTXtCommentCreated with GIMPd.e]IDAT8˭k@ƟPHۿJ)B(3(]Dw Kk?F$‰$]Gd6%0څ!$tIENDB`pekwm-release-0.1.18/data/themes/default/button-min_hover.png000066400000000000000000000004631374756504400242130ustar00rootroot00000000000000PNG  IHDRbKv3bKGDC pHYs  tIMECiTXtCommentCreated with GIMPd.eIDAT8cT 3hhb( #40J223#P S*yF.efCy0.eaDJTs) R3P6h ub)RD101:02"QNbjEpxKi(I}tAfS,=AcIENDB`pekwm-release-0.1.18/data/themes/default/button-min_press.png000066400000000000000000000004241374756504400242210ustar00rootroot00000000000000PNG  IHDRbKv3bKGD pHYs  tIME siTXtCommentCreated with GIMPd.exIDAT8cTʀ&002 CGpȥlCť,l4HR4p) Ui:JAwꬑ"+f````f%sDLeadfj\ 3댰C#I}t@!IENDB`pekwm-release-0.1.18/data/themes/default/button.png000066400000000000000000000010431374756504400222220ustar00rootroot00000000000000PNG  IHDRmJbKGDC pHYs  tIME4L2iTXtCommentCreated with GIMPd.eIDAT8˭JQ;3H3BϠ+WYOB02l-."ڶYԢm\%=BaBLPl1zmsg ʞ҈i2߬|`ts(*!4'3,J' kBYJmv9 ]'y9,+?rT6jgNj]q1V![z\d:MuȒA Jn5,蘒,V3x'2D:節-Z=~kBe5 "w)VKTf|Cj6^F+^2mRff|O15nTHW zdC ywqBQ91;xޣk,/ -O=IENDB`pekwm-release-0.1.18/data/themes/default/button_hover.png000066400000000000000000000031441374756504400234310ustar00rootroot00000000000000PNG  IHDRmJsRGBbKGDC pHYs  tIME\cxtEXtCommentCreated with GIMPWIDAT8K- .*@h)E պÛ,K{) 6W-K{)*Jz >g) /".;` +Eٿٿ,I , -J'A &%+!(    .ּ-׾ %=  %= ؿʧ'*̩O 3T&= ؿϯT # T~i~IENDB`pekwm-release-0.1.18/data/themes/default/button_press.png000066400000000000000000000031441374756504400234420ustar00rootroot00000000000000PNG  IHDRmJsRGBbKGDC pHYs  tIMELΏtEXtCommentCreated with GIMPWIDAT8K- .*@h)E պÛ,K{) 6W-K{)*Jz >g).;` +E,I ,  &%׾ؿʧ̩O 3T&= ؿϯT #  }"IENDB`pekwm-release-0.1.18/data/themes/default/button_unfocus.png000066400000000000000000000026111374756504400237660ustar00rootroot00000000000000PNG  IHDRZsRGBbKGD pHYs  tIME<:tEXtCommentCreated with GIMPWIDAT8&" шIENDB`pekwm-release-0.1.18/data/themes/default/item.png000066400000000000000000000021271374756504400216510ustar00rootroot00000000000000PNG  IHDR٬sRGB pHYs B(xtIME 1+񳚧IDAT(!nnnԙ uuupppߏDDD  GGGGGGXXX444쬬000OOO888DDDGGG...WWW"""['w˜IENDB`pekwm-release-0.1.18/data/themes/default/item_focus.png000066400000000000000000000012471374756504400230520ustar00rootroot00000000000000PNG  IHDR sRGB pHYs B(xtIME  +-D9IDAT(./tٻVIENDB`pekwm-release-0.1.18/data/themes/default/left-border.png000066400000000000000000000003571374756504400231230ustar00rootroot00000000000000PNG  IHDR"{sRGBbKGD pHYs  tIME @tEXtCommentCreated with GIMPWJIDAT??:`.IENDB`pekwm-release-0.1.18/data/themes/default/left-border_unfocus.png000066400000000000000000000003131374756504400246550ustar00rootroot00000000000000PNG  IHDRށsRGBbKGD pHYs  tIME ,etEXtCommentCreated with GIMPW&IDATooo!IENDB`pekwm-release-0.1.18/data/themes/default/menu-bottom.png000066400000000000000000000011371374756504400231610ustar00rootroot00000000000000PNG  IHDR×sRGB pHYs  tIME ;N.XIDATA?&bIENDB`pekwm-release-0.1.18/data/themes/default/menu-bottom_unfocus.png000066400000000000000000000011371374756504400247230ustar00rootroot00000000000000PNG  IHDR×sRGB pHYs  tIME ;mIDATooo%QASIENDB`pekwm-release-0.1.18/data/themes/default/menuline.png000066400000000000000000000010621374756504400225240ustar00rootroot00000000000000PNG  IHDR TsRGB pHYs  tIME ;;IDATF=k :IENDB`pekwm-release-0.1.18/data/themes/default/right-border.png000066400000000000000000000003571374756504400233060ustar00rootroot00000000000000PNG  IHDR"{sRGBbKGD pHYs  tIME I[MtEXtCommentCreated with GIMPWJIDAT?:01 JIENDB`pekwm-release-0.1.18/data/themes/default/tab-separator_unfocus.png000066400000000000000000000006101374756504400252140ustar00rootroot00000000000000PNG  IHDR,sRGBbKGD pHYs  tIME |tEXtCommentCreated with GIMPWIDAT'D ۢIENDB`pekwm-release-0.1.18/data/themes/default/theme000066400000000000000000000116171374756504400212360ustar00rootroot00000000000000# default-nice Pekwm theme # License: GPL # Author: adriano.src # Email: adriano.src@gmail.com # Homepage: http://adrinux.wordpress.com $FONT = "XFT#Sans:size=9#Left" $FONT_TITLE = "XFT#Sans:size=9:weight=bold#Center#1 1" Require { Templates = "True" } Define = "Border" { Focused { TopLeft = "Image top-left.png" Top = "Image top-border.png" TopRight = "Image top-right.png" Left = "Image left-border.png" Right = "Image right-border.png" BottomLeft = "Image bottom-left.png" Bottom = "Image bottom-border.png" BottomRight = "Image bottom-right.png" } Unfocused { TopLeft = "Image top-left_unfocus.png" Top = "Image top-border_unfocus.png" TopRight = "Image top-right_unfocus.png" Left = "Image left-border_unfocus.png" Right = "Image right-border_unfocus.png" BottomLeft = "Image bottom-left_unfocus.png" Bottom = "Image bottom-border_unfocus.png" BottomRight = "Image bottom-right_unfocus.png" } } Define = "BaseDecor" { Height = "20" # Increase first number to bring title text downwards Pad = "2 5 5 0" Focused = "Image title.png" Unfocused = "Image title_unfocus.png" Tab { Focused = "Image title.png" FocusedSelected = "Image title.png" Unfocused = "Image title_unfocus.png" UnfocusedSelected = "Image title_unfocus.png" } Separator { Focused = "Image tab-separator.png" Unfocused = "Image tab-separator_unfocus.png" } Font { Focused = "$FONT_TITLE" } FontColor { Focused = "#ffc571 #000000,50" FocusedSelected = "#efefef #000000,70" Unfocused = "#777777" UnfocusedSelected = "#777777" } Border { @Border } } Define = "BaseButtons" { Buttons { Right = "Close" { Focused = "Image button-close.png" Unfocused = "Image button_unfocus.png" Hoover = "Image button-close_hover.png" Pressed = "Image button-close_press.png" Button = "1" { Actions = "Close" } Button = "3" { Actions = "Kill" } } Right = "Maximize" { Focused = "Image button-max.png" Unfocused = "Image button_unfocus.png" Hoover = "Image button-max_hover.png" Pressed = "Image button-max_press.png" Button = "1" { Actions = "Toggle Maximized 1 1" } } Right = "Iconify" { Focused = "Image button-min.png" Unfocused = "Image button_unfocus.png" Hoover = "Image button-min_hover.png" Pressed = "Image button-min_press.png" Button = "1" { Actions = "Set Iconified" } } } } Define = "EmptyDecor" { Height = "0" Focused = "Empty" Unfocused = "Empty" Tab { Focused = "Empty" FocusedSelected = "Empty" Unfocused = "Empty" UnfocusedSelected = "Empty" } Separator { Focused = "Empty" Unfocused = "Empty" } Font { Focused = "Empty" } FontColor { Focused = "Empty" FocusedSelected = "Empty" Unfocused = "Empty" UnfocusedSelected = "Empty" } Border { Focused { TopLeft = "Empty" Top = "Empty" TopRight = "Empty" Left = "Empty" Right = "Empty" BottomLeft = "Empty" Bottom = "Empty" BottomRight = "Empty" } Unfocused { TopLeft = "Empty" Top = "Empty" TopRight = "Empty" Left = "Empty" Right = "Empty" BottomLeft = "Empty" Bottom = "Empty" BottomRight = "Empty" } } } Define = "BorderOnly" { @EmptyDecor Border { @Border Focused { TopRight = "Image top-right-no-buttons.png" } } } PDecor { Decor = "Default" { Title { @BaseDecor @BaseButtons } } Decor = "Menu" { Title { @BaseDecor Border { Focused { TopRight = "Image top-right-no-buttons.png" } } } } Decor = "Titlebarless" { Title { @BorderOnly } } Decor = "Statuswindow" { Title { @EmptyDecor } } Decor = "WorkspaceIndicator" { Title { @BorderOnly } } } Harbour { Texture = "Solid #f9f9f9" } Menu { Pad = "0 0 4 4" Focused { Font = "$FONT" Background = "Solid #f9f9f9" Item = "Empty" Text = "#8b8b89" Separator = "Image menuline.png#Scaled" Arrow = "Image arrow.png" } Unfocused { Font = "$FONT" Background = "Solid #f9f9f9" Item = "Empty" Text = "#777777" Separator = "Image menuline.png#Scaled" Arrow = "Image arrow.png" } Selected { Font = "$FONT" Background = "Solid #f88408" Item = "Image item_focus.png" Text = "#ffffff" Arrow = "Image arrow_focus.png" } } CmdDialog { Font = "$FONT" Texture = "Solid #ffffff" Text = "#000000" Pad = "3 0 1 10" } Status { Font = "$FONT" Texture = "Solid #ffffff" Text = "#8b8b89" Pad = "2 2 10 10" } WorkspaceIndicator { Font = "$FONT_TITLE" Background = "Solid #ffffff" Workspace = "Solid #cccccc" WorkspaceActive = "Solid #aaaaaa" Text = "#000000" EdgePadding = "5" WorkspacePadding = "2" }pekwm-release-0.1.18/data/themes/default/title.png000066400000000000000000000003541374756504400220340ustar00rootroot00000000000000PNG  IHDR|ksRGBbKGD pHYs  tIME:).ރtEXtCommentCreated with GIMPWGIDAT(cT`b *`a`dP#33@ lFL`bT3 f46 yx8ޠoIENDB`pekwm-release-0.1.18/data/themes/default/title_unfocus.png000066400000000000000000000020641374756504400235760ustar00rootroot00000000000000PNG  IHDR [,hsRGBbKGD pHYs  tIME "+jftEXtCommentCreated with GIMPWIDAT({ tIENDB`pekwm-release-0.1.18/data/themes/default/top-border.png000066400000000000000000000003321374756504400227640ustar00rootroot00000000000000PNG  IHDRj]sRGBbKGD pHYs  tIME  8<ȱtEXtCommentCreated with GIMPW5IDAT*>m?@VIENDB`pekwm-release-0.1.18/data/themes/default/top-border_unfocus.png000066400000000000000000000003521374756504400245300ustar00rootroot00000000000000PNG  IHDR`sRGBbKGD pHYs  tIME tEXtCommentCreated with GIMPWEIDAT:lllS ,ZIENDB`pekwm-release-0.1.18/data/themes/default/top-left.png000066400000000000000000000004611374756504400224440ustar00rootroot00000000000000PNG  IHDR=sRGBbKGD pHYs  tIME  ftEXtCommentCreated with GIMPWIDATӅ; PEDH-@ؤvMنkH%E,O|*̹wFxLS $oKt5uʻE@|<Z͞Iް"R!>/7p%ąيEȗ7H;w-t-wYgC IENDB`pekwm-release-0.1.18/data/themes/default/top-left_unfocus.png000066400000000000000000000010461374756504400242060ustar00rootroot00000000000000PNG  IHDR=sRGBbKGD pHYs  tIME *<tEXtCommentCreated with GIMPWIDATvoooooo999.C;&*IENDB`pekwm-release-0.1.18/data/themes/default/top-right-no-buttons.png000066400000000000000000000010461374756504400247350ustar00rootroot00000000000000PNG  IHDR=sRGBbKGD pHYs  tIME 8tEXtCommentCreated with GIMPWIDATv??`4J ~+  hGIENDB`pekwm-release-0.1.18/data/themes/default/top-right.png000066400000000000000000000004511374756504400226260ustar00rootroot00000000000000PNG  IHDR=bKGDC pHYs  tIME-i= iTXtCommentCreated with GIMPd.eIDATӅ=@FZ,^+Z;*j:[/Q ű` ?qyyG9-2.OSH*@S=;hc0`Ll ܶ"FxG4QS v G}ǃoѾ@{ /CM{NeSIENDB`pekwm-release-0.1.18/data/themes/default/top-right_unfocus.png000066400000000000000000000010461374756504400243710ustar00rootroot00000000000000PNG  IHDR=sRGBbKGD pHYs  tIME' AtEXtCommentCreated with GIMPWIDATvoooooo t#}IENDB`pekwm-release-0.1.18/data/themes/pion/000077500000000000000000000000001374756504400175245ustar00rootroot00000000000000pekwm-release-0.1.18/data/themes/pion/CMakeLists.txt000066400000000000000000000001421374756504400222610ustar00rootroot00000000000000cmake_minimum_required(VERSION 2.8) install(FILES theme DESTINATION share/pekwm/themes/pion) pekwm-release-0.1.18/data/themes/pion/Makefile.am000066400000000000000000000002401374756504400215540ustar00rootroot00000000000000AUTOMAKE_OPTIONS = foreign themedir = $(pkgdatadir)/themes/pion theme_DATA = theme EXTRA_DIST = $(theme_DATA) CMakeLists.txt distclean-local: rm -f *\~ .\#* pekwm-release-0.1.18/data/themes/pion/theme000066400000000000000000000075761374756504400205700ustar00rootroot00000000000000# # pekwm theme for ordinary and tiling mode, based on pwm_brownsteel # and ion_cleanice themes modelled after PWM and ION themes. # $FONT = "XFT#Sans:size=9#Left" $FONT_TITLE = "XFT#Sans:size=9#Center" Require { Templates = "True" } Define = "BaseDecor" { Height = "20" Pad = "2 5 2 5" Font { Focused = "$FONT_TITLE" } FontColor { Focused = "#ffc571" FocusedSelected = "white" Unfocused = "#777777" UnfocusedSelected = "#777777" } Separator { Focused = "EMPTY" Unfocused = "EMPTY" } Border { Focused { TopLeft = "Solid #303030 1x1" Top = "Solid #303030 1x1" TopRight = "Solid #303030 1x1" Left = "Solid #303030 1x1" Right = "Solid #303030 1x1" BottomLeft = "Solid #303030 1x1" Bottom = "Solid #303030 1x1" BottomRight = "Solid #303030 1x1" } Unfocused { TopLeft = "Solid #303030 1x1" Top = "Solid #303030 1x1" TopRight = "Solid #303030 1x1" Left = "Solid #303030 1x1" Right = "Solid #303030 1x1" BottomLeft = "Solid #303030 1x1" Bottom = "Solid #303030 1x1" BottomRight = "Solid #303030 1x1" } } } Define = "BaseButtons" { Buttons { } } Define = "EmptyDecor" { Focused = "Empty" Unfocused = "Empty" Tab { Focused = "Empty" FocusedSelected = "Empty" Unfocused = "Empty" UnfocusedSelected = "Empty" } Font { Focused = "Empty" } FontColor { Focused = "Empty" FocusedSelected = "Empty" Unfocused = "Empty" UnfocusedSelected = "Empty" } Border { Focused { TopLeft = "Empty" Top = "Empty" TopRight = "Empty" Left = "Empty" Right = "Empty" BottomLeft = "Empty" Bottom = "Empty" BottomRight = "Empty" } Unfocused { TopLeft = "Empty" Top = "Empty" TopRight = "Empty" Left = "Empty" Right = "Empty" BottomLeft = "Empty" Bottom = "Empty" BottomRight = "Empty" } } } PDecor { Decor = "Default" { Title { @BaseDecor @BaseButtons WidthMin = "150" WidthMax = "95" WidthSymetric = "true" Tab { Focused = "SolidRaised #586468 #f8fcf8 #f8fcf8 0 0 1x1" FocusedSelected = "SolidRaised #889898 #f8fcf8 0 0 1x1" Unfocused = "SolidRaised #505c70 #b8bcb8 #b8bcb8 0 0 1x1" UnfocusedSelected = "SolidRaised #283038 #b8bcb8 #b8bcb8 0 0 1x1" } } } Decor = "Tiling" { Title { @BaseDecor Pad = "2 0 2 0" Tab { Focused = "SolidRaised #586468 #f8fcf8 #f8fcf8 0 0 1x1" FocusedSelected = "SolidRaised #889898 #f8fcf8 0 0 1x1" Unfocused = "SolidRaised #505c70 #b8bcb8 #b8bcb8 0 0 1x1" UnfocusedSelected = "SolidRaised #283038 #b8bcb8 #b8bcb8 0 0 1x1" } } } Decor = "Menu" { Title { @BaseDecor Focused = "SolidRaised #586468 #f8fcf8 #f8fcf8 0 0 1x1" Unfocused = "SolidRaised #505c70 #b8bcb8 #b8bcb8 0 0 1x1" } } Decor = "Titlebarless" { Title { @EmptyDecor } } Decor = "Statuswindow" { Title { @EmptyDecor } } } Harbour { Texture = "Solid #f9f9f9" } Menu { Pad = "0 0 4 4" Focused { Font = "$FONT" Background = "Solid #f8fcf8" Item = "Solid #ffffff" Text = "#111111" Separator = "Solid #888888 0x1" Arrow = "Image #111111 2x2" } Unfocused { Font = "$FONT" Background = "Solid #b8bcb8" Item = "Solid #cccccc" Text = "#555555" Separator = "Solid #303030 0x1" Arrow = "Image #555555 2x2" } Selected { Font = "$FONT" Background = "Empty" Item = "SolidRaised #bbbbbb #666666 #666666 1 0" Text = "#ffffff" Arrow = "Solid #111111 2x2" } } CmdDialog { Font = "$FONT" Texture = "Solid #ffffff" Text = "#000000" Pad = "3 0 1 10" } Status { Font = "$FONT" Texture = "Solid #ffffff" Text = "#8b8b89" Pad = "2 2 10 10" } pekwm-release-0.1.18/data/vars000066400000000000000000000000601374756504400161640ustar00rootroot00000000000000$TERM="xterm -fn fixed +sb -bg white -fg black" pekwm-release-0.1.18/doc/000077500000000000000000000000001374756504400151265ustar00rootroot00000000000000pekwm-release-0.1.18/doc/CMakeLists.txt000066400000000000000000000001321374756504400176620ustar00rootroot00000000000000cmake_minimum_required(VERSION 2.8) install(FILES pekwm.1 DESTINATION share/man/man1)pekwm-release-0.1.18/doc/Makefile.am000066400000000000000000000001721374756504400171620ustar00rootroot00000000000000AUTOMAKE_OPTIONS = foreign man_MANS = pekwm.1 EXTRA_DIST = $(man_MANS) CMakeLists.txt distclean-local: rm -f *\~ .\#* pekwm-release-0.1.18/doc/book/000077500000000000000000000000001374756504400160605ustar00rootroot00000000000000pekwm-release-0.1.18/doc/book/abstract.xml000066400000000000000000000002021374756504400203770ustar00rootroot00000000000000 This document aims to be a complete documentation of the pekwm window manager. pekwm-release-0.1.18/doc/book/authorgroup.xml000066400000000000000000000005001374756504400211540ustar00rootroot00000000000000Authors: ClaesNästén RandoChristensen JyriJokinen pekwm-release-0.1.18/doc/book/book.ent000066400000000000000000000017711374756504400175300ustar00rootroot00000000000000 pekwm-release-0.1.18/doc/book/book.xml000066400000000000000000000001161374756504400175320ustar00rootroot00000000000000&book-info; &overview; &usage; &config; &development; &faq; pekwm-release-0.1.18/doc/book/bookinfo.xml000066400000000000000000000005331374756504400204110ustar00rootroot00000000000000 documentation for version pekwm-¤t-version;, last updated &releasedate;. &book-info-authorgroup; &book-info-copyright; &book-info-abstract; pekwm-release-0.1.18/doc/book/copyright.xml000066400000000000000000000001501374756504400206060ustar00rootroot00000000000000 2002-2013 ©right-holder; pekwm-release-0.1.18/doc/book/legalnotice.xml000066400000000000000000000002001374756504400210600ustar00rootroot00000000000000 Copyright © 2002-2013 ©right-holder; All rights reserved. pekwm-release-0.1.18/doc/config/000077500000000000000000000000001374756504400163735ustar00rootroot00000000000000pekwm-release-0.1.18/doc/config/autoprops/000077500000000000000000000000001374756504400204275ustar00rootroot00000000000000pekwm-release-0.1.18/doc/config/autoprops/advanced.xml000066400000000000000000000346661374756504400227350ustar00rootroot00000000000000 Advanced Autoproperties Below is a list of the different actions available to you in your autoproperties file; These are the actual Auto Properties. They can take four types of arguments: bool, integer, string, or geom. A bool is either True (1) or False (0). An Integer is a number, negative or positive. A string is any string, it's used as an identifier. Finally, geom is an X Geometry String by the form: "[=][<width>{xX}<height>][{+-}<xoffset>{+-}<yoffset>]" (see: man 3 XParseGeometry). Examples are 200x300+0+0, 0x500+200+300, 20x10+0+50, et cetera. Exhaustive Autoprops List AllowedActions (string) , DisallowedActions (string) A list of actions to allow/deny performing on a client. "Move" ((Dis)allow moving of the client window) "Resize" ((Dis)allow resizing of the client window) "Iconify" ((Dis)allow iconifying of the client window) "Shade" ((Dis)allow shading of the client window) "Stick" ((Dis)allow setting sticky state on the client window) "MaximizeHorizontal" ((Dis)allow maximizing the client window horizontally) "MaximizeVertical" ((Dis)allow maximizing the client window vertically) "Fullscreen" ((Dis)allow setting the client window in fullscreen mode) "SetWorkspace" ((Dis)allow changing of workspace) "Close" ((Dis)allow closing) ApplyOn (string) A list of conditions of when to apply this autoprop (so be sure to include this in your property), consisting of "New" (Applies when the application first starts) "Reload" (Apply when pekwm's config files are reloaded) "Start" (Apply if window already exists before pekwm starts/restarts. Note when using grouping Start will not take workspaces in account) "Transient" (Apply to Transient windows as well as normal windows. Dialog boxes are commonly transient windows) "TransientOnly" (Apply to Transient windows only. Dialog boxes are commonly transient windows) "Workspace" (Apply when the window is sent to another workspace) Border (bool) Window starts with a border CfgDeny (string) A list of conditions of when to deny things requested by the client program, consisting of "Above" (Ignore client request to always place window above other windows) "ActiveWindow" (Ignore client requests for showing and giving input focus) "Below" (Ignore client request to always place window below other windows) "Fullscreen" (Ignore client request to set window to fullscreen mode) "Hidden" (Ignore client request to show/hide window) "MaximizedHorz" (Ignore client request to maximize window horizontally) "MaximizedVert" (Ignore client request to maximize window vertically) "Position" (Ignore client requested changes to window position) "Size" (Ignore client requested changes to window size) "Stacking" (Ignore client requested changes to window stacking) "Strut" (Ignore client request for reserving space in the screen corners, typically done by panels and the like) "Tiling" (Tiling layouters should leave this window floating) ClientGeometry (geom) X Geometry String showing the initial size and position of the client, excluding the possible pekwm titlebar and window borders. Decor (string) Use the specified decor for this window. The decor has to be defined in the used theme. The decor is chosen by the first match in order: AutoProperty, TypeRules, DecorRules. Focusable (bool) Toggles if this client can be focused while it's running. FocusNew (bool) Toggles if this client gets focused when it initially pops up a window. FrameGeometry (geom) X Geometry String showing the initial size and position of the window frame. Window frame includes the client window and the possible pekwm titlebar and window borders. If both ClientGeometry and FrameGeometry are present, FrameGeometry overrides the ClientGeometry. Fullscreen (bool) Window starts in fullscreen mode Group (string) Defines the name of the group. Also the section that contains all the grouping options. They are: Behind (bool) - If true makes new clients of a group not to become the active one in the group. FocusedFirst (bool) - If true and there are more than one frame where the window could be autogrouped into, the currently focused frame is considered the first option. Global (bool) - If true makes new clients start in a group even if the group is on another workspace or iconified. Raise (bool) - If true makes new clients raise the frame they open in. Size (integer) - How many clients should be grouped in one group. Iconified (bool) Window starts Iconified Layer (string) Windows layer. Makes the window stay under or above other windows. Default layer is "Normal". Possible parameters are (listed from the bottommost to the uppermost): Desktop Below Normal OnTop Harbour AboveHarbour Menu MaximizedHorizontal (bool) Window starts Maximized Horizontally MaximizedVertical (bool) Window starts Maximized Vertically Opacity (int int) Sets the focused and unfocused opacity values for the window. A value of 100 means completely opaque, while 0 stands for completely transparent. Note that a Composite Manager needs to be running for this feature to take effect. PlaceNew (bool) Toggles the use of placing rules for this client. Role (string) Apply this autoproperty on clients that have a WM_WINDOW_ROLE hint that matches this string. String is a regexp like: "^Main". Shaded (bool) Window starts Shaded Skip (string) A list of situations when to ignore the defined application and let the user action skip over it, consisting of "Snap" (Do not snap to this window while moving windows) "Menus" (Do not show this window in pekwm menus other than the icon menu) "FocusToggle" (Do not focus to this window when doing Next/PrevFrame) Sticky (bool) Window starts Sticky (present on all workspaces) Title (string) Apply this autoproperty on clients that have a title that matches this string. String is a regexp like: "^Saving". Titlebar (bool) Window starts with a TitleBar Workspace (integer) Which workspace to start program on. pekwm-release-0.1.18/doc/config/autoprops/autoprops.xml000066400000000000000000000005171374756504400232100ustar00rootroot00000000000000 Autoproperties &config-autoprops-what; &config-autoprops-basic; &config-autoprops-adv; &config-autoprops-groups; &config-autoprops-types; &config-autoprops-help; pekwm-release-0.1.18/doc/config/autoprops/basic.xml000066400000000000000000000156661374756504400222500ustar00rootroot00000000000000 Basic Autoproperties Syntax The ~/.pekwm/autoproperties file follows the rules in . This file can become rather complicated, but it's also the most powerful of any of pekwm's config files. The one important thing to remember is the Property tag. This identifier tells us where to apply properties. It means which windows to apply it on. To find out the two terms, use xprop WM_CLASS and click on your window. Below you'll find a bash/zsh function which will give you the correct string for this file. You can also specify a regexp wildcard, such as ".*,opera", which means anything for the first word, opera for the second. propstring () { echo -n 'Property ' xprop WM_CLASS | sed 's/.*"\(.*\)", "\(.*\)".*/= "\1,\2" {/g' echo '}' } Autoproperties have an both an old and new style matching clients. The new style was introduced to support using configuration template overwriting. In addition with WM_CLASS, pekwm also can identify clients by their title string (xprop WM_NAME or xprop _NET_WM_NAME). # New syntax, requires Require { Templates = "True" } Property = "^dillo,^Dillo,,Dillo: pekwm.org - not just another windowmanager" { ApplyOn = "Start New" Layer = "OnTop" } # Old syntax Property = "^dillo,^Dillo" { Title = "Dillo: pekwm.org - not just another windowmanager" ApplyOn = "Start New" Layer = "OnTop" } Or by their role (xprop WM_WINDOW_ROLE): # New syntax, requires Require { Templates = "True" } Property = "^gaim,^Gaim,preferences" { ApplyOn = "New" Skip = "Menus" } # Old syntax Property = "^gaim,^Gaim" { Role = "preferences" ApplyOn = "New" Skip = "Menus" } Pekwm can rewrite window titles. This is done in a separate TitleRules section, where one defines properties on which clients to use the rewriting and then a regexp rule of what to do to that clients title. These rules do not affect the actual WM_NAME string. You can use Role and Title keywords to narrow down the clients the titlerule applies to. A simple rule that would change "Title: this is the title" to "this is the title" looks like this: TitleRules { Property = "^foo,^bar" { Rule = "/Title: (.*)/\\1/" } } In pekwm, you can make certain windows have their own decoration set. The different decorations are defined in the theme, and they are connected to client windows with an autoproperty. These autoproperties reside in their own DecorRules subsection and look like this: DecorRules { Property = "^foo,^bar" { Decor = "TERM" } } It's also possible to decide the order of applications that start in the harbour. As with TitleRules and DecorRules, there is it's own separate section for this purpose called Harbour. Position is a signed int and order goes: "1 2 3 0 0 0 -3 -2 -1", and so on. That looked cryptic. Worry not. Basically, a Position number of 0 means the application will be placed in the middle. If the number is positive, the application will be placed before the zero-positioned applications. If the number is negative, the applications will be placed after the zero-position ones. So the positive numbered show up first in your harbour, then the zero numbered, and after the zeros come the negatively numbered applications. I hope that is clear, the next part is tricky. The larger the value of the base number the closer to the zero applications they will be. So the smaller the base number the closer to the ends of the harbour the application will be. Position 1 would be the first application to show up on the harbour. And similarly Position -1 would be the last application on the harbour. If you have application on the harbour that do not match any of the property rules on the Harbour section, they will act as if you had given them Position 0. Applications with the same Position will show up next to each other in the order they are launched. In our example below, obpager will always be placed the last on the harbour. Harbour { Property = "^obpager,^obpager" { Position = "-1"; } } If you want certain autoproperties to be only applied when you are on a specific workspace, you can add a workspace section. The following example sets an autoproperty that removes the border and titlebar from xterm on the second and third workspace. Please keep in mind that we start counting with 0. Workspace = "1 2" { Property = "xterm,XTerm" { ApplyOn = "Start New Reload" Border = "False" Titlebar = "False" } } Here's an example ~/.pekwm/autoproperties file: Property = ".*,^xmms" { ApplyOn = "Start New" Layer = "0" Sticky = "True" } Property = "^xclock,^XClock" { ApplyOn = "Start New" FrameGeometry = "100x100+0-0" Border = "False"; Titlebar = "False" Sticky = "True" Layer = "Desktop" } Property = "^dillo,^Dillo" { ApplyOn = "Start New" Group = "browsers" { Size = "30" Behind = "True" Global = "False" } } TitleRules { Property = "^dillo,^Dillo" { Rule = "/Dillo: (.*)/\\1 [dillo]/" } Property = "^opera,^opera" { Rule = "/...:... - (.*) - Opera .*/\\1 [opera]/" } } DecorRules { Property = "^.term,^XTerm" { Decor = "TERM" } } Harbour { Property = "^obpager,^obpager" { Position = "-1" } } Regular Expressions! The pekwm autoproperties file uses Regular Expression syntax for wildcards. Regular expressions can be really confusing to people with no experience with them. A good rule of thumb is: "Anywhere you'd think to use '*', use '.*'". Also, '^' matches the beginning of a string, '$' matches the end, and '.' is any single character. Pekwm has some special flags to that modifies regular expression matching. Specifying regular expressions in the form /pattern/flags allow flags to be set. The supported flags are ! for inverting the match and i for case insensitive matches. Explaining the syntax of regular expressions goes beyond the scope of this documentation. You might want to look at http://www.regularexpressions.info/ or http://en.wikipedia.org/wiki/Regular_expressions. pekwm-release-0.1.18/doc/config/autoprops/grouping.xml000066400000000000000000000031671374756504400230120ustar00rootroot00000000000000 AutoGrouping The last thing to know is autogrouping. Autogrouping is actually very simple, although it might be a bit confusing at first. Group is an identifier, it's just a string, (in my example, we'll call it netwin). Size tells how many clients to group together in one frame. The example: We want to autogroup Sylpheed and Opera together, allowing as many instances of the program windows to be grouped as there are. Here's the Autoprops section for that: Property = ".*,^opera" { Group = "netwin" { Size = "0" } ApplyOn = "New Start Reload" } Property = ".*,^Sylpheed" { Group = "netwin" { Size = "0" } ApplyOn = "New Start Reload Transient" } This creates two rules: "For any window matching '.*,^opera', group these in the 'netwin' group. Apply this on pekwm start/reload and when new windows matching this property are opened, but do not include dialog windows", and "For any window matching '.*,^Sylpheed', group in the 'netwin' group. Apply on pekwm start/reload and when new windows matching this property are opened, also include possible dialog windows to the group. Open the window to the group but do not bring it upmost automatically". To group unlimited windows together, use size 0. Also note that you can have as many Group identifiers as you want. Autogrouping is a very flexible system. Try playing around with it. pekwm-release-0.1.18/doc/config/autoprops/morehelp.xml000066400000000000000000000011251374756504400227630ustar00rootroot00000000000000 Getting more help Autoprops can be a daunting topic. If you've read everything here in the docs and are still having problems, feel free to hit the channel and ask. Check the before asking. Remember that: "IF YOU WANT AN ANSWER TO YOUR QUESTION, YOU HAD BETTER HAVE ALREADY READ THE DOCUMENTATION". pekwm-release-0.1.18/doc/config/autoprops/types.xml000066400000000000000000000047731374756504400223300ustar00rootroot00000000000000 TypeRules, autoproperties controlling _NET_WM_WINDOW_TYPE The TypeRules decides how the _NET_WM_WINDOW_TYPE should be interpreted. The _NET_WM_WINDOW_TYPE hint gives the application writer possibility to inform the window manager what kind of window it is creating. TypeRules are defined in the TypeRules section of the ~/.pekwm/autoproperties file. A sample section could look something like this: TypeRules { ... Property = "MENU" { Titlebar = "False" Border = "False" Skip = "FocusToggle Menus Snap" } ... } Using TypeRules are done the same way as with but the property is matched based on the value of _NET_WM_WINDOW_TYPE. Supported values are available in the list below. Supported values Desktop A desktop window such as the window containing desktop icons on the Gnome desktop. Dock Toolbar Menu Utility Splash Application startup screen usually presenting loading progress. Dialog Dialogs prompting for information such as "Save as" dialogs. Normal Any other window, can be used to set default autoproperties. pekwm-release-0.1.18/doc/config/autoprops/what.xml000066400000000000000000000012701374756504400221140ustar00rootroot00000000000000 What are Autoproperties? "Autoproperties" is short for "Automatic Properties". This is pekwm's way of setting certain things up for applications based on the window's internal id. You can set up a lot of things, such as size, iconified state, start location, grouped state (automatically having one window group to another), workspace to start on, whether it has a border or titlebar, and more. It is also possible to automatically modify window titles and to decide the order of applications on the harbour with autoproperties. pekwm-release-0.1.18/doc/config/config.ent000066400000000000000000000037631374756504400203610ustar00rootroot00000000000000 pekwm-release-0.1.18/doc/config/config.xml000066400000000000000000000007151374756504400203650ustar00rootroot00000000000000 Configuration The configuration part of this documentation is focused on providing complete documentation for all config files located in your ~/.pekwm directory. &config-syntax; &config-configfile; &config-menu; &config-autoprops; &config-keys_mouse; &config-start; &config-theme; pekwm-release-0.1.18/doc/config/configfile/000077500000000000000000000000001374756504400205005ustar00rootroot00000000000000pekwm-release-0.1.18/doc/config/configfile/basic.xml000066400000000000000000000036001374756504400223020ustar00rootroot00000000000000 Basic Config As previously indicated, the config file follows the rules defined in . Here's an example ~/.pekwm/config file: Files { Keys = "~/.pekwm/keys" Mouse = "~/.pekwm/mouse" Menu = "~/.pekwm/menu" Start = "~/.pekwm/start" AutoProps = "~/.pekwm/autoproperties" Theme = "~/.pekwm/themes/default" Icons = "~/.pekwm/icons/" } MoveResize { EdgeAttract = "10" EdgeResist = "10" WindowAttract = "5" WindowResist = "5" OpaqueMove = "True" OpaqueResize = "False" } Screen { Workspaces = "4" WorkspacesPerRow = "2" WorkspaceNames = "Main;Web;E-mail;Music" ShowFrameList = "True" ShowStatusWindow = "True" ShowStatusWindowCenteredOnRoot = "False" ShowClientID = "False" ShowWorkspaceIndicator = "500" FocusNew = "True" PlaceNew = "True" TrimTitle = "..." FullscreenAbove = "True" FullscreenDetect = "True" HonourRandr = "True" HonourAspectRatio = "True" EdgeSize = "1 1 1 1" EdgeIndent = "False" DoubleClickTime = "250" Placement { Model = "Smart" WorkspacePlacements = "Smart;MouseCentered" TransientOnParent = "True" Smart { Row = "False" TopToBottom = "True" LeftToRight = "True" OffsetX = "0" OffsetY = "0" } } UniqueNames { SetUnique = "True" Pre = " #" Post = "" } } Menu { DisplayIcons = "True" Icons = "DEFAULT" { Minimum = "16x16" Maximum = "16x16" } Select = "Motion" Enter = "Motion ButtonPress" Exec = "ButtonRelease" } CmdDialog { HistoryUnique = "True" HistorySize = "1024" HistoryFile = "~/.pekwm/history" HistorySaveInterval = "16" } Harbour { OnTop = "True" MaximizeOver = "False" Placement = "Right" Orientation = "TopToBottom" Head = "0" DockApp { SideMin = "64" SideMax = "0" } } pekwm-release-0.1.18/doc/config/configfile/configfile.xml000066400000000000000000000005411374756504400233270ustar00rootroot00000000000000 The main config file The main config file is where all the base config stuff goes. &config-configfile-basic; &config-configfile-keywords; &config-configfile-screensubsections; pekwm-release-0.1.18/doc/config/configfile/keywords.xml000066400000000000000000000436231374756504400231010ustar00rootroot00000000000000 Config File Keywords Here's a table showing the different elements that can be used in your config file. Remember that 'boolean' means 'true' or 'false' and that all values should be placed inside quotes. Config File Elements under the Files-section: Keys (string) The location of the keys file, such as ~/.pekwm/keys Menu (string) The location of the menu file, such as ~/.pekwm/menu Start (string) The location of the start file, such as ~/.pekwm/start AutoProps (string) The location of the autoprops file, such as ~/.pekwm/autoproperties Theme (string) The location of the Theme directory, such as ~/.pekwm/themes/themename Icons (string) The location of the Icons directory, such as ~/.pekwm/icons Config File Elements under the MoveResize-section: EdgeAttract (int) The distance from screen edge required for the window to snap against it in pixels. EdgeResist (int) The distance from screen edge required for the window moving to start being resisted in pixels. WindowAttract (int) The distance from other clients that a window will snap against them to in pixels. WindowResist (int) The distance from other clients that a window movement will start being resisted. OpaqueMove (boolean) If true, turns on opaque Moving OpaqueResize (boolean) If true, turns on opaque Resizing Config File Elements under the Screen-section: Workspaces (int) Number of workspaces enabled. WorkspacesPerRow (int) Number of workspaces on each row. Value < 1 fits all workspaces on a single row. WorkspaceNames (string) List of names for workspaces separated by ;. ShowFrameList (boolean) Controls whether a list of all available frames on the workspace is displayed during the NextFrame/PrevFrame actions. ShowStatusWindow (boolean) Controls whether a size/position info window is shown when moving or resizing windows. ShowStatusWindowCenteredOnRoot (boolean) Controls whether a size/position info window is shown centered on the current head or the current window. ShowClientID (boolean) Should Client IDs be displayed in window titles. ShowWorkspaceIndicator (int) Show WorkspaceIndicator for N milliseconds. If set to < 1, the WorkspaceIndicator is disabled. WorkspaceIndicatorScale (int) Changes the size of the WorkspaceIndicator, higher value means smaller size. WorkspaceIndicatorOpacity (int) Sets the opacity/transparency of the WorkspaceIndicator. A value of 100 means completely opaque, while 0 stands for completely transparent. Note that a Composite Manager needs to be running for this feature to take effect. FocusNew (boolean) Toggles if new windows should be focused when they pop up. FocusNewChild (boolean) Toggles if new transient windows should be focused when they pop up if the window they are transient for is focused. PlaceNew (boolean) Toggles if new windows should be placed using the rules found in the Placement subsection, or just opened on the top left corner of your screen. ReportAllClients (boolean) Toggles if all clients in a frame or only the active one should be reported and thus displayed in pager applications etc. TrimTitle (string) This string contains what pekwm uses to trim down overlong window titles. If it's empty, no trimming down is performed at all. FullscreenAbove (boolean) Toggles restacking of windows when going to and from fullscreen mode. Windows are restacked to the top of all windows when going to fullscreen and to the top of their layer when being restored from fullscreen. FullscreenDetect (boolean) Toggles detection of broken fullscreen requests setting clients to fullscreen mode when requesting to be the size of the screen. Default true. HonourRandr (boolean) Toggles reading of XRANDR information, this can be disabled if the display driver gives both Xinerama and Randr information and only of the two is correct. Default true. HonourAspectRatio (boolean) Toggles if pekwm respects the aspect ratio of clients (XSizeHints). Default true. EdgeSize (int) (int) (int) (int) How many pixels from the edge of the screen should screen edges be. Parameters correspond to the following edges: top bottom left right. A value of 0 disables edges. EdgeIndent (boolean) Toggles if the screen edge should be reserved space. DoubleClicktime (int) Time, in milliseconds, between clicks to be counted as a doubleclick. Config File Elements under the Placement-subsection of the Screen-section: TransientOnParent (bool) Set to true if you want the transient windows to be mappend on their "parent" window (tiling layouters might ignore this option). Model (string) Smart - Tries to place windows where no other window is present MouseCentered - Places the center of the window underneath the current mouse pointer position MouseTopLeft - Places the top-left corner of the window under the pointer MouseNotUnder - Places windows on screen corners avoiding the current mouse cursor position. CenteredOnParent - Places transient windows at center of their parent window. WorkspacePlacements (string) List of placement models for the workspaces separated by ;. For an explanation of the allowed options see "Model" above. Config File Elements under the Smart-subsection of the Placement-subsection: Row (boolean) Whether to use row or column placement, if true, uses row. TopToBottom (boolean) If false, the window is placed starting from the bottom. LeftToRight (boolean) If false, the window is placed starting from the right. OffsetX (int) Pixels to leave between new and old windows and screen edges. When 0, no space is reserved. OffsetY (int) Pixels to leave between new and old windows and screen edges. When 0, no space is reserved. Config File Elements under the UniqueNames-subsection of the Screen-section: SetUnique (boolean) Decides if the feature is used or not. False or True. Pre (string) String to place before the unique client number. Post (string) String to place after the unique client number. Config File Elements under the CmdDialog-section: HistoryUnique (boolean) If true, identical items in the history will only appear once where the most recently used is the first item. Default true. HistorySize (integer) Number of entries in the history that should be kept track of. Default 1024. HistoryFile (string) Path to history file where history is persisted between session. Default ~/.pekwm/history HistorySaveInterval (int) Defines how often the history file should be saved counting each time the CmdDialog finish a command. Default 16. Config File Elements under the Menu-section: DisplayIcons (boolean) Defines wheter menus should render their icons. Default true. FocusOpacity (int) Sets the opacity/transparency for focused Menus. A value of 100 means completely opaque, while 0 stands for completely transparent. UnfocusOpacity (int) Sets the opacity/transparency for unfocused Menus. Icons = "MENU" Minimum (width x height) Defines minimum size of icons, if 0x0 no check is done. Default 16x16. Maximum (width x height) Defines maximum size of icons, if 0x0 no check is done. Default 16x16. Select (list of strings) Decides on what mouse events to select a menu entry. List is space separated and can include "ButtonPress, ButtonRelease, DoubleClick, Motion, MotionPressed" Enter (list of strings) Decides on what mouse events to enter a submenu. List is space separated and can include "ButtonPress, ButtonRelease, DoubleClick, Motion, MotionPressed" Exec (list of strings) Decides on what mouse events to execute an entry. List is space separated anc can include "ButtonPress, ButtonRelease, DoubleClick, Motion, MotionPressed" Config File Elements under the Harbour-section: Placement (string) Which edge to place the harbour on. One of Right, Left, Top, or Bottom. Orientation (string) From what to which direction the harbour expands. One of TopToBottom, BottomToTop, RightToLeft, LeftToRight. OnTop (boolean) Whether or not the harbour is "always on top" MaximizeOver (boolean) Controls whether maximized clients will cover the harbour (true), or if they will stop at the edge of the harbour (false). Head (int) When RandR or Xinerama is on, decides on what head the harbour resides on. Integer is the head number. Opacity (int) Sets the opacity/transparency for the harbour. A value of 100 means completely opaque, while 0 stands for completely transparent. Config File Elements under the DockApp-subsection of the Harbour-section: SideMin (int) Controls the minimum size of dockapp clients. If a dockapp client is smaller than the minimum, it gets resized up to the SideMin value. Integer is a number of pixels. SideMax (int) Controls the maximum size of dockapp clients. If a dockapp client is larger than the maximum, it gets resized down to the SideMax value. Integer is a number of pixels. pekwm-release-0.1.18/doc/config/configfile/screen-subsections.xml000066400000000000000000000020231374756504400250350ustar00rootroot00000000000000 Screen Subsections There are two subsections in the screen section - Placement and UniqueNames. Placement can optionally have its own subsection. Sounds hard? It's not! It's really quite simple. We'll start off with Placement. Placement has two options: Model, and a 'Smart' subsection. Model is very simple, it's simply a list of keywords that describes how to place new windows, such as "Smart MouseCentered". Secondly, there's a Smart section, which describes how pekwm computes where to place a new window in smart mode. The second subsection, UniqueNames, lets you configure how pekwm should handle similar client names. Pekwm can add unique number identifiers to clients that have the same title so that instead of "terminal" and "terminal", you would end up with something like "terminal" and "terminal [2]". pekwm-release-0.1.18/doc/config/keys_mouse/000077500000000000000000000000001374756504400205565ustar00rootroot00000000000000pekwm-release-0.1.18/doc/config/keys_mouse/actions.xml000066400000000000000000001053451374756504400227500ustar00rootroot00000000000000 Keys/Mouse actions and window attributes Here is the list of all possible actions and attributes. First table shows all toggleable attributes. Toggleable attributes are controlled using the Set, Unset and Toggle actions. Examples below. Keypress = "Mod4 s" { Actions = "Toggle Shaded" } Keypress = "Mod4 m" { Actions = "Toggle Maximized True True" } Keypress = "Mod4 t" { Actions = "Set Tagged" } Keypress = "Mod4 Shift t" { Actions = "Unset Tagged" } Toggleable attributes: Maximized (bool bool) If a frame is maximized. Two parameters, first one decides if the frame is maximized horizontally, the second if it is maximized vertically. Fullscreen If a frame should be fullscreen. Fullscreen frame takes over the whole desktop ignoring any harbour or struts and becomes decorless. Shaded If a frame should be shaded (so that only the titlebar shows until it's unset or toggled off). Sticky If a frame should be sticky so it appears on every workspace. AlwaysOnTop If frame should always be on top of other frames. AlwaysBelow If a frame should always be below other frames. Decor When used with Set/Toggle it takes an additional parameter for the decorname that is set/toggled. Unset just removes the last "override"-decor. DecorBorder If frame should have borders. DecorTitlebar If frame should have a titlebar. Iconified If a frame should be iconified. Opaque If the frame should be fully opaque (ie: disable the opacity setting). Tagged (bool) If a frame should swallow all new clients until unset or toggled off. One parameter, if true new clients open in the background. Defaults to false. Marked If a frame is marked for later attaching (with AttachMarked). Skip (string) If a frame should be ignored on specified places, string is one of menus focustoggle snap CfgDeny (string) When things to be done to this window requested by the client program should be denied, string is one of: above (don't let client place window above other windows) activewindow (don't let client give input focus) below (don't let client place window below other windows) fullscreen (don't let client set window fullscreen mode) hidden (don't let client hide window) maximizedhorz (don't let client maximize window horizontally) maximizedvert (don't let client maximize a window vertically) position (don't let the client move the window) size (don't let the client resize the window) stacking (don't allow the client to raise or lower the window) tiling (Tiling layouters should leave this window floating) Title (string) Changes the clients titlebar text to string when set. Unsetting returns the clients title text back to the client specified one. HarbourHidden If set, harbour and anything in it will be hidden from the screen. GlobalGrouping If all autogrouping should be in use or not. By default it's set, as in autogrouping is enabled. Keys/Mouse Actions: Focus Gives focus to a frame. UnFocus Removes focus from a frame. Set (one of toggleable attributes) Makes toggleable attributes set. UnSet (one of toggleable attributes) Unsets toggleable attributes. Toggle (one of toggleable attributes) Toggles toggleable attributes. MaxFill (bool bool) Acts much like Maximize, but considers other frames while doing it. Instead of filling the whole screen, it only fills to the borders of neighboring frames. Takes two parameters, first one decides if the frame is maxfilled horizontally, the second if it should be maxfilled vertically. GrowDirection (string) Grows the frame in one of the directions up to the edge of the head. String is one of up, down, left, right. Close Closes a client window. CloseFrame Closes a frame and all client windows in it. Kill Kills a client window, use if close doesn't work. SetGeometry (string int) Sets the geometry of a frame. The first option is a geometry string that XParseGeometry can parse. The second one specifies the head number that geometry should be relative to. It defaults to -1 which means the geometry is relative to the whole screen. Raise (bool) Raises a frame above other frames. If bool is true raises a frame and all of the currently active clients child/parent windows above other frames. Lower (bool) Lowers a frame under other frames. If bool is true lowers a frame and all of the currently active clients child/parent windows under other frames. ActivateOrRaise If the frame this action is used on is not focused, focuses it. If the frame is focused, raises it. If used on a groups titlebar, activates the selected client of the group. ActivateClientRel (int) Moves the focus and raises a client inside a frame relative to the currently selected client. Int is 1 to move right, -1 to move left. MoveClientRel (int) Moves the current clients position inside the current frame. Int is 1 to move right, -1 to move left. ActivateClient Activates a client of a frame. Mouse-specific ActivateClientNum (int) Activates the #th client of a frame. Int is the client number counting from left. Keygrabber-specific Resize (string) Resizes a frame. String is one of top, bottom, left, right, topleft, topright, bottomleft, bottomright. Mouse-specific (parameters frameborder-specific) Move Moves a frame. Mouse-specific MoveResize Activates the keyboard move and resize. Keygrabber-specific GroupingDrag (bool) Drags windows in and out of frames, if parameter is true dragged windows go in the background of a frame. Mouse-specific WarpToWorkspace (string) Makes a dragged window warp to specified workspace when a it's moved over a screen edge. String is one: next - send to the next workspace, if on last workspace, wrap to the first one. prev - send to the previous workspace, if on first workspace, wrap to the last one. left - send to the previous workspace right - send to the next workspace int - integer is a workspace number to send to to ScreenEdge specific mouse binding MoveToHead (int) Moves the frame to the same relative position on another head. The window is shrinked to fit if it is larger than the new head. MoveToEdge (string) Moves the frame to the specified place on the screen. String is one of TopLeft, TopEdge, TopRight, RightEdge, BottomRight, BottomEdge, BottomLeft, LeftEdge, Center, TopCenterEdge, BottomCenterEdge, LeftCenterEdge, RightCenterEdge. Keygrabber-specific NextFrame (string boolean) Focuses the next frame. String is one of: alwaysraise - raise windows while toggling them endraise - raise the selected client neverraise - do not raise the selected client (unless it's iconified) tempraise - raise the selected client but keep the order of the other windows If boolean is true, also goes thru iconified windows. Defaults to false. PrevFrame (string boolean) Focuses the previous frame. String is: alwaysraise - raise windows while toggling them endraise - raise the selected client neverraise - do not raise the selected client (unless it's iconified) tempraise - raise the selected client but keep the order of the other windows If boolean is true, also goes thru iconified windows. Defaults to false. NextFrameMRU (string boolean) Focuses the next frame so that the last focused windows will get switched to first. String is: alwaysraise - raise windows while toggling them endraise - raise the selected client neverraise - do not raise the selected client (unless it's iconified) tempraise - raise the selected client but keep the order of the other windows If boolean is true, also goes thru iconified windows. Defaults to false. PrevFrameMRU (string boolean) Focuses the previous frame so that the last focused windows will get switched to first. String is: alwaysraise - raise windows while toggling them endraise - raise the selected client neverraise - do not raise the selected client (unless it's iconified) tempraise - raise the selected client but keep the order of the other windows If boolean is true, also goes thru iconified windows. Defaults to false. FocusDirectional (string bool) Focuses the first window on the direction specified, and optionally raises it. Takes two options, first one is the direction and the second specifies if the focused frame should be raised or not. Bool defaults to True. String is one of up, down, left, right AttachMarked Attachs all marked clients to the current frame. AttachClientInNextFrame Attachs client to the next frame. AttachClientInPrevFrame Attachs client to the previous frame. FindClient (string) Searches the client list for a client that has a title matching the given regex string. GotoClientID (string) Shows and focuses a client based on the Client ID given as a parameter. Detach Detach the current client from its frame. SendToWorkspace (string) Sends a frame to the specified workspace. String is one of: next - send to the next workspace, if on last workspace, wrap to the first one. prev - send to the previous workspace, if on first workspace, wrap to the last one. left - send to the previous workspace right - send to the next workspace prevv - send to the previous (vertical) workspace, if on last workspace, wrap to the first one. up - send to the previous (vertical) workspace. nextv - sed to the next (vertical) workspace, if on last workspace, wrap to the first one. down - last - send to workspace you last used before the current int - integer is a workspace number to send to to GotoWorkspace (string) Changes workspaces. String is one of: left - go to the previous workspace on current row. prev - go to the previous workspace on current row, if on first workspace, wrap to the last one on current row. right - go to the next workspace on current row. next - go to the next workspace on current row, if on last workspace, wrap to the first one on current row. leftn - go to the previous workspace. prevn - go to the previous workspace, if on first workspace, wrap to the last. rightn - go to the next workspace. nextn - go to the next workspace, if on last workspace, wrap to the first. prevv - up - nextv - down - last - go to workspace you last used before the current int - integer is a workspace number to go to Exec (string) Executes a program, string is a path to an executable file. Reload Reloads pekwm configs. Keygrabber-specific Restart Restarts pekwm. Keygrabber-specific RestartOther Quits pekwm and starts the program you specify. String is a path to an executable file. Keygrabber-specific Exit Exits pekwm. ShowCmdDialog (string) Shows the command dialog that can be used to input pekwm actions. If it's a window specific action, it affects the window focused when CmdDialog was summoned. If entered action doesn't match any valid pekwm action, pekwm tries to Exec it as a shell command. Takes an optional string as a parameter. This string will then be pre-filled as the initial value of the dialog. ShowSearchDialog (string) Shows the search dialog that can be used to search for clients and when selected the client will be activated. Takes an optional string as a parameter. This string will then be pre-filled as the initial value of the dialog. ShowMenu (string bool) Shows a menu. String is menu type from below list or user defined menu name (see ): root - shows your application menu icon - shows iconified windows goto - shows currently active clients gotoclient - shows all open clients window - shows a window specific menu decor - shows possible decorations in the current theme attachclient - allows to attach clients in current frame attachframe - allows to attach whole frame in current frame attachclientinframe - allows attaching current client in any other frame attachframeinframe - allows attaching current frame in any other frame Bool is true for sticky menus, false for click to vanish. Defaults to false. HideAllMenus Closes all pekwm menus. SendKey Send a key, possibly with modifiers, to the active window. SetOpacity (int int) Sets the Focused and Unfocused opacity values for the active window. 100 stands for fully opaque while 0 is completely transparent. MoveResize actions: MoveHorizontal (int) Moves a frame horizontally. Int is amount of pixels and can be negative. Moveresize-specific keybinding MoveVertical (int) Moves a frame vertically. Int is amount of pixels and can be negative. Moveresize-specific keybinding ResizeHorizontal (int) Resizes a frame horizontally. Int is amount of pixels and can be negative. Moveresize-specific keybinding ResizeVertical (int) Resizes a frame vertically. Int is amount of pixels and can be negative. Moveresize-specific keybinding MoveSnap Snaps the frame to the closest frames or screenedges. Moveresize-specific keybinding Cancel Cancels all moveresize actions and keeps the frame how it was before them. Moveresize-specific keybinding End Acknowledges the moveresize actions and moves/resizes the frame as wished. Moveresize-specific keybinding Menu actions: NextItem Goes to next menu item. Menu-specific keybinding PrevItem Goes to previous menu item. Menu-specific keybinding GotoItem (int) Goes to item number int. First item in menu is 1. Menu-specific keybinding Select Selects the current menu item. Menu-specific keybinding EnterSubmenu Enters a submenu. Menu-specific keybinding LeaveSubmenu Leaves a submenu. Menu-specific keybinding InputDialog actions: Insert Allows for the keypress to be inputted to the text field of InputDialog. Usually used to allow any other keys than the ones used for InputDialog. InputDialog-specific keybinding Erase Erases the previous character according to the cursor position. InputDialog-specific keybinding Clear Clears the whole InputDialog line. InputDialog-specific keybinding ClearFromCursor Erases all characters after the current cursor position. InputDialog-specific keybinding Exec Finishes input and executes the the data Close Closes an InputDialog. InputDialog-specific keybinding CursNext Moves InputDialog cursor one characer space to right. InputDialog-specific keybinding CursPrev Moves InputDialog cursor one characer space to left. InputDialog-specific keybinding CursEnd Moves InputDialog cursor to the end of the line. InputDialog-specific keybinding CursBegin Moves InputDialog cursor to the beginning of the line. InputDialog-specific keybinding HistNext Get next history item previously used in InputDialog. InputDialog-specific keybinding HistPrev Get previous history item previously used in InputDialog. InputDialog-specific keybinding pekwm-release-0.1.18/doc/config/keys_mouse/border.xml000066400000000000000000000012141374756504400225530ustar00rootroot00000000000000 Border Subsection The Border subsection in ~/.pekwm/mouse defines the actions to take when handling the window borders. Border { TopLeft { Enter = "Any Any" { Actions = "Focus" } ButtonPress = "1" { Actions = "Resize TopLeft" } } } It's subsections refer to the frame part in question. They are: Top, Bottom, Left, Right, TopLeft, TopRight, BottomLeft, and BottomRight. In these subsections you can define events and actions as usual. pekwm-release-0.1.18/doc/config/keys_mouse/keychains.xml000066400000000000000000000030401374756504400232530ustar00rootroot00000000000000 Keychains Pekwm also supports keychains. Keychain syntax follows the general config syntax and looks like this: Chain = "modifiers and key" { Chain = "modifiers and key" { KeyPress = "modifiers and key" { Actions = "actions and their parameters" } } Keypress = "modifiers and key" { Actions = "actions and their parameters" } } It might seem complicated at start but once you look into it, it is fairly nice and logical. This syntax supports as many nested Chains as you might want. Now for some examples. Here we have a simple nested chain that lets you press Ctrl+Alt+M, then M, then M, V or H to toggle maximized attribute into Full/Vertical or Horizontal, and a simpler one level chain that brings up the root menu. Chain = "Ctrl Mod1 A" { Chain = "M" { KeyPress = "M" { Actions = "Toggle Maximized True True" } KeyPress = "V" { Actions = "Toggle Maximized False True" } KeyPress = "H" { Actions = "Toggle Maximized True False" } } } Chain = "Ctrl Mod1 M" { KeyPress = "R" { Actions = "ShowMenu Root" } } This next rule is a pure show-off, it lets you type in 'test' and then executes xterm. Note that this will make you unable to type the character 't' to any programs. Chain = "t" { Chain = "e" { Chain = "s" { Keypress = "t" { Actions = "Exec xterm" } } } } pekwm-release-0.1.18/doc/config/keys_mouse/keys.xml000066400000000000000000000102251374756504400222530ustar00rootroot00000000000000 Key Bindings The pekwm keybindings go in ~/.pekwm/keys, and are even more simple than the mouse bindings. Here's the format: KeyPress = "optional modifiers like mod1, ctrl, etc and the key" { Actions = "action and the parameters for the action, if they are needed" } Multiple actions can be given for one keypress. The actions are separated from each other with a semicolon: Keypress = "Ctrl t" { Actions = "Exec xterm; Set Maximized True True; Close" } Here's a small fragment of an example keys file; you can see a full version in ~/.pekwm/keys. As with the mouse, you can see the full list of actions in the section. Global { # Moving in frames KeyPress = "Mod1 Tab" { Actions = "NextFrame EndRaise" } KeyPress = "Mod1 Shift Tab" { Actions = "PrevFrame EndRaise" } KeyPress = "Mod1 Ctrl Tab" { Actions = "NextFrameMRU EndRaise" } KeyPress = "Mod1 Ctrl Shift Tab" { Actions = "PrevFrameMRU EndRaise" } # Simple window management KeyPress = "Mod4 M" { Actions = "Toggle Maximized True True" } KeyPress = "Mod4 G" { Actions = "Maxfill True True" } KeyPress = "Mod4 F" { Actions = "Toggle FullScreen" } KeyPress = "Mod4 Return" { Actions = "MoveResize" } # Wm actions Chain = "Ctrl Mod1 P" { KeyPress = "Delete" { Actions = "Reload" } KeyPress = "Next" { Actions = "Restart" } KeyPress = "End" { Actions = "Exit" } KeyPress = "Prior" { Actions = "RestartOther twm" } } } MoveResize { KeyPress = "Left" { Actions = "MoveHorizontal -10" } KeyPress = "Right" { Actions = "MoveHorizontal 10" } KeyPress = "Up" { Actions = "MoveVertical -10" } KeyPress = "Down" { Actions = "MoveVertical 10" } Keypress = "Mod4 Left" { Actions = "ResizeHorizontal -10" } Keypress = "Mod4 Right" { Actions = "ResizeHorizontal 10" } Keypress = "Mod4 Up" { Actions = "ResizeVertical -10" } Keypress = "Mod4 Down" { Actions = "ResizeVertical 10" } Keypress = "s" { Actions = "MoveSnap" } Keypress = "Escape" { Actions = "Cancel" } Keypress = "Return" { Actions = "End" } } Menu { KeyPress = "Down" { Actions = "NextItem" } KeyPress = "Up" { Actions = "PrevItem" } KeyPress = "Left" { Actions = "LeaveSubmenu" } KeyPress = "Right" { Actions = "EnterSubmenu" } KeyPress = "Return" { Actions = "Select" } KeyPress = "Escape" { Actions = "Close" } } InputDialog { KeyPress = "BackSpace" { Actions = "Erase" } KeyPress = "Right" { Actions = "CursNext" } KeyPress = "Left" { Actions = "CursPrev" } KeyPress = "Up" { Actions = "HistPrev" } KeyPress = "Down" { Actions = "HistNext" } KeyPress = "Delete" { Actions = "Clear" } KeyPress = "Return" { Actions = "Exec" } KeyPress = "Escape" { Actions = "Close" } KeyPress = "Any Any" { Actions = "Insert" } } As you might have noticed, the file consist of four sections. These sections are Global, MoveResize, Menu and InputDialog. The first section, Global, contains all the generic actions. The MoveResize section has the keybindings that will get used when the MoveResize action is called. Menu section contains the keys that are used when the ShowMenu action is called. E.g. these are the keys you use to browse thru the menus of pekwm. Note that while ShowMenu is active, the Global keybindings are also listened. If a keybinding is same in both Menu and Global sections, keybindings in Menu section override the global keybinding as long as a menu is active. Finally, the InputDialog section allow for tuning of what keys are available for line editing when the CmdDialog window that enables the user to enter pekwm actions for running windows is active. Keys can be identified with their XString name or with their keycode. Both can be found out using the X application xev. If you want to use a keycode, prefix it with #. pekwm-release-0.1.18/doc/config/keys_mouse/keys_mouse.xml000066400000000000000000000007061374756504400234660ustar00rootroot00000000000000 Keyboard and Mouse Configuration Pekwm allows you to remap almost all keyboard and mouse events. &config-keys_mouse-mouse; &config-keys_mouse-border; &config-keys_mouse-screenedge; &config-keys_mouse-keys; &config-keys_mouse-keychains; &config-keys_mouse-actions; pekwm-release-0.1.18/doc/config/keys_mouse/mouse.xml000066400000000000000000000206401374756504400224320ustar00rootroot00000000000000 Mouse Bindings The pekwm Mousebindings go in ~/.pekwm/mouse, and are very simple. They're divided up into two groups: The 'where' and 'event'. Below is an example file: FrameTitle { ButtonRelease = "1" { Actions = "Raise; Focus; ActivateClient" } ButtonRelease = "2" { Actions = "ActivateClient" } ButtonRelease = "Mod4 3" { Actions = "Close" } ButtonRelease = "3" { Actions = "ShowMenu Window" } ButtonRelease = "4" { Actions = "ActivateClientRel 1" } ButtonRelease = "5" { Actions = "ActivateClientRel -1" } DoubleClick = "2" { Actions = "Toggle Shaded" } DoubleClick = "1" { Actions = "MaxFill True True" } Motion = "1" { Threshold = "4"; Actions = "Move" } Motion = "Mod1 1" { Threshold = "4"; Actions = "Move" } Motion = "Mod4 1" { Threshold = "4"; Actions = "Move" } Motion = "2" { Threshold = "4"; Actions = "GroupingDrag True" } Motion = "Mod1 3" { Actions = "Resize" } Enter = "Any Any" { Actions = "Focus" } } OtherTitle { ButtonRelease = "1" { Actions = "Raise; Focus; ActivateClient" } ButtonRelease = "Mod4 3" { Actions = "Close" } DoubleClick = "2" { Actions = "Toggle Shaded" } DoubleClick = "1" { Actions = "MaxFill True True" } Motion = "1" { Threshold = "4"; Actions = "Move" } Motion = "Mod1 1" { Threshold = "4"; Actions = "Move" } Motion = "Mod4 1" { Threshold = "4"; Actions = "Move" } Motion = "Mod1 3" { Actions = "Resize" } Enter = "Any Any" { Actions = "Focus" } } Border { TopLeft { Enter = "Any Any" { Actions = "Focus" }; ButtonPress = "1" { Actions = "Resize TopLeft" } } Top { Enter = "Any Any" { Actions = "Focus" }; ButtonPress = "1" { Actions = "Move" } } TopRight { Enter = "Any Any" { Actions = "Focus" }; ButtonPress = "1" { Actions = "Resize TopRight" } } Left { Enter = "Any Any" { Actions = "Focus" }; ButtonPress = "1" { Actions = "Resize Left" } } Right { Enter = "Any Any" { Actions = "Focus" }; ButtonPress = "1" { Actions = "Resize Right" } } BottomLeft { Enter = "Any Any" { Actions = "Focus" }; ButtonPress = "1" { Actions = "Resize BottomLeft" } } Bottom { Enter = "Any Any" { Actions = "Focus" }; ButtonPress = "1" { Actions = "Resize Bottom" } } BottomRight { Enter = "Any Any" { Actions = "Focus" }; ButtonPress = "1" { Actions = "Resize BottomRight" } } } ScreenEdge { Down { ButtonRelease = "3" { Actions = "ShowMenu Root" } ButtonRelease = "2" { Actions = "ShowMenu Goto" } } Up { ButtonRelease = "3" { Actions = "ShowMenu Root" } ButtonRelease = "2" { Actions = "ShowMenu Goto" } ButtonRelease = "Mod1 4" { Actions = "GoToWorkspace Right" } ButtonRelease = "Mod1 5" { Actions = "GoToWorkspace Left" } } Left { Enter = "Mod1 Any" { Actions = "GoToWorkspace Left" } ButtonRelease = "3" { Actions = "ShowMenu Root" } ButtonRelease = "1" { Actions = "GoToWorkspace Left" } DoubleClick = "1" { Actions = "GoToWorkspace Left" } ButtonRelease = "2" { Actions = "ShowMenu Goto" } ButtonRelease = "4" { Actions = "GoToWorkspace Right" } ButtonRelease = "5" { Actions = "GoToWorkspace Left" } } Right { Enter = "Mod1 Any" { Actions = "GoToWorkspace Right" } ButtonRelease = "3" { Actions = "ShowMenu Root" } ButtonRelease = "1" { Actions = "GoToWorkspace Right" } DoubleClick = "1" { Actions = "GoToWorkspace Right" } ButtonRelease = "2" { Actions = "ShowMenu Goto" } ButtonRelease = "4" { Actions = "GoToWorkspace Right" } ButtonRelease = "5" { Actions = "GoToWorkspace Left" } } } Client { ButtonPress = "1" { Actions = "Focus" } ButtonRelease = "Mod1 1" { Actions = "Focus; Raise" } ButtonRelease = "Mod4 1" { Actions = "Lower" } Motion = "Mod1 1" { Actions = "Focus; Raise; Move" } Motion = "Mod4 1" { Actions = "Focus; Raise; Move" } Motion = "Mod1 2" { Threshold = "4"; Actions = "GroupingDrag True" } Motion = "Mod1 3" { Actions = "Resize" } Enter = "Any Any" { Actions = "Focus" } } Root { ButtonRelease = "3" { Actions = "ShowMenu Root" } ButtonRelease = "2" { Actions = "ShowMenu Goto" } ButtonRelease = "4" { Actions = "GoToWorkspace Right" } ButtonRelease = "5" { Actions = "GoToWorkspace Left" } ButtonRelease = "1" { Actions = "HideAllMenus" } } Menu { Enter = "Any Any" { Actions = "Focus" } ButtonRelease = "2" { Actions = "Toggle Sticky" } Motion = "1" { Threshold = "10"; Actions = "Move" } ButtonRelease = "3" { Actions = "Close" } } Other { Enter = "Any Any" { Actions = "Focus" } ButtonRelease = "Mod4 3" { Actions = "Close" } Motion = "1" { Actions = "Focus; Raise; Move" } Motion = "Mod1 1" { Actions = "Focus; Raise; Move" } } Below are defined the different fields. The actions themselves can be found in the section. 'Where' fields: FrameTitle On a regular window's Titlebar. OtherTitle On menu/cmdDialog/etc pekwm's own window's Titlebar. Border On the window's borders. See for more information. ScreenEdge On the screen edges. See for more information. Client Anywhere on the window's interior. It's best to use a keyboard modifier with these. Root On the Root window (also called the 'desktop'). Menu On the various menus excluding their titlebars. Other On everything else that doesn't have it's own section. 'Event' fields: ButtonPress A single click ButtonRelease A single click that activates once the button is released DoubleClick A double click Motion Clicking, holding, and Dragging. Enter Defines how to act when mouse pointer enters a place defined by the 'where' field. Leave Defines how to act when mouse pointer leaves a place defined by the 'where' field. EnterMoving Defines how to act when a dragged window enters a ScreenEdge. Only works with screen edges. Definitions work like this: 'Where' { 'Event' = "optional modifiers, like mod1, ctrl, etc and a mouse button" { Actions = "actions and their parameters" } 'Event' = "optional modifiers, like mod1, ctrl, etc and a mouse button" { Actions = "actions and their parameters" } } Additional notes Modifiers and mouse buttons can be defined as "Any" which is useful for Enter and Leave events. Any also applies as none. Motion events have a threshold argument. This is the number of pixels you must drag your mouse before they begin to work. Multiple actions can be defined for a single user action. Example: Motion = "1" { Actions = "Move"; Treshold = "3" } ButtonPress = "1" { Actions = "Raise; ActivateClient" } pekwm-release-0.1.18/doc/config/keys_mouse/screenedge.xml000066400000000000000000000016231374756504400234060ustar00rootroot00000000000000 ScreenEdge Subsection The ScreenEdge subsection in ~/.pekwm/mouse defines the actions to take when an event happens on the specified screenedge. ScreenEdge { Left { Enter = "Mod1 Any" { Actions = "GoToWorkspace Left" } ButtonPress = "3" { Actions = "ShowMenu Root" } ButtonPress = "1" { Actions = "GoToWorkspace Left" } ButtonPress = "2" { Actions = "ShowMenu Goto" } ButtonPress = "4" { Actions = "GoToWorkspace Right" } ButtonPress = "5" { Actions = "GoToWorkspace Left" } } } It has four subsections: Up, Down, Left, and Right, that all refer to the screen edge in question. In these subsections you can give events and actions as usual. pekwm-release-0.1.18/doc/config/menu/000077500000000000000000000000001374756504400173375ustar00rootroot00000000000000pekwm-release-0.1.18/doc/config/menu/basic.xml000066400000000000000000000045521374756504400211500ustar00rootroot00000000000000 Basic Menu Syntax As previously indicated, the root and window menus follow the rules defined in . There aren't many possible options, and they're all either within the main menu, or within a submenu. This is all handled by a single file. As addition to the default menu types, RootMenu and WindowMenu, user can define any number of new menus following the same syntax. Here's an example ~/.pekwm/menu file, where we have the usual RootMenu and WindowMenu and our own most used applications menu called MyOwnMenuName: # Menu config for pekwm # Variables $TERM = "xterm -fn fixed +sb -bg black -fg white" RootMenu = "Pekwm" { Entry = "Term" { Actions = "Exec $TERM &" } Entry = "Emacs" { Icon = "emacs.png"; Actions = "Exec $TERM -title emacs -e emacs -nw &" } Entry = "Vim" { Actions = "Exec $TERM -title vim -e vi &" } Separator {} Submenu = "Utils" { Entry = "XCalc" { Actions = "Exec xcalc &" } Entry = "XMan" { Actions = "Exec xman &" } } Separator {} Submenu = "Pekwm" { Entry = "Reload" { Actions = "Reload" } Entry = "Restart" { Actions = "Restart" } Entry = "Exit" { Actions = "Exit" } Submenu = "Others" { Entry = "Xterm" { Actions = "RestartOther xterm" } Entry = "Twm" { Actions = "RestartOther twm" } } Submenu = "Themes" { Entry { Actions = "Dynamic ~/.pekwm/scripts/pekwm_themeset.pl" } } } } WindowMenu = "Window Menu" { Entry = "(Un)Stick" { Actions = "Toggle Sticky" } Entry = "(Un)Shade" { Actions = "Toggle Shaded" } ... SubMenu = "Send To" { Entry = "Workspace 1" { Actions = "SendToWorkspace 1" } Entry = "Workspace 2" { Actions = "SendToWorkspace 2" } Entry = "Workspace 3" { Actions = "SendToWorkspace 3" } Entry = "Workspace 4" { Actions = "SendToWorkspace 4; GoToWorkspace 4" } } ... Entry = "Close" { Actions = "Close" } } MyOwnMenuName = "Most used apps" { Entry = "Term" { Actions = "Exec $TERM &" } Entry = "XCalc" { Actions = "Exec xcalc &" } Entry = "Dillo" { Actions = "Exec dillo &" } } pekwm-release-0.1.18/doc/config/menu/custommenus.xml000066400000000000000000000025041374756504400224440ustar00rootroot00000000000000 Custom Menus User can also define an unlimited amount of custom menus. They are called with the ShowMenu action much like the Root and Window menus are (see ). In the example menu on this documentation, we created your own menu, called 'MyOwnMenuName'. Basically, outside of the RootMenu and WindowMenu sections, we open our own section called 'MyOwnMenuName'. This can of course be called whatever you want it to be called, but do note that the menu names are case insensitive. This means you can't have one menu called 'MyMostUsedApps' and one called 'mymostusedapps'. Lets see that example again, simplified: RootMenu = "Pekwm" { ... } WindowMenu = "Window Menu" { ... } MyOwnMenuName = "Most used apps" { Entry = "Term" { Actions = "Exec $TERM &" } Entry = "XCalc" { Actions = "Exec xcalc &" } Entry = "Dillo" { Actions = "Exec dillo &" } } We would call this new menu using the action 'ShowMenu MyOwnMenuName', The menu would show 'Most used apps' as the menu title and list 'Term', 'XCalc' and 'Dillo' in the menu ready to be executed. pekwm-release-0.1.18/doc/config/menu/dynamic.xml000066400000000000000000000032011374756504400215010ustar00rootroot00000000000000 Dynamic Menus It is possible to use dynamic menus in pekwm, that is menus that regenerate themselves whenever the menu is viewed. This is done with the Dynamic keyword. To use this feature, you need to put a dynamic entry in the ~/.pekwm/menu file with a parameter that tells pekwm what file to execute to get the menu. This file can be of any language you prefer, the main thing is that it outputs valid pekwm menu syntax inside a Dynamic {} section. The syntax of dynamic entry looks like this: Entry = "" { Actions = "Dynamic /path/to/filename" } The input from a program that creates the dynamic content should follow the general menu syntax encapsulated inside a Dynamic {} section. Variables have to be included inside the dynamic menu for them to work. A simple script to give pekwm dynamic menu content would look like this: #!/bin/bash output=$RANDOM # gets a random number echo "Dynamic {" echo " Entry = \"$output\" { Actions = \"Exec xmessage $output\" }" echo "}" This script would output something like: Dynamic { Entry = "31549" { Actions = "Exec xmessage 31549" } } Clients can access the PID and Window that was active when the script was executed via the environment variables $CLIENT_PID and $CLIENT_WINDOW. $CLIENT_PID is only available if the client is being run on the same host as pekwm. pekwm-release-0.1.18/doc/config/menu/keywords.xml000066400000000000000000000043301374756504400217300ustar00rootroot00000000000000 Menu Keywords Here are the different elements that can be used in your root menu file. Root Menu Elements: Submenu (Name) Begins a submenu. 'name' is what will appear in the root menu for the entry. Entry (Name) Begins a menu entry. 'Name' is the text shown in the menu for this entry. Actions (Action) Run an action. 'Action' is the action(s) to run. Most actions listed in will also work from the root and window menus. Icon (Image) Set icon left of entry from image in icon path. Separator Adds a separator to the menu. Menu Actions: Exec Exec makes pekwm to execute the command that follows it. Make sure the program gets backgrounded. Put an '&' at the end of the action if it doesn't do this on it's own. ReloadWhen this is called, pekwm will re-read all configuration files without exiting. RestartThis will cause pekwm to exit and re-start completely. RestartOtherQuits pekwm and starts another application. The application to run is given as a parameter. ExitExits pekwm. Under a normal X setup, This will end your X session. Of course, in addition to these, many actions found from also work. pekwm-release-0.1.18/doc/config/menu/menu.xml000066400000000000000000000010601374756504400210220ustar00rootroot00000000000000 Configuring the menus The root menu is what you get when you (by default- See the section) left-click on the root window (also called the desktop). You can also configure the window menu, which you get when you right-click on a window title. &config-menu-basic; &config-menu-keywords; &config-menu-custommenus; &config-menu-dynamic; pekwm-release-0.1.18/doc/config/start/000077500000000000000000000000001374756504400175305ustar00rootroot00000000000000pekwm-release-0.1.18/doc/config/start/start.xml000066400000000000000000000020011374756504400214000ustar00rootroot00000000000000 The pekwm start file The ~/.pekwm/start file is the simplest of all of pekwm's config files. It's a simple shell script that's run on pekwm startup. Therefore, to run, it needs to be set executable with chmod +x ~/.pekwm/start. Why anyone would use start rather than just use their ~/.xinitrc file? Well, the answer is, the start file is executed during the pekwm initialization phase - therefore, it gets re-executed when you issue a pekwm 'restart'. Here's an example pekwm start file. Be careful to place long running applications to the background, or you will seem stuck when trying to start pekwm. #!/bin/sh xmessage 'hi. pekwm started.' & some_command & pekwm-release-0.1.18/doc/config/syntax/000077500000000000000000000000001374756504400177215ustar00rootroot00000000000000pekwm-release-0.1.18/doc/config/syntax/basic.xml000066400000000000000000000027731374756504400215350ustar00rootroot00000000000000 Basic Syntax All pekwm config files (with the exception of the start file- see ) follow a common syntax for options. # comment // another comment /* yet another comment */ $VARIABLE = "Value" $_ENVIRONMENT_VARIABLE = "Value" INCLUDE = "another_configuration.cfg" COMMAND = "program to execute and add the valid config syntax it outputs here" # Normal format Section = "Name" { Event = "Param" { Actions = "action parameter; action parameter; $VAR $_VARIABLE" } } // Compressed format Section = "Name" { Event = "Param" { Actions = "action parameters; action parameters; $VAR $_VARIABLE" } } You can usually modify the spacing and line breaks, but this is the "Correct" format, so the documentation will try to stick to it. Events can be combined into the same line by issuing a semicolon between them. Actions can be combined into the same user action by issuing a semicolon between them. You can use an INCLUDE anywhere in the file. Pekwm has a vars file to set common variables between config files. Variables are defined in vars and the file is INCLUDEd from the configuration files. Comments are allowed in all config files, by starting a comment line with # or //, or enclosing the comments inside /* and */. pekwm-release-0.1.18/doc/config/syntax/syntax.xml000066400000000000000000000004041374756504400217670ustar00rootroot00000000000000 The Pekwm Common Syntax for Config Files &config-syntax-basic; &config-syntax-templates; &config-syntax-variables; pekwm-release-0.1.18/doc/config/syntax/templates.xml000066400000000000000000000030761374756504400224470ustar00rootroot00000000000000 Template Syntax The pekwm configuration parser supports the use of templates to reduce typing. Template support is currently available in autoproperties and theme configuration files. Template configuration is not fully compatible with the non-template syntax and thus requires activation to not break backwards compatibility. To enable template parsing start the configuration file with the following: Require { Templates = "True" } Defining templates is just like creating an ordinary section, but uses the special name Define. Below is an example defining a template named NAME: Define = "NAME" { Section = "Sub" { ValueSub = "Sub Value" } Value = "Value" } The above defined template can later be used by using the magic character @. The below example shows usage of the template NAME in a two sections named Name and NameOverride overriding one of the template values: Section = "Name" { @NAME } Section = "NameOverride" { @NAME Value = "Overridden value" } The above example is equivalent of writing the following: Section = "Name" { Section = "Sub" { ValueSub = "Sub Value" } Value = "Value" } Section = "Name" { Section = "Sub" { ValueSub = "Sub Value" } Value = "Overridden" } pekwm-release-0.1.18/doc/config/syntax/variables.xml000066400000000000000000000021431374756504400224130ustar00rootroot00000000000000 Variables In Pekwm Config Files Pekwm config enables you to use both internal to pekwm variables, as well as global system variables. Internal variables are prefixed with a $, global variables with $_. # examples of how to set both type of variables $INTERNAL = "this is an internal variable" $_GLOBAL = "this is a global variable" # examples of how to read both type of variables RootMenu = "Menu" { Entry = "$_GLOBAL" { Actions = "xmessage $INTERNAL" } } There is one special global variable pekwm handles. It is called $_PEKWM_CONFIG_FILE. This global variable is read when pekwm starts, and it's contents will be used as the default config file. It will also be updated to point to the currently active config file if needed. Variables can probably be defined almost anywhere, but it's probably a better idea to place them at the top of the file, outside of any sections. pekwm-release-0.1.18/doc/config/theme/000077500000000000000000000000001374756504400174755ustar00rootroot00000000000000pekwm-release-0.1.18/doc/config/theme/explanation.xml000066400000000000000000000157761374756504400225610ustar00rootroot00000000000000
Attribute names used, explanations, possible values, examples Here is the explanation of Attributes names of themes Attributes: pixels An integer, amount of pixels. example: "2" size Pixels vertically times pixels horizontally. example: "2x2" percent Any percent value from 1 to 100. example: "87" toggle sets a value as true (1) or false (0). example: "true" padding Free pixels from top, free pixels under, free pixels from left, free pixels from right. example: "2 2 2 2" decorname Name for decoration, any name can be used and applied to windows with autoproperties or the set decor action. The list below includes names with special meaning: DEFAULT Defines decorations to all windows unless overridden with another decoration set (REQUIRED). ATTENTION Defines the decoration for windows that set the urgency/demand-attention hint. BORDERLESS Defines decorations for borderless windows (recommended). INPUTDIALOG Defines decorations for input dialogs, such as the CmdDialog. MENU Defines decorations for menus. STATUSWINDOW Defines decorations for the command dialog. TITLEBARLESS Defines decorations for titlebarless windows (recommended, should be there if your theme looks nasty when toggled titlebarless). WORKSPACEINDICATOR Defines decorations for the workspace indicator. colour A colour value in RGB format. example: "#FFFFFF" imagename Name of the imagefile with an option after the # #fixed Image is fixed size. #scaled Image will be scaled to fit the area it's defined for. #tiled Image will be repeated as many times as needed to fill the area it's defined for. This is the default if no option is specified. texture Any valid texture. Valid textures are: EMPTY No texture (transparent). SOLID colour size A solid colour texture of defined colour and size. SOLIDRAISED colour colour colour pixels pixels toggle toggle toggle toggle size A solid colour texture with a 3D look of defined colours, form and size. First colour defines the main fill colour, second the highlight colour used on the left and top parts of the texture, third the highlight colour on the bottom and right parts of the texture. First pixel amount defines how fart apart the 3D effects are from each other, second pixel amount is how thick the bordering will be (both pixels default to 1). The four toggles are used to tell which raised corners are to be drawn. This is useful for example when defining solidraised frame corner pieces. The order is Top, Bottom, Left, Right (not unlike that used in padding). As example: "True False True False" (or 1 0 1 0) could mean you want to draw the TopLeft piece of a solidraised window border. Size should explain itself, see above. IMAGE imagename An image texture using the defined imagename fontstring Defines a font. Chopped to parts by # marks. First the font type (XFT or X11), then the font name, then the text orientation, then shadow offsets. Some fields can be omitted. example: "XFT#Verdana:size=10#Left#1 1" example: "-misc-fixed-*-*-*-*-14-*-*-*-*-*-*-1#Center#1 1" buttonactions Buttonactions work alike what you are used from the mouse config, first mouse button number pressed when this action should happen, then any standard pekwm actions. example: "1" { Actions = "Close" }
pekwm-release-0.1.18/doc/config/theme/guidelines.xml000066400000000000000000000034611374756504400223530ustar00rootroot00000000000000
Guidelines It is strongly recommended and expected that theme tarballs are labeled for the pekwm version they are made and tested with. The filename format should be theme_name-pekwm_version.[tar.gz|tgz|tar.bz2|tbz]. For example silly_theme-pekwm_0.1.5.tar.bz2. It is also highly recommended that theme directories are named in a similar fashion. However, for stable releases this is not mandatory, the tarball filename is enough. If you're building for a GIT revision, mention it in as many places as possible. The silly theme from above would contain a directory structure as follows: silly_theme-pekwm_0.1.5/ pekwm_0.1.5/theme pekwm_0.1.5/menubg.png pekwm_0.1.5/submenu.png The theme file header should contain at least the themes name, the pekwm version the theme is for, address to reach the theme maker/porter or get an updated theme, and a last modified date. Changelog entries won't hurt if you aren't the original theme author. For example: # silly, a PekWM 0.1.5 theme by shared (themes@adresh.com) # This theme is available from hewphoria.com. # Last modified 20060529. # Extract this theme directory under ~/.pekwm/themes/ and the # themes menu will pick it up automatically. # Changelog: # 2006-05-29 HAX0ROFUNIVERSE <hawt@haxorland.invalid> # * REWROTE EVERYTHING WITH CAPS LOCK ON, # CAPS LOCK IS CRUISE CONTROL FOR COOL! Try to stick to the theme syntax and rather than deleting entries please use the EMPTY texture.
pekwm-release-0.1.18/doc/config/theme/structure.xml000066400000000000000000000301761374756504400222660ustar00rootroot00000000000000
Theme structure
PDecor The block for decoration sets, any amount of Decor sections can exist inside this block.
Decor A list of blocks with theme specifications the various types of decorations.
Title Theming of the frame. Height (pixels): Amount of pixels the titlebar should height. HeightAdapt (boolean): If true, Height is adapted to fit the Title font. Pad (pixels t,l,r,b): How many pixels are left around a title text. Focused (texture): Background texture for a focused titlebar. UnFocused (texture): Background texture for an unfocused titlebar. WidthMin (pixels): Minimum width of title in pixels, will also place the titlebar outside of the window borders. Use 0 to place titlebar inside borders. WidthMax (percent): Maximum width of titles relative to window width, when this value ends up being smaller than the value in WidthMin, WidthMin is overridden. WidthSymetric (boolean): Set true to constant width titles or false to use titles that only are as big as the clients title text string requires (note, asymmetric width is not fully implemented yet, always set this true for now to avoid problems).
Tab Theming of a titlebar tabs. Focused (texture): Background texture for a tab of a focused window. Unfocused (texture): Background texture for a tab of an unfocused window. FocusedSelected (texture): Background texture for the currently selected tab of a focused window. UnFocusedSelected (texture): Background texture for the currently selected tab of an unfocused window.
FontColor Theming of font colors. Focused (colour colour): Text colour for a tab of a focused window. second value is the shadow colour. Unfocused (colour colour): Text colour for a tab of an unfocused window. second value for shadow. FocusedSelected (colour colour): Text colour for the currently selected tab of a focused window. second value for shadow. UnFocusedSelected (colour colour): Text colour for the currently selected tab of an unfocused window. second value for shadow.
Font Theming of the titlebar fonts. Focused (fontstring): Font of the text of a tab of a focused window. Unfocused (fontstring): Font of the text of a tab of an unfocused window. FocusedSelected (fontstring): Font of the text of the currently selected tab of a focused window. UnFocusedSelected (fontstring): Font of the text of the currently selected tab of an unfocused window.
Separator Theming of the tab separator. Focused (texture): Separator texture for a focused window. Unfocused (texture): Separator texture for an unfocused window.
Buttons Theming of titlebar buttons.
Right = "Name" Places the button on the right end of the titlebar.
Left = "Name" Places the button on the left end of the titlebar. Focused (texture): Texture for button of a focused window. Unfocused (texture): Texture for button of an unfocused window. Pressed (texture): Texture for button that is pressed. Hover (texture): Texture for button when pointer is placed on it. SetShape (bool): If true, the shape of the button is derived from the alpha-channel. If false, the alpha-channel sets only the transparency. (defaults to true) Button (buttonactions): Configures what to do when a button is pressed.
Border Theming of the borders. Focused: borders for focused windows. UnFocused: borders for unfocused windows. TopLeft (texture): Texture for the top left corner. Top (texture): Texture for the top border. TopRight (texture): Texture for the top right corner. Left (texture): Texture for the left border. Right (texture): Texture for the right birder. BottomLeft (texture): Texture for the bottom left corner. Bottom (texture): Texture for the bottom border. BottomRight (texture): Texture for the bottom right border.
Harbour Enables theming of the harbour. Texture, texture: Texture to use as the harbour background.
Menu Themes the insides of a menu window. Pad (padding): How many pixels of space around an entry is reserved.
State One of Focused, Unfocused and Selected defining the appearance when the menu/submenu is focused, not focused and the menu entry currently selected. Font (fontstring): What font to use. Background (texture): A texture that starts from the top of the menu and ends on the bottom. Item (texture): A texture that starts from the top of a menu entry and ends on the bottom of the entry. Text (colour): Colour of text to use. Separator (texture): Texture to use as separator (required, client menu will break if none is defined). Arrow (texture): Texture to use for indicating submenus (you want this to be defined too).
CmdDialog Themes the insides of a command dialog window. Font (fontstring): What font to use. Texture (texture): Texture to use as the background. Text (colour): Colour of text. Pad (padding): Amount of pixels of space around font to reserve.
Status Themes the insides of the status window that shows up when moving windows and so on. Font (fontstring): What font to use. Texture (texture): Texture to use as the background. Text (colour): Colour of text. Pad (padding): Amount of pixels of space around font to reserve.
WorkspaceIndicator Themes the workspace indicator that shows up when switching workspace. Font (fontstring): What font to use. Background (texture): Background for the whole window. Workspace (texture): Texture to use when rendering a workspace. WorkspaceActive (texture): Texture to use when rendering the active workspace. Text (colour): Colour of text. EdgePadding (padding): Amount of pixels of space around window edges and workspaces. WorkspacePadding (padding): Amount of pixels of space between workspaces.
pekwm-release-0.1.18/doc/config/theme/theme.xml000066400000000000000000000007171374756504400213260ustar00rootroot00000000000000 Pekwm themes This section aims to documenting the pekwm theme structure. It's rather cryptic at first look, sorry. Please use existing themes as real life examples and base when it comes to making your own. &config-theme-guidelines; &config-theme-explanation; &config-theme-structure; pekwm-release-0.1.18/doc/css/000077500000000000000000000000001374756504400157165ustar00rootroot00000000000000pekwm-release-0.1.18/doc/css/pekwm-docs.css000066400000000000000000000005731374756504400205060ustar00rootroot00000000000000body { width: 65em; margin-top: 120px; margin-left: auto; margin-right: auto; font-family: sans-serif; } div.TITLEPAGE div.mediaobject p img { position: absolute; top: 15px; } div.TITLEPAGE h1 { display: none; } div.TITLEPAGE h2 { font-size: large; } div.TITLEPAGE h3 { font-size: medium; display: inline; padding-left: 1em; } pekwm-release-0.1.18/doc/development/000077500000000000000000000000001374756504400174505ustar00rootroot00000000000000pekwm-release-0.1.18/doc/development/devel/000077500000000000000000000000001374756504400205475ustar00rootroot00000000000000pekwm-release-0.1.18/doc/development/devel/bugtracker.xml000066400000000000000000000012761374756504400234300ustar00rootroot00000000000000 Bug Tracker Pekwm bug tracker can be reached at pekwm.org . It is based on septic, so bugs are inside tasks. Tasks can be reported and viewed. One can even include a patch to resolve one. Aside from bugs, tickets also eat feature requests. pekwm-release-0.1.18/doc/development/devel/help.xml000066400000000000000000000000001374756504400222070ustar00rootroot00000000000000pekwm-release-0.1.18/doc/development/devel/irc.xml000066400000000000000000000065201374756504400220510ustar00rootroot00000000000000 IRC Our IRC channel #pekwm is located on irc.freenode.net. A lot of development discussion goes on there, however you can also get simple help there pretty easily. The following is a "do not" list. If some idiotic behaviour like, public away messages, or nick changing as a way of telling what you are doing, are not mentioned it doesn't mean you can do them. As it seems to be a problem for some, do not ask questions in IRC unless you are willing to listen to the answer. If listening is your problem, you need other help than what we at IRC can provide. If you have a question, ask it. It doesn't help to go around shouting "can anyone help me". Help you with what? This will help the right people to take initial contact with you, saving your time and adding less clutter to the channel. For same reasons, don't ask if we are alive or other meaningless questions leading to the real question. Don't ask if someone specific is around either. This is not the pager channel for you and your friends. Do not ask from one person. The fact is, even how much you think he or she must be the only one who knows the answer, you are wrong. There's at least a handful of people lurking on the channel who could help you. Read the documentation and FAQ before you ask anything. Doing this is common courtesy towards the people who answer your questions. Not reading at least the FAQ will be considered rude. When asking a question, the answer more than often depends on the version of pekwm you use. Showing us the information the command pekwm --info gives will help us help you. Do not expect people to answer your questions during the two minutes you stay in the channel. We can't sit there all the time waiting for your questions. If you can't wait longer, think about how stressful your life is, take a break, go on a vacation, take it easy for a while. For similar reasons, don't repeat yourself. We saw it the first time. Repeating easily gets you ignored completely so it eats its own purpose. It's also considered rude, much like cutting in line. If people tell you to read the documentation, they have a good reason to do so. If they include an URL that helps you find the info quicker, offer them your firstborn as a payback. Don't offend anyone. They will offend you back two times. Nicks with excessive capital letters will be hunted down and shot on sight. You might as well use a proper nick to start with to avoid this. You can check the section to see the list of developers mapped to their IRC nicks. As with all IRC channels, it's best to not do anything too drastic before keeping an eye for a while on how the channel works. We won't mind even if you just idle there, there are long standing traditions on that. Welcome aboard! pekwm-release-0.1.18/doc/development/devel/ml.xml000066400000000000000000000012201374756504400216740ustar00rootroot00000000000000 Mailing Lists The pekwm mailing list is used for questions, comments, development talk and announces. You can only post to the list as a subscriber! Please subscribe before posting using the web interface mentioned above. Include your pekwm --info output with your questions and generally try to be as clear as possible so that everyone understands you. pekwm-release-0.1.18/doc/development/devel/who.xml000066400000000000000000000020771374756504400220740ustar00rootroot00000000000000 The developers Below is a list of pekwm developers and what they do. The email address is more of an informational thing than anything else; the developers all subscribe to the + pekwm mailing list, so you should email that instead. Developers: &program-author; (aka &program-author-nick;) &program-author-email; Main developer- Writes code. Has a serious screenshot fetish. Jyri Jokinen (aka shared) shared@adresh.com Writes documentation. Acts ill-tempered. You have been warned. pekwm-release-0.1.18/doc/development/development.ent000066400000000000000000000003501374756504400225000ustar00rootroot00000000000000 pekwm-release-0.1.18/doc/development/development.xml000066400000000000000000000005501374756504400225140ustar00rootroot00000000000000 Development Interested in pekwm? Want to keep up with the development? Good, we can tell you how. &devel-ml; &devel-irc; &devel-bugtracker; &devel-who; pekwm-release-0.1.18/doc/faq/000077500000000000000000000000001374756504400156755ustar00rootroot00000000000000pekwm-release-0.1.18/doc/faq/answers/000077500000000000000000000000001374756504400173575ustar00rootroot00000000000000pekwm-release-0.1.18/doc/faq/answers/answers.xml000066400000000000000000000443131374756504400215700ustar00rootroot00000000000000 Common questions and answers How is this ~/.pekwm/start thing used? The file ~/.pekwm/start is a regular shell script that is executed when pekwm starts. The file needs to be chmodded as executable (chmod +x) for it to get used. A simple example start file could look like this: #!/bin/sh gkrellm & Esetroot -s mybackground.png & Remember the &'s. What is the harbour and how is it used? Harbour is pekwm's way of supporting dockapps, special small applications that usually display things like system information or the status of your email inbox. It's essentially the same thing you might know as a dock or a wharf. The harbour is not a KDE/GNOME systray for notification icons. If you want notification icons in the harbour, you need to find a dockapp that does this for you. If a dockapp doesn't go into the harbour even you have it enabled at compile time, you should see if the application has an option to start it "withdrawn". Can I have automatically changing menus in pekwm? Yes. The Dynamic keyword is a way to use automatically generated menus in pekwm. That is, menus that regenerate every time you view them. As an example, by default the themes menu is dynamic. See for more information. How do I install themes? The idea is to unpack/uncompress the theme file you downloaded into some directory. In this case, we will unpack it to ~/.pekwm/themes, which is the standard location for user installed themes. In simple, first make sure the themes directory exist, and if not, make it by issuing the command mkdir ~/.pekwm/themes. Then copy the theme package, lets call it theme.tar.gz, into ~/.pekwm/themes. Then uncompress the theme pack with the appropriate tool. Unpack the theme with: gzip -dc theme.tar.gz | tar xvf - You will then end up with a new subdirectory - this is the theme. Since we uncompressed the theme in a standard location, after this you can select the new theme from the themes menu. If you installed in a non-standard location, you'll have to manually edit ~/.pekwm/config. In the top of this file there is a section named "Files {}". In this section, there is a line that says something like: Theme = "/usr/local/share/pekwm/themes/minimal" Edit this line to point to the directory you installed the theme. Restart pekwm and you're set. I upgraded pekwm and now ......... won't work! Pekwm has not yet achieved a freeze on it's configuration file syntax. And as pekwm is an actively developed application, there probably have been some changes on some part of the configuration. If you encounter a situation that when you upgrade your pekwm, and some thing just stops to work, you should either: Move your old configuration out of the way - Move your pekwm configuration files out of ~/.pekwm ( mv ~/.pekwm ~/old.pekwm), which will result in new fresh configuration files being copied in. If this helps, your configuration files weren't compatible with the new version of pekwm. Check the wiki - If something configurable wise has been changed, it has been documented on the wiki page for the release. You can find the wiki on pekwm's homepage. This is a helpful resource when you want to convert your old configuration files to a newer configuration format. Look under the source trees data/ directory for reference - If you can't find info about a new feature or for some reason you don't understand the brief explanation on the wiki, there is a data/ directory in the source package of pekwm that has example configuration files (these act as the default configuration on a new install). Chances are you'll find help from there. Read the documentation. - You can find links to up to date documentation for your pekwm version at the pekwm homepage. Make sure the right executable is being executed. - Locate all instances of pekwm (find / -name 'pekwm'). If you see many pekwm executables laying around, maybe one in /usr/bin and one in /usr/local/bin, you might be starting a wrong version pekwm. This might happen when you for example, install a premade pekwm package for your distribution and later install pekwm from source yourself. The safe way is to remove all these pekwm instances and either re-apply the package or do make install again in the source. You can also, of course, go thru every pekwm binary with the --version parameter to find the right executable to keep. Note to give the full path to the executable when querying for the version (/usr/local/bin/pekwm --version). Can I turn off this sloppy focus crap? Yes. You can. You need to make all enter and leave events not affect the focus of frames, borders, clients. Simply, just comment out all the Enter lines that use the action Focus in ~/.pekwm/mouse. The default ~/.pekwm/mouse configuration file has helpful "# Remove the following line if you want to use click to focus." notes in it to make this easier. Just search for such lines and remove or comment out the line (using a # in front of the line) next to the message. See for more info on the mouse configuration file. What is Mod1? How about Mod4? In the ~/.pekwm/keys and ~/.pekwm/mouse there are all these odd Mod1 and Mod4 things used as modifier keys. It's simple - Mod1 is more widely known as the Alt key, and Mod4 as the "windows key" found on recent keyboards. Use xev to find out what names keys carry. Why do my terminals start the wrong size when grouped? This is a very complicated issue in fact, and has to do with the way terminals handle their resize actions. One way to bring at least some help to this situation is to put resize > /dev/null in your .bashrc or equal. Where can I find the current size/position of a window? Use the command xwininfo | grep geometry. How do I bring up the window menu when the window has no decorations? You press keys. The default keybinding for window menu is at the moment first Ctrl+Mod1+M, then W (or Mod4+W for short). You can specify your own keybinding for window menu at the ~/.pekwm/keys configuration file. See for information on how to edit keybindings. The start file doesn't work! chmod +x ~/.pekwm/start. Yes, this is a duplicate of the first FAQ entry. Just making sure we never have to see this question in IRC anymore. How do I set a background/root/desktop image? In simple terms, you use any program that is capable of setting background images. What? Want links too? Because you asked nice, here's feh and hsetroot. If you have Eterm installed you have a program named Esetroot, that will set you backgrounds. There's a million of similar apps, and this is no place for a comprehensive list of them. You want that the background gets set automatically when you start pekwm? Add the command for setting background in to your pekwm start file located at ~/.pekwm/start. Remember to chmod +x. A theme I tested doesn't work! Pekwm is an ongoing process. This means the theme file format has gone thru considerable amounts of changes. Some of these changes are backwards compatible, some are not. You have hit a theme with too old or too new theme syntax for your copy of pekwm. Nothing can be done unless someone who knows the differences between theme formats owns you a favour and agrees to edit it out for you. Pekwm shouldn't refuse to start again after a faulting theme test, but you will usually see everything scrambled up. In this case you can either try to select a new working theme from the menu or change the theme used manually. This is done in ~/.pekwm/config. Under the Files-section, there is an entry named Theme, that points to your current theme. It might look something like this: Files { Theme = "/home/shared/.pekwm/themes/blopsus9-blaah" } Now, all you need to do is make the path point to any theme you know is working. The default theme is usually a safe bet. After edited and saved, (re)start pekwm. What desktop pagers work with pekwm? For general use any NETWM compliant pager should do. IPager, screenpager, rox-pager, fbpanel's pager, obpager, gai-pager, gnome's pager, kde's pager, perlpanel's pager, netwmpager, and so on. Do report your success stories with pagers not already mentioned here. How do I make submenus open on mouse over rather than when clicked? You need to edit ~/.pekwm/config. Open it in an editor and search for the Menu section towards the end of the file. It should look somewhat like this: Menu { # Defines how menus act on mouse input. # Possible values are: "ButtonPress ButtonRelease DoubleClick Motion" # To make submenus open on mouse over, comment the default Enter, # uncomment the alternative, and reload pekwm. Select = "Motion" Enter = "ButtonPress" # Enter = "Motion" Exec = "ButtonRelease" } To make submenus open on mouse over, remove or comment out the line Enter = "ButtonPress" and remove the # character from this line: # Enter = "Motion" so that it looks like this: Enter = "Motion" and you should be fine. Reload pekwm configuration from the menu or press ctrl+mod1+delete to do it with a keybinding. Test your semiautomatic pekwm menus! The default requires you to click because of dynamic menus. While reasonably fast, they can sometimes take a second or two to be generated depending on the script behind it. Browsing the menu tree can at such times become more annoying, specially on a slower machine, than having to do that extra click. There you have it, our reasoning and the solution for if you don't like it. My keyboard doesn't have the window keys, the default key bindings suck! Probably the easiest way to use the default keybindings on a keyboard that has no window keys is to assign some other key the Mod4 status. Since Caps Lock is one of the most unused and annoying keys around, we'll make it the Mod4 modifier by adding the following lines to ~/.pekwm/start: # Make Caps Lock act as Mod4 xmodmap -e "remove lock = Caps_Lock" xmodmap -e "add mod4 = Caps_Lock" Remember to chmod +x ~/.pekwm/start, then restart pekwm. Your caps lock key should now act as Mod4. Oh joy. Where's my Unicode support? Edit your favorite theme to use your preferred Unicode font, and enjoy all kinds of characters on the titlebars and menus. Where did my titlebar buttons go? Buttons require a name to be set when template based syntax is enabled in themes or the last button will be the only visible one. Using this syntax will create only one button: Require { Templates = "True" } Buttons { Left { @button } Left { @button } } Given names, both buttons will be created: Require { Templates = "True" } Buttons { Left = "button1" { @button } Left = "button2" { @button } } How can I disable the workspace indicator popup? In the main configuration file under the Screen section there should be a ShowWorkspaceIndicator parameter, set this to 0 to disable the WorkspaceIndicator. Why is nvidia dual-head misbehaving? The nvidia proprietary driver provides dual head information both in Xinerama and RANDR form. The RANDR information given by the driver is in the form of one large screen, the Xinerama is divided up into multiple heads. To work around this the HonourRandr option has been introduced in the Screen section of the main configuration file. Set it to False making pekwm only listen on the Xinerama information. Screen { ... HonourRandr = "False" ... pekwm-release-0.1.18/doc/faq/faq.ent000066400000000000000000000001231374756504400171500ustar00rootroot00000000000000 pekwm-release-0.1.18/doc/faq/faq.xml000066400000000000000000000015311374756504400171660ustar00rootroot00000000000000 The pekwm FAQ This is the official pekwm FAQ. Here you can find answers to the questions and cries for help frequently appearing in the pekwm IRC channel and mailing lists. If you can't find the answer to your question here, read the whole thing again. Chances are you just missed it the first time around. If you still can't find it, and you have gone through the documentation, tried until your fingers bleed from typing, and started a hunger strike against evil documentation projects that contain no helpful advices for you, then you may ask your question in IRC or on the mailing list. &faq-answers; pekwm-release-0.1.18/doc/img/000077500000000000000000000000001374756504400157025ustar00rootroot00000000000000pekwm-release-0.1.18/doc/img/pekwm_logo.png000066400000000000000000000213221374756504400205530ustar00rootroot00000000000000PNG  IHDRaMsRGBbKGD pHYs B(xtIME.%Bl IDATx]ixU~OU/t7"`YdQ!P\h\0̀3: :6dfqc+1!FA0PA {Hg:ߏ4B':+>O~{=0` 0` 4P%-U]0; A\zɪ""|DS]L&?tR%'-Dοcm_ljɓ\c\;MJt~Hж]F>/WM{#55#sJpy 23 ZאGڞ 9u&U8:VrBtVB'80fm5j?`PBCJ+jz7Ǭm(3 5*)DؘmgKۦ/v Rуe:.;Ze;8ˠxxMF 4lu,w +s,({>v9O{VD'g7BP45-gzбh`Ls}.)Z9`reZ}pv^V=m_/6> ^=T_Gp^DX3<]g2 7Ӽw^vb3UZ-kduB<;QG;` O9'4$o]P \MDy3b JP45vØl_\qPH BV4˽g:V8GԐ svTGDz TpP!`/Hsiy 7Ke0CYw8!7joU2@B!ڈwlLޜA/=9F1hَ ܇`9.`T3`7!(Oӓ?5im4_m 8Bׁ0wIwio}}~c Vz_'xXjOPŝ4^x]F *{Qרr4z@ڳTѾ[.<HR70CG?h?Hm4*hJ2{7'*Pv >x& nn ^)Zoftr44"4NtohӨt t-+ׁ+hҟkv! U[":g8ǃ:cAnRv`ӹ *~n :vdk趱Yt .m0l<}[OjN(^ Dtf)lI@ Es ` "B!xBc=hmp[r_ y{ˢn[[k@3AW(7HwBPѼӯ!@`_Ztp^0N. M f`](WIfaP%,t)CY ҺLKU @inѼU băHiƽ,{:5va 7A_Y7ZAf Ma?Z fNO愑tn|88n[7Ò4U[MW@ߛ d9)W]+q )kA/g^hjymMgf83S928=$+W+KAV;jбĮ`S K'p/{oV\3ۖC8Rl$tT,o]>vIπp}"͕ٜV *jeLJYe ;.l@7ћp ieN@ >,QcM0>Ӱ>-$SW\F90^ 1hscp8 K@LEP6W䁶,M6u!r4N>x;} y7geϴzGeN\t;9No4W2zlkk!ZIyNl(@Y>g:> k sarzbo%zhӛ|{:6V} ;bDpC)Yl4󸒊^ȃ`5 NO*\9WU[0]&>.3mT؍iB(AYO8ñ 0J9Ӿ断uv1N L\ùMr'AvAИqbmh-a3fWg} 1wlZ.ZN  Bޱ 7@i>{SQs!\< ~U){vHQ 9z֟d `<1 K^%4d &.}oznjWV?eŴq=1GL՜i3# ?BY/g]sQlݦo&I0`l3 S4x?}xa5 Pˡ]u B"QH>V_Q;i^ב[9D^a%߷ '66K~0 WčcM7XwJy+YDwM;cF*sUskkY{#SeOC~}0˥_Z-&ZDMKs˶̳֙8#kw'0_1KwzOPwAYTus2\/n~෣7WJ`kV0 W]7bFh$aAm@m/:+u({lN~@yv|bHޮwT"|W]#0ֻ@ظA]WA} p߁C_̎҅j =ABgmFÜ gGδ߇@ck |JeL.I4SMz (9:CߙFvxaoox#@\{Yg%::LX30[SpYmPt a?'<\+0{ޱX Ɲ:F3täިGb o"֭PjO+w~̯L=ޤ~ yP_VVPTxڎb-/nnE/&<3GsL#6˄%]gͱ{V\?H %X-}ͶOVޫ:S1 &X[ ᜑOYeOC~ ~ Q\Fr:ZkV"UR$r;?46{khy2_\FY ߱6Qt't9 t(lsHjjeUh Kzb/϶;u5Oc r҄g9/eyǴGM@ă, J@5C;QUPXbqm!7C0~ZoBr+<.d3zހAPiT<4%Ud_ꛫwxF0 5(s+KXvȰۍ7`=_z[ޤrbξA>jw WG G6B˛@}ՠG~B嚗Wa}'!IҕiiiFKDzU|l&S\ǵzj%V+$&&v3-++y^JD6"At#P>UX5B ;3{< |,3{9'$BЍV*iզ{p{_].#`Q'y|cH$IZ9"M$NzzU==y>TOC_II̙> )̼J.++{U1kM] !vPvEpsP֯q[/!|b H- !#~2ߗ ??l":K999͎`L>3Ow [QPw绺Oz c0v_g}>b5/,,\ %~@.k.)tO7;eY23ɲpdf;mZVw▤iWYMY j{<Dkx-ݦҵĠqp\nf^ N蹂֑HL $˛_ehByu Bk8z庤h_t'nɤ(Y+-#7C;.=rpCypN2{iۿ=ҜZrrjo2L,W2VDDUv8SuuNzzl3?Af{"]fP(@ƎOQ|jI"0--m\nnǍնGpvбM(}&J+Tw%t7TnI ^8mQQfnKQ$$iiɡIGM"Zp8&%yjjP93ώ EV +V(&/---QQ5u8쪪v/lruZK;\+%{UTa:nM{  n۾s\U_ ~_XX" %IxBg^zH~׶s\/@_pY~~K+))i m:\Z33cEdU .?>4Ѝ;sa0YOxN0u#hDVUs $yg^~sr$@ ux!|3->nOG 0v_k(x3tH0la:C/ a>j}>rŵc 8YY@Рꌵ/¡D( 3^1h\ @m ];A.777>/_O\U{ު{@̓_}R*JDZh_kn^͆lZ5A=BٵAi>;G;bѮ[>khy0LBr5YuaQUUJrIFFr"Zp-$,*$i$I@Ck Li0dG]hMW}*U7Uތ+ppۣo:MFf:gܸq$BD D4bʕQoE$:~Byyrzz 3.|LD>:ߠQ]#E]r%*WAe]`98XlkP|$9 µ,F! 3 5$Peǵ,M͍;CcfkCry5VuBj#^zNJt^x8(77F`K\Z; ɥ7AVx6uuo5ĨsSE=2 --X;==vXPu_v+ZK$B/ogA;5z]A8\QK4h=3/ k睖6JuasQDKqƝ#rQ=InEE% E(((uL>֏Ϲ狢&L N󵨉Yw*w9yh4 uMBwذaAz F7IXx7߻Zn{LUՏp¹'HDv}TXFe˲1E1>oBR44rrrM&8": +\.WKNNs\ @O>;;Bų:f@r+UpLP1MV_ǣ+´dS$IO#DJL|z:tqt=%Izf!>zYZ1a"&// KS]k{@DE$Dp%Ifm#"8>mzݦjK ehh_ iPz`W<&%\hf=xѽUU*ϬN,k.F3*IfVTT]PP $Vu0ѵ<4BDϗgֵT]Wz#''<99Z*P RZf$eY ท{Pzia '5;zk;A]/HJJzn#kɌ].jA|UU b?I8$MF8 e6Lb"uM/N׻1Ue)=L$kT[ 1m[M<17z?u߅r$PaB< ˄gD;f#ARd;<~ˇňeyAkzϵ&WB7_A"UwCDr7$GMg9/eyW*/ M'IP FIDATO\@a5cЏ}@yU3 AX ҷԕћ$IVs>Y>#LUlٿud"Z&b-iiiQ&)45ݻw7 E@Q[n]aENhg <.$qt B~z"[g %%e dzrjyUU]AkcƌhXz89 4kDOt`+DYUq ؂0/>=Iޯk_ ~1%q~?;K,p\c^":7ʕ+j8ye"^AH(L CP=j/ R8eNxBpC*gn7M?+s&U޺kF*Ota[ A867 %book; %overview; %usage; %config; %development; %faq; ]> pekwm documentation &book; pekwm-release-0.1.18/doc/overview/000077500000000000000000000000001374756504400167745ustar00rootroot00000000000000pekwm-release-0.1.18/doc/overview/compiling/000077500000000000000000000000001374756504400207555ustar00rootroot00000000000000pekwm-release-0.1.18/doc/overview/compiling/build.xml000066400000000000000000000021321374756504400225740ustar00rootroot00000000000000 Building and installing After running ./configure with any options you need, run make. This should only take a few minutes. After that, become root (unless you used a prefix in your home directory, such as --prefix=/home/you/pkg) and type make install Adding exec pekwm to ~/.xinitrc if you start X running startx or ~/.xsession if you use a display manager should usually be enough to get pekwm running. That's it! pekwm is installed on your computer now. Next you should read the chapter. pekwm-release-0.1.18/doc/overview/compiling/compiling.xml000066400000000000000000000004601374756504400234600ustar00rootroot00000000000000 Compiling Pekwm This chapter will help you get pekwm compiled. &overview-compiling-unpack; &overview-compiling-configure; &overview-compiling-build; pekwm-release-0.1.18/doc/overview/compiling/configure.xml000066400000000000000000000047161374756504400234700ustar00rootroot00000000000000 Configuration Options The first thing to do is to run the configure script. This configures compile options for pekwm. Here are some of the more used options and what their default values are. Important ./configure options: --enable-shape Enables the use of the Xshape extension for non-rectangular windows. By default, Enabled --enable-xinerama Enables Xinerama multi screen support By default, Enabled --enable-xrandr Enables RandR multi screen support By default, Enabled --enable-xft Enables Xft font support in pekwm (themes). By default, Enabled --enable-image-xpm XPM image support using libXpm. By default, Enabled --enable-image-jpeg JPEG image support using libjpeg. By default, Enabled --enable-image-png PNG image support using libpng. By default, Enabled --enable-debug Enables debugging output By default, Disabled --enable-pedantic Enables pedantic compile flags when using GCC By default, Disabled --prefix=PREFIX It may be useful to use a custom prefix to install the files. By default, /usr/local pekwm-release-0.1.18/doc/overview/compiling/unpack.xml000066400000000000000000000022441374756504400227620ustar00rootroot00000000000000 Unpacking the Archive The first step to compiling pekwm is to unpack the archive. Unpacking it depends on which version you downloaded: tar -zxvf pekwm-¤t-version;.tar.gz tar -jxvf pekwm-¤t-version;.tar.bz2 The '-j' option works normally on most linux systems, and as of the current GNU tar development version, is part of GNU tar. If your system does not support the -j option, you can use two things: bzip2 -dc pekwm-¤t-version;.tar.bz2 | tar -xvf - or bzip2 -d pekwm-¤t-version;.tar.bz2 followed by tar -xvf pekwm-¤t-version;.tar. This also works for the .tar.gz version using gzip -dc or gzip -d. The 'v' options are optional, they show you the filenames as they're being extracted. at this point, you should have a pekwm-¤t-version; directory. Use cd pekwm-¤t-version; to get there. pekwm-release-0.1.18/doc/overview/getting/000077500000000000000000000000001374756504400204355ustar00rootroot00000000000000pekwm-release-0.1.18/doc/overview/getting/getting.xml000066400000000000000000000006161374756504400226230ustar00rootroot00000000000000 Getting Pekwm Now that you've decided to try it out, you need to get it. You're left with two options. The first is to download and compile the source, and the second is finding a pre-compiled package. &overview-getting-src; &overview-getting-pkg; pekwm-release-0.1.18/doc/overview/getting/packages.xml000066400000000000000000000011621374756504400227350ustar00rootroot00000000000000 Getting prebuilt Pekwm packages Links to pre-built pekwm packages are available at the pekwm website, &http-site;. The current version of pekwm is ¤t-version;. If there's no package for your distribution, and you'd like to build one, Let us know! We'll gladly host or link to binary packages. pekwm-release-0.1.18/doc/overview/getting/source.xml000066400000000000000000000011321374756504400224540ustar00rootroot00000000000000 Getting the Pekwm source The source code is available from the pekwm website, &http-site;. Files are named pekwm-¤t-version;.tar.gz and pekwm-¤t-version;.tar.bz2. Although it doesn't matter which you get, keep in mind that the .bz2 is smaller. pekwm-release-0.1.18/doc/overview/intro/000077500000000000000000000000001374756504400201275ustar00rootroot00000000000000pekwm-release-0.1.18/doc/overview/intro/features.xml000066400000000000000000000022741374756504400224740ustar00rootroot00000000000000 Pekwm Features Here's a short list of some of the features included in pekwm: Possibility to group windows in a single frame Configurable keygrabber that supports keychains Configurable mouse actions Configurable root- and window-menus and keybindings for all menus Dynamic menus that regenerate on every view from a script output Multi-screen support both via RandR and Xinerama Configurable window placement Theming support with images, shaping and configurable buttons. Autoproperties (Automatic properties such as a window's sticky state, etc.) pekwm-release-0.1.18/doc/overview/intro/intro.xml000066400000000000000000000010741374756504400220060ustar00rootroot00000000000000 An Introduction to Pekwm The Pekwm Window Manager is written by &program-author;. The code is based on the aewm++ window manager, but it has evolved enough that it no longer resembles aewm++ at all. It also has an expanded feature-set, including window grouping (similar to ion, pwm, or fluxbox), auto properties, xinerama and keygrabber that supports keychains, and much more. &overview-intro-why; &overview-intro-features; pekwm-release-0.1.18/doc/overview/intro/why.xml000066400000000000000000000036521374756504400214660ustar00rootroot00000000000000 Why Pekwm? "Why make another window manager?", some ask. This may confuse some people, but the best answer is "Why not?". There are arguments out there that it's better to have a single standard desktop environment, so that our mothers can find their way around, but in all honestly, if most of us wanted the same environment as our mothers, we probably wouldn't be reading this anyway. The same can also be applied to Your sister, your roommate, your wife, even your cat. "Why should I use pekwm?", others ask. Nobody ever said you should. However, we use it. And you're welcome to as well. You should use the environment most suited to you. For a better answer to this question, Check out the section below. pekwm-release-0.1.18/doc/overview/overview.ent000066400000000000000000000012111374756504400213450ustar00rootroot00000000000000 pekwm-release-0.1.18/doc/overview/overview.xml000066400000000000000000000005271374756504400213700ustar00rootroot00000000000000 An overview of pekwm Pekwm is a fast, functional, and flexible window manager which aims to be usable, even without a mouse. &overview-intro; &overview-getting; &overview-compiling; pekwm-release-0.1.18/doc/pekwm.1000066400000000000000000000016571374756504400163440ustar00rootroot00000000000000.TH pekwm "1" "October 2009" "pekwm 0.1.11" "User Commands" .SH NAME pekwm \- a tabbed window manager .SH SYNOPSIS .TP \fPpekwm\fP [\fIoptions\fP] .SH DESCRIPTION Pekwm is a tabbed window manager which focuses on being highly configurable. Pekwm has a rich feature set including: * Autoproperties, set properties and group windows automatically based on type or title. * Keychains, multi-level keybindings. * XRandR and Xinerama support. .PP For more information about the pekwm project and for full documentation, visit http://www.pekwm.org. .SH OPTIONS .TP \fB\--help\fR Show help information. .TP \fB\--version\fR Show version information. .TP \fB\--info\fR Show information about compiled in features. .TP \fB\--display\fR \fIDISPLAY\fR Connect to DISPLAY instead of DISPLAY set in environment. .TP \fB\--config\fR \fICONFIG\fR Use CONFIG file instead of default ~/.pekwm/config .TP \fB\--replace\fR Replace running window manager. pekwm-release-0.1.18/doc/tools/000077500000000000000000000000001374756504400162665ustar00rootroot00000000000000pekwm-release-0.1.18/doc/tools/empty000066400000000000000000000001101374756504400173370ustar00rootroot00000000000000

    pekwm-release-0.1.18/doc/tools/index.php000066400000000000000000000001531374756504400201050ustar00rootroot00000000000000 Pekwm Documentation pekwm-release-0.1.18/doc/tools/mkdocs.sh000077500000000000000000000240021374756504400201030ustar00rootroot00000000000000#!/usr/bin/env bash # # Copyright © 2009 the pekwm development team # # Applications, tidy is disabled as it fails on many platforms. OPENJADE=$(which openjade 2>/dev/null) PDFJADETEX=$(which pdfjadetex 2>/dev/null) TIDY=$(which tidy-disabled 2>/dev/null) ZIP=$(which zip 2>/dev/null) # Paths DOCSNAME=pekwm-doc CURDIR=`pwd` FINDIR=${CURDIR}/fin HTMLDIR=${FINDIR}/html NOCHDIR=${FINDIR}/nochunks TEXTDIR=${FINDIR}/text MANDIR=${FINDIR}/man PDFDIR=${FINDIR}/pdf RTFDIR=${FINDIR}/rtf ARCDIR=${FINDIR}/arc TOOLDIR=${CURDIR}/tools DIRS="config development overview usage faq" PKGNAME=${DOCSNAME}.tar.bz2 ALLDOCS="html nochunks man text pdf rtf arc" DPFX=docs LOGDIR="${CURDIR}/logs" # CentOS # # yum install docbook-dtds docbook-style-dsssl # # CentOS 5.9 if grep 'release 5' /etc/redhat-release >/dev/null 2>&1; then DBDIR="/usr/share/sgml/docbook/dsssl-stylesheets-1.79/" DBX="${DBDIR}/dtds/decls/xml.dcl" DBV="/usr/share/sgml/docbook/xml-dtd-4.3-1.0-30.1/docbookx.dtd" elif grep 'release 6' /etc/redhat-release >/dev/null 2>&1; then DBDIR="/usr/share/sgml/docbook/dsssl-stylesheets-1.79/" DBX="${DBDIR}/dtds/decls/xml.dcl" DBV="/usr/share/sgml/docbook/xml-dtd-4.3-1.0-51.el6/docbookx.dtd" elif test -f /etc/os-release; then . /etc/os-release if test $ID = "ubuntu"; then # Ubuntu Hardy/Intrepid DBDIR="/usr/share/sgml/docbook/stylesheet/dsssl/modular" DBX="/usr/share/sgml/declaration/xml.dcl" DBV="/usr/share/xml/docbook/schema/dtd/4.3/docbookx.dtd" fi fi if test -z $DBDIR; then # Fedora 11 # DBDIR="/usr/share/sgml/docbook/dsssl-stylesheets-1.79/" # DBX="${DBDIR}/dtds/decls/xml.dcl" # DBV="/usr/share/sgml/docbook/xml-dtd-4.3-1.0-46.fc11/docbookx.dtd" # FreeBSD 9 # DBDIR="/usr/local/share/sgml/docbook/dsssl/modular" # DBV="/usr/local/share/xml/docbook/4.3/docbookx.dtd" # DBX="/usr/local/share/sgml/docbook/dsssl/modular/dtds/decls/xml.dcl" # NetBSD 5 # DBDIR="/usr/pkg/share/sgml/docbook/dsssl/modular" # DBV="/usr/pkg/share/xml/docbook/4.3/docbookx.dtd" # DBX="/usr/pkg/share/sgml/docbook/dsssl/modular/dtds/decls/xml.dcl" exit 1 fi # Shared DBP="${DBDIR}/print/plain.dsl" DBC="${DBDIR}/html/pekwm.dsl" ## Print error message and exit function print_error() { echo "ERROR: $@" exit 1 } ## Print status message function print_status() { echo "STATUS: $1" } ## Clean up files function do_clean() { print_status "cleaning up" rm -rf ${LOGDIR} ${FINDIR} ${CURDIR}/index.xml } ## Make all targets mk_all() { do_prep mk_html mk_pdf mk_rtf mk_arc do_pp } ## Prepare for document generation function do_prep() { print_status "versioning index.xml" ${TOOLDIR}/version-process.pl index.in.xml index.xml "$DBV" print_status "versioning indices" mkdir -p ${FINDIR} || print_error "unable to create directory ${FINDIR}" ${TOOLDIR}/version-process.pl ${TOOLDIR}/empty ${FINDIR}/inc.html ${TOOLDIR}/version-process.pl ${TOOLDIR}/empty ${FINDIR}/inc2.html } ## Post process creating indicies function do_pp() { print_status "post-processing indices" echo '
' >> ${FINDIR}/inc.html echo '' >> ${FINDIR}/inc2.html print_status "making php index" cp ${TOOLDIR}/index.php ${FINDIR}/index.php } ## Make tarballs of documentations function mk_arc() { cd ${FINDIR} cp -r ${HTMLDIR} ${DOCSNAME} mkdir -p ${ARCDIR} print_status "creating tar.bz2" tar -jcf ${ARCDIR}/${DOCSNAME}.tar.bz2 ${DOCSNAME} print_status "creating tar.gz" tar -zcf ${ARCDIR}/${DOCSNAME}.tar.gz ${DOCSNAME} print_status "generating arc indices" ${TOOLDIR}/mkdulink.pl . ${ARCDIR}/${DOCSNAME}.tar.bz2 HTML Files, tar + bzip2 >> ${FINDIR}/inc.html ${TOOLDIR}/mkdulink.pl . ${ARCDIR}/${DOCSNAME}.tar.gz HTML Files, tar + gzip >> ${FINDIR}/inc.html ${TOOLDIR}/mkdulink.pl ${DPFX} ${ARCDIR}/${DOCSNAME}.tar.bz2 HTML Files, tar + bzip2 >> ${FINDIR}/inc2.html ${TOOLDIR}/mkdulink.pl ${DPFX} ${ARCDIR}/${DOCSNAME}.tar.gz HTML Files, tar + gzip >> ${FINDIR}/inc2.html if test -x "${ZIP}"; then print_status "creating zip" zip -9rq ${ARCDIR}/${DOCSNAME}.zip ${DOCSNAME} rm -r ${DOCSNAME} ${TOOLDIR}/mkdulink.pl ${DPFX} ${ARCDIR}/${DOCSNAME}.zip HTML Files, zip format >> ${FINDIR}/inc2.html ${TOOLDIR}/mkdulink.pl . ${ARCDIR}/${DOCSNAME}.zip HTML Files, zip format >> ${FINDIR}/inc.html fi } ## Make RTF version of documentation function mk_rtf() { print_status "generating rtf" mkdir -p ${LOGDIR} || print_error "unable to create directory ${LOGDIR}" mkdir -p ${RTFDIR} || print_error "unable to create directory ${RTFDIR}" ${OPENJADE} -t rtf -b utf-8 -d ${DBP} ${DBX} index.xml >${LOGDIR}/rtf.log 2>${LOGDIR}/rtf.err if test ${?} -gt 0; then print_error "rtf generation failed! see rtf logs!" fi mv index.rtf ${RTFDIR}/${DOCSNAME}.rtf print_status "generating rtf indices" ${TOOLDIR}/mkdulink.pl . ${RTFDIR}/${DOCSNAME}.rtf RTF format >> ${FINDIR}/inc.html ${TOOLDIR}/mkdulink.pl ${DPFX} ${RTFDIR}/${DOCSNAME}.rtf RTF format >> ${FINDIR}/inc2.html } ## Make HTML version of documentation, split up and single file. function mk_html() { mk_html_singlefile mk_html_multifile } ## Make HTML version of documentation, single file. function mk_html_singlefile() { print_status "starting html-singlefile" mkdir -p ${LOGDIR} || print_error "unable to create directory ${LOGDIR}" mkdir -p ${NOCHDIR} || print_error "unable to create directory ${NOCHDIR}" ${OPENJADE} -t xml -b utf-8 -V nochunks -d ${DBC} ${DBX} ${CURDIR}/index.xml \ > ${NOCHDIR}/${DOCSNAME}.html 2>${LOGDIR}/html-singlefile.log if test ${?} -gt 0; then print_error "html generation failed! see html-singlefile logs!" fi cp -R ${CURDIR}/img ${NOCHDIR} if test ${?} -ne 0; then print_error "failed to copy images! see html-singlefile logs!" fi cp -R ${CURDIR}/css ${NOCHDIR} if test ${?} -ne 0; then print_error "failed to copy stylesheets! see html-singlefile logs!" fi if test -x "${TIDY}"; then print_status "tidy - html-singlefile" ${TIDY} -cibqm ${NOCHDIR}/${DOCSNAME}.html \ >${LOGDIR}/htsinglefile-tidy.log 2>${LOGDIR}/htsinglefile-tidy.err if test ${?} -gt 1; then print_error "tidy error on html-singlefile" fi fi print_status "generating singlefile indices" ${TOOLDIR}/mkdulink.pl . ${NOCHDIR}/${DOCSNAME}.html HTML, One Big File >> ${FINDIR}/inc.html ${TOOLDIR}/mkdulink.pl ${DPFX} ${NOCHDIR}/${DOCSNAME}.html HTML, One Big File >> ${FINDIR}/inc2.html } ## Make HTML version of documentation, multiple files. function mk_html_multifile() { print_status "starting html-multifile" mkdir -p ${LOGDIR} || print_error "unable to create directory ${LOGDIR}" mkdir -p ${HTMLDIR} || print_error "unable to create directory ${HTMLDIR}" ( cd ${HTMLDIR} && \ mkdir -p ${DIRS} && \ ${OPENJADE} -t xml -b utf-8 -d ${DBC} ${DBX} ${CURDIR}/index.xml ) \ >${LOGDIR}/html-multifile.log 2>${LOGDIR}/html-multifile.err if test ${?} -gt 0; then print_error "html generation failed! see html-multifile logs!" fi # Correct relative css/img links for html in ${HTMLDIR}/*/*.html; do sed 's/HREF="\(css\|img\)/HREF="..\/\1/g' ${html} > ${html}.tmp mv ${html}.tmp ${html} done cp -R ${CURDIR}/img ${HTMLDIR} if test ${?} -ne 0; then print_error "failed to copy images! see html-multifile logs!" fi cp -R ${CURDIR}/css ${HTMLDIR} if test ${?} -ne 0; then print_error "failed to copy stylesheets!! see html-multifile logs!" fi if test -x "${TIDY}"; then print_status "tidy - html-multifile" for i in $(find ${HTMLDIR} -name '*.html'); do print_status "tidy - html-multifile - $i" echo -e "\n\n****** $i\n" >> ${LOGDIR}/htmultifile-tidy.log echo -e "\n\n****** $i\n" >> ${LOGDIR}/htmultifile-tidy.err ${TIDY} -cibqm $i >> ${LOGDIR}/htmultifile-tidy.log 2> ${LOGDIR}/htmultifile-tidy.err if test ${?} -gt 1; then print_error "tidy error on $i" fi done fi print_status "generating multifile indices" ${TOOLDIR}/mklink.pl . ${HTMLDIR}/index.html HTML, Many files >> ${FINDIR}/inc.html ${TOOLDIR}/mklink.pl ${DPFX} ${HTMLDIR}/index.html HTML, Many files >> ${FINDIR}/inc2.html } ## Generate PDF documentation function mk_pdf() { if ! test -x "${PDFJADETEX}"; then print_status "skipping PDF generation as pdfjadetex does not exist." return fi print_status "starting pdf" mkdir -p ${LOGDIR} || print_error "unable to create directory ${LOGDIR}" mkdir -p ${PDFDIR} || print_error "unable to create directory ${PDFDIR}" # Step 1, generate TeX print_status "starting tex generation" ${OPENJADE} -t tex -b utf-8 -o ${PDFDIR}/index.tex -d ${DBP} ${DBX} ${CURDIR}/index.xml \ >${LOGDIR}/pdf-tex.log 2>${LOGDIR}/pdf-tex.err if test ${?} -gt 0; then print_error "tex generation failed! see pdf logs!" fi # Step 2, generate PDF print_status "starting pdf generation" ( cd ${PDFDIR} && ${PDFJADETEX} ${PDFDIR}/index.tex ) >${LOGDIR}/pdf-pdf.log 2>${LOGDIR}/pdf-pdf.err find ${PDFDIR} -type f | grep -v '\.pdf' | xargs rm print_status "generating pdf indicies" ${TOOLDIR}/mklink.pl . ${PDFDIR}/index.pdf PDF >> ${FINDIR}/inc.html ${TOOLDIR}/mklink.pl ${DPFX} ${PDFDIR}/index.pdf PDF >> ${FINDIR}/inc2.html } ############ PROGRAM EXECUTION BEGINS # Check for required tools if test ! -x "${OPENJADE}"; then print_error "openjade does not exist, can not generate documentation" fi # Check standard files, checked before pekwm as it depends on DBPATH for f in $DBP $DBC $DBV $DBX; do if test ! -e "$f"; then print_error "$f does not exist, make sure dsssl-docbook-modular is installed,\nand that DBPATH ($DBPATH) is set correctly." fi done # Pekwm specific files if test ! -e "${DBC}"; then print_error "${DBC} does not exist, copy from doc/tools/pekwm.dsl" fi case $1 in *clean) do_clean ;; *all) do_clean mk_all ;; *help) echo "$0 (clean|all) [arg]" exit ;; *) exec $0 all ;; esac pekwm-release-0.1.18/doc/tools/mkdulink.pl000077500000000000000000000005631374756504400204500ustar00rootroot00000000000000#!/usr/bin/env perl # # Copyright © 2009 the pekwm development team # use warnings; use strict; my $pfx = shift(@ARGV); my $link = shift(@ARGV); my $desc = join(' ', @ARGV); my $du = qx(ls -lh $link | awk '{print \$5}'); $link =~ s+^.*fin/++g; chomp($du); # print("ls -lh fin/$link | awk {print \$5}\n"); print("
  • $desc ($du)
  • \n"); pekwm-release-0.1.18/doc/tools/mklink.pl000077500000000000000000000003761374756504400201210ustar00rootroot00000000000000#!/usr/bin/env perl # # Copyright © 2009 the pekwm development team # use warnings; use strict; my $pfx = shift(@ARGV); my $link = shift(@ARGV); my $desc = join(' ', @ARGV); $link =~ s+^.*fin/++g; print("
  • $desc
  • \n"); pekwm-release-0.1.18/doc/tools/pekwm.dsl000066400000000000000000000047741374756504400201310ustar00rootroot00000000000000 ]> (define %generate-legalnotice-link% ;; put the legal notice in a separate file #t) (define %stylesheet% "css/pekwm-docs.css") (define ($legalnotice-link-file$ legalnotice) ;; filename of the legalnotice file (string-append "legalnotice"%html-ext%)) (define %html-ext% ;; html extenstion ".html") (define %root-filename% ;; index file of the book "index") (define %use-id-as-filename% ;; filenames same as id attribute in title tags #t) (define %body-attr% ;; html body settings (list (list "BGCOLOR" "#FFFFFF") (list "TEXT" "#000000"))) (define (chunk-skip-first-element-list) ;; forces the Table of Contents on separate page '()) (define (list-element-list) ;; fixes bug in Table of Contents generation '()) (define %shade-verbatim% ;; verbatim sections will be shaded if t(rue) #t) (define %section-autolabel% ;; for enumerated sections (1.1, 1.1.1, 1.2, etc.) #t) ;; custom formatting (element para (make element gi: "P" attributes: '(("STYLE" "text-indent: 1em;")) (process-children))) (element tgroup (make element gi: "TABLE" attributes: '(("CELLSPACING" "1") ("BORDER" "1") ("CELLPADDING" "1") ("WIDTH" "100%") ("BGCOLOR" "#C8CCC8")))) (element varlistentry (make element gi: "DT" attributes: '(("STYLE" "text-decoration: underline")))) (element screen (make element gi: "DIV" attributes: '(("ALIGN" "center")) (make element gi: "TABLE" attributes: '(("CELLSPACING" "1") ("CELLPADDING" "1") ("WIDTH" "100%") ("BGCOLOR" "#C8CCC8")) (make element gi: "TR" (make element gi: "TD" attributes: '(("BGCOLOR" "#FEFFEC")) (make element gi: "PRE" ;; (process-children) attributes: '(("STYLE" "padding: 0.25em") ("STYLE" "text-align: left") ("STYLE" "margin-top: 0.25em") ("STYLE" "margin-bottom: 0.2em")))))))) ;; make role=strong equate to bold for emphasis tag (element emphasis (if (equal? (attribute-string "role") "strong") (make element gi: "STRONG" (process-children)) (make element gi: "EM" (process-children)))) pekwm-release-0.1.18/doc/tools/version000066400000000000000000000000041374756504400176700ustar00rootroot00000000000000GIT pekwm-release-0.1.18/doc/tools/version-process.pl000077500000000000000000000026441374756504400217750ustar00rootroot00000000000000#!/usr/bin/env perl # # Copyright © 2009 the pekwm development team # use strict; use warnings; use POSIX qw(strftime); my $infile = $ARGV[0]; my $outfile = $ARGV[1]; my $dbv = $ARGV[2]; #-- set up date variables my @lt = localtime(); my $d_compact = strftime('%Y%m%d', @lt); my $d_full = strftime('%B %d, %Y', @lt); #-- version variable open(VER, "tools/version"); my $version = ; chomp($version); close(VER); #-- actual out strings my $o_cv = sprintf("\n", $version); my $o_dc = sprintf("\n", $d_compact); my $o_df = sprintf("\n", $d_full); my $h_desc = sprintf("Documentation corresponding to pekwm version %s, last updated %s.\n", $version, $d_compact); open(INPUT, "<$infile") or die $!; my @invar = ; close(INPUT); my @outvar = (); my $inloop=0; foreach (@invar) { if(m/BEGIN HEADER/g) { $inloop=1; push(@outvar, "\"$dbv\" [\n"); } elsif(m/END HEADER/g) { $inloop=0; push(@outvar, $_); } elsif(m/BEGIN VERSIONING/g) { $inloop=1; push(@outvar, $_, $o_cv, $o_dc, $o_df) } elsif(m/BEGIN HTML VERSIONING/g) { $inloop=1; push(@outvar, $_, $h_desc); } elsif(m/END VERSIONING/g) { $inloop=0; push(@outvar, $_); } elsif($inloop == 0){ push(@outvar, $_); } } open(OUT, ">$outfile"); foreach my $str (@outvar) { print(OUT $str); } close(OUT); pekwm-release-0.1.18/doc/usage/000077500000000000000000000000001374756504400162325ustar00rootroot00000000000000pekwm-release-0.1.18/doc/usage/gettingstarted/000077500000000000000000000000001374756504400212625ustar00rootroot00000000000000pekwm-release-0.1.18/doc/usage/gettingstarted/firstrun.xml000066400000000000000000000011431374756504400236570ustar00rootroot00000000000000 First Run The first time you run pekwm, the following files should be copied into your ~/.pekwm directory: config, menu, keys, autoproperties, start, vars. You will learn more about these files in the section. All this happens behind-the-scenes, so by default, you'll be placed into a nice working environment. pekwm-release-0.1.18/doc/usage/gettingstarted/gettingstarted.xml000066400000000000000000000017021374756504400250340ustar00rootroot00000000000000 Getting Started Now that you have pekwm installed, you should take a few moments to test how the basics work. The documentation generally tries to explain the terms it uses, but useful terms to know beforehand include "Mod1" which usually means your Alt key, and "Mod4" which refers to the "windows key" found on recent keyboards. It's also good to know that a "frame" basically means the same as a window, but this window can contain one or more real windows. The same concept is also referred as a "window group". In relation to this, window inside such a frame can be referred as a "grouped window" or a "client window", or simply just as a "client". &usage-gettingstarted-firstrun; &usage-gettingstarted-icons; &usage-gettingstarted-mouse; &usage-gettingstarted-keyboard; pekwm-release-0.1.18/doc/usage/gettingstarted/iconification.xml000066400000000000000000000046341374756504400246310ustar00rootroot00000000000000 About Menus and Iconification When you iconify (This is the traditional name in unix. Windows calls this minimizing.) a window in pekwm, it doesn't really go anywhere like you might expect. You can de-iconify using one of three menus: The Icon menu, the Goto menu, or the GotoClient menu. When you click on an item in one of these menus, it takes you to that window deiconifying when necessary. Icon menu shows you a list of all currently iconified windows. Use Mod4+Shift+I to bring it up. Goto menu shows you a list of windows currently active. This menu will only show the currently active window of possible window groups. Use Mod4+L, or middle click of the mouse on the root window or screen edges to bring this menu up. GotoClient menu shows you a list of every window currently open. Window groups are separated from each other with a menu separator which is defined by the currently used theme, usually a line of some sort. You need to be using window grouping to really see any difference between the GotoClient and Goto menus. Use Mod4+C, or middle click of the mouse on the root window or screen edges while holding down Mod4 to bring up the GotoClient menu. An item in the goto and gotoclient menu and icon menu (and attach menus) has the following syntax: <number> [symbols] Window title The number represents what workspace the window is on. Symbols is a list of symbols that represent window states. They are: Symbols in the pekwm menus * (sticky) . (iconified) ^ (shaded) + (above normal window layer) - (below normal window layer) A (active in group) If you are using window grouping, the whole group will iconify instead of one window. Please ungroup before minimizing if you wish to iconify a single client window from a group frame. pekwm-release-0.1.18/doc/usage/gettingstarted/keyboard.xml000066400000000000000000000052351374756504400236110ustar00rootroot00000000000000 Using the keyboard Pekwm allows excellent keyboard control of your window management. Lets try it out a bit. If you don't have the windows key on your keyboard, please see ~/.pekwm/keys for the keychains you can use to do the same and a lot more. Moving and Resizing windows. To be able to move and resize windows you have to activate the special MoveResize state. This happens by pressing Mod4+Enter. The window should after this be movable by using the arrow keys. To resize, press Mod4 and use the arrows. Using the Shift-key with these actions makes them be careful. To accept the new size and position, press Enter. To fail back to the old position and size press Escape. Minimizing. Press Mod4+I. Mod4+Shift+I pops up the icon menu you can use to bring it back. Shading. This is to hide most of the window, leaving only the titlebar visible. Press Mod4+S to toggle the shaded state. Maximizing. Mod4+M toggles the maximized state. Filling (making a window grow as big as it can in the space it has around it). Press Mod4+G to make windows grow to fit. Fullscreen. Press Mod4+F to toggle the fullscreen state. Moving between frames. Press Mod1+Tab and Mod1+Shift+Tab to move between frames. Or use Mod1+Ctrl+Tab and Mod1+Ctrl+Shift+Tab to move between most recently used frames. You can also use directional focusing. Press Mod4 and one of the arrow keys. The focus should change to the frame that is in the direction you pointed to. Try it out. Moving inside frames. Press Mod4+Tab and Mod4+Shift+Tab to move between the clients in a frame. Closing. Press Mod4+Q to close windows. Grouping. The easiest way to group is to use marking. You select clients you want to group to another frame by toggling them marked with Mod4+Z. You can have as many marked clients as you wish. Then go to the frame you want those now marked clients to be attached and press Mod4+A. That's it. Menus. There are some simple menu bindings. Mod4+R shows your main menu (the Root menu). Mod4+L shows a list of your active windows (the Goto menu). Mod4+C shows a list of all your open windows (the Goto menu). Mod4+W brings up the Window menu. And Mod4+Shift+I the Icon menu. Those were the basics. There's a ton more. See the rest of the documentation for rest of the simple bindings and ~/.pekwm/keys for a list of the keychains. And again, if you hated something, go ahead and edit it. pekwm-release-0.1.18/doc/usage/gettingstarted/mouse.xml000066400000000000000000000075041374756504400231420ustar00rootroot00000000000000 Using the mouse Pekwm has excellent mouse support. Here you'll learn how to do some usual window management actions using the default configuration. Moving windows is rather easy and I think you already got the hang of using the left mouse button on the titlebar and dragging. But did you notice that when you press Mod1 while dragging on the client window (not the titlebar) it works just as well. Resizing is also easy and most are familiar with it. Hang on to a border of the window with the left mouse button and drag. Release the button and you're done. But what you likely didn't know is that if you press Mod1 and then drag on the client window with the right mouse button it also makes windows resize. Try it, it's great. Minimizing (iconifying) with the mouse is possible thru the window menu. Right click on a windows titlebar and select Iconify. Many themes also implement a iconifying button on the titlebar. Also see . Shading is done by double clicking the titlebar with the middle mouse button. Unshade doing it again. Maximizing is quite easy. Hold Mod1 and double click with the left button. Many themes also have a maximize button in them. The default theme has one on the right corner of the titlebar. It's also possible to use the window menu (right click on titlebar). Filling. Sounds odd? Its not. It just means you can make a window grow as large as it can until it hits the borders of the windows surrounding it. Easy as pie, double click on the titlebar with the left mouse button. Excellent feature you are likely to grow to like. Raising windows. Easy. Left click on the windows titlebar or hold Mod1 and left click anywhere on the window. Lowering windows. Hold Mod4 and left click anywhere on the window. Closing. Most themes implement a close button. Default theme has one on the left end of the titlebar. You can also close a client by holding Mod4 and right clicking on its title. Note that the client doesn't have to be the active client of the frame for this to work. Also see the window menu. Grouping. Middle click and drag on a titlebar and release over the frame you want the window into. Holding Mod1 and middle clicking works on the whole client window. This process can also be automated, more on that later. Activating clients. Now that you have multiple clients grouped into one frame, you can switch between them simply by left clicking on the clients title. Doing so also raises the frame. If you don't want the frame to raise, middle click on the clients title. Also try turning the mouse wheel on a frames titlebar when it has more than one client. Menus. As mentioned, press the right mouse button on a windows titlebar and you get the window menu. You can do lots of things from there that are not possible by mouse shortcuts. To bring up the root menu (the one you use to launch programs) click the right button on the background or on the screen edges. To get the Goto menu, click the middle button on the background or screen edges. Most theme buttons work with a left click. Some also have specials when you use other mouse buttons on them. Like the default themes maximize button. Try it. The default themes close button also has a special when you right click on it. With it it is possible to kill the client if it's so stuck you can't close it normally. That ends our short introduction to using the mouse in pekwm. Hope you found the defaults pleasant to use. Remember that if you didn't like something, you can change it. See for how. pekwm-release-0.1.18/doc/usage/grouping/000077500000000000000000000000001374756504400200645ustar00rootroot00000000000000pekwm-release-0.1.18/doc/usage/grouping/advanced.xml000066400000000000000000000037271374756504400223640ustar00rootroot00000000000000 Advanced Grouping Topics Another thing you can do with window grouping is Tagging. This is done by setting the toggleable attribute "tagged" on a frame with the action "Set Tagged". A tag is like a miniature autogroup. It says "All new windows launched should be automatically grouped to this Frame" and all other autogrouping defined in the autoproperties will be ignored while it is set. "UnSet Tagged" removes the tag. Default keybinding to toggle tagging on a frame is Ctrl+Mod1+T then T. Unsetting tagging works even if the window you have set tagged isn't active. It's default keybinding is Ctrl+Mod1+T then C. You can toggle all autogrouping on and off with the toggleable attribute GlobalGrouping. To disable you need to use the action "Unset GlobalGrouping" and to enable autogrouping use "Set GlobalGrouping". The default keybinding that toggless between set and unset is Ctrl+Mod1+T then G. You can set a marked state on clients with "set marked" and then attach those marked clients to another frame by focusing the frame you want the marked clients attached to and then using the AttachMarked action. By default marking can be reached with two simple keybindings. Mod4+Z toggles a clients Marked state and Mod4+A attaches clients with marked state set into the current frame. Marked clients will have "[M]" appended to their titlebars. Pekwm also includes some menus that have to do with grouping. AttachClientInFrame (Ctrl+Mod1+M, A) sends the current client to the selected frame. AttachFrameInFrame (Ctrl+Mod1+M, F) sends the contents of the current frame to the selected frame. AttachClient (Ctrl+Mod1+M, Shift+A) brings the selected client into the current frame. AttachFrame (Ctrl+Mod1+M, Shift+F) brings the contents of the selected frame into the current frame. pekwm-release-0.1.18/doc/usage/grouping/basics.xml000066400000000000000000000030731374756504400220550ustar00rootroot00000000000000 How window grouping works The first thing to know is how to group one window to another. Middle-Click (On a normal X setup, the 2nd mouse button is the middle button) the titlebar of the first window and begin to drag the window. You should now see a rectangle with the window's title in it. Drag that rectangle to above the target window, and release your mouse button. Any time this document mentions a key or mouse button, there's a strong likelihood that you can change which key or mouse button is used for that function. Please see the section. Now that you have windows in a group, you need to learn to choose between windows in that group. The first way is by clicking the middle mouse button on the window's part of the titlebar. That window should now be the currently-active window of the group. You can also use a keybinding for this. The default keybindings are Mod4+Tab and Mod4+Shift+Tab to go forward and back between active window in the frame. To de-group, simply middle click and drag the window off the frame, and release anywhere. If you release over another window group, you'll move the window to the new group. Default keybinding for detaching clients from a group is first Ctrl+Mod1+T then D. You can also set windows up to automatically be grouped to one another. See the section for more details. pekwm-release-0.1.18/doc/usage/grouping/grouping.xml000066400000000000000000000005611374756504400224420ustar00rootroot00000000000000 Window Grouping The main feature of pekwm is window grouping, similar to that of ion, or the tabs in pwm or fluxbox. &usage-grouping-what; &usage-grouping-basics; &usage-grouping-advanced; pekwm-release-0.1.18/doc/usage/grouping/what.xml000066400000000000000000000021131374756504400215460ustar00rootroot00000000000000 What is window grouping? Window grouping is a very simple concept, but it could be hard to understand at first. It's a simple way of making multiple applications share the exact same space. The simplest way to explain this is with an analogy. Imagine you have 20 sheets of paper. To save space, you stack them on top of each other. then, you have little tabs sticking out of one edge so you can quickly flip to any sheet of paper. You have likely stumbled upon a WWW-browser that calls this tabbing. In pekwm, Window grouping is visually done by dividing up the physical space of the titlebar. We don't call them tabs for historical reasons, but refer to them as "clients". Windows that can contain any number of clients are more than often referred as "frames". Also note that a frame can contain any type of clients. If you want to group one of your WWW-browser windows with your text editor for future reference, you're free to do so. pekwm-release-0.1.18/doc/usage/harbour/000077500000000000000000000000001374756504400176745ustar00rootroot00000000000000pekwm-release-0.1.18/doc/usage/harbour/basics.xml000066400000000000000000000004131374756504400216600ustar00rootroot00000000000000 How window grouping works The first thing to know is how to group one window to another. pekwm-release-0.1.18/doc/usage/usage.ent000066400000000000000000000014201374756504400200430ustar00rootroot00000000000000 pekwm-release-0.1.18/doc/usage/usage.xml000066400000000000000000000005321374756504400200600ustar00rootroot00000000000000 Basic Usage Pekwm is a fast, functional, and flexible window manager. Here's some notes on how to operate it on it's default settings. &usage-gettingstarted; &usage-grouping; &usage-workspaces; pekwm-release-0.1.18/doc/usage/workspaces/000077500000000000000000000000001374756504400204135ustar00rootroot00000000000000pekwm-release-0.1.18/doc/usage/workspaces/navigation.xml000066400000000000000000000023401374756504400232730ustar00rootroot00000000000000 Workspace Navigation You can send windows to another workspace by right-clicking the titlebar, going to 'send to' and picking the desktop you'd like. Another option is using the SendToWorkspace keybindings (by default, Mod4 and one of F1, F2, F3, or F4). Using the mouse to drag a window over the right or left screen edge makes it move to the next or previous workspace. Also try placing the mouse pointer on a client window and rotating the mouse wheel while holding Mod1 down to send a window to the next or previous workspace and follow it there yourself. Switch desktops by using the GoToWorkspace keybindings (by default Mod4 and one of 1,2,3, or 4), or the "GotoWorkspace Next" and "GotoWorkspace Prev" actions (by default Ctrl+Mod1+Right and Ctrl+Mod1+Left). Holding Mod1 key while moving the mouse pointer over the right or left screen edge will make you move to the next or previous workspace. Also pressing the left mouse button on the right or left screen edge will make you move to the next or previous workspace. Using the mouse wheel on the background or the screen edges also changes your workspace. pekwm-release-0.1.18/doc/usage/workspaces/workspaces.xml000066400000000000000000000012341374756504400233160ustar00rootroot00000000000000 Workspaces Workspaces in pekwm are a very common feature, found in almost every UNIX window manager in existence. They're also called desktops in some window managers. In Pekwm-Speak, "workspace", "desktop", and "desk" are interchangeable. Use whichever one you feel like using. By default, pekwm enables four workspaces. You can change this by editing your ~/.pekwm/config file. See section for more details. &usage-workspaces-nav; pekwm-release-0.1.18/m4/000077500000000000000000000000001374756504400147015ustar00rootroot00000000000000pekwm-release-0.1.18/m4/ax_cxx_compile_stdcxx_11.m4000066400000000000000000000107641374756504400220530ustar00rootroot00000000000000# ============================================================================ # http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html # ============================================================================ # # SYNOPSIS # # AX_CXX_COMPILE_STDCXX_11([ext|noext],[mandatory|optional]) # # DESCRIPTION # # Check for baseline language coverage in the compiler for the C++11 # standard; if necessary, add switches to CXXFLAGS to enable support. # # The first argument, if specified, indicates whether you insist on an # extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. # -std=c++11). If neither is specified, you get whatever works, with # preference for an extended mode. # # The second argument, if specified 'mandatory' or if left unspecified, # indicates that baseline C++11 support is required and that the macro # should error out if no mode with that support is found. If specified # 'optional', then configuration proceeds regardless, after defining # HAVE_CXX11 if and only if a supporting mode is found. # # LICENSE # # Copyright (c) 2008 Benjamin Kosnik # Copyright (c) 2012 Zack Weinberg # Copyright (c) 2013 Roy Stogner # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 3 m4_define([_AX_CXX_COMPILE_STDCXX_11_testbody], [ template struct check { static_assert(sizeof(int) <= sizeof(T), "not big enough"); }; typedef check> right_angle_brackets; int a; decltype(a) b; typedef check check_type; check_type c; check_type&& cr = static_cast(c); auto d = a; ]) AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [dnl m4_if([$1], [], [], [$1], [ext], [], [$1], [noext], [], [m4_fatal([invalid argument `$1' to AX_CXX_COMPILE_STDCXX_11])])dnl m4_if([$2], [], [ax_cxx_compile_cxx11_required=true], [$2], [mandatory], [ax_cxx_compile_cxx11_required=true], [$2], [optional], [ax_cxx_compile_cxx11_required=false], [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX_11])])dnl AC_LANG_PUSH([C++])dnl ac_success=no AC_CACHE_CHECK(whether $CXX supports C++11 features by default, ax_cv_cxx_compile_cxx11, [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], [ax_cv_cxx_compile_cxx11=yes], [ax_cv_cxx_compile_cxx11=no])]) if test x$ax_cv_cxx_compile_cxx11 = xyes; then ac_success=yes fi m4_if([$1], [noext], [], [dnl if test x$ac_success = xno; then for switch in -std=gnu++11 -std=gnu++0x; do cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch]) AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch, $cachevar, [ac_save_CXXFLAGS="$CXXFLAGS" CXXFLAGS="$CXXFLAGS $switch" AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], [eval $cachevar=yes], [eval $cachevar=no]) CXXFLAGS="$ac_save_CXXFLAGS"]) if eval test x\$$cachevar = xyes; then CXXFLAGS="$CXXFLAGS $switch" ac_success=yes break fi done fi]) m4_if([$1], [ext], [], [dnl if test x$ac_success = xno; then for switch in -std=c++11 -std=c++0x; do cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch]) AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch, $cachevar, [ac_save_CXXFLAGS="$CXXFLAGS" CXXFLAGS="$CXXFLAGS $switch" AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], [eval $cachevar=yes], [eval $cachevar=no]) CXXFLAGS="$ac_save_CXXFLAGS"]) if eval test x\$$cachevar = xyes; then CXXFLAGS="$CXXFLAGS $switch" ac_success=yes break fi done fi]) AC_LANG_POP([C++]) if test x$ax_cxx_compile_cxx11_required = xtrue; then if test x$ac_success = xno; then AC_MSG_ERROR([*** A compiler with support for C++11 language features is required.]) fi else if test x$ac_success = xno; then HAVE_CXX11=0 AC_MSG_NOTICE([No compiler with C++11 support was found]) else HAVE_CXX11=1 AC_DEFINE(HAVE_CXX11,1, [define if the compiler supports basic C++11 syntax]) fi AC_SUBST(HAVE_CXX11) fi ]) pekwm-release-0.1.18/m4/iconv.m4000066400000000000000000000143031374756504400162620ustar00rootroot00000000000000# iconv.m4 serial AM6 (gettext-0.17) dnl Copyright (C) 2000-2002, 2007 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. AC_DEFUN([AM_ICONV_LINKFLAGS_BODY], [ dnl Prerequisites of AC_LIB_LINKFLAGS_BODY. AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) AC_REQUIRE([AC_LIB_RPATH]) dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV dnl accordingly. AC_LIB_LINKFLAGS_BODY([iconv]) ]) AC_DEFUN([AM_ICONV_LINK], [ dnl Some systems have iconv in libc, some have it in libiconv (OSF/1 and dnl those with the standalone portable GNU libiconv installed). AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV dnl accordingly. AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY]) dnl Add $INCICONV to CPPFLAGS before performing the following checks, dnl because if the user has installed libiconv and not disabled its use dnl via --without-libiconv-prefix, he wants to use it. The first dnl AC_TRY_LINK will then fail, the second AC_TRY_LINK will succeed. am_save_CPPFLAGS="$CPPFLAGS" AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCICONV]) AC_CACHE_CHECK([for iconv], am_cv_func_iconv, [ am_cv_func_iconv="no, consider installing GNU libiconv" am_cv_lib_iconv=no AC_TRY_LINK([#include #include ], [iconv_t cd = iconv_open("",""); iconv(cd,NULL,NULL,NULL,NULL); iconv_close(cd);], am_cv_func_iconv=yes) if test "$am_cv_func_iconv" != yes; then am_save_LIBS="$LIBS" LIBS="$LIBS $LIBICONV" AC_TRY_LINK([#include #include ], [iconv_t cd = iconv_open("",""); iconv(cd,NULL,NULL,NULL,NULL); iconv_close(cd);], am_cv_lib_iconv=yes am_cv_func_iconv=yes) LIBS="$am_save_LIBS" fi ]) if test "$am_cv_func_iconv" = yes; then AC_CACHE_CHECK([for working iconv], am_cv_func_iconv_works, [ dnl This tests against bugs in AIX 5.1 and HP-UX 11.11. am_save_LIBS="$LIBS" if test $am_cv_lib_iconv = yes; then LIBS="$LIBS $LIBICONV" fi AC_TRY_RUN([ #include #include int main () { /* Test against AIX 5.1 bug: Failures are not distinguishable from successful returns. */ { iconv_t cd_utf8_to_88591 = iconv_open ("ISO8859-1", "UTF-8"); if (cd_utf8_to_88591 != (iconv_t)(-1)) { static const char input[] = "\342\202\254"; /* EURO SIGN */ char buf[10]; const char *inptr = input; size_t inbytesleft = strlen (input); char *outptr = buf; size_t outbytesleft = sizeof (buf); size_t res = iconv (cd_utf8_to_88591, #ifdef ICONV_CONST &inptr, &inbytesleft, #else (char **) &inptr, &inbytesleft, #endif &outptr, &outbytesleft); if (res == 0) return 1; } } #if 0 /* This bug could be worked around by the caller. */ /* Test against HP-UX 11.11 bug: Positive return value instead of 0. */ { iconv_t cd_88591_to_utf8 = iconv_open ("utf8", "iso88591"); if (cd_88591_to_utf8 != (iconv_t)(-1)) { static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337"; char buf[50]; const char *inptr = input; size_t inbytesleft = strlen (input); char *outptr = buf; size_t outbytesleft = sizeof (buf); size_t res = iconv (cd_88591_to_utf8, #ifdef ICONV_CONST &inptr, &inbytesleft, #else (char **) &inptr, &inbytesleft, #endif &outptr, &outbytesleft); if ((int)res > 0) return 1; } } #endif /* Test against HP-UX 11.11 bug: No converter from EUC-JP to UTF-8 is provided. */ if (/* Try standardized names. */ iconv_open ("UTF-8", "EUC-JP") == (iconv_t)(-1) /* Try IRIX, OSF/1 names. */ && iconv_open ("UTF-8", "eucJP") == (iconv_t)(-1) /* Try AIX names. */ && iconv_open ("UTF-8", "IBM-eucJP") == (iconv_t)(-1) /* Try HP-UX names. */ && iconv_open ("utf8", "eucJP") == (iconv_t)(-1)) return 1; return 0; }], [am_cv_func_iconv_works=yes], [am_cv_func_iconv_works=no], [case "$host_os" in aix* | hpux*) am_cv_func_iconv_works="guessing no" ;; *) am_cv_func_iconv_works="guessing yes" ;; esac]) LIBS="$am_save_LIBS" ]) case "$am_cv_func_iconv_works" in *no) am_func_iconv=no am_cv_lib_iconv=no ;; *) am_func_iconv=yes ;; esac else am_func_iconv=no am_cv_lib_iconv=no fi if test "$am_func_iconv" = yes; then AC_DEFINE(HAVE_ICONV, 1, [Define if you have the iconv() function and it works.]) fi if test "$am_cv_lib_iconv" = yes; then AC_MSG_CHECKING([how to link with libiconv]) AC_MSG_RESULT([$LIBICONV]) else dnl If $LIBICONV didn't lead to a usable library, we don't need $INCICONV dnl either. CPPFLAGS="$am_save_CPPFLAGS" LIBICONV= LTLIBICONV= fi AC_SUBST(LIBICONV) AC_SUBST(LTLIBICONV) ]) AC_DEFUN([AM_ICONV_CONST], [ AC_MSG_CHECKING([for iconv declaration]) AC_CACHE_VAL(am_cv_proto_iconv, [ AC_TRY_COMPILE([ #include #include extern #ifdef __cplusplus "C" #endif #if defined(__STDC__) || defined(__cplusplus) size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); #else size_t iconv(); #endif ], [], am_cv_proto_iconv_arg1="", am_cv_proto_iconv_arg1="const") am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"]) am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'` AC_MSG_RESULT([$]{ac_t:- }[$]am_cv_proto_iconv) if test "x$am_cv_proto_iconv_arg1" = "xconst"; then AC_DEFINE_UNQUOTED(ICONV_CONST, 1, [Define as const if the declaration of iconv() needs const.]) fi ]) AC_DEFUN([AM_ICONV], [ AM_ICONV_CONST AM_ICONV_LINK ]) pekwm-release-0.1.18/pekwm.spec000066400000000000000000000000251374756504400163550ustar00rootroot00000000000000updated by dist-hook pekwm-release-0.1.18/pekwm.spec.in000066400000000000000000000072301374756504400167670ustar00rootroot00000000000000Name: pekwm Version: Release: 4%{?dist} Summary: A small and flexible window manager Group: User Interface/Desktops License: GPLv2+ URL: http://www.pekwm.org/ Source0: http://www.pekwm.org/projects/pekwm/files/%{name}-%{version}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildRequires: libX11-devel libpng-devel libXrandr-devel BuildRequires: libXft-devel libXext-devel libXinerama-devel BuildRequires: libXpm-devel libjpeg-devel libICE-devel libSM-devel %description Pekwm is a window manager that once up on a time was based on the aewm++ window manager, but it has evolved enough that it no longer resembles aewm++ at all. It has a much expanded feature-set, including window grouping (similar to ion, pwm, or fluxbox), autoproperties, xinerama, keygrabber that supports keychains, and much more. * Lightweight and Unobtrusive, a window manager shouldn't be noticed. * Very configurable, we all work and think in different ways. * Automatic properties, for all the lazy people, make things appear as they should when starting applications. * Chainable Keygrabber, usability for everyone. %prep %setup -q %build %configure make %{?_smp_mflags} %install rm -rf %{buildroot} make install DESTDIR=%{buildroot} INSTALL="install -p" # Create desktop file mkdir -p %{buildroot}%{_datadir}/xsessions/ cat << EOF > %{buildroot}%{_datadir}/xsessions/%{name}.desktop [Desktop Entry] Name=PekWM Comment=Very small and fast window manger Exec=pekwm TryExec=pekwm Type=XSession EOF # Delete makefiles from contrib folder find contrib/Makefile* -type f | xargs rm -rf || true find contrib/lobo/Makefile* -type f | xargs rm -rf || true # Rearrange the contents of contrib folder mv contrib/lobo/* contrib/ rm -rf contrib/lobo # Fix permissions to include scripts in %%doc find contrib/pekwm_autoprop.pl -type f | xargs chmod 0644 || true find contrib/pekwm_menu_config.pl -type f | xargs chmod 0644 || true %clean rm -rf %{buildroot} %files %defattr(-,root,root,-) %doc AUTHORS ChangeLog ChangeLog.aewm++ ChangeLog.until-0.1.6 LICENSE NEWS README contrib/ %{_bindir}/%{name} %config(noreplace) %{_sysconfdir}/%{name}/autoproperties %config(noreplace) %{_sysconfdir}/%{name}/config %config(noreplace) %{_sysconfdir}/%{name}/keys %config(noreplace) %{_sysconfdir}/%{name}/menu %config(noreplace) %{_sysconfdir}/%{name}/mouse %config(noreplace) %{_sysconfdir}/%{name}/vars %config(noreplace) %attr(755,root,root) %{_sysconfdir}/%{name}/start %{_datadir}/%{name}/ %{_mandir}/man1/%{name}.* %{_datadir}/xsessions/%{name}.desktop %changelog * Tue May 11 2010 German A. Racca 0.1.12-4 - Fixed BuildRequires to compile from scratch * Sun May 09 2010 German A. Racca 0.1.12-3 - Deleted makefiles form contrib folder - Rearranged contents in contrib folder * Mon Apr 26 2010 German A. Racca 0.1.12-2 - Added %%{dist} tag - Fixed patch - Added contrib stuff to docs * Tue Apr 20 2010 German A. Racca 0.1.12-1 - New version 0.1.12 - Fixed timestamp for tarball source - Added BuildRoot tag - Fixed BuildRequires - Added menu patch - Added INSTALL="install -p" to preserve timestamps - Corrected type in xsession file - Added ChangeLog.aewm++ and ChangeLog.until-0.1.6 to doc files - Own directory %%{_datadir}/%%{name} - Marqued 'start' as config file * Sat Feb 20 2010 German A. Racca 0.1.11-3 - Changed Summary - Changed BuildRequires - Modified desktop file - Added exec attr to 'start' file * Fri Jan 15 2010 German A. Racca 0.1.11-2 - Added Source0 to spec file * Thu Dec 17 2009 German A. Racca 0.1.11-1 - Initial release of RPM package pekwm-release-0.1.18/src/000077500000000000000000000000001374756504400151505ustar00rootroot00000000000000pekwm-release-0.1.18/src/Action.hh000066400000000000000000000136431374756504400167150ustar00rootroot00000000000000// // Action.hh for pekwm // Copyright (C) 2003-2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifndef _ACTION_HH_ #define _ACTION_HH_ #include "config.h" #include "Types.hh" #include #include #include class PWinObj; //! @brief Masks used to set Action context validity. enum ActionOk { KEYGRABBER_OK = (1<<1), //!< Keygrabber ok. FRAME_OK = (1<<2), //!< Frame title ok. CLIENT_OK = (1<<3), //!< Client click ok. ROOTCLICK_OK = (1<<4), //!< Root window click ok. BUTTONCLICK_OK = (1<<5), //!< Button{Press,Release} ok. WINDOWMENU_OK = (1<<6), //!< Ok from WindowMenu. ROOTMENU_OK = (1<<7), //!< Ok from RootMenu. FRAME_BORDER_OK = (1<<8), //!< Frame border ok. SCREEN_EDGE_OK = (1<<9) //!< ScreenEdge ok. }; /** * Mask used in auto properties granting/disallowing actions. */ enum ActionAccessMask { ACTION_ACCESS_NO = 0, ACTION_ACCESS_MOVE = 1<<1, ACTION_ACCESS_RESIZE = 1<<2, ACTION_ACCESS_ICONIFY = 1<<3, ACTION_ACCESS_SHADE = 1<<4, ACTION_ACCESS_STICK = 1<<5, ACTION_ACCESS_MAXIMIZE_HORZ = 1<<6, ACTION_ACCESS_MAXIMIZE_VERT = 1<<7, ACTION_ACCESS_FULLSCREEN = 1<<8, ACTION_ACCESS_CHANGE_DESKTOP = 1<<9, ACTION_ACCESS_CLOSE = 1<<10 }; enum ActionType { ACTION_UNSET = 0, ACTION_SET = 1, // to conform with bool values ACTION_TOGGLE, ACTION_FOCUS, ACTION_UNFOCUS, ACTION_GROW_DIRECTION, ACTION_MAXFILL, ACTION_RESIZE, ACTION_MOVE_RESIZE, ACTION_RAISE, ACTION_LOWER, ACTION_ACTIVATE_OR_RAISE, ACTION_CLOSE, ACTION_CLOSE_FRAME, ACTION_KILL, ACTION_SET_GEOMETRY, ACTION_MOVE_TO_HEAD, ACTION_MOVE_TO_EDGE, ACTION_NEXT_FRAME, ACTION_NEXT_FRAME_MRU, ACTION_PREV_FRAME, ACTION_PREV_FRAME_MRU, ACTION_FOCUS_DIRECTIONAL, ACTION_GOTO_CLIENT, ACTION_ACTIVATE_CLIENT_REL, ACTION_MOVE_CLIENT_REL, ACTION_ACTIVATE_CLIENT, ACTION_ACTIVATE_CLIENT_NUM, ACTION_SEND_TO_WORKSPACE, ACTION_GOTO_WORKSPACE, ACTION_WARP_TO_WORKSPACE, ACTION_SHOW_MENU, ACTION_HIDE_ALL_MENUS, ACTION_DETACH, ACTION_ATTACH_MARKED, ACTION_ATTACH_CLIENT_IN_NEXT_FRAME, ACTION_ATTACH_CLIENT_IN_PREV_FRAME, ACTION_ATTACH_FRAME_IN_NEXT_FRAME, ACTION_ATTACH_FRAME_IN_PREV_FRAME, ACTION_GOTO_CLIENT_ID, ACTION_FIND_CLIENT, ACTION_EXEC, ACTION_RELOAD, ACTION_RESTART, ACTION_RESTART_OTHER, ACTION_EXIT, ACTION_MENU_NEXT, ACTION_MENU_PREV, ACTION_MENU_GOTO, ACTION_MENU_SELECT, ACTION_MENU_ENTER_SUBMENU, ACTION_MENU_LEAVE_SUBMENU, ACTION_MENU_SUB, ACTION_MENU_DYN, ACTION_MOVE, ACTION_GROUPING_DRAG, ACTION_SHOW_CMD_DIALOG, ACTION_SHOW_SEARCH_DIALOG, ACTION_SEND_KEY, ACTION_SET_OPACITY, ACTION_LAYOUT_ONCE, ACTION_SET_LAYOUTER, ACTION_SET_LAYOUTER_OPTION, ACTION_DEBUG, ACTION_NO }; enum ActionStateType { ACTION_STATE_MAXIMIZED, ACTION_STATE_FULLSCREEN, ACTION_STATE_SHADED, ACTION_STATE_STICKY, ACTION_STATE_ALWAYS_ONTOP, ACTION_STATE_ALWAYS_BELOW, ACTION_STATE_DECOR_BORDER, ACTION_STATE_DECOR_TITLEBAR, ACTION_STATE_DECOR, ACTION_STATE_TITLE, ACTION_STATE_ICONIFIED, ACTION_STATE_TAGGED, ACTION_STATE_MARKED, ACTION_STATE_SKIP, ACTION_STATE_CFG_DENY, ACTION_STATE_OPAQUE, ACTION_STATE_HARBOUR_HIDDEN, ACTION_STATE_GLOBAL_GROUPING, ACTION_STATE_NO }; enum StateAction { STATE_SET = ACTION_SET, STATE_UNSET = ACTION_UNSET, STATE_TOGGLE = ACTION_TOGGLE }; enum MoveResizeActionType { MOVE_HORIZONTAL = 1, MOVE_VERTICAL, RESIZE_HORIZONTAL, RESIZE_VERTICAL, MOVE_SNAP, MOVE_CANCEL, MOVE_END, NO_MOVERESIZE_ACTION = 0 }; enum InputDialogAction { INPUT_INSERT, INPUT_REMOVE, INPUT_CLEAR, INPUT_CLEARFROMCURSOR, INPUT_EXEC, INPUT_CLOSE, INPUT_COMPLETE, INPUT_COMPLETE_ABORT, INPUT_CURS_NEXT, INPUT_CURS_PREV, INPUT_CURS_END, INPUT_CURS_BEGIN, INPUT_HIST_NEXT, INPUT_HIST_PREV, INPUT_NO_ACTION }; // Action Utils namespace ActionUtil { //! @brief Determines if state needs toggling. //! @return true if state needs toggling, else false. inline bool needToggle(StateAction sa, bool state) { if ((state && (sa == STATE_SET)) || (! state && (sa == STATE_UNSET))) { return false; } return true; } } // Structs and Classes class Action { public: Action(void) { clear(); } Action(uint action) { clear(); _action = action; } ~Action(void) { } inline uint getAction(void) const { return _action; } inline int getParamI(uint n) const { return _param_i[(n < 3) ? n : 0]; } inline const std::string &getParamS(void) const { return _param_s; } inline void setAction(uint action) { _action = action; } inline void setParamI(uint n, int param) { _param_i[(n < 3) ? n : 0] = param; } inline void setParamS(const std::string param) { _param_s = param; } inline void clear() { _action = ACTION_UNSET; _param_s.clear(); memset(_param_i, '\0', sizeof(_param_i)); } private: uint _action; int _param_i[3]; std::string _param_s; }; class ActionEvent { public: ActionEvent(void) { } ~ActionEvent(void) { } inline bool isOnlyAction(uint action) const { return ((action_list.size() == 1) && (action_list.front().getAction() == action)); } uint mod, sym; // event matching uint type, threshold; // more matching, press, release etc std::vector action_list; }; class ActionPerformed { public: ActionPerformed(PWinObj *w, const ActionEvent &a) : wo(w), ae(a), type(0) { } ~ActionPerformed(void) { } PWinObj *wo; const ActionEvent &ae; int type; union _event { XButtonEvent *button; XKeyEvent *key; XMotionEvent *motion; XCrossingEvent *crossing; XExposeEvent *expose; } event; }; #endif // _ACTION_HH_ pekwm-release-0.1.18/src/ActionHandler.cc000066400000000000000000001023641374756504400202000ustar00rootroot00000000000000// // ActionHandler.cc for pekwm // Copyright © 2002-2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "config.h" #include "ActionHandler.hh" #include "Debug.hh" #include "PWinObj.hh" #include "PDecor.hh" #include "PMenu.hh" #include "x11.hh" #include "Frame.hh" #include "Client.hh" #include "Config.hh" #include "CmdDialog.hh" #include "SearchDialog.hh" #include "Workspaces.hh" #include "WindowManager.hh" #include "Util.hh" #include "RegexString.hh" #include "WorkspaceIndicator.hh" #include "Harbour.hh" #include "MenuHandler.hh" #include "PDecor.hh" #include "PMenu.hh" #include "WORefMenu.hh" #include "ActionMenu.hh" #include "FrameListMenu.hh" #include using std::string; using std::find; using std::map; ActionHandler *ActionHandler::_instance = 0; //! @brief ActionHandler constructor ActionHandler::ActionHandler(void) { _instance = this; // Initialize state_to_keycode map for (uint i = 0; i < X11::MODIFIER_TO_MASK_NUM; ++i) { uint modifier = X11::MODIFIER_TO_MASK[i]; _state_to_keycode[modifier] = X11::getKeycodeFromMask(modifier); } } //! @brief ActionHandler destructor ActionHandler::~ActionHandler(void) { _instance = 0; } //! @brief Executes an ActionPerformed event. void ActionHandler::handleAction(const ActionPerformed &ap) { PWinObj *wo = ap.wo; Client *client = 0; Frame *frame = 0; PMenu *menu = 0; PDecor *decor = 0; bool matched = false; // go through the list of actions and execute them vector::const_iterator it = ap.ae.action_list.begin(); for (; it != ap.ae.action_list.end(); ++it, matched = false) { // Determine what type if any of the window object that is focused // and check if it is still alive. lookupWindowObjects(&wo, &client, &frame, &menu, &decor); // actions valid for all PWinObjs if (! matched && wo) { matched = true; switch (it->getAction()) { case ACTION_FOCUS: wo->giveInputFocus(); break; case ACTION_UNFOCUS: PWinObj::getRootPWinObj()->giveInputFocus(); break; case ACTION_FOCUS_DIRECTIONAL: actionFocusDirectional(wo, DirectionType(it->getParamI(0)), it->getParamI(1)); break; case ACTION_SEND_KEY: actionSendKey(wo, it->getParamS()); break; default: matched = false; break; }; } // actions valid for Clients and Frames if (! matched && frame) { matched = true; switch (it->getAction()) { case ACTION_GROUPING_DRAG: if (ap.type == MotionNotify) { frame->doGroupingDrag(ap.event.motion, client, it->getParamI(0)); } break; case ACTION_ACTIVATE_CLIENT: if ((ap.type == ButtonPress) || (ap.type == ButtonRelease)) frame->activateChild(frame->getChildFromPos(ap.event.button->x)); break; case ACTION_GOTO_CLIENT: gotoClient(client); break; case ACTION_MAXFILL: if (! Workspaces::isTiling(frame->getWorkspace()) || ! frame->allowTiling()) { frame->setStateMaximized(STATE_SET, it->getParamI(0), it->getParamI(1), true); } break; case ACTION_GROW_DIRECTION: if (! Workspaces::isTiling(frame->getWorkspace()) || ! frame->allowTiling()) { frame->growDirection(it->getParamI(0)); } break; case ACTION_RESIZE: if (! Workspaces::isTiling(frame->getWorkspace()) || ! frame->allowTiling()) { if (ap.type == MotionNotify && ! it->getParamI(0)) frame->doResize(ap.event.motion); else frame->doResize(BorderPosition(it->getParamI(0)-1)); } break; case ACTION_MOVE_RESIZE: if (! Workspaces::isTiling(frame->getWorkspace()) || ! frame->allowTiling()) { frame->doKeyboardMoveResize(); } break; case ACTION_CLOSE: client->close(); break; case ACTION_CLOSE_FRAME: frame->close(); break; case ACTION_KILL: client->kill(); break; case ACTION_SET_GEOMETRY: frame->setGeometry(it->getParamS(), it->getParamI(0)); break; case ACTION_RAISE: if (it->getParamI(0)) { WindowManager::instance()->familyRaiseLower(client, true); } else { frame->raise(); } break; case ACTION_LOWER: if (it->getParamI(0)) { WindowManager::instance()->familyRaiseLower(client, false); } else { frame->lower(); } break; case ACTION_ACTIVATE_OR_RAISE: if ((ap.type == ButtonPress) || (ap.type == ButtonRelease)) { if (ap.event.button->window == frame->getTitleWindow()) { frame->activateChild(frame->getChildFromPos(ap.event.button->x)); } } if (frame->isFocused()) { frame->raise(); } else { wo->giveInputFocus(); } break; case ACTION_MOVE_TO_HEAD: frame->moveToHead(it->getParamI(0)); break; case ACTION_MOVE_TO_EDGE: frame->moveToEdge(OrientationType(it->getParamI(0))); break; case ACTION_ACTIVATE_CLIENT_REL: frame->activateChildRel(it->getParamI(0)); break; case ACTION_MOVE_CLIENT_REL: frame->moveChildRel(it->getParamI(0)); break; case ACTION_ACTIVATE_CLIENT_NUM: frame->activateChildNum(it->getParamI(0)); break; case ACTION_SEND_TO_WORKSPACE: actionSendToWorkspace(decor, it->getParamI(0)); break; case ACTION_DETACH: frame->detachClient(client); break; case ACTION_ATTACH_MARKED: WindowManager::instance()->attachMarked(frame); break; case ACTION_ATTACH_CLIENT_IN_NEXT_FRAME: WindowManager::instance()->attachInNextPrevFrame(client, false, true); break; case ACTION_ATTACH_CLIENT_IN_PREV_FRAME: WindowManager::instance()->attachInNextPrevFrame(client, false, false); break; case ACTION_ATTACH_FRAME_IN_NEXT_FRAME: WindowManager::instance()->attachInNextPrevFrame(client, true, true); break; case ACTION_ATTACH_FRAME_IN_PREV_FRAME: WindowManager::instance()->attachInNextPrevFrame(client, true, false); break; case ACTION_SET_OPACITY: actionSetOpacity(client, frame, it->getParamI(0), it->getParamI(1)); break; case ACTION_SET_LAYOUTER_OPTION: Workspaces::setLayouterOption(it->getParamS(), frame); break; default: matched = false; break; } } // Actions valid for Menus if (! matched && menu) { matched = true; switch (it->getAction()) { // menu navigation case ACTION_MENU_NEXT: menu->selectNextItem(); break; case ACTION_MENU_PREV: menu->selectPrevItem(); break; case ACTION_MENU_GOTO: menu->selectItemNum(it->getParamI(0)); break; case ACTION_MENU_SELECT: menu->exec(menu->getItemCurr()); // special case: execItem can cause an reload to be issued, if that's // the case it causes the list (ae) to change and therefore // it can't be used anymore return; case ACTION_MENU_ENTER_SUBMENU: if (menu->getItemCurr() && menu->getItemCurr()->getWORef() && (menu->getItemCurr()->getWORef()->getType() == PWinObj::WO_MENU)) { menu->mapSubmenu(static_cast(menu->getItemCurr()->getWORef()), true); } break; case ACTION_MENU_LEAVE_SUBMENU: menu->gotoParentMenu(); break; case ACTION_CLOSE: menu->unmapAll(); WindowManager::instance()->findWOAndFocus(0); break; default: matched = false; break; } } // actions valid for pdecor if (! matched && decor) { int x_root, y_root; matched = true; switch (it->getAction()) { case ACTION_MOVE: // Get root position, previously event positions was // used however this seems to be error prone on // Xinerama setups X11::getMousePosition(x_root, y_root); decor->doMove(x_root, y_root); break; case ACTION_CLOSE: decor->unmapWindow(); if (decor->getType() == PWinObj::WO_CMD_DIALOG || decor->getType() == PWinObj::WO_SEARCH_DIALOG) { WindowManager::instance()->findWOAndFocus(0); } break; case ACTION_WARP_TO_WORKSPACE: actionWarpToWorkspace(decor, it->getParamI(0)); break; default: matched = false; break; } } // Actions valid from everywhere if (! matched) { matched = true; switch (it->getAction()) { case ACTION_SET: case ACTION_UNSET: case ACTION_TOGGLE: handleStateAction(*it, wo, client, frame); break; case ACTION_NEXT_FRAME: actionFocusToggle(ap.ae.sym, it->getParamI(0), 1 /* Direction */, it->getParamI(1), false); break; case ACTION_NEXT_FRAME_MRU: actionFocusToggle(ap.ae.sym, it->getParamI(0), 1 /* Direction */, it->getParamI(1), true); break; case ACTION_PREV_FRAME: actionFocusToggle(ap.ae.sym, it->getParamI(0), -1 /* Direction */, it->getParamI(1), false); break; case ACTION_PREV_FRAME_MRU: actionFocusToggle(ap.ae.sym, it->getParamI(0), -1 /* Direction */, it->getParamI(1), true); break; case ACTION_GOTO_WORKSPACE: // Events caused by a motion event ( dragging frame to // the edge ) or enter event ( moving the pointer to // the edge ) should warp the pointer. actionGotoWorkspace(it->getParamI(0), (ap.type == MotionNotify) || (ap.type == EnterNotify)); break; case ACTION_FIND_CLIENT: actionFindClient(Util::to_wide_str(it->getParamS())); break; case ACTION_GOTO_CLIENT_ID: actionGotoClientID(it->getParamI(0)); break; case ACTION_EXEC: actionExec(client, it->getParamS()); break; case ACTION_SHOW_MENU: actionShowMenu(it->getParamS(), it->getParamI(0), ap.type, client ? client : wo); break; case ACTION_HIDE_ALL_MENUS: MenuHandler::hideAllMenus(); break; case ACTION_RELOAD: WindowManager::instance()->reload(); break; case ACTION_RESTART: WindowManager::instance()->restart(); break; case ACTION_RESTART_OTHER: if (it->getParamS().size()) WindowManager::instance()->restart(it->getParamS()); break; case ACTION_EXIT: WindowManager::instance()->shutdown(); break; case ACTION_SHOW_CMD_DIALOG: actionShowInputDialog(WindowManager::instance()->getCmdDialog(), it->getParamS(), frame, wo); break; case ACTION_SHOW_SEARCH_DIALOG: actionShowInputDialog(WindowManager::instance()->getSearchDialog(), it->getParamS(), frame, wo); break; case ACTION_LAYOUT_ONCE: Workspaces::layoutOnce(it->getParamS()); break; case ACTION_SET_LAYOUTER: Workspaces::setLayouter(Workspaces::getActive(), it->getParamS()); Workspaces::layout(); break; case ACTION_SET_LAYOUTER_OPTION: Workspaces::setLayouterOption(it->getParamS(), 0); break; case ACTION_DEBUG: #ifdef DEBUG Debug::doAction(it->getParamS()); #endif break; default: matched = false; break; } } } } void ActionHandler::lookupWindowObjects(PWinObj **wo, Client **client, Frame **frame, PMenu **menu, PDecor **decor) { *client = 0; *frame = 0; *menu = 0; *decor = 0; if (PWinObj::windowObjectExists(*wo)) { if ((*wo)->getType() == PWinObj::WO_CLIENT) { *client = static_cast(*wo); *frame = static_cast((*client)->getParent()); *decor = static_cast(*frame); } else if ((*wo)->getType() == PWinObj::WO_FRAME) { *frame = static_cast(*wo); *client = static_cast((*frame)->getActiveChild()); *decor = static_cast(*wo); } else if ((*wo)->getType() == PWinObj::WO_MENU) { *menu = static_cast(*wo); *decor = static_cast(*wo); } else { *decor = dynamic_cast(*wo); } } else { *wo = 0; } } //! @brief Handles state actions void ActionHandler::handleStateAction(const Action &action, PWinObj *wo, Client *client, Frame *frame) { StateAction sa = static_cast(action.getAction()); // convenience bool matched = false; // check for frame actions if (! matched && frame) { matched = true; switch (action.getParamI(0)) { case ACTION_STATE_MAXIMIZED: frame->setStateMaximized(sa, action.getParamI(1), action.getParamI(2), false); break; case ACTION_STATE_FULLSCREEN: frame->setStateFullscreen(sa); break; case ACTION_STATE_SHADED: frame->setShaded(sa); break; case ACTION_STATE_STICKY: frame->setStateSticky(sa); break; case ACTION_STATE_ALWAYS_ONTOP: frame->setStateAlwaysOnTop(sa); break; case ACTION_STATE_ALWAYS_BELOW: frame->setStateAlwaysBelow(sa); break; case ACTION_STATE_DECOR_BORDER: frame->setStateDecorBorder(sa); break; case ACTION_STATE_DECOR_TITLEBAR: frame->setStateDecorTitlebar(sa); break; case ACTION_STATE_ICONIFIED: frame->setStateIconified(sa); break; case ACTION_STATE_TAGGED: frame->setStateTagged(sa, action.getParamI(1)); break; case ACTION_STATE_MARKED: frame->setStateMarked(sa, client); break; case ACTION_STATE_SKIP: frame->setStateSkip(sa, action.getParamI(1)); break; case ACTION_STATE_CFG_DENY: client->setStateCfgDeny(sa, action.getParamI(1)); break; case ACTION_STATE_DECOR: frame->setDecorOverride(sa, action.getParamS()); break; case ACTION_STATE_TITLE: frame->setStateTitle(sa, client, Util::to_wide_str(action.getParamS())); break; case ACTION_STATE_OPAQUE: frame->setStateOpaque(sa); break; default: matched = false; break; } } // check for menu actions if (! matched && wo && (wo->getType() == PWinObj::WO_MENU)) { matched = true; switch (action.getParamI(0)) { case ACTION_STATE_STICKY: wo->stick(); break; default: matched = false; break; } } if (! matched) { matched = true; switch (action.getParamI(0)) { case ACTION_STATE_HARBOUR_HIDDEN: WindowManager::instance()->getHarbour()->setStateHidden(sa); break; case ACTION_STATE_GLOBAL_GROUPING: WindowManager::instance()->setStateGlobalGrouping(sa); break; default: matched = false; break; } } } //! @brief Checks if motion threshold is within bounds. bool ActionHandler::checkAEThreshold(int x, int y, int x_t, int y_t, uint t) { if (((x > x_t) ? (x > (x_t + signed(t))) : (x < (x_t - signed(t)))) || ((y > y_t) ? (y > (y_t + signed(t))) : (y < (y_t - signed(t))))) { return true; } return false; } //! @brief Searches the actions list for an matching event ActionEvent* ActionHandler::findMouseAction(uint button, uint state, MouseEventType type, vector *actions) { if (! actions) { return 0; } X11::stripStateModifiers(&state); X11::stripButtonModifiers(&state); vector::iterator it(actions->begin()); for (; it != actions->end(); ++it) { if ((it->type == unsigned(type)) && ((it->mod == MOD_ANY) || (it->mod == state)) && ((it->sym == BUTTON_ANY) || (it->sym == button))) { return &*it; } } return 0; } /** * Execute action, setting client environment before (if any). */ void ActionHandler::actionExec(Client *client, const std::string &command) { if (command.size()) { Client::setClientEnvironment(client); Util::forkExec(command); } } //! @brief Searches for a client matching titles and makes it visible void ActionHandler::actionFindClient(const std::wstring &title) { Client *client = findClientFromTitle(title); if (client) { gotoClient(client); } } //! @brief Goto workspace //! @param workspace Workspace to got to //! @param warp If true, warp pointer as well void ActionHandler::actionGotoWorkspace(uint workspace, bool warp) { Workspaces::gotoWorkspace(workspace, warp); } //! @brief Focus client with id. //! @param id Client id. void ActionHandler::actionGotoClientID(uint id) { Client *client = Client::findClientFromID(id); if (client) { gotoClient(client); } } //! @brief Sends client to specified workspace //! @param direction Workspace to send to, or special meaning relative space. void ActionHandler::actionSendToWorkspace(PDecor *decor, int direction) { // Convenience const uint per_row = Workspaces::getPerRow(), cur_row = Workspaces::getRow(), cur_act = Workspaces::getActive(), row_min = Workspaces::getRowMin(), row_max = Workspaces::getRowMax(); switch (static_cast(direction)) { case WORKSPACE_LEFT: case WORKSPACE_PREV: if (cur_act > row_min) { decor->setWorkspace(cur_act - 1); } else if (static_cast(direction) == WORKSPACE_PREV) { decor->setWorkspace(row_max); } break; case WORKSPACE_NEXT: case WORKSPACE_RIGHT: if (cur_act < row_max) { decor->setWorkspace(cur_act + 1); } else if (static_cast(direction) == WORKSPACE_NEXT) { decor->setWorkspace(row_min); } break; case WORKSPACE_PREV_V: case WORKSPACE_UP: if (cur_act >= per_row) { decor->setWorkspace(cur_act - per_row); } else if (static_cast(direction) == WORKSPACE_PREV_V) { // Bottom left + column decor->setWorkspace(Workspaces::size() - per_row + cur_act - cur_row * per_row); } break; case WORKSPACE_NEXT_V: case WORKSPACE_DOWN: if ((cur_act + per_row) < Workspaces::size()) { decor->setWorkspace(cur_act + per_row); } else if (static_cast(direction) == WORKSPACE_NEXT_V) { decor->setWorkspace(cur_act - cur_row * per_row); } break; case WORKSPACE_LAST: decor->setWorkspace(Workspaces::getPrevious()); break; default: decor->setWorkspace(direction); break; } } //! @brief void ActionHandler::actionWarpToWorkspace(PDecor *decor, uint direction) { // Removing the already accumulated motion events can help // to avoid skipping workspaces (see task #77). X11::removeMotionEvents(); // actually did move if (Workspaces::gotoWorkspace(DirectionType(direction), true)) { int x, y; X11::getMousePosition(x, y); decor->move(decor->getClickX() + x - decor->getPointerX(), decor->getClickY() + y - decor->getPointerY()); decor->setWorkspace(Workspaces::getActive()); } } //! @brief Tries to find the next/prev frame relative to the focused client void ActionHandler::actionFocusToggle(uint button, uint raise, int off, bool show_iconified, bool mru) { std::unique_ptr menu{createNextPrevMenu(show_iconified, mru)}; // no clients in the list if (menu->size() == 0) { return; } // unable to grab keyboard if (! X11::grabKeyboard(X11::getRoot())) { return; } // find the focused window object PWinObj *fo_wo = 0; if (PWinObj::isFocusedPWinObj(PWinObj::WO_CLIENT)) { fo_wo = PWinObj::getFocusedPWinObj()->getParent(); vector::const_iterator it(menu->m_begin()); for (; it != menu->m_end(); ++it) { if ((*it)->getWORef() == fo_wo) { menu->selectItem(it); break; } } fo_wo->setFocused(false); } if (Config::instance()->getShowFrameList()) { menu->buildMenu(); Geometry head; X11::getHeadInfo(X11::getCurrHead(), head); menu->move(head.x + ((head.width - menu->getWidth()) / 2), head.y + ((head.height - menu->getHeight()) / 2)); menu->setFocused(true); menu->mapWindowRaised(); } menu->selectItemRel(off); fo_wo = menu->getItemCurr()->getWORef(); XEvent ev; bool cycling = true; bool was_iconified = false; while (cycling) { if (fo_wo) { fo_wo->setFocused(true); if (raise == ALWAYS_RAISE) { // Make sure it's not iconified if raise is on. if (fo_wo->isIconified()) { was_iconified = true; fo_wo->mapWindow(); } fo_wo->raise(); } else if (raise == TEMP_RAISE) { XRaiseWindow(X11::getDpy(), fo_wo->getWindow()); XRaiseWindow(X11::getDpy(), menu->getWindow()); } } XMaskEvent(X11::getDpy(), KeyPressMask|KeyReleaseMask, &ev); if (ev.type == KeyPress) { if (ev.xkey.keycode == button) { if (fo_wo) { if (raise == TEMP_RAISE) { Workspaces::fixStacking(fo_wo); } // Restore iconified state if (was_iconified) { was_iconified = false; fo_wo->iconify(); } fo_wo->setFocused(false); } menu->selectItemRel(off); fo_wo = menu->getItemCurr()->getWORef(); } else { XPutBackEvent(X11::getDpy(), &ev); cycling = false; } } else if (ev.type == KeyRelease) { if (IsModifierKey(X11::getKeysymFromKeycode(ev.xkey.keycode))) { cycling = false; } } else { XPutBackEvent(X11::getDpy(), &ev); } } X11::ungrabKeyboard(); // Got something to focus if (fo_wo) { if (raise == TEMP_RAISE) { fo_wo->raise(); fo_wo->setFocused(true); } // De-iconify if iconified, user probably wants this if (fo_wo->isIconified()) { // If the window was iconfied, and sticky fo_wo->setWorkspace(Workspaces::getActive()); fo_wo->mapWindow(); fo_wo->raise(); } else if (Raise(raise) == END_RAISE) { fo_wo->raise(); } // Give focus fo_wo->giveInputFocus(); } } //! @brief Finds a window in direction and gives it focus void ActionHandler::actionFocusDirectional(PWinObj *wo, DirectionType dir, bool raise) { PWinObj *wo_focus = Workspaces::findDirectional(wo, dir, SKIP_FOCUS_TOGGLE); if (wo_focus) { if (raise) { wo_focus->raise(); } wo_focus->giveInputFocus(); } } /** * Parse key information and send to wo. * * To handle this smoothly first all state modifiers are pressed one * by one adding to the state, then the real key is pressed and * released, then the state modifiers are released. * * @param win Window to send key to. * @param key_str String definition of key to send. * @return true if key was parsed ok, no validation of sending is done. */ bool ActionHandler::actionSendKey(PWinObj *wo, const std::string &key_str) { uint mod, key; if (! Config::instance()->parseKey(key_str, mod, key)) { return false; } XEvent ev; initSendKeyEvent(ev, wo); // Press state modifiers map::iterator it; for (it = _state_to_keycode.begin(); it != _state_to_keycode.end(); ++it) { if (mod & it->first) { ev.xkey.keycode = it->second; XSendEvent(X11::getDpy(), wo->getWindow(), True, KeyPressMask, &ev); ev.xkey.state |= it->first; } } // Send press and release of main key ev.xkey.keycode = key; XSendEvent(X11::getDpy(), wo->getWindow(), True, KeyPressMask, &ev); ev.type = KeyRelease; XSendEvent(X11::getDpy(), wo->getWindow(), True, KeyPressMask, &ev); // Release state modifiers for (it = _state_to_keycode.begin(); it != _state_to_keycode.end(); ++it) { if (mod & it->first) { ev.xkey.keycode = it->second; XSendEvent(X11::getDpy(), wo->getWindow(), True, KeyPressMask, &ev); ev.xkey.state &= ~it->first; } } return true; } void ActionHandler::actionSetOpacity(PWinObj *client, PWinObj *frame, uint focus, uint unfocus) { if (! unfocus) { unfocus = focus; } CONV_OPACITY(focus); CONV_OPACITY(unfocus); client->setOpacity(focus, unfocus); frame->setOpacity(client); } //! @brief Toggles visibility of menu. //! @param name Name of menu to toggle visibilty of //! @param stick Stick menu when showing //! @param e_type Event type triggered this action //! @param wo_ref Reference to active window object void ActionHandler::actionShowMenu(const std::string &name, bool stick, uint e_type, PWinObj *wo_ref) { PMenu *menu = MenuHandler::getMenu(name); if (! menu) { return; } if (menu->isMapped()) { menu->unmapAll(); } else { // if it's a WORefMenu, set referencing client WORefMenu *wo_ref_menu = dynamic_cast(menu); if (wo_ref_menu // Don't set reference on these, we don't want a funky title && (wo_ref_menu->getMenuType() != ROOTMENU_TYPE) && (wo_ref_menu->getMenuType() != ROOTMENU_STANDALONE_TYPE)) { wo_ref_menu->setWORef(wo_ref); } // mapping can fail because of empty menu, like iconmenu, so we check menu->mapUnderMouse(); if (menu->isMapped()) { menu->giveInputFocus(); if (stick) { menu->setSticky(true); } // if we opened the menu with the keyboard, select item 0 if (e_type == KeyPress) { menu->selectItemNum(0); } } } } void ActionHandler::actionShowInputDialog(InputDialog *dialog, const std::string &initial, Frame *frame, PWinObj *wo) { if (dialog->isMapped()) { dialog->unmapWindow(); } else { Geometry gm; if (frame) { frame->getGeometry(gm); } else { uint head = X11::getCurrHead(); X11::getHeadInfo(head, gm); } dialog->mapCentered(initial, gm, frame ? frame : wo); } } //! @brief Creates a menu containing a list of Frames currently visible //! @param show_iconified Flag to show/hide iconified windows //! @param mru Whether MRU order should be used or not. PMenu* ActionHandler::createNextPrevMenu(bool show_iconified, bool mru) { Frame *fr; ActionEvent ae; // empty ae, used when inserting PMenu *menu = new PMenu(WindowManager::instance()->getTheme(), mru?L"MRU Windows":L"Windows", "" /* Empty name*/); vector::const_iterator itr = mru?WindowManager::instance()->mru_begin():Frame::frame_begin(); vector::const_iterator end = mru?WindowManager::instance()->mru_end():Frame::frame_end(); for (; itr != end; ++itr) { fr = *itr; if (createMenuInclude(fr, show_iconified)) { menu->insert(static_cast(fr->getActiveChild())->getTitle()->getVisible(), ae, fr, static_cast(fr->getActiveChild())->getIcon()); } } return menu; } //! @brief Helper to decide wheter or not to include Frame in menu //! @param frame Frame to check //! @param show_iconified Wheter or not to include iconified windows //! @return true if it should be included, else false bool ActionHandler::createMenuInclude(Frame *frame, bool show_iconified) { // Make sure the frame is mapped, or on the correct workspace if // it's iconified. Also make sure it's possible to give it focus // and should not be skipped. The condition is rather complex, so // we split it up for readability. // focw == frame on current workspace bool focw = frame->isSticky() || frame->getWorkspace() == Workspaces::getActive(); // ibs == iconified but should be shown bool ibs = show_iconified && frame->isIconified() && focw; // mos == mapped or shown nonetheless bool mos = frame->isMapped() || ibs; return ! frame->isSkip(SKIP_FOCUS_TOGGLE) && frame->isFocusable() && mos; } //! @brief Searches the client list for a client with a title matching title Client* ActionHandler::findClientFromTitle(const std::wstring &or_title) { RegexString o_rs; if (o_rs.parse_match(or_title, true)) { vector::const_iterator it(Client::client_begin()); for (; it != Client::client_end(); ++it) { if (o_rs == (*it)->getTitle()->getVisible()) { return (*it); } } } return 0; } //! @brief Makes sure Client gets visible and focus it. //! @param client Client to activate. void ActionHandler::gotoClient(Client *client) { Frame *frame = dynamic_cast(client->getParent()); if (! frame) { WARN("parent is not a Frame"); return; } // Make sure it's visible if (! frame->isSticky() && (frame->getWorkspace() != Workspaces::getActive())) { Workspaces::setWorkspace(frame->getWorkspace(), false); WindowManager::instance()->addToMRUFront(frame); } if (! frame->isMapped()) { frame->mapWindow(); } // Activate it within the Frame. frame->activateChild(client); frame->raise(); frame->giveInputFocus(); } /** * Initialize XEvent for sending KeyPress/KeyRelease events. * * @param ev Reference to event. * @param wo PWinObj key event is aimed for. */ void ActionHandler::initSendKeyEvent(XEvent &ev, PWinObj *wo) { ev.type = KeyPress; ev.xkey.display = X11::getDpy(); ev.xkey.root = X11::getRoot(); ev.xkey.window = wo->getWindow(); ev.xkey.time = CurrentTime; ev.xkey.x = 1; ev.xkey.y = 1; X11::getMousePosition(ev.xkey.x_root, ev.xkey.y_root); ev.xkey.same_screen = True; ev.xkey.type = KeyPress; ev.xkey.state = 0; } pekwm-release-0.1.18/src/ActionHandler.hh000066400000000000000000000047051374756504400202120ustar00rootroot00000000000000// // ActionHandler.hh for pekwm // Copyright © 2003-2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifndef _ACTIONHANDLER_HH_ #define _ACTIONHANDLER_HH_ #include "config.h" #include "pekwm.hh" #include "Action.hh" #include "InputDialog.hh" #include #include class Client; class Frame; class PWinObj; class PDecor; class PMenu; class ActionHandler { public: ActionHandler(void); ~ActionHandler(void); static inline ActionHandler *instance(void) { return _instance; } void handleAction(const ActionPerformed &ap); static bool checkAEThreshold(int x, int y, int x_t, int y_t, uint t); static ActionEvent *findMouseAction(uint button, uint mod, MouseEventType type, vector *actions); private: void lookupWindowObjects(PWinObj **wo, Client **client, Frame **frame, PMenu **menu, PDecor **decor); void handleStateAction(const Action &action, PWinObj *wo, Client *client, Frame *frame); void actionExec(Client *client, const std::string &command); void actionFindClient(const std::wstring &title); void actionGotoClientID(uint id); void actionGotoWorkspace(uint workspace, bool warp); void actionSendToWorkspace(PDecor *decor, int direction); void actionWarpToWorkspace(PDecor *decor, uint direction); void actionFocusToggle(uint button, uint raise, int off, bool show_iconified, bool mru); void actionFocusDirectional(PWinObj *wo, DirectionType dir, bool raise); bool actionSendKey(PWinObj *wo, const std::string &key_str); static void actionSetOpacity(PWinObj *client, PWinObj *frame, uint focus, uint unfocus); void actionShowMenu(const std::string &name, bool stick, uint e_type, PWinObj *wo_ref); void actionShowInputDialog(InputDialog *dialog, const std::string &initial, Frame *frame, PWinObj *wo); // action helpers Client *findClientFromTitle(const std::wstring &title); void gotoClient(Client *client); PMenu *createNextPrevMenu(bool show_iconified, bool mru); bool createMenuInclude(Frame *frame, bool show_iconified); void initSendKeyEvent(XEvent &ev, PWinObj *wo); private: std::map _state_to_keycode; /**< Map translating state modifiers to keycode. */ static ActionHandler *_instance; /**< Instance pointer for ActionHandler. */ }; #endif // _ACTIONHANDLER_HH_ pekwm-release-0.1.18/src/ActionMenu.cc000066400000000000000000000224531374756504400175270ustar00rootroot00000000000000// // ActionMenu.cc for pekwm // Copyright © 2002-2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "config.h" #include #include #include #include "PWinObj.hh" #include "PDecor.hh" #include "PMenu.hh" #include "WORefMenu.hh" #include "ActionMenu.hh" #include "TextureHandler.hh" #include "ImageHandler.hh" #include "Config.hh" #include "ActionHandler.hh" #include "Client.hh" #include "Frame.hh" #include "WindowManager.hh" #include "Util.hh" using std::cerr; using std::endl; using std::find; using std::string; using std::wstring; //! @brief ActionMenu constructor //! @param type Type of menu //! @param title Title of menu //! @param name Name of the menu, empty for dynamic else should be unique //! @param decor_name Name of decor to use, defaults to MENU. ActionMenu::ActionMenu(MenuType type, const std::wstring &title, const std::string &name, const std::string &decor_name) : WORefMenu(WindowManager::instance()->getTheme(), title, name, decor_name), _act(WindowManager::instance()->getActionHandler()), _has_dynamic(false) { // when creating dynamic submenus, this needs to be initialized as // dynamic inserting will be done _insert_at = 0; _menu_type = type; if (_menu_type == WINDOWMENU_TYPE) { _action_ok = WINDOWMENU_OK; } else if ((_menu_type == ROOTMENU_TYPE) || (_menu_type == ROOTMENU_STANDALONE_TYPE)) { _action_ok = ROOTMENU_OK; } } //! @brief ActionMenu destructor ActionMenu::~ActionMenu(void) { removeAll(); } // START - PWinObj interface. //! @brief Rebuilds the vmenu and if it has any items after it shows it. void ActionMenu::mapWindow(void) { // find and rebuild the dynamic entries if (! isMapped() && _has_dynamic) { uint size_before = _items.size(); rebuildDynamic(); if (size_before != _items.size()) { buildMenu(); } } PMenu::mapWindow(); } //! @brief Hides and removes all items created by dynamic entries. void ActionMenu::unmapWindow(void) { if (! isMapped()) { return; } if (_has_dynamic) { removeDynamic(); } PMenu::unmapWindow(); } // END - PWinObj interface. //! @brief Handle item exec. void ActionMenu::handleItemExec(PMenu::Item *item) { if (! item) { return; } ActionPerformed ap(getWORef(), item->getAE()); _act->handleAction(ap); } /** * Re-reads the configuration clearing old entries from the menu. This * adds the ICON_PATH to the ImageHandler before loading to support * loading icons properly. * * @param section CfgParser::Entry with menu configuration */ void ActionMenu::reload(CfgParser::Entry *section) { // Clear menu removeAll(); // Parse section (if any) ImageHandler::instance()->path_push_back(Config::instance()->getSystemIconPath()); ImageHandler::instance()->path_push_back(Config::instance()->getIconPath()); _insert_at = 0; parse(section); ImageHandler::instance()->path_pop_back(); ImageHandler::instance()->path_pop_back(); // Build menu from parsed content buildMenu(); } //! @brief Checks if we have a position set for where to insert. void ActionMenu::insert(PMenu::Item *item) { if (! item) { return; } checkItemWORef(item); _items.insert(_items.begin() + _insert_at, item); ++_insert_at; } //! @brief Removes a BaseMenuItem from the menu void ActionMenu::remove(PMenu::Item *item) { if (! item) { return; } if (item->getIcon()) { TextureHandler::instance()->returnTexture(item->getIcon()); } if (item->getWORef() && (item->getWORef()->getType() == WO_MENU)) { delete item->getWORef(); } PMenu::remove(item); } //! @brief Removes all items from the menu void ActionMenu::removeAll(void) { while (! _items.empty()) { remove(_items.back()); } _item_curr = 0; } //! @brief Parse config and push items into menu //! @param cs Section object to read config from //! @param menu BaseMenu object to push object in //! @param has_dynamic If true the menu being parsed is dynamic, defaults to false. void ActionMenu::parse(CfgParser::Entry *section, PMenu::Item *parent) { if (! section) { return; } if (section->getValue().size()) { wstring title(Util::to_wide_str(section->getValue())); setTitle(title); _title_base = title; } CfgParser::Entry *value; ActionEvent ae; ActionMenu *submenu = 0; PMenu::Item *item = 0; PTexture *icon = 0; CfgParser::iterator it(section->begin()); for (; it != section->end(); ++it) { item = 0; if (*(*it) == "SUBMENU") { CfgParser::Entry *sub_section = (*it)->getSection(); if (sub_section) { icon = getIcon(sub_section->findEntry("ICON")); submenu = new ActionMenu(_menu_type, Util::to_wide_str((*it)->getValue()), (*it)->getValue()); submenu->_menu_parent = this; submenu->parse(sub_section, parent); submenu->buildMenu(); item = new PMenu::Item(Util::to_wide_str(sub_section->getValue()), submenu, icon); item->setCreator(parent); } else { cerr << " *** WARNING: submenu entry does not contain any section." << endl; } } else if (*(*it) == "SEPARATOR") { // No icon support on separators. item = new PMenu::Item(L"", 0, 0); item->setType(PMenu::Item::MENU_ITEM_SEPARATOR); item->setCreator(parent); } else { CfgParser::Entry *sub_section = (*it)->getSection(); if (sub_section) { // Inside of the Entry = "foo" { ... } section, here // Actions and Icon are the valid options. value = sub_section->findEntry("ACTIONS"); if (value && Config::instance()->parseActions(value->getValue(), ae, _action_ok)) { icon = getIcon(sub_section->findEntry("ICON")); item = new PMenu::Item(Util::to_wide_str(sub_section->getValue()), 0, icon); item->setCreator(parent); item->setAE(ae); if (ae.isOnlyAction(ACTION_MENU_DYN)) { _has_dynamic = true; item->setType(PMenu::Item::MENU_ITEM_HIDDEN); } } } } // If an item was successfully created, insert it to the menu. if (item) { insert(item); } } } /** * Get icon texture from parser value. * * @param value Entry to get icon name from. * @return PTexture if icon was loaded, else 0. */ PTexture* ActionMenu::getIcon(CfgParser::Entry *value) { // Skip blank icons if (! value || ! value->getValue().size()) { return 0; } PTexture *icon = 0; // Try to load the icon as a complete texture specification, if // that fails load is an scaled image. icon = TextureHandler::instance()->getTexture(value->getValue()); if (! icon) { icon = TextureHandler::instance()->getTexture("IMAGE " + value->getValue() + "#SCALED"); } return icon; } /** * Executes all Dynamic entries in the menu. */ void ActionMenu::rebuildDynamic(void) { PWinObj *wo_ref = getWORef(); // Export environment before to dynamic script. Client *client = 0; if (wo_ref && wo_ref->getType() == WO_CLIENT) { client = static_cast(wo_ref); } Client::setClientEnvironment(client); // Setup icon path before parsing. ImageHandler::instance()->path_push_back(Config::instance()->getSystemIconPath()); ImageHandler::instance()->path_push_back(Config::instance()->getIconPath()); PMenu::Item* item = 0; vector::iterator it; for (it = _items.begin(); it != _items.end(); ++it) { if ((*it)->getAE().isOnlyAction(ACTION_MENU_DYN)) { _insert_at = it - _items.begin(); item = *it; CfgParser dynamic; if (dynamic.parse((*it)->getAE().action_list.front().getParamS(), CfgParserSource::SOURCE_COMMAND)) { _has_dynamic = true; parse(dynamic.getEntryRoot()->findSection("DYNAMIC"), *it); } it = find(_items.begin(), _items.end(), item); } } _insert_at = _items.size(); // Cleanup icon path ImageHandler::instance()->path_pop_back(); ImageHandler::instance()->path_pop_back(); } //! @brief Remove all entries from the menu created by dynamic entries. void ActionMenu::removeDynamic(void) { std::set dynlist; vector::iterator it(_items.begin()); for (; it != _items.end(); ++it) { if ((*it)->getType() == PMenu::Item::MENU_ITEM_HIDDEN) { dynlist.insert(*it); } } it = _items.begin(); for (; it != _items.end();) { if (dynlist.find((*it)->getCreator()) != dynlist.end()) { if ((*it)->getWORef() && ((*it)->getWORef()->getType() == WO_MENU)) { delete (*it)->getWORef(); } delete (*it); it = _items.erase(it); } else { ++it; } } } pekwm-release-0.1.18/src/ActionMenu.hh000066400000000000000000000027161374756504400175410ustar00rootroot00000000000000// // ActionMenu.hh for pekwm // Copyright © 2002-2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifndef _ACTIONMENU_HH_ #define _ACTIONMENU_HH_ #include "config.h" #include "pekwm.hh" #include "Action.hh" // For ActionOk #include "CfgParser.hh" #include "PMenu.hh" #include class WORefMenu; class PScreen; class Theme; class ActionHandler; class ActionMenu : public WORefMenu { public: ActionMenu(MenuType type, const std::wstring &title, const std::string &name, const std::string &decor_name = "MENU"); virtual ~ActionMenu(void); // START - PWinObj interface. virtual void mapWindow(void); virtual void unmapWindow(void); // END - PWinObj interface. virtual void handleItemExec(PMenu::Item *item); virtual void insert(PMenu::Item *item); using PMenu::insert; virtual void reload(CfgParser::Entry *section); virtual void remove(PMenu::Item *item); virtual void removeAll(void); private: void parse(CfgParser::Entry *section, PMenu::Item *parent=0); PTexture *getIcon(CfgParser::Entry *value); void rebuildDynamic(void); void removeDynamic(void); private: ActionHandler *_act; ActionOk _action_ok; vector::size_type _insert_at; bool _has_dynamic; /**< Set to true if any of the entries in the menu is dynamic. */ }; #endif // _ACTIONMENU_HH_ pekwm-release-0.1.18/src/AutoProperties.cc000066400000000000000000000675551374756504400204660ustar00rootroot00000000000000// // AutoProperties.cc for pekwm // Copyright © 2003-2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "config.h" #include #include #include "AutoProperties.hh" #include "Config.hh" #include "Util.hh" using std::cerr; using std::endl; using std::find; using std::map; using std::string; using std::strtol; AutoProperties *AutoProperties::_instance = 0; //! @brief Constructor for AutoProperties class AutoProperties::AutoProperties(void) : _extended(false), _harbour_sort(false), _apply_on_start(true) { #ifdef DEBUG if (_instance) { cerr << __FILE__ << "@" << __LINE__ << ": " << "AutoProperties(" << this << ")::AutoProperties()" << endl << " *** _instance already set: " << _instance << endl; } #endif // DEBUG _instance = this; // fill parsing maps _apply_on_map[""] = APPLY_ON_ALWAYS; _apply_on_map["START"] = APPLY_ON_START; _apply_on_map["NEW"] = APPLY_ON_NEW; _apply_on_map["RELOAD"] = APPLY_ON_RELOAD; _apply_on_map["WORKSPACE"] = APPLY_ON_WORKSPACE; _apply_on_map["TRANSIENT"] = APPLY_ON_TRANSIENT; _apply_on_map["TRANSIENTONLY"] = APPLY_ON_TRANSIENT_ONLY; // global properties _property_map[""] = AP_NO_PROPERTY; _property_map["WORKSPACE"] = AP_WORKSPACE; _property_map["PROPERTY"] = AP_PROPERTY; _property_map["STICKY"] = AP_STICKY; _property_map["SHADED"] = AP_SHADED; _property_map["MAXIMIZEDVERTICAL"] = AP_MAXIMIZED_VERTICAL; _property_map["MAXIMIZEDHORIZONTAL"] = AP_MAXIMIZED_HORIZONTAL; _property_map["ICONIFIED"] = AP_ICONIFIED; _property_map["BORDER"] = AP_BORDER; _property_map["TITLEBAR"] = AP_TITLEBAR; _property_map["FRAMEGEOMETRY"] = AP_FRAME_GEOMETRY; _property_map["CLIENTGEOMETRY"] = AP_CLIENT_GEOMETRY; _property_map["LAYER"] = AP_LAYER; _property_map["SKIP"] = AP_SKIP; _property_map["FULLSCREEN"] = AP_FULLSCREEN; _property_map["PLACENEW"] = AP_PLACE_NEW; _property_map["FOCUSNEW"] = AP_FOCUS_NEW; _property_map["FOCUSABLE"] = AP_FOCUSABLE; _property_map["CFGDENY"] = AP_CFG_DENY; _property_map["ALLOWEDACTIONS"] = AP_ALLOWED_ACTIONS; _property_map["DISALLOWEDACTIONS"] = AP_DISALLOWED_ACTIONS; _property_map["OPACITY"] = AP_OPACITY; _property_map["DECOR"] = AP_DECOR; // group properties _group_property_map[""] = AP_NO_PROPERTY; _group_property_map["SIZE"] = AP_GROUP_SIZE; _group_property_map["BEHIND"] = AP_GROUP_BEHIND; _group_property_map["FOCUSEDFIRST"] = AP_GROUP_FOCUSED_FIRST; _group_property_map["GLOBAL"] = AP_GROUP_GLOBAL; _group_property_map["RAISE"] = AP_GROUP_RAISE; // window type map _window_type_map[""] = WINDOW_TYPE; _window_type_map["DESKTOP"] = WINDOW_TYPE_DESKTOP; _window_type_map["DOCK"] = WINDOW_TYPE_DOCK; _window_type_map["TOOLBAR"] = WINDOW_TYPE_TOOLBAR; _window_type_map["MENU"] = WINDOW_TYPE_MENU; _window_type_map["UTILITY"] = WINDOW_TYPE_UTILITY; _window_type_map["SPLASH"] = WINDOW_TYPE_SPLASH; _window_type_map["DIALOG"] = WINDOW_TYPE_DIALOG; _window_type_map["NORMAL"] = WINDOW_TYPE_NORMAL; } //! @brief Destructor for AutoProperties class AutoProperties::~AutoProperties(void) { unload(); _instance = 0; } //! @brief Loads the autoprop config file. bool AutoProperties::load(void) { string cfg_file(Config::instance()->getAutoPropsFile()); if (! _cfg_files.requireReload(cfg_file)) { return false; } // dealloc memory unload(); CfgParser a_cfg; if (! a_cfg.parse(cfg_file, CfgParserSource::SOURCE_FILE, false)) { cfg_file = SYSCONFDIR "/autoproperties"; if (! a_cfg.parse (cfg_file, CfgParserSource::SOURCE_FILE, false)) { setDefaultTypeProperties(); return false; } } // Setup template parsing if requested loadRequire(a_cfg, cfg_file); if (a_cfg.isDynamicContent()) { _cfg_files.clear(); } else { _cfg_files = a_cfg.getCfgFiles(); } // reset values _apply_on_start = true; vector tokens; vector::iterator token_it; vector workspaces; CfgParser::iterator it(a_cfg.getEntryRoot()->begin()); for (; it != a_cfg.getEntryRoot()->end(); ++it) { if (*(*it) == "PROPERTY") { parseAutoProperty(*it, 0); } else if (*(*it) == "TITLERULES") { parseTitleProperty(*it); } else if (*(*it) == "DECORRULES") { parseDecorProperty(*it); } else if (*(*it) == "TYPERULES") { parseTypeProperty(*it); } else if (*(*it) == "HARBOUR") { parseDockAppProperty(*it); } else if (*(*it) == "WORKSPACE") { // Workspace section CfgParser::Entry *workspace = (*it)->getSection(); tokens.clear(); if (Util::splitString(workspace->getValue(), tokens, " \t")) { workspaces.clear(); for (token_it = tokens.begin(); token_it != tokens.end(); ++token_it) workspaces.push_back(strtol(token_it->c_str(), 0, 10)); // Get all properties on for these workspaces. CfgParser::iterator workspace_it(workspace->begin()); for (; workspace_it != workspace->end(); ++workspace_it) { parseAutoProperty(*workspace_it, &workspaces); } } } } // Validate date setDefaultTypeProperties(); return true; } /** * Load autoproperties quirks. */ void AutoProperties::loadRequire(CfgParser &a_cfg, std::string &file) { CfgParser::Entry *section; // Look for requires section, section = a_cfg.getEntryRoot()->findSection("REQUIRE"); if (section) { vector keys; keys.push_back(new CfgParserKeyBool("TEMPLATES", _extended, false)); section->parseKeyValues(keys.begin(), keys.end()); for_each(keys.begin(), keys.end(), Util::Free()); // Re-load configuration with templates enabled. if (_extended) { a_cfg.clear(true); a_cfg.parse(file, CfgParserSource::SOURCE_FILE, true); } } else { _extended = false; } } //! @brief Frees allocated memory void AutoProperties::unload(void) { vector::iterator it; // remove auto properties for (it = _prop_list.begin(); it != _prop_list.end(); ++it) { delete *it; } _prop_list.clear(); // remove title properties for (it = _title_prop_list.begin(); it != _title_prop_list.end(); ++it) { delete *it; } _title_prop_list.clear(); // remove decor properties for (it = _decor_prop_list.begin(); it != _decor_prop_list.end(); ++it) { delete *it; } _decor_prop_list.clear(); // remove dock app properties for (it = _dock_app_prop_list.begin(); it != _dock_app_prop_list.end(); ++it) { delete *it; } _dock_app_prop_list.clear(); // remove type properties map::iterator m_it(_window_type_prop_map.begin()); for (; m_it != _window_type_prop_map.end(); ++m_it) { delete m_it->second; } _window_type_prop_map.clear(); } //! @brief Finds a property from the prop_list Property* AutoProperties::findProperty(const ClassHint* class_hint, vector* prop_list, uint ws, ApplyOn type) { // Allready remove apply on start if (! _apply_on_start && (type == APPLY_ON_START)) return 0; vector::const_iterator it(prop_list->begin()); vector::const_iterator end(prop_list->end()); // start searching for a suitable property for (; it != end; ++it) { // see if the type matches, if we have one if ((type != APPLY_ON_ALWAYS) && ! (*it)->isApplyOn(type)) continue; if (matchAutoClass(*class_hint, *it)) { return (*it)->applyOnWs(ws)?*it:0; } } return 0; } /** * Parse regex_str and set on regex, outputting warning with name if * it fails. */ bool AutoProperties::parseRegexpOrWarning(RegexString ®ex, const std::string regex_str, const std::string &name) { if (! regex_str.size() || regex.parse_match(Util::to_wide_str(regex_str))) { return true; } else { cerr << " *** WARNING: invalid regexp " << regex_str << " for autoproperty " << name << endl; return false; } } //! @brief Parses a property match rule //! @param str String to parse. //! @param prop Property to place result in. //! @return true on success, else false. bool AutoProperties::parsePropertyMatch(const std::string &str, Property *prop) { bool status = false; // Format of property matches are regexp,regexp . Split up in class // and role regexps. vector tokens; Util::splitString(str, tokens, ",", _extended ? 5 : 2, true); if (tokens.size() >= 2) { // Make sure one of the two regexps compiles status = parseRegexpOrWarning(prop->getHintName(), tokens[0], "name"); status = status && parseRegexpOrWarning(prop->getHintClass(), tokens[1], "class"); } // Parse extended part of regexp, role, title and apply on if (status && _extended) { if (status && tokens.size() > 2) { status = parseRegexpOrWarning(prop->getRole(), tokens[2], "role"); } if (status && tokens.size() > 3) { status = parseRegexpOrWarning(prop->getTitle(), tokens[3], "title"); } if (status && tokens.size() > 4) { parsePropertyApplyOn(tokens[4], prop); } } return status; } //! @brief Parses a cs and sets up a basic property bool AutoProperties::parseProperty(CfgParser::Entry *section, Property *prop) { CfgParser::Entry *value; // Get extra matching info. value = section->findEntry("TITLE"); if (value) { parseRegexpOrWarning(prop->getTitle(), value->getValue(), "title"); } value = section->findEntry("ROLE"); if (value) { parseRegexpOrWarning(prop->getRole(), value->getValue(), "role"); } // Parse apply on mask. value = section->findEntry("APPLYON"); if (value) { parsePropertyApplyOn(value->getValue(), prop); } return true; } /** * Parse property apply on. */ void AutoProperties::parsePropertyApplyOn(const std::string &apply_on, Property *prop) { vector tokens; if (Util::splitString(apply_on, tokens, " \t", 5)) { vector::iterator it(tokens.begin()); for (; it != tokens.end(); ++it) { prop->applyAdd(static_cast(ParseUtil::getValue(*it, _apply_on_map))); } } } //! @brief Parses AutopProperty void AutoProperties::parseAutoProperty(CfgParser::Entry *section, vector *ws) { // Get sub section section = section->getSection(); if (! section) { return; } AutoProperty* property = new AutoProperty(); parsePropertyMatch(section->getValue(), property); if (parseProperty(section, property)) { parseAutoPropertyValue(section, property, ws); _prop_list.push_back(property); } else { delete property; } } //! @brief Parses a Group section of the AutoProps void AutoProperties::parseAutoGroup(CfgParser::Entry *section, AutoProperty* property) { if (! section) { return; } if (section->getValue().size()) { property->group_name = Util::to_wide_str(section->getValue()); } PropertyType property_type; CfgParser::iterator it(section->begin()); for (; it != section->end(); ++it) { property_type = ParseUtil::getValue((*it)->getName(), _group_property_map); switch (property_type) { case AP_GROUP_SIZE: property->group_size = strtol((*it)->getValue().c_str(), 0, 10); break; case AP_GROUP_BEHIND: property->group_behind = Util::isTrue((*it)->getValue()); break; case AP_GROUP_FOCUSED_FIRST: property->group_focused_first = Util::isTrue((*it)->getValue()); break; case AP_GROUP_GLOBAL: property->group_global = Util::isTrue((*it)->getValue()); break; case AP_GROUP_RAISE: property->group_raise = Util::isTrue((*it)->getValue()); break; default: // do nothing break; } } } /** * Parses a title property section. */ void AutoProperties::parseTitleProperty(CfgParser::Entry *section) { section = section->getSection(); TitleProperty *title_property; CfgParser::Entry *title_section; CfgParser::iterator it(section->begin()); for (; it != section->end(); ++it) { title_section = (*it)->getSection(); if (! title_section) { continue; } title_property = new TitleProperty(); parsePropertyMatch(title_section->getValue(), title_property); if (parseProperty(title_section, title_property)) { CfgParser::Entry *value = title_section->findEntry("RULE"); if (value && title_property->getTitleRule().parse_ed_s(Util::to_wide_str(value->getValue()))) { _title_prop_list.push_back(title_property); title_property = 0; } } if (title_property) { delete title_property; } } } /** * Parse decor property sections. */ void AutoProperties::parseDecorProperty(CfgParser::Entry *section) { section = section->getSection(); DecorProperty *decor_property; CfgParser::Entry *decor_section; CfgParser::iterator it(section->begin()); for (; it != section->end(); ++it) { decor_section = (*it)->getSection (); if (! decor_section) { continue; } decor_property = new DecorProperty(); parsePropertyMatch(decor_section->getValue (), decor_property); if (parseProperty(decor_section, decor_property)) { CfgParser::Entry *value = decor_section->findEntry("DECOR"); if (value) { decor_property->applyAdd(APPLY_ON_START); decor_property->setName(value->getValue()); _decor_prop_list.push_back(decor_property); decor_property = 0; } } if (decor_property) { delete decor_property; } } } /** * Parse dock app properties. */ void AutoProperties::parseDockAppProperty(CfgParser::Entry *section) { section = section->getSection(); // Reset harbour sort, set to true if POSITION property found. _harbour_sort = false; DockAppProperty *dock_property; CfgParser::Entry *dock_section; CfgParser::iterator it(section->begin()); for (; it != section->end(); ++it) { dock_section = (*it)->getSection(); if (! dock_section) { continue; } dock_property = new DockAppProperty(); parsePropertyMatch(dock_section->getValue(), dock_property); if (parseProperty(dock_section, dock_property)) { CfgParser::Entry *value = dock_section->findEntry("POSITION"); if (value) { _harbour_sort = true; int position = strtol(value->getValue().c_str(), 0, 10); dock_property->setPosition(position); _decor_prop_list.push_back(dock_property); dock_property = 0; } } if (dock_property) { delete dock_property; } } } //! @brief Parse type auto properties. //! @param section Section containing properties. void AutoProperties::parseTypeProperty(CfgParser::Entry *section) { // Get sub section section = section->getSection(); AtomName atom; AutoProperty *type_property; CfgParser::Entry *type_section; map::iterator atom_it; // Look for all type properties CfgParser::iterator it(section->begin()); for (; it != section->end(); ++it) { type_section = (*it)->getSection(); if (! type_section) { continue; } // Create new property and try to parse type_property = new AutoProperty(); atom = ParseUtil::getValue(type_section->getValue(), _window_type_map); if (atom == WINDOW_TYPE) { cerr << " *** WARNING: unknown type " << type_section->getValue() << " for autoproperty." << endl; } if (atom != WINDOW_TYPE && parseProperty(type_section, type_property)) { // Parse of match ok, parse values parseAutoPropertyValue(type_section, type_property, 0); // Add to list, make sure it does not exist already atom_it = _window_type_prop_map.find(atom); if (atom_it != _window_type_prop_map.end()) { cerr << " *** WARNING: multiple type autoproperties for type " << type_section->getValue() << endl; delete atom_it->second; } _window_type_prop_map[atom] = type_property; } else { delete type_property; } } } //! @brief Set default values for type auto properties not in configuration. void AutoProperties::setDefaultTypeProperties(void) { // DESKTOP if (! findWindowTypeProperty(WINDOW_TYPE_DESKTOP)) { AutoProperty *prop = new AutoProperty(); prop->maskAdd(AP_CLIENT_GEOMETRY); prop->client_gm_mask = XParseGeometry("0x0+0+0", &prop->client_gm.x, &prop->client_gm.y, &prop->client_gm.width, &prop->client_gm.height); prop->maskAdd(AP_STICKY); prop->sticky = true; prop->maskAdd(AP_TITLEBAR); prop->titlebar = false; prop->maskAdd(AP_BORDER); prop->border = false; prop->maskAdd(AP_SKIP); prop->skip = SKIP_MENUS|SKIP_FOCUS_TOGGLE|SKIP_SNAP|SKIP_PAGER|SKIP_TASKBAR; prop->maskAdd(AP_LAYER); prop->layer = LAYER_DESKTOP; prop->maskAdd(AP_FOCUSABLE); prop->focusable = false; prop->maskAdd(AP_DISALLOWED_ACTIONS); prop->disallowed_actions = ACTION_ACCESS_MOVE|ACTION_ACCESS_RESIZE; _window_type_prop_map[WINDOW_TYPE_DESKTOP] = prop; } // DOCK if (! findWindowTypeProperty(WINDOW_TYPE_DOCK)) { AutoProperty *prop = new AutoProperty(); prop->maskAdd(AP_STICKY); prop->sticky = true; prop->maskAdd(AP_TITLEBAR); prop->titlebar = false; prop->maskAdd(AP_BORDER); prop->border = false; prop->maskAdd(AP_SKIP); prop->skip = SKIP_MENUS|SKIP_FOCUS_TOGGLE|SKIP_PAGER|SKIP_TASKBAR; prop->maskAdd(AP_LAYER); prop->layer = LAYER_DOCK; prop->maskAdd(AP_FOCUSABLE); prop->focusable = false; prop->maskAdd(AP_DISALLOWED_ACTIONS); prop->disallowed_actions = ACTION_ACCESS_MOVE|ACTION_ACCESS_RESIZE; _window_type_prop_map[WINDOW_TYPE_DOCK] = prop; } // TOOLBAR if (! findWindowTypeProperty(WINDOW_TYPE_TOOLBAR)) { AutoProperty *prop = new AutoProperty(); prop->maskAdd(AP_TITLEBAR); prop->titlebar = true; prop->maskAdd(AP_BORDER); prop->border = true; prop->maskAdd(AP_SKIP); prop->skip = SKIP_MENUS|SKIP_FOCUS_TOGGLE|SKIP_PAGER|SKIP_TASKBAR; _window_type_prop_map[WINDOW_TYPE_TOOLBAR] = prop; } // MENU if (! findWindowTypeProperty(WINDOW_TYPE_MENU)) { AutoProperty *prop = new AutoProperty(); prop->maskAdd(AP_TITLEBAR); prop->titlebar = false; prop->maskAdd(AP_BORDER); prop->border = false; prop->maskAdd(AP_SKIP); prop->skip = SKIP_MENUS|SKIP_FOCUS_TOGGLE|SKIP_SNAP|SKIP_PAGER|SKIP_TASKBAR; _window_type_prop_map[WINDOW_TYPE_MENU] = prop; } // UTILITY if (! findWindowTypeProperty(WINDOW_TYPE_UTILITY)) { AutoProperty *prop = new AutoProperty(); prop->maskAdd(AP_TITLEBAR); prop->titlebar = true; prop->maskAdd(AP_BORDER); prop->border = true; prop->maskAdd(AP_SKIP); prop->skip = SKIP_MENUS|SKIP_FOCUS_TOGGLE|SKIP_SNAP; _window_type_prop_map[WINDOW_TYPE_UTILITY] = prop; } // SPLASH if (! findWindowTypeProperty(WINDOW_TYPE_SPLASH)) { AutoProperty *prop = new AutoProperty(); prop->maskAdd(AP_TITLEBAR); prop->titlebar = false; prop->maskAdd(AP_BORDER); prop->border = false; _window_type_prop_map[WINDOW_TYPE_SPLASH] = prop; } } //! @brief Parse AutoProperty value attributes. //! @param section Config section to parse. //! @param prop Property to store result in. //! @param ws List of workspaces to apply property on. void AutoProperties::parseAutoPropertyValue(CfgParser::Entry *section, AutoProperty *prop, vector *ws) { // Copy workspaces, if any if (ws) { prop->setWorkspaces(*ws); } // See if we have a group section CfgParser::Entry *group_section(section->findSection("GROUP")); if (group_section) { parseAutoGroup(group_section, prop); } // start parsing of values string name, value; vector tokens; vector::iterator token_it; PropertyType property_type; CfgParser::iterator it(section->begin()); for (; it != section->end(); ++it) { property_type = ParseUtil::getValue((*it)->getName(), _property_map); switch (property_type) { case AP_STICKY: prop->maskAdd(AP_STICKY); prop->sticky = Util::isTrue((*it)->getValue()); break; case AP_SHADED: prop->maskAdd(AP_SHADED); prop->shaded = Util::isTrue((*it)->getValue()); break; case AP_MAXIMIZED_VERTICAL: prop->maskAdd(AP_MAXIMIZED_VERTICAL); prop->maximized_vertical = Util::isTrue((*it)->getValue()); break; case AP_MAXIMIZED_HORIZONTAL: prop->maskAdd(AP_MAXIMIZED_HORIZONTAL); prop->maximized_horizontal = Util::isTrue((*it)->getValue()); break; case AP_ICONIFIED: prop->maskAdd(AP_ICONIFIED); prop->iconified = Util::isTrue((*it)->getValue()); break; case AP_BORDER: prop->maskAdd(AP_BORDER); prop->border = Util::isTrue((*it)->getValue()); break; case AP_TITLEBAR: prop->maskAdd(AP_TITLEBAR); prop->titlebar = Util::isTrue((*it)->getValue()); break; case AP_FRAME_GEOMETRY: prop->maskAdd(AP_FRAME_GEOMETRY); prop->frame_gm_mask = XParseGeometry((char*) (*it)->getValue().c_str(), &prop->frame_gm.x, &prop->frame_gm.y, &prop->frame_gm.width, &prop->frame_gm.height); break; case AP_CLIENT_GEOMETRY: prop->maskAdd(AP_CLIENT_GEOMETRY); prop->client_gm_mask = XParseGeometry((char*) (*it)->getValue().c_str(), &prop->client_gm.x, &prop->client_gm.y, &prop->client_gm.width, &prop->client_gm.height); break; case AP_LAYER: prop->layer = Config::instance()->getLayer((*it)->getValue()); if (prop->layer != LAYER_NONE) { prop->maskAdd(AP_LAYER); } break; case AP_WORKSPACE: prop->maskAdd(AP_WORKSPACE); prop->workspace = unsigned(strtol((*it)->getValue().c_str(), 0, 10) - 1); break; case AP_SKIP: prop->maskAdd(AP_SKIP); tokens.clear(); if ((Util::splitString((*it)->getValue(), tokens, " \t"))) { for (token_it = tokens.begin(); token_it != tokens.end(); ++token_it) { prop->skip |= Config::instance()->getSkip(*token_it); } } break; case AP_FULLSCREEN: prop->maskAdd(AP_FULLSCREEN); prop->fullscreen = Util::isTrue((*it)->getValue()); break; case AP_PLACE_NEW: prop->maskAdd(AP_PLACE_NEW); prop->place_new = Util::isTrue((*it)->getValue()); break; case AP_FOCUS_NEW: prop->maskAdd(AP_FOCUS_NEW); prop->focus_new = Util::isTrue((*it)->getValue()); break; case AP_FOCUSABLE: prop->maskAdd(AP_FOCUSABLE); prop->focusable = Util::isTrue((*it)->getValue()); break; case AP_CFG_DENY: prop->maskAdd(AP_CFG_DENY); tokens.clear(); if ((Util::splitString((*it)->getValue(), tokens, " \t"))) { for (token_it = tokens.begin(); token_it != tokens.end(); ++token_it) { prop->cfg_deny |= Config::instance()->getCfgDeny(*token_it); } } break; case AP_ALLOWED_ACTIONS: prop->maskAdd(AP_ALLOWED_ACTIONS); Config::instance()->parseActionAccessMask((*it)->getValue(), prop->allowed_actions); break; case AP_DISALLOWED_ACTIONS: prop->maskAdd(AP_DISALLOWED_ACTIONS); Config::instance()->parseActionAccessMask((*it)->getValue(), prop->disallowed_actions); break; case AP_OPACITY: prop->maskAdd(AP_OPACITY); Config::parseOpacity((*it)->getValue(), prop->focus_opacity, prop->unfocus_opacity); break; case AP_DECOR: prop->maskAdd(AP_DECOR); prop->frame_decor = (*it)->getValue(); break; default: // do nothing break; } } } //! @brief Searches the _prop_list for a property AutoProperty* AutoProperties::findAutoProperty(const ClassHint* class_hint, int ws, ApplyOn type) { return static_cast(findProperty(class_hint, &_prop_list, ws, type)); } //! @brief Searches the _title_prop_list for a property TitleProperty* AutoProperties::findTitleProperty(const ClassHint* class_hint) { return static_cast(findProperty(class_hint, &_title_prop_list, -1, APPLY_ON_ALWAYS)); } //! @brief DecorProperty* AutoProperties::findDecorProperty(const ClassHint* class_hint) { return static_cast(findProperty(class_hint, &_decor_prop_list, -1, APPLY_ON_ALWAYS)); } DockAppProperty* AutoProperties::findDockAppProperty(const ClassHint *class_hint) { return static_cast(findProperty(class_hint, &_dock_app_prop_list, -1, APPLY_ON_ALWAYS)); } //! @brief Get AutoProperty for window of type type //! @param atom Atom to get property for. //! @return AutoProperty on success, else 0. AutoProperty* AutoProperties::findWindowTypeProperty(AtomName atom) { AutoProperty *prop = 0; map::iterator it(_window_type_prop_map.find(atom)); if (it != _window_type_prop_map.end()) { prop = it->second; } return prop; } //! @brief Removes all ApplyOnStart actions as they consume memory void AutoProperties::removeApplyOnStart(void) { vector::iterator it(_prop_list.begin()); for (; it != _prop_list.end(); ++it) { if ((*it)->isApplyOn(APPLY_ON_START)) { (*it)->applyRemove(APPLY_ON_START); if (! (*it)->getApplyOn()) { delete *it; it = _prop_list.erase(it); --it; // compensate for the ++ in the loop } } } _apply_on_start = false; } //! @brief Tries to match a class hint against an autoproperty data entry bool AutoProperties::matchAutoClass(const ClassHint &hint, Property *prop) { bool ok = false; if ((prop->getHintName() == hint.h_name) && (prop->getHintClass() == hint.h_class)) { ok = true; if (prop->getTitle ().is_match_ok ()) { ok = (prop->getTitle () == hint.title); } if (ok && prop->getRole ().is_match_ok ()) { ok = (prop->getRole () == hint.h_role); } } return ok; } pekwm-release-0.1.18/src/AutoProperties.hh000066400000000000000000000202141374756504400204550ustar00rootroot00000000000000// // AutoProperties.hh for pekwm // Copyright © 2003-2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifndef _AUTOPROPERTIES_HH_ #define _AUTOPROPERTIES_HH_ #include "config.h" #include "pekwm.hh" #include "CfgParser.hh" #include "RegexString.hh" #include "ParseUtil.hh" #include /** * Bitmask with different auto property types, used to identify what * properties has been set in Property. */ enum PropertyType { AP_STICKY = (1L << 1), AP_SHADED = (1L << 2), AP_MAXIMIZED_VERTICAL = (1L << 3), AP_MAXIMIZED_HORIZONTAL = (1L << 4), AP_ICONIFIED = (1L << 5), AP_BORDER = (1L << 6), AP_TITLEBAR = (1L << 7), AP_FRAME_GEOMETRY = (1L << 8), AP_CLIENT_GEOMETRY = (1L << 9), AP_LAYER = (1L << 10), AP_WORKSPACE = (1L << 11), AP_SKIP = (1L << 12), AP_FULLSCREEN = (1L << 13), AP_PLACE_NEW = (1L << 14), AP_FOCUS_NEW = (1L << 15), AP_FOCUSABLE = (1L << 16), AP_CFG_DENY = (1L << 17), AP_ALLOWED_ACTIONS = (1L << 18), AP_DISALLOWED_ACTIONS = (1L << 19), AP_OPACITY = (1L << 20), AP_DECOR = (1L << 21), AP_GROUP_SIZE, AP_GROUP_BEHIND, AP_GROUP_FOCUSED_FIRST, AP_GROUP_GLOBAL, AP_GROUP_RAISE, AP_PROPERTY, AP_NO_PROPERTY }; /** * ClassHint holds information from a window required to identify it. */ class ClassHint { public: ClassHint(void) { } ClassHint(const std::wstring &n_h_name, const std::wstring &n_h_class, const std::wstring &n_h_role, const std::wstring &n_title, const std::wstring &n_group) : h_name(n_h_name), h_class(n_h_class), h_role(n_h_role), title(n_title), group(n_group) { } ~ClassHint(void) { } inline ClassHint& operator = (const ClassHint& rhs) { h_name = rhs.h_name; h_class = rhs.h_class; h_role = rhs.h_role; title = rhs.title; group = rhs.group; return *this; } inline bool operator == (const ClassHint& rhs) const { if (group.size() > 0) { if (group == rhs.group) { return true; } } else if ((h_name == rhs.h_name) && (h_class == rhs.h_class) && (h_role == rhs.h_role)) { return true; } return false; } public: std::wstring h_name; /**< name part of WM_CLASS hint. */ std::wstring h_class; /**< class part of WM_CLASS hint. */ std::wstring h_role; /**< WM_ROLE hint value. */ std::wstring title; /**< Title of window. */ std::wstring group; /**< Group window belongs to. */ }; /** * Base class for auto properties, includes base matching information. */ class Property { public: Property(void) : _apply_mask(0) { } virtual ~Property(void) { } inline RegexString& getHintName(void) { return _hint_name; } inline RegexString& getHintClass(void) { return _hint_class; } inline RegexString& getRole(void) { return _role; } inline RegexString& getTitle(void) { return _title; } inline uint getApplyOn(void) const { return _apply_mask; } inline bool isApplyOn(uint mask) const { return (_apply_mask&mask); } inline void applyAdd(uint mask) { _apply_mask |= mask; } inline void applyRemove(uint mask) { _apply_mask &= ~mask; } inline void setWorkspaces(const vector &ws) { _workspaces=ws; } inline bool applyOnWs(uint ws) { vector::const_iterator it(find(_workspaces.begin(), _workspaces.end(), ws)); return _workspaces.empty() || it != _workspaces.end(); } private: RegexString _hint_name, _hint_class; RegexString _role, _title; uint _apply_mask; vector _workspaces; }; // AutoProperty for everything except title rewriting class AutoProperty : public Property { public: AutoProperty(void) : skip(SKIP_NONE), cfg_deny(0), group_size(-1), group_behind(false), group_focused_first(false), group_global(false), group_raise(false), _prop_mask(0) { } virtual ~AutoProperty(void) { } inline bool isMask(uint mask) { return (_prop_mask&mask); } inline void maskAdd(uint mask) { _prop_mask |= mask; } inline void maskRemove(uint mask) { _prop_mask &= ~mask; } public: Geometry frame_gm, client_gm; int frame_gm_mask, client_gm_mask; bool sticky, shaded, iconified; bool maximized_vertical, maximized_horizontal, fullscreen; bool border, titlebar; bool focusable, place_new, focus_new; uint workspace, skip, cfg_deny; Layer layer; uint focus_opacity, unfocus_opacity; uint allowed_actions, disallowed_actions; std::string frame_decor; // grouping variables int group_size; std::wstring group_name; bool group_behind, group_focused_first, group_global, group_raise; private: uint _prop_mask; }; // TitleProperty for title rewriting class TitleProperty : public Property { public: TitleProperty(void) { } virtual ~TitleProperty(void) { } RegexString& getTitleRule(void) { return _title_rule; } private: RegexString _title_rule; }; // DecorProperty for multiple decor types class DecorProperty : public Property { public: DecorProperty(void) { } virtual ~DecorProperty(void) { } inline const std::string &getName(void) const { return _decor_name; } inline void setName(const std::string &name) { _decor_name = name; } private: std::string _decor_name; }; // DockApp for Harbour sorting class DockAppProperty : public Property { public: DockAppProperty(void) : _position(0) { } virtual ~DockAppProperty(void) { } inline int getPosition(void) const { return _position; } inline void setPosition(int position) { _position = position; } private: int _position; }; class AutoProperties { public: AutoProperties(void); ~AutoProperties(void); static inline AutoProperties *instance(void) { return _instance; } AutoProperty* findAutoProperty(const ClassHint* class_hintbb, int ws = -1, ApplyOn type = APPLY_ON_ALWAYS); TitleProperty* findTitleProperty(const ClassHint* class_hint); DecorProperty* findDecorProperty(const ClassHint* class_hint); DockAppProperty* findDockAppProperty(const ClassHint *class_hint); inline bool isHarbourSort(void) const { return _harbour_sort; } AutoProperty *findWindowTypeProperty(AtomName atom); bool load(void); void unload(void); void removeApplyOnStart(void); static bool matchAutoClass(const ClassHint &hint, Property *prop); private: Property* findProperty(const ClassHint* class_hint, vector* prop_list, uint ws, ApplyOn type); void loadRequire(CfgParser &a_cfg, std::string &file); bool parsePropertyMatch(const std::string &str, Property *prop); void parsePropertyApplyOn(const std::string &apply_on, Property *prop); bool parseRegexpOrWarning(RegexString ®ex, const std::string regex_str, const std::string &name); bool parseProperty(CfgParser::Entry *section, Property *prop); void parseAutoProperty(CfgParser::Entry *section, vector *ws); void parseAutoGroup(CfgParser::Entry *section, AutoProperty* prop); void parseTitleProperty(CfgParser::Entry *section); void parseDecorProperty(CfgParser::Entry *section); void parseAutoPropertyValue(CfgParser::Entry *section, AutoProperty *prop, vector *ws); void parseDockAppProperty(CfgParser::Entry *section); void parseTypeProperty(CfgParser::Entry *section); void setDefaultTypeProperties(void); TimeFiles _cfg_files; bool _extended; /**< Extended syntax enabled for autoproperties? */ std::map _window_type_prop_map; vector _prop_list; vector _title_prop_list; vector _decor_prop_list; vector _dock_app_prop_list; bool _harbour_sort; bool _apply_on_start; std::map _apply_on_map; std::map _property_map; std::map _group_property_map; std::map _window_type_map; static AutoProperties *_instance; }; #endif // _AUTOPROPS_HH_ pekwm-release-0.1.18/src/CMakeLists.txt000066400000000000000000000055311374756504400177140ustar00rootroot00000000000000cmake_minimum_required(VERSION 2.8) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) configure_file(${CMAKE_SOURCE_DIR}/CMake/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h) set(pekwm_SOURCES ActionHandler.cc ActionMenu.cc AutoProperties.cc CfgParser.cc CfgParserKey.cc CfgParserSource.cc Compat.cc Completer.cc Client.cc CmdDialog.cc Config.cc DockApp.cc Frame.cc FontHandler.cc FrameListMenu.cc Harbour.cc ImageHandler.cc InputDialog.cc KeyGrabber.cc LayouterTiling.cc ManagerWindows.cc MenuHandler.cc Observable.cc PDecor.cc PFont.cc PMenu.cc PTexturePlain.cc PWinObj.cc PWinObjReference.cc PImage.cc PImageIcon.cc RegexString.cc StatusWindow.cc SearchDialog.cc Theme.cc TextureHandler.cc Util.cc WORefMenu.cc WindowManager.cc WinLayouter.cc Workspaces.cc WorkspaceIndicator.cc x11.cc main.cc) set(pekwm_INCLUDE_DIRS ${PROJECT_BINARY_DIR}/src ${ICONV_INCLUDE_DIR} ${X11_INCLUDE_DIR}) set(pekwm_LIBRARIES ${ICONV_LIBRARIES} ${X11_LIBRARIES}) if (DEBUG) set(pekwm_SOURCES ${pekwm_SOURCES} Debug.cc) endif (DEBUG) if (X11_Xshape_FOUND) set(pekwm_INCLUDE_DIRS ${pekwm_INCLUDE_DIRS} ${X11_Xshape_INCLUDE_PATH}) set(pekwm_LIBRARIES ${pekwm_LIBRARIES} ${X11_Xshape_LIB}) endif (X11_Xshape_FOUND) if (X11_Xinerama_FOUND) set(pekwm_INCLUDE_DIRS ${pekwm_INCLUDE_DIRS} ${X11_Xinerama_INCLUDE_PATH}) set(pekwm_LIBRARIES ${pekwm_LIBRARIES} ${X11_Xinerama_LIB}) endif (X11_Xinerama_FOUND) if (X11_Xft_FOUND AND FREETYPE_FOUND) set(pekwm_INCLUDE_DIRS ${pekwm_INCLUDE_DIRS} ${X11_Xft_INCLUDE_PATH} ${FREETYPE_INCLUDE_DIRS}) set(pekwm_LIBRARIES ${pekwm_LIBRARIES} ${X11_Xft_LIB} ${FREETYPE_LIBRARIES}) endif (X11_Xft_FOUND AND FREETYPE_FOUND) if (JPEG_FOUND) set(pekwm_SOURCES ${pekwm_SOURCES} PImageLoaderJpeg.cc) set(pekwm_INCLUDE_DIRS ${pekwm_INCLUDE_DIRS} ${JPEG_INCLUDE_DIR}) set(pekwm_LIBRARIES ${pekwm_LIBRARIES} ${JPEG_LIBRARY}) endif (JPEG_FOUND) if (PNG_FOUND) set(pekwm_SOURCES ${pekwm_SOURCES} PImageLoaderPng.cc) set(pekwm_INCLUDE_DIRS ${pekwm_INCLUDE_DIRS} ${PNG_INCLUDE_DIR}) set(pekwm_LIBRARIES ${pekwm_LIBRARIES} ${PNG_LIBRARY_RELEASE}) endif (PNG_FOUND) if (X11_Xpm_FOUND) set(pekwm_SOURCES ${pekwm_SOURCES} PImageLoaderXpm.cc) set(pekwm_INCLUDE_DIRS ${pekwm_INCLUDE_DIRS} ${X11_Xpm_INCLUDE_PATH}) set(pekwm_LIBRARIES ${pekwm_LIBRARIES} ${X11_Xpm_LIB}) endif (X11_Xpm_FOUND) if (X11_Xrandr_FOUND) set(pekwm_INCLUDE_DIRS ${pekwm_INCLUDE_DIRS} ${X11_Xrandr_INCLUDE_PATH}) set(pekwm_LIBRARIES ${pekwm_LIBRARIES} ${X11_Xrandr_LIB}) endif (X11_Xrandr_FOUND) add_executable(pekwm ${pekwm_SOURCES}) target_include_directories(pekwm PUBLIC ${pekwm_INCLUDE_DIRS}) target_link_libraries(pekwm ${pekwm_LIBRARIES}) # Use when CMake 3.1 is available/required set_target_properties(pekwm PROPERTIES CXX_STANDARD 11 CXX_STANDARD_REQUIRED ON) install(TARGETS pekwm DESTINATION bin) pekwm-release-0.1.18/src/CfgParser.cc000066400000000000000000000526361374756504400173470ustar00rootroot00000000000000// // Copyright © 2005-2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "CfgParser.hh" #include "Debug.hh" #include "Compat.hh" #include "Util.hh" #include #include #include #include #include #include enum { PARSE_BUF_SIZE = 1024 }; using std::cerr; using std::endl; using std::vector; using std::map; using std::set; using std::string; const string CfgParser::_root_source_name = string(""); const char *CP_PARSE_BLANKS = " \t\n"; bool TimeFiles::requireReload(const std::string &file) { // Check for the file, signal reload if not previously loaded. vector::const_iterator it(find(files.begin(), files.end(), file)); if (it == files.end()) { return true; } struct stat stat_buf; // Check state of all files, if one is updated reload. for (it = files.begin(); it != files.end(); ++it) { if (stat((*it).c_str(), &stat_buf)) stat_buf.st_mtime = 0; if (stat_buf.st_mtime > mtime) { if (time(0) > stat_buf.st_mtime) { mtime = stat_buf.st_mtime; } return true; } } return false; } //! @brief CfgParser::Entry constructor. CfgParser::Entry::Entry(const std::string &source_name, int line, const std::string &name, const std::string &value, CfgParser::Entry *section) : _section(section), _name(name), _value(value), _line(line), _source_name(source_name) { } /** * Copy Entry together with the content. */ CfgParser::Entry::Entry(const CfgParser::Entry &entry) : _section(0), _name(entry._name), _value(entry._value), _line(entry._line), _source_name(entry._source_name) { vector::const_iterator it(entry._entries.begin()); for (; it != entry._entries.end(); ++it) { _entries.push_back(new Entry(*(*it))); } if (entry._section) { _section = new Entry(*entry._section); } } //! @brief CfgParser::Entry destructor. CfgParser::Entry::~Entry(void) { for_each(_entries.begin(), _entries.end(), Util::Free()); if (_section) { delete _section; _section = 0; } } /** * Append Entry to the end of Entry list at current depth. */ CfgParser::Entry* CfgParser::Entry::addEntry(CfgParser::Entry *entry, bool overwrite) { CfgParser::Entry *entry_search = 0; if (overwrite) { if (entry->getSection()) { entry_search = findEntry(entry->getName(), true, entry->getSection()->getValue().c_str()); } else { entry_search = findEntry(entry->getName(), false); } } // This is a bit awkward but to keep compatible with old // configuration syntax overwriting of section is only allowed // when the value is the same. if (entry_search && (! entry_search->getSection() || strcasecmp(entry->getValue().c_str(), entry_search->getValue().c_str()) == 0)) { entry_search->_value = entry->getValue(); entry_search->setSection(entry->getSection(), overwrite); // Clear resources used by entry entry->_section = 0; delete entry; entry = entry_search; } else { _entries.push_back(entry); } return entry; } //! @brief Adds Entry to the end of Entry list at current depth. CfgParser::Entry* CfgParser::Entry::addEntry(const std::string &source_name, int line, const std::string &name, const std::string &value, CfgParser::Entry *section, bool overwrite) { return addEntry(new Entry(source_name, line, name, value, section), overwrite); } /** * Set section, copy section entires over if overwrite. */ CfgParser::Entry* CfgParser::Entry::setSection(CfgParser::Entry *section, bool overwrite) { if (_section) { if (overwrite) { _section->copyTreeInto(section, overwrite); delete section; } else { delete _section; _section = section; } } else { _section = section; } return _section; } //! @brief Gets next entry without subsection matching the name name. //! @param name Name of Entry to look for. CfgParser::Entry* CfgParser::Entry::findEntry(const std::string &name, bool include_sections, const char *value) { CfgParser::Entry *value_check; vector::iterator it(_entries.begin()); for (; it != _entries.end(); ++it) { value_check = include_sections ? (*it)->getSection() : (*it); if (*(*it) == name.c_str() && (! (*it)->getSection() || include_sections) && (! value || (value_check && value_check->getValue() == value))) { return *it; } } return 0; } //! @brief Gets the next entry with subsection matchin the name name. //! @param name Name of Entry to look for. CfgParser::Entry* CfgParser::Entry::findSection(const std::string &name, const char *value) { vector::iterator it(_entries.begin()); for (; it != _entries.end(); ++it) { if ((*it)->getSection() && *(*it) == name.c_str() && (! value || (*it)->getSection()->getValue() == value)) { return (*it)->getSection(); } } return 0; } //! @brief Sets and validates data specified by key list. void CfgParser::Entry::parseKeyValues(std::vector::const_iterator it, std::vector::const_iterator end) { CfgParser::Entry *value; for (; it != end; ++it) { value = findEntry((*it)->getName()); if (value) { try { (*it)->parseValue(value->getValue()); } catch (string &ex) { WARN("Exception: " << ex << " - " << *value); } } } } /** Print tree to stderr. */ void CfgParser::Entry::print(uint level) { for (uint i = 0; i < level; ++i) { cerr << " "; } cerr << " * " << getName() << "=" << getValue() << endl; CfgParser::iterator it(begin()); for (; it != end(); ++it) { if ((*it)->getSection()) { (*it)->getSection()->print(level + 1); } else { for (uint i = 0; i < level; ++i) { cerr << " "; } cerr << " - " << getName() << "=" << getValue() << endl; } } } /** * Copy tree into current entry, overwrite entries if overwrite is * true. */ void CfgParser::Entry::copyTreeInto(CfgParser::Entry *from, bool overwrite) { // Copy section if (from->getSection()) { if (_section) { _section->copyTreeInto(from->getSection(), overwrite); } else { _section = new Entry(*(from->getSection())); } } // Copy elements CfgParser::iterator it(from->begin()); for (; it != from->end(); ++it) { CfgParser::Entry *entry_section = 0; if ((*it)->getSection()) { entry_section = new Entry(*((*it)->getSection())); } addEntry((*it)->getSourceName(), (*it)->getLine(), (*it)->getName(), (*it)->getValue(), entry_section, true); } } //! @brief Operator <<, return info on source, line, name and value. std::ostream& operator<<(std::ostream &stream, const CfgParser::Entry &entry) { stream << entry.getSourceName() << "@" << entry.getLine() << " " << entry.getName() << " = " << entry.getValue(); return stream; } //! @brief CfgParser constructor. CfgParser::CfgParser(void) : _source(0), _root_entry(0), _is_dynamic_content(false), _section(_root_entry), _overwrite(false) { _root_entry = new CfgParser::Entry(_root_source_name, 0, "ROOT", ""); _section = _root_entry; } //! @brief CfgParser destructor. CfgParser::~CfgParser(void) { clear(false); } /** * Clear resources used by parser, end up in the same state as in * after construction. * * @param realloc If realloc is false, root_entry will be cleared as well rendering the parser useless. Defaults to true. */ void CfgParser::clear(bool realloc) { _source = 0; delete _root_entry; if (realloc) { _root_entry = new CfgParser::Entry(_root_source_name, 0, "ROOT", ""); } else { _root_entry = 0; } _section = _root_entry; _overwrite = false; // Clear lists _sources.clear(); _source_names.clear(); _source_name_set.clear(); _sections.clear(); _var_map.clear(); // Remove sections map::iterator it(_section_map.begin()); for (; it != _section_map.end(); ++it) { delete it->second; } _section_map.clear(); } /** * Parses source and fills root section with data. * * @param src Source. * @param type Type of source, defaults to file. * @param overwrite Overwrite or append duplicate elements, defaults to false. */ bool CfgParser::parse(const std::string &src, CfgParserSource::Type type, bool overwrite) { // Set overwrite _overwrite = overwrite; // Init parse buffer and reserve memory. string buf, value; buf.reserve(PARSE_BUF_SIZE); // Open initial source. parseSourceNew(src, type); if (_sources.size() == 0) { return false; } int c, next; while (_sources.size()) { _source = _sources.back(); if (_source->isDynamic()) { _is_dynamic_content = true; } while ((c = _source->getc()) != EOF) { switch (c) { case '\n': // To be able to handle entry ends AND { after \n a check // to see what comes after the newline is done. If { appears // we continue as nothing happened else we finish the entry. next = parseSkipBlank(_source); if (next != '{') { parseEntryFinish(buf, value); } break; case ';': parseEntryFinish(buf, value); break; case '{': if (parseName(buf)) { parseSectionFinish(buf, value); } else { LOG("Ignoring section as name is empty."); } buf.clear(); value.clear(); break; case '}': if (_sections.size() > 0) { if (buf.size() && parseName(buf)) { parseEntryFinish(buf, value); buf.clear(); value.clear(); } _section = _sections.back(); _sections.pop_back(); } else { LOG("Extra } character found, ignoring."); } break; case '=': value.clear(); parseValue(value); break; case '#': parseCommentLine(_source); break; case '/': next = _source->getc(); if (next == '/') { parseCommentLine(_source); } else if (next == '*') { parseCommentC(_source); } else { buf += c; _source->ungetc(next); } break; default: buf += c; break; } } try { _source->close(); } catch (string &ex) { LOG("Exception: " << ex); } delete _source; _sources.pop_back(); _source_names.pop_back(); } if (buf.size()) { parseEntryFinish(buf, value); } return true; } //! @brief Creates and opens new CfgParserSource. void CfgParser::parseSourceNew(const std::string &name_orig, CfgParserSource::Type type) { int done = 0; string name(name_orig); do { CfgParserSource *source = sourceNew(name, type); ERR_IF(!source, "source == 0"); // Open and set as active, delete if fails. try { source->open(); time_t time; // Add source to file list if file if (type == CfgParserSource::SOURCE_FILE) { time = Util::getMtime(name); _cfg_files.files.push_back(name); if (_cfg_files.mtime < time) { _cfg_files.mtime = time; } } _source = source; _sources.push_back(_source); done = 1; } catch (string &ex) { delete source; // Previously added in source_new _source_names.pop_back(); // Display error message on second try if (done) { LOG("Exception: " << ex); } // If the open fails and we are trying to open a file, try // to open the file from the current files directory. if (! done && (type == CfgParserSource::SOURCE_FILE)) { if (_source_names.size() && name[0] != '/') { name = Util::getDir(_source_names.back()); name += "/" + name_orig; } } } } while (! done++ && (type == CfgParserSource::SOURCE_FILE)); } //! @brief Parses from beginning to first blank. bool CfgParser::parseName(std::string &buf) { if (! buf.size()) { LOG("Unable to parse empty name."); return false; } // Identify name. string::size_type begin, end; begin = buf.find_first_not_of(CP_PARSE_BLANKS); if (begin == string::npos) { return false; } end = buf.find_first_of(CP_PARSE_BLANKS, begin); // Check if there is any garbage after the value. if (end != string::npos) { if (buf.find_first_not_of(CP_PARSE_BLANKS, end) != string::npos) { // Pass, do notihng } } // Set name. buf = buf.substr(begin, end - begin); return true; } //! @brief Parses _source after = to end of " pair. void CfgParser::parseValue(std::string &value) { // We expect to get a " after the =, however we ignore anything else. int c; while ((c = _source->getc()) != EOF && c != '"') ; // Check if we got EOF before getting a quotation mark. if (c == EOF) { LOG("Reached EOF before opening \" in value."); return; } // Parse until next ", and escape characters after \. while ((c = _source->getc()) != EOF && c != '"') { // Escape character after \, if newline drop it. if (c == '\\') { c = _source->getc(); if (c == '\n' || c == EOF) { continue; } } value += c; } LOG_IF(c == EOF, "Reached EOF before closing \" in value."); // If the value is empty, parseEntryFinish() might later just skip // the complete entry. To allow empty config options we add a dummy space. if (!value.size()) { value = " "; } } //! @brief Parses entry (name + value) and executes command accordingly. void CfgParser::parseEntryFinish(std::string &buf, std::string &value) { if (value.size()) { parseEntryFinishStandard(buf, value); } else { // Template handling, expand or define template. if (buf.size() && parseName(buf) && buf[0] == '@') { parseEntryFinishTemplate(buf); } buf.clear(); } } /** * Finish standard entry. */ void CfgParser::parseEntryFinishStandard(std::string &buf, std::string &value) { if (parseName(buf)) { if (buf[0] == '$') { variableDefine(buf, value); } else { variableExpand(value); if (buf == "INCLUDE") { parseSourceNew(value, CfgParserSource::SOURCE_FILE); } else if (buf == "COMMAND") { parseSourceNew(value, CfgParserSource::SOURCE_COMMAND); } else { _section->addEntry(_source->getName(), _source->getLine(), buf, value, 0, _overwrite); } } } else { LOG("Dropping entry with empty name."); } value.clear(); buf.clear(); } /** * Finish template entry, copy data into current section. */ void CfgParser::parseEntryFinishTemplate(std::string &name) { map::iterator it(_section_map.find(name.c_str() + 1)); if (it == _section_map.end()) { WARN("No such template " << name); return; } _section->copyTreeInto(it->second); } //! @brief Creates new Section on { void CfgParser::parseSectionFinish(std::string &buf, std::string &value) { // Create Entry representing Section Entry *section = 0; if (buf.size() == 6 && strcasecmp(buf.c_str(), "DEFINE") == 0) { // Look for define section, started with Define = "Name" { map::iterator it(_section_map.find(value)); if (it != _section_map.end()) { delete it->second; _section_map.erase(it); } section = new Entry(_source->getName(), _source->getLine(), buf, value); _section_map[value] = section; } else { // Create Entry for sub-section. section = new Entry(_source->getName(), _source->getLine(), buf, value); // Add parent section, get section from parent section as it // can be different from the newly created if it is not // overwritten. CfgParser::Entry *parent = _section->addEntry(_source->getName(), _source->getLine(), buf, value, section, _overwrite); section = parent->getSection(); } // Set current Entry to newly created Section. _sections.push_back(_section); _section = section; } //! @brief Parses Source until end of line discarding input. void CfgParser::parseCommentLine(CfgParserSource *source) { int c; while (((c = source->getc()) != EOF) && (c != '\n')) ; // Give back the newline, needed for flushing value before comment if (c == '\n') { source->ungetc(c); } } //! @brief Parses Source until */ is found. void CfgParser::parseCommentC(CfgParserSource *source) { int c; while ((c = source->getc()) != EOF) { if (c == '*') { if ((c = source->getc()) == '/') { break; } else if (c != EOF) { source->ungetc(c); } } } LOG_IF(c == EOF, "Reached EOF before closing */ in comment."); } //! @brief Parses Source until next non whitespace char is found. char CfgParser::parseSkipBlank(CfgParserSource *source) { int c; while (((c = source->getc()) != EOF) && isspace(c)) ; if (c != EOF) { source->ungetc(c); } return c; } //! @brief Creates a CfgParserSource of type type. CfgParserSource* CfgParser::sourceNew(const std::string &name, CfgParserSource::Type type) { CfgParserSource *source = 0; // Create CfgParserSource. _source_names.push_back(name); _source_name_set.insert(name); switch (type) { case CfgParserSource::SOURCE_FILE: source = new CfgParserSourceFile(*_source_name_set.find(name)); break; case CfgParserSource::SOURCE_COMMAND: source = new CfgParserSourceCommand(*_source_name_set.find(name)); break; default: break; } return source; } //! @brief Defines a variable in the _var_map/setenv. void CfgParser::variableDefine(const std::string &name, const std::string &value) { _var_map[name] = value; // If the variable begins with $_ it should update the environment aswell. if ((name.size() > 2) && (name[1] == '_')) { setenv(name.c_str() + 2, value.c_str(), 1); } } //! @brief Expands all $ variables in a string. void CfgParser::variableExpand(std::string &var) { bool did_expand; do { did_expand = false; string::size_type begin = 0, end = 0; while ((begin = var.find_first_of('$', end)) != string::npos) { end = begin + 1; // Skip escaped \$ if ((begin > 0) && (var[begin - 1] == '\\')) { continue; } // Find end of variable for (; end != var.size(); ++end) { if ((isalnum(var[end]) == 0) && (var[end] != '_')) { break; } } did_expand = variableExpandName(var, begin, end) || did_expand; } } while (did_expand); } bool CfgParser::variableExpandName(std::string &var, string::size_type begin, string::size_type &end) { bool did_expand = false; string var_name(var.substr(begin, end - begin)); // If the variable starts with _ it is considered an environment // variable, use getenv to see if it is available if (var_name.size() > 2 && var_name[1] == '_') { char *value = getenv(var_name.c_str() + 2); if (value) { var.replace(begin, end - begin, value); end = begin + strlen(value); did_expand = true; } else { LOG("Trying to use undefined environment variable: " << var_name); } } else { map::iterator it(_var_map.find(var_name)); if (it != _var_map.end()) { var.replace(begin, end - begin, it->second); end = begin + it->second.size(); did_expand = true; } else { LOG("Trying to use undefined variable: " << var_name); } } return did_expand; } pekwm-release-0.1.18/src/CfgParser.hh000066400000000000000000000133151374756504400173500ustar00rootroot00000000000000// // Copyright © 2005-2009 Claes Nasten // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // // // Configuration file parser with file inclusion support and command // output parsing support. The format being parsed: // // $var = "value" // INCLUDE = "file to include" // // section = "name" { // key = "name" { // value = "$var" // } // } // #ifndef _CFG_PARSER_HH_ #define _CFG_PARSER_HH_ #include "config.h" #include "CfgParserKey.hh" #include "CfgParserSource.hh" #include #include #include #include #include #include #include //! @brief Helper class class TimeFiles { public: TimeFiles() : mtime(0) {} time_t mtime; std::vector files; bool requireReload(const std::string &file); void clear() { files.clear(); mtime = 0; } }; //! @brief Configuration file parser. class CfgParser { public: //! @brief Entry in parsed data structure. class Entry { public: Entry(const std::string &source_name, int line, const std::string &name, const std::string &value, CfgParser::Entry *section=0); Entry(const Entry &entry); ~Entry(void); vector::const_iterator begin(void) { return _entries.begin(); } vector::const_iterator end(void) { return _entries.end(); } //! @brief Returns the name. const std::string &getName(void) const { return _name; } //! @brief Returns the value. const std::string &getValue(void) const { return _value; } //! @brief Returns the linenumber in the source this was parsed. int getLine(void) const { return _line; } //! @brief Returns the name of the source this was parsed. const std::string &getSourceName(void) const { return _source_name; } Entry *addEntry(Entry *entry, bool overwrite=false); Entry *addEntry(const std::string &source_name, int line, const std::string &name, const std::string &value, CfgParser::Entry *section=0, bool overwrite=false); //! @brief Returns the sub section. Entry *getSection(void) { return _section; } Entry *setSection(Entry *section, bool overwrite=false); Entry *findEntry(const std::string &name, bool include_sections=false, const char *value=0); Entry *findSection(const std::string &name, const char *value=0); void parseKeyValues(vector::const_iterator begin, vector::const_iterator end); void print(uint level = 0); void copyTreeInto(CfgParser::Entry *from, bool overwrite=false); //! @brief Matches Entry name agains op_rhs. bool operator==(const char *rhs) { return (strcasecmp(rhs, _name.c_str()) == 0); } friend std::ostream &operator<<(std::ostream &stream, const CfgParser::Entry &entry); private: vector _entries; /**< List of entries in section. */ Entry *_section; /**< Sub-section of node. */ std::string _name; /**< Name of node. */ std::string _value; /**< Value of node. */ int _line; const std::string &_source_name; }; typedef std::vector::const_iterator iterator; CfgParser(void); ~CfgParser(void); TimeFiles getCfgFiles(void) const { return _cfg_files; } //! @brief Returns the root Entry node. Entry *getEntryRoot(void) { return _root_entry; } /** Return true if data parsed included dynamic content such as from COMMAND. */ bool isDynamicContent(void) { return _is_dynamic_content; } void clear(bool realloc = true); bool parse(const std::string &src, CfgParserSource::Type type = CfgParserSource::SOURCE_FILE, bool overwrite = false); private: void parseSourceNew(const std::string &name, CfgParserSource::Type type); bool parseName(std::string &buf); void parseValue(std::string &value); void parseEntryFinish(std::string &buf, std::string &value); void parseEntryFinishStandard(std::string &buf, std::string &value); void parseEntryFinishTemplate(std::string &name); void parseSectionFinish(std::string &buf, std::string &value); void parseCommentLine(CfgParserSource *source); void parseCommentC(CfgParserSource *source); char parseSkipBlank(CfgParserSource *source); CfgParserSource *sourceNew(const std::string &name, CfgParserSource::Type type); void variableDefine(const std::string &name, const std::string &value); void variableExpand(std::string &var); bool variableExpandName(std::string &var, std::string::size_type begin, std::string::size_type &end); CfgParserSource *_source; TimeFiles _cfg_files; vector _sources; //!< Vector of sources, for recursive parsing. vector _source_names; //!< Vector of source names, to keep track of current source. std::set _source_name_set; //!< Set of source names, source of memory usage on long-going CfgParser objects. vector _sections; //!< for recursive parsing. std::map _var_map; //!< Map of $VARS std::map _section_map; //!< Map of Define = ... sections Entry *_root_entry; /**< Root Entry. */ bool _is_dynamic_content; /**< If true, parsed data included command or similar. */ Entry *_section; /**< Current section. */ bool _overwrite; /**< Overwrite elements when appending. */ static const std::string _root_source_name; //!< Root Entry Source Name. }; #endif // _CFG_PARSER_HH_ pekwm-release-0.1.18/src/CfgParserKey.cc000066400000000000000000000032621374756504400200070ustar00rootroot00000000000000// // Copyright © 2005-2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "CfgParserKey.hh" #include "Util.hh" #include #include using std::string; using std::cerr; using std::endl; using std::numeric_limits; //! @brief Parses value and sets _br_set. //! Boolean true is represented either by case insensitive true or 1. //! Boolean false is represented either by case insensitive false or 0. //! @param value Value to parse. //! @return true on success, else false and _br_set set to _b_default. void CfgParserKeyBool::parseValue(const std::string &value) { if ((value == "1") || ! strcasecmp(value.c_str(), "TRUE")) { _set = true; } else if ((value == "0") || ! strcasecmp(value.c_str(), "FALSE")) { _set = false; } else { _set = _default; throw string("not bool value"); } } //! @brief Parses value and sets _set. //! @param value Value to parse. //! @return true on success, else false and _set set to _default. void CfgParserKeyString::parseValue(const std::string &value) { if (value.size() < _length_min) { throw string("string too short, min length " + Util::to_string(_length_min)); } _set = value; } //! @brief Parses value and sets _set. //! @param value Value to parse. //! @return true on success, else false and _set set to _default. void CfgParserKeyPath::parseValue(const std::string &value) { if (value.size()) { _set = value; Util::expandFileName(_set); } else { _set = _default; throw string("path too short"); } } pekwm-release-0.1.18/src/CfgParserKey.hh000066400000000000000000000117441374756504400200250ustar00rootroot00000000000000// // Copyright © 2005-2013 the pekwm development team // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifndef _CFG_PARSER_KEY_HH_ #define _CFG_PARSER_KEY_HH_ #include #include #include #include "Util.hh" //! @brief CfgParserKey base class. class CfgParserKey { public: //! @brief CfgParserKey constructor. CfgParserKey(const char *name) : _name(name) { } //! @brief CfgParserKey destructor. virtual ~CfgParserKey(void) { } //! @brief Returns Key name. const char *getName(void) const { return _name; } //! @brief Parses value and sets Key value. virtual void parseValue(const std::string &) { } protected: const char *_name; //!< Key name. }; /** * CfgParserKey numeric type with minimum, maximum and default * value. The type must be available in numeric_limits. */ template class CfgParserKeyNumeric : public CfgParserKey { public: /** * CfgParserKeyNumeric constructor, sets default values * * @param name Name of the key. * @param set Variable to store parsed value in. * @param default_val Default value for key, defaults to 0. * @param value_min Minimum value for key, defaults to limits::min(). * @param value_min Maximum value for key, defaults to limits::max(). */ CfgParserKeyNumeric(const char *name, T &set, const T default_val = 0, const T value_min = std::numeric_limits::min(), const T value_max = std::numeric_limits::max()) : CfgParserKey(name), _set(set), _default(default_val), _value_min(value_min), _value_max(value_max) { } /** * CfgParserKeyNumeric destructor. */ virtual ~CfgParserKeyNumeric(void) { } /** * Parses and store integer value. * * @param value Reference to string representing integer value. */ virtual void parseValue(const std::string &value_str) { double value; char *endptr; // Get long value. value = strtod(value_str.c_str(), &endptr); // Check for validity, 0 is returned on failiure with endptr set to the // beginning of the string, else we are (semi) ok. if ((value == 0) && (endptr == value_str.c_str())) { _set = _default; } else { T value_for_type = static_cast(value); if (value_for_type < _value_min) { _set = _value_min; throw std::string("value to low, min value " + Util::to_string(_value_min)); } if (value_for_type > _value_max) { _set = _value_max; throw std::string("value to high, max value " + Util::to_string(_value_max)); } _set = value_for_type; } } private: T &_set; /**< Reference to store parsed value in. */ const T _default; /**< Default value. */ const T _value_min; /**< Minimum value. */ const T _value_max; /**< Maximum value. */ }; //! @brief CfgParser Key boolean value parser. class CfgParserKeyBool : public CfgParserKey { public: //! @brief CfgParserKeyBool constructor. CfgParserKeyBool(const char *name, bool &set, const bool default_val = false) : CfgParserKey(name), _set(set), _default(default_val) { } //! @brief CfgParserKeyBool destructor. virtual ~CfgParserKeyBool(void) { } virtual void parseValue(const std::string &value); private: bool &_set; //! Reference to stored parsed value in. const bool _default; //! Default value. }; //! @brief CfgParser Key string value parser. class CfgParserKeyString : public CfgParserKey { public: //! @brief CfgParserKeyString constructor. CfgParserKeyString(const char *name, std::string &set, const std::string default_val = "", const std::string::size_type length_min = 0) : CfgParserKey(name), _set(set), _length_min(length_min) { _set = default_val; } //! @brief CfgParserKeyString destructor. virtual ~CfgParserKeyString(void) { } virtual void parseValue(const std::string &value); private: std::string &_set; //!< Reference to store parsed value in. const std::string::size_type _length_min; //!< Minimum length of string. }; //! @brief CfgParser Key path parser. class CfgParserKeyPath : public CfgParserKey { public: //! @brief CfgParserKeyPath constructor. CfgParserKeyPath(const char *name, std::string &set, const std::string default_val = "") : CfgParserKey(name), _set(set), _default(default_val) { Util::expandFileName(_default); } //! @brief CfgParserKeyPath destructor. virtual ~CfgParserKeyPath(void) { } virtual void parseValue(const std::string &value); private: std::string &_set; //!< Reference to store parsed value in. std::string _default; //!< Default value. }; #endif // _CFG_PARSER_KEY_HH_ pekwm-release-0.1.18/src/CfgParserSource.cc000066400000000000000000000051101374756504400205110ustar00rootroot00000000000000// // Copyright © 2005-2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "config.h" #include "CfgParserSource.hh" #include "Util.hh" #include #include #include extern "C" { #include #include } using std::cerr; using std::endl; using std::string; using std::fopen; using std::fclose; using std::exit; unsigned int CfgParserSourceCommand::_sigaction_counter = 0; /** * Open file based configuration source. */ bool CfgParserSourceFile::open(void) { if (_file) { throw string("TRYING TO OPEN ALREADY OPEN SOURCE"); } _file = fopen(_name.c_str(), "r"); if (! _file) { throw string("failed to open file " + _name); } return true; } void CfgParserSourceFile::close(void) { if (! _file) { throw string("trying to close already closed source"); } fclose(_file); _file = 0; } /** * Run command and treat output as configuration source. */ bool CfgParserSourceCommand::open(void) { int fd[2]; int status; status = pipe(fd); if (status == -1) { return false; } // Remove signal handler while parsing as otherwise reading from the // pipe will break sometimes. if (_sigaction_counter++ == 0) { struct sigaction action; action.sa_handler = SIG_DFL; action.sa_mask = sigset_t(); action.sa_flags = 0; sigaction(SIGCHLD, &action, &_sigaction); } _pid = fork(); if (_pid == -1) { // Error return false; } else if (_pid == 0) { // Child dup2(fd[1], STDOUT_FILENO); ::close(fd[0]); ::close(fd[1]); execlp("/bin/sh", "sh", "-c", _name.c_str(), (char *) 0); // PRINT ERROR ::close (STDOUT_FILENO); exit (1); } else { // Parent ::close (fd[1]); _file = ::fdopen(fd[0], "r"); } return true; } /** * Close source, wait for child process to finish. */ void CfgParserSourceCommand::close(void) { if (_sigaction_counter < 1) { return; } _sigaction_counter--; // Close source. fclose(_file); // Wait for process. int status; int pid_status; status = waitpid(_pid, &pid_status, 0); // If no other open CfgParserSourceCommand open, restore sigaction. if (_sigaction_counter == 0) { sigaction(SIGCHLD, &_sigaction, 0); } // Wait failed, throw error if (status == -1) { throw string("failed to wait for pid " + Util::to_string(_pid)); } } pekwm-release-0.1.18/src/CfgParserSource.hh000066400000000000000000000062721374756504400205350ustar00rootroot00000000000000// // Copyright © 2005-2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifndef _CFG_PARSER_SOURCE_HH_ #define _CFG_PARSER_SOURCE_HH_ #include #include extern "C" { #include #include #include } /** * Base class for configuration sources defining the interface and * common methods. */ class CfgParserSource { public: /** * Source type description. */ enum Type { SOURCE_FILE, /**< Source from filesystem accesible file. */ SOURCE_COMMAND, /**< Source from command output. */ SOURCE_VIRTUAL /**< Source base type. */ }; /** * CfgParserSource constructor, just set default values. */ CfgParserSource(const std::string &source) : _file(0), _name(source), _type(SOURCE_VIRTUAL), _line(0), _is_dynamic(false) { } virtual ~CfgParserSource (void) { } /** * Gets a character from _file, increments line count if \n. */ inline int getc(void) { int c = std::fgetc(_file); if (c == '\n') { ++_line; } return c; } /** * Returns a character to _op_file, decrements line count if \n. */ inline void ungetc(int c) { std::ungetc(c, _file); if (c == '\n') { --_line; } } /**< Return name of source. */ const std::string &getName(void) const { return _name; } /**< return type of source. */ CfgParserSource::Type getType(void) const { return _type; } /**< Get current line from source. */ unsigned int getLine(void) const { return _line; } /**< Return true if current source is dynamic. */ bool isDynamic(void) const { return _is_dynamic; } virtual bool open(void) { return false; } virtual void close(void) { } protected: std::FILE *_file; /**< FILE object source is reading from. */ const std::string &_name; /**< Name of source. */ CfgParserSource::Type _type; /**< Type of source. */ unsigned int _line; /**< Line number. */ bool _is_dynamic; /**< Set to true if source has dynamic content. */ }; /** * File based configuration source, reads data from a plain file on * disk. */ class CfgParserSourceFile : public CfgParserSource { public: CfgParserSourceFile (const std::string &source) : CfgParserSource(source) { _type = SOURCE_FILE; } virtual ~CfgParserSourceFile (void) { } virtual bool open(void); virtual void close(void); }; /** * Command based configuration source, executes a commands and parses * the output. */ class CfgParserSourceCommand : public CfgParserSource { public: CfgParserSourceCommand(const std::string &source) : CfgParserSource (source) { _type = SOURCE_COMMAND; _is_dynamic = true; } virtual ~CfgParserSourceCommand(void) { } virtual bool open(void); virtual void close(void); private: pid_t _pid; /**< Process id of command generating output. */ struct sigaction _sigaction; /**< sigaction for restore. */ static unsigned int _sigaction_counter; /**< Counts open. */ }; #endif // _CFG_PARSER_SOURCE_HH_ pekwm-release-0.1.18/src/Client.cc000066400000000000000000001516651374756504400167130ustar00rootroot00000000000000// // Client.cc for pekwm // Copyright © 2002-2013 Claes Nästén // // client.cc for aewm++ // Copyright (C) 2000 Frank Hale // http://sapphire.sourceforge.net/ // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "config.h" #include #include #include extern "C" { #include #include #include #ifdef HAVE_SHAPE #include #endif // HAVE_SHAPE } #include "Compat.hh" // setenv, unsetenv #include "Debug.hh" #include "PWinObj.hh" #include "PDecor.hh" // PDecor::TitleItem #include "Client.hh" #include "x11.hh" #include "Config.hh" #include "KeyGrabber.hh" #include "Theme.hh" #include "AutoProperties.hh" #include "Frame.hh" #include "Workspaces.hh" #include "WindowManager.hh" #include "PTexturePlain.hh" #include "PImageIcon.hh" #include "TextureHandler.hh" #include "PMenu.hh" #include "WORefMenu.hh" using std::cerr; using std::endl; using std::find; using std::string; using std::vector; using std::wstring; const long Client::_clientEventMask = \ PropertyChangeMask|StructureNotifyMask|FocusChangeMask|KeyPressMask; vector Client::_clients; vector Client::_clientids; Client::Client(Window new_client, ClientInitConfig &initConfig, bool is_new) : PWinObj(true), _id(0), _size(0), _transient_for(0), _strut(0), _icon(0), _pid(0), _is_remote(false), _class_hint(0), _window_type(WINDOW_TYPE_NORMAL), _alive(false), _marked(false), _send_focus_message(false), _send_close_message(false), _wm_hints_input(true), _cfg_request_lock(false), _extended_net_name(false), _demands_attention(false) { // PWinObj attributes, required by validate etc. _window = new_client; _type = WO_CLIENT; // Construct the client X11::grabServer(); if (! validate() || ! getAndUpdateWindowAttributes()) { X11::ungrabServer(true); return; } // Get unique Client id _id = findClientID(); _title.setId(_id); _title.infoAdd(PDecor::TitleItem::INFO_ID); #ifdef HAVE_SHAPE if (X11::hasExtensionShape()) { XShapeSelectInput(X11::getDpy(), _window, ShapeNotifyMask); int isShaped; X11::shapeQuery(_window, &isShaped); _shape_bounding = isShaped; int num=0; int foo; XRectangle *rect = XShapeGetRectangles(X11::getDpy(), _window, ShapeInput, &num, &foo); if (rect) { if (num == 1) { unsigned w, h, bw; X11::getGeometry(_window, &w, &h, &bw); if (rect->x > 0 || rect->y > 0 || rect->width < w+bw || rect->height < h+bw) { _shape_input = true; } } else { _shape_input = true; } XFree(rect); } } #endif // HAVE_SHAPE XAddToSaveSet(X11::getDpy(), _window); XSetWindowBorderWidth(X11::getDpy(), _window, 0); // Load the Class hint before loading the autoprops and // getting client title as we search for TitleRule in the autoprops _class_hint = new ClassHint(); readClassRoleHints(); getWMNormalHints(); readName(); // cyclic dependency, getting the name requires quiering autoprops _class_hint->title = _title.getReal(); // Get Autoproperties before EWMH as we need the cfg_deny // property, however the _transient hint needs to be setup to // avoid auto-grouping to be to greedy. getTransientForHint(); AutoProperty *ap = readAutoprops(WindowManager::instance()->isStartup() ? APPLY_ON_NEW : APPLY_ON_START); readHints(); // We need to set the state before acquiring a frame, // so that Frame's state can match the state of the Client. setInitialState(); initConfig.parent_is_new = findOrCreateFrame(ap); // Grab keybindings and mousebutton actions KeyGrabber::instance()->grabKeys(_window); grabButtons(); // Tell the world about our state updateEwmhStates(); X11::ungrabServer(true); setClientInitConfig(initConfig, is_new, ap); _alive = true; findAndRaiseIfTransient(); // Finished creating the client, so now adding it to the client list. woListAdd(this); _wo_map[_window] = this; _clients.push_back(this); } //! @brief Client destructor Client::~Client(void) { // Remove from lists if (_transient_for) { vector &tc(_transient_for->_transients); tc.erase(std::remove(tc.begin(), tc.end(), this), tc.end()); _transient_for->removeObserver(this); } _wo_map.erase(_window); woListRemove(this); _clients.erase(std::remove(_clients.begin(), _clients.end(), this), _clients.end()); returnClientID(_id); X11::grabServer(); // removes gravity and moves it back to root if we are alive bool focus = false; if (_parent && (_parent->getType() == PWinObj::WO_FRAME)) { focus = _parent->isFocused(); static_cast(_parent)->removeChild(this); } // Focus the parent if we had focus before if (focus && _transient_for) { Frame *trans_frame = static_cast(_transient_for->getParent()); if (trans_frame->getActiveChild() == _transient_for) { trans_frame->giveInputFocus(); } } // Clean up if the client still is alive, it'll be dead all times // except when we exit pekwm if (_alive) { X11::ungrabButton(_window); KeyGrabber::instance()->ungrabKeys(_window); XRemoveFromSaveSet(X11::getDpy(), _window); PWinObj::mapWindow(); } // free names and size hint if (_size) { XFree(_size); } removeStrutHint(); if (_class_hint) { delete _class_hint; } if (_icon) { TextureHandler::instance()->returnTexture(_icon); _icon = 0; } X11::ungrabServer(true); } /** * Read basic window attributes including geometry and update the * window attributes being listened to. Returns false if the client * disappears during the check. */ bool Client::getAndUpdateWindowAttributes(void) { XWindowAttributes attr; if (! XGetWindowAttributes(X11::getDpy(), _window, &attr)) { return false; } _gm.x = attr.x; _gm.y = attr.y; _gm.width = attr.width; _gm.height = attr.height; _cmap = attr.colormap; _size = XAllocSizeHints(); XSetWindowAttributes sattr; sattr.event_mask = PropertyChangeMask|StructureNotifyMask|FocusChangeMask; sattr.do_not_propagate_mask = ButtonPressMask|ButtonReleaseMask|ButtonMotionMask; // We don't want these masks to be propagated down to the frame XChangeWindowAttributes(X11::getDpy(), _window, CWEventMask|CWDontPropagate, &sattr); return true; } /** * Find frame for client based on tagging, hints and * autoproperties. Create a new one if not found and add the client. * * \return true if a new find was created. */ bool Client::findOrCreateFrame(AutoProperty *autoproperty) { bool parent_is_new = false; if (! _parent) { findTaggedFrame(); } if (! _parent) { findPreviousFrame(); } // Apply Autoproperties again to override EWMH state. It's done twice as // we need the cfg_deny property when reading the EWMH state. if (autoproperty != 0) { applyAutoprops(autoproperty); if (! _parent) { findAutoGroupFrame(autoproperty); } } // if we don't have a frame already, create a new one if (! _parent) { parent_is_new = true; _parent = new Frame(this, autoproperty); } return parent_is_new; } /** * Find from client from for the currently tagged client. */ bool Client::findTaggedFrame(void) { if (! WindowManager::instance()->isStartup()) { return false; } // Check for tagged frame Frame *frame = Frame::getTagFrame(); if (frame && frame->isMapped()) { _parent = frame; frame->addChild(this); if (! Frame::getTagBehind()) { frame->activateChild(this); } } return _parent != 0; } /** * Find frame for client on PEKWM_FRAME_ID hint. */ bool Client::findPreviousFrame(void) { if (WindowManager::instance()->isStartup()) { return false; } long id; if (X11::getLong(_window, PEKWM_FRAME_ID, id)) { _parent = Frame::findFrameFromID(id); if (_parent) { Frame *frame = static_cast(_parent); frame->addChildOrdered(this); if (getPekwmFrameActive()) { frame->activateChild(this); } } } return _parent != 0; } /** * Find frame for client based on autoproperties. */ bool Client::findAutoGroupFrame(AutoProperty *autoproperty) { if (autoproperty->group_size < 0) { return false; } Frame* frame = WindowManager::instance()->findGroup(autoproperty); if (frame) { frame->addChild(this); if (! autoproperty->group_behind) { frame->activateChild(this); } if (autoproperty->group_raise) { frame->raise(); } } return _parent != 0; } /** * Get the client state and set iconified and mapped flags. */ void Client::setInitialState(void) { // Set state either specified in hint ulong initial_state = getWMHints(); if (getWmState() == IconicState) { _iconified = true; } if (_iconified || initial_state == IconicState) { _iconified = true; _mapped = true; unmapWindow(); } else { setWmState(initial_state); } } /** * Ensure the Client is (un) mapped and give input focus if requested. */ void Client::setClientInitConfig(ClientInitConfig &initConfig, bool is_new, AutoProperty *autoproperty) { initConfig.map = (! _iconified && _parent->isMapped()); initConfig.focus = false; // Let us hear what autoproperties has to say about focusing bool do_focus = is_new ? Config::instance()->isFocusNew() : false; if (is_new && autoproperty && autoproperty->isMask(AP_FOCUS_NEW)) { do_focus = autoproperty->focus_new; } // Only can give input focus to mapped windows if (_parent->isMapped()) { // Ordinary focus if (do_focus) { initConfig.focus = true; // Check if we are transient, and if we want to focus } else if (_transient_for && _transient_for->isFocused() && Config::instance()->isFocusNewChild()) { initConfig.focus = true; } } } /** * Re-lookup transient client if window is set but not client, raise over * transient for window if found/set. */ void Client::findAndRaiseIfTransient(void) { if (_transient_for_window != None && ! _transient_for) { getTransientForHint(); } if (_transient_for) { // Ensure layer is at least as high as the parent if (_transient_for->getLayer() > getLayer()) { setLayer(_transient_for->getLayer()); updateParentLayerAndRaiseIfActive(); } } } // START - PWinObj interface. //! @brief Maps the window. void Client::mapWindow(void) { if (_mapped) { return; } if (_iconified) { _iconified = false; setWmState(NormalState); updateEwmhStates(); } if(! _transient_for) { // Unmap our transient windows if we have any mapOrUnmapTransients(_window, false); } X11::selectInput(_window, NoEventMask); PWinObj::mapWindow(); X11::selectInput(_window, _clientEventMask); } //! @brief Sets the client to WithdrawnState and unmaps it. void Client::unmapWindow(void) { if (! _mapped) { return; } if (_iconified) { // Set the state of the window setWmState(IconicState); updateEwmhStates(); } X11::selectInput(_window, NoEventMask); PWinObj::unmapWindow(); X11::selectInput(_window, _clientEventMask); } //! @brief Iconifies the client and adds it to the iconmenu void Client::iconify(void) { if (_iconified) { return; } _iconified = true; if (! _transient_for) { mapOrUnmapTransients(_window, true); } unmapWindow(); } //! @brief Toggle client sticky state void Client::stick(void) { PWinObj::stick(); updateEwmhStates(); } //! @brief Update the position variables. void Client::move(int x, int y) { bool request = ((_gm.x != x) || (_gm.y != y)); _gm.x = x; _gm.y = y; if (request) { configureRequestSend(); } } //! @brief Resizes the client window to specified size. void Client::resize(uint width, uint height) { bool request = ((_gm.width != width) || (_gm.height != height)); PWinObj::resize(width, height); if (request) { configureRequestSend(); } } //! @brief Move and resizes the client window to specified size. void Client::moveResize(int x, int y, uint width, uint height) { bool request = ((_gm.x != x) || (_gm.y != y) || (_gm.width != width) || (_gm.height != height)); _gm.x = x; _gm.y = y; PWinObj::resize(width, height); if (request) { configureRequestSend(); } } //! @brief Sets the workspace and updates the _NET_WM_DESKTOP hint. void Client::setWorkspace(uint workspace) { if (workspace != NET_WM_STICKY_WINDOW) { if (workspace >= Workspaces::size()) { workspace = Workspaces::size() - 1; } _workspace = workspace; if (_sticky) { X11::setLong(_window, NET_WM_DESKTOP, NET_WM_STICKY_WINDOW); } else { X11::setLong(_window, NET_WM_DESKTOP, _workspace); } } } //! @brief Gives the Client input focus. void Client::giveInputFocus(void) { Frame *frame; if (demandsAttention() && (frame = static_cast(_parent))) { setDemandsAttention(false); frame->decrAttention(); } if (_wm_hints_input) { PWinObj::giveInputFocus(); } sendTakeFocusMessage(); } //! @brief Reparents and sets _parent member, filtering unmap events void Client::reparent(PWinObj *parent, int x, int y) { X11::selectInput(_window, NoEventMask); PWinObj::reparent(parent, x, y); _gm.x = parent->getX() + x; _gm.y = parent->getY() + y; X11::selectInput(_window, PropertyChangeMask|StructureNotifyMask|FocusChangeMask); } ActionEvent* Client::handleMapRequest(XMapRequestEvent *ev) { if (_parent && dynamic_cast(_parent)) { dynamic_cast(_parent)->deiconify(); } return 0; } ActionEvent* Client::handleUnmapEvent(XUnmapEvent *ev) { if ((ev->window != ev->event) && (ev->send_event != true)) { return 0; } // The window might not exist any more, so just ignore the errors. setXErrorsIgnore(true); // ICCCM 4.1.4 advices the window manager to trigger the transition to // Withdrawn state on real and synthetic UnmapNotify events. setWmState(WithdrawnState); // Extended Window Manager Hints 1.3 specifies that a window manager // should remove the _NET_WM_STATE property when a window is withdrawn. X11::unsetProperty(_window, STATE); // Extended Window Manager Hints 1.3 specifies that a window manager // should remove the _NET_WM_DESKTOP property when a window is withdrawn. // (to allow legacy applications to reuse a withdrawn window) X11::unsetProperty(_window, NET_WM_DESKTOP); // FIXME: Listen mask should change as this doesn't work? _alive = false; delete this; setXErrorsIgnore(false); return 0; } // END - PWinObj interface. #ifdef HAVE_SHAPE void Client::handleShapeEvent(XShapeEvent *ev) { if (ev->kind == ShapeBounding) { _shape_bounding = ev->shaped; } else if (ev->kind == ShapeInput) { _shape_input = ev->shaped; } else { return; } if (_parent) { static_cast(_parent)->handleShapeEvent(ev); } } #endif // HAVE_SHAPE // START - Observer interface void Client::notify(Observable *observable, Observation *observation) { if (observation) { LayerObservation *layer_observation = dynamic_cast(observation); if (layer_observation && layer_observation->layer > getLayer()) { setLayer(layer_observation->layer); updateParentLayerAndRaiseIfActive(); } } else { Client *client = static_cast(observable); if (client == _transient_for) { _transient_for = 0; } else { _transients.erase(std::remove(_transients.begin(), _transients.end(), this), _transients.end()); } } } // END - Observer interface //! @brief Finds the Client which holds the Window w. //! @param win Window to search for. //! @return Pointer to the client if found, else 0 Client* Client::findClient(Window win) { // Validate input window. if ((win == None) || (win == X11::getRoot())) { return 0; } vector::const_iterator it(_clients.begin()); for (; it != _clients.end(); ++it) { if (win == (*it)->getWindow() || ((*it)->getParent() && (*((*it)->getParent()) == win))) { return (*it); } } return 0; } //! @brief Finds the Client of Window win. //! @param win Window to search for. Client* Client::findClientFromWindow(Window win) { // Validate input window. if (! win || win == X11::getRoot()) { return 0; } vector::const_iterator it(_clients.begin()); for(; it != _clients.end(); ++it) { if (win == (*it)->getWindow()) { return (*it); } } return 0; } //! @brief Finds Client with equal ClassHint. //! @param class_hint ClassHint to search for. //! @return Client if found, else 0. Client* Client::findClientFromHint(const ClassHint *class_hint) { vector::const_iterator it(_clients.begin()); for (; it != _clients.end(); ++it) { if (*class_hint == *(*it)->getClassHint()) { return *it; } } return 0; } //! @brief Finds Client with id. //! @param id ID to search for. //! @return Client if found, else 0. Client* Client::findClientFromID(uint id) { vector::const_iterator it(_clients.begin()); for (; it != _clients.end(); ++it) { if ((*it)->getClientID() == id) { return *it; } } return 0; } /** * Insert all clients with the transient for set to win. */ void Client::findFamilyFromWindow(vector &client_list, Window win) { vector::const_iterator it(Client::client_begin()); for (; it != Client::client_end(); ++it) { if ((*it)->getTransientForClientWindow() == win) { client_list.push_back(*it); } } } /** * (Un)Maps all windows having transient_for set to win */ void Client::mapOrUnmapTransients(Window win, bool hide) { vector client_list; findFamilyFromWindow(client_list, win); vector::const_iterator it(client_list.begin()); for (; it != client_list.end(); ++it) { if (static_cast((*it)->getParent())->getActiveChild() == *it) { if (hide) { (*it)->getParent()->iconify(); } else { (*it)->getParent()->mapWindow(); } } } } //! @brief Checks if the window has any Destroy or Unmap notifys. bool Client::validate(void) { XSync(X11::getDpy(), false); XEvent ev; if (XCheckTypedWindowEvent(X11::getDpy(), _window, DestroyNotify, &ev) || XCheckTypedWindowEvent(X11::getDpy(), _window, UnmapNotify, &ev)) { XPutBackEvent(X11::getDpy(), &ev); return false; } return true; } //! @brief Checks if the window has attribute IsViewable set bool Client::isViewable(void) { XWindowAttributes attr; XGetWindowAttributes(X11::getDpy(), _window, &attr); return (attr.map_state == IsViewable); } //! @brief Grabs all the mouse button actions on the client. void Client::grabButtons(void) { // Make sure we don't have any buttons grabbed. X11::ungrabButton(_window); vector *actions = Config::instance()->getMouseActionList(MOUSE_ACTION_LIST_CHILD_FRAME); vector::const_iterator it(actions->begin()); for (; it != actions->end(); ++it) { if ((it->type == MOUSE_EVENT_PRESS) || (it->type == MOUSE_EVENT_RELEASE)) { // No need to grab mod less events, replied with the frame if ((it->mod == 0) || (it->mod == MOD_ANY)) { continue; } grabButton(it->sym, it->mod, ButtonPressMask|ButtonReleaseMask, _window); } else if (it->type == MOUSE_EVENT_MOTION) { // FIXME: Add support for MOD_ANY grabButton(it->sym, it->mod, ButtonPressMask|ButtonReleaseMask|ButtonMotionMask, _window); } } } //! @brief Sets CfgDeny state on Client void Client::setStateCfgDeny(StateAction sa, uint deny) { if (! ActionUtil::needToggle(sa, _state.cfg_deny&deny)) { return; } if (_state.cfg_deny&deny) { _state.cfg_deny &= ~deny; } else { _state.cfg_deny |= deny; } } /** * Read "all" hints required during creation of Client. */ void Client::readHints(void) { readMwmHints(); readEwmhHints(); readPekwmHints(); readIcon(); readClientPid(); readClientRemote(); getWMProtocols(); } /** * Read the WM_CLASS hint and set information on the _class_hint used * in matching auto properties. */ void Client::readClassRoleHints(void) { // class hint XClassHint class_hint; if (XGetClassHint(X11::getDpy(), _window, &class_hint)) { _class_hint->h_name = Util::to_wide_str(class_hint.res_name); _class_hint->h_class = Util::to_wide_str(class_hint.res_class); XFree(class_hint.res_name); XFree(class_hint.res_class); } // wm window role string role; X11::getString(_window, WM_WINDOW_ROLE, role); _class_hint->h_role = Util::to_wide_str(role); } //! @brief Loads the Clients state from EWMH atoms. void Client::readEwmhHints(void) { // which workspace do we belong to? long workspace = -1; X11::getLong(_window, NET_WM_DESKTOP, workspace); if (workspace < 0) { _workspace = Workspaces::getActive(); X11::setLong(_window, NET_WM_DESKTOP, _workspace); } else { _workspace = workspace; } updateWinType(true); // Apply autoproperties for window type AutoProperty *auto_property = AutoProperties::instance()->findWindowTypeProperty(_window_type); if (auto_property) { applyAutoprops(auto_property); } // The _NET_WM_STATE overrides the _NET_WM_TYPE NetWMStates win_states; if (getEwmhStates(win_states)) { if (win_states.hidden) _iconified = true; if (win_states.shaded) _state.shaded = true; if (win_states.max_vert) _state.maximized_vert = true; if (win_states.max_horz) _state.maximized_horz = true; if (win_states.skip_taskbar) _state.skip |= SKIP_TASKBAR; if (win_states.skip_pager) _state.skip |= SKIP_PAGER; if (win_states.sticky) _sticky = true; if (win_states.above) { setLayer(LAYER_ABOVE_DOCK); } if (win_states.below) { setLayer(LAYER_BELOW); } if (win_states.fullscreen) _state.fullscreen = true; _demands_attention = win_states.demands_attention; } // check if we have a strut getStrutHint(); } //! @brief Loads the Clients state from MWM atoms. void Client::readMwmHints(void) { MwmHints *mwm_hints = getMwmHints(_window); if (mwm_hints) { if (mwm_hints->flags&MWM_HINTS_FUNCTIONS) { bool state = ! (mwm_hints->functions&MWM_FUNC_ALL); _actions.resize = (mwm_hints->functions&MWM_FUNC_RESIZE) ? state : ! state; _actions.move = (mwm_hints->functions&MWM_FUNC_MOVE) ? state : ! state; _actions.iconify = (mwm_hints->functions&MWM_FUNC_ICONIFY) ? state : ! state; _actions.close = (mwm_hints->functions&MWM_FUNC_CLOSE) ? state : ! state; _actions.maximize_vert = (mwm_hints->functions&MWM_FUNC_MAXIMIZE) ? state : ! state; _actions.maximize_horz = (mwm_hints->functions&MWM_FUNC_MAXIMIZE) ? state : ! state; } // Check decoration flags if (mwm_hints->flags & MWM_HINTS_DECORATIONS) { if (mwm_hints->decorations & MWM_DECOR_ALL) { setTitlebar(true); setBorder(true); } else { if (! (mwm_hints->decorations & MWM_DECOR_TITLE)) { setTitlebar(false); } if (! (mwm_hints->decorations & MWM_DECOR_BORDER)) { setBorder(false); } // Do not handle HANDLE, MENU, ICONFIY or MAXIMIZE. Maybe // one should set the allowed actions for the client based // on this but that might be annoying so ignoring these. } } XFree(mwm_hints); } } //! @brief Reads non-standard pekwm hints void Client::readPekwmHints(void) { long value; string str; // Get decor state if (X11::getLong(_window, PEKWM_FRAME_DECOR, value)) { _state.decor = value; } // Get skip state if (X11::getLong(_window, PEKWM_FRAME_SKIP, value)) { _state.skip = value; } // Get custom title if (X11::getString(_window, PEKWM_TITLE, str)) { _title.setUser(Util::to_wide_str(str)); } _state.initial_frame_order = getPekwmFrameOrder(); } //! @brief Read _NET_WM_ICON from client window. void Client::readIcon(void) { PImageIcon *image = new PImageIcon; if (image->loadFromWindow(_window)) { if (! _icon) { _icon = new PTextureImage; TextureHandler::instance()->referenceTexture(_icon); } _icon->setImage(image); } else { if (image) { delete image; } if (_icon) { TextureHandler::instance()->returnTexture(_icon); _icon = 0; } } } //! @brief Tries to find a AutoProp for the current client. //! @param type Defaults to APPLY_ON_ALWAYS. //! @return AutoProperty if any is found, else 0. AutoProperty* Client::readAutoprops(ApplyOn type) { AutoProperty *data = AutoProperties::instance()->findAutoProperty(_class_hint, Workspaces::getActive(), type); if (data) { // Make sure transient state matches if (isTransient() ? data->isApplyOn(APPLY_ON_TRANSIENT|APPLY_ON_TRANSIENT_ONLY) : ! data->isApplyOn(APPLY_ON_TRANSIENT_ONLY)) { applyAutoprops(data); } else { data = 0; } } return data; } //! @brief Applies AutoPropery to this Client. void Client::applyAutoprops(AutoProperty *ap) { // Set the correct group of the window _class_hint->group = ap->group_name; // We only apply grouping if it's a new client or if we are restarting // and have APPLY_ON_START set if (ap->isMask(AP_STICKY)) _sticky = ap->sticky; if (ap->isMask(AP_SHADED)) _state.shaded = ap->shaded; if (ap->isMask(AP_MAXIMIZED_VERTICAL)) _state.maximized_vert = ap->maximized_vertical; if (ap->isMask(AP_MAXIMIZED_HORIZONTAL)) _state.maximized_horz = ap->maximized_horizontal; if (ap->isMask(AP_FULLSCREEN)) _state.fullscreen = ap->fullscreen; if (ap->isMask(AP_ICONIFIED)) _iconified = ap->iconified; if (ap->isMask(AP_TITLEBAR)) setTitlebar(ap->titlebar); if (ap->isMask(AP_BORDER)) setBorder(ap->border); if (ap->isMask(AP_LAYER) && (ap->layer <= LAYER_MENU)) { setLayer(ap->layer); } if (ap->isMask(AP_SKIP)) _state.skip = ap->skip; if (ap->isMask(AP_FOCUSABLE)) _focusable = ap->focusable; if (ap->isMask(AP_WORKSPACE)) { _workspace = ap->workspace; } if (ap->isMask(AP_CFG_DENY)) { _state.cfg_deny = ap->cfg_deny; } if (ap->isMask(AP_ALLOWED_ACTIONS)) { applyActionAccessMask(ap->allowed_actions, true); } if (ap->isMask(AP_DISALLOWED_ACTIONS)) { applyActionAccessMask(ap->disallowed_actions, false); } if (ap->isMask(AP_OPACITY)) { setOpacity(ap->focus_opacity, ap->unfocus_opacity); } } void Client::applyActionAccessMask(uint mask, bool value) { if (mask & ACTION_ACCESS_MOVE) { _actions.move = value; } if (mask & ACTION_ACCESS_RESIZE) { _actions.resize = value; } if (mask & ACTION_ACCESS_ICONIFY) { _actions.iconify = value; } if (mask & ACTION_ACCESS_SHADE) { _actions.shade = value; } if (mask & ACTION_ACCESS_STICK) { _actions.stick = value; } if (mask & ACTION_ACCESS_MAXIMIZE_HORZ) { _actions.maximize_horz = value; } if (mask & ACTION_ACCESS_MAXIMIZE_VERT) { _actions.maximize_vert = value; } if (mask & ACTION_ACCESS_FULLSCREEN) { _actions.fullscreen = value; } if (mask & ACTION_ACCESS_CHANGE_DESKTOP) { _actions.change_ws = value; } if (mask & ACTION_ACCESS_CLOSE) { _actions.close = value; } } /** * Read _NET_WM_PID. */ void Client::readClientPid(void) { X11::getLong(_window, NET_WM_PID, _pid); } /** * Read WM_CLIENT_MACHINE and check against local hostname and set * _is_remote if it does not match. */ void Client::readClientRemote(void) { string client_machine; if (X11::getTextProperty(_window, XA_WM_CLIENT_MACHINE, client_machine)) { _is_remote = Util::getHostname() != client_machine; } } //! @brief Finds free Client ID. //! @return First free Client ID. uint Client::findClientID(void) { uint id = 0; if (_clientids.size()) { // Check for used Frame IDs id = _clientids.back(); _clientids.pop_back(); } else { // No free, get next number (Client is not in list when this is called.) id = _clients.size() + 1; } return id; } //! @brief Returns Client ID to used client id list. //! @param id ID to return. void Client::returnClientID(uint id) { vector::iterator it(_clientids.begin()); for (; it != _clientids.end() && id < *it; ++it) ; _clientids.insert(it, id); } /** * Tries to get the NET_WM name, else fall back to WM_NAME */ void Client::readName(void) { // Read title, bail out if it fails. string title; std::wstring wtitle; if (X11::getUtf8String(_window, NET_WM_NAME, title)) { wtitle = Util::from_utf8_str(title); } else if (X11::getTextProperty(_window, XA_WM_NAME, title)) { wtitle = Util::to_wide_str(title); } else { return; } // Mirror it on the visible _title.setCustom(L""); _title.setCount(titleFindID(wtitle)); _title.setReal(wtitle); // Apply title rules and find unique name, doesn't apply on // user-set titles if (titleApplyRule(wtitle)) { _title.setCustom(wtitle); X11::setUtf8String(_window, NET_WM_VISIBLE_NAME, Util::to_utf8_str(wtitle)); } else { X11::unsetProperty(_window, NET_WM_VISIBLE_NAME); } } //! @brief Searches for an TitleRule and if found, applies it //! @param title Title to apply rule on. //! @return true if rule was applied, else false. bool Client::titleApplyRule(std::wstring &title) { _class_hint->title = title; TitleProperty *data = AutoProperties::instance()->findTitleProperty(_class_hint); if (data) { return data->getTitleRule().ed_s(title); } else { return false; } } //! @brief Searches for a unique ID within Clients having the same title //! @param title Title of client to find ID for. //! @return Number of clients with that id. uint Client::titleFindID(std::wstring &title) { // Do not search for unique IDs if it is not enabled. if (! Config::instance()->getClientUniqueName()) { return 0; } uint id_found = 0; vector ids_used; vector::const_iterator it = _clients.begin(); for (; it != _clients.end(); ++it) { if (*it != this) { if ((*it)->getTitle()->getReal() == title) { ids_used.push_back((*it)->getTitle()->getCount()); } } } // more than one client having this name if (ids_used.size() > 0) { std::sort(ids_used.begin(), ids_used.end()); vector::const_iterator ui_it(ids_used.begin()); for (uint i = 0; ui_it != ids_used.end(); ++i, ++ui_it) { if (i < *ui_it) { id_found = i; break; } } if (ui_it == ids_used.end()) { id_found = ids_used.size(); } } return id_found; } //! @brief Sets the WM_STATE of the client to state //! @param state State to set. void Client::setWmState(ulong state) { ulong data[2]; data[0] = state; data[1] = None; // No Icon XChangeProperty(X11::getDpy(), _window, X11::getAtom(WM_STATE), X11::getAtom(WM_STATE), 32, PropModeReplace, (uchar*) data, 2); } // If we can't find a wm_state we're going to have to assume // Withdrawn. This is not exactly optimal, since we can't really // distinguish between the case where no WM has run yet and when the // state was explicitly removed (Clients are allowed to either set the // atom to Withdrawn or just remove it... yuck.) long Client::getWmState(void) { Atom real_type; int real_format; long *data, state = WithdrawnState; ulong items_read, items_left; uchar *udata; int status = XGetWindowProperty(X11::getDpy(), _window, X11::getAtom(WM_STATE), 0L, 2L, False, X11::getAtom(WM_STATE), &real_type, &real_format, &items_read, &items_left, &udata); if ((status == Success) && items_read) { data = reinterpret_cast(udata); state = *data; XFree(udata); } return state; } //! @brief Send XConfigureEvent, letting the client know about changes void Client::configureRequestSend(void) { if (_cfg_request_lock) { return; } XConfigureEvent e; e.type = ConfigureNotify; e.event = _window; e.window = _window; e.x = _gm.x; e.y = _gm.y; e.width = _gm.width; e.height = _gm.height; e.border_width = 0; e.above = None; e.override_redirect = False; XSendEvent(X11::getDpy(), _window, false, StructureNotifyMask, (XEvent *) &e); } //! @brief Send a TAKE_FOCUS client message to the client (if requested by it). void Client::sendTakeFocusMessage(void) { if (_send_focus_message) { { XEvent ev; XChangeProperty(X11::getDpy(), X11::getRoot(), XA_PRIMARY, XA_STRING, 8, PropModeAppend, 0, 0); XWindowEvent(X11::getDpy(), X11::getRoot(), PropertyChangeMask, &ev); X11::setLastEventTime(ev.xproperty.time); } X11::sendEvent(_window, X11::getAtom(WM_PROTOCOLS), NoEventMask, X11::getAtom(WM_TAKE_FOCUS), X11::getLastEventTime()); } } //! @brief Grabs a button on the window win //! Grabs the button button, with the mod mod and mask mask on the window win //! and cursor curs with "all" possible extra modifiers void Client::grabButton(int button, int mod, int mask, Window win) { uint num_lock = X11::getNumLock(); uint scroll_lock = X11::getScrollLock(); X11::grabButton(button, mod, win, mask); X11::grabButton(button, mod|LockMask, win, mask); if (num_lock) { X11::grabButton(button, mod|num_lock, win, mask); X11::grabButton(button, mod|num_lock|LockMask, win, mask); } if (scroll_lock) { X11::grabButton(button, mod|scroll_lock, win, mask); X11::grabButton(button, mod|scroll_lock|LockMask, win, mask); } if (num_lock && scroll_lock) { X11::grabButton(button, mod|num_lock|scroll_lock, win, mask); X11::grabButton(button, mod|num_lock|scroll_lock|LockMask, win, mask); } } /** * Toggles the clients always on top state */ void Client::alwaysOnTop(bool top) { setLayer(top ? LAYER_ONTOP : LAYER_NORMAL); updateEwmhStates(); } /** * Toggles the clients always below state. */ void Client::alwaysBelow(bool below) { setLayer(below ? LAYER_BELOW : LAYER_NORMAL); updateEwmhStates(); } //! @brief Sets the skip state, and updates the _PEKWM_FRAME_SKIP atom void Client::setSkip(uint skip) { _state.skip = skip; X11::setLong(_window, PEKWM_FRAME_SKIP, _state.skip); } std::string Client::getAPDecorName(void) { WindowManager *wm = WindowManager::instance(); // for convenience AutoProperty *ap = wm->getAutoProperties()->findAutoProperty(getClassHint()); if (ap && ap->isMask(AP_DECOR)) { return ap->frame_decor; } ap = wm->getAutoProperties()->findWindowTypeProperty(getWinType()); if (ap && ap->isMask(AP_DECOR)) { return ap->frame_decor; } DecorProperty *dp = wm->getAutoProperties()->findDecorProperty(getClassHint()); if (dp) { return dp->getName(); } return ""; } //! @brief Sends an WM_DELETE message to the client, else kills it. void Client::close(void) { // Check for DisallowedActions="Close". if (! allowClose()) { return; } if (_send_close_message) { X11::sendEvent(_window, X11::getAtom(WM_PROTOCOLS), NoEventMask, X11::getAtom(WM_DELETE_WINDOW), CurrentTime); } else { kill(); } } //! @brief Kills the client using XKillClient void Client::kill(void) { XKillClient(X11::getDpy(), _window); } //! @brief Get the closest size confirming to the aspect ratio and ResizeInc (if applicable) //! @param r_w Pointer to put the new width in //! @param r_h Pointer to put the new height in //! @param w Width to calculate from //! @param h Height to calculate from //! @return true if width/height have changed bool Client::getAspectSize(uint *r_w, uint *r_h, uint w, uint h) { // see ICCCM 4.1.2.3 for PAspect and {min,max}_aspect if (_size->flags & PAspect && Config::instance()->isHonourAspectRatio()) { // shorthand const uint amin_x = _size->min_aspect.x; const uint amin_y = _size->min_aspect.y; const uint amax_x = _size->max_aspect.x; const uint amax_y = _size->max_aspect.y; uint base_w = 0, base_h = 0; // If PBaseSize is specified, base_{width,height} should be subtracted // before checking the aspect ratio (c.f. ICCCM). The additional checks avoid // underflows in w and h. Keep in mind that _size->base_{width,height} are // guaranteed to be non-negative by getWMNormalHints(). if (_size->flags & PBaseSize) { if (static_cast(_size->base_width) < w) { base_w = _size->base_width; w -= base_w; } if (static_cast(_size->base_height) < h) { base_h = _size->base_height; h -= base_h; } } double tmp; // We have to ensure: min_aspect.x/min_aspect.y <= w/h <= max_aspect.x/max_aspect.y // How do we calculate the new r_w, r_h? // Consider the plane spanned by width and height. The points with one specific // aspect ratio form a line and (w,h) is a point. So, we simply calculate the // point on the line that is closest to (w, h) under the Euclidean metric. // Lesson learned doing this: It is good to look at a different implementation // (thanks fluxbox!) and then let a friend go over your own calculation to // tell you what your mistake is (thanks Robert!). ;-) // Check if w/h is less than amin_x/amin_y if (w * amin_y < h * amin_x) { tmp = ((double)(w * amin_x + h * amin_y)) / ((double)(amin_x * amin_x + amin_y * amin_y)); w = static_cast(amin_x * tmp) + base_w; h = static_cast(amin_y * tmp) + base_h; // Check if w/h is greater than amax_x/amax_y } else if (w * amax_y > amax_x * h) { tmp = ((double)(w * amax_x + h * amax_y)) / ((double)(amax_x * amax_x + amax_y * amax_y)); w = static_cast(amax_x * tmp) + base_w; h = static_cast(amax_y * tmp) + base_h; } getIncSize(r_w, r_h, w, h, false); return true; } return getIncSize(r_w, r_h, w, h); } //! @brief Get the size closest to the ResizeInc incrementer //! @param r_w Pointer to put the new width in //! @param r_h Pointer to put the new height in //! @param w Width to calculate from //! @param h Height to calculate from //! @param incr If true, increase w,h to fulfil PResizeInc (instead of decreasing them) bool Client::getIncSize(uint *r_w, uint *r_h, uint w, uint h, bool incr) { uint basex, basey; if (_size->flags&PResizeInc) { basex = (_size->flags&PBaseSize) ? _size->base_width : (_size->flags&PMinSize) ? _size->min_width : 0; basey = (_size->flags&PBaseSize) ? _size->base_height : (_size->flags&PMinSize) ? _size->min_height : 0; if (w < basex || h < basey) { basex=basey=0; } uint dw = (w - basex) % _size->width_inc; uint dh = (h - basey) % _size->height_inc; *r_w = w - dw + ((incr && dw)?_size->width_inc:0); *r_h = h - dh + ((incr && dh)?_size->height_inc:0); return true; } *r_w = w; *r_h = h; return false; } //! @brief Gets a MwmHint structure from a window. Doesn't free memory. Client::MwmHints* Client::getMwmHints(Window win) { Atom real_type; int real_format; ulong items_read, items_left; MwmHints *data = 0; uchar *udata; Atom hints_atom = X11::getAtom(MOTIF_WM_HINTS); int status = XGetWindowProperty(X11::getDpy(), win, hints_atom, 0L, 20L, False, hints_atom, &real_type, &real_format, &items_read, &items_left, &udata); if (status == Success) { if (items_read < MWM_HINTS_NUM) { XFree(udata); udata = 0; } } else { udata = 0; } if (udata) { data = reinterpret_cast(udata); } return data; } // This happens when a window is iconified and destroys itself. An // Unmap event wouldn't happen in that case because the window is // already unmapped. void Client::handleDestroyEvent(XDestroyWindowEvent *e) { _alive = false; delete this; } void Client::handleColormapChange(XColormapEvent *e) { if (e->c_new) { _cmap = e->colormap; XInstallColormap(X11::getDpy(), _cmap); } } //! @brief bool Client::getEwmhStates(NetWMStates &win_states) { int num = 0; Atom *states; states = (Atom*) X11::getEwmhPropData(_window, STATE, XA_ATOM, num); if (states) { for (int i = 0; i < num; ++i) { if (states[i] == X11::getAtom(STATE_MODAL)) { win_states.modal = true; } else if (states[i] == X11::getAtom(STATE_STICKY)) { win_states.sticky = true; } else if (states[i] == X11::getAtom(STATE_MAXIMIZED_VERT) && ! isCfgDeny(CFG_DENY_STATE_MAXIMIZED_VERT)) { win_states.max_vert = true; } else if (states[i] == X11::getAtom(STATE_MAXIMIZED_HORZ) && ! isCfgDeny(CFG_DENY_STATE_MAXIMIZED_HORZ)) { win_states.max_horz = true; } else if (states[i] == X11::getAtom(STATE_SHADED)) { win_states.shaded = true; } else if (states[i] == X11::getAtom(STATE_SKIP_TASKBAR)) { win_states.skip_taskbar = true; } else if (states[i] == X11::getAtom(STATE_SKIP_PAGER)) { win_states.skip_pager = true; } else if (states[i] == X11::getAtom(STATE_DEMANDS_ATTENTION)) { win_states.demands_attention = true; } else if (states[i] == X11::getAtom(STATE_HIDDEN) && ! isCfgDeny(CFG_DENY_STATE_HIDDEN)) { win_states.hidden = true; } else if (states[i] == X11::getAtom(STATE_FULLSCREEN) && ! isCfgDeny(CFG_DENY_STATE_FULLSCREEN)) { win_states.fullscreen = true; } else if (states[i] == X11::getAtom(STATE_ABOVE) && ! isCfgDeny(CFG_DENY_STATE_ABOVE)) { win_states.above = true; } else if (states[i] == X11::getAtom(STATE_BELOW) && ! isCfgDeny(CFG_DENY_STATE_BELOW)) { win_states.below = true; } } XFree(states); return true; } else { return false; } } //! @brief Tells the world about our states, such as shaded etc. void Client::updateEwmhStates(void) { vector states; if (false) // we don't yet support modal state states.push_back(X11::getAtom(STATE_MODAL)); if (_sticky) states.push_back(X11::getAtom(STATE_STICKY)); if (_state.maximized_vert) states.push_back(X11::getAtom(STATE_MAXIMIZED_VERT)); if (_state.maximized_horz) states.push_back(X11::getAtom(STATE_MAXIMIZED_HORZ)); if (_state.shaded) states.push_back(X11::getAtom(STATE_SHADED)); if (isSkip(SKIP_TASKBAR)) states.push_back(X11::getAtom(STATE_SKIP_TASKBAR)); if (isSkip(SKIP_PAGER)) states.push_back(X11::getAtom(STATE_SKIP_PAGER)); if (_iconified) states.push_back(X11::getAtom(STATE_HIDDEN)); if (_state.fullscreen) states.push_back(X11::getAtom(STATE_FULLSCREEN)); if (getLayer() == LAYER_ABOVE_DOCK) { states.push_back(X11::getAtom(STATE_ABOVE)); } if (getLayer() == LAYER_BELOW) { states.push_back(X11::getAtom(STATE_BELOW)); } Atom *atoms = new Atom[(states.size() > 0) ? states.size() : 1]; if (states.size() > 0) { copy(states.begin(), states.end(), atoms); } X11::setAtoms(_window, STATE, atoms, states.size()); delete [] atoms; } void Client::updateWinType(bool set) { // try to figure out what kind of window we are and alter it accordingly int items; Atom *atoms = 0; _window_type = WINDOW_TYPE; atoms = (Atom*) X11::getEwmhPropData(_window, WINDOW_TYPE, XA_ATOM, items); if (atoms) { for (int i = 0; _window_type == WINDOW_TYPE && i < items; ++i) { if (atoms[i] == X11::getAtom(WINDOW_TYPE_DESKTOP)) { _window_type = WINDOW_TYPE_DESKTOP; } else if (atoms[i] == X11::getAtom(WINDOW_TYPE_DOCK)) { _window_type = WINDOW_TYPE_DOCK; } else if (atoms[i] == X11::getAtom(WINDOW_TYPE_TOOLBAR)) { _window_type = WINDOW_TYPE_TOOLBAR; } else if (atoms[i] == X11::getAtom(WINDOW_TYPE_MENU)) { _window_type = WINDOW_TYPE_MENU; } else if (atoms[i] == X11::getAtom(WINDOW_TYPE_UTILITY)) { _window_type = WINDOW_TYPE_UTILITY; } else if (atoms[i] == X11::getAtom(WINDOW_TYPE_DIALOG)) { _window_type = WINDOW_TYPE_DIALOG; } else if (atoms[i] == X11::getAtom(WINDOW_TYPE_SPLASH)) { _window_type = WINDOW_TYPE_SPLASH; } else if (atoms[i] == X11::getAtom(WINDOW_TYPE_NORMAL)) { _window_type = WINDOW_TYPE_NORMAL; } } XFree(atoms); } // Set window type to WINDOW_TYPE_NORMAL if it did not match if (_window_type == WINDOW_TYPE) { _window_type = WINDOW_TYPE_NORMAL; if (set) X11::setAtom(_window, WINDOW_TYPE, WINDOW_TYPE_NORMAL); } } /** * Read WM Hints, return the initial state of the window. */ ulong Client::getWMHints(void) { ulong initial_state = NormalState; XWMHints* hints = XGetWMHints(X11::getDpy(), _window); if (hints) { // get the input focus mode if (hints->flags&InputHint) { // FIXME: More logic needed _wm_hints_input = hints->input; } // Get initial state of the window if (hints->flags&StateHint) { initial_state = hints->initial_state; } setDemandsAttention(hints->flags&XUrgencyHint); XFree(hints); } return initial_state; } void Client::getWMNormalHints(void) { long dummy; XGetWMNormalHints(X11::getDpy(), _window, _size, &dummy); // let's do some sanity checking if (_size->flags & PBaseSize) { if (_size->base_width < 1 || _size->base_height < 1) { _size->base_width = _size->base_height = 0; _size->flags &= ~PBaseSize; } } if (_size->flags & PAspect) { if (_size->min_aspect.x < 1 || _size->min_aspect.y < 1 || _size->max_aspect.x < 1 || _size->max_aspect.y < 1) { _size->min_aspect.x = _size->min_aspect.y = 0; _size->max_aspect.x = _size->max_aspect.y = 0; _size->flags &= ~PAspect; } } if (_size->flags & PResizeInc) { if (_size->width_inc < 1 || _size->height_inc < 1) { _size->width_inc = 0; _size->height_inc = 0; _size->flags &= ~PResizeInc; } } if (_size->flags & PMaxSize) { if (_size->max_width < 1 || _size->max_height < 1 || ((_size->flags & PMinSize) && (_size->max_width < _size->min_width || _size->max_height < _size->min_height) )) { _size->max_width = 0; _size->max_height = 0; _size->flags &= ~PMaxSize; } } } //! @brief void Client::getWMProtocols(void) { int count; Atom *protocols; if (XGetWMProtocols(X11::getDpy(), _window, &protocols, &count) != 0) { for (int i = 0; i < count; ++i) { if (protocols[i] == X11::getAtom(WM_TAKE_FOCUS)) { _send_focus_message = true; } else if (protocols[i] == X11::getAtom(WM_DELETE_WINDOW)) { _send_close_message = true; } } XFree(protocols); } } /** * Read WM_TRANSIENT_FOR hint. */ void Client::getTransientForHint(void) { if (_transient_for) { return; } XGetTransientForHint(X11::getDpy(), _window, &_transient_for_window); if (_transient_for_window != None) { if (_transient_for_window == _window) { ERR("Client set transient hint for itself."); _transient_for_window = None; return; } _transient_for = findClientFromWindow(_transient_for_window); if (_transient_for) { // Observe for changes _transient_for->_transients.push_back(this); _transient_for->addObserver(this); } } } void Client::updateParentLayerAndRaiseIfActive(void) { Frame *frame = static_cast(getParent()); if (frame->getActiveChild() == this) { frame->setLayer(getLayer()); frame->raise(); } } /** Read the NET_WM_STRUT hint from the client window if any, adding it to the global list of struts if the client does not have Strut in it's CfgDeny. */ void Client::getStrutHint(void) { // Clear out old strut, well re-add if a new one is found. removeStrutHint(); int num = 0; long *strut = static_cast(X11::getEwmhPropData(_window, NET_WM_STRUT, XA_CARDINAL, num)); if (strut) { _strut = new Strut(); *_strut = strut; XFree(strut); if (! isCfgDeny(CFG_DENY_STRUT)) { X11::addStrut(_strut); } } } /** Free resources used by the clients strut hint if any and unregister it from the screen if Strut is not in it's CfgDeny. */ void Client::removeStrutHint(void) { if ( _strut) { if (! isCfgDeny(CFG_DENY_STRUT)) { X11::removeStrut(_strut); } delete _strut; _strut = 0; } } /** * Get _PEKWM_FRAME_ORDER hint from client, return < 0 on failure. */ long Client::getPekwmFrameOrder(void) { long num = -1; X11::getLong(_window, PEKWM_FRAME_ORDER, num); return num; } /** * Update _PEKWM_FRAME_ORDER hint on client window. */ void Client::setPekwmFrameOrder(long num) { X11::setLong(_window, PEKWM_FRAME_ORDER, num); } /** * Get _PEKWM_FRAME_ACTIVE hint from client window, return true if * client is treated as active. */ bool Client::getPekwmFrameActive(void) { long act = 0; return (X11::getLong(_window, PEKWM_FRAME_ACTIVE, act) && act == 1); } /** * Set _PEKWM_FRAME_ACTIVE hint on client window. */ void Client::setPekwmFrameActive(bool act) { X11::setLong(_window, PEKWM_FRAME_ACTIVE, act ? 1 : 0); } /** * Update the environment with CLIENT_PID and CLIENT_WINDOW. */ void Client::setClientEnvironment(Client *client) { if (client) { setenv("CLIENT_PID", Util::to_string(client->isRemote() ? -1 : client->getPid()).c_str(), 1); setenv("CLIENT_WINDOW", Util::to_string(client->getWindow()).c_str(), 1); } else { unsetenv("CLIENT_PID"); unsetenv("CLIENT_WINDOW"); } } pekwm-release-0.1.18/src/Client.hh000066400000000000000000000324301374756504400167110ustar00rootroot00000000000000// // Client.hh for pekwm // Copyright © 2003-2009 Claes Nästén // // client.hh for aewm++ // Copyright (C) 2002 Frank Hale // http://sapphire.sourceforge.net/ // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifndef _CLIENT_HH_ #define _CLIENT_HH_ #include "config.h" #include "pekwm.hh" #include "PWinObj.hh" #include "Observer.hh" #include "PTexturePlain.hh" #include "PDecor.hh" class PScreen; class Strut; class ClassHint; class AutoProperty; class Frame; #include extern "C" { #include } class LayerObservation : public Observation { public: LayerObservation(enum Layer _layer) : layer(_layer) { }; virtual ~LayerObservation(void) { }; public: const enum Layer layer; /**< Layer client changed to. */ }; class ClientInitConfig { public: bool focus; bool focus_parent; bool map; bool parent_is_new; }; class Client : public PWinObj, public Observer { // FIXME: This relationship should end as soon as possible, but I need to // figure out a good way of sharing. :) friend class Frame; public: // Public Member Functions struct MwmHints { ulong flags; ulong functions; ulong decorations; }; enum { MWM_HINTS_FUNCTIONS = (1L << 0), MWM_HINTS_DECORATIONS = (1L << 1), MWM_HINTS_NUM = 3 }; enum { MWM_FUNC_ALL = (1L << 0), MWM_FUNC_RESIZE = (1L << 1), MWM_FUNC_MOVE = (1L << 2), MWM_FUNC_ICONIFY = (1L << 3), MWM_FUNC_MAXIMIZE = (1L << 4), MWM_FUNC_CLOSE = (1L << 5) }; enum { MWM_DECOR_ALL = (1L << 0), MWM_DECOR_BORDER = (1L << 1), MWM_DECOR_HANDLE = (1L << 2), MWM_DECOR_TITLE = (1L << 3), MWM_DECOR_MENU = (1L << 4), MWM_DECOR_ICONIFY = (1L << 5), MWM_DECOR_MAXIMIZE = (1L << 6) }; Client(Window new_client, ClientInitConfig &initConfig, bool is_new = false); virtual ~Client(void); // START - PWinObj interface. virtual void mapWindow(void); virtual void unmapWindow(void); virtual void iconify(void); virtual void stick(void); virtual void move(int x, int y); virtual void resize(uint width, uint height); virtual void moveResize(int x, int y, uint width, uint height); virtual void setWorkspace(uint workspace); virtual void giveInputFocus(void); virtual void reparent(PWinObj *parent, int x, int y); virtual ActionEvent *handleButtonPress(XButtonEvent *ev) { if (_parent) { return _parent->handleButtonPress(ev); } return 0; } virtual ActionEvent *handleButtonRelease(XButtonEvent *ev) { if (_parent) { return _parent->handleButtonRelease(ev); } return 0; } virtual ActionEvent *handleMapRequest(XMapRequestEvent *ev); virtual ActionEvent *handleUnmapEvent(XUnmapEvent *ev); // END - PWinObj interface. #ifdef HAVE_SHAPE void handleShapeEvent(XShapeEvent *); #endif // HAVE_SHAPE // START - Observer interface. virtual void notify(Observable *observable, Observation *observation); // END - Observer interface. static Client *findClient(Window win); static Client *findClientFromWindow(Window win); static Client *findClientFromHint(const ClassHint *class_hint); static Client *findClientFromID(uint id); static void findFamilyFromWindow(vector &client_list, Window win); static void mapOrUnmapTransients(Window win, bool hide); // START - Iterators static uint client_size(void) { return _clients.size(); } static vector::const_iterator client_begin(void) { return _clients.begin(); } static vector::const_iterator client_end(void) { return _clients.end(); } static vector::const_reverse_iterator client_rbegin(void) { return _clients.rbegin(); } static vector::const_reverse_iterator client_rend(void) { return _clients.rend(); } bool hasTransients() const { return ! _transients.empty(); } vector::const_iterator getTransientsBegin(void) const { return _transients.begin(); } vector::const_iterator getTransientsEnd(void) const { return _transients.end(); } // END - Iterators bool validate(void); inline uint getClientID(void) { return _id; } /**< Return title item for client name. */ inline PDecor::TitleItem *getTitle(void) { return &_title; } inline const ClassHint* getClassHint(void) const { return _class_hint; } bool isTransient(void) const { return _transient_for_window != None; } Client *getTransientForClient(void) const { return _transient_for; } Window getTransientForClientWindow(void) const { return _transient_for_window; } void findAndRaiseIfTransient(void); inline XSizeHints* getXSizeHints(void) const { return _size; } bool isViewable(void); bool cameWithPosition(void) { return _size->flags & (PPosition|USPosition); } inline bool hasTitlebar(void) const { return (_state.decor&DECOR_TITLEBAR); } inline bool hasBorder(void) const { return (_state.decor&DECOR_BORDER); } inline bool hasStrut(void) const { return (_strut); } Strut *getStrut(void) const { return _strut; } inline bool demandsAttention(void) const { return _demands_attention; } PTexture *getIcon(void) const { return _icon; } /** Return PID of client. */ long getPid(void) const { return _pid; } /** Return true if client is remote. */ bool isRemote(void) const { return _is_remote; } // State accessors inline bool isMaximizedVert(void) const { return _state.maximized_vert; } inline bool isMaximizedHorz(void) const { return _state.maximized_horz; } inline bool isShaded(void) const { return _state.shaded; } inline bool isFullscreen(void) const { return _state.fullscreen; } inline bool isPlaced(void) const { return _state.placed; } inline uint getInitialFrameOrder(void) const { return _state.initial_frame_order; } inline uint getSkip(void) const { return _state.skip; } inline bool isSkip(Skip skip) const { return (_state.skip&skip); } inline uint getDecorState(void) const { return _state.decor; } inline bool isCfgDeny(uint deny) { return (_state.cfg_deny&deny); } inline bool allowMove(void) const { return _actions.move; } inline bool allowResize(void) const { return _actions.resize; } inline bool allowIconify(void) const { return _actions.iconify; } inline bool allowShade(void) const { return _actions.shade; } inline bool allowStick(void) const { return _actions.stick; } inline bool allowMaximizeHorz(void) const { return _actions.maximize_horz; } inline bool allowMaximizeVert(void) const { return _actions.maximize_vert; } inline bool allowFullscreen(void) const { return _actions.fullscreen; } inline bool allowChangeWorkspace(void) const { return _actions.change_ws; } inline bool allowClose(void) const { return _actions.close; } inline bool isAlive(void) const { return _alive; } inline bool isMarked(void) const { return _marked; } // We have this public so that we can reload button actions. void grabButtons(void); void setStateCfgDeny(StateAction sa, uint deny); inline void setStateMarked(StateAction sa) { if (ActionUtil::needToggle(sa, _marked)) { _marked = !_marked; if (_marked) { _title.infoAdd(PDecor::TitleItem::INFO_MARKED); } else { _title.infoRemove(PDecor::TitleItem::INFO_MARKED); } _title.updateVisible(); } } // toggles void alwaysOnTop(bool top); void alwaysBelow(bool bottom); void setSkip(uint skip); inline void setStateSkip(StateAction sa, Skip skip) { if ((isSkip(skip) && (sa == STATE_SET)) || (! isSkip(skip) && (sa == STATE_UNSET))) { return; } _state.skip ^= skip; } inline void setTitlebar(bool titlebar) { if (titlebar) { _state.decor |= DECOR_TITLEBAR; } else { _state.decor &= ~DECOR_TITLEBAR; } } inline void setBorder(bool border) { if (border) { _state.decor |= DECOR_BORDER; } else { _state.decor &= ~DECOR_BORDER; } } inline void setDemandsAttention(bool attention) { _demands_attention = attention; } std::string getAPDecorName(void); void close(void); void kill(void); // Event handlers below - Used by WindowManager void handleDestroyEvent(XDestroyWindowEvent *ev); void handleColormapChange(XColormapEvent *ev); inline bool setConfigureRequestLock(bool lock) { bool old_lock = _cfg_request_lock; _cfg_request_lock = lock; return old_lock; } void configureRequestSend(void); void sendTakeFocusMessage(void); bool getAspectSize(uint *r_w, uint *r_h, uint w, uint h); bool getIncSize(uint *r_w, uint *r_h, uint w, uint h, bool incr=false); bool getEwmhStates(NetWMStates &win_states); void updateEwmhStates(void); inline AtomName getWinType(void) const { return _window_type; } void updateWinType(bool set); ulong getWMHints(void); void getWMNormalHints(void); void getWMProtocols(void); void getTransientForHint(void); void updateParentLayerAndRaiseIfActive(void); void getStrutHint(void); void readName(void); void removeStrutHint(void); long getPekwmFrameOrder(void); void setPekwmFrameOrder(long num); bool getPekwmFrameActive(void); void setPekwmFrameActive(bool active); static void setClientEnvironment(Client *client); AutoProperty* readAutoprops(ApplyOn type = APPLY_ON_ALWAYS); private: bool getAndUpdateWindowAttributes(void); bool findOrCreateFrame(AutoProperty *autoproperty); bool findTaggedFrame(void); bool findPreviousFrame(void); bool findAutoGroupFrame(AutoProperty *autoproperty); void setInitialState(void); void setClientInitConfig(ClientInitConfig &initConfig, bool is_new, AutoProperty *autoproperty); bool titleApplyRule(std::wstring &wtitle); uint titleFindID(std::wstring &wtitle); void setWmState(ulong state); long getWmState(void); MwmHints* getMwmHints(Window w); // these are used by frame inline void setMaximizedVert(bool m) { _state.maximized_vert = m; } inline void setMaximizedHorz(bool m) { _state.maximized_horz = m; } inline void setShade(bool s) { _state.shaded = s; } inline void setFullscreen(bool f) { _state.fullscreen = f; } inline void setFocusable(bool f) { _focusable = f; } // Grabs button with Caps,Num and so on void grabButton(int button, int mod, int mask, Window win); void readHints(void); void readClassRoleHints(void); void readEwmhHints(void); void readMwmHints(void); void readPekwmHints(void); void readIcon(void); void applyAutoprops(AutoProperty *ap); void applyActionAccessMask(uint mask, bool value); void readClientPid(void); void readClientRemote(void); static uint findClientID(void); static void returnClientID(uint id); private: // Private Member Variables uint _id; // _transients; /**< Vector of transient clients. */ Strut *_strut; PDecor::TitleItem _title; /**< Name of the client. */ PTextureImage *_icon; long _pid; /**< _NET_WM_PID of the client, only valid if is_remote is false. */ bool _is_remote; /**< Boolean flag */ ClassHint *_class_hint; AtomName _window_type; /**< _NET_WM_WINDOW_TYPE */ bool _alive, _marked; bool _send_focus_message, _send_close_message, _wm_hints_input; bool _cfg_request_lock; bool _extended_net_name; bool _demands_attention; /**< If true, the client requires attention from the user. */ class State { public: State(void) : maximized_vert(false), maximized_horz(false), shaded(false), fullscreen(false), placed(false), initial_frame_order(0), skip(0), decor(DECOR_TITLEBAR|DECOR_BORDER), cfg_deny(CFG_DENY_NO) { } ~State(void) { } bool maximized_vert, maximized_horz; bool shaded; bool fullscreen; // pekwm states bool placed; uint initial_frame_order; /**< Initial frame position */ uint skip, decor, cfg_deny; } _state; class Actions { public: Actions(void) : move(true), resize(true), iconify(true), shade(true), stick(true), maximize_horz(true), maximize_vert(true), fullscreen(true), change_ws(true), close(true) { } ~Actions(void) { } bool move:1; bool resize:1; bool iconify:1; // iconify bool shade:1; bool stick:1; bool maximize_horz:1; bool maximize_vert:1; bool fullscreen:1; bool change_ws:1; // workspace bool close:1; } _actions; static const long _clientEventMask; static vector _clients; //!< Vector of all Clients. static vector _clientids; //!< Vector of free Client IDs. }; #endif // _CLIENT_HH_ pekwm-release-0.1.18/src/CmdDialog.cc000066400000000000000000000064141374756504400173070ustar00rootroot00000000000000// // CmdDialog.cc for pekwm // Copyright © 2004-2015 the pekwm development team // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "config.h" #include #include #include extern "C" { #include #include // XLookupString #include } #include "PWinObj.hh" #include "PDecor.hh" #include "CmdDialog.hh" #include "Config.hh" #include "KeyGrabber.hh" #include "Workspaces.hh" using std::cerr; using std::endl; using std::list; using std::string; using std::wstring; /** * CmdDialog constructor, init and load history file. * * @todo Make size configurable. */ CmdDialog::CmdDialog(Theme *theme) : InputDialog(theme, L"Enter command"), _exec_count(0) { _type = PWinObj::WO_CMD_DIALOG; if (Config::instance()->getCmdDialogHistoryFile().size() > 0) { loadHistory(Config::instance()->getCmdDialogHistoryFile()); } } /** * CmdDialog de-structor, clean up and save history file. */ CmdDialog::~CmdDialog(void) { if (Config::instance()->getCmdDialogHistoryFile().size() > 0) { saveHistory(Config::instance()->getCmdDialogHistoryFile()); } } //! @brief Parses _buf and tries to generate an ActionEvent //! @return Pointer to ActionEvent. ActionEvent* CmdDialog::exec(void) { // Update history if (Config::instance()->isCmdDialogHistoryUnique()) { addHistoryUnique(_buf); } else { _history.push_back(_buf); } if (_history.size() > static_cast(Config::instance()->getCmdDialogHistorySize())) { _history.erase(_history.begin()); } // Persist changes if (Config::instance()->getCmdDialogHistorySaveInterval() > 0 && Config::instance()->getCmdDialogHistoryFile().size() > 0 && ++_exec_count > Config::instance()->getCmdDialogHistorySaveInterval()) { saveHistory(Config::instance()->getCmdDialogHistoryFile()); _exec_count = 0; } // Check if it's a valid Action, if not we assume it's a command and try // to execute it. string buf_mb(Util::to_mb_str(_buf)); if (! Config::instance()->parseAction(buf_mb, _ae.action_list.back(), KEYGRABBER_OK)) { _ae.action_list.back().setAction(ACTION_EXEC); _ae.action_list.back().setParamS(buf_mb); } return &_ae; } //! @brief Unmaps window, overloaded to clear buffer. void CmdDialog::unmapWindow(void) { if (_mapped) { InputDialog::unmapWindow(); setWORef(0); bufClear(); } } /** * Tab completion, complete word at cursor position. */ void CmdDialog::complete(void) { // Find completion if changed since last time. if (_buf != _buf_on_complete_result) { InputDialog::complete(); _complete_list = _completer.find_completions(_buf, _pos); _complete_it = _complete_list.begin(); } if (_complete_list.size()) { _buf = _completer.do_complete(_buf_on_complete, _pos, _complete_list, _complete_it); _buf_on_complete_result = _buf; } } /** * Map CmdDialog centered on wo_ref is specified, else _wo_ref. */ void CmdDialog::mapCentered(const std::string &buf, const Geometry &geom, PWinObj *wo_ref) { if (wo_ref != 0) { setWORef(wo_ref); } InputDialog::mapCentered(buf, geom, wo_ref); } pekwm-release-0.1.18/src/CmdDialog.hh000066400000000000000000000022051374756504400173130ustar00rootroot00000000000000// // CmdDialog.hh for pekwm // Copyright © 2004-2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifndef _CMD_DIALOG_HH_ #define _CMD_DIALOG_HH_ #include "config.h" #include "Action.hh" #include "Completer.hh" #include "InputDialog.hh" #include "Theme.hh" #include #include //! @brief CmdDialog presenting the user with an pekwm action command line. class CmdDialog : public InputDialog { public: CmdDialog(Theme *theme); virtual ~CmdDialog(void); void unmapWindow(void); virtual void mapCentered(const std::string &buf, const Geometry &geom, PWinObj *wo_ref); private: void render(void); virtual ActionEvent *exec(void); virtual void complete(void); private: Completer _completer; /**< Completer used completing actions. */ complete_list _complete_list; /**< List of completions found by completer. */ complete_it _complete_it; /**< Iterator used to step between completions. */ int _exec_count; /**< Number of CmdDialog has run exec since last history save. */ }; #endif // _CMD_DIALOG_HH_ pekwm-release-0.1.18/src/Compat.cc000066400000000000000000000052471374756504400167120ustar00rootroot00000000000000// // Compat.cc for pekwm // Copyright © 2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "config.h" #include "Compat.hh" #include "Util.hh" #include #include extern "C" { #include #include } #ifndef HAVE_UNSETENV #include #endif // ! HAVE_UNSETENV using std::string; using std::wstring; #ifndef HAVE_SWPRINTF /**< Message displayed when %ls formatting is attempted. */ static const wchar_t *SWPRINTF_LS_NOT_SUPPORTED = L"%ls format string not supported"; /** * Compat swprintf, print formatted wide string. * * @param wcs Result string, maxlen long. * @param maxlen Maximum number of characters to print. * @param format Formatting string. * @param ... Formatting arguments. * @return Number of characters written or -1 on error. */ namespace std { int swprintf(wchar_t *wcs, size_t maxlen, const wchar_t *format, ...) { size_t len; string mb_format(Util::to_mb_str(format)); // Look for wide string formatting, not yet implemented. if (mb_format.find("%ls") != string::npos) { len = std::min(wcslen(SWPRINTF_LS_NOT_SUPPORTED), maxlen - 1); wmemcpy(wcs, SWPRINTF_LS_NOT_SUPPORTED, len); } else { char *res = new char[maxlen]; va_list ap; va_start(ap, format); vsnprintf(res, maxlen, mb_format.c_str(), ap); va_end(ap); wstring w_res(Util::to_wide_str(res)); len = std::min(maxlen - 1, w_res.size()); wmemcpy(wcs, w_res.c_str(), len); delete [] res; } // Null terminate and return result. wcs[len] = L'\0'; return wcslen(wcs); } } #endif // HAVE_SWPRINTF #ifndef HAVE_SETENV /** * Compat setenv, insert variable to environment. */ int setenv(const char *name, const char *value, int overwrite) { // Invalid parameters if (! name || ! value) { return -1; } // Do not overwrite if (! overwrite && getenv(name)) { return 0; } size_t len = strlen(name) + strlen(value) + 2; char *str = new char[len]; if (! str) { errno = ENOMEM; return -1; } snprintf(str, len, "%s=%s", name, value); return (putenv(str)); } #endif // ! HAVE_SETENV #ifndef HAVE_UNSETENV /** * Compat unsetenv, removes variable from the environment. */ int unsetenv(const char *name) { const char *value = getenv(name); if (value && strlen(value)) { return setenv(name, "", 1); } else { errno = EINVAL; return -1; } } #endif // ! HAVE_UNSETENV pekwm-release-0.1.18/src/Compat.hh000066400000000000000000000026701374756504400167210ustar00rootroot00000000000000// // Compat.hh for pekwm // Copyright © 2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifndef _COMPAT_HH_ #define _COMPAT_HH_ #include "config.h" #include #include #ifndef HAVE_SWPRINTF namespace std { int swprintf(wchar_t *wcs, size_t maxlen, const wchar_t *format, ...); } #endif // HAVE_SWPRINTF using std::swprintf; #ifdef HAVE_SETENV extern "C" { #include } #else // ! HAVE_SETENV int setenv(const char *name, const char *value, int overwrite); #endif // HAVE_SETENV #ifdef HAVE_UNSETENV extern "C" { #include } #else // ! HAVE_UNSETENV int unsetenv(const char *name); #endif // HAVE_UNSETENV #ifndef HAVE_TIMERSUB #define timersub(a, b, result) \ do { \ (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ if ((result)->tv_usec < 0) { \ --(result)->tv_sec; \ (result)->tv_usec += 1000000; \ } \ } while (0) #endif // HAVE_TIMERSUB #endif // _COMPAT_HH_ pekwm-release-0.1.18/src/Completer.cc000066400000000000000000000260751374756504400174230ustar00rootroot00000000000000// // Completer.cc for pekwm // Copyright © 2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "config.h" #include #include #include #include #include extern "C" { #include #include #include } #include "Completer.hh" #include "Config.hh" #include "Util.hh" #include "PWinObj.hh" #include "MenuHandler.hh" using std::copy; using std::cerr; using std::wcerr; using std::endl; using std::vector; using std::string; using std::wstring; using std::pair; /** * Build completions_list from a container of strings. */ template static void completions_list_from_name_list(T name_list, completions_list &completions_list) { completions_list.clear(); typename T::const_iterator it(name_list.begin()); for (; it != name_list.end(); ++it) { wstring name(Util::to_wide_str(*it)); wstring name_lower(name); Util::to_lower(name_lower); completions_list.push_back(pair(name_lower, name)); } std::unique(completions_list.begin(), completions_list.end()); std::sort(completions_list.begin(), completions_list.end()); } /** * Base class for completer methods, provides method to see if it * should be used and also actual completion. */ class CompleterMethod { public: /** Constructor for CompleterMethod, refresh completion list. */ CompleterMethod(void) { } /** Destructor for CompleterMethod */ virtual ~CompleterMethod(void) { } /** Find completions for string. */ virtual unsigned int complete(CompletionState &completion_state) { return 0; } /** Refresh completion list. */ virtual void refresh(void)=0; protected: /** * Find matches for word in completions_list and add to completions. */ unsigned int complete_word(completions_list &completions_list, complete_list &completions, const std::wstring &word) { unsigned int completed = 0, equality = -1; completions_it it(completions_list.begin()); for (; it != completions_list.end(); ++it) { if (it->first.size() < word.size()) { continue; } equality = it->first.compare(0, word.size(), word, 0, word.size()); if (equality == 0) { completions.push_back(it->second); completed++; } } return completed; } }; /** * Path completer, provides completion of elements in the path. */ class PathCompleterMethod : public CompleterMethod { public: /** Constructor for PathCompleter method. */ PathCompleterMethod(void) : CompleterMethod() { refresh(); } /** Destructor for PathCompleterMethod */ virtual ~PathCompleterMethod(void) { } /** * Complete str with available path elements. */ virtual unsigned int complete(CompletionState &completion_state) { return complete_word(_path_list, completion_state.completions, completion_state.word); } void refresh(void) { // Clear out previous data _path_list.clear(); vector path_parts; Util::splitString(getenv("PATH") ? getenv("PATH") : "", path_parts, ":"); vector::iterator it(path_parts.begin()); for (; it != path_parts.end(); ++it) { DIR *dh = opendir(it->c_str()); if (dh) { refresh_path(dh, Util::to_wide_str(*it)); closedir(dh); } } std::unique(_path_list.begin(), _path_list.end()); std::sort(_path_list.begin(), _path_list.end()); } private: //! Refresh single directory. void refresh_path(DIR *dh, const std::wstring path) { struct dirent *entry; while ((entry = readdir(dh)) != 0) { if (entry->d_name[0] == '.') { continue; } wstring name(Util::to_wide_str(entry->d_name)); _path_list.push_back(pair(name, name)); _path_list.push_back(pair(path + L"/" + name, path + L"/" + name)); } } completions_list _path_list; /**< List of all elements in path. */ }; /** * Action completer, provides completion of all available actions in * pekwm. */ class ActionCompleterMethod : public CompleterMethod { public: /** * States for context sensitive ActionCompleterMethod completions. */ enum State { STATE_ACTION, STATE_STATE, STATE_MENU, STATE_NO, STATE_NUM = 5 }; /** * Context match information. */ class StateMatch { public: StateMatch(State state, const wchar_t *prefix) : _prefix(prefix), _prefix_len(wcslen(prefix)), _state(state) { } State get_state(void) { return _state; } //! Check if str matches state prefix. bool is_state(const wstring &str, size_t pos) { return (str.size() - pos < _prefix_len) ? false : ! str.compare(pos, _prefix_len, _prefix, _prefix_len); } private: const wchar_t *_prefix; /**< Matching prefix */ const size_t _prefix_len; /**< */ State _state; /**< State */ }; /** Constructor for ActionCompleter method. */ ActionCompleterMethod(void) : CompleterMethod() { refresh(); } /** Destructor for ActionCompleterMethod */ virtual ~ActionCompleterMethod(void) { } virtual unsigned int complete(CompletionState &state) { State type_state = find_state(state); switch (type_state) { case STATE_STATE: return complete_word(_state_list, state.completions, state.word_lower); case STATE_MENU: return complete_word(_menu_list, state.completions, state.word_lower); case STATE_ACTION: return complete_word(_action_list, state.completions, state.word_lower); case STATE_NO: default: return 0; } } //! Build list of completions from available actions. virtual void refresh(void) { completions_list_from_name_list(Config::instance()->getActionNameList(), _action_list); completions_list_from_name_list(Config::instance()->getStateNameList(), _state_list); completions_list_from_name_list(MenuHandler::getMenuNames(), _menu_list); } private: State find_state(CompletionState &completion_state); size_t find_state_word_start(const std::wstring &str); completions_list _action_list; /**< List of all available actions. */ completions_list _state_list; /**< List of parameters to state actions. */ completions_list _menu_list; /**< List of parameters to state actions. */ static StateMatch STATE_MATCHES[]; /**< List of known states with matching data. */ }; ActionCompleterMethod::StateMatch ActionCompleterMethod::STATE_MATCHES[] = { StateMatch(ActionCompleterMethod::STATE_STATE, L"set"), StateMatch(ActionCompleterMethod::STATE_STATE, L"unset"), StateMatch(ActionCompleterMethod::STATE_STATE, L"toggle"), StateMatch(ActionCompleterMethod::STATE_MENU, L"showmenu") }; /** * Detect state being completed */ ActionCompleterMethod::State ActionCompleterMethod::find_state(CompletionState &completion_state) { if (completion_state.word_begin != 0) { for (unsigned i = 0; i < sizeof(STATE_MATCHES)/sizeof(StateMatch); ++i) { if (STATE_MATCHES[i].is_state(completion_state.part_lower, completion_state.part_begin)) { return STATE_MATCHES[i].get_state(); } } return STATE_NO; } return STATE_ACTION; } Completer::Completer(void) : _completer_action(new ActionCompleterMethod), _completer_path(new PathCompleterMethod) { } Completer::~Completer(void) { delete _completer_action; delete _completer_path; } /** * Find completions for string with the cursor at position. */ complete_list Completer::find_completions(const wstring &str, unsigned int pos) { // Get current part of str, if it is empty return no completions. CompletionState state; state.part = state.part_lower = get_part(str, pos, state.part_begin, state.part_end); if (! state.part.size()) { return state.completions; } // Get word at position, the one that will be completed state.word = state.word_lower = get_word_at_position(str, pos, state.word_begin, state.word_end); Util::to_lower(state.part_lower); Util::to_lower(state.word_lower); _completer_action->complete(state); _completer_path->complete(state); return state.completions; } /** * Perform actual completion, returns new string with completion * inserted if any. * * @param str String to complete. * @param pos Cursor position in string. * @return Completed string. */ wstring Completer::do_complete(const wstring &str, unsigned int &pos, complete_list &completions, complete_it &it) { // Do not perform completion if there is nothing to complete if (! completions.size()) { pos = str.size(); return str; } // Wrap completions, return original string if (it == completions.end()) { it = completions.begin(); pos = str.size(); return str; } // Get current word, this is the one being replaced size_t word_begin, word_end; wstring word(get_word_at_position(str, pos, word_begin, word_end)); // Replace the current word wstring completed(str); completed.replace(word_begin, word_end - word_begin, *it); // Update position pos = word_begin + it->size(); // Increment completion it++; return completed; } /** * Find current part being completed, string can be split up with * separators and only one part should be treated at a time. * * @param str String to find part in. * @param pos Position in string. * @param part_begin * @param part_end * @return Current part of string. */ wstring Completer::get_part(const wstring &str, unsigned int pos, size_t &part_begin, size_t &part_end) { // Get beginning and end of string, add 1 for removal of separator part_begin = String::safe_position(str.find_last_of(L";", pos), 0, 1); part_end = String::safe_position(str.find_first_of(L";", pos), str.size()); // Strip spaces from the beginning of the string part_begin = String::safe_position(str.find_first_not_of(L" \t", part_begin), part_end); return str.substr(part_begin, part_end - part_begin); } /** * Get word at position. */ wstring Completer::get_word_at_position(const wstring &str, unsigned int pos, size_t &word_begin, size_t &word_end) { // Get beginning and end of string, add 1 for removal of separator word_begin = String::safe_position(str.find_last_of(L" \t", pos), 0, 1); word_end = String::safe_position(str.find_first_of(L" \t", pos), str.size()); return str.substr(word_begin, word_end - word_begin); } pekwm-release-0.1.18/src/Completer.hh000066400000000000000000000033471374756504400174320ustar00rootroot00000000000000// // Completer.cc for pekwm // Copyright © 2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifndef _COMPLETER_HH_ #define _COMPLETER_HH_ #include "config.h" #include #include typedef std::vector complete_list; typedef complete_list::iterator complete_it; typedef std::vector > completions_list; typedef completions_list::iterator completions_it; /** * State data used during completion. */ class CompletionState { public: std::wstring part; std::wstring part_lower; size_t part_begin, part_end; std::wstring word; std::wstring word_lower; size_t word_begin, word_end; complete_list completions; }; class CompleterMethod; /** * Completer class, has a set of completer methods which provides * completions. Handles the string handling to detect the action, * replacing completion results etc. */ class Completer { public: /** Completer constructor */ Completer(void); /** Completer destructor. */ ~Completer(void); complete_list find_completions(const std::wstring &str, unsigned int pos); std::wstring do_complete(const std::wstring &str, unsigned int &pos, complete_list &completions, complete_it &it); private: std::wstring get_part(const std::wstring &str, unsigned int pos, size_t &part_begin, size_t &part_end); std::wstring get_word_at_position(const std::wstring &str, unsigned int pos, size_t &word_begin, size_t &word_end); CompleterMethod *_completer_action; CompleterMethod *_completer_path; }; #endif // _COMPLETER_HH_ pekwm-release-0.1.18/src/Config.cc000066400000000000000000002045071374756504400166740ustar00rootroot00000000000000// // Config.cc for pekwm // Copyright © 2002-2015 the pekwm development team // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "config.h" #include "Config.hh" #include "Compat.hh" #include "PFont.hh" #include "Util.hh" #include "Workspaces.hh" #include "x11.hh" // for DPY in keyconfig code #include #include #include extern "C" { #include #include #include } using std::cerr; using std::endl; using std::string; using std::wstring; using std::map; using std::vector; using std::pair; using std::ifstream; using std::ofstream; using std::strtol; using std::getenv; Config* Config::_instance = 0; const int FRAME_MASK = FRAME_OK|FRAME_BORDER_OK|CLIENT_OK|WINDOWMENU_OK| KEYGRABBER_OK|BUTTONCLICK_OK; const int ANY_MASK = KEYGRABBER_OK|FRAME_OK|FRAME_BORDER_OK|CLIENT_OK|ROOTCLICK_OK| BUTTONCLICK_OK|WINDOWMENU_OK|ROOTMENU_OK|SCREEN_EDGE_OK; /** * Parse width and height limits. */ bool SizeLimits::parse(const std::string &minimum, const std::string &maximum) { return (parseLimit(minimum, _limits[WIDTH_MIN], _limits[HEIGHT_MIN]) && parseLimit(maximum, _limits[WIDTH_MAX], _limits[HEIGHT_MAX])); } /** * Parse single limit. */ bool SizeLimits::parseLimit(const std::string &limit, unsigned int &min, unsigned int &max) { bool status = false; vector tokens; if ((Util::splitString(limit, tokens, "x", 2, true)) == 2) { min = strtol(tokens[0].c_str(), 0, 10); max = strtol(tokens[1].c_str(), 0, 10); status = true; } else { min = 0; max = 0; } return status; } //! @brief Constructor for Config class Config::Config(void) : _moveresize_edgeattract(0), _moveresize_edgeresist(0), _moveresize_woattract(0), _moveresize_woresist(0), _moveresize_opaquemove(0), _moveresize_opaqueresize(0), _screen_workspaces(4), _screen_workspaces_per_row(0), _screen_workspace_name_default(L"Workspace"), _screen_edge_indent(false), _screen_doubleclicktime(250), _screen_fullscreen_above(true), _screen_fullscreen_detect(true), _screen_showframelist(true), _screen_show_status_window(true), _screen_show_status_window_on_root(false), _screen_show_client_id(false), _screen_show_workspace_indicator(500), _screen_workspace_indicator_scale(16), _screen_workspace_indicator_opacity(EWMH_OPAQUE_WINDOW), _screen_place_new(true), _screen_focus_new(false), _screen_focus_new_child(true), _screen_focus_steal_protect(0), _screen_honour_randr(true), _screen_honour_aspectratio(true), _screen_placement_row(false), _screen_placement_ltr(true), _screen_placement_ttb(true), _screen_placement_offset_x(0), _screen_placement_offset_y(0), _place_trans_parent(true), _screen_client_unique_name(true), _screen_client_unique_name_pre(" #"), _screen_client_unique_name_post(""), _screen_report_all_clients(false), _menu_select_mask(0), _menu_enter_mask(0), _menu_exec_mask(0), _menu_display_icons(true), _menu_focus_opacity(EWMH_OPAQUE_WINDOW), _menu_unfocus_opacity(EWMH_OPAQUE_WINDOW), _cmd_dialog_history_unique(true), _cmd_dialog_history_size(1024), _cmd_dialog_history_file("~/.pekwm/history"), _cmd_dialog_history_save_interval(16), _harbour_da_min_s(0), _harbour_da_max_s(0), _harbour_ontop(true), _harbour_maximize_over(false), _harbour_placement(TOP), _harbour_orientation(TOP_TO_BOTTOM), _harbour_head_nr(0), _harbour_opacity(EWMH_OPAQUE_WINDOW) { if (_instance) { throw string("Config, trying to create multiple instances"); } _instance = this; for (uint i = 0; i <= SCREEN_EDGE_NO; ++i) { _screen_edge_sizes.push_back(0); } // fill parsing maps _action_map[""] = pair(ACTION_NO, 0); _action_map["Focus"] = pair(ACTION_FOCUS, ANY_MASK); _action_map["UnFocus"] = pair(ACTION_UNFOCUS, ANY_MASK); _action_map["Set"] = pair(ACTION_SET, ANY_MASK); _action_map["Unset"] = pair(ACTION_UNSET, ANY_MASK); _action_map["Toggle"] = pair(ACTION_TOGGLE, ANY_MASK); _action_map["MaxFill"] = pair(ACTION_MAXFILL, FRAME_MASK); _action_map["GrowDirection"] = pair(ACTION_GROW_DIRECTION, FRAME_MASK); _action_map["Close"] = pair(ACTION_CLOSE, FRAME_MASK); _action_map["CloseFrame"] = pair(ACTION_CLOSE_FRAME, FRAME_MASK); _action_map["Kill"] = pair(ACTION_KILL, FRAME_MASK); _action_map["SetGeometry"] = pair(ACTION_SET_GEOMETRY, FRAME_MASK); _action_map["Raise"] = pair(ACTION_RAISE, FRAME_MASK); _action_map["Lower"] = pair(ACTION_LOWER, FRAME_MASK); _action_map["ActivateOrRaise"] = pair(ACTION_ACTIVATE_OR_RAISE, FRAME_MASK); _action_map["ActivateClientRel"] = pair(ACTION_ACTIVATE_CLIENT_REL, FRAME_MASK); _action_map["MoveClientRel"] = pair(ACTION_MOVE_CLIENT_REL, FRAME_MASK); _action_map["ActivateClient"] = pair(ACTION_ACTIVATE_CLIENT, FRAME_MASK); _action_map["ActivateClientNum"] = pair(ACTION_ACTIVATE_CLIENT_NUM, KEYGRABBER_OK); _action_map["Resize"] = pair(ACTION_RESIZE, BUTTONCLICK_OK|CLIENT_OK|FRAME_OK|FRAME_BORDER_OK); _action_map["Move"] = pair(ACTION_MOVE, FRAME_OK|FRAME_BORDER_OK|CLIENT_OK); _action_map["MoveResize"] = pair(ACTION_MOVE_RESIZE, KEYGRABBER_OK); _action_map["GroupingDrag"] = pair(ACTION_GROUPING_DRAG, FRAME_OK|CLIENT_OK); _action_map["WarpToWorkspace"] = pair(ACTION_WARP_TO_WORKSPACE, SCREEN_EDGE_OK); _action_map["MoveToHead"] = pair(ACTION_MOVE_TO_HEAD, FRAME_MASK); _action_map["MoveToEdge"] = pair(ACTION_MOVE_TO_EDGE, KEYGRABBER_OK); _action_map["NextFrame"] = pair(ACTION_NEXT_FRAME, KEYGRABBER_OK|ROOTCLICK_OK|SCREEN_EDGE_OK); _action_map["PrevFrame"] = pair(ACTION_PREV_FRAME, KEYGRABBER_OK|ROOTCLICK_OK|SCREEN_EDGE_OK); _action_map["NextFrameMRU"] = pair(ACTION_NEXT_FRAME_MRU, KEYGRABBER_OK|ROOTCLICK_OK|SCREEN_EDGE_OK); _action_map["PrevFrameMRU"] = pair(ACTION_PREV_FRAME_MRU, KEYGRABBER_OK|ROOTCLICK_OK|SCREEN_EDGE_OK); _action_map["FocusDirectional"] = pair(ACTION_FOCUS_DIRECTIONAL, FRAME_MASK); _action_map["AttachMarked"] = pair(ACTION_ATTACH_MARKED, FRAME_MASK); _action_map["AttachClientInNextFrame"] = pair(ACTION_ATTACH_CLIENT_IN_NEXT_FRAME, FRAME_MASK); _action_map["AttachClientInPrevFrame"] = pair(ACTION_ATTACH_CLIENT_IN_PREV_FRAME, FRAME_MASK); _action_map["FindClient"] = pair(ACTION_FIND_CLIENT, ANY_MASK); _action_map["GotoClientID"] = pair(ACTION_GOTO_CLIENT_ID, ANY_MASK); _action_map["Detach"] = pair(ACTION_DETACH, FRAME_MASK); _action_map["SendToWorkspace"] = pair(ACTION_SEND_TO_WORKSPACE, ANY_MASK); _action_map["GoToWorkspace"] = pair(ACTION_GOTO_WORKSPACE, ANY_MASK ); _action_map["Exec"] = pair(ACTION_EXEC, FRAME_MASK|ROOTMENU_OK|ROOTCLICK_OK|SCREEN_EDGE_OK); _action_map["Reload"] = pair(ACTION_RELOAD, KEYGRABBER_OK|ROOTMENU_OK); _action_map["Restart"] = pair(ACTION_RESTART, KEYGRABBER_OK|ROOTMENU_OK); _action_map["RestartOther"] = pair(ACTION_RESTART_OTHER, KEYGRABBER_OK|ROOTMENU_OK); _action_map["Exit"] = pair(ACTION_EXIT, KEYGRABBER_OK|ROOTMENU_OK); _action_map["ShowCmdDialog"] = pair(ACTION_SHOW_CMD_DIALOG, KEYGRABBER_OK|ROOTCLICK_OK|SCREEN_EDGE_OK|ROOTMENU_OK|WINDOWMENU_OK); _action_map["ShowSearchDialog"] = pair(ACTION_SHOW_SEARCH_DIALOG, KEYGRABBER_OK|ROOTCLICK_OK|SCREEN_EDGE_OK|ROOTMENU_OK|WINDOWMENU_OK); _action_map["ShowMenu"] = pair(ACTION_SHOW_MENU, FRAME_MASK|ROOTCLICK_OK|SCREEN_EDGE_OK|ROOTMENU_OK|WINDOWMENU_OK); _action_map["HideAllMenus"] = pair(ACTION_HIDE_ALL_MENUS, FRAME_MASK|ROOTCLICK_OK|SCREEN_EDGE_OK); _action_map["SubMenu"] = pair(ACTION_MENU_SUB, ROOTMENU_OK|WINDOWMENU_OK); _action_map["Dynamic"] = pair(ACTION_MENU_DYN, ROOTMENU_OK|WINDOWMENU_OK); _action_map["SendKey"] = pair(ACTION_SEND_KEY, ANY_MASK); _action_map["SetOpacity"] = pair(ACTION_SET_OPACITY, FRAME_MASK); _action_map["LayoutOnce"] = pair(ACTION_LAYOUT_ONCE, ANY_MASK); _action_map["SetLayouter"] = pair(ACTION_SET_LAYOUTER, ANY_MASK); _action_map["SetLayouterOption"] = pair(ACTION_SET_LAYOUTER_OPTION, ANY_MASK); _action_map["Debug"] = pair(ACTION_DEBUG, ANY_MASK); _action_access_mask_map[""] = ACTION_ACCESS_NO; _action_access_mask_map["MOVE"] = ACTION_ACCESS_MOVE; _action_access_mask_map["RESIZE"] = ACTION_ACCESS_RESIZE; _action_access_mask_map["ICONIFY"] = ACTION_ACCESS_ICONIFY; _action_access_mask_map["SHADE"] = ACTION_ACCESS_SHADE; _action_access_mask_map["STICK"] = ACTION_ACCESS_STICK; _action_access_mask_map["MAXIMIZEHORIZONTAL"] = ACTION_ACCESS_MAXIMIZE_HORZ; _action_access_mask_map["MAXIMIZEVERTICAL"] = ACTION_ACCESS_MAXIMIZE_VERT; _action_access_mask_map["FULLSCREEN"] = ACTION_ACCESS_FULLSCREEN; _action_access_mask_map["SETWORKSPACE"] = ACTION_ACCESS_CHANGE_DESKTOP; _action_access_mask_map["CLOSE"] = ACTION_ACCESS_CLOSE; _edge_map[""] = NO_EDGE; _edge_map["TOPLEFT"] = TOP_LEFT; _edge_map["TOPEDGE"] = TOP_EDGE; _edge_map["TOPCENTEREDGE"] = TOP_CENTER_EDGE; _edge_map["TOPRIGHT"] = TOP_RIGHT; _edge_map["BOTTOMRIGHT"] = BOTTOM_RIGHT; _edge_map["BOTTOMEDGE"] = BOTTOM_EDGE; _edge_map["BOTTOMCENTEREDGE"] = BOTTOM_CENTER_EDGE; _edge_map["BOTTOMLEFT"] = BOTTOM_LEFT; _edge_map["LEFTEDGE"] = LEFT_EDGE; _edge_map["LEFTCENTEREDGE"] = LEFT_CENTER_EDGE; _edge_map["RIGHTEDGE"] = RIGHT_EDGE; _edge_map["RIGHTCENTEREDGE"] = RIGHT_CENTER_EDGE; _edge_map["CENTER"] = CENTER; _raise_map[""] = NO_RAISE; _raise_map["ALWAYSRAISE"] = ALWAYS_RAISE; _raise_map["ENDRAISE"] = END_RAISE; _raise_map["NEVERRAISE"] = NEVER_RAISE; _raise_map["TEMPRAISE"] = TEMP_RAISE; _skip_map[""] = SKIP_NONE; _skip_map["MENUS"] = SKIP_MENUS; _skip_map["FOCUSTOGGLE"] = SKIP_FOCUS_TOGGLE; _skip_map["SNAP"] = SKIP_SNAP; _skip_map["PAGER"] = SKIP_PAGER; _skip_map["TASKBAR"] = SKIP_TASKBAR; _layer_map[""] = LAYER_NONE; _layer_map["DESKTOP"] = LAYER_DESKTOP; _layer_map["BELOW"] = LAYER_BELOW; _layer_map["NORMAL"] = LAYER_NORMAL; _layer_map["ONTOP"] = LAYER_ONTOP; _layer_map["HARBOUR"] = LAYER_DOCK; _layer_map["ABOVEHARBOUR"] = LAYER_ABOVE_DOCK; _layer_map["MENU"] = LAYER_MENU; _moveresize_map[""] = NO_MOVERESIZE_ACTION; _moveresize_map["MOVEHORIZONTAL"] = MOVE_HORIZONTAL; _moveresize_map["MOVEVERTICAL"] = MOVE_VERTICAL; _moveresize_map["RESIZEHORIZONTAL"] = RESIZE_HORIZONTAL; _moveresize_map["RESIZEVERTICAL"] = RESIZE_VERTICAL; _moveresize_map["MOVESNAP"] = MOVE_SNAP; _moveresize_map["CANCEL"] = MOVE_CANCEL; _moveresize_map["END"] = MOVE_END; _inputdialog_map[""] = INPUT_NO_ACTION; _inputdialog_map["INSERT"] = INPUT_INSERT; _inputdialog_map["ERASE"] = INPUT_REMOVE; _inputdialog_map["CLEAR"] = INPUT_CLEAR; _inputdialog_map["CLEARFROMCURSOR"] = INPUT_CLEARFROMCURSOR; _inputdialog_map["EXEC"] = INPUT_EXEC; _inputdialog_map["CLOSE"] = INPUT_CLOSE; _inputdialog_map["COMPLETE"] = INPUT_COMPLETE; _inputdialog_map["COMPLETEABORT"] = INPUT_COMPLETE_ABORT; _inputdialog_map["CURSNEXT"] = INPUT_CURS_NEXT; _inputdialog_map["CURSPREV"] = INPUT_CURS_PREV; _inputdialog_map["CURSEND"] = INPUT_CURS_END; _inputdialog_map["CURSBEGIN"] = INPUT_CURS_BEGIN; _inputdialog_map["HISTNEXT"] = INPUT_HIST_NEXT; _inputdialog_map["HISTPREV"] = INPUT_HIST_PREV; _direction_map[""] = DIRECTION_NO; _direction_map["UP"] = DIRECTION_UP; _direction_map["DOWN"] = DIRECTION_DOWN; _direction_map["LEFT"] = DIRECTION_LEFT; _direction_map["RIGHT"] = DIRECTION_RIGHT; _workspace_change_map[""] = WORKSPACE_NO; _workspace_change_map["LEFT"] = WORKSPACE_LEFT; _workspace_change_map["LEFTN"] = WORKSPACE_LEFT_N; _workspace_change_map["PREV"] = WORKSPACE_PREV; _workspace_change_map["PREVN"] = WORKSPACE_PREV_N; _workspace_change_map["RIGHT"] = WORKSPACE_RIGHT; _workspace_change_map["RIGHTN"] = WORKSPACE_RIGHT_N; _workspace_change_map["NEXT"] = WORKSPACE_NEXT; _workspace_change_map["NEXTN"] = WORKSPACE_NEXT_N; _workspace_change_map["PREVV"] = WORKSPACE_PREV_V; _workspace_change_map["UP"] = WORKSPACE_UP; _workspace_change_map["NEXTV"] = WORKSPACE_NEXT_V; _workspace_change_map["DOWN"] = WORKSPACE_DOWN; _workspace_change_map["LAST"] = WORKSPACE_LAST; _borderpos_map[""] = BORDER_NO_POS; _borderpos_map["TOPLEFT"] = BORDER_TOP_LEFT; _borderpos_map["TOP"] = BORDER_TOP; _borderpos_map["TOPRIGHT"] = BORDER_TOP_RIGHT; _borderpos_map["LEFT"] = BORDER_LEFT; _borderpos_map["RIGHT"] = BORDER_RIGHT; _borderpos_map["BOTTOMLEFT"] = BORDER_BOTTOM_LEFT; _borderpos_map["BOTTOM"] = BORDER_BOTTOM; _borderpos_map["BOTTOMRIGHT"] = BORDER_BOTTOM_RIGHT; _mouse_event_map[""] = MOUSE_EVENT_NO; _mouse_event_map["BUTTONPRESS"] = MOUSE_EVENT_PRESS; _mouse_event_map["BUTTONRELEASE"] = MOUSE_EVENT_RELEASE; _mouse_event_map["DOUBLECLICK"] = MOUSE_EVENT_DOUBLE; _mouse_event_map["MOTION"] = MOUSE_EVENT_MOTION; _mouse_event_map["ENTER"] = MOUSE_EVENT_ENTER; _mouse_event_map["LEAVE"] = MOUSE_EVENT_LEAVE; _mouse_event_map["ENTERMOVING"] = MOUSE_EVENT_ENTER_MOVING; _mouse_event_map["MOTIONPRESSED"] = MOUSE_EVENT_MOTION_PRESSED; _mod_map[""] = 0; _mod_map["NONE"] = 0; _mod_map["SHIFT"] = ShiftMask; _mod_map["CTRL"] = ControlMask; _mod_map["MOD1"] = Mod1Mask; _mod_map["MOD2"] = Mod2Mask; _mod_map["MOD3"] = Mod3Mask; _mod_map["MOD4"] = Mod4Mask; _mod_map["MOD5"] = Mod5Mask; _mod_map["ANY"] = MOD_ANY; _action_state_map[""] = ACTION_STATE_NO; _action_state_map["Maximized"] = ACTION_STATE_MAXIMIZED; _action_state_map["Fullscreen"] = ACTION_STATE_FULLSCREEN; _action_state_map["Shaded"] = ACTION_STATE_SHADED; _action_state_map["Sticky"] = ACTION_STATE_STICKY; _action_state_map["AlwaysOnTop"] = ACTION_STATE_ALWAYS_ONTOP; _action_state_map["AlwaysBelow"] = ACTION_STATE_ALWAYS_BELOW; _action_state_map["Decor"] = ACTION_STATE_DECOR; _action_state_map["DecorBorder"] = ACTION_STATE_DECOR_BORDER; _action_state_map["DecorTitlebar"] = ACTION_STATE_DECOR_TITLEBAR; _action_state_map["Iconified"] = ACTION_STATE_ICONIFIED; _action_state_map["Tagged"] = ACTION_STATE_TAGGED; _action_state_map["Marked"] = ACTION_STATE_MARKED; _action_state_map["Skip"] = ACTION_STATE_SKIP; _action_state_map["CfgDeny"] = ACTION_STATE_CFG_DENY; _action_state_map["Opaque"] = ACTION_STATE_OPAQUE; _action_state_map["Title"] = ACTION_STATE_TITLE; _action_state_map["HarbourHidden"] = ACTION_STATE_HARBOUR_HIDDEN; _action_state_map["GlobalGrouping"] = ACTION_STATE_GLOBAL_GROUPING; _cfg_deny_map["POSITION"] = CFG_DENY_POSITION; _cfg_deny_map["SIZE"] = CFG_DENY_SIZE; _cfg_deny_map["STACKING"] = CFG_DENY_STACKING; _cfg_deny_map["ACTIVEWINDOW"] = CFG_DENY_ACTIVE_WINDOW; _cfg_deny_map["MAXIMIZEDVERT"] = CFG_DENY_STATE_MAXIMIZED_VERT; _cfg_deny_map["MAXIMIZEDHORZ"] = CFG_DENY_STATE_MAXIMIZED_HORZ; _cfg_deny_map["HIDDEN"] = CFG_DENY_STATE_HIDDEN; _cfg_deny_map["FULLSCREEN"] = CFG_DENY_STATE_FULLSCREEN; _cfg_deny_map["ABOVE"] = CFG_DENY_STATE_ABOVE; _cfg_deny_map["BELOW"] = CFG_DENY_STATE_BELOW; _cfg_deny_map["STRUT"] = CFG_DENY_STRUT; _cfg_deny_map["TILING"] = CFG_DENY_TILING; _menu_action_map[""] = ACTION_MENU_NEXT; _menu_action_map["NEXTITEM"] = ACTION_MENU_NEXT; _menu_action_map["PREVITEM"] = ACTION_MENU_PREV; _menu_action_map["SELECT"] = ACTION_MENU_SELECT; _menu_action_map["ENTERSUBMENU"] = ACTION_MENU_ENTER_SUBMENU; _menu_action_map["LEAVESUBMENU"] = ACTION_MENU_LEAVE_SUBMENU; _menu_action_map["CLOSE"] = ACTION_CLOSE; _harbour_placement_map[""] = NO_HARBOUR_PLACEMENT; _harbour_placement_map["TOP"] = TOP; _harbour_placement_map["LEFT"] = LEFT; _harbour_placement_map["RIGHT"] = RIGHT; _harbour_placement_map["BOTTOM"] = BOTTOM; _harbour_orientation_map[""] = NO_ORIENTATION; _harbour_orientation_map["TOPTOBOTTOM"] = TOP_TO_BOTTOM; _harbour_orientation_map["LEFTTORIGHT"] = TOP_TO_BOTTOM; _harbour_orientation_map["BOTTOMTOTOP"] = BOTTOM_TO_TOP; _harbour_orientation_map["RIGHTTOLEFT"] = BOTTOM_TO_TOP; // fill the mouse action map _mouse_action_map[MOUSE_ACTION_LIST_TITLE_FRAME] = new vector; _mouse_action_map[MOUSE_ACTION_LIST_TITLE_OTHER] = new vector; _mouse_action_map[MOUSE_ACTION_LIST_CHILD_FRAME] = new vector; _mouse_action_map[MOUSE_ACTION_LIST_CHILD_OTHER] = new vector; _mouse_action_map[MOUSE_ACTION_LIST_ROOT] = new vector; _mouse_action_map[MOUSE_ACTION_LIST_MENU] = new vector; _mouse_action_map[MOUSE_ACTION_LIST_OTHER] = new vector; _mouse_action_map[MOUSE_ACTION_LIST_EDGE_T] = new vector; _mouse_action_map[MOUSE_ACTION_LIST_EDGE_B] = new vector; _mouse_action_map[MOUSE_ACTION_LIST_EDGE_L] = new vector; _mouse_action_map[MOUSE_ACTION_LIST_EDGE_R] = new vector; _mouse_action_map[MOUSE_ACTION_LIST_BORDER_TL] = new vector; _mouse_action_map[MOUSE_ACTION_LIST_BORDER_T] = new vector; _mouse_action_map[MOUSE_ACTION_LIST_BORDER_TR] = new vector; _mouse_action_map[MOUSE_ACTION_LIST_BORDER_L] = new vector; _mouse_action_map[MOUSE_ACTION_LIST_BORDER_R] = new vector; _mouse_action_map[MOUSE_ACTION_LIST_BORDER_BL] = new vector; _mouse_action_map[MOUSE_ACTION_LIST_BORDER_B] = new vector; _mouse_action_map[MOUSE_ACTION_LIST_BORDER_BR] = new vector; } //! @brief Destructor for Config class Config::~Config(void) { _instance = 0; map* >::iterator it; for (it = _mouse_action_map.begin(); it != _mouse_action_map.end(); ++it) { delete it->second; } } /** * Returns an array of NULL-terminated desktop names in UTF-8. * * @param names *names will be set to an array of desktop names or 0. The caller has to delete [] *names * @param length *length will be set to the complete length of array *names points to or 0. */ void Config::getDesktopNamesUTF8(uchar **names, uint *length) const { if (! _screen_workspace_names.size()) { *names = 0; *length = 0; return; } // Convert strings to UTF-8 and calculate total length string utf8_names; vector::const_iterator it(_screen_workspace_names.begin()); for (; it != _screen_workspace_names.end(); ++it) { string utf8_name(Util::to_utf8_str(*it)); utf8_names.append(utf8_name.c_str(), utf8_name.size() + 1); } *names = new uchar[utf8_names.size()]; ::memcpy(*names, utf8_names.c_str(), utf8_names.size()); *length = utf8_names.size(); } /** * Sets the desktop names. * * @param names names is expected to point to an array of NULL-terminated utf8-strings. * @param length The length of the array "names". */ void Config::setDesktopNamesUTF8(char *names, ulong length) { _screen_workspace_names.clear(); if (! names || ! length) { return; } for (ulong i = 0; i < length;) { _screen_workspace_names.push_back(Util::from_utf8_str(names)); i += strlen(names) + 1; names += strlen(names) + 1; } } //! @brief Tries to load config_file, ~/.pekwm/config, SYSCONFDIR/config bool Config::load(const std::string &config_file) { if (! _cfg_files.requireReload(config_file)) { return false; } CfgParser cfg; _config_file = config_file; bool success = tryHardLoadConfig(cfg, _config_file); // Make sure config is reloaded next time as content is dynamically // generated from the configuration file. if (! success || cfg.isDynamicContent()) { _cfg_files.clear(); } else { _cfg_files = cfg.getCfgFiles(); } if (! success) { cerr << " *** WARNING: unable to load configuration files!" << endl; return false; } // Update PEKWM_CONFIG_FILE environment if needed (to reflect active file) char *cfg_env = getenv("PEKWM_CONFIG_FILE"); if (! cfg_env || (strcmp(cfg_env, _config_file.c_str()) != 0)) { setenv("PEKWM_CONFIG_FILE", _config_file.c_str(), 1); } string o_file_mouse; // temporary filepath for mouseconfig CfgParser::Entry *section; // Get other config files dests. section = cfg.getEntryRoot()->findSection("FILES"); if (section) { loadFiles(section); } // Parse moving / resizing options. section = cfg.getEntryRoot()->findSection("MOVERESIZE"); if (section) { loadMoveResize(section); } // Screen, important stuff such as number of workspaces section = cfg.getEntryRoot()->findSection("SCREEN"); if (section) { loadScreen(section); } section = cfg.getEntryRoot()->findSection("MENU"); if (section) { loadMenu(section); } section = cfg.getEntryRoot()->findSection("CMDDIALOG"); if (section) { loadCmdDialog(section); } section = cfg.getEntryRoot()->findSection("HARBOUR"); if (section) { loadHarbour(section); } return true; } //! @brief Loads file section of configuration //! @param section Pointer to FILES section. void Config::loadFiles(CfgParser::Entry *section) { if (! section) { return; } vector keys; keys.push_back(new CfgParserKeyPath("KEYS", _files_keys, SYSCONFDIR "/keys")); keys.push_back(new CfgParserKeyPath("MOUSE", _files_mouse, SYSCONFDIR "/mouse")); keys.push_back(new CfgParserKeyPath("MENU", _files_menu, SYSCONFDIR "/menu")); keys.push_back(new CfgParserKeyPath("START", _files_start, SYSCONFDIR "/start")); keys.push_back(new CfgParserKeyPath("AUTOPROPS", _files_autoprops, SYSCONFDIR "/autoproperties")); keys.push_back(new CfgParserKeyPath("THEME", _files_theme, DATADIR "/pekwm/themes/default/theme")); keys.push_back(new CfgParserKeyPath("ICONS", _files_icon_path, DATADIR "/pekwm/icons")); // Parse section->parseKeyValues(keys.begin(), keys.end()); // Free up resources for_each(keys.begin(), keys.end(), Util::Free()); } //! @brief Loads MOVERESIZE section of main configuration //! @param section Pointer to MOVERESIZE section. void Config::loadMoveResize(CfgParser::Entry *section) { if (! section) { return; } vector keys; keys.push_back(new CfgParserKeyNumeric("EDGEATTRACT", _moveresize_edgeattract, 0, 0)); keys.push_back(new CfgParserKeyNumeric("EDGERESIST", _moveresize_edgeresist, 0, 0)); keys.push_back(new CfgParserKeyNumeric("WINDOWATTRACT",_moveresize_woattract, 0, 0)); keys.push_back(new CfgParserKeyNumeric("WINDOWRESIST", _moveresize_woresist, 0, 0)); keys.push_back(new CfgParserKeyBool("OPAQUEMOVE", _moveresize_opaquemove)); keys.push_back(new CfgParserKeyBool("OPAQUERESIZE", _moveresize_opaqueresize)); // Parse data section->parseKeyValues(keys.begin(), keys.end()); // Free up resources for_each(keys.begin(), keys.end(), Util::Free()); } //! @brief Loads SCREEN section of main configuration //! @param section Pointer to SCREEN section. void Config::loadScreen(CfgParser::Entry *section) { if (! section) { return; } // Parse data string edge_size, workspace_names, trim_title; CfgParser::Entry *value; vector keys; keys.push_back(new CfgParserKeyNumeric("WORKSPACES", _screen_workspaces, 4, 1)); keys.push_back(new CfgParserKeyNumeric("WORKSPACESPERROW", _screen_workspaces_per_row, 0, 0)); keys.push_back(new CfgParserKeyString("WORKSPACENAMES", workspace_names)); keys.push_back(new CfgParserKeyString("EDGESIZE", edge_size)); keys.push_back(new CfgParserKeyBool("EDGEINDENT", _screen_edge_indent)); keys.push_back(new CfgParserKeyNumeric("DOUBLECLICKTIME", _screen_doubleclicktime, 250, 0)); keys.push_back(new CfgParserKeyString("TRIMTITLE", trim_title)); keys.push_back(new CfgParserKeyBool("FULLSCREENABOVE", _screen_fullscreen_above, true)); keys.push_back(new CfgParserKeyBool("FULLSCREENDETECT", _screen_fullscreen_detect, true)); keys.push_back(new CfgParserKeyBool("SHOWFRAMELIST", _screen_showframelist)); keys.push_back(new CfgParserKeyBool("SHOWSTATUSWINDOW", _screen_show_status_window)); keys.push_back(new CfgParserKeyBool("SHOWSTATUSWINDOWCENTEREDONROOT", _screen_show_status_window_on_root, false)); keys.push_back(new CfgParserKeyBool("SHOWCLIENTID", _screen_show_client_id)); keys.push_back(new CfgParserKeyNumeric("SHOWWORKSPACEINDICATOR", _screen_show_workspace_indicator, 500, 0)); keys.push_back(new CfgParserKeyNumeric("WORKSPACEINDICATORSCALE", _screen_workspace_indicator_scale, 16, 2)); keys.push_back(new CfgParserKeyNumeric("WORKSPACEINDICATOROPACITY", _screen_workspace_indicator_opacity, 100, 0, 100)); keys.push_back(new CfgParserKeyBool("PLACENEW", _screen_place_new)); keys.push_back(new CfgParserKeyBool("FOCUSNEW", _screen_focus_new)); keys.push_back(new CfgParserKeyBool("FOCUSNEWCHILD", _screen_focus_new_child, true)); keys.push_back(new CfgParserKeyNumeric("FOCUSSTEALPROTECT", _screen_focus_steal_protect, 0)); keys.push_back(new CfgParserKeyBool("HONOURRANDR", _screen_honour_randr, true)); keys.push_back(new CfgParserKeyBool("HONOURASPECTRATIO", _screen_honour_aspectratio, true)); keys.push_back(new CfgParserKeyBool("REPORTALLCLIENTS", _screen_report_all_clients, false)); // Parse data section->parseKeyValues(keys.begin(), keys.end()); // Free up resources for_each(keys.begin(), keys.end(), Util::Free()); keys.clear(); PFont::setTrimString(trim_title); // Convert opacity from percent to absolute value CONV_OPACITY(_screen_workspace_indicator_opacity); int edge_size_all = 0; _screen_edge_sizes.clear(); if (edge_size.size()) { vector sizes; if (Util::splitString(edge_size, sizes, " \t", 4) == 4) { for (vector::iterator it(sizes.begin()); it != sizes.end(); ++it) { _screen_edge_sizes.push_back(strtol(it->c_str(), 0, 10)); } } else { edge_size_all = strtol(edge_size.c_str(), 0, 10); } } for (uint i = 0; i < SCREEN_EDGE_NO; ++i) { _screen_edge_sizes.push_back(edge_size_all); } // Add SCREEN_EDGE_NO to the list for safety _screen_edge_sizes.push_back(0); // Workspace names _screen_workspace_names.clear(); vector vs; if (Util::splitString(workspace_names, vs, ";", 0, true)) { vector::iterator vs_it(vs.begin()); for (; vs_it != vs.end(); ++vs_it) { _screen_workspace_names.push_back(Util::to_wide_str(*vs_it)); } } CfgParser::Entry *sub = section->findSection("PLACEMENT"); if (sub) { value = sub->findEntry("MODEL"); if (value) { Workspace::setDefaultLayouter(value->getValue()); } value = sub->findEntry("WORKSPACEPLACEMENTS"); if (value) { vs.clear(); if (Util::splitString(value->getValue(), vs, ";", 0, true)) { for (uint i = 0; i < vs.size(); ++i) { Workspaces::setLayouter(i, vs[i]); } } } CfgParser::Entry *sub_2 = sub->findSection("SMART"); if (sub_2) { keys.push_back(new CfgParserKeyBool("ROW", _screen_placement_row)); keys.push_back(new CfgParserKeyBool("LEFTTORIGHT", _screen_placement_ltr)); keys.push_back(new CfgParserKeyBool("TOPTOBOTTOM", _screen_placement_ttb)); keys.push_back(new CfgParserKeyNumeric("OFFSETX", _screen_placement_offset_x, 0, 0)); keys.push_back(new CfgParserKeyNumeric("OFFSETY", _screen_placement_offset_y, 0, 0)); // Do the parsing sub_2->parseKeyValues(keys.begin(), keys.end()); // Freeup resources for_each(keys.begin(), keys.end(), Util::Free()); keys.clear(); } keys.push_back(new CfgParserKeyBool("TRANSIENTONPARENT", _place_trans_parent, true)); sub->parseKeyValues(keys.begin(), keys.end()); for_each(keys.begin(), keys.end(), Util::Free()); keys.clear(); } sub = section->findSection("UNIQUENAMES"); if (sub) { keys.push_back(new CfgParserKeyBool("SETUNIQUE", _screen_client_unique_name)); keys.push_back(new CfgParserKeyString("PRE", _screen_client_unique_name_pre)); keys.push_back(new CfgParserKeyString("POST", _screen_client_unique_name_post)); // Parse data sub->parseKeyValues(keys.begin(), keys.end()); // Free up resources for_each(keys.begin(), keys.end(), Util::Free()); keys.clear(); } } //! @brief Loads the MENU section of the main configuration //! @param section Pointer to MENU section void Config::loadMenu(CfgParser::Entry *section) { if (! section) { return; } vector keys; string value_select, value_enter, value_exec; keys.push_back(new CfgParserKeyString("SELECT", value_select, "MOTION", 0)); keys.push_back(new CfgParserKeyString("ENTER", value_enter, "BUTTONPRESS", 0)); keys.push_back(new CfgParserKeyString("EXEC", value_exec, "BUTTONRELEASE", 0)); keys.push_back(new CfgParserKeyBool("DISPLAYICONS", _menu_display_icons, true)); keys.push_back(new CfgParserKeyNumeric("FOCUSOPACITY", _menu_focus_opacity, 100, 0, 100)); keys.push_back(new CfgParserKeyNumeric("UNFOCUSOPACITY", _menu_unfocus_opacity, 100, 0, 100)); // Parse data section->parseKeyValues(keys.begin(), keys.end()); _menu_select_mask = getMenuMask(value_select); _menu_enter_mask = getMenuMask(value_enter); _menu_exec_mask = getMenuMask(value_exec); // Free up resources for_each(keys.begin(), keys.end(), Util::Free()); keys.clear(); // Parse icon size limits CfgParser::iterator it(section->begin()); for (; it != section->end(); ++it) { if (*(*it) == "ICONS") { loadMenuIcons((*it)->getSection()); } } // Convert opacity from percent to absolute value CONV_OPACITY(_menu_focus_opacity); CONV_OPACITY(_menu_unfocus_opacity); } /** * Load Icon size limits for menu. */ void Config::loadMenuIcons(CfgParser::Entry *section) { if (! section || ! section->getValue().size()) { return; } vector keys; string minimum, maximum; keys.push_back(new CfgParserKeyString("MINIMUM", minimum, "16x16", 3)); keys.push_back(new CfgParserKeyString("MAXIMUM", maximum, "16x16", 3)); // Parse data section->parseKeyValues(keys.begin(), keys.end()); for_each(keys.begin(), keys.end(), Util::Free()); SizeLimits limits; if (limits.parse(minimum, maximum)) { _menu_icon_limits[section->getValue()] = limits; } } /** * Load configuration from CmdDialog section. */ void Config::loadCmdDialog(CfgParser::Entry *section) { if (! section) { return; } vector keys; keys.push_back(new CfgParserKeyBool("HISTORYUNIQUE", _cmd_dialog_history_unique)); keys.push_back(new CfgParserKeyNumeric("HISTORYSIZE", _cmd_dialog_history_size, 1024, 1)); keys.push_back(new CfgParserKeyPath("HISTORYFILE", _cmd_dialog_history_file, "~/.pekwm/history")); keys.push_back(new CfgParserKeyNumeric("HISTORYSAVEINTERVAL", _cmd_dialog_history_save_interval, 16, 0)); section->parseKeyValues(keys.begin(), keys.end()); for_each(keys.begin(), keys.end(), Util::Free()); } //! @brief Loads the HARBOUR section of the main configuration void Config::loadHarbour(CfgParser::Entry *section) { if (! section) { return; } vector keys; string value_placement, value_orientation; keys.push_back(new CfgParserKeyBool("ONTOP", _harbour_ontop, true)); keys.push_back(new CfgParserKeyBool("MAXIMIZEOVER", _harbour_maximize_over, false)); keys.push_back(new CfgParserKeyNumeric("HEAD", _harbour_head_nr, 0, 0)); keys.push_back(new CfgParserKeyString("PLACEMENT", value_placement, "RIGHT", 0)); keys.push_back(new CfgParserKeyString("ORIENTATION", value_orientation, "TOPTOBOTTOM", 0)); keys.push_back(new CfgParserKeyNumeric("OPACITY", _harbour_opacity, 100, 0, 100)); // Parse data section->parseKeyValues(keys.begin(), keys.end()); // Free up resources for_each(keys.begin(), keys.end(), Util::Free()); keys.clear(); // Convert opacity from percent to absolute value CONV_OPACITY(_harbour_opacity); _harbour_placement = ParseUtil::getValue(value_placement, _harbour_placement_map); _harbour_orientation = ParseUtil::getValue(value_orientation, _harbour_orientation_map); if (_harbour_placement == NO_HARBOUR_PLACEMENT) { _harbour_placement = RIGHT; } if (_harbour_orientation == NO_ORIENTATION) { _harbour_orientation = TOP_TO_BOTTOM; } CfgParser::Entry *sub = section->findSection("DOCKAPP"); if (sub) { keys.push_back(new CfgParserKeyNumeric("SIDEMIN", _harbour_da_min_s, 64, 0)); keys.push_back(new CfgParserKeyNumeric("SIDEMAX", _harbour_da_max_s, 64, 0)); // Parse data sub->parseKeyValues(keys.begin(), keys.end()); // Free up resources for_each(keys.begin(), keys.end(), Util::Free()); keys.clear(); } } //! @brief ActionType Config::getAction(const std::string &name, uint mask) { pair val(ParseUtil::getValue >(name, _action_map)); if ((val.first != ACTION_NO) && (val.second&mask)) { return val.first; } return ACTION_NO; } ActionAccessMask Config::getActionAccessMask(const std::string &name) { ActionAccessMask mask = ParseUtil::getValue(name, _action_access_mask_map); return mask; } //! @brief bool Config::parseKey(const std::string &key_string, uint &mod, uint &key) { // used for parsing vector tok; vector::iterator it; uint num; // chop the string up separating mods and the end key/button if (Util::splitString(key_string, tok, " \t")) { num = tok.size() - 1; if ((tok[num].size() > 1) && (tok[num][0] == '#')) { key = strtol(tok[num].c_str() + 1, 0, 10); } else if (strcasecmp(tok[num].c_str(), "ANY") == 0) { // Do no matching, anything goes. key = 0; } else { KeySym keysym = XStringToKeysym(tok[num].c_str()); // XStringToKeysym() may fail. Perhaps we have luck after some // simple transformations. First we convert the string to lowercase // and try again. Then we try with only the first character in // uppercase and at last we try a complete uppercase string. If all // fails, we print a warning and return false. if (keysym == NoSymbol) { string str = tok[num]; Util::to_lower(str); keysym = XStringToKeysym(str.c_str()); if (keysym == NoSymbol) { str[0] = ::toupper(str[0]); keysym = XStringToKeysym(str.c_str()); if (keysym == NoSymbol) { Util::to_upper(str); keysym = XStringToKeysym(str.c_str()); if (keysym == NoSymbol) { cerr << " *** WARNING: Couldn't find keysym for " << tok[num] << endl; return false; } } } } key = XKeysymToKeycode(X11::getDpy(), keysym); } // if the last token isn't an key/button, the action isn't valid if ((key != 0) || (strcasecmp(tok[num].c_str(), "ANY") == 0)) { tok.pop_back(); // remove the key/button // add the modifier mod = 0; for (it = tok.begin(); it != tok.end(); ++it) { mod |= getMod(*it); } return true; } } return false; } bool Config::parseButton(const std::string &button_string, uint &mod, uint &button) { // used for parsing vector tok; vector::iterator it; // chop the string up separating mods and the end key/button if (Util::splitString(button_string, tok, " \t")) { // if the last token isn't an key/button, the action isn't valid button = getMouseButton(tok[tok.size() - 1]); if (button != BUTTON_NO) { tok.pop_back(); // remove the key/button // add the modifier mod = 0; uint tmp_mod; for (it = tok.begin(); it != tok.end(); ++it) { tmp_mod = getMod(*it); if (tmp_mod == MOD_ANY) { mod = MOD_ANY; break; } else { mod |= tmp_mod; } } return true; } } return false; } //! @brief Parse a single action and fills action. //! @param action_string String representation of action. //! @param action Action structure to fill in. //! @param mask Mask action is valid for. //! @return true on success, else false bool Config::parseAction(const std::string &action_string, Action &action, uint mask) { vector tok; // chop the string up separating the action and parameters if (Util::splitString(action_string, tok, " \t", 2)) { action.setAction(getAction(tok[0], mask)); if (action.getAction() != ACTION_NO) { if (tok.size() == 2) { // we got enough tok for a parameter switch (action.getAction()) { case ACTION_EXEC: case ACTION_RESTART_OTHER: case ACTION_FIND_CLIENT: case ACTION_SHOW_CMD_DIALOG: case ACTION_SHOW_SEARCH_DIALOG: case ACTION_SEND_KEY: case ACTION_MENU_DYN: case ACTION_LAYOUT_ONCE: case ACTION_SET_LAYOUTER: case ACTION_SET_LAYOUTER_OPTION: case ACTION_DEBUG: action.setParamS(tok[1]); break; case ACTION_SET_GEOMETRY: // Add optional head parameter, -1 means screen. Util::splitString(tok[1], tok, " \t", 2); if (tok.size() == 4) { action.setParamS(tok[2]); action.setParamI(0, strtol(tok[3].c_str(), 0, 10)); } else { action.setParamS(tok[1]); action.setParamI(0, -1); } break; case ACTION_ACTIVATE_CLIENT_REL: case ACTION_MOVE_CLIENT_REL: case ACTION_GOTO_CLIENT_ID: case ACTION_MOVE_TO_HEAD: action.setParamI(0, strtol(tok[1].c_str(), 0, 10)); break; case ACTION_SET: case ACTION_UNSET: case ACTION_TOGGLE: parseActionState(action, tok[1]); break; case ACTION_MAXFILL: if ((Util::splitString(tok[1], tok, " \t", 2)) == 2) { action.setParamI(0, Util::isTrue(tok[tok.size() - 2])); action.setParamI(1, Util::isTrue(tok[tok.size() - 1])); } else { cerr << "*** WARNING: Missing argument to MaxFill." << endl; } break; case ACTION_GROW_DIRECTION: action.setParamI(0, ParseUtil::getValue(tok[1], _direction_map)); break; case ACTION_ACTIVATE_CLIENT_NUM: action.setParamI(0, strtol(tok[1].c_str(), 0, 10) - 1); if (action.getParamI(0) < 0) { cerr << "*** WARNING: Negative number to ActivateClientNum." << endl; action.setParamI(0, 0); } break; case ACTION_WARP_TO_WORKSPACE: case ACTION_SEND_TO_WORKSPACE: case ACTION_GOTO_WORKSPACE: action.setParamI(0, parseWorkspaceNumber(tok[1])); break; case ACTION_GROUPING_DRAG: action.setParamI(0, Util::isTrue(tok[1])); break; case ACTION_MOVE_TO_EDGE: action.setParamI(0, ParseUtil::getValue(tok[1], _edge_map)); break; case ACTION_NEXT_FRAME: case ACTION_NEXT_FRAME_MRU: case ACTION_PREV_FRAME: case ACTION_PREV_FRAME_MRU: if ((Util::splitString(tok[1], tok, " \t", 2)) == 2) { action.setParamI(0, ParseUtil::getValue(tok[tok.size() - 2], _raise_map)); action.setParamI(1, Util::isTrue(tok[tok.size() - 1])); } else { action.setParamI(0, ParseUtil::getValue(tok[1], _raise_map)); action.setParamI(1, false); } break; case ACTION_FOCUS_DIRECTIONAL: if ((Util::splitString(tok[1], tok, " \t", 2)) == 2) { action.setParamI(0, ParseUtil::getValue(tok[tok.size() - 2], _direction_map)); action.setParamI(1, Util::isTrue(tok[tok.size() - 1])); // raise? } else { action.setParamI(0, ParseUtil::getValue(tok[1], _direction_map)); action.setParamI(1, true); // default to raise } break; case ACTION_RESIZE: action.setParamI(0, 1 + ParseUtil::getValue(tok[1], _borderpos_map)); break; case ACTION_RAISE: case ACTION_LOWER: if ((Util::splitString(tok[1], tok, " \t", 1)) == 1) { action.setParamI(0, Util::isTrue(tok[tok.size() - 1])); } else { action.setParamI(0, false); } break; case ACTION_SHOW_MENU: if ((Util::splitString(tok[1], tok, " \t", 2)) == 2) { Util::to_upper(tok[tok.size() - 2]); action.setParamS(tok[tok.size() - 2]); action.setParamI(0, Util::isTrue(tok[tok.size() - 1])); } else { Util::to_upper(tok[1]); action.setParamS(tok[1]); action.setParamI(0, false); // Default to non-sticky } break; case ACTION_SET_OPACITY: if ((Util::splitString(tok[1], tok, " \t", 2)) == 2) { action.setParamI(0, std::atoi(tok[tok.size() - 2].c_str())); action.setParamI(1, std::atoi(tok[tok.size() - 1].c_str())); } else { action.setParamI(0, std::atoi(tok[1].c_str())); action.setParamI(1, std::atoi(tok[1].c_str())); } break; default: // do nothing break; } } else { switch (action.getAction()) { case ACTION_MAXFILL: action.setParamI(0, 1); action.setParamI(1, 1); break; default: // do nothing break; } } return true; } } return false; } bool Config::parseActionAccessMask(const std::string &action_mask, uint &mask) { mask = ACTION_ACCESS_NO; vector tok; if (Util::splitString(action_mask, tok, " \t")) { vector::iterator it(tok.begin()); for (; it != tok.end(); ++it) { mask |= getActionAccessMask(*it); } } return true; } //! @brief bool Config::parseActionState(Action &action, const std::string &as_action) { vector tok; // chop the string up separating the action and parameters if (Util::splitString(as_action, tok, " \t", 2)) { action.setParamI(0, ParseUtil::getValue(tok[0], _action_state_map)); if (action.getParamI(0) != ACTION_STATE_NO) { if (tok.size() == 2) { // we got enough tok for a parameter string directions; switch (action.getParamI(0)) { case ACTION_STATE_MAXIMIZED: // Using copy of token here to silence valgrind checks. directions = tok[1]; Util::splitString(directions, tok, " \t", 2); if (tok.size() == 4) { action.setParamI(1, Util::isTrue(tok[2])); action.setParamI(2, Util::isTrue(tok[3])); } else { cerr << "*** WARNING: Missing argument to Maximized." << endl; } break; case ACTION_STATE_TAGGED: action.setParamI(1, Util::isTrue(tok[1])); break; case ACTION_STATE_SKIP: action.setParamI(1, getSkip(tok[1])); break; case ACTION_STATE_CFG_DENY: action.setParamI(1, getCfgDeny(tok[1])); break; case ACTION_STATE_DECOR: case ACTION_STATE_TITLE: action.setParamS(tok[1]); break; }; } else { switch (action.getParamI(0)) { case ACTION_STATE_MAXIMIZED: action.setParamI(1, 1); action.setParamI(2, 1); break; default: // do nothing break; } } return true; } } return false; } //! @brief bool Config::parseActions(const std::string &action_string, ActionEvent &ae, uint mask) { vector tok; vector::iterator it; Action action; // reset the action event ae.action_list.clear(); // chop the string up separating the actions if (Util::splitString(action_string, tok, ";", 0, false, '\\')) { for (it = tok.begin(); it != tok.end(); ++it) { if (parseAction(*it, action, mask)) { ae.action_list.push_back(action); action.clear(); } } return true; } return false; } //! @brief bool Config::parseActionEvent(CfgParser::Entry *section, ActionEvent &ae, uint mask, bool button) { CfgParser::Entry *value = section->findEntry("ACTIONS"); if (! value && section->getSection()) { value = section->getSection()->findEntry("ACTIONS"); } if (! value) { return false; } string str_button = section->getValue(); if (! str_button.size()) { if ((ae.type == MOUSE_EVENT_ENTER) || (ae.type == MOUSE_EVENT_LEAVE)) { str_button = "1"; } else { return false; } } bool ok; if (button) { ok = parseButton(str_button, ae.mod, ae.sym); } else { ok = parseKey(str_button, ae.mod, ae.sym); } if (ok) { return parseActions(value->getValue(), ae, mask); } return false; } //! @brief bool Config::parseMoveResizeAction(const std::string &action_string, Action &action) { vector tok; // Chop the string up separating the actions. if (Util::splitString(action_string, tok, " \t", 2)) { action.setAction(ParseUtil::getValue(tok[0], _moveresize_map)); if (action.getAction() != NO_MOVERESIZE_ACTION) { if (tok.size() == 2) { // we got enough tok for a paremeter switch (action.getAction()) { case MOVE_HORIZONTAL: case MOVE_VERTICAL: case RESIZE_HORIZONTAL: case RESIZE_VERTICAL: case MOVE_SNAP: action.setParamI(0, strtol(tok[1].c_str(), 0, 10)); break; default: // Do nothing. break; } } return true; } } return false; } //! @brief bool Config::parseMoveResizeActions(const std::string &action_string, ActionEvent& ae) { vector tok; vector::iterator it; Action action; // reset the action event ae.action_list.clear(); // chop the string up separating the actions if (Util::splitString(action_string, tok, ";")) { for (it = tok.begin(); it != tok.end(); ++it) { if (parseMoveResizeAction(*it, action)) { ae.action_list.push_back(action); action.clear(); } } return true; } return false; } //! @brief Parses MoveResize Event. bool Config::parseMoveResizeEvent(CfgParser::Entry *section, ActionEvent& ae) { CfgParser::Entry *value; if (! section->getValue().size ()) { return false; } if (parseKey(section->getValue(), ae.mod, ae.sym)) { value = section->getSection()->findEntry("ACTIONS"); if (value) { return parseMoveResizeActions(value->getValue(), ae); } } return false; } //! @brief bool Config::parseInputDialogAction(const std::string &val, Action &action) { action.setAction(ParseUtil::getValue(val, _inputdialog_map)); return (action.getAction() != INPUT_NO_ACTION); } //! @brief bool Config::parseInputDialogActions(const std::string &actions, ActionEvent &ae) { vector tok; vector::iterator it; Action action; string::size_type first, last; // reset the action event ae.action_list.clear(); // chop the string up separating the actions if (Util::splitString(actions, tok, ";")) { for (it = tok.begin(); it != tok.end(); ++it) { first = (*it).find_first_not_of(" \t\n"); if (first == string::npos) continue; last = (*it).find_last_not_of(" \t\n"); (*it) = (*it).substr(first, last-first+1); if (parseInputDialogAction(*it, action)) { ae.action_list.push_back(action); action.clear(); } } return true; } return false; } //! @brief Parses InputDialog Event. bool Config::parseInputDialogEvent(CfgParser::Entry *section, ActionEvent &ae) { CfgParser::Entry *value; if (! section->getValue().size()) { return false; } if (parseKey(section->getValue(), ae.mod, ae.sym)) { value = section->getSection()->findEntry("ACTIONS"); if (value) { return parseInputDialogActions(value->getValue(), ae); } } return false; } /** * Get mask for handling menu events. */ uint Config::getMenuMask(const std::string &mask) { uint mask_return = 0, val; vector tok; Util::splitString(mask, tok, " \t"); vector::iterator it(tok.begin()); for (; it != tok.end(); ++it) { val = ParseUtil::getValue(*it, _mouse_event_map); if (val != MOUSE_EVENT_NO) { mask_return |= val; } } return mask_return; } //! @brief bool Config::parseMenuAction(const std::string &action_string, Action &action) { vector tok; // chop the string up separating the actions if (Util::splitString(action_string, tok, " \t", 2)) { action.setAction(ParseUtil::getValue(tok[0], _menu_action_map)); if (action.getAction() != ACTION_NO) { return true; } } return false; } //! @brief bool Config::parseMenuActions(const std::string &actions, ActionEvent &ae) { vector tok; vector::iterator it; Action action; // reset the action event ae.action_list.clear(); // chop the string up separating the actions if (Util::splitString(actions, tok, ";", 0, false, '\\')) { for (it = tok.begin(); it != tok.end(); ++it) { if (parseMenuAction(*it, action)) { ae.action_list.push_back(action); action.clear(); } } return true; } return false; } //! @brief Parses MenuEvent. bool Config::parseMenuEvent(CfgParser::Entry *section, ActionEvent& ae) { CfgParser::Entry *value; if (! section->getValue().size()) { return false; } if (parseKey(section->getValue(), ae.mod, ae.sym)) { value = section->getSection()->findEntry("ACTIONS"); if (value) { return parseMenuActions(value->getValue(), ae); } } return false; } //! @brief uint Config::getMouseButton(const std::string &button) { uint btn; if (button.size() == 1 || button.size() == 2) { // it's a button btn = unsigned(strtol(button.c_str(), 0, 10)); } else if (strcasecmp(button.c_str(), "ANY") == 0) { // any button btn = BUTTON_ANY; } else { btn = BUTTON_NO; } if (btn > BUTTON_NO) { btn = BUTTON_NO; } return btn; } /** * Load main configuration file, priority as follows: * * 1. Load command line specified file. * 2. Load ~/.pekwm/config * 3. Copy configuration and load ~/.pekwm/config * 4. Load system configuration */ bool Config::tryHardLoadConfig(CfgParser &cfg, std::string &file) { bool success = false; // Try loading command line specified file. if (file.size()) { success = cfg.parse(file, CfgParserSource::SOURCE_FILE, true); } // Try loading ~/.pekwm/config if (! success) { file = string(getenv("HOME")) + string("/.pekwm/config"); success = cfg.parse(file, CfgParserSource::SOURCE_FILE, true); // Copy cfg files to ~/.pekwm and try loading ~/.pekwm/config again. if (! success) { copyConfigFiles(); success = cfg.parse(file, CfgParserSource::SOURCE_FILE, true); } } // Try loading system configuration files. if (! success) { file = string(SYSCONFDIR "/config"); success = cfg.parse(file, CfgParserSource::SOURCE_FILE, true); } return success; } //! @brief Populates the ~/.pekwm/ dir with config files void Config::copyConfigFiles(void) { string cfg_dir = getenv("HOME") + string("/.pekwm"); string cfg_file = cfg_dir + string("/config"); string keys_file = cfg_dir + string("/keys"); string mouse_file = cfg_dir + string("/mouse"); string menu_file = cfg_dir + string("/menu"); string autoprops_file = cfg_dir + string("/autoproperties"); string start_file = cfg_dir + string("/start"); string vars_file = cfg_dir + string("/vars"); string themes_dir = cfg_dir + string("/themes"); bool cp_config, cp_keys, cp_mouse, cp_menu; bool cp_autoprops, cp_start, cp_vars; bool make_themes = false; cp_config = cp_keys = cp_mouse = cp_menu = false; cp_autoprops = cp_start = cp_vars = false; struct stat stat_buf; // check and see if we already have a ~/.pekwm/ directory if (stat(cfg_dir.c_str(), &stat_buf) == 0) { // is it a dir or file? if (! S_ISDIR(stat_buf.st_mode)) { cerr << cfg_dir << " already exists and isn't a directory" << endl << "Can't copy config files !" << endl; return; } // we already have a directory, see if it's writeable and executable bool cfg_dir_ok = false; if (getuid() == stat_buf.st_uid) { if ((stat_buf.st_mode&S_IWUSR) && (stat_buf.st_mode&(S_IXUSR))) { cfg_dir_ok = true; } } if (! cfg_dir_ok) { if (getgid() == stat_buf.st_gid) { if ((stat_buf.st_mode&S_IWGRP) && (stat_buf.st_mode&(S_IXGRP))) { cfg_dir_ok = true; } } } if (! cfg_dir_ok) { if (! (stat_buf.st_mode&S_IWOTH) || ! (stat_buf.st_mode&(S_IXOTH))) { cerr << "You don't have the rights to add files to the: " << cfg_dir << " directory! Therefor I can't copy the config files!" << endl; return; } } // we apparently could write and exec that dir, now see if we have any // files in it if (stat(cfg_file.c_str(), &stat_buf)) cp_config = true; if (stat(keys_file.c_str(), &stat_buf)) cp_keys = true; if (stat(mouse_file.c_str(), &stat_buf)) cp_mouse = true; if (stat(menu_file.c_str(), &stat_buf)) cp_menu = true; if (stat(autoprops_file.c_str(), &stat_buf)) cp_autoprops = true; if (stat(start_file.c_str(), &stat_buf)) cp_start = true; if (stat(vars_file.c_str(), &stat_buf)) cp_vars = true; if (stat(themes_dir.c_str(), &stat_buf)) { make_themes = true; } } else { // we didn't have a ~/.pekwm directory already, lets create one if (mkdir(cfg_dir.c_str(), 0700)) { cerr << "Can't create " << cfg_dir << " directory!" << endl; cerr << "Can't copy config files !" << endl; return; } cp_config = cp_keys = cp_mouse = cp_menu = true; cp_autoprops = cp_start = cp_vars = true; make_themes = true; } if (cp_config) { Util::copyTextFile(SYSCONFDIR "/config", cfg_file); } if (cp_keys) { Util::copyTextFile(SYSCONFDIR "/keys", keys_file); } if (cp_mouse) { Util::copyTextFile(SYSCONFDIR "/mouse", mouse_file); } if (cp_menu) { Util::copyTextFile(SYSCONFDIR "/menu", menu_file); } if (cp_autoprops) { Util::copyTextFile(SYSCONFDIR "/autoproperties", autoprops_file); } if (cp_start) { Util::copyTextFile(SYSCONFDIR "/start", start_file); } if (cp_vars) { Util::copyTextFile(SYSCONFDIR "/vars", vars_file); } if (make_themes) { mkdir(themes_dir.c_str(), 0700); } } /** * Parses mouse configuration file. */ bool Config::loadMouseConfig(const std::string &mouse_file) { if (! _cfg_files_mouse.requireReload(mouse_file)) { return false; } CfgParser mouse_cfg; if (! mouse_cfg.parse(mouse_file, CfgParserSource::SOURCE_FILE, true) && ! mouse_cfg.parse(SYSCONFDIR "/mouse", CfgParserSource::SOURCE_FILE, true)) { _cfg_files_mouse.clear(); return false; } if (mouse_cfg.isDynamicContent()) { _cfg_files_mouse.clear(); } else { _cfg_files_mouse = mouse_cfg.getCfgFiles(); } // Make sure old actions get unloaded. map* >::iterator it; for (it = _mouse_action_map.begin(); it != _mouse_action_map.end(); ++it) { it->second->clear(); } CfgParser::Entry *section; section = mouse_cfg.getEntryRoot()->findSection("FRAMETITLE"); if (section) { parseButtons(section, _mouse_action_map[MOUSE_ACTION_LIST_TITLE_FRAME], FRAME_OK); } section = mouse_cfg.getEntryRoot()->findSection("OTHERTITLE"); if (section) { parseButtons(section, _mouse_action_map[MOUSE_ACTION_LIST_TITLE_OTHER], FRAME_OK); } section = mouse_cfg.getEntryRoot()->findSection("CLIENT"); if (section) { parseButtons(section, _mouse_action_map[MOUSE_ACTION_LIST_CHILD_FRAME], CLIENT_OK); } section = mouse_cfg.getEntryRoot()->findSection("ROOT"); if (section) { parseButtons(section, _mouse_action_map[MOUSE_ACTION_LIST_ROOT], ROOTCLICK_OK); } section = mouse_cfg.getEntryRoot()->findSection("MENU"); if (section) { parseButtons(section, _mouse_action_map[MOUSE_ACTION_LIST_MENU], FRAME_OK); } section = mouse_cfg.getEntryRoot()->findSection("OTHER"); if (section) { parseButtons(section, _mouse_action_map[MOUSE_ACTION_LIST_OTHER], FRAME_OK); } section = mouse_cfg.getEntryRoot()->findSection("SCREENEDGE"); if (section) { CfgParser::iterator edge_it(section->begin()); for (; edge_it != section->end(); ++edge_it) { uint pos = ParseUtil::getValue((*edge_it)->getName(), _direction_map); if (pos != SCREEN_EDGE_NO) { parseButtons((*edge_it)->getSection(), getEdgeListFromPosition(pos), SCREEN_EDGE_OK); } } } section = mouse_cfg.getEntryRoot()->findSection("BORDER"); if (section) { CfgParser::iterator border_it(section->begin()); for (; border_it != section->end(); ++border_it) { uint pos = ParseUtil::getValue((*border_it)->getName(), _borderpos_map); if (pos != BORDER_NO_POS) { parseButtons((*border_it)->getSection(), getBorderListFromPosition(pos), FRAME_BORDER_OK); } } } return true; } //! @brief Parses mouse config section, like FRAME void Config::parseButtons(CfgParser::Entry *section, vector* mouse_list, ActionOk action_ok) { if (! section || ! mouse_list) { return; } ActionEvent ae; CfgParser::Entry *value; CfgParser::iterator it(section->begin()); for (; it != section->end(); ++it) { if (! (*it)->getSection()) { continue; } ae.type = ParseUtil::getValue((*it)->getName(), _mouse_event_map); if (ae.type == MOUSE_EVENT_NO) { continue; } if (ae.type == MOUSE_EVENT_MOTION) { value = (*it)->getSection()->findEntry("THRESHOLD"); if (value) { ae.threshold = strtol(value->getValue().c_str(), 0, 10); } else { ae.threshold = 0; } } if (parseActionEvent((*it), ae, action_ok, true)) { mouse_list->push_back(ae); } } } // frame border configuration vector* Config::getBorderListFromPosition(uint pos) { vector *ret = 0; switch (pos) { case BORDER_TOP_LEFT: ret = _mouse_action_map[MOUSE_ACTION_LIST_BORDER_TL]; break; case BORDER_TOP: ret = _mouse_action_map[MOUSE_ACTION_LIST_BORDER_T]; break; case BORDER_TOP_RIGHT: ret = _mouse_action_map[MOUSE_ACTION_LIST_BORDER_TR]; break; case BORDER_LEFT: ret = _mouse_action_map[MOUSE_ACTION_LIST_BORDER_L]; break; case BORDER_RIGHT: ret = _mouse_action_map[MOUSE_ACTION_LIST_BORDER_R]; break; case BORDER_BOTTOM_LEFT: ret = _mouse_action_map[MOUSE_ACTION_LIST_BORDER_BL]; break; case BORDER_BOTTOM: ret = _mouse_action_map[MOUSE_ACTION_LIST_BORDER_B]; break; case BORDER_BOTTOM_RIGHT: ret = _mouse_action_map[MOUSE_ACTION_LIST_BORDER_BR]; break; } return ret; } vector* Config::getEdgeListFromPosition(uint pos) { vector *ret = 0; switch (pos) { case SCREEN_EDGE_TOP: ret = _mouse_action_map[MOUSE_ACTION_LIST_EDGE_T]; break; case SCREEN_EDGE_BOTTOM: ret = _mouse_action_map[MOUSE_ACTION_LIST_EDGE_B]; break; case SCREEN_EDGE_LEFT: ret = _mouse_action_map[MOUSE_ACTION_LIST_EDGE_L]; break; case SCREEN_EDGE_RIGHT: ret = _mouse_action_map[MOUSE_ACTION_LIST_EDGE_R]; break; }; return ret; } //! @brief Parses workspace number int Config::parseWorkspaceNumber(const std::string &workspace) { // Get workspace looking for relative numbers uint num = ParseUtil::getValue(workspace, _workspace_change_map); if (num == WORKSPACE_NO) { // Workspace isn't relative, check for 2x2 and ordinary specification vector tok; if (Util::splitString(workspace, tok, "x", 2, true) == 2) { uint row = strtol(tok[0].c_str(), 0, 10) - 1; uint col = strtol(tok[1].c_str(), 0, 10) - 1; num = _screen_workspaces_per_row * row + col; } else { num = strtol(workspace.c_str(), 0, 10) - 1; } } return num; } //! @brief Parses a string which contains two opacity values bool Config::parseOpacity(const std::string value, uint &focused, uint &unfocused) { std::vector tokens; switch ((Util::splitString(value, tokens, " ,", 2))) { case 2: focused = std::atoi(tokens.at(0).c_str()); unfocused = std::atoi(tokens.at(1).c_str()); break; case 1: focused = unfocused = std::atoi(tokens.at(0).c_str()); break; default: return false; } CONV_OPACITY(focused); CONV_OPACITY(unfocused); return true; } pekwm-release-0.1.18/src/Config.hh000066400000000000000000000373461374756504400167130ustar00rootroot00000000000000// // Config.hh for pekwm // Copyright © 2002-2016 the pekwm development team // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifndef _CONFIG_HH_ #define _CONFIG_HH_ #include "config.h" #include "pekwm.hh" #include "Action.hh" #include "CfgParser.hh" #include "ParseUtil.hh" #include #include #include /** * Enum describing the different limits of a size limit. */ enum SizeLimitType { WIDTH_MIN = 0, WIDTH_MAX, HEIGHT_MIN, HEIGHT_MAX }; /** * Simple class describing size limitations, width and height min and * max sizes. */ class SizeLimits { public: /** SizeLimits constructor setting limits to 0. */ SizeLimits(void) { for (unsigned int i = 0; i < HEIGHT_MAX; ++i) { _limits[i] = 0; } } /** Get limit for limit type. */ unsigned int get(SizeLimitType limit) const { return _limits[limit]; } bool parse(const std::string &minimum, const std::string &maximum); private: bool parseLimit(const std::string &limit, unsigned int &min, unsigned int &max); private: unsigned int _limits[HEIGHT_MAX + 1]; /**< Limits. */ }; // CONV_OPACITY converts percentage to absolute opacity values. // The variable X containing the percent value is changed directly. #define CONV_OPACITY(X)\ X = (X == 100)?EWMH_OPAQUE_WINDOW:X*(EWMH_OPAQUE_WINDOW/100) /** * Large set of configuration options stored and parsed by the * singleton Config class. */ class Config { public: Config(void); ~Config(void); static Config* instance(void) { return _instance; } bool load(const std::string &config_file); bool loadMouseConfig(const std::string &mouse_file); inline const std::string &getConfigFile(void) const { return _config_file; } /** Return vector with available keyboard actions names. */ vector getActionNameList(void) { vector action_names; std::map >::iterator it; for (it = _action_map.begin(); it != _action_map.end(); ++it) { if (it->second.second&KEYGRABBER_OK) { action_names.push_back(it->first.get_text()); } } return action_names; } /** Return vector with available state action names. */ vector getStateNameList(void) { vector state_names; std::map::iterator it; for (it = _action_state_map.begin(); it != _action_state_map.end(); ++it) { state_names.push_back(it->first.get_text()); } return state_names; } // Files const std::string &getKeyFile(void) const { return _files_keys; } const std::string &getMenuFile(void) const { return _files_menu; } const std::string &getStartFile(void) const { return _files_start; } const std::string &getAutoPropsFile(void) const { return _files_autoprops; } const std::string &getThemeFile(void) const { return _files_theme; } const std::string &getMouseConfigFile(void) const { return _files_mouse; } const std::string &getIconPath(void) const { return _files_icon_path; } const char *getSystemIconPath(void) const { return DATADIR "/pekwm/icons/"; } // Moveresize inline int getEdgeAttract(void) const { return _moveresize_edgeattract; } inline int getEdgeResist(void) const { return _moveresize_edgeresist; } inline int getWOAttract(void) const { return _moveresize_woattract; } inline int getWOResist(void) const { return _moveresize_woresist; } inline bool getOpaqueMove(void) const { return _moveresize_opaquemove; } inline bool getOpaqueResize(void) const { return _moveresize_opaqueresize; } // Screen inline int getWorkspaces(void) const { return _screen_workspaces; } inline int getWorkspacesPerRow(void) const { return _screen_workspaces_per_row; } void getDesktopNamesUTF8(uchar **names, uint *length) const; const std::wstring &getWorkspaceName(uint num) const { return (num >= _screen_workspace_names.size())?_screen_workspace_name_default: _screen_workspace_names[num]; } void setDesktopNamesUTF8(char *names, ulong length); inline int getScreenEdgeSize(EdgeType edge) const { return _screen_edge_sizes[edge]; } inline bool getScreenEdgeIndent(void) const { return _screen_edge_indent; } inline int getDoubleClickTime(void) const { return _screen_doubleclicktime; } inline bool isFullscreenAbove(void) const { return _screen_fullscreen_above; } inline bool isFullscreenDetect(void) const { return _screen_fullscreen_detect; } inline bool getShowFrameList(void) const { return _screen_showframelist; } inline bool isShowStatusWindow(void) const { return _screen_show_status_window; } bool isShowStatusWindowOnRoot(void) const { return _screen_show_status_window_on_root; } inline bool isShowClientID(void) const { return _screen_show_client_id; } int getShowWorkspaceIndicator(void) const { return _screen_show_workspace_indicator; } int getWorkspaceIndicatorScale(void) const { return _screen_workspace_indicator_scale; } inline uint getWorkspaceIndicatorOpacity(void) const { return _screen_workspace_indicator_opacity; } inline bool isPlaceNew(void) const { return _screen_place_new; } inline bool isFocusNew(void) const { return _screen_focus_new; } inline bool isFocusNewChild(void) const { return _screen_focus_new_child; } inline uint getFocusStealProtect(void) const { return _screen_focus_steal_protect; } inline bool isHonourRandr(void) const { return _screen_honour_randr; } inline bool isHonourAspectRatio(void) const { return _screen_honour_aspectratio; } inline bool placeTransOnParent(void) const { return _place_trans_parent; } inline bool getPlacementRow(void) const { return _screen_placement_row; } inline bool getPlacementLtR(void) const { return _screen_placement_ltr; } inline bool getPlacementTtB(void) const { return _screen_placement_ttb; } inline int getPlacementOffsetX(void) const { return _screen_placement_offset_x; } inline int getPlacementOffsetY(void) const { return _screen_placement_offset_y; } inline bool getClientUniqueName(void) const { return _screen_client_unique_name; } inline const std::string &getClientUniqueNamePre(void) const { return _screen_client_unique_name_pre; } inline const std::string &getClientUniqueNamePost(void) const { return _screen_client_unique_name_post; } inline bool isReportAllClients(void) const { return _screen_report_all_clients; } inline bool isMenuSelectOn(uint val) const { return (_menu_select_mask&val); } inline bool isMenuEnterOn(uint val) const { return (_menu_enter_mask&val); } inline bool isMenuExecOn(uint val) const { return (_menu_exec_mask&val); } bool isDisplayMenuIcons(void) const { return _menu_display_icons; } inline uint getMenuFocusOpacity(void) const { return _menu_focus_opacity; } inline uint getMenuUnfocusOpacity(void) const { return _menu_unfocus_opacity; } bool isCmdDialogHistoryUnique(void) const { return _cmd_dialog_history_unique; } int getCmdDialogHistorySize(void) const { return _cmd_dialog_history_size; } const std::string &getCmdDialogHistoryFile(void) const { return _cmd_dialog_history_file; } int getCmdDialogHistorySaveInterval(void) const { return _cmd_dialog_history_save_interval; } inline int getHarbourDAMinSide(void) const { return _harbour_da_min_s; } inline int getHarbourDAMaxSide(void) const { return _harbour_da_max_s; } inline int getHarbourHead(void) const { return _harbour_head_nr; } inline bool isHarbourOntop(void) const { return _harbour_ontop; } inline bool isHarbourMaximizeOver(void) const { return _harbour_maximize_over; } inline uint getHarbourPlacement(void) const { return _harbour_placement; } inline uint getHarbourOrientation(void) const { return _harbour_orientation; } inline uint getHarbourOpacity(void) const { return _harbour_opacity; } inline vector *getMouseActionList(MouseActionListName name) { return _mouse_action_map[name]; } vector *getBorderListFromPosition(uint pos); vector *getEdgeListFromPosition(uint pos); // map parsing ActionType getAction(const std::string &name, uint mask); ActionAccessMask getActionAccessMask(const std::string &name); inline Layer getLayer(const std::string &layer) { return ParseUtil::getValue(layer, _layer_map); } inline Skip getSkip(const std::string &skip) { return ParseUtil::getValue(skip, _skip_map); } inline CfgDeny getCfgDeny(const std::string &deny) { return ParseUtil::getValue(deny, _cfg_deny_map); } bool parseKey(const std::string &key_string, uint& mod, uint &key); bool parseButton(const std::string &button_string, uint &mod, uint &button); bool parseAction(const std::string &action_string, Action &action, uint mask); bool parseActionAccessMask(const std::string &action_mask_string, uint &mask); bool parseActionState(Action &action, const std::string &st_action); bool parseActions(const std::string &actions, ActionEvent &ae, uint mask); bool parseActionEvent(CfgParser::Entry *section, ActionEvent &ae, uint mask, bool button); bool parseMoveResizeAction(const std::string &action_string, Action &action); bool parseMoveResizeActions(const std::string &actions, ActionEvent &ae); bool parseMoveResizeEvent(CfgParser::Entry *section, ActionEvent &ae); bool parseInputDialogAction(const std::string &val, Action &action); bool parseInputDialogActions(const std::string &actions, ActionEvent &ae); bool parseInputDialogEvent(CfgParser::Entry *section, ActionEvent &ae); uint getMenuMask(const std::string &mask); /** Return maximum allowed icon width. */ unsigned int getMenuIconLimit(unsigned int value, SizeLimitType limit, const std::string &name) const { unsigned int limit_val = 0; std::map::const_iterator it(_menu_icon_limits.find(name)); if (it == _menu_icon_limits.end()) { if (name == "DEFAULT") { limit_val = 16; } else { limit_val = getMenuIconLimit(value, limit, "DEFAULT"); } } else { limit_val = it->second.get(limit); } return limit_val ? limit_val : value; } bool parseMenuAction(const std::string& action_string, Action& action); bool parseMenuActions(const std::string& actions, ActionEvent& ae); bool parseMenuEvent(CfgParser::Entry *section, ActionEvent& ae); inline uint getMod(const std::string &mod) { return ParseUtil::getValue(mod, _mod_map); } uint getMouseButton(const std::string& button); static bool parseOpacity(const std::string value, uint &focused, uint &unfocused); private: bool tryHardLoadConfig(CfgParser &cfg, std::string &file); void copyConfigFiles(void); void loadFiles(CfgParser::Entry *section); void loadMoveResize(CfgParser::Entry *section); void loadScreen(CfgParser::Entry *section); void loadMenu(CfgParser::Entry *section); void loadMenuIcons(CfgParser::Entry *section); void loadCmdDialog(CfgParser::Entry *section); void loadHarbour(CfgParser::Entry *section); void parseButtons(CfgParser::Entry *section, vector* mouse_list, ActionOk action_ok); int parseWorkspaceNumber(const std::string &workspace); std::string _config_file; /**< Path to config file last loaded. */ TimeFiles _cfg_files; TimeFiles _cfg_files_mouse; // files std::string _files_keys, _files_menu; std::string _files_start, _files_autoprops; std::string _files_theme, _files_mouse; std::string _files_icon_path; /**< Path to user icon directory. */ // moveresize int _moveresize_edgeattract, _moveresize_edgeresist; int _moveresize_woattract, _moveresize_woresist; bool _moveresize_opaquemove, _moveresize_opaqueresize; // screen int _screen_workspaces; int _screen_workspaces_per_row; vector _screen_workspace_names; std::wstring _screen_workspace_name_default; vector _screen_edge_sizes; bool _screen_edge_indent; int _screen_doubleclicktime; bool _screen_fullscreen_above; //!< Flag to make fullscreen go above all windows. */ bool _screen_fullscreen_detect; /**< Flag to make configure request fullscreen detection. */ bool _screen_showframelist; bool _screen_show_status_window; bool _screen_show_status_window_on_root; /**< If true, center status window relative to current head. */ bool _screen_show_client_id; //!< Flag to display client ID in title. int _screen_show_workspace_indicator; //!< Display workspace indicator for N seconds. int _screen_workspace_indicator_scale; //!< Scale of the workspace indicator head uint _screen_workspace_indicator_opacity; bool _screen_place_new, _screen_focus_new, _screen_focus_new_child; uint _screen_focus_steal_protect; /**< Number of seconds to protect against focus stealing. */ bool _screen_honour_randr; /**< Boolean flag if randr information should be honoured. */ bool _screen_honour_aspectratio; /**< if true, pekwm keeps aspect ratio (XSizeHint) */ bool _screen_placement_row, _screen_placement_ltr, _screen_placement_ttb; int _screen_placement_offset_x, _screen_placement_offset_y; bool _place_trans_parent; bool _screen_client_unique_name; std::string _screen_client_unique_name_pre, _screen_client_unique_name_post; bool _screen_report_all_clients; uint _menu_select_mask, _menu_enter_mask, _menu_exec_mask; bool _menu_display_icons; /**< Boolean flag, when true display icons in menus. */ uint _menu_focus_opacity, _menu_unfocus_opacity; std::map _menu_icon_limits; /**< Map of name -> limit for icons in menus */ bool _cmd_dialog_history_unique; /**< Boolean flag, when true entries in the CmdDialog history are unique. */ int _cmd_dialog_history_size; /**< Number of entries in the history before the last entries are dropped. */ std::string _cmd_dialog_history_file; /**< Path to cmd dialog history file. */ int _cmd_dialog_history_save_interval; /**< Save history file each Nth CmdDialog exec. */ int _harbour_da_min_s, _harbour_da_max_s; bool _harbour_ontop; bool _harbour_maximize_over; uint _harbour_placement; uint _harbour_orientation; int _harbour_head_nr; uint _harbour_opacity; std::map* > _mouse_action_map; std::map > _action_map; std::map _action_access_mask_map; std::map _edge_map; std::map _raise_map; std::map _skip_map; std::map _layer_map; std::map _moveresize_map; std::map _inputdialog_map; std::map _direction_map; std::map _workspace_change_map; std::map _borderpos_map; std::map _mouse_event_map; std::map _mod_map; std::map _action_state_map; std::map _cfg_deny_map; std::map _menu_action_map; std::map _harbour_placement_map; std::map _harbour_orientation_map; static Config *_instance; /**< Singleton Config pointer. */ }; #endif // _CONFIG_HH_ pekwm-release-0.1.18/src/Debug.cc000066400000000000000000000110421374756504400165030ustar00rootroot00000000000000// // Debug.cc for pekwm // Copyright © 2012 Andreas Schlick // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "pekwm.hh" #include "Debug.hh" #include "Util.hh" #include #if defined(__GLIBC__) && defined(__GLIBCXX__) #include #include #endif // __GLIBC__ && __GLIBCXX__ /** * Debug Commands: * * enable [logfile|cerr] - enable logging to [logfile|std::cerr] * disable [logfile|cerr] - disable logging to [logfile|std::cerr] * toggle [logfile|cerr] - toggle logging to [logfile|std::cerr] * logfile - open filename as the logfile * (this always closes the old logfile) * dump - write all stored log messages to the logfile * maxmsgs - log the current maximum number of stored messages * maxmsgs - sets the maximum of stored messages (in RAM) to nr * */ void Debug::doAction(const std::string &cmd) { vector args; uint nr = Util::splitString(cmd, args, " \t"); if (nr) Util::to_lower(args[0]); if (nr == 1) { if (args[0] == "dump") { if (! _log.is_open()) return; _log << "--- DUMPING LOG ---" << std::endl; for (unsigned i=0; i < _msgs.size(); ++i) { _log << i << ".) " << _msgs[i] << std::endl; } } else if (args[0] == "maxmsgs") { _log << "Currently are " << _max_msgs << " log entries stored." << std::endl; } return; } if (nr == 2) { if (args[0] == "enable") { if (args[1] == "logfile") { enable_logfile = true; } else if (args[1] == "cerr") { enable_cerr = true; } } else if (args[0] == "disable") { if (args[1] == "logfile") { enable_logfile = false; } else if (args[1] == "cerr") { enable_cerr = false; } } else if (args[0] == "toggle") { if (args[1] == "logfile") { enable_logfile = ! enable_logfile; } else if (args[1] == "cerr") { enable_cerr = ! enable_cerr; } } else if (args[0] == "logfile") { setLogFile(args[1].c_str()); if (! _log.is_open()) { enable_logfile = false; } } else if (args[0] == "maxmsgs") { int nr = std::atoi(args[1].c_str()); if (nr>=0) { _max_msgs = nr; if (_msgs.size() > _max_msgs) { _msgs.erase(_msgs.begin(), _msgs.begin() + _msgs.size() - _max_msgs); } } else { WARN("Debug command \"maxmsgs\" called with wrong parameter."); } } return; } } #if defined(__GLIBC__) && defined(__GLIBCXX__) static const char *demangle_cpp(const char *str, char **dest, size_t *len) { int status=1; const char *begin = strchr(str, '('), *end; if (begin && *(++begin) && *begin != '+') { end = strchr(begin, '+'); if (end) { char *buf = new char[end-begin+1]; memcpy(buf, begin, end-begin); buf[end-begin] = 0; *dest = abi::__cxa_demangle(buf, *dest, len, &status); delete[] buf; } } return status?str:*dest; } void Debug::logBacktrace(DebugBTObj &dobj) { void *btbuffer[100]; char *name=0, **str=0; size_t len=0; int size = backtrace(btbuffer, 100); if (! size) { dobj << "Generating backtrace failed!"; return; } str = backtrace_symbols(btbuffer, size); if (! str) { dobj << "Translating backtrace failed!"; return; } // The first entry is always Debug::logBacktrace(), // so we begin with i=1. for (int i=1; i Debug::_msgs; std::vector::size_type Debug::_max_msgs = 32; const std::string Debug::_msg_info(" *INFO* "); const std::string Debug::_msg_warn(" *WARNING* "); const std::string Debug::_msg_err(" *ERROR* "); const std::string Debug::_msg_bt(" *BACKTRACE* "); unsigned int DebugFuncCall::_depth=0; pekwm-release-0.1.18/src/Debug.hh000066400000000000000000000076061374756504400165300ustar00rootroot00000000000000// // Debug.hh for pekwm // Copyright © 2012-2013 Andreas Schlick // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifndef _PEKWM_DEBUG_HH_ #define _PEKWM_DEBUG_HH_ #include "config.h" #include #define ___PEKDEBUG_START __PRETTY_FUNCTION__ << '@' << __LINE__ \ << ":\n\t" << std::showbase << std::hex #ifdef DEBUG #include #include #include #include class DebugBTObj; class Debug { public: static void doAction(const std::string &); static bool enable_cerr; static bool enable_logfile; static void setLogFile(const char *f) { _log.close(); _log.open(f); } static void addLog(const std::string s) { if (_msgs.size() >= _max_msgs) { _msgs.erase(_msgs.begin()); } _msgs.push_back(s); if (enable_logfile) { _log << s << std::endl; } if (enable_cerr) { std::cerr << s << std::endl; } } static void addInfo(const std::string s) { addLog(_msg_info + s); } static void addWarn(const std::string s) { addLog(_msg_warn + s); } static void addErr(const std::string s) { addLog(_msg_err + s); } static void addBT(const std::string s) { addLog(_msg_bt + s); } static void logBacktrace(DebugBTObj &); private: static std::ofstream _log; static std::vector _msgs; static std::vector::size_type _max_msgs; static const std::string _msg_info, _msg_warn, _msg_err, _msg_bt; }; class DebugInfoObj : public std::stringstream { public: virtual ~DebugInfoObj() { Debug::addInfo(str()); } }; class DebugWarnObj : public std::stringstream { public: virtual ~DebugWarnObj() { Debug::addWarn(str()); } }; class DebugErrObj : public std::stringstream { public: virtual ~DebugErrObj() { Debug::addErr(str()); } }; class DebugBTObj : public std::stringstream { public: virtual ~DebugBTObj() { Debug::addBT(str()); } }; class DebugFuncCall { public: DebugFuncCall(const char *func) : _fname(func) { logName(); ++_depth; } ~DebugFuncCall() { --_depth; } private: void logName(void) { std::string msg("FCall: "); for (unsigned int i=0; i < _depth; ++i) msg += " "; msg += "+-" + _fname; Debug::addLog(msg); } std::string _fname; static unsigned int _depth; }; #define LOG_CALL() DebugFuncCall ___PEKDEBUG_VAR##__FUNCTION__(__PRETTY_FUNCTION__) #define LOG(M) do { DebugInfoObj dobj; dobj << ___PEKDEBUG_START << M; } while (0) #define LOG_IF(C, M) do { if (C) { DebugInfoObj dobj; dobj << ___PEKDEBUG_START << M; } } while (0) #define LOG_IFE(C, M1, M2) do { DebugInfoObj dobj; dobj << ___PEKDEBUG_START << ((C)?M1:M2); } while (0) #define WARN(M) do { DebugWarnObj dobj; dobj << ___PEKDEBUG_START << M; } while (0) #define ERR(M) do { DebugErrObj dobj; dobj << ___PEKDEBUG_START << M; } while (0) #define ERR_IF(C, M) do { if (C) { DebugErrObj dobj; dobj << ___PEKDEBUG_START << M; } } while (0) #define BACKTRACEM(M) do { DebugBTObj dobj; dobj << __FILE__ << '@' << __LINE__ << ": " << std::hex \ << std::showbase << M << '\n'; Debug::logBacktrace(dobj); } while (0) #define BACKTRACE() BACKTRACEM("\n") #else #define LOG_CALL() do { (void)0; } while (0) #define LOG(M) do { (void)0; } while (0) #define LOG_IF(C,M) do { (void)0; } while (0) #define LOG_IFE(C, M1, M2) do { (void)0; } while (0) #define WARN(M) do { std::cerr << " *WARNING* " << ___PEKDEBUG_START << M << std::endl; } while (0) #define ERR(M) do { std::cerr << " *ERROR* " << ___PEKDEBUG_START << M << std::endl; } while (0) #define ERR_IF(C, M) do { if (C) { std::cerr << " *ERROR* " << ___PEKDEBUG_START << M << std::endl; } } while (0) #define BACKTRACEM(M) do { (void)0; } while (0) #define BACKTRACE() do { (void)0; } while (0) #endif // DEBUG #endif // _PEKWM_DEBUG_HH_ pekwm-release-0.1.18/src/DockApp.cc000066400000000000000000000175451374756504400170140ustar00rootroot00000000000000// // Dockapp.cc for pekwm // Copyright © 2003-2016 the pekwm development team // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "config.h" #include "PWinObj.hh" #include "DockApp.hh" #include "Config.hh" #include "x11.hh" #include "PTexture.hh" #include "PDecor.hh" #include "Theme.hh" #include "AutoProperties.hh" #include "WindowManager.hh" extern "C" { #include } const uint DOCKAPP_DEFAULT_SIDE = 64; const uint DOCKAPP_BORDER_WIDTH = 2; //! @brief DockApp constructor DockApp::DockApp(Window win) : PWinObj(false), _dockapp_window(win), _client_window(win), _icon_window(None), _position(0), _background(None), _is_alive(true) { Config *cfg = Config::instance(); // PWinObj attributes. _type = WO_DOCKAPP; _iconified = true; // We set ourself iconified for workspace switching. _sticky = true; // First, we need to figure out which window that actually belongs to the // dockapp. This we do by checking if it has the IconWindowHint set in it's // WM Hint. XWMHints *wm_hints = XGetWMHints(X11::getDpy(), _dockapp_window); if (wm_hints) { if ((wm_hints->flags&IconWindowHint) && (wm_hints->icon_window != None)) { // let us hide the _client_window window, as we won't use it. X11::unmapWindow(_client_window); _icon_window = wm_hints->icon_window; _dockapp_window = wm_hints->icon_window; } XFree(wm_hints); } // Now, when we now what window id we should use, set the size up. XWindowAttributes attr; if (XGetWindowAttributes(X11::getDpy(), _dockapp_window, &attr)) { _c_gm.width = attr.width; _c_gm.height = attr.height; _gm.width = attr.width; _gm.height = attr.height; } else { // Didn't get any size from the dockapp, use default if (cfg->getHarbourDAMinSide() > 0) { _c_gm.width = cfg->getHarbourDAMinSide(); _c_gm.height = cfg->getHarbourDAMinSide(); } else { _c_gm.width = DOCKAPP_DEFAULT_SIDE - DOCKAPP_BORDER_WIDTH * 2; _c_gm.height = DOCKAPP_DEFAULT_SIDE - DOCKAPP_BORDER_WIDTH * 2; } _gm.width = _c_gm.width; _gm.height = _c_gm.height; } // make sure size is valid and position the dockapp updateSize(); // Okie, now lets create it's parent window which is going to hold the border XSetWindowAttributes sattr; sattr.override_redirect = True; sattr.event_mask = SubstructureRedirectMask|ButtonPressMask|ButtonMotionMask; _window = XCreateWindow(X11::getDpy(), X11::getRoot(), _gm.x, _gm.y, _gm.width, _gm.height, 0, CopyFromParent, InputOutput, CopyFromParent, CWOverrideRedirect|CWEventMask, &sattr); // initial makeup repaint(); XSetWindowBorderWidth(X11::getDpy(), _dockapp_window, 0); // move the dockapp to it's new parent, making sure we don't // get any UnmapEvents X11::selectInput(_dockapp_window, NoEventMask); XReparentWindow(X11::getDpy(), _dockapp_window, _window, _c_gm.x, _c_gm.y); X11::selectInput(_dockapp_window, SubstructureNotifyMask); readClassHint(); readAutoProperties(); } //! @brief DockApp destructor DockApp::~DockApp(void) { // if the client still is alive, we should reparent it to the root // window, else we don't have to care about that. if (_is_alive) { X11::grabServer(); if (_icon_window != None) { X11::unmapWindow(_icon_window); } // move the dockapp back to the root window, making sure we don't // get any UnmapEvents X11::selectInput(_dockapp_window, NoEventMask); XReparentWindow(X11::getDpy(), _dockapp_window, X11::getRoot(), _gm.x, _gm.y); X11::mapWindow(_client_window); X11::ungrabServer(false); } X11::freePixmap(_background); XDestroyWindow(X11::getDpy(), _window); } // START - PWinObj interface. //! @brief Maps the DockApp void DockApp::mapWindow(void) { if (_mapped) { return; } _mapped = true; X11::selectInput(_dockapp_window, NoEventMask); X11::mapWindow(_window); X11::mapWindow(_dockapp_window); X11::selectInput(_dockapp_window, StructureNotifyMask|SubstructureNotifyMask); } //! @brief Unmaps the DockApp void DockApp::unmapWindow(void) { if (! _mapped) { return; } _mapped = false; X11::selectInput(_dockapp_window, NoEventMask); X11::unmapWindow(_dockapp_window); X11::unmapWindow(_window); X11::selectInput(_dockapp_window, StructureNotifyMask|SubstructureNotifyMask); } // END - PWinObj interface. //! @brief Kills the DockApp void DockApp::kill(void) { XKillClient(X11::getDpy(), _dockapp_window); } //! @brief Resizes the DockApp, size excludes the border. //! @todo Make sure it's inside the screen! void DockApp::resize(uint width, uint height) { if ((_c_gm.width == width) && (_c_gm.height == height)) { return; } _c_gm.width = width; _c_gm.height = height; updateSize(); XMoveResizeWindow(X11::getDpy(), _window, _gm.x, _gm.y, _gm.width, _gm.height); XMoveResizeWindow(X11::getDpy(), _dockapp_window, _c_gm.x, _c_gm.y, _c_gm.width, _c_gm.height); repaint(); } //! @brief Loads the current theme and repaints the DockApp. void DockApp::loadTheme(void) { // Note, here we are going to check if the DockApp borderwidth have // changed etc in the future but for now we'll only have to repaint it repaint(); } //! @brief Repaints the DockApp's background. void DockApp::repaint(void) { X11::freePixmap(_background); _background = X11::createPixmap(_gm.width, _gm.height); WindowManager::instance()->getTheme()->getHarbourData()->getTexture()->render(_background, 0, 0, _gm.width, _gm.height); XSetWindowBackgroundPixmap(X11::getDpy(), _window, _background); XClearWindow(X11::getDpy(), _window); } //! @brief Validates geometry and centers the window void DockApp::updateSize(void) { // resize the window holding the dockapp _gm.width = _c_gm.width + DOCKAPP_BORDER_WIDTH * 2; _gm.height = _c_gm.height + DOCKAPP_BORDER_WIDTH * 2; // resize validateSize(); // position the dockapp _c_gm.x = (_gm.width - _c_gm.width) / 2; _c_gm.y = (_gm.height - _c_gm.height) / 2; } //! @brief Makes sure DockApp conforms to SideMin and SideMax void DockApp::validateSize(void) { Config *cfg = Config::instance(); // convenience if (cfg->getHarbourDAMinSide() > 0) { if (_gm.width < static_cast(cfg->getHarbourDAMinSide())) { _gm.width = cfg->getHarbourDAMinSide(); } if (_gm.height < static_cast(cfg->getHarbourDAMinSide())) { _gm.height = cfg->getHarbourDAMinSide(); } } if (cfg->getHarbourDAMaxSide() > 0) { if (_gm.width > static_cast(cfg->getHarbourDAMaxSide())) { _gm.width = cfg->getHarbourDAMaxSide(); } if (_gm.height > static_cast(cfg->getHarbourDAMaxSide())) { _gm.height = cfg->getHarbourDAMaxSide(); } } } //! @brief Reads XClassHint of client. void DockApp::readClassHint(void) { XClassHint x_class_hint; if (XGetClassHint(X11::getDpy(), _client_window, &x_class_hint)) { _class_hint.h_name = Util::to_wide_str(x_class_hint.res_name); _class_hint.h_class = Util::to_wide_str(x_class_hint.res_class); XFree(x_class_hint.res_name); XFree(x_class_hint.res_class); } } //! @brief Reads DockApp AutoProperties. void DockApp::readAutoProperties(void) { DockAppProperty *prop = AutoProperties::instance()->findDockAppProperty(&_class_hint); if (prop) { _position = prop->getPosition(); } } pekwm-release-0.1.18/src/DockApp.hh000066400000000000000000000036451374756504400170220ustar00rootroot00000000000000// // DockApp.hh for pekwm // Copyright © 2003-2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifndef _DOCKAPP_HH_ #define _DOCKAPP_HH_ #include "config.h" #include "pekwm.hh" #include "AutoProperties.hh" class Theme; class PWinObj; //! @brief DockApp handling class. class DockApp : public PWinObj { public: DockApp(Window win); ~DockApp(void); // START - PWinObj interface. virtual void mapWindow(void); virtual void unmapWindow(void); // END - PWinObj interface. //! @brief Returns DockApp client width. inline uint getClientWidth(void) const { return _c_gm.width; } //! @brief Returns DockApp client height. inline uint getClientHeight(void) const { return _c_gm.height; } //! @brief Returns DockApp position. inline int getPosition(void) const { return _position; } //! @brief Sets alive state of DockApp. inline void setAlive(bool alive) { _is_alive = alive; } //! @brief Matches win against DockApp client window(s). inline bool findDockApp(Window win) { if ((win != None) && ((win == _client_window) || (win == _icon_window))) { return true; } return false; } //! @brief Matches win against DockApp window. inline bool findDockAppFromFrame(Window win) { if ((win != None) && (win == _window)) return true; return false; } void kill(void); void resize(uint width, uint height); void loadTheme(void); private: void repaint(void); void updateSize(void); void validateSize(void); void readClassHint(void); void readAutoProperties(void); Window _dockapp_window; Window _client_window, _icon_window; ClassHint _class_hint; Geometry _c_gm; int _position; // used in sorted mode Pixmap _background; bool _is_alive; }; #endif // _DOCKAPP_HH_ pekwm-release-0.1.18/src/Exception.hh000066400000000000000000000011761374756504400174340ustar00rootroot00000000000000// // PDecor.hh for pekwm // Copyright © 2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifndef _EXCEPTION_H_ #define _EXCEPTION_H_ #include "config.h" /** * Exception thrown when loading of a file/data fails. */ class LoadException { public: LoadException(const char *resource) : _resource(resource) { } virtual ~LoadException(void) { } /** Get resource string. */ const char *getResource(void) const { return _resource; } private: const char *_resource; /**< Resource that failed to load. */ }; #endif // _EXCEPTION_H_ pekwm-release-0.1.18/src/FontHandler.cc000066400000000000000000000160531374756504400176700ustar00rootroot00000000000000// // FontHandler.cc for pekwm // Copyright © 2004-2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "config.h" #include #include #include "FontHandler.hh" #include "x11.hh" #include "Util.hh" using std::cerr; using std::endl; using std::map; using std::string; FontHandler* FontHandler::_instance = 0; //! @brief FontHandler constructor FontHandler::FontHandler(void) { #ifdef DEBUG if (_instance) { cerr << __FILE__ << "@" << __LINE__ << ": " << "FontHandler(" << this << ")::FontHandler()" << endl << " *** _instance already set" << endl; } #endif // DEBUG if (_map_justify.size() == 0) { _map_justify[""] = FONT_JUSTIFY_NO; _map_justify["LEFT"] = FONT_JUSTIFY_LEFT; _map_justify["CENTER"] = FONT_JUSTIFY_CENTER; _map_justify["RIGHT"] = FONT_JUSTIFY_RIGHT; } if (_map_type.size() == 0) { _map_type[""] = PFont::FONT_TYPE_NO; _map_type["X11"] = PFont::FONT_TYPE_X11; _map_type["XFT"] = PFont::FONT_TYPE_XFT; _map_type["XMB"] = PFont::FONT_TYPE_XMB; } _instance = this; } //! @brief FontHandler destructor FontHandler::~FontHandler(void) { vector >::iterator it_f(_fonts.begin()); for (; it_f != _fonts.end(); ++it_f) { delete it_f->getData(); } vector >::iterator it_c(_colours.begin()); for (; it_c != _colours.end(); ++it_c) { delete it_c->getData(); } } //! @brief Gets or allocs a font //! //! Syntax of font specification goes as follows: //! "Font Name#Justify#Offset#Type" ex "Vera#Center#1 1#XFT" //! where only the first field is obligatory and type needs to be the last //! PFont* FontHandler::getFont(const std::string &font) { // Check cache vector >::iterator it(_fonts.begin()); for (; it != _fonts.end(); ++it) { if (*it == font) { it->incRef(); return it->getData(); } } // create new PFont *pfont = 0; vector tok; vector::iterator tok_it; // old gcc doesn't like --tok.end() if ((Util::splitString(font, tok, "#", 0, true)) > 1) { // Try getting the font type from the first paramter, if that // doesn't work fall back to the last. This is to backwards // compatible. tok_it = tok.begin(); uint type = ParseUtil::getValue(*tok_it, _map_type); if (type == PFont::FONT_TYPE_NO) { tok_it = tok.end() - 1; type = ParseUtil::getValue(*tok_it, _map_type); } switch (type) { case PFont::FONT_TYPE_XMB: pfont = new PFontXmb; tok.erase(tok_it); break; #ifdef HAVE_XFT case PFont::FONT_TYPE_XFT: pfont = new PFontXft; tok.erase(tok_it); break; #endif // HAVE_XFT case PFont::FONT_TYPE_X11: pfont = new PFontX11; tok.erase(tok_it); break; default: pfont = new PFontXmb; break; }; pfont->load(tok.front()); // Remove used fields, type and tok.erase(tok.begin()); // fields left for justify and offset vector::iterator s_it(tok.begin()); for (; s_it != tok.end(); ++s_it) { if (isdigit((*s_it)[0])) { // number vector tok_2; if (Util::splitString(*s_it, tok_2, " \t", 2) == 2) { pfont->setOffset(strtol(tok_2[0].c_str(), 0, 10), strtol(tok_2[1].c_str(), 0, 10)); } } else { // justify uint justify = ParseUtil::getValue(*s_it, _map_justify); if (justify == FONT_JUSTIFY_NO) { justify = FONT_JUSTIFY_LEFT; } pfont->setJustify(justify); } } } else { pfont = new PFontXmb; pfont->load(font); } // create new entry HandlerEntry entry(font); entry.incRef(); entry.setData(pfont); _fonts.push_back(entry); return pfont; } //! @brief Returns a font void FontHandler::returnFont(PFont *font) { vector >::iterator it(_fonts.begin()); for (; it != _fonts.end(); ++it) { if (it->getData() == font) { it->decRef(); if (! it->getRef()) { delete it->getData(); _fonts.erase(it); } break; } } } //! @brief Gets or allocs a color PFont::Color* FontHandler::getColor(const std::string &color) { // check cache vector >::iterator it(_colours.begin()); for (; it != _colours.end(); ++it) { if (*it == color) { it->incRef(); return it->getData(); } } // create new PFont::Color *font_color = new PFont::Color(); font_color->setHasFg(true); vector tok; if (Util::splitString(color, tok, " \t", 2) == 2) { loadColor(tok[0], font_color, true); loadColor(tok[1], font_color, false); font_color->setHasBg(true); } else { loadColor(color, font_color, true); } // create new entry HandlerEntry entry(color); entry.incRef(); entry.setData(font_color); _colours.push_back(entry); return font_color; } //! @brief Returns a color void FontHandler::returnColor(PFont::Color *color) { vector >::iterator it(_colours.begin()); for (; it != _colours.end(); ++it) { if (it->getData() == color) { it->decRef(); if (! it->getRef()) { delete it->getData(); _colours.erase(it); } break; } } } //! @brief Helper loader of font colors ( main and offset color ) void FontHandler::loadColor(const std::string &color, PFont::Color *font_color, bool fg) { XColor *xc; vector tok; if (Util::splitString(color, tok, ",", 2, true) == 2) { uint alpha = static_cast(strtol(tok[1].c_str(), 0, 10)); if (alpha > 100) { cerr << " *** WARNING: Alpha for font color greater than 100%" << endl; alpha = 100; } alpha = static_cast(65535 * (static_cast(alpha) / 100)); if (fg) { font_color->setFgAlpha(alpha); } else { font_color->setBgAlpha(alpha); } xc = X11::getColor(tok[0]); } else { xc = X11::getColor(color); } if (fg) { font_color->setFg(xc); } else { font_color->setBg(xc); } } //! @brief Helper unloader of font colors void FontHandler::freeColor(PFont::Color *font_color) { if (font_color->hasFg()) { X11::returnColor(font_color->getFg()); } if (font_color->hasBg()) { X11::returnColor(font_color->getBg()); } delete font_color; } pekwm-release-0.1.18/src/FontHandler.hh000066400000000000000000000024411374756504400176760ustar00rootroot00000000000000// // FontHandler.hh for pekwm // Copyright (C) 2004-2009 Claes Nasten // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "config.h" #ifndef _FONT_HANDLER_HH_ #define _FONT_HANDLER_HH_ #include "PFont.hh" #include "Handler.hh" #include "ParseUtil.hh" #include #include //! @brief FontHandler, a caching and font type transparent font handler. class FontHandler { public: FontHandler(void); ~FontHandler(void); //! @brief Returns the FontHandler instance pointer. static inline FontHandler *instance(void) { return _instance; } PFont *getFont(const std::string &font); void returnFont(PFont *font); PFont::Color *getColor(const std::string &color); void returnColor(PFont::Color *color); private: void loadColor(const std::string &color, PFont::Color *font_color, bool fg); void freeColor(PFont::Color *font_color); private: vector > _fonts; vector > _colours; std::map _map_type; std::map _map_justify; //! @brief Pointer to FontHandler instance, should only be one. static FontHandler *_instance; }; #endif // _FONT_HANDLER_HH_ pekwm-release-0.1.18/src/Frame.cc000066400000000000000000001762751374756504400165330ustar00rootroot00000000000000// // Frame.cc for pekwm // Copyright © 2002-2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "config.h" #include #include #include #include extern "C" { #include } #include "Debug.hh" #include "PWinObj.hh" #include "PDecor.hh" #include "Frame.hh" #include "Compat.hh" #include "x11.hh" #include "Config.hh" #include "ActionHandler.hh" #include "AutoProperties.hh" #include "Client.hh" #include "StatusWindow.hh" #include "Workspaces.hh" #include "WindowManager.hh" #include "KeyGrabber.hh" #include "Theme.hh" using std::string; using std::wstring; vector Frame::_frames; vector Frame::_frameid_list; Frame* Frame::_tag_frame = 0; bool Frame::_tag_behind = false; //! @brief Frame constructor Frame::Frame(Client *client, AutoProperty *ap) : PDecor(WindowManager::instance()->getTheme(), client->getAPDecorName(), client->getWindow()), _id(0), _client(client), _class_hint(0), _non_fullscreen_decor_state(0), _non_fullscreen_layer(LAYER_NORMAL) { // PWinObj attributes _type = WO_FRAME; // PDecor attributes _decor_cfg_child_move_overloaded = true; _decor_cfg_bpr_replay_pointer = true; _decor_cfg_bpr_al_title = MOUSE_ACTION_LIST_TITLE_FRAME; _decor_cfg_bpr_al_child = MOUSE_ACTION_LIST_CHILD_FRAME; // grab buttons so that we can reply them for (uint i = 0; i < BUTTON_NO; ++i) { X11::grabButton(i, AnyModifier, _window, ButtonPressMask|ButtonReleaseMask, GrabModeSync); } // get unique id of the frame, if the client didn't have an id if (! WindowManager::instance()->isStartup()) { long id; if (X11::getLong(client->getWindow(), PEKWM_FRAME_ID, id)) { _id = id; } } else { _id = findFrameID(); } // get the clients class_hint _class_hint = new ClassHint(); *_class_hint = *client->getClassHint(); X11::grabServer(); // We don't send any ConfigurRequests during setup, we send one when we // are finished to minimize traffic and confusion client->setConfigureRequestLock(true); // Before setting position and size up we make sure the decor state // of the client match the decore state of the framewidget if (! client->hasBorder()) { setBorder(STATE_UNSET); } if (! client->hasTitlebar()) { setTitlebar(STATE_UNSET); } // We first get the size of the window as it will be needed when placing // the window with the help of WinGravity. resizeChild(client->getWidth(), client->getHeight()); // setup position bool place = false; if (client->isViewable() || client->isPlaced() || (client->cameWithPosition() && ! client->isCfgDeny(CFG_DENY_POSITION))) { moveChild(client->getX(), client->getY()); } else { place = Config::instance()->isPlaceNew(); } // override both position and size with autoproperties bool ap_geometry = false; if (ap) { if (ap->isMask(AP_FRAME_GEOMETRY|AP_CLIENT_GEOMETRY)) { ap_geometry = true; setupAPGeometry(client, ap); if (ap->frame_gm_mask&(XValue|YValue) || ap->client_gm_mask&(XValue|YValue)) { place = false; } } if (ap->isMask(AP_PLACE_NEW)) { place = ap->place_new; } } _non_fullscreen_decor_state = client->getDecorState(); _non_fullscreen_layer = client->getLayer(); X11::ungrabServer(true); // ungrab and sync // now insert the client in the frame we created. addChild(client); // needs to be done before the workspace insert and after the client // has been inserted, in order for layer settings to be propagated setLayer(client->getLayer()); // I add these to the list before I insert the client into the frame to // be able to skip an extra updateClientList _frames.push_back(this); WindowManager::instance()->addToMRUBack(this); activateChild(client); // set the window states, shaded, maximized... getState(client); if (! _client->hasStrut() && ! ap_geometry) { if (fixGeometry()) { moveResize(_gm.x, _gm.y, _gm.width, _gm.height); } } client->setConfigureRequestLock(false); client->configureRequestSend(); // Figure out if we should be hidden or not, do not read autoprops PDecor::setWorkspace(_client->getWorkspace()); woListAdd(this); _wo_map[_window] = this; // still need a position? if (place) { Workspaces::layout(this, client->getTransientForClientWindow()); } _old_gm = _gm; } //! @brief Frame destructor Frame::~Frame(void) { // remove from lists _wo_map.erase(_window); woListRemove(this); _frames.erase(std::remove(_frames.begin(), _frames.end(), this), _frames.end()); Workspaces::remove(this); WindowManager::instance()->removeFromFrameList(this); if (_tag_frame == this) { _tag_frame = 0; } returnFrameID(_id); if (_class_hint) { delete _class_hint; } Workspaces::updateClientList(); Workspaces::updateClientStackingList(); } // START - PWinObj interface. //! @brief Iconifies the Frame. void Frame::iconify(void) { if (_iconified) { return; } _iconified = true; unmapWindow(); } //! @brief Toggles the Frame's sticky state void Frame::stick(void) { _client->setSticky(_sticky); // FIXME: FRAME _client->stick(); _sticky = ! _sticky; // make sure it's visible/hidden PDecor::setWorkspace(Workspaces::getActive()); Workspaces::layoutIfTiling(); updateDecor(); } //! @brief Sets workspace on frame, wrapper to allow autoproperty loading void Frame::setWorkspace(unsigned int workspace) { // Duplicate the behavior done in PDecor::setWorkspace to have a sane // value on _workspace and not NET_WM_STICKY_WINDOW. if (workspace != NET_WM_STICKY_WINDOW) { // Check for DisallowedActions="SetWorkspace". if (! _client->allowChangeWorkspace()) { return; } // First we set the workspace, then load autoproperties for possible // overrun of workspace and then set the workspace. _workspace = workspace; readAutoprops(APPLY_ON_WORKSPACE); workspace = _workspace; } PDecor::setWorkspace(workspace); updateDecor(); } void Frame::setLayer(Layer layer) { PDecor::setLayer(layer); if (_client->getLayer() != layer) { _client->setLayer(layer); LayerObservation observation(layer); _client->notifyObservers(&observation); } } // event handlers ActionEvent* Frame::handleMotionEvent(XMotionEvent *ev) { // This is true when we have a title button pressed and then we don't want // to be able to drag windows around, therefore we ignore the event if (_button) { return 0; } ActionEvent *ae = 0; uint button = X11::getButtonFromState(ev->state); if (ev->window == getTitleWindow()) { ae = ActionHandler::findMouseAction(button, ev->state, MOUSE_EVENT_MOTION, Config::instance()->getMouseActionList(MOUSE_ACTION_LIST_TITLE_FRAME)); } else if (ev->window == _client->getWindow()) { ae = ActionHandler::findMouseAction(button, ev->state, MOUSE_EVENT_MOTION, Config::instance()->getMouseActionList(MOUSE_ACTION_LIST_CHILD_FRAME)); } else { uint pos = getBorderPosition(ev->subwindow); // If ev->subwindow wasn't one of the border windows, perhaps ev->window is. if (pos == BORDER_NO_POS) { pos = getBorderPosition(ev->window); } if (pos != BORDER_NO_POS) { vector *bl = Config::instance()->getBorderListFromPosition(pos); ae = ActionHandler::findMouseAction(button, ev->state, MOUSE_EVENT_MOTION, bl); } } // check motion threshold if (ae && (ae->threshold > 0)) { if (! ActionHandler::checkAEThreshold(ev->x_root, ev->y_root, _pointer_x, _pointer_y, ae->threshold)) { ae = 0; } } return ae; } //! @brief ActionEvent* Frame::handleEnterEvent(XCrossingEvent *ev) { // Run event handler to get hoovering to work but ignore action // returned. PDecor::handleEnterEvent(ev); ActionEvent *ae = 0; vector *al = 0; if (ev->window == getTitleWindow() || findButton(ev->window)) { al = Config::instance()->getMouseActionList(MOUSE_ACTION_LIST_TITLE_FRAME); } else if (ev->subwindow == _client->getWindow()) { al = Config::instance()->getMouseActionList(MOUSE_ACTION_LIST_CHILD_FRAME); } else { uint pos = getBorderPosition(ev->window); if (pos != BORDER_NO_POS) { al = Config::instance()->getBorderListFromPosition(pos); } } if (al) { ae = ActionHandler::findMouseAction(BUTTON_ANY, ev->state, MOUSE_EVENT_ENTER, al); } return ae; } //! @brief ActionEvent* Frame::handleLeaveEvent(XCrossingEvent *ev) { // Run event handler to get hoovering to work but ignore action // returned. PDecor::handleLeaveEvent(ev); ActionEvent *ae; MouseActionListName ln = MOUSE_ACTION_LIST_TITLE_FRAME; if (ev->window == _client->getWindow()) { ln = MOUSE_ACTION_LIST_CHILD_FRAME; } ae = ActionHandler::findMouseAction(BUTTON_ANY, ev->state, MOUSE_EVENT_LEAVE, Config::instance()->getMouseActionList(ln)); return ae; } ActionEvent* Frame::handleMapRequest(XMapRequestEvent *ev) { if (ev->window != _client->getWindow()) { return 0; } if (! _sticky && _workspace != Workspaces::getActive()) { LOG("Ignoring MapRequest, not on current workspace!"); return 0; } mapWindow(); return 0; } ActionEvent* Frame::handleUnmapEvent(XUnmapEvent *ev) { vector::const_iterator it(_children.begin()); for (; it != _children.end(); ++it) { if (*(*it) == ev->window) { (*it)->handleUnmapEvent(ev); break; } } return 0; } // END - PWinObj interface. #ifdef HAVE_SHAPE void Frame::handleShapeEvent(XShapeEvent *ev) { if (ev->window != _client->getWindow()) { return; } applyBorderShape(ev->kind); } #endif // HAVE_SHAPE // START - PDecor interface. bool Frame::allowMove(void) const { return _client->allowMove(); } /** * Return active client, or 0 if no clients or active child is not a Client. */ Client* Frame::getActiveClient(void) { if (getActiveChild() && getActiveChild()->getType() == WO_CLIENT) { return static_cast(getActiveChild()); } else { return 0; } } //! @brief Adds child to the frame. void Frame::addChild(PWinObj *child, vector::iterator *it) { PDecor::addChild(child, it); X11::setLong(child->getWindow(), PEKWM_FRAME_ID, _id); child->lower(); Client *client = dynamic_cast(child); if (client && client->demandsAttention()) { incrAttention(); } } /** * Add child preserving order from the previous pekwm run. */ void Frame::addChildOrdered(Client *child) { Client *client; vector::iterator it(_children.begin()); for (; it != _children.end(); ++it) { client = static_cast(*it); if (child->getInitialFrameOrder() < client->getInitialFrameOrder()) { break; } } addChild(child, &it); } //! @brief Removes child from the frame. void Frame::removeChild(PWinObj *child, bool do_delete) { if (static_cast(child)->demandsAttention()) { decrAttention(); } PDecor::removeChild(child, do_delete); } /** * Activates child in Frame, updating it's state and re-loading decor * rules to match updated title. */ void Frame::activateChild(PWinObj *child) { // FIXME: Update default decoration for this child, can change // decoration from DEFAULT to REMOTE or WARNING // Sync the frame state with the client only if we already had a client if (_client != child) { applyState(static_cast(child)); } _client = static_cast(child); if (_client->demandsAttention()) { _client->setDemandsAttention(false); decrAttention(); } PDecor::activateChild(child); #ifdef HAVE_SHAPE // applyBorderShape() uses current active child, so we need to activate // the child before setting shape if (X11::hasExtensionShape()) { applyBorderShape(ShapeBounding); applyBorderShape(ShapeInput); } #endif // HAVE_SHAPE setOpacity(_client); if (_focused) { child->giveInputFocus(); } // Reload decor rules if needed. handleTitleChange(_client); Workspaces::updateClientList(); Workspaces::updateClientStackingList(); } /** * Called when child order is updated, re-sets the titles and updates * the _PEKWM_FRAME hints. */ void Frame::updatedChildOrder(void) { titleClear(); Client *client; vector::const_iterator it(_children.begin()); for (long num = 0; it != _children.end(); ++num, ++it) { client = static_cast(*it); client->setPekwmFrameOrder(num); titleAdd(client->getTitle()); } updatedActiveChild(); } /** * Set the active title and update the _PEKWM_FRAME hints. */ void Frame::updatedActiveChild(void) { titleSetActive(0); Client *client; uint size = _children.size(); for (uint i = 0; i < size; ++i) { client = static_cast(_children[i]); client->setPekwmFrameActive(_child == client); if (_child == client) { titleSetActive(i); } } renderTitle(); } //! @brief void Frame::getDecorInfo(wchar_t *buf, uint size) { uint width, height; calcSizeInCells(width, height); swprintf(buf, size, L"%d+%d+%d+%d", width, height, _gm.x, _gm.y); } void Frame::giveInputFocus(void) { if (_client->demandsAttention()) { _client->setDemandsAttention(false); decrAttention(); } PDecor::giveInputFocus(); } //! @brief void Frame::setShaded(StateAction sa) { bool shaded = isShaded(); // Check for DisallowedActions="Shade" if (! _client->allowShade()) { sa = STATE_UNSET; } PDecor::setShaded(sa); if (shaded != isShaded()) { _client->setShade(isShaded()); _client->updateEwmhStates(); } } //! @brief int Frame::resizeHorzStep(int diff) const { int diff_ret = 0; uint min = _gm.width - getChildWidth(); if (min == 0) { // borderless windows, we don't want X errors min = 1; } const XSizeHints *hints = _client->getXSizeHints(); // convenience // if we have ResizeInc hint set we use it instead of pixel diff if (hints->flags&PResizeInc) { if (diff > 0) { diff_ret = hints->width_inc; } else if ((_gm.width - hints->width_inc) >= min) { diff_ret = -hints->width_inc; } } else if ((_gm.width + diff) >= min) { diff_ret = diff; } // check max/min size hints if (diff > 0) { if ((hints->flags&PMaxSize) && ((getChildWidth() + diff) > unsigned(hints->max_width))) { diff_ret = _gm.width - hints->max_width + min; } } else if ((hints->flags&PMinSize) && ((getChildWidth() + diff) < unsigned(hints->min_width))) { diff_ret = _gm.width - hints->min_width + min; } return diff_ret; } //! @brief int Frame::resizeVertStep(int diff) const { int diff_ret = 0; uint min = _gm.height - getChildHeight(); if (min == 0) { // borderless windows, we don't want X errors min = 1; } const XSizeHints *hints = _client->getXSizeHints(); // convenience // if we have ResizeInc hint set we use it instead of pixel diff if (hints->flags&PResizeInc) { if (diff > 0) { diff_ret = hints->height_inc; } else if ((_gm.height - hints->height_inc) >= min) { diff_ret = -hints->height_inc; } } else { diff_ret = diff; } // check max/min size hints if (diff > 0) { if ((hints->flags&PMaxSize) && ((getChildHeight() + diff) > unsigned(hints->max_height))) { diff_ret = _gm.height - hints->max_height + min; } } else if ((hints->flags&PMinSize) && ((getChildHeight() + diff) < unsigned(hints->min_height))) { diff_ret = _gm.height - hints->min_width + min; } return diff_ret; } /** * Return decor name for the current client or attention decor if * Frame has client which demands attention. */ std::string Frame::getDecorName(void) { if (! demandAttention()) { string name = _client->getAPDecorName(); if (! name.empty()) { return name; } } return PDecor::getDecorName(); } // END - PDecor interface. //! @brief Sets _PEKWM_FRAME_ID on all children in the frame void Frame::setId(uint id) { _id = id; vector::const_iterator it(_children.begin()); for (; it != _children.end(); ++it) { X11::setLong((*it)->getWindow(), PEKWM_FRAME_ID, id); } } //! @brief Gets the state from the Client void Frame::getState(Client *cl) { if (! cl) return; bool b_client_iconified = cl->isIconified (); if (_sticky != cl->isSticky()) _sticky = ! _sticky; if (_maximized_horz != cl->isMaximizedHorz()) setStateMaximized(STATE_TOGGLE, true, false, false); if (_maximized_vert != cl->isMaximizedVert()) setStateMaximized(STATE_TOGGLE, false, true, false); if (isShaded() != cl->isShaded()) setShaded(STATE_TOGGLE); if (getLayer() != cl->getLayer()) { setLayer(cl->getLayer()); } if (_workspace != cl->getWorkspace()) PDecor::setWorkspace(cl->getWorkspace()); // We need to set border and titlebar before setting fullscreen, as // fullscreen will unset border and titlebar if needed. if (hasBorder() != _client->hasBorder()) setBorder(STATE_TOGGLE); if (hasTitlebar() != _client->hasTitlebar()) setTitlebar(STATE_TOGGLE); if (_fullscreen != cl->isFullscreen()) setStateFullscreen(STATE_TOGGLE); if (_iconified != b_client_iconified) { if (_iconified) { mapWindow(); } else { iconify(); } } if (_skip != cl->getSkip()) { setSkip(cl->getSkip()); } } //! @brief Applies the frame's state on the Client void Frame::applyState(Client *cl) { if (! cl) { return; } cl->setSticky(_sticky); cl->setMaximizedHorz(_maximized_horz); cl->setMaximizedVert(_maximized_vert); cl->setShade(isShaded()); cl->setWorkspace(_workspace); cl->setLayer(getLayer()); // fix border / titlebar state cl->setBorder(hasBorder()); cl->setTitlebar(hasTitlebar()); // make sure the window has the correct mapped state if (_mapped != cl->isMapped()) { if (! _mapped) { cl->unmapWindow(); } else { cl->mapWindow(); } } cl->updateEwmhStates(); } //! @brief Sets skip state. void Frame::setSkip(uint skip) { PDecor::setSkip(skip); _client->setSkip(skip); } //! @brief Find Frame with Window //! @param win Window to search for. //! @return Frame if found, else 0. Frame* Frame::findFrameFromWindow(Window win) { // Validate input window. if ((win == None) || (win == X11::getRoot())) { return 0; } vector::const_iterator it(_frames.begin()); for(; it !=_frames.end(); ++it) { if (win == (*it)->getWindow()) { // operator == does more than that return (*it); } } return 0; } //! @brief Find Frame with id. //! @param id ID to search for. //! @return Frame if found, else 0. Frame* Frame::findFrameFromID(uint id) { vector::const_iterator it(_frames.begin()); for (; it != _frames.end(); ++it) { if ((*it)->getId() == id) { return (*it); } } return 0; } void Frame::setupAPGeometry(Client *client, AutoProperty *ap) { // frame geomtry overides client geometry // get client geometry if (ap->isMask(AP_CLIENT_GEOMETRY)) { Geometry gm(client->_gm); applyGeometry(gm, ap->client_gm, ap->client_gm_mask); if (ap->client_gm_mask&(XValue|YValue)) { moveChild(gm.x, gm.y); } if(ap->client_gm_mask&(WidthValue|HeightValue)) { resizeChild(gm.width, gm.height); } } // get frame geometry if (ap->isMask(AP_FRAME_GEOMETRY)) { setGeometry(ap->frame_gm, ap->frame_gm_mask); } } void Frame::applyGeometry(Geometry &gm, const Geometry &ap_gm, int mask) { applyGeometry(gm, ap_gm, mask, X11::getScreenGeometry()); } //! @brief Apply geometry. //! @param gm Geometry to modify. //! @param ap_gm Geometry to get values from. //! @param mask Geometry mask. //! @param screen_gm Geometry of the screen/head for position. void Frame::applyGeometry(Geometry &gm, const Geometry &ap_gm, int mask, const Geometry &screen_gm) { // Read size before position so negative position works, if size is // < 1 consider it to be full screen size. if (mask&WidthValue) { if (ap_gm.width < 1) { gm.width = screen_gm.width; } else { gm.width = ap_gm.width; } } if (mask&HeightValue) { if (ap_gm.height < 1) { gm.height = screen_gm.height; } else { gm.height = ap_gm.height; } } // Read position if (mask&XValue) { gm.x = screen_gm.x + ap_gm.x; if (mask&XNegative) { gm.x += screen_gm.width - gm.width; } } if (mask&YValue) { gm.y = screen_gm.y + ap_gm.y; if (mask&YNegative) { gm.y += screen_gm.height - gm.height; } } } //! @brief Finds free Frame ID. //! @return First free Frame ID. uint Frame::findFrameID(void) { uint id = 0; if (_frameid_list.size()) { // Check for used Frame IDs id = _frameid_list.back(); _frameid_list.pop_back(); } else { // No free, get next number (Frame is not in list when this is called.) id = _frames.size() + 1; } return id; } //! @brief Returns Frame ID to used frame id list. //! @param id ID to return. void Frame::returnFrameID(uint id) { vector::iterator it(_frameid_list.begin()); for (; it != _frameid_list.end() && id < *it; ++it) ; _frameid_list.insert(it, id); } //! @brief Resets Frame IDs. void Frame::resetFrameIDs(void) { vector::const_iterator it(_frames.begin()); for (uint id = 1; it != _frames.end(); ++id, ++it) { (*it)->setId(id); } } //! @brief Removes the client from the Frame and creates a new Frame for it void Frame::detachClient(Client *client) { if (client->getParent() != this) { return; } if (_children.size() > 1) { removeChild(client); client->move(_gm.x, _gm.y + borderTop()); Frame *frame = new Frame(client, 0); Workspaces::insert(frame); client->setParent(frame); client->setWorkspace(Workspaces::getActive()); setFocused(false); } } //! @brief Makes sure the frame doesn't cover any struts / the harbour. bool Frame::fixGeometry(void) { Geometry head, before; if (_fullscreen) X11::getHeadInfo(getNearestHead(), head); else X11::getHeadInfoWithEdge(getNearestHead(), head); before = _gm; // fix size if (_gm.width > head.width) { _gm.width = head.width; } if (_gm.height > head.height) { _gm.height = head.height; } // fix position if (_gm.x < head.x) { _gm.x = head.x; } else if ((_gm.x + _gm.width) > (head.x + head.width)) { _gm.x = head.x + head.width - _gm.width; } if (_gm.y < head.y) { _gm.y = head.y; } else if ((_gm.y + _gm.height) > (head.y + head.height)) { _gm.y = head.y + head.height - _gm.height; } return (_gm != before); } //! @brief Initiates grouping move, based on a XMotionEvent. void Frame::doGroupingDrag(XMotionEvent *ev, Client *client, bool behind) // FIXME: rewrite { if (! client) { return; } int o_x, o_y; o_x = ev ? ev->x_root : 0; o_y = ev ? ev->y_root : 0; wstring name(L"Grouping "); if (client->getTitle()->getVisible().size() > 0) { name += client->getTitle()->getVisible(); } else { name += L"No Name"; } bool status = X11::grabPointer(X11::getRoot(), ButtonReleaseMask|PointerMotionMask, CURSOR_NONE); if (status != true) { return; } StatusWindow *sw = StatusWindow::instance(); sw->draw(name); // resize window and render bg sw->move(o_x, o_y); sw->mapWindowRaised(); sw->draw(name); // redraw after map XEvent e; while (true) { // this breaks when we get an button release XMaskEvent(X11::getDpy(), PointerMotionMask|ButtonReleaseMask, &e); switch (e.type) { case MotionNotify: // update the position o_x = e.xmotion.x_root; o_y = e.xmotion.y_root; sw->move(o_x, o_y); sw->draw(name); break; case ButtonRelease: sw->unmapWindow(); X11::ungrabPointer(); Client *search = 0; // only group if we have grouping turned on if (WindowManager::instance()->isAllowGrouping()) { int x, y; Window win; // find the frame we dropped the client on XTranslateCoordinates(X11::getDpy(), X11::getRoot(), X11::getRoot(), e.xmotion.x_root, e.xmotion.y_root, &x, &y, &win); search = Client::findClient(win); } // if we found a client, and it's not in the current frame and // it has a "normal" ( make configurable? ) layer we group if (search && search->getParent() && (search->getParent() != this) && (search->getLayer() > LAYER_BELOW) && (search->getLayer() < LAYER_ONTOP)) { // if we currently have focus and the frame exists after we remove // this client we need to redraw it as unfocused bool focus = behind ? false : (_children.size() > 1); removeChild(client); Frame *frame = static_cast(search->getParent()); frame->addChild(client); if (! behind) { frame->activateChild(client); frame->giveInputFocus(); } if (focus) { setFocused(false); } } else if (_children.size() > 1) { // if we have more than one client in the frame detach this one removeChild(client); client->move(e.xmotion.x_root, e.xmotion.y_root); Frame *frame = new Frame(client, 0); Workspaces::insert(frame); client->setParent(frame); // make sure the client ends up on the current workspace client->setWorkspace(Workspaces::getActive()); // make sure it get's focus setFocused(false); frame->giveInputFocus(); } return; } } } //! @brief Initiates resizing of a window based on motion event void Frame::doResize(XMotionEvent *ev) { if (! ev) { return; } // figure out which part of the window we are in bool left = false, top = false; if (ev->x < signed(_gm.width / 2)) { left = true; } if (ev->y < signed(_gm.height / 2)) { top = true; } doResize(left, true, top, true); } //! @brief Initiates resizing of a window based border position void Frame::doResize(BorderPosition pos) { bool x = false, y = false; bool left = false, top = false, resize = true; switch (pos) { case BORDER_TOP_LEFT: x = y = left = top = true; break; case BORDER_TOP: y = top = true; break; case BORDER_TOP_RIGHT: x = y = top = true; break; case BORDER_LEFT: x = left = true; break; case BORDER_RIGHT: x = true; break; case BORDER_BOTTOM_LEFT: x = y = left = true; break; case BORDER_BOTTOM: y = true; break; case BORDER_BOTTOM_RIGHT: x = y = true; break; default: resize = false; break; } if (resize) { doResize(left, x, top, y); } } //! @brief Resizes the frame by handling MotionNotify events. void Frame::doResize(bool left, bool x, bool top, bool y) { if (! _client->allowResize() || isShaded()) { return; } if (! X11::grabPointer(X11::getRoot(), ButtonMotionMask|ButtonReleaseMask, CURSOR_RESIZE)) { return; } setShaded(STATE_UNSET); // make sure the frame isn't shaded setStateFullscreen(STATE_UNSET); // Initialize variables int start_x, new_x; int start_y, new_y; uint old_width; uint old_height; start_x = new_x = left ? _gm.x : (_gm.x + _gm.width); start_y = new_y = top ? _gm.y : (_gm.y + _gm.height); old_width = _gm.width; old_height = _gm.height; // the basepoint of our window _click_x = left ? (_gm.x + _gm.width) : _gm.x; _click_y = top ? (_gm.y + _gm.height) : _gm.y; int pointer_x = _gm.x, pointer_y = _gm.y; X11::getMousePosition(pointer_x, pointer_y); bool center_on_root = Config::instance()->isShowStatusWindowOnRoot(); StatusWindow *sw = StatusWindow::instance(); if (Config::instance()->isShowStatusWindow()) { sw->drawGeometry(_gm, center_on_root); sw->mapWindowRaised(); sw->drawGeometry(_gm, center_on_root); } bool outline = ! Config::instance()->getOpaqueResize(); // grab server, we don't want invert traces if (outline) { X11::grabServer(); } const long resize_mask = ButtonPressMask|ButtonReleaseMask|ButtonMotionMask; XEvent ev; bool exit = false; while (exit != true) { if (outline) { drawOutline(_gm); } XMaskEvent(X11::getDpy(), resize_mask, &ev); if (outline) { drawOutline(_gm); // clear } switch (ev.type) { case MotionNotify: // Flush all pointer motion, no need to redraw and redraw. X11::removeMotionEvents(); if (x) { new_x = start_x - pointer_x + ev.xmotion.x; } if (y) { new_y = start_y - pointer_y + ev.xmotion.y; } recalcResizeDrag(new_x, new_y, left, top); if (Config::instance()->isShowStatusWindow()) { sw->drawGeometry(_gm, center_on_root); } // only updated when needed when in opaque mode if (! outline) { if ((old_width != _gm.width) || (old_height != _gm.height)) { moveResize(_gm.x, _gm.y, _gm.width, _gm.height); } old_width = _gm.width; old_height = _gm.height; } break; case ButtonRelease: exit = true; break; } } if (Config::instance()->isShowStatusWindow()) { sw->unmapWindow(); } X11::ungrabPointer(); // Make sure the state isn't set to maximized after we've resized. if (_maximized_horz || _maximized_vert) { _maximized_horz = false; _maximized_vert = false; _client->setMaximizedHorz(false); _client->setMaximizedVert(false); _client->updateEwmhStates(); } if (outline) { moveResize(_gm.x, _gm.y, _gm.width, _gm.height); X11::ungrabServer(true); } } //! @brief Updates the width, height of the frame when resizing it. void Frame::recalcResizeDrag(int nx, int ny, bool left, bool top) { uint brdr_lr = borderLeft() + borderRight(); uint brdr_tb = borderTop() + borderBottom(); if (left) { if (nx >= signed(_click_x - brdr_lr)) nx = _click_x - brdr_lr - 1; } else { if (nx <= signed(_click_x + brdr_lr)) nx = _click_x + brdr_lr + 1; } if (top) { if (ny >= signed(_click_y - getTitleHeight() - brdr_tb)) ny = _click_y - getTitleHeight() - brdr_tb - 1; } else { if (ny <= signed(_click_y + getTitleHeight() + brdr_tb)) ny = _click_y + getTitleHeight() + brdr_tb + 1; } uint width = left ? (_click_x - nx) : (nx - _click_x); uint height = top ? (_click_y - ny) : (ny - _click_y); width -= brdr_lr; height -= brdr_tb + getTitleHeight(); _client->getAspectSize(&width, &height, width, height); const XSizeHints *hints = _client->getXSizeHints(); // check so we aren't overriding min or max size if (hints->flags & PMinSize) { if (signed(width) < hints->min_width) width = hints->min_width; if (signed(height) < hints->min_height) height = hints->min_height; } if (hints->flags & PMaxSize) { if (signed(width) > hints->max_width) width = hints->max_width; if (signed(height) > hints->max_height) height = hints->max_height; } _gm.width = width + brdr_lr; _gm.height = height + getTitleHeight() + brdr_tb; _gm.x = left ? (_click_x - _gm.width) : _click_x; _gm.y = top ? (_click_y - _gm.height) : _click_y; } void Frame::moveToHead(int head_nr) { int curr_head_nr = getNearestHead(); if (curr_head_nr == head_nr || head_nr >= X11::getNumHeads()) { return; } Geometry old_gm, new_gm; X11::getHeadInfoWithEdge(curr_head_nr, old_gm); X11::getHeadInfoWithEdge(head_nr, new_gm); // Ensure the window fits in the new head. _gm.x = new_gm.x + (_gm.x - old_gm.x); _gm.y = new_gm.y + (_gm.y - old_gm.y); _gm.width = std::min(_gm.width, new_gm.width); _gm.height = std::min(_gm.height, new_gm.height); if ((_gm.x + _gm.width) > (new_gm.x + new_gm.width)) { _gm.x = new_gm.x + new_gm.width - _gm.width; } if ((_gm.y + _gm.height) > (new_gm.y + new_gm.height)) { _gm.y = new_gm.y + new_gm.height - _gm.height; } moveResize(_gm.x, _gm.y, _gm.width, _gm.height); } //! @brief Moves the Frame to the screen edge ori ( considering struts ) void Frame::moveToEdge(OrientationType ori) { uint head_nr; Geometry head, real_head; head_nr = getNearestHead(); X11::getHeadInfo(head_nr, real_head); X11::getHeadInfoWithEdge(head_nr, head); switch (ori) { case TOP_LEFT: _gm.x = head.x; _gm.y = head.y; break; case TOP_EDGE: _gm.y = head.y; break; case TOP_CENTER_EDGE: _gm.x = real_head.x + ((real_head.width - _gm.width) / 2); _gm.y = head.y; break; case TOP_RIGHT: _gm.x = head.x + head.width - _gm.width; _gm.y = head.y; break; case BOTTOM_RIGHT: _gm.x = head.x + head.width - _gm.width; _gm.y = head.y + head.height - _gm.height; break; case BOTTOM_EDGE: _gm.y = head.y + head.height - _gm.height; break; case BOTTOM_CENTER_EDGE: _gm.x = real_head.x + ((real_head.width - _gm.width) / 2); _gm.y = head.y + head.height - _gm.height; break; case BOTTOM_LEFT: _gm.x = head.x; _gm.y = head.y + head.height - _gm.height; break; case LEFT_EDGE: _gm.x = head.x; break; case LEFT_CENTER_EDGE: _gm.x = head.x; _gm.y = real_head.y + ((real_head.height - _gm.height) / 2); break; case RIGHT_EDGE: _gm.x = head.x + head.width - _gm.width; break; case RIGHT_CENTER_EDGE: _gm.x = head.x + head.width - _gm.width; _gm.y = real_head.y + ((real_head.height - _gm.height) / 2); break; case CENTER: _gm.x = real_head.x + ((real_head.width - _gm.width) / 2); _gm.y = real_head.y + ((real_head.height - _gm.height) / 2); default: // DO NOTHING break; } move(_gm.x, _gm.y); } //! @brief Updates all inactive childrens geometry and state void Frame::updateInactiveChildInfo(void) { vector::const_iterator it(_children.begin()); for (; it != _children.end(); ++it) { if (*it != _client) { applyState(static_cast(*it)); (*it)->resize(getChildWidth(), getChildHeight()); } } } // STATE actions begin //! @brief Toggles current clients max size //! @param sa State to set //! @param horz Include horizontal in (de)maximize //! @param vert Include vertcical in (de)maximize //! @param fill Limit size by other frame boundaries ( defaults to false ) void Frame::setStateMaximized(StateAction sa, bool horz, bool vert, bool fill) { setShaded(STATE_UNSET); setStateFullscreen(STATE_UNSET); if (Workspaces::isTiling(_workspace) && allowTiling()) { return; } // make sure the two states are in sync if toggling if ((horz == vert) && (sa == STATE_TOGGLE)) { if (_maximized_horz != _maximized_vert) { horz = ! _maximized_horz; vert = ! _maximized_vert; } } XSizeHints *size_hint = _client->getXSizeHints(); // convenience Geometry head; X11::getHeadInfoWithEdge(getNearestHead(), head); int max_x, max_r, max_y, max_b; max_x = head.x; max_r = head.width + head.x; max_y = head.y; max_b = head.height + head.y; if (fill) { getMaxBounds(max_x, max_r, max_y, max_b); // make sure vert and horz gets set if fill is on sa = STATE_SET; } if (horz && (fill || _client->allowMaximizeHorz())) { // maximize if ((sa == STATE_SET) || ((sa == STATE_TOGGLE) && ! _maximized_horz)) { uint h_decor = _gm.width - getChildWidth(); if (! fill) { _old_gm.x = _gm.x; _old_gm.width = _gm.width; } _gm.x = max_x; _gm.width = max_r - max_x; if ((size_hint->flags&PMaxSize) && (_gm.width > (size_hint->max_width + h_decor))) { _gm.width = size_hint->max_width + h_decor; } // demaximize } else if ((sa == STATE_UNSET) || ((sa == STATE_TOGGLE) && _maximized_horz)) { _gm.x = _old_gm.x; _gm.width = _old_gm.width; } // we unset the maximized state if we use maxfill _maximized_horz = fill ? false : ! _maximized_horz; _client->setMaximizedHorz(_maximized_horz); } if (vert && (fill || _client->allowMaximizeVert())) { // maximize if ((sa == STATE_SET) || ((sa == STATE_TOGGLE) && ! _maximized_vert)) { uint v_decor = _gm.height - getChildHeight(); if (! fill) { _old_gm.y = _gm.y; _old_gm.height = _gm.height; } _gm.y = max_y; _gm.height = max_b - max_y; if ((size_hint->flags&PMaxSize) && (_gm.height > (size_hint->max_height + v_decor))) { _gm.height = size_hint->max_height + v_decor; } // demaximize } else if ((sa == STATE_UNSET) || ((sa == STATE_TOGGLE) && _maximized_vert)) { _gm.y = _old_gm.y; _gm.height = _old_gm.height; } // we unset the maximized state if we use maxfill _maximized_vert = fill ? false : ! _maximized_vert; _client->setMaximizedVert(_maximized_vert); } fixGeometry(); // harbour already considered downSize(_gm, true, true); // keep x and keep y ( make conform to inc size ) moveResize(_gm.x, _gm.y, _gm.width, _gm.height); _client->updateEwmhStates(); } //! @brief Set fullscreen state void Frame::setStateFullscreen(StateAction sa) { // Check for DisallowedActions="Fullscreen". if (! _client->allowFullscreen()) { sa = STATE_UNSET; } if (! ActionUtil::needToggle(sa, _fullscreen)) { return; } bool lock = _client->setConfigureRequestLock(true); if (_fullscreen) { if ((_non_fullscreen_decor_state&DECOR_BORDER) != hasBorder()) { setBorder(STATE_TOGGLE); } if ((_non_fullscreen_decor_state&DECOR_TITLEBAR) != hasTitlebar()) { setTitlebar(STATE_TOGGLE); } _gm = _old_gm; } else { _old_gm = _gm; _non_fullscreen_decor_state = _client->getDecorState(); _non_fullscreen_layer = _client->getLayer(); setBorder(STATE_UNSET); setTitlebar(STATE_UNSET); Geometry head; uint nr = getNearestHead(); X11::getHeadInfo(nr, head); _gm = head; } _fullscreen = !_fullscreen; _client->setFullscreen(_fullscreen); moveResize(_gm.x, _gm.y, _gm.width, _gm.height); // Re-stack window if fullscreen is above other windows. if (Config::instance()->isFullscreenAbove() && _client->getLayer() != LAYER_DESKTOP) { setLayer(_fullscreen ? LAYER_ABOVE_DOCK : _non_fullscreen_layer); raise(); } _client->setConfigureRequestLock(lock); _client->configureRequestSend(); _client->updateEwmhStates(); } //! @brief void Frame::setStateSticky(StateAction sa) { // Check for DisallowedActions="Stick". if (! _client->allowStick()) { sa = STATE_UNSET; } if (ActionUtil::needToggle(sa, _sticky)) { stick(); } } void Frame::setStateAlwaysOnTop(StateAction sa) { if (! ActionUtil::needToggle(sa, getLayer() >= LAYER_ONTOP)) { return; } _client->alwaysOnTop(getLayer() < LAYER_ONTOP); setLayer(_client->getLayer()); raise(); } void Frame::setStateAlwaysBelow(StateAction sa) { if (! ActionUtil::needToggle(sa, getLayer() == LAYER_BELOW)) { return; } _client->alwaysBelow(getLayer() > LAYER_BELOW); setLayer(_client->getLayer()); lower(); } //! @brief Hides/Shows the border depending on _client //! @param sa State to set void Frame::setStateDecorBorder(StateAction sa) { bool border = hasBorder(); setBorder(sa); // state changed, update client and atom state if (border != hasBorder()) { _client->setBorder(hasBorder()); // update the _PEKWM_FRAME_DECOR hint X11::setLong(_client->getWindow(), PEKWM_FRAME_DECOR, _client->getDecorState()); } } //! @brief Hides/Shows the titlebar depending on _client //! @param sa State to set void Frame::setStateDecorTitlebar(StateAction sa) { bool titlebar = hasTitlebar(); setTitlebar(sa); // state changed, update client and atom state if (titlebar != hasTitlebar()) { _client->setTitlebar(hasTitlebar()); X11::setLong(_client->getWindow(), PEKWM_FRAME_DECOR, _client->getDecorState()); } } //! @brief void Frame::setStateIconified(StateAction sa) { // Check for DisallowedActions="Iconify". if (! _client->allowIconify()) { sa = STATE_UNSET; } if (! ActionUtil::needToggle(sa, _iconified)) { return; } if (_iconified) { mapWindow(); } else { iconify(); } } //! (Un)Sets the tagged Frame. //! //! @param sa Set/Unset or Toggle the state. //! @param behind Should tagged actions be behind (non-focused). void Frame::setStateTagged(StateAction sa, bool behind) { if (ActionUtil::needToggle(sa, (_tag_frame != 0))) { _tag_frame = (this == _tag_frame) ? 0 : this; _tag_behind = behind; } } //! @brief void Frame::setStateSkip(StateAction sa, uint skip) { if (! ActionUtil::needToggle(sa, _skip&skip)) { return; } if (_skip&skip) { _skip &= ~skip; } else { _skip |= skip; } setSkip(_skip); } //! @brief Sets client title void Frame::setStateTitle(StateAction sa, Client *client, const std::wstring &title) { if (sa == STATE_SET) { client->getTitle()->setUser(title); } else if (sa == STATE_UNSET) { client->getTitle()->setUser(L""); client->readName(); } else { if (client->getTitle()->isUserSet()) { client->getTitle()->setUser(L""); } else { client->getTitle()->setUser(title); } } // Set PEKWM_TITLE atom to preserve title on client between sessions. X11::setString(client->getWindow(), PEKWM_TITLE, Util::to_mb_str(client->getTitle()->getUser())); renderTitle(); } //! @brief Sets clients marked state. //! @param sa //! @param client void Frame::setStateMarked(StateAction sa, Client *client) { if (! client || ! ActionUtil::needToggle(sa, client->isMarked())) { return; } // Set marked state and re-render title to update visual marker. client->setStateMarked(sa); renderTitle(); } void Frame::setStateOpaque(StateAction sa) { if (! ActionUtil::needToggle(sa, _opaque)) { return; } _client->setOpaque(!_opaque); setOpaque(!_opaque); } // STATE actions end //! @brief void Frame::getMaxBounds(int &max_x,int &max_r, int &max_y, int &max_b) { int f_r, f_b; int x, y, r, b; f_r = getRX(); f_b = getBY(); vector::const_iterator it = _frames.begin(); for (; it != _frames.end(); ++it) { if (! (*it)->isMapped()) { continue; } x = (*it)->getX(); y = (*it)->getY(); r = (*it)->getRX(); b = (*it)->getBY(); // update max borders when other frame border lies between // this border and prior max border (originally screen/head edge) if ((r >= max_x) && (r <= _gm.x) && ! ((y >= f_b) || (b <= _gm.y))) { max_x = r; } if ((x <= max_r) && (x >= f_r) && ! ((y >= f_b) || (b <= _gm.y))) { max_r = x; } if ((b >= max_y) && (b <= _gm.y) && ! ((x >= f_r) || (r <= _gm.x))) { max_y = b; } if ((y <= max_b) && (y >= f_b) && ! ((x >= f_r) || (r <= _gm.x))) { max_b = y; } } } void Frame::setGeometry(const std::string geometry, int head) { Geometry gm; int mask = XParseGeometry(geometry.c_str(), &gm.x, &gm.y, &gm.width, &gm.height); setGeometry(gm, mask, head); } void Frame::setGeometry(const Geometry &geometry, int gm_mask, int head) { Geometry screen_gm; if (head == -1) { screen_gm = X11::getScreenGeometry(); } else { screen_gm = X11::getHeadGeometry(head); } applyGeometry(_gm, geometry, gm_mask, screen_gm); if (gm_mask&(XValue|YValue)) { move(_gm.x, _gm.y); } if (gm_mask&(WidthValue|HeightValue)) { resize(_gm.width, _gm.height); } } void Frame::growDirection(uint direction) { Geometry head; X11::getHeadInfoWithEdge(getNearestHead(), head); switch (direction) { case DIRECTION_UP: _gm.height = getBY() - head.y; _gm.y = head.y; break; case DIRECTION_DOWN: _gm.height = head.y + head.height - _gm.y; break; case DIRECTION_LEFT: _gm.width = getRX() - head.x; _gm.x = head.x; break; case DIRECTION_RIGHT: _gm.width = head.x + head.width - _gm.x; break; default: break; } downSize(_gm, (direction != DIRECTION_LEFT), (direction != DIRECTION_UP)); moveResize(_gm.x, _gm.y, _gm.width, _gm.height); } //! @brief Closes the frame and all clients in it void Frame::close(void) { vector::const_iterator it(_children.begin()); for (; it != _children.end(); ++it) { static_cast(*it)->close(); } } //! @brief Reads autoprops for the active client. //! @param type Defaults to APPLY_ON_RELOAD void Frame::readAutoprops(ApplyOn type) { if ((type != APPLY_ON_RELOAD) && (type != APPLY_ON_WORKSPACE)) return; _class_hint->title = _client->getTitle()->getReal(); AutoProperty *data = AutoProperties::instance()->findAutoProperty(_class_hint, _workspace, type); _class_hint->title = L""; if (! data) { return; } // Set the correct group of the window _class_hint->group = data->group_name; if (_class_hint == _client->getClassHint() && (_client->isTransient() && ! data->isApplyOn(APPLY_ON_TRANSIENT))) { return; } if (data->isMask(AP_STICKY) && _sticky != data->sticky) { stick(); } if (data->isMask(AP_SHADED) && (isShaded() != data->shaded)) { setShaded(STATE_UNSET); } if (data->isMask(AP_MAXIMIZED_HORIZONTAL) && (_maximized_horz != data->maximized_horizontal)) { setStateMaximized(STATE_TOGGLE, true, false, false); } if (data->isMask(AP_MAXIMIZED_VERTICAL) && (_maximized_vert != data->maximized_vertical)) { setStateMaximized(STATE_TOGGLE, false, true, false); } if (data->isMask(AP_FULLSCREEN) && (_fullscreen != data->fullscreen)) { setStateFullscreen(STATE_TOGGLE); } if (data->isMask(AP_ICONIFIED) && (_iconified != data->iconified)) { if (_iconified) { mapWindow(); } else { iconify(); } } if (data->isMask(AP_WORKSPACE)) { // In order to avoid eternal recursion, the workspace is only set here // and then actually called PDecor::setWorkspace from Frame::setWorkspace if (type == APPLY_ON_WORKSPACE) { _workspace = data->workspace; } else if (_workspace != data->workspace) { // Call PDecor directly to avoid recursion. PDecor::setWorkspace(data->workspace); } } if (data->isMask(AP_SHADED) && (isShaded() != data->shaded)) { setShaded(STATE_TOGGLE); } if (data->isMask(AP_LAYER) && (data->layer <= LAYER_MENU)) { _client->setLayer(data->layer); raise(); // restack the frame } if (data->isMask(AP_FRAME_GEOMETRY|AP_CLIENT_GEOMETRY)) { setupAPGeometry(_client, data); // Apply changes moveResize(_gm.x, _gm.y, _gm.width, _gm.height); } if (data->isMask(AP_BORDER) && (hasBorder() != data->border)) { setStateDecorBorder(STATE_TOGGLE); } if (data->isMask(AP_TITLEBAR) && (hasTitlebar() != data->titlebar)) { setStateDecorTitlebar(STATE_TOGGLE); } if (data->isMask(AP_SKIP)) { _client->setSkip(data->skip); setSkip(_client->getSkip()); } if (data->isMask(AP_FOCUSABLE)) { _client->setFocusable(data->focusable); } } //! @brief Figure out how large the frame is in cells. void Frame::calcSizeInCells(uint &width, uint &height) { const XSizeHints *hints = _client->getXSizeHints(); if (hints->flags&PResizeInc) { width = (getChildWidth() - hints->base_width) / hints->width_inc; height = (getChildHeight() - hints->base_height) / hints->height_inc; } else { width = _gm.width; height = _gm.height; } } void Frame::setGravityPosition(int gravity, int &x, int &y, int w, int h) { switch (gravity) { case NorthWestGravity: break; case NorthGravity: x = x - w/2; break; case NorthEastGravity: x = x - w; break; case WestGravity: y = y - h/2; break; case CenterGravity: x = x - w/2; y = y - h/2; break; case EastGravity: x = x - w; y = y - h/2; break; case SouthWestGravity: y = y - h; break; case SouthGravity: x = x - w/2; y = y - h; break; case SouthEastGravity: x = x - w; y = y - h; break; case StaticGravity: // FIXME: What should we do here? break; default: break; } } /** * Makes gm conform to _clients width and height inc. */ void Frame::downSize(Geometry &gm, bool keep_x, bool keep_y) { XSizeHints *size_hint = _client->getXSizeHints(); // convenience // conform to width_inc if (size_hint->flags&PResizeInc) { int o_r = getRX(); int b_x = (size_hint->flags&PBaseSize) ? size_hint->base_width : (size_hint->flags&PMinSize) ? size_hint->min_width : 0; gm.width -= (getChildWidth() - b_x) % size_hint->width_inc; if (! keep_x) { gm.x = o_r - gm.width; } } // conform to height_inc if (size_hint->flags&PResizeInc) { int o_b = getBY(); int b_y = (size_hint->flags&PBaseSize) ? size_hint->base_height : (size_hint->flags&PMinSize) ? size_hint->min_height : 0; gm.height -= (getChildHeight() - b_y) % size_hint->height_inc; if (! keep_y) { gm.y = o_b - gm.height; } } } // Below this Client message handling is done //! @brief Handle XConfgiureRequestEvents void Frame::handleConfigureRequest(XConfigureRequestEvent *ev, Client *client) { if (client != _client) { _client->configureRequestSend(); return; // only handle the active client's events } // Update the stacking (ev->value_mask&CWSibling should not happen) if (! client->isCfgDeny(CFG_DENY_STACKING) && ev->value_mask&CWStackMode) { if (ev->detail == Above) { raise(); } else if (ev->detail == Below) { lower(); } // ignore TopIf, BottomIf, Opposite - PekWM is a reparenting WM } // Update the geometry if requested bool chg_size = ! _client->isCfgDeny(CFG_DENY_SIZE) && (ev->value_mask&(CWWidth|CWHeight)); bool chg_pos = ! _client->isCfgDeny(CFG_DENY_POSITION) && (ev->value_mask&(CWX|CWY)); if (! (chg_size || chg_pos) || (Workspaces::isTiling(_workspace) && allowTiling())) { _client->configureRequestSend(); return; } if (Config::instance()->isFullscreenDetect() && (ev->value_mask&(CWX|CWY|CWWidth|CWHeight)) == (CWX|CWY|CWWidth|CWHeight) && isRequestGeometryFullscreen(ev)) { if (isFullscreen()) { _client->configureRequestSend(); } else { setStateFullscreen(STATE_SET); } return; } Geometry gm = _gm; if (chg_size) { int diff_w = ev->width - gm.width + borderLeft() + borderRight(); gm.width += diff_w; int diff_h = ev->height - gm.height + borderTop() + borderBottom() + getTitleHeight(); gm.height += diff_h; if (!chg_pos) { setGravityPosition(_client->getXSizeHints()->win_gravity, gm.x, gm.y, diff_w, diff_h); } } if (chg_pos) { gm.x = ev->x; gm.y = ev->y; } X11::keepVisible(gm); if (Config::instance()->isFullscreenDetect() && isFullscreen()) { _old_gm = gm; setStateFullscreen(STATE_UNSET); return; } moveResize(gm.x, gm.y, gm.width, gm.height); } /** * Check if requested size if "fullscreen" */ bool Frame::isRequestGeometryFullscreen(XConfigureRequestEvent *ev) { if (_client->isCfgDeny(CFG_DENY_SIZE) || _client->isCfgDeny(CFG_DENY_POSITION) || ! _client->allowFullscreen()) { return false; } int nearest_head = X11::getNearestHead(ev->x, ev->y); Geometry gm_request(ev->x, ev->y, ev->width, ev->height); Geometry gm_screen(X11::getScreenGeometry()); Geometry gm_head(X11::getHeadGeometry(nearest_head)); bool is_fullscreen = false; if (gm_request == gm_screen || gm_request == gm_head) { is_fullscreen = true; } else { downSize(gm_screen, true, true); downSize(gm_head, true, true); if (gm_request == gm_screen || gm_request == gm_head) { is_fullscreen = true; } } return is_fullscreen; } /** * Handle client message. */ void Frame::handleClientMessage(XClientMessageEvent *ev, Client *client) { if (ev->message_type == X11::getAtom(STATE)) { handleClientStateMessage(ev, client); } else if (ev->message_type == X11::getAtom(NET_ACTIVE_WINDOW)) { if (! client->isCfgDeny(CFG_DENY_ACTIVE_WINDOW)) { // Active child if it's not the active child if (client != _client) { activateChild(client); } // If we aren't mapped we check if we make sure we're on the right // workspace and then map the window. if (! _mapped) { if (_workspace != Workspaces::getActive() && !isSticky()) { Workspaces::setWorkspace(_workspace, false); } mapWindow(); } // Seems as if raising the window is implied in activating it raise(); giveInputFocus(); } } else if (ev->message_type == X11::getAtom(NET_CLOSE_WINDOW)) { client->close(); } else if (ev->message_type == X11::getAtom(NET_WM_DESKTOP)) { if (client == _client) { setWorkspace(ev->data.l[0]); } } else if (ev->message_type == X11::getAtom(WM_CHANGE_STATE) && (ev->format == 32) && (ev->data.l[0] == IconicState)) { if (client == _client) { iconify(); } } else if (ev->message_type == X11::getAtom(NET_WM_MOVERESIZE) && ev->format == 32) { if (Workspaces::isTiling(getWorkspace()) && allowTiling()) { return; } switch (ev->data.l[2]) { case NET_WM_MOVERESIZE_SIZE_TOPLEFT: doResize(true, true, true, true); break; case NET_WM_MOVERESIZE_SIZE_TOP: doResize(false, false, true, true); break; case NET_WM_MOVERESIZE_SIZE_TOPRIGHT: doResize(false, true, true, true); break; case NET_WM_MOVERESIZE_SIZE_RIGHT: doResize(false, true, false, false); break; case NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT: doResize(false, true, false, true); break; case NET_WM_MOVERESIZE_SIZE_BOTTOM: doResize(false, false, false, true); break; case NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT: doResize(true, true, false, true); break; case NET_WM_MOVERESIZE_SIZE_LEFT: doResize(true, true, false, false); break; case NET_WM_MOVERESIZE_MOVE: doMove(ev->data.l[0], ev->data.l[1]); break; case NET_WM_MOVERESIZE_SIZE_KEYBOARD: case NET_WM_MOVERESIZE_MOVE_KEYBOARD: doKeyboardMoveResize(); break; } } } /** * Handle _NET_WM_STATE atom. */ void Frame::handleClientStateMessage(XClientMessageEvent *ev, Client *client) { StateAction sa = getStateActionFromMessage(ev); handleStateAtom(sa, ev->data.l[1], client); if (ev->data.l[2] != 0) { handleStateAtom(sa, ev->data.l[2], client); } client->updateEwmhStates(); } /** * Get StateAction from NET_WM atom. */ StateAction Frame::getStateActionFromMessage(XClientMessageEvent *ev) { StateAction sa = STATE_SET; if (ev->data.l[0]== NET_WM_STATE_REMOVE) { sa = STATE_UNSET; } else if (ev->data.l[0]== NET_WM_STATE_ADD) { sa = STATE_SET; } else if (ev->data.l[0]== NET_WM_STATE_TOGGLE) { sa = STATE_TOGGLE; } return sa; } /** * Handle state atom for client. */ void Frame::handleStateAtom(StateAction sa, Atom atom, Client *client) { if (client == _client) { handleCurrentClientStateAtom(sa, atom, client); } switch (atom) { case STATE_SKIP_TASKBAR: client->setStateSkip(sa, SKIP_TASKBAR); break; case STATE_SKIP_PAGER: client->setStateSkip(sa, SKIP_PAGER); break; case STATE_DEMANDS_ATTENTION: bool ostate = client->demandsAttention(); bool nstate = (sa == STATE_SET || (sa == STATE_TOGGLE && ! ostate)); client->setDemandsAttention(nstate); if (ostate != nstate) { if (ostate) { decrAttention(); } else { incrAttention(); } } break; } } /** * Handle state atom for actions that apply only on active client. */ void Frame::handleCurrentClientStateAtom(StateAction sa, Atom atom, Client *client) { if (atom == X11::getAtom(STATE_STICKY)) { setStateSticky(sa); } if (atom == X11::getAtom(STATE_MAXIMIZED_HORZ) && ! client->isCfgDeny(CFG_DENY_STATE_MAXIMIZED_HORZ)) { setStateMaximized(sa, true, false, false); } if (atom == X11::getAtom(STATE_MAXIMIZED_VERT) && ! client->isCfgDeny(CFG_DENY_STATE_MAXIMIZED_VERT)) { setStateMaximized(sa, false, true, false); } if (atom == X11::getAtom(STATE_SHADED)) { setShaded(sa); } if (atom == X11::getAtom(STATE_HIDDEN) && ! client->isCfgDeny(CFG_DENY_STATE_HIDDEN)) { setStateIconified(sa); } if (atom == X11::getAtom(STATE_FULLSCREEN) && ! client->isCfgDeny(CFG_DENY_STATE_FULLSCREEN)) { setStateFullscreen(sa); } if (atom == X11::getAtom(STATE_ABOVE) && ! client->isCfgDeny(CFG_DENY_STATE_ABOVE)) { setStateAlwaysOnTop(sa); } if (atom == X11::getAtom(STATE_BELOW) && ! client->isCfgDeny(CFG_DENY_STATE_BELOW)) { setStateAlwaysBelow(sa); } } //! @brief void Frame::handlePropertyChange(XPropertyEvent *ev, Client *client) { if (ev->atom == X11::getAtom(NET_WM_DESKTOP)) { if (client == _client) { long workspace; if (X11::getLong(client->getWindow(), NET_WM_DESKTOP, workspace)) { if (workspace != signed(_workspace)) setWorkspace(workspace); } } } else if (ev->atom == X11::getAtom(NET_WM_STRUT)) { client->getStrutHint(); } else if (ev->atom == X11::getAtom(NET_WM_NAME) || ev->atom == XA_WM_NAME) { handleTitleChange(client); } else if (ev->atom == X11::getAtom(MOTIF_WM_HINTS)) { client->readMwmHints(); if (! isFullscreen() && _client == client) { setBorder(_client->hasBorder()?STATE_SET:STATE_UNSET); setTitlebar(_client->hasTitlebar()?STATE_SET:STATE_UNSET); } } else if (ev->atom == XA_WM_NORMAL_HINTS) { client->getWMNormalHints(); } else if (ev->atom == XA_WM_TRANSIENT_FOR) { client->getTransientForHint(); } else if (ev->atom == X11::getAtom(WM_HINTS)) { bool ostate = client->demandsAttention(); client->getWMHints(); bool nstate = client->demandsAttention(); if (ostate != nstate) { if (ostate) { decrAttention(); } else { incrAttention(); } } } else if (ev->atom == X11::getAtom(WM_PROTOCOLS)) { client->getWMProtocols(); } } /** * Handle title change, find decoration rules based on changed title * and update if changed. */ void Frame::handleTitleChange(Client *client) { // Update title client->readName(); if (client != _client || ! updateDecor()) { // Render title as either the title changed was not the active // title or the name change did not cause the decor to change. renderTitle(); } } pekwm-release-0.1.18/src/Frame.hh000066400000000000000000000161741374756504400165340ustar00rootroot00000000000000// // Frame.hh for pekwm // Copyright © 2003-2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifndef _FRAME_HH_ #define _FRAME_HH_ #include "config.h" #include "pekwm.hh" #include "Action.hh" #include "PDecor.hh" #include "Client.hh" class PWinObj; class Strut; class ClassHint; class AutoProperty; #include class Frame : public PDecor { public: Frame(Client *client, AutoProperty *ap); virtual ~Frame(void); // START - PWinObj interface. virtual void iconify(void); virtual void stick(void); virtual void setWorkspace(unsigned int workspace); virtual void setLayer(Layer layer); virtual ActionEvent *handleMotionEvent(XMotionEvent *ev); virtual ActionEvent *handleEnterEvent(XCrossingEvent *ev); virtual ActionEvent *handleLeaveEvent(XCrossingEvent *ev); virtual ActionEvent *handleMapRequest(XMapRequestEvent *ev); virtual ActionEvent *handleUnmapEvent(XUnmapEvent *ev); // END - PWinObj interface. #ifdef HAVE_SHAPE virtual void handleShapeEvent(XShapeEvent *ev); #endif // START - PDecor interface. virtual bool allowMove(void) const; virtual void addChild(PWinObj *child, vector::iterator *it = 0); virtual void removeChild(PWinObj *child, bool do_delete = true); virtual void activateChild(PWinObj *child); virtual void updatedChildOrder(void); virtual void updatedActiveChild(void); virtual bool allowTiling(void) { return ! (isSticky() || _client->isCfgDeny(CFG_DENY_TILING)); } virtual void getDecorInfo(wchar_t *buf, uint size); virtual void giveInputFocus(void); virtual void setShaded(StateAction sa); virtual void setSkip(uint skip); // END - PDecor interface. Client *getActiveClient(void); void addChildOrdered(Client *child); static Frame *findFrameFromWindow(Window win); static Frame *findFrameFromID(uint id); // START - Iterators static uint frame_size(void) { return _frames.size(); } static vector::const_iterator frame_begin(void) { return _frames.begin(); } static vector::const_iterator frame_end(void) { return _frames.end(); } static vector::const_reverse_iterator frame_rbegin(void) { return _frames.rbegin(); } static vector::const_reverse_iterator frame_rend(void) { return _frames.rend(); } Client *getTransFor(void) const { return _client?_client->getTransientForClient():0; } bool hasTrans(void) const { return _client && _client->hasTransients(); } // Call getTransBegin() only (!) if hasTrans() == true. vector::const_iterator getTransBegin(void) const { return _client->getTransientsBegin(); } // Call getTransEnd() only (!) if hasTrans() == true. vector::const_iterator getTransEnd(void) const { return _client->getTransientsEnd(); } // END - Iterator inline uint getId(void) const { return _id; } void setId(uint id); void detachClient(Client *client); inline const ClassHint* getClassHint(void) const { return _class_hint; } void setGeometry(const std::string geometry, int head=-1); void setGeometry(const Geometry &geometry, int gm_mask, int head=-1); void growDirection(uint direction); void moveToHead(int head_nr); void moveToEdge(OrientationType ori); void updateInactiveChildInfo(void); // state actions void setStateMaximized(StateAction sa, bool horz, bool vert, bool fill); void setStateFullscreen(StateAction sa); void setStateSticky(StateAction sa); void setStateAlwaysOnTop(StateAction sa); void setStateAlwaysBelow(StateAction sa); void setStateDecorBorder(StateAction sa); void setStateDecorTitlebar(StateAction sa); void setStateIconified(StateAction sa); void setStateTagged(StateAction sa, bool behind); void setStateSkip(StateAction sa, uint skip); void setStateTitle(StateAction sa, Client *client, const std::wstring &title); void setStateMarked(StateAction sa, Client *client); void setStateOpaque(StateAction sa); void close(void); void readAutoprops(ApplyOn type = APPLY_ON_RELOAD); void doResize(XMotionEvent *ev); // redirects to doResize(bool... void doResize(BorderPosition pos); // redirect to doResize(bool... void doResize(bool left, bool x, bool top, bool y); void doGroupingDrag(XMotionEvent *ev, Client *client, bool behind); bool fixGeometry(void); // client message handling void handleConfigureRequest(XConfigureRequestEvent *ev, Client *client); void handleClientMessage(XClientMessageEvent *ev, Client *client); void handlePropertyChange(XPropertyEvent *ev, Client *client); static Frame *getTagFrame(void) { return _tag_frame; } static bool getTagBehind(void) { return _tag_behind; } static void resetFrameIDs(void); protected: // BEGIN - PDecor interface virtual int resizeHorzStep(int diff) const; virtual int resizeVertStep(int diff) const; std::string getDecorName(void); // END - PDecor interface private: void handleClientStateMessage(XClientMessageEvent *ev, Client *client); static StateAction getStateActionFromMessage(XClientMessageEvent *ev); void handleStateAtom(StateAction sa, Atom atom, Client *client); void handleCurrentClientStateAtom(StateAction sa, Atom atom, Client *client); bool isRequestGeometryFullscreen(XConfigureRequestEvent *ev); void recalcResizeDrag(int nx, int ny, bool left, bool top); void getMaxBounds(int &max_x,int &max_r, int &max_y, int &max_b); void calcSizeInCells(uint &width, uint &height); void setGravityPosition(int gravity, int &x, int &y, int diff_w, int diff_h); void downSize(Geometry &gm, bool keep_x, bool keep_y); void handleTitleChange(Client *client); void getState(Client *cl); void applyState(Client *cl); void setupAPGeometry(Client *client, AutoProperty *ap); void applyGeometry(Geometry &gm, const Geometry &ap_gm, int mask); void applyGeometry(Geometry &gm, const Geometry &ap_gm, int mask, const Geometry &screen_gm); void setActiveTitle(void); static uint findFrameID(void); static void returnFrameID(uint id); private: uint _id; // unique id of the frame Client *_client; // to skip all the casts from PWinObj ClassHint *_class_hint; // frame information used when maximizing / going fullscreen Geometry _old_gm; // FIXME: move to PDecor? uint _non_fullscreen_decor_state; // FIXME: move to PDecor? Layer _non_fullscreen_layer; static vector _frames; //!< Vector of all Frames. static vector _frameid_list; //!< Vector of free Frame IDs. // Tagging, static as only one Frame can be tagged static Frame *_tag_frame; //!< Pointer to tagged frame. static bool _tag_behind; //!< Tagging actions will set behind. // EWMH static const int NET_WM_STATE_REMOVE = 0; // remove/unset property static const int NET_WM_STATE_ADD = 1; // add/set property static const int NET_WM_STATE_TOGGLE = 2; // toggle property }; #endif // _FRAME_HH_ pekwm-release-0.1.18/src/FrameListMenu.cc000066400000000000000000000171131374756504400201750ustar00rootroot00000000000000// // FrameListMenu.cc for pekwm // Copyright © 2002-2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "config.h" #include #include #include #include "Compat.hh" #include "PWinObj.hh" #include "PDecor.hh" #include "PMenu.hh" #include "WORefMenu.hh" #include "FrameListMenu.hh" #include "Config.hh" #include "Client.hh" #include "Frame.hh" #include "Workspaces.hh" #include "WindowManager.hh" using std::cerr; using std::endl; using std::list; using std::string; using std::vector; using std::wstring; //! @brief FrameListMenu constructor. //! @param theme Pointer to Theme //! @param type Type of menu. //! @param title Title of menu. //! @param name Name of menu //! @param decor_name Decor name, defaults to MENU FrameListMenu::FrameListMenu(Theme *theme, MenuType type, const std::wstring &title, const std::string &name, const std::string &decor_name) : WORefMenu(theme, title, name, decor_name) { _menu_type = type; } //! @brief FrameListMenu destructor FrameListMenu::~FrameListMenu(void) { } // START - PWinObj interface. //! @brief Rebuilds the menu and if it has any items after it shows it. void FrameListMenu::mapWindow(void) { updateFrameListMenu(); if (size() > 0) { WORefMenu::mapWindow(); } } // END - PWinObj interface. /** * Execute item execution. */ void FrameListMenu::handleItemExec(PMenu::Item *item) { if (! item) { return; } Client *item_client = dynamic_cast(item->getWORef()); Client *wo_ref_client = dynamic_cast(getWORef()); switch (_menu_type) { case GOTOMENU_TYPE: case GOTOCLIENTMENU_TYPE: handleGotomenu(item_client); break; case ICONMENU_TYPE: handleIconmenu(item_client); break; case ATTACH_CLIENT_TYPE: case ATTACH_FRAME_TYPE: handleAttach(wo_ref_client, item_client, (_menu_type == ATTACH_FRAME_TYPE)); break; case ATTACH_CLIENT_IN_FRAME_TYPE: case ATTACH_FRAME_IN_FRAME_TYPE: handleAttach(item_client, wo_ref_client, (_menu_type == ATTACH_FRAME_IN_FRAME_TYPE)); break; default: // do nothing break; } } //! @brief Rebuilds the menu. void FrameListMenu::updateFrameListMenu(void) { removeAll(); wchar_t buf[16]; wstring name; // need to add an action, otherwise it looks as if we don't have anything // to exec and thus it doesn't get handled. Action action; ActionEvent ae; ae.action_list.push_back(action); // Decide wheter to show clients and iconified. bool show_clients = false, show_iconified_only = false; if (_menu_type == ATTACH_CLIENT_TYPE || _menu_type == GOTOCLIENTMENU_TYPE) { show_clients = true; } else if (_menu_type == ICONMENU_TYPE) { show_iconified_only = true; } // if we have 1 workspace, we won't put an workspace indicator buf[0] = '\0'; vector::const_iterator it; for (uint i = 0; i < Workspaces::size(); ++i) { if (Workspaces::size() > 1) { swprintf(buf, 16, L"<%d> ", i + 1); } for (it = Frame::frame_begin(); it != Frame::frame_end(); ++it) { if (((*it)->getWorkspace() == i) && // sort by workspace // don't include ourselves if we're not doing a gotoclient menu ((_menu_type != GOTOCLIENTMENU_TYPE) ? ((*it)->getActiveChild() != getWORef()) : true) && (show_iconified_only ? (*it)->isIconified() : !(*it)->isSkip(SKIP_MENUS))) { name = buf; if (show_clients) { buildFrameNames(*it, name); } else { buildName(*it, name); name.append(L"] "); name.append(static_cast((*it)->getActiveChild())->getTitle()->getVisible()); insert(name, ae, (*it)->getActiveChild(), static_cast((*it)->getActiveChild())->getIcon()); } } } } // remove the last separator, not needed if (show_clients && size() > 0) { remove(_items.back()); } buildMenu(); } //! @brief Builds the name for the frame. void FrameListMenu::buildName(Frame* frame, std::wstring &name) { name.append(L"["); if (frame->isSticky()) { name.append(L"*"); } if (frame->isIconified()) { name.append(L"."); } if (frame->isShaded()) { name.append(L"^"); } if (frame->getActiveChild()->getLayer() > LAYER_NORMAL) { name.append(L"+"); } else if (frame->getActiveChild()->getLayer() < LAYER_NORMAL) { name.append(L"-"); } } //! @brief Builds names for all the clients in a frame. void FrameListMenu::buildFrameNames(Frame *frame, std::wstring &pre_name) { wstring name, status_name; // need to add an action, otherwise it looks as if we don't have anything // to exec and thus it doesn't get handled. Action action; ActionEvent ae; ae.action_list.push_back(action); buildName(frame, status_name); // add states to the name vector::const_iterator it(frame->begin()); for (; it != frame->end(); ++it) { name = pre_name; name.append(status_name); if (frame->getActiveChild() == *it) { name.append(L"A"); } name.append(L"] "); name.append(static_cast(*it)->getTitle()->getVisible()); insert(name, ae, *it, static_cast(*it)->getIcon()); } // add separator PMenu::Item *item = new PMenu::Item(L""); item->setType(PMenu::Item::MENU_ITEM_SEPARATOR); insert(item); } //! @brief Handles gotomeu presses void FrameListMenu::handleGotomenu(Client *client) { if (! client) { return; } Frame *frame = static_cast(client->getParent()); // make sure it's on correct workspace if (! frame->isSticky() && (frame->getWorkspace() != Workspaces::getActive())) { Workspaces::setWorkspace(frame->getWorkspace(), false); } // make sure it isn't hidden if (! frame->isMapped()) { frame->mapWindow(); } frame->activateChild(client); frame->raise(); frame->giveInputFocus(); } //! @brief Handles iconmenu presses void FrameListMenu::handleIconmenu(Client *client) { if (! client) { return; } Frame *frame = static_cast(client->getParent()); // make sure it's on the current workspace if (frame->getWorkspace() != Workspaces::getActive()) { frame->setWorkspace(Workspaces::getActive()); } frame->raise(); frame->mapWindow(); frame->giveInputFocus(); } //! @brief Handles attach*menu presses void FrameListMenu::handleAttach(Client *client_to, Client *client_from, bool frame) { if (! client_to || ! client_from) { return; } Frame *frame_to = static_cast(client_to->getParent()); Frame *frame_from = static_cast(client_from->getParent()); // insert frame if (frame) { frame_to->addDecor(frame_from); // insert client } else if (frame_to != frame_from) { frame_from->removeChild(client_from); client_from->setWorkspace(frame_to->getWorkspace()); frame_to->addChild(client_from); frame_to->activateChild(client_from); frame_to->giveInputFocus(); } } pekwm-release-0.1.18/src/FrameListMenu.hh000066400000000000000000000023011374756504400202000ustar00rootroot00000000000000// // FrameListMenu.hh for pekwm // Copyright © 2003-2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifndef _FRAMELISTMENU_HH_ #define _FRAMELISTMENU_HH_ #include "config.h" #include "pekwm.hh" #include "PMenu.hh" #include #include class WORefMenu; class PScreen; class Theme; class Frame; class Client; class FrameListMenu : public WORefMenu { public: FrameListMenu(Theme *theme, MenuType type, const std::wstring &title, const std::string &name, const std::string &decor_name = "MENU"); virtual ~FrameListMenu(void); // START - PWinObj interface. virtual void mapWindow(void); // END - PWinObj interface. virtual void handleItemExec(PMenu::Item *item); private: void updateFrameListMenu(void); private: void buildName(Frame *frame, std::wstring &name); void buildFrameNames(Frame *frame, std::wstring &pre_name); void handleGotomenu(Client *client); void handleIconmenu(Client *client); void handleAttach(Client *client_to, Client *client_from, bool frame); }; #endif // _FRAMELISTMENU_HH_ pekwm-release-0.1.18/src/Handler.hh000066400000000000000000000017321374756504400170510ustar00rootroot00000000000000// // Handler.hh for pekwm // Copyright (C) 2004-2009 Claes Nasten // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "config.h" #ifndef _HANDLER_HH_ #define _HANDLER_HH_ #include #include template class HandlerEntry { public: HandlerEntry(const std::string &name) : _name(name), _ref(0) { } virtual ~HandlerEntry(void) { } const std::string &getName(void) { return _name; } inline T getData(void) { return _data; } inline void setData(T data) { _data = data; } inline uint getRef(void) const { return _ref; } inline void incRef(void) { _ref++; } inline void decRef(void) { if (_ref > 0) { _ref--; } } inline bool operator==(const std::string &name) { return (strcasecmp(_name.c_str(), name.c_str()) == 0); } private: std::string _name; // id uint _ref; // ref count T _data; }; #endif // _HANDLER_HH_ pekwm-release-0.1.18/src/Harbour.cc000066400000000000000000000371021374756504400170640ustar00rootroot00000000000000// // Harbour.cc for pekwm // Copyright © 2003-2009 Claes Nästen // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "config.h" #include "Harbour.hh" #include "x11.hh" #include "Config.hh" #include "PWinObj.hh" #include "DockApp.hh" #include "Workspaces.hh" #include "AutoProperties.hh" #include "PDecor.hh" #include "PMenu.hh" #include #include using std::mem_fun; using std::find; #ifdef DEBUG #include using std::cerr; using std::endl; #endif // DEBUG //! @brief Harbour constructor Harbour::Harbour(void) : _hidden(false), _size(0), _strut(0), _last_button_x(0), _last_button_y(0) { _strut = new Strut(); X11::addStrut(_strut); _strut->head = Config::instance()->getHarbourHead(); } //! @brief Harbour destructor Harbour::~Harbour(void) { removeAllDockApps(); X11::removeStrut(_strut); delete _strut; } //! @brief Adds a DockApp to the Harbour //! @todo Add sort option void Harbour::addDockApp(DockApp *da) { if (! da) { return; } // add to the list if (AutoProperties::instance()->isHarbourSort()) { insertDockAppSorted(da); placeDockAppsSorted(); // place in sorted way } else { _dapps.push_back(da); placeDockApp(da); // place it in a empty space } da->setLayer(Config::instance()->isHarbourOntop() ? LAYER_DOCK : LAYER_DESKTOP); Workspaces::insert(da); // add the dockapp to the stacking list if (! da->isMapped()) { // make sure it's visible da->mapWindow(); } da->setOpacity(Config::instance()->getHarbourOpacity()); updateHarbourSize(); } //! @brief Removes a DockApp from the Harbour void Harbour::removeDockApp(DockApp *da) { if (! da) return; vector::iterator it(find(_dapps.begin(), _dapps.end(), da)); if (it != _dapps.end()) { _dapps.erase(it); Workspaces::remove(da); // remove the dockapp to the stacking list delete da; if (AutoProperties::instance()->isHarbourSort()) { placeDockAppsSorted(); } } updateHarbourSize(); } //! @brief Removes all DockApps from the Harbour void Harbour::removeAllDockApps(void) { vector::const_iterator it(_dapps.begin()); for (; it != _dapps.end(); ++it) { Workspaces::remove(*it); // remove the dockapp to the stacking list delete (*it); } _dapps.clear(); } //! @brief Tries to find a dockapp which uses the window win DockApp* Harbour::findDockApp(Window win) { DockApp *dockapp = 0; vector::const_iterator it(_dapps.begin()); for (; it != _dapps.end(); ++it) { if ((*it)->findDockApp(win)) { dockapp = (*it); break; } } return dockapp; } //! @brief Tries to find a dockapp which has the window win as frame. DockApp* Harbour::findDockAppFromFrame(Window win) { DockApp *dockapp = 0; vector::const_iterator it(_dapps.begin()); for (; it != _dapps.end(); ++it) { if ((*it)->findDockAppFromFrame(win)) { dockapp = (*it); break; } } return dockapp; } #ifdef HAVE_XRANDR //! @brief Refetches the root-window size and takes appropriate actions. void Harbour::updateGeometry(void) { vector::const_iterator it(_dapps.begin()); for (; it != _dapps.end(); ++it) { placeDockAppInsideScreen(*it); } } #endif // HAVE_XRANDR //! @brief Lowers or Raises all the DockApps in the harbour. void Harbour::restack(void) { X11::removeStrut(_strut); if (Config::instance()->isHarbourOntop() || ! Config::instance()->isHarbourMaximizeOver()) { X11::addStrut(_strut); } Layer l = Config::instance()->isHarbourOntop() ? LAYER_DOCK : LAYER_DESKTOP; vector::const_iterator it(_dapps.begin()); for (; it != _dapps.end(); ++it) { (*it)->setLayer(l); if (Config::instance()->isHarbourOntop()) { Workspaces::raise(*it); } else { Workspaces::lower(*it); } } } //! @brief Goes through the DockApp list and places the dockapp. void Harbour::rearrange(void) { _strut->head = Config::instance()->getHarbourHead(); if (AutoProperties::instance()->isHarbourSort()) { placeDockAppsSorted(); } else { vector::const_iterator it(_dapps.begin()); for (; it != _dapps.end(); ++it) placeDockApp(*it); } } //! @brief Repaints all dockapps with the new theme void Harbour::loadTheme(void) { for_each(_dapps.begin(), _dapps.end(), mem_fun(&DockApp::loadTheme)); } //! @brief Updates the harbour max size variable. void Harbour::updateHarbourSize(void) { _size = 0; vector::const_iterator it(_dapps.begin()); for (; it != _dapps.end(); ++it) { switch (Config::instance()->getHarbourPlacement()) { case TOP: case BOTTOM: if ((*it)->getHeight() > _size) _size = (*it)->getHeight(); break; case LEFT: case RIGHT: if ((*it)->getWidth() > _size) _size = (*it)->getWidth(); break; default: // Do nothing. break; } } updateStrutSize(); } //! @brief Sets the Hidden state of the harbour //! @param sa StateAction specifying state to set. void Harbour::setStateHidden(StateAction sa) { // Check if there is anything to do if (! ActionUtil::needToggle(sa, _hidden)) { return; } if (_hidden) { // Show if currently hidden. for_each(_dapps.begin(), _dapps.end(), mem_fun(&DockApp::mapWindow)); } else { // Hide if currently visible. for_each(_dapps.begin(), _dapps.end(), mem_fun(&DockApp::unmapWindow)); } _hidden = !_hidden; updateStrutSize(); } //! @brief Updates Harbour strut size. void Harbour::updateStrutSize(void) { _strut->left = _strut->right = _strut->top = _strut->bottom = 0; if (! Config::instance()->isHarbourMaximizeOver() && ! _hidden) { switch (Config::instance()->getHarbourPlacement()) { case TOP: _strut->top = _size; break; case BOTTOM: _strut->bottom = _size; break; case LEFT: _strut->left = _size; break; case RIGHT: _strut->right = _size; break; } } X11::updateStrut(); } //! @brief Handles XButtonEvents made on the DockApp's frames. void Harbour::handleButtonEvent(XButtonEvent* ev, DockApp* da) { if (! da) { return; } _last_button_x = ev->x; _last_button_y = ev->y; } //! @brief Initiates moving of a DockApp based on info from a XMotionEvent. void Harbour::handleMotionNotifyEvent(XMotionEvent* ev, DockApp* da) { if (! da) { return; } Geometry head; int x = 0, y = 0; X11::getHeadInfo(Config::instance()->getHarbourHead(), head); switch(Config::instance()->getHarbourPlacement()) { case TOP: case BOTTOM: x = ev->x_root - _last_button_x; y = da->getY(); if (x < head.x) { x = head.x; } else if ((x + da->getWidth()) > (head.x + head.width)) { x = head.x + head.width - da->getWidth(); } break; case LEFT: case RIGHT: x = da->getX(); y = ev->y_root - _last_button_y; if (y < head.y) { y = head.y; } else if ((y + da->getHeight()) > (head.y + head.height)) { y = head.y + head.height - da->getHeight(); } break; default: // do nothing break; } da->move(x, y); } //! @brief Handles XConfigureRequestEvents. void Harbour::handleConfigureRequestEvent(XConfigureRequestEvent* ev, DockApp* da) { if (! da) { return; } vector::const_iterator it(find(_dapps.begin(), _dapps.end(), da)); if (it != _dapps.end()) { // Thing is that we doesn't listen to border width, position or // stackign so the only thing that we'll alter is size if that's // what we want to configure uint width = (ev->value_mask&CWWidth) ? ev->width : da->getClientWidth(); uint height = (ev->value_mask&CWHeight) ? ev->height : da->getClientHeight(); da->resize(width, height); placeDockAppInsideScreen(da); } } //! @brief Tries to find a empty spot for the DockApp void Harbour::placeDockApp(DockApp *da) { if (! da || ! _dapps.size()) return; bool right = (Config::instance()->getHarbourOrientation() == BOTTOM_TO_TOP); int test, x = 0, y = 0; bool placed = false, increase = false, x_place = false; Geometry head; X11::getHeadInfo(Config::instance()->getHarbourHead(), head); getPlaceStartPosition (da, x, y, x_place); if (right) { if (x_place) { x -= da->getWidth (); } else { y -= da->getHeight (); } } vector::const_iterator it; if (x_place) { x = test = right ? head.x + head.width - da->getWidth() : head.x; while (! placed && (right ? (test >= 0) : ((test + da->getWidth()) < (head.x + head.width)))) { placed = increase = true; it = _dapps.begin(); for (; placed && it != _dapps.end(); ++it) { if ((*it) == da) { continue; // exclude ourselves } if (((*it)->getX() < static_cast(test + da->getWidth())) && ((*it)->getRX() > test)) { placed = increase = false; test = right ? (*it)->getX() - da->getWidth() : (*it)->getRX(); } } if (placed) { x = test; } else if (increase) { test += right ? -1 : 1; } } } else { // !x_place y = test = right ? head.y + head.height - da->getHeight() : head.y; while (! placed && (right ? (test >= 0) : ((test + da->getHeight()) < (head.y + head.height)))) { placed = increase = true; it = _dapps.begin(); for (; placed && it != _dapps.end(); ++it) { if ((*it) == da) { continue; // exclude ourselves } if (((*it)->getY() < static_cast(test + da->getHeight())) && ((*it)->getBY() > test)) { placed = increase = false; test = right ? (*it)->getY() - da->getHeight() : (*it)->getBY(); } } if (placed) { y = test; } else if (increase) { test += right ? -1 : 1; } } } da->move(x, y); } //! @brief Inserts DockApp and places all dockapps in sorted order //! @todo Screen boundary checking void Harbour::placeDockAppsSorted(void) { if (! _dapps.size()) { return; } // place the dockapps int x, y, x_real, y_real; bool inc_x = false; bool right = (Config::instance()->getHarbourOrientation() == BOTTOM_TO_TOP); getPlaceStartPosition(_dapps.front (), x_real, y_real, inc_x); vector::const_iterator it(_dapps.begin()); for (; it != _dapps.end(); ++it) { getPlaceStartPosition(*it, x, y, inc_x); if (inc_x) { if (right) { (*it)->move(x_real - (*it)->getWidth(), y); x_real -= -(*it)->getWidth(); } else { (*it)->move(x_real, y); x_real += (*it)->getWidth(); } } else { if (right) { (*it)->move(x, y_real - (*it)->getHeight()); y_real -= (*it)->getHeight(); } else { (*it)->move(x, y_real); y_real += (*it)->getHeight(); } } } } /** * Make sure dock app is inside screen boundaries and placed on the * right edge, usually called after resizing the dockapp. */ void Harbour::placeDockAppInsideScreen(DockApp *da) { Geometry head; X11::getHeadInfo(Config::instance()->getHarbourHead(), head); uint pos = Config::instance()->getHarbourPlacement(); // top or bottom placement if ((pos == TOP) || (pos == BOTTOM)) { // check horizontal position if (da->getX() < head.x) { da->move(head.x, da->getY()); } else if (da->getRX() > static_cast(head.x + head.width)) { da->move(head.x + head.width - da->getWidth(), da->getY()); } // check vertical position if ((pos == TOP) && (da->getY() != head.y)) { da->move(da->getX(), head.y); } else if ((pos == BOTTOM) && (da->getBY() != static_cast(head.y + head.height))) { da->move(da->getX(), head.y + head.height - da->getHeight()); } // left or right placement } else { // check vertical position if (da->getY() < head.y) { da->move(da->getX(), head.y); } else if (da->getBY() > static_cast(head.y + head.height)) { da->move(da->getX(), head.y + head.height - da->getHeight()); } // check horizontal position if ((pos == LEFT) && (da->getX() != head.x)) { da->move(head.x, da->getY()); } else if ((pos == RIGHT) && (da->getRX() != static_cast(head.x + head.width))) { da->move(head.x + head.width - da->getWidth(), da->getY()); } } } //! @brief void Harbour::getPlaceStartPosition(DockApp *da, int &x, int &y, bool &inc_x) { if (! da) { return; } Geometry head; X11::getHeadInfo(Config::instance()->getHarbourHead(), head); bool right = (Config::instance()->getHarbourOrientation() == BOTTOM_TO_TOP); switch (Config::instance()->getHarbourPlacement()) { case TOP: inc_x = true; x = right ? head.x + head.width : head.x; y = head.y; break; case BOTTOM: inc_x = true; x = right ? head.x + head.width : head.x; y = head.y + head.height - da->getHeight(); break; case LEFT: x = head.x; y = right ? head.y + head.height : head.y; break; case RIGHT: x = head.x + head.width - da->getWidth(); y = right ? head.y + head.height : head.y; break; } } //! @brief Inserts DockApp in sorted order in the list void Harbour::insertDockAppSorted(DockApp *da) { vector::iterator it(_dapps.begin()); // The order of this list doesn't make much sense to me when // it comes to representing it in code, however it's perfectly sane // for representing the order in the config files. // anyway, order goes as follows: 1 2 3 0 0 0 -3 -2 -1 // Middle of the list. if (da->getPosition() == 0) { for (; it != _dapps.end() && (*it)->getPosition() >= 0; ++it) ; // Beginning of the list. } else if (da->getPosition() > 0) { for (; it != _dapps.end(); ++it) { if (((*it)->getPosition() < 1) || // got to 0 or less (da->getPosition() <= (*it)->getPosition())) { break; } } // end of the list } else { for (; it != _dapps.end() && (*it)->getPosition() >= 0; ++it) ; for (; it != _dapps.end() && da->getPosition() >= (*it)->getPosition(); ++it) ; } _dapps.insert(it, da); } pekwm-release-0.1.18/src/Harbour.hh000066400000000000000000000027321374756504400170770ustar00rootroot00000000000000// // Harbour.hh for pekwm // Copyright (C) 2003-2009 Claes Nasten // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "config.h" #ifndef _HARBOUR_HH_ #define _HARBOUR_HH_ #include "pekwm.hh" class DockApp; class Strut; #include "Action.hh" class Harbour { public: Harbour(void); ~Harbour(void); void addDockApp(DockApp* da); void removeDockApp(DockApp* da); void removeAllDockApps(void); DockApp* findDockApp(Window win); DockApp* findDockAppFromFrame(Window win); inline uint getSize(void) const { return _size; } #ifdef HAVE_XRANDR void updateGeometry(void); #endif // HAVE_XRANDR void restack(void); void rearrange(void); void loadTheme(void); void updateHarbourSize(void); void setStateHidden(StateAction sa); void handleButtonEvent(XButtonEvent* ev, DockApp* da); void handleMotionNotifyEvent(XMotionEvent* ev, DockApp* da); void handleConfigureRequestEvent(XConfigureRequestEvent* ev, DockApp* da); private: void placeDockApp(DockApp *da); void placeDockAppsSorted(void); void placeDockAppInsideScreen(DockApp *da); void getPlaceStartPosition(DockApp *da, int &x, int &y, bool &inc_x); void insertDockAppSorted(DockApp *da); void updateStrutSize(void); vector _dapps; bool _hidden; uint _size; Strut *_strut; int _last_button_x, _last_button_y; }; #endif // _HARBOUR_HH_ pekwm-release-0.1.18/src/ImageHandler.cc000066400000000000000000000106611374756504400200030ustar00rootroot00000000000000// // ImageHandler.cc for pekwm // Copyright © 2003-2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "config.h" #include #include "Config.hh" #include "PImage.hh" #include "ImageHandler.hh" #include "PImageLoaderJpeg.hh" #include "PImageLoaderPng.hh" #include "PImageLoaderXpm.hh" #include "Util.hh" using std::cerr; using std::endl; using std::string; ImageHandler *ImageHandler::_instance = 0; //! @brief ImageHandler constructor ImageHandler::ImageHandler(void) : _free_on_return(false) { #ifdef DEBUG if (_instance) { cerr << __FILE__ << "@" << __LINE__ << ": " << "ImageHandler(" << this << ")::ImageHandler() *** _instance already set: " << _instance << endl; } #endif // DEBUG _instance = this; // setup parsing maps _image_type_map[""] = IMAGE_TYPE_NO; _image_type_map["TILED"] = IMAGE_TYPE_TILED; _image_type_map["SCALED"] = IMAGE_TYPE_SCALED; _image_type_map["FIXED"] = IMAGE_TYPE_FIXED; #ifdef HAVE_IMAGE_JPEG PImage::loaderAdd(new PImageLoaderJpeg()); #endif // HAVE_IMAGE_JPEG #ifdef HAVE_IMAGE_PNG PImage::loaderAdd(new PImageLoaderPng()); #endif // HAVE_IMAGE_PNG #ifdef HAVE_IMAGE_XPM PImage::loaderAdd(new PImageLoaderXpm()); #endif // HAVE_IMAGE_XPM } //! @brief ImageHandler destructor ImageHandler::~ImageHandler(void) { if (_images.size()) { cerr << " *** WARNING: ImageHandler not empty, " << _images.size() << " entries left:" << endl; while (_images.size()) { cerr << " * " << _images.back().getName() << endl; delete _images.back().getData(); _images.pop_back(); } } PImage::loaderClear(); } //! @brief Gets or creates a Image PImage* ImageHandler::getImage(const std::string &file) { if (! file.size()) { return 0; } string real_file(file); ImageType image_type = IMAGE_TYPE_TILED; // Split image in path # type parts. string::size_type pos = file.rfind('#'); if (string::npos != pos) { real_file = file.substr(0, pos); image_type = ParseUtil::getValue(file.substr(pos+1), _image_type_map); } // Load the image, try load paths if not an absolute image path // already. PImage *image = 0; if (real_file[0] == '/') { image = getImageFromPath(real_file); } else { vector::const_reverse_iterator it(_search_path.rbegin()); for (; ! image && it != _search_path.rend(); ++it) { image = getImageFromPath(*it + real_file); } } // Image was found, set correct type. if (image) { image->setType(image_type); } return image; } /** * Load image from absolute path, checks cache for hit before loading. * * @param file Path to image file. * @return PImage or 0 if fails. */ PImage* ImageHandler::getImageFromPath(const std::string &file) { // Check cache for entry. vector >::iterator it(_images.begin()); for (; it != _images.end(); ++it) { if (*it == file) { it->incRef(); return it->getData(); } } // Try to load the image, setup cache only if it succeeds. PImage *image; try { image = new PImage(file); } catch (LoadException&) { image = 0; } // Create new PImage and handler entry for it. if (image) { HandlerEntry entry(file); entry.incRef(); entry.setData(image); _images.push_back(entry); } return image; } //! @brief Returns a Image void ImageHandler::returnImage(PImage *image) { bool found = false; vector >::iterator it(_images.begin()); for (; it != _images.end(); ++it) { if (it->getData() == image) { found = true; it->decRef(); if (_free_on_return || ! it->getRef()) { delete it->getData(); _images.erase(it); } break; } } if (! found) { delete image; } } //! @brief Frees all images not beeing in use void ImageHandler::freeUnref(void) { vector >::iterator it(_images.begin()); while (it != _images.end()) { if (it->getRef() == 0) { delete it->getData(); it = _images.erase(it); } else { ++it; } } } pekwm-release-0.1.18/src/ImageHandler.hh000066400000000000000000000030541374756504400200130ustar00rootroot00000000000000// // ImageHandler.hh for pekwm // Copyright © 2003-2009 Claes Nasten // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifndef _IMAGE_HANDLER_HH_ #define _IMAGE_HANDLER_HH_ #include "config.h" #include "Handler.hh" #include "ParseUtil.hh" #include class PImage; /** * ImageHandler, a caching and image type transparent image handler. */ class ImageHandler { public: ImageHandler(void); ~ImageHandler(void); //! @brief Returns the ImageHandler instance pointer. static inline ImageHandler *instance(void) { return _instance; } /** Add path entry to the search path. */ void path_push_back(const std::string &path) { _search_path.push_back(path); } /** Remove newest entry in the search path. */ void path_pop_back(void) { _search_path.pop_back(); } /** Remove all entries from the search path. */ void path_clear(void) { _search_path.clear(); } PImage *getImage(const std::string &file); void returnImage(PImage *image); void freeUnref(void); private: PImage *getImageFromPath(const std::string &file); vector _search_path; /**< List of directories to search. */ vector > _images; /**< List of loaded images. */ bool _free_on_return; /**< If true, images are deleted when returned. */ std::map _image_type_map; /**< Type name to type enum map. */ static ImageHandler *_instance; /**< Singleton instance pointer. */ }; #endif // _IMAGE_HANDLER_HH_ pekwm-release-0.1.18/src/InputDialog.cc000066400000000000000000000353751374756504400177130ustar00rootroot00000000000000// // InputDialog.cc for pekwm // Copyright © 2009-2013 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "config.h" #include #include #include #include #include "InputDialog.hh" #include "KeyGrabber.hh" #include "x11.hh" #include "Workspaces.hh" extern "C" { #include } using std::map; using std::wstring; using std::iswprint; map InputDialog::_keysym_map; /** * InputDialog constructor. */ InputDialog::InputDialog(Theme *theme, const std::wstring &title) : PDecor(theme, "INPUTDIALOG"), PWinObjReference(0), _data(theme->getCmdDialogData()), _pixmap_bg(None), _pos(0), _buf_off(0), _buf_chars(0) { // PWinObj attributes setLayer(LAYER_NONE); // hack, goes over LAYER_MENU _hidden = true; // don't care about it when changing worskpace etc if (! _keysym_map.size()) { reloadKeysymMap(); } // Add action to list, going to be used from close and exec ::Action action; _ae.action_list.push_back(action); titleAdd(&_title); titleSetActive(0); setTitle(title); _text_wo = new PWinObj(true); XSetWindowAttributes attr; attr.override_redirect = false; attr.event_mask = ButtonPressMask|ButtonReleaseMask|ButtonMotionMask| FocusChangeMask|KeyPressMask|KeyReleaseMask; _text_wo->setWindow(XCreateWindow(X11::getDpy(), _window, 0, 0, 1, 1, 0, CopyFromParent, InputOutput, CopyFromParent, CWOverrideRedirect|CWEventMask, &attr)); addChild(_text_wo); addChildWindow(_text_wo->getWindow()); activateChild(_text_wo); _text_wo->mapWindow(); // setup texture, size etc loadTheme(); Workspaces::insert(this); woListAdd(this); _wo_map[_window] = this; } /** * InputDialog destructor. */ InputDialog::~InputDialog(void) { Workspaces::remove(this); _wo_map.erase(_window); woListRemove(this); // Free resources if (_text_wo) { _children.erase(std::remove(_children.begin(), _children.end(), _text_wo), _children.end()); removeChildWindow(_text_wo->getWindow()); XDestroyWindow(X11::getDpy(), _text_wo->getWindow()); delete _text_wo; } unloadTheme(); } void InputDialog::reloadKeysymMap(void) { _keysym_map.clear(); addKeysymToKeysymMap(XK_KP_0, L'0'); addKeysymToKeysymMap(XK_KP_1, L'1'); addKeysymToKeysymMap(XK_KP_2, L'2'); addKeysymToKeysymMap(XK_KP_3, L'3'); addKeysymToKeysymMap(XK_KP_4, L'4'); addKeysymToKeysymMap(XK_KP_5, L'5'); addKeysymToKeysymMap(XK_KP_6, L'6'); addKeysymToKeysymMap(XK_KP_7, L'7'); addKeysymToKeysymMap(XK_KP_8, L'8'); addKeysymToKeysymMap(XK_KP_9, L'9'); } void InputDialog::addKeysymToKeysymMap(KeySym keysym, wchar_t chr) { Display *dpy = X11::getDpy(); int keysyms_per_keycode; KeyCode keycode = XKeysymToKeycode(dpy, keysym); KeySym *keysyms = XGetKeyboardMapping(dpy, keycode, 1, &keysyms_per_keycode); if (keysyms) { for (int i = 0; i < keysyms_per_keycode; i++) { if (keysyms[i] != NoSymbol) { _keysym_map[keysyms[i]] = chr; } } XFree(keysyms); } } /** * Handles ButtonPress, moving the text cursor */ ActionEvent* InputDialog::handleButtonPress(XButtonEvent *ev) { if (*_text_wo == ev->window) { // FIXME: move cursor return 0; } else { return PDecor::handleButtonPress(ev); } } /** * Handles KeyPress, editing the buffer */ ActionEvent* InputDialog::handleKeyPress(XKeyEvent *ev) { bool matched; ActionEvent *c_ae, *ae = 0; if ( (c_ae = KeyGrabber::instance()->findAction(ev, _type, &matched)) ) { vector::iterator it(c_ae->action_list.begin()); for (; it != c_ae->action_list.end(); ++it) { switch (it->getAction()) { case INPUT_INSERT: bufAdd(ev); completeReset(); break; case INPUT_REMOVE: bufRemove(); break; case INPUT_CLEAR: bufClear(); completeReset(); break; case INPUT_CLEARFROMCURSOR: bufKill(); completeReset(); break; case INPUT_EXEC: ae = exec(); break; case INPUT_CLOSE: ae = close(); break; case INPUT_COMPLETE: complete(); break; case INPUT_COMPLETE_ABORT: completeAbort(); break; case INPUT_CURS_NEXT: bufChangePos(1); completeReset(); break; case INPUT_CURS_PREV: bufChangePos(-1); completeReset(); break; case INPUT_CURS_BEGIN: _pos = 0; completeReset(); break; case INPUT_CURS_END: _pos = _buf.size(); completeReset(); break; case INPUT_HIST_NEXT: histNext(); completeReset(); break; case INPUT_HIST_PREV: histPrev(); completeReset(); break; case INPUT_NO_ACTION: default: // do nothing, shouldn't happen break; }; } // something ( most likely ) changed, redraw the window if (! ae) { bufChanged(); render(); } } return ae; } /** * Handles ExposeEvent, redraw when ev->count == 0 */ ActionEvent* InputDialog::handleExposeEvent(XExposeEvent *ev) { if (ev->count > 0) { return 0; } render(); return 0; } /** * Maps the InputDialog center on the PWinObj it executes actions on. * * @param buf Buffer content. * @param wo_ref PWinObj reference, defaults to 0 which does not update. */ void InputDialog::mapCentered(const std::string &buf, const Geometry &gm, PWinObj *wo_ref) { // Setup data _hist_it = _history.end(); _buf = Util::to_wide_str(buf); _pos = _buf.size(); bufChanged(); Geometry head; uint head_nr = X11::getNearestHead(gm.x + (gm.width / 2), gm.y + (gm.height / 2)); X11::getHeadInfo(head_nr, head); // Update size (before, as we center) and position updateSize(head); moveCentered(head, gm); // Map and render PDecor::mapWindowRaised(); render(); giveInputFocus(); } /** * Moves to center of geometry. * * @param gm Geometry to center on. */ void InputDialog::moveCentered(const Geometry &head, const Geometry &gm) { // Make sure X is inside head. int new_x = gm.x + (static_cast(gm.width) - static_cast(_gm.width)) / 2; if (new_x < head.x) { new_x = head.x; } else if ((new_x + _gm.width) > (head.x + head.width)) { new_x = head.x + head.width - _gm.width; } // Make sure Y is inside head. int new_y = gm.y + (static_cast(gm.height) - static_cast(_gm.height)) / 2; if (new_y < head.y) { new_y = head.y; } else if ((new_y + _gm.height) > (head.y + head.height)) { new_y = head.y + head.height - _gm.height; } // Update position. move(new_x, new_y); } /** * Sets title of decor */ void InputDialog::setTitle(const std::wstring &title) { _title.setReal(title); } /** * Maps window, overloaded to refresh content of window after mapping. */ void InputDialog::mapWindow(void) { if (! _mapped) { Geometry head; X11::getHeadInfo(getHead(), head); // Correct size for current head before mapping updateSize(head); PDecor::mapWindow(); render(); } } /** * Sets background and size */ void InputDialog::loadTheme(void) { Geometry head; X11::getHeadInfo(getHead(), head); _data = _theme->getCmdDialogData(); updateSize(head); updatePixmapSize(); } /** * Frees resources */ void InputDialog::unloadTheme(void) { X11::freePixmap(_pixmap_bg); } /** * Renders _buf onto _text_wo */ void InputDialog::render(void) { _text_wo->clear(); uint pos = _data->getPad(PAD_LEFT); const wchar_t *buf = _buf.c_str() + _buf_off; // draw buf content _data->getFont()->setColor(_data->getColor()); _data->getFont()->draw(_text_wo->getWindow(), pos, _data->getPad(PAD_UP), buf, _buf_chars); // draw cursor if (_pos > 0) { pos += _data->getFont()->getWidth(buf, _pos - _buf_off) + 1; } _data->getFont()->draw(_text_wo->getWindow(), pos, _data->getPad(PAD_UP), L"|"); } /** * Generates ACTION_CLOSE closing dialog. * * @return Pointer to ActionEvent. */ ActionEvent* InputDialog::close(void) { _ae.action_list.back().setAction(ACTION_NO); return &_ae; } /** * Default implementation, fills in _buf_on_complete to safely run * completeAbort. */ void InputDialog::complete(void) { _buf_on_complete = _buf; _pos_on_complete = _pos; } /** * Restore buffer and clear completion buffers. */ void InputDialog::completeAbort(void) { if (_buf_on_complete.size()) { _buf = _buf_on_complete; _pos = _pos_on_complete; } completeReset(); } /** * Clear the completion buffer. */ void InputDialog::completeReset(void) { // Old gcc doesn't know about .clear() _buf_on_complete = _buf_on_complete_result = L""; _pos_on_complete = 0; } /** * Adds char to buffer */ void InputDialog::bufAdd(XKeyEvent *ev) { KeySym keysym; char c_return[64]; memset(c_return, '\0', sizeof(c_return)); XLookupString(ev, c_return, sizeof(c_return), &keysym, 0); if (_keysym_map.count(keysym)) { _buf.insert(_buf.begin() + _pos++, _keysym_map[keysym]); } else { // Add wide string to buffer counting position wstring buf_ret(Util::to_wide_str(c_return)); for (unsigned int i = 0; i < buf_ret.size(); ++i) { if (iswprint(buf_ret[i])) { _buf.insert(_buf.begin() + _pos++, buf_ret[i]); } } } } /** * Removes char from buffer */ void InputDialog::bufRemove(void) { if ((_pos > _buf.size()) || (_pos == 0) || (_buf.size() == 0)) { return; } _buf.erase(_buf.begin() + --_pos); } /** * Clears the buffer, resets status */ void InputDialog::bufClear(void) { _buf = _buf_on_complete = _buf_on_complete_result = L""; // old gcc doesn't know about .clear() _pos = _pos_on_complete = _buf_off = _buf_chars = 0; } /** * Removes buffer content after cursor position */ void InputDialog::bufKill(void) { _buf.resize(_pos); } /** * Moves the marker */ void InputDialog::bufChangePos(int off) { if ((signed(_pos) + off) < 0) { _pos = 0; } else if (unsigned(_pos + off) > _buf.size()) { _pos = _buf.size(); } else { _pos += off; } } /** * Recalculates, _buf_off and _buf_chars */ void InputDialog::bufChanged(void) { PFont *font = _data->getFont(); // convenience // complete string doesn't fit in the window OR // we don't fit in the first set if ((_pos > 0) && (font->getWidth(_buf.c_str()) > _text_wo->getWidth()) && (font->getWidth(_buf.c_str(), _pos) > _text_wo->getWidth())) { // increase position until it all fits for (_buf_off = 0; _buf_off < _pos; ++_buf_off) { if (font->getWidth(_buf.c_str() + _buf_off, _buf.size() - _buf_off) < _text_wo->getWidth()) { break; } } _buf_chars = _buf.size() - _buf_off; } else { _buf_off = 0; _buf_chars = _buf.size(); } } /** * Sets the buffer to the next item in the history. */ void InputDialog::histNext(void) { if (_hist_it == _history.end()) { return; // nothing to do } // get next item, if at the end, restore the edit buffer ++_hist_it; if (_hist_it == _history.end()) { _buf = _hist_new; } else { _buf = *_hist_it; } // move cursor to the end of line _pos = _buf.size(); } /** * Sets the buffer to the previous item in the history. */ void InputDialog::histPrev(void) { if (_hist_it == _history.begin()) { return; // nothing to do } // save item so we can restore the edit buffer later if (_hist_it == _history.end()) { _hist_new = _buf; } // get prev item _buf = *(--_hist_it); // move cursor to the end of line _pos = _buf.size(); } /** * Update command dialog size for view on current head. */ void InputDialog::updateSize(const Geometry &head) { // Resize the child window and update the size depending. uint old_width = _gm.width; unsigned int width, height; getInputSize(head, width, height); resizeChild(width, height); // If size was updated, replace the texture and recalculate display // buffer. if (old_width != _gm.width) { updatePixmapSize(); bufChanged(); } } /** * Update background pixmap size and redraw. */ void InputDialog::updatePixmapSize(void) { // Get new pixmap and render texture X11::freePixmap(_pixmap_bg); _pixmap_bg = X11::createPixmap(_text_wo->getWidth(), _text_wo->getHeight()); _data->getTexture()->render(_pixmap_bg, 0, 0, _text_wo->getWidth(), _text_wo->getHeight()); _text_wo->setBackgroundPixmap(_pixmap_bg); _text_wo->clear(); } /** * Get size of the text input widget. * * @param width Fill in width. * @param height Fill in height. */ void InputDialog::getInputSize(const Geometry &head, unsigned int &width, unsigned int &height) { width = head.width / 3; height = _data->getFont()->getHeight() + _data->getPad(PAD_UP) + _data->getPad(PAD_DOWN); } void InputDialog::addHistoryUnique(const std::wstring &entry) { vector::iterator it(find(_history.begin(), _history.end(), entry)); if (it != _history.end()) { _history.erase(it); } _history.push_back(entry); } void InputDialog::loadHistory(const std::string &path) { std::ifstream ifile(path.c_str()); if (ifile.is_open()) { // Update only path if successfully opened. std::string mb_line; while (ifile.good()) { getline(ifile, mb_line); if (mb_line.size()) { _history.push_back(Util::to_wide_str(mb_line)); } } ifile.close(); } } void InputDialog::saveHistory(const std::string &path) { std::ofstream ofile(path.c_str()); if (ofile.is_open()) { vector::iterator it(_history.begin()); for (; it != _history.end(); ++it) { ofile << Util::to_utf8_str(*it) << "\n"; } ofile.close(); } } pekwm-release-0.1.18/src/InputDialog.hh000066400000000000000000000055301374756504400177130ustar00rootroot00000000000000// // CmdDialog.hh for pekwm // Copyright © 2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifndef _INPUT_DIALOG_HH_ #define _INPUT_DIALOG_HH_ #include "config.h" #include extern "C" { #include } #include "PWinObj.hh" #include "PWinObjReference.hh" #include "PDecor.hh" /** * Base for windows handling text input. */ class InputDialog : public PDecor, public PWinObjReference { public: InputDialog(Theme *theme, const std::wstring &title); virtual ~InputDialog(void); // BEGIN - PWinObj interface virtual void mapWindow(void); // PWinObj event interface ActionEvent *handleButtonPress(XButtonEvent *ev); ActionEvent *handleKeyPress(XKeyEvent *ev); ActionEvent *handleExposeEvent(XExposeEvent *ev); // END - PWinObj interface void setTitle(const std::wstring &title); void loadTheme(void); void unloadTheme(void); void render(void); static void reloadKeysymMap(void); virtual void mapCentered(const std::string &buf, const Geometry &gm, PWinObj *wo_ref=0); virtual void moveCentered(const Geometry &head, const Geometry &gm); protected: virtual ActionEvent *close(void); virtual ActionEvent *exec(void) { return 0; } virtual void complete(void); virtual void completeAbort(void); virtual void completeReset(void); virtual void bufAdd(XKeyEvent *ev); virtual void bufRemove(void); virtual void bufClear(void); virtual void bufKill(void); virtual void bufChangePos(int off); virtual void bufChanged(void); // recalculates buf position virtual void histNext(void); virtual void histPrev(void); virtual void updateSize(const Geometry &head); virtual void updatePixmapSize(void); void getInputSize(const Geometry &head, unsigned int &width, unsigned int &height); Theme::TextDialogData *_data; ActionEvent _ae; //!< Action event for event handling PWinObj *_text_wo; PDecor::TitleItem _title; Pixmap _pixmap_bg; // content related std::wstring _buf; uint _pos, _buf_off, _buf_chars; // position, start and num display // Completion std::wstring _buf_on_complete; /**< Buffer before completion. */ std::wstring _buf_on_complete_result; /** Buffer after completion. */ unsigned int _pos_on_complete; /**< Cursor position on completion start. */ // history std::wstring _hist_new; // the one we started editing on vector _history; vector::iterator _hist_it; void addHistoryUnique(const std::wstring &); void loadHistory(const std::string &file); void saveHistory(const std::string &file); private: static void addKeysymToKeysymMap(KeySym keysym, wchar_t chr); static std::map _keysym_map; }; #endif // _INPUT_DIALOG_HH_ pekwm-release-0.1.18/src/KeyGrabber.cc000066400000000000000000000265571374756504400175130ustar00rootroot00000000000000// // KeyGrabber.cc for pekwm // Copyright © 2003-2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "config.h" #include "KeyGrabber.hh" #include "Config.hh" #include "x11.hh" #include "CfgParser.hh" #include "Util.hh" extern "C" { #include } #include using std::cerr; using std::endl; using std::string; using std::find; KeyGrabber* KeyGrabber::_instance = 0; //! @brief Constructor for Chain class KeyGrabber::Chain::Chain(uint mod, uint key) : _mod(mod), _key(key) { } //! @brief Destructor for Chain class KeyGrabber::Chain::~Chain(void) { unload(); } //! @brief Unloads all chains and keys void KeyGrabber::Chain::unload(void) { vector::iterator it(_chains.begin()); for (; it != _chains.end(); ++it) { delete *it; } _chains.clear(); _keys.clear(); } //! @brief Searches the _chains list for an action KeyGrabber::Chain* KeyGrabber::Chain::findChain(XKeyEvent *ev, bool *matched) { vector::iterator it(_chains.begin()); for (; it != _chains.end(); ++it) { if ((((*it)->getMod() == MOD_ANY) || ((*it)->getMod() == ev->state)) && (((*it)->getKey() == 0) || ((*it)->getKey() == ev->keycode))) { return *it; } } return 0; } //! @brief Searches the _keys list for an action ActionEvent* KeyGrabber::Chain::findAction(XKeyEvent *ev, bool *matched) { vector::iterator it(_keys.begin()); for (; it != _keys.end(); ++it) { if ((it->mod == MOD_ANY || it->mod == ev->state) && (it->sym == 0 || it->sym == ev->keycode)) { *matched = true; return &*it; } } return 0; } //! @brief KeyGrabber constructor KeyGrabber::KeyGrabber(void) : _menu_chain(0, 0), _global_chain(0, 0), _moveresize_chain(0, 0), _input_dialog_chain(0, 0) { #ifdef DEBUG if (_instance) { cerr << __FILE__ << "@" << __LINE__ << ": " << "KeyGrabber(" << this << ")::KeyGrabber()" << endl << " *** _instance already set: " << _instance << endl; } #endif // DEBUG _instance = this; _num_lock = X11::getNumLock(); _scroll_lock = X11::getScrollLock(); } //! @brief Destructor for KeyGrabber class KeyGrabber::~KeyGrabber(void) { _instance = 0; } //! @brief Parses the "KeyFile" and inserts into _global_keys. //! If _global_keys holds any keygrabs they will be flushed before //! reloading the new keybindings. bool KeyGrabber::load(const std::string &file, bool force) { if (! force && ! _cfg_files.requireReload(file)) { return false; } CfgParser key_cfg; if (! key_cfg.parse(file, CfgParserSource::SOURCE_FILE)) { _cfg_files.clear(); if (! key_cfg.parse(SYSCONFDIR "/keys", CfgParserSource::SOURCE_FILE, true)) { cerr << __FILE__ << "@" << __LINE__ << "Error: no keyfile at " << file << " or " << SYSCONFDIR "/keys" << endl; return false; } } if (key_cfg.isDynamicContent()) { _cfg_files.clear(); } else { _cfg_files = key_cfg.getCfgFiles(); } CfgParser::Entry *section; section = key_cfg.getEntryRoot()->findSection("GLOBAL"); if (section) { _global_chain.unload(); parseGlobalChain(section, &_global_chain); } section = key_cfg.getEntryRoot ()->findSection("MOVERESIZE"); if (section) { _moveresize_chain.unload (); parseMoveResizeChain (section, &_moveresize_chain); } // Previously there was only a CmdDialog section, however the text // handling parts have been moved into InputDialog but to keep // compatibility this check exists. section = key_cfg.getEntryRoot()->findSection("INPUTDIALOG"); if (! section) { section = key_cfg.getEntryRoot()->findSection("CMDDIALOG"); } if (section) { _input_dialog_chain.unload (); parseInputDialogChain (section, &_input_dialog_chain); } section = key_cfg.getEntryRoot ()->findSection("MENU"); if (section) { _menu_chain.unload(); parseMenuChain(section, &_menu_chain); } return true; } //! @brief Parses chain, getting actions as plain ActionEvents void KeyGrabber::parseGlobalChain(CfgParser::Entry *section, KeyGrabber::Chain *chain) { ActionEvent ae; uint key, mod; CfgParser::iterator it(section->begin()); for (; it != section->end(); ++it) { if ((*it)->getSection() && *(*it) == "CHAIN") { // Figure out mod and key, create a new chain. if (Config::instance()->parseKey((*it)->getValue(), mod, key)) { KeyGrabber::Chain *sub_chain = new KeyGrabber::Chain(mod, key); parseGlobalChain((*it)->getSection(), sub_chain); chain->addChain(sub_chain); } } else if (Config::instance()->parseActionEvent((*it), ae, KEYGRABBER_OK, false)) { chain->addAction(ae); } } } //! @brief Parses chain, getting actions as MoveResizeEvents void KeyGrabber::parseMoveResizeChain(CfgParser::Entry *section, KeyGrabber::Chain *chain) { ActionEvent ae; uint key, mod; CfgParser::iterator it(section->begin()); for (; it != section->end(); ++it) { if ((*it)->getSection() && *(*it) == "CHAIN") { // Figure out mod and key, create a new chain. if (Config::instance()->parseKey((*it)->getValue(), mod, key)) { KeyGrabber::Chain *sub_chain = new KeyGrabber::Chain(mod, key); parseMoveResizeChain((*it)->getSection(), sub_chain); chain->addChain(sub_chain); } } else if (Config::instance()->parseMoveResizeEvent((*it), ae)) { chain->addAction(ae); } } } //! @brief Parses chain, getting actions as InputDialog Events void KeyGrabber::parseInputDialogChain(CfgParser::Entry *section, KeyGrabber::Chain *chain) { ActionEvent ae; uint key, mod; CfgParser::iterator it(section->begin()); for (; it != section->end(); ++it) { if ((*it)->getSection() && *(*it) == "CHAIN") { // Figure out mod and key, create a new chain. if (Config::instance()->parseKey((*it)->getValue(), mod, key)) { KeyGrabber::Chain *sub_chain = new KeyGrabber::Chain(mod, key); parseInputDialogChain((*it)->getSection(), sub_chain); chain->addChain(sub_chain); } } else if (Config::instance()->parseInputDialogEvent((*it), ae)) { chain->addAction(ae); } } } //! @brief Parses chain, getting actions as MenuEvents void KeyGrabber::parseMenuChain(CfgParser::Entry *section, KeyGrabber::Chain *chain) { ActionEvent ae; uint key, mod; CfgParser::iterator it(section->begin()); for (; it != section->end(); ++it) { if ((*it)->getSection() && *(*it) == "CHAIN") { // Figure out mod and key, create a new chain. if (Config::instance()->parseKey((*it)->getValue(), mod, key)) { KeyGrabber::Chain *sub_chain = new KeyGrabber::Chain (mod, key); parseGlobalChain((*it)->getSection(), sub_chain); chain->addChain(sub_chain); } } else if (Config::instance()->parseMenuEvent((*it), ae)) { chain->addAction(ae); } } } //! @brief Grabs all the keybindings in _keybindings on the Window win. //! @param win Window to grab the keys on. void KeyGrabber::grabKeys(Window win) { const vector &chains(_global_chain.getChains()); vector::const_iterator c_it = chains.begin(); for (; c_it != chains.end(); ++c_it) grabKey(win, (*c_it)->getMod(), (*c_it)->getKey()); const vector &keys(_global_chain.getKeys()); vector::const_iterator k_it = keys.begin(); for (; k_it != keys.end(); ++k_it) grabKey(win, k_it->mod, k_it->sym); } //! @brief Grabs a key with state on Window win with "all possible" modifiers. //! @param win Window to grab the key on. //! @param mod Modifier state to grab. //! @param key Key state to grab. void KeyGrabber::grabKey(Window win, uint mod, uint key) { Display *dpy = X11::getDpy(); // convenience XGrabKey(dpy, key, mod, win, true, GrabModeAsync, GrabModeAsync); XGrabKey(dpy, key, mod|LockMask, win, true, GrabModeAsync, GrabModeAsync); if (_num_lock) { XGrabKey(dpy, key, mod|_num_lock, win, true, GrabModeAsync, GrabModeAsync); XGrabKey(dpy, key, mod|_num_lock|LockMask, win, true, GrabModeAsync, GrabModeAsync); } if (_scroll_lock) { XGrabKey(dpy, key, mod|_scroll_lock, win, true, GrabModeAsync, GrabModeAsync); XGrabKey(dpy, key, mod|_scroll_lock|LockMask, win, true, GrabModeAsync, GrabModeAsync); } if (_num_lock && _scroll_lock) { XGrabKey(dpy, key, mod|_num_lock|_scroll_lock, win, true, GrabModeAsync, GrabModeAsync); XGrabKey(dpy, key, mod|_num_lock|_scroll_lock|LockMask, win, true, GrabModeAsync, GrabModeAsync); } } //! @brief Ungrabs all the keybindings on the Window win. //! @param win Window to ungrab keys on. void KeyGrabber::ungrabKeys(Window win) { XUngrabKey(X11::getDpy(), AnyKey, AnyModifier, win); } //! @brief Tries to match the XKeyEvent to an usefull action and return it //! @param ev XKeyEvent to match. ActionEvent* KeyGrabber::findAction(XKeyEvent *ev, KeyGrabber::Chain *chain, bool *matched) { if (! ev) { return 0; } X11::stripStateModifiers(&ev->state); ActionEvent *action = 0; KeyGrabber::Chain *sub_chain = _global_chain.findChain(ev, matched); if (sub_chain) { *matched = true; if (X11::grabKeyboard(X11::getRoot())) { XEvent c_ev; KeyGrabber::Chain *last_chain; bool exit = false; while (! exit) { XMaskEvent(X11::getDpy(), KeyPressMask, &c_ev); X11::stripStateModifiers(&c_ev.xkey.state); if (IsModifierKey(X11::getKeysymFromKeycode(c_ev.xkey.keycode))) { // do nothing } else if ((last_chain = sub_chain->findChain(&c_ev.xkey, matched))) { sub_chain = last_chain; } else { action = sub_chain->findAction(&c_ev.xkey, matched); exit = true; } } X11::ungrabKeyboard(); } } else { action = chain->findAction(ev, matched); } return action; } //! @brief Finds action matching ev, continues chain if needed ActionEvent* KeyGrabber::findAction(XKeyEvent *ev, PWinObj::Type type, bool *matched) { ActionEvent *ae = 0; *matched = false; if (type == PWinObj::WO_MENU) { ae = findAction(ev, &_menu_chain, matched); } if (type == PWinObj::WO_CMD_DIALOG || type == PWinObj::WO_SEARCH_DIALOG) { ae = findAction(ev, &_input_dialog_chain, matched); } // no action the menu list, try the global list if (! ae) { ae = findAction(ev, &_global_chain, matched); } return ae; } //! @brief Searches the _moveresize_chain for actions. ActionEvent* KeyGrabber::findMoveResizeAction(XKeyEvent *ev) { bool matched; return findAction(ev, &_moveresize_chain, &matched); } pekwm-release-0.1.18/src/KeyGrabber.hh000066400000000000000000000054151374756504400175130ustar00rootroot00000000000000// // KeyGrabber.hh for pekwm // Copyright © 2003-2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifndef _KEYGRABBER_HH_ #define _KEYGRABBER_HH_ #include "config.h" #include "pekwm.hh" #include "Action.hh" #include "CfgParser.hh" #include "PWinObj.hh" #include extern "C" { #include } //! @brief Key grabbing and matching routines with key chain support. class KeyGrabber { public: //! @brief Key chain state information. class Chain { public: Chain(uint mod, uint key); ~Chain(void); void unload(void); //! @brief Returns modifier state Chain represents. inline uint getMod(void) const { return _mod; } //! @brief Returns key state Chain represents. inline uint getKey(void) const { return _key; } //! @brief Returns vector of Chains that follows. inline const vector &getChains(void) const { return _chains; } //! @brief Returns vector of Keys in chain. inline const vector &getKeys(void) const { return _keys; } //! @brief Adds chain to Chain vector. inline void addChain(Chain *chain) { _chains.push_back(chain); } //! @brief Adds action to Key vector. inline void addAction(const ActionEvent &key) { _keys.push_back(key); } Chain *findChain(XKeyEvent *ev, bool *matched); ActionEvent *findAction(XKeyEvent *ev, bool *matched); private: uint _mod, _key; vector _chains; vector _keys; }; KeyGrabber(void); ~KeyGrabber(void); //! @brief Returns the KeyGrabber instance pointer. static KeyGrabber *instance(void) { return _instance; } bool load(const std::string &file, bool force=false); void grabKeys(Window win); void ungrabKeys(Window win); ActionEvent *findAction(XKeyEvent *ev, PWinObj::Type type, bool *matched); ActionEvent *findMoveResizeAction(XKeyEvent *ev); private: void grabKey(Window win, uint mod, uint key); void parseGlobalChain(CfgParser::Entry *section, KeyGrabber::Chain *chain); void parseMoveResizeChain(CfgParser::Entry *section, KeyGrabber::Chain *chain); void parseInputDialogChain(CfgParser::Entry *section, KeyGrabber::Chain *chain); void parseMenuChain(CfgParser::Entry *section, KeyGrabber::Chain *chain); ActionEvent *findAction(XKeyEvent *ev, KeyGrabber::Chain *chain, bool *matched); TimeFiles _cfg_files; KeyGrabber::Chain _menu_chain; KeyGrabber::Chain _global_chain; KeyGrabber::Chain _moveresize_chain; KeyGrabber::Chain _input_dialog_chain; uint _num_lock; uint _scroll_lock; static KeyGrabber *_instance; }; #endif // _KEYGRABBER_HH_ pekwm-release-0.1.18/src/LayouterTiling.cc000066400000000000000000000247401374756504400204410ustar00rootroot00000000000000// // LayouterTiling.cc for pekwm // Copyright © 2012-2013 Andreas Schlick // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "pekwm.hh" #include "LayouterTiling.hh" #include "Client.hh" #include "Frame.hh" #include "Util.hh" #include "WindowManager.hh" #include "Workspaces.hh" #include "x11.hh" using std::string; typedef vector::size_type vecsize_t; static void collectTilingFrames(vector &vec, Geometry &gm) { Client *client; Frame *frame; vector::const_iterator it = Workspaces::begin(); vector::const_iterator end = Workspaces::end(); for (; it != end; ++it) { if (! (frame = dynamic_cast(*it))) continue; if (frame->isMapped() && ! frame->isFullscreen() && ! frame->isSticky()) { client = frame->getActiveClient(); if (client && ! client->isCfgDeny(CFG_DENY_TILING) && client->getWinType() == WINDOW_TYPE_NORMAL) { vec.push_back(frame); } } } X11::getHeadInfoWithEdge(X11::getCurrHead(), gm); if (vec.size() == 1) { vec.back()->checkMoveResize(gm.x, gm.y, gm.width, gm.height); vec.clear(); } } bool LayouterTiling::setupFrames(Geometry &gm) { vector vec, vec2; vecsize_t i,j; collectTilingFrames(vec, gm); if (vec.empty()) return false; // vec2 := _frames \cap vec for (i=0; i<_frames.size(); ++i) { for (j=0; j &opts, Frame *frame) { if (_frames.empty()) return; vector::size_type nropts = opts.size(); const char *str = opts[0].c_str(); if (! strcasecmp(str, "cycle")) { frame = _frames.front(); for (uint i=1; i < _frames.size(); ++i) { _frames[i-1] = _frames[i]; } _frames.back() = frame; layout(0, false); return; } if (! frame) frame = *WindowManager::instance()->mru_begin(); if (frame) { const vector::iterator end = _frames.end(); const vector::iterator it = find(_frames.begin(), end, frame); vector::iterator it2; if (it == end) return; if (! strcasecmp(str, "switch")) { frame = _frames.front(); _frames.front() = *it; *it = frame; } else if (! strcasecmp(str, "switchgeometry")) { vector::const_iterator fit, fend; if (nropts > 1 && Util::isTrue(opts[1])) { fit = WindowManager::instance()->mru_begin(); fend = WindowManager::instance()->mru_end(); for (; fit != fend; ++fit) { if ((*fit)->isMapped() && *fit != frame) { it2 = find(_frames.begin(), _frames.end(), *fit); if (it2 != end) { break; } } } } else { fend = Frame::frame_end(); fit = find(Frame::frame_begin(), fend, frame); for (;;) { if (++fit == fend) fit = Frame::frame_begin(); if (*fit == frame) { // Reaching frame again means that we have come // full circle and should break out of the loop. fit = fend; // signal our failure to find a 2nd frame break; } if ((*fit)->isMapped()) { it2 = find(_frames.begin(), _frames.end(), *fit); if (it2 != end) { break; } } } } if (fit != fend) { *it = *it2; *it2 = frame; if (nropts > 2 && Util::isTrue(opts[2])) { (*it2)->raise(); (*it2)->giveInputFocus(); } } } layout(0, false); } } bool LayouterBoxed::layout_impl(Frame *) { Geometry gm; uint cols; vecsize_t i; int x, y; if (! setupFrames(gm)) { return true; } if (_centre) { cols = _frames.size()/2; x = gm.x + gm.width/4; y = gm.y + gm.height/4; _frames[0]->checkMoveResize(x, y, gm.width/2, gm.height/2); i = 1; } else { cols = (_frames.size()+1)/2; i = 0; } gm.width /= cols; gm.height /= 2; x = gm.x; y = gm.y; for (;i < _frames.size(); ++i) { _frames[i]->checkMoveResize(x, y, gm.width, gm.height); if (gm.y != y) { y = gm.y; x += gm.width; } else { y = gm.height; } } _frames[0]->raise(); return true; } bool LayouterDwindle::layout_impl(Frame *) { Geometry gm; vecsize_t i; bool horiz=false; if (! setupFrames(gm)) { return true; } gm.width /= 2; _frames[0]->checkMoveResize(gm.x, gm.y, gm.width, gm.height); for (i=1; i < _frames.size()-1; ++i) { if (horiz) { gm.width /= 2; gm.y += gm.height; } else { gm.height /= 2; gm.x += gm.width; } _frames[i]->checkMoveResize(gm.x, gm.y, gm.width, gm.height); horiz = !horiz; } if (horiz) { gm.y += gm.height; } else { gm.x += gm.width; } _frames.back()->checkMoveResize(gm.x, gm.y, gm.width, gm.height); return true; } bool LayouterFibonacci::layout_impl(Frame *) { Geometry gm; uint NrFib = 11; // max. index for Fib (12-1) uint oldw, oldh; uint w=0, h=0, x = 0, y = 0; if (! setupFrames(gm)) { return true; } oldw = gm.width; oldh = gm.height; if (_frames.size() < NrFib) NrFib = _frames.size(); w = oldw * Fib[NrFib]/(Fib[NrFib] + Fib[NrFib-1]); h = oldh; _frames[0]->checkMoveResize(x, y, w, h); NrFib--; vecsize_t i; for (i = 0; i < NrFib; ++i) { switch (i%4) { case 0: x += w; w = oldw - w; oldh = h; h *= Fib[NrFib-i]/(Fib[NrFib-i] + Fib[NrFib-1-i]); break; case 1: y += h; h = oldh - h; oldw = w; w *= Fib[NrFib-i]/(Fib[NrFib-i] + Fib[NrFib-1-i]); x += oldw - w; break; case 2: x -= oldw - w; w = oldw - w; oldh = h; h *= Fib[NrFib-i]/(Fib[NrFib-i] + Fib[NrFib-1-i]); y += oldh - h; break; case 3: y -= oldh - h; h = oldh - h; oldw = w; w *= Fib[NrFib-i]/(Fib[NrFib-i] + Fib[NrFib-1-i]); break; } _frames[i+1]->checkMoveResize(x, y, w, h); } for (; i < _frames.size(); ++i) { _frames[i]->checkMoveResize(x, y, w, h); } return true; } const double LayouterFibonacci::Fib[] = { 0,1,1,2,3,5,8,13,21,34,55,89 }; bool LayouterLayers::layout_impl(Frame *) { Geometry gm; uint nr_wins, delta_x, delta_y, width, height; int x, y; if (! setupFrames(gm)) { return true; } nr_wins = _frames.size(); delta_x = _horiz?gm.width/nr_wins:0; delta_y = _horiz?0:gm.height/nr_wins; if (! delta_x && ! delta_y) { if (_horiz) delta_x = 10; else delta_y = 10; } x = gm.x; y = gm.y; height = gm.height; width = gm.width; if (_horiz) { width /= nr_wins; if (! width) width = 10; } else { height /= nr_wins; if (! height) height = 10; } for (vecsize_t i=0; i<_frames.size(); ++i) { _frames[i]->checkMoveResize(x, y, width, height); x += delta_x; y += delta_y; if (y > 0 && static_cast(y) > gm.height) { y = gm.y; } if (x > 0 && static_cast(x) > gm.width) { x = gm.x; } } return true; } bool LayouterStacked::layout_impl(Frame *) { Geometry gm; uint x, y, h; if (! setupFrames(gm)) { return true; } x = (gm.width*2)/3; y = gm.y; _frames[0]->checkMoveResize(gm.x, gm.y, x, gm.height); gm.x += x; gm.width -= x; h = gm.height / (_frames.size()-1); if (!h) h = 10; for (vecsize_t i=1; i<_frames.size(); ++i) { _frames[i]->checkMoveResize(gm.x, y, gm.width, h); if (y+h > gm.height) y = gm.y; y += h; } return true; } bool LayouterTriple::layout_impl(Frame *) { Geometry gm; uint height; if (! setupFrames(gm)) return true; height = gm.height - int(gm.height * _height/100.0); _frames[0]->checkMoveResize(gm.x, gm.y, gm.width, height); gm.height -= int(gm.height* (100.0-_height)/100.0); if (_frames.size() == 2) { _frames[1]->checkMoveResize(gm.x, height, gm.width, gm.height); return true; } bool left = true; for (vecsize_t i=1; i<_frames.size(); ++i, left = !left) { if (left) { _frames[i]->checkMoveResize(gm.x, height, gm.y+gm.width/2, gm.height); } else { _frames[i]->checkMoveResize(gm.x+gm.width/2, height, gm.y+gm.width/2, gm.height); } } return true; } void LayouterTriple::setOption(vector &opts, Frame *frame) { if (2 == opts.size()) { int height=0; if (! strcasecmp(opts[0].c_str(), "abs")) { height = atoi(opts[1].c_str()); } else if (! strcasecmp(opts[0].c_str(), "rel")) { height = atoi(opts[1].c_str()); height += _height; } if (height > 5 && height < 100) _height = static_cast(height); } else { default_setOption(opts, frame); } } pekwm-release-0.1.18/src/LayouterTiling.hh000066400000000000000000000063141374756504400204500ustar00rootroot00000000000000// // LayouterTiling.hh for pekwm // Copyright © 2012-2013 Andreas Schlick // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifndef _LAYOUTERTILING_HH_ #define _LAYOUTERTILING_HH_ #include "WinLayouter.hh" class LayouterTiling : public WinLayouter { public: LayouterTiling(void) : WinLayouter(true) { } virtual ~LayouterTiling() { } virtual void setOption(vector &opts, Frame *frame) { default_setOption(opts, frame); } protected: bool setupFrames(Geometry &gm); void default_setOption(vector &opts, Frame *frame); vector _frames; }; /** * Boxed layout implementation * * With centre == false: * ------------- * | | | | * | 1 | 2 | 3 | * |-----------| * | | | | * | 4 | 5 | 6 | * ------------- * * With centre == true: * ---------------- * | 2 | 3 | 4 | * | +------+ | * |---| 1 |---| * | +------+ | * | 5 | 6 | 7 | * ---------------- */ class LayouterBoxed : public LayouterTiling { public: LayouterBoxed(bool centre) : LayouterTiling(), _centre(centre) {} virtual ~LayouterBoxed() {} private: bool _centre; virtual bool layout_impl(Frame *frame); }; class LayouterDwindle : public LayouterTiling { public: LayouterDwindle() : LayouterTiling() {} ~LayouterDwindle() {} private: virtual bool layout_impl(Frame *frame); }; class LayouterFibonacci : public LayouterTiling { public: LayouterFibonacci() : LayouterTiling() {} ~LayouterFibonacci() {} private: virtual bool layout_impl(Frame *frame); static const double Fib[]; }; /** * horiz == false: * ----------------- * | 1 | * |---------------| * | 2 | * |---------------| * | 3 | * |---------------| * | 4 | * ----------------- * * horiz == true: * ----------------- * | | | | | * | 1 | 2 | 3 | 4 | * | | | | | * | | | | | * ----------------- */ class LayouterLayers : public LayouterTiling { public: LayouterLayers(bool horiz) : LayouterTiling(), _horiz(horiz) {} ~LayouterLayers() {} private: bool _horiz; virtual bool layout_impl(Frame *frame); }; /** * One big window on the left and all other stacked on the right. * * ---------------- * | | 2 | * | +----+ * | 1 | 3 | * | +----+ * | | 4 | * ---------------- */ class LayouterStacked : public LayouterTiling { public: LayouterStacked() : LayouterTiling() {} ~LayouterStacked() {} private: virtual bool layout_impl(Frame *frame); }; /** * Three area layout implementation. * * ---------------- * | | * | 1 | * | | * |______________| <- The bar is adjustable with a % option, default is 20. * | 2 | 3 | * ---------------- */ class LayouterTriple: public LayouterTiling { public: LayouterTriple() : LayouterTiling(), _height(20) {} ~LayouterTriple() {} virtual void setOption(vector &opts, Frame *frame); private: uint _height; virtual bool layout_impl(Frame *frame); }; #endif // _LAYOUTERTILING_HH_ pekwm-release-0.1.18/src/Makefile.am000066400000000000000000000035551374756504400172140ustar00rootroot00000000000000AUTOMAKE_OPTIONS = foreign CXXFLAGS = @CXXFLAGS@ -DSYSCONFDIR=\"$(sysconfdir)/pekwm\" -DDATADIR=\"$(datadir)\" EXTRA_DIST = CMakeLists.txt if DEBUG_INFRASTRUCTURE debugsource = Debug.cc else debugsource = endif bin_PROGRAMS = pekwm pekwm_SOURCES = $(debugsource)\ Action.hh \ ActionHandler.cc ActionHandler.hh \ ActionMenu.cc ActionMenu.hh \ AutoProperties.cc AutoProperties.hh \ CfgParser.cc CfgParser.hh \ CfgParserKey.cc CfgParserKey.hh \ CfgParserSource.cc CfgParserSource.hh \ Compat.cc Compat.hh \ Completer.cc Completer.hh \ Client.cc Client.hh \ CmdDialog.cc CmdDialog.hh \ Config.cc Config.hh \ Debug.hh \ DockApp.cc DockApp.hh \ Exception.hh \ Frame.cc Frame.hh \ FontHandler.cc FontHandler.hh \ FrameListMenu.cc FrameListMenu.hh \ Harbour.cc Harbour.hh \ Handler.hh \ ImageHandler.cc ImageHandler.hh \ InputDialog.cc InputDialog.hh \ KeyGrabber.cc KeyGrabber.hh \ LayouterTiling.cc LayouterTiling.hh \ ManagerWindows.cc ManagerWindows.hh \ MenuHandler.cc MenuHandler.hh \ Observer.hh \ Observable.cc Observable.hh \ PDecor.cc PDecor.hh \ PFont.cc PFont.hh \ PMenu.cc PMenu.hh \ PTexture.hh \ PTexturePlain.cc PTexturePlain.hh \ PWinObj.cc PWinObj.hh \ PWinObjReference.cc PWinObjReference.hh \ PImage.cc PImage.hh \ PImageIcon.cc PImageIcon.hh \ PImageLoader.hh \ PImageLoaderJpeg.cc PImageLoaderJpeg.hh \ PImageLoaderPng.cc PImageLoaderPng.hh \ PImageLoaderXpm.cc PImageLoaderXpm.hh \ RegexString.cc RegexString.hh \ ParseUtil.hh \ StatusWindow.cc StatusWindow.hh \ SearchDialog.cc SearchDialog.hh \ Theme.cc Theme.hh \ TextureHandler.cc TextureHandler.hh \ Types.hh \ Util.cc Util.hh \ WORefMenu.cc WORefMenu.hh \ WindowManager.cc WindowManager.hh \ WinLayouter.cc WinLayouter.hh \ Workspaces.cc Workspaces.hh \ WorkspaceIndicator.cc WorkspaceIndicator.hh \ x11.cc x11.hh \ main.cc \ pekwm.hh distclean-local: rm -f *\~ .\#* pekwm-release-0.1.18/src/ManagerWindows.cc000066400000000000000000000360651374756504400204160ustar00rootroot00000000000000// // ManagerWindows.cc for pekwm // Copyright © 2009-2013 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "config.h" #include "Config.hh" #include "ActionHandler.hh" #include "ManagerWindows.hh" #include "Workspaces.hh" #include "Util.hh" #include extern "C" { #include } using std::cerr; using std::endl; using std::string; // Static initializers const string HintWO::WM_NAME = string("pekwm"); HintWO *HintWO::_instance = 0; const unsigned int HintWO::DISPLAY_WAIT = 10; const unsigned long RootWO::EVENT_MASK = StructureNotifyMask|PropertyChangeMask| SubstructureNotifyMask|SubstructureRedirectMask| ColormapChangeMask|FocusChangeMask|EnterWindowMask| ButtonPressMask|ButtonReleaseMask|ButtonMotionMask; const unsigned long RootWO::EXPECTED_DESKTOP_NAMES_LENGTH = 256; /** * Hint window constructor, creates window and sets supported * protocols. */ HintWO::HintWO(Window root, bool replace) : PWinObj(false) { if (_instance) { throw string("trying to create HintWO which is already created."); } _instance = this; _type = WO_SCREEN_HINT; setLayer(LAYER_NONE); _sticky = true; // Hack, do not map/unmap this window _iconified = true; // Hack, to be ignored when placing // Create window _window = XCreateSimpleWindow(X11::getDpy(), root, -200, -200, 5, 5, 0, 0, 0); // Remove override redirect from window XSetWindowAttributes attr; attr.override_redirect = True; attr.event_mask = PropertyChangeMask; XChangeWindowAttributes(X11::getDpy(), _window, CWEventMask|CWOverrideRedirect, &attr); // Set hints not being updated X11::setUtf8String(_window, NET_WM_NAME, WM_NAME); X11::setWindow(_window, NET_SUPPORTING_WM_CHECK, _window); if (! claimDisplay(replace)) { throw string("unable to claim display"); } } /** * Hint WO destructor, destroy hint window. */ HintWO::~HintWO(void) { XDestroyWindow(X11::getDpy(), _window); _instance = 0; } /** * Get current time of server by generating an event and reading the * timestamp on it. * * @return Time on server. */ Time HintWO::getTime(void) { XEvent event; // Generate event on ourselves XChangeProperty(X11::getDpy(), _window, X11::getAtom(WM_CLASS), X11::getAtom(STRING), 8, PropModeAppend, 0, 0); XWindowEvent(X11::getDpy(), _window, PropertyChangeMask, &event); return event.xproperty.time; } /** * Claim ownership over the current display. * * @param replace Replace current running window manager. */ bool HintWO::claimDisplay(bool replace) { bool status = true; // Get atom for the current screen and it's owner string session_name("WM_S" + Util::to_string(DefaultScreen(X11::getDpy()))); Atom session_atom = XInternAtom(X11::getDpy(), session_name.c_str(), false); Window session_owner = XGetSelectionOwner(X11::getDpy(), session_atom); if (session_owner && session_owner != _window) { if (! replace) { cerr << " *** WARNING: window manager already running." << endl; return false; } XSync(X11::getDpy(), false); setXErrorsIgnore(true); uint errors_before = xerrors_count; // Select event to get notified when current owner dies. X11::selectInput(session_owner, StructureNotifyMask); XSync(X11::getDpy(), false); setXErrorsIgnore(false); if (errors_before != xerrors_count) { session_owner = None; } } Time timestamp = getTime(); XSetSelectionOwner(X11::getDpy(), session_atom, _window, timestamp); if (XGetSelectionOwner(X11::getDpy(), session_atom) == _window) { if (session_owner) { // Wait for the previous window manager to go away and update owner. status = claimDisplayWait(session_owner); if (status) { claimDisplayOwner(session_atom, timestamp); } } } else { cerr << "pekwm: unable to replace current window manager." << endl; status = false; } return status; } /** * After claiming the display, wait for the previous window manager to * go away. */ bool HintWO::claimDisplayWait(Window session_owner) { XEvent event; cerr << " *** INFO: waiting for previous window manager to exit. " << endl; for (uint waited = 0; waited < HintWO::DISPLAY_WAIT; ++waited) { if (XCheckWindowEvent(X11::getDpy(), session_owner, StructureNotifyMask, &event) && event.type == DestroyNotify) { return true; } sleep(1); } cerr << " *** INFO: previous window manager did not exit. " << endl; return false; } /** * Send message updating the owner of the screen. */ void HintWO::claimDisplayOwner(Window session_atom, Time timestamp) { XEvent event; // FIXME: One should use _root_wo here? Window root = X11::getRoot(); event.xclient.type = ClientMessage; event.xclient.message_type = X11::getAtom(MANAGER); event.xclient.display = X11::getDpy(); event.xclient.window = root; event.xclient.format = 32; event.xclient.data.l[0] = timestamp; event.xclient.data.l[1] = session_atom; event.xclient.data.l[2] = _window; event.xclient.data.l[3] = 0; XSendEvent(X11::getDpy(), root, false, SubstructureNotifyMask, &event); } /** * Root window constructor, reads geometry and sets basic atoms. */ RootWO::RootWO(Window root) : PWinObj(false) { _type = WO_SCREEN_ROOT; setLayer(LAYER_NONE); _mapped = true; _window = root; _gm.width = X11::getWidth(); _gm.height = X11::getHeight(); XSync(X11::getDpy(), false); setXErrorsIgnore(true); uint errors_before = xerrors_count; // Select window events X11::selectInput(_window, RootWO::EVENT_MASK); XSync(X11::getDpy(), false); setXErrorsIgnore(false); if (errors_before != xerrors_count) { cerr << "pekwm: root window unavailable, can't start!" << endl; exit(1); } // Set hits on the hint window, these are not updated so they are // set in the constructor. X11::setLong(_window, NET_WM_PID, static_cast(getpid())); X11::setString(_window, WM_CLIENT_MACHINE, Util::getHostname()); X11::setWindow(_window, NET_SUPPORTING_WM_CHECK, HintWO::instance()->getWindow()); X11::setEwmhAtomsSupport(_window); X11::setLong(_window, NET_NUMBER_OF_DESKTOPS, Config::instance()->getWorkspaces()); X11::setLong(_window, NET_CURRENT_DESKTOP, 0); long desktop_geometry[2]; desktop_geometry[0] = _gm.width; desktop_geometry[1] = _gm.height; X11::setLongs(_window, NET_DESKTOP_GEOMETRY, desktop_geometry, 2); woListAdd(this); _wo_map[_window] = this; } /** * Root window destructor, clears atoms set. */ RootWO::~RootWO(void) { // Remove atoms, PID will not be valid on shutdown. X11::unsetProperty(_window, NET_WM_PID); X11::unsetProperty(_window, WM_CLIENT_MACHINE); _wo_map.erase(_window); woListRemove(this); } /** * Button press event handler, gets actions from root list. */ ActionEvent* RootWO::handleButtonPress(XButtonEvent *ev) { return ActionHandler::findMouseAction(ev->button, ev->state, MOUSE_EVENT_PRESS, Config::instance()->getMouseActionList(MOUSE_ACTION_LIST_ROOT)); } /** * Button release event handler, gets actions from root list. */ ActionEvent* RootWO::handleButtonRelease(XButtonEvent *ev) { MouseEventType mb = MOUSE_EVENT_RELEASE; // first we check if it's a double click if (X11::isDoubleClick(ev->window, ev->button - 1, ev->time, Config::instance()->getDoubleClickTime())) { X11::setLastClickID(ev->window); X11::setLastClickTime(ev->button - 1, 0); mb = MOUSE_EVENT_DOUBLE; } else { X11::setLastClickID(ev->window); X11::setLastClickTime(ev->button - 1, ev->time); } return ActionHandler::findMouseAction(ev->button, ev->state, mb, Config::instance()->getMouseActionList(MOUSE_ACTION_LIST_ROOT)); } /** * Motion event handler, gets actions from root list. */ ActionEvent* RootWO::handleMotionEvent(XMotionEvent *ev) { unsigned int button = X11::getButtonFromState(ev->state); return ActionHandler::findMouseAction(button, ev->state, MOUSE_EVENT_MOTION, Config::instance()->getMouseActionList(MOUSE_ACTION_LIST_ROOT)); } /** * Enter event handler, gets actions from root list. */ ActionEvent* RootWO::handleEnterEvent(XCrossingEvent *ev) { return ActionHandler::findMouseAction(BUTTON_ANY, ev->state, MOUSE_EVENT_ENTER, Config::instance()->getMouseActionList(MOUSE_ACTION_LIST_ROOT)); } /** * Leave event handler, gets actions from root list. */ ActionEvent* RootWO::handleLeaveEvent(XCrossingEvent *ev) { return ActionHandler::findMouseAction(BUTTON_ANY, ev->state, MOUSE_EVENT_LEAVE, Config::instance()->getMouseActionList(MOUSE_ACTION_LIST_ROOT)); } /** * Update _NET_WORKAREA property. * * @param workarea Geometry with work area. */ void RootWO::setEwmhWorkarea(const Geometry &workarea) { long workarea_array[4] = { workarea.x, workarea.y, 0, 0 }; workarea_array[2] = workarea.width; workarea_array[3] = workarea.height; X11::setLongs(_window, NET_WORKAREA, workarea_array, 4); } /** * Update _NET_ACTIVE_WINDOW property. * * @param win Window to set as active window. */ void RootWO::setEwmhActiveWindow(Window win) { X11::setWindow(X11::getRoot(), NET_ACTIVE_WINDOW, win); } /** * Reads the _NET_DESKTOP_NAMES hint and sets the workspaces names accordingly. */ void RootWO::readEwmhDesktopNames(void) { uchar *data; ulong data_length; if (X11::getProperty(X11::getRoot(), NET_DESKTOP_NAMES, X11::getAtom(UTF8_STRING), EXPECTED_DESKTOP_NAMES_LENGTH, &data, &data_length)) { Config::instance()->setDesktopNamesUTF8(reinterpret_cast(data), data_length); XFree(data); } } /** * Update _NET_DESKTOP_NAMES property on the root window. */ void RootWO::setEwmhDesktopNames(void) { unsigned char *desktopnames = 0; unsigned int length = 0; Config::instance()->getDesktopNamesUTF8(&desktopnames, &length); if (desktopnames) { X11::setUtf8StringArray(X11::getRoot(), NET_DESKTOP_NAMES, desktopnames, length); delete [] desktopnames; } } /** * Update _NET_DESKTOP_LAYOUT property on the root window. */ void RootWO::setEwmhDesktopLayout(void) { // This property is defined to be set by the pager, however, as pekwm // displays a "pager" when changing workspaces and other applications // might want to read this information set it anyway. long desktop_layout[] = { NET_WM_ORIENTATION_HORZ, static_cast(Workspaces::getPerRow()), static_cast(Workspaces::getRows()), NET_WM_TOPLEFT }; X11::setLongs(X11::getRoot(), NET_DESKTOP_LAYOUT, desktop_layout, sizeof(desktop_layout)/sizeof(desktop_layout[0])); } /** * Edge window constructor, create window, setup strut and register * window. */ EdgeWO::EdgeWO(Window root, EdgeType edge, bool set_strut) : PWinObj(false), _edge(edge) { _type = WO_SCREEN_EDGE; setLayer(LAYER_NONE); // hack, goes over LAYER_MENU _sticky = true; // don't map/unmap _iconified = true; // hack, to be ignored when placing _focusable = false; // focusing input only windows crashes X XSetWindowAttributes sattr; sattr.override_redirect = True; sattr.event_mask = EnterWindowMask|LeaveWindowMask|ButtonPressMask|ButtonReleaseMask; _window = XCreateWindow(X11::getDpy(), root, 0, 0, 1, 1, 0, CopyFromParent, InputOnly, CopyFromParent, CWOverrideRedirect|CWEventMask, &sattr); configureStrut(set_strut); X11::addStrut(&_strut); woListAdd(this); _wo_map[_window] = this; } /** * Edge window destructor, remove strut and destroy window resources. */ EdgeWO::~EdgeWO(void) { X11::removeStrut(&_strut); _wo_map.erase(_window); woListRemove(this); XDestroyWindow(X11::getDpy(), _window); } /** * Configure strut on edge window. * * @param set_strut If true, set actual values on the strut, false sets all to 0. */ void EdgeWO::configureStrut(bool set_strut) { // Reset value, on strut to zero. _strut.left = _strut.right = _strut.top = _strut.bottom = 0; // Set strut if requested. if (set_strut) { switch (_edge) { case SCREEN_EDGE_TOP: _strut.top = _gm.height; break; case SCREEN_EDGE_BOTTOM: _strut.bottom = _gm.height; break; case SCREEN_EDGE_LEFT: _strut.left = _gm.width; break; case SCREEN_EDGE_RIGHT: _strut.right = _gm.width; break; case SCREEN_EDGE_NO: default: // do nothing break; } } } /** * Edge version of mapped window, makes sure the iconified state is * set at all times in order to avoid counting the edge windows when * snapping windows etc. */ void EdgeWO::mapWindow(void) { if (_mapped) { return; } PWinObj::mapWindow(); _iconified = true; } /** * Enter event handler, gets actions from EdgeList on _edge. */ ActionEvent* EdgeWO::handleEnterEvent(XCrossingEvent *ev) { return ActionHandler::findMouseAction(BUTTON_ANY, ev->state, MOUSE_EVENT_ENTER, Config::instance()->getEdgeListFromPosition(_edge)); } /** * Button press event handler, gets actions from EdgeList on _edge. */ ActionEvent* EdgeWO::handleButtonPress(XButtonEvent *ev) { return ActionHandler::findMouseAction(ev->button, ev->state, MOUSE_EVENT_PRESS, Config::instance()->getEdgeListFromPosition(_edge)); } /** * Button release event handler, gets actions from EdgeList on _edge. */ ActionEvent* EdgeWO::handleButtonRelease(XButtonEvent *ev) { // Make sure the release is on the actual window. This probably // could be done smarter. if (ev->x_root < _gm.x || ev->x_root > static_cast(_gm.x + _gm.width) || ev->y_root < _gm.y || ev->y_root > static_cast(_gm.y + _gm.height)) { return 0; } MouseEventType mb = MOUSE_EVENT_RELEASE; // first we check if it's a double click if (X11::isDoubleClick(ev->window, ev->button - 1, ev->time, Config::instance()->getDoubleClickTime())) { X11::setLastClickID(ev->window); X11::setLastClickTime(ev->button - 1, 0); mb = MOUSE_EVENT_DOUBLE; } else { X11::setLastClickID(ev->window); X11::setLastClickTime(ev->button - 1, ev->time); } return ActionHandler::findMouseAction(ev->button, ev->state, mb, Config::instance()->getEdgeListFromPosition(_edge)); } pekwm-release-0.1.18/src/ManagerWindows.hh000066400000000000000000000054201374756504400204170ustar00rootroot00000000000000// // ManagerWindows.hh for pekwm // Copyright © 2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifndef _MANAGER_WINDOWS_H_ #define _MANAGER_WINDOWS_H_ #include "config.h" #include "pekwm.hh" #include "PWinObj.hh" #include /** * Window for handling of EWMH hints, sets supported attributes etc. */ class HintWO : public PWinObj { public: HintWO(Window root, bool replace); virtual ~HintWO(void); inline static HintWO *instance(void) { return _instance; } private: Time getTime(void); bool claimDisplay(bool replace); bool claimDisplayWait(Window session_owner); void claimDisplayOwner(Window session_atom, Time timestamp); private: static const std::string WM_NAME; /**< Name of the window manager, that is pekwm. */ static HintWO *_instance; /**< Singleton HintWO pointer. */ static const unsigned int DISPLAY_WAIT; /**< Max wait time for previous WM. */ }; /** * Window object representing the Root window, handles actions and * sets atoms on the window. */ class RootWO : public PWinObj { public: RootWO(Window root); virtual ~RootWO(void); /** Resize root window, does no actual resizing but updates the geometry of the window. */ virtual void resize(uint width, uint height) { _gm.width = width; _gm.height = height; } virtual ActionEvent *handleButtonPress(XButtonEvent *ev); virtual ActionEvent *handleButtonRelease(XButtonEvent *ev); virtual ActionEvent *handleMotionEvent(XMotionEvent *ev); virtual ActionEvent *handleEnterEvent(XCrossingEvent *ev); virtual ActionEvent *handleLeaveEvent(XCrossingEvent *ev); void setEwmhWorkarea(const Geometry &workarea); void setEwmhActiveWindow(Window win); void readEwmhDesktopNames(void); void setEwmhDesktopNames(void); void setEwmhDesktopLayout(void); private: static const unsigned long EVENT_MASK; /**< Root window event mask. */ static const unsigned long EXPECTED_DESKTOP_NAMES_LENGTH; /**< Expected length of desktop hint. */ }; /** * Window object used as a screen border, input only window that only * handles actions. */ class EdgeWO : public PWinObj { public: EdgeWO(Window root, EdgeType edge, bool set_strut); virtual ~EdgeWO(void); void configureStrut(bool set_strut); virtual void mapWindow(void); virtual ActionEvent *handleButtonPress(XButtonEvent *ev); virtual ActionEvent *handleButtonRelease(XButtonEvent *ev); virtual ActionEvent *handleEnterEvent(XCrossingEvent *ev); inline EdgeType getEdge(void) const { return _edge; } private: EdgeType _edge; /**< Edge position. */ Strut _strut; /*< Strut for reserving screen edge space. */ }; #endif // _MANAGER_WINDOWS_H_ pekwm-release-0.1.18/src/MenuHandler.cc000066400000000000000000000126541374756504400176710ustar00rootroot00000000000000// // MenuHandler.cc for pekwm // Copyright © 2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "config.h" #include #include #include #include "PWinObj.hh" #include "PMenu.hh" #include "MenuHandler.hh" #include "ActionHandler.hh" #include "WORefMenu.hh" #include "ActionMenu.hh" #include "FrameListMenu.hh" using std::map; using std::string; TimeFiles MenuHandler::_cfg_files; std::map MenuHandler::_menu_map; /** * Creates reserved menus and populates _menu_map */ void MenuHandler::createMenus(Theme *theme) { PMenu *menu = 0; menu = new FrameListMenu(theme, ATTACH_CLIENT_IN_FRAME_TYPE, L"Attach Client In Frame", "AttachClientInFrame"); _menu_map["ATTACHCLIENTINFRAME"] = menu; menu = new FrameListMenu(theme, ATTACH_CLIENT_TYPE, L"Attach Client", "AttachClient"); _menu_map["ATTACHCLIENT"] = menu; menu = new FrameListMenu(theme, ATTACH_FRAME_IN_FRAME_TYPE, L"Attach Frame In Frame", "AttachFrameInFrame"); _menu_map["ATTACHFRAMEINFRAME"] = menu; menu = new FrameListMenu(theme, ATTACH_FRAME_TYPE, L"Attach Frame", "AttachFrame"); _menu_map["ATTACHFRAME"] = menu; menu = new FrameListMenu(theme, GOTOCLIENTMENU_TYPE, L"Focus Client", "GotoClient"); _menu_map["GOTOCLIENT"] = menu; menu = new FrameListMenu(theme, GOTOMENU_TYPE, L"Focus Frame", "Goto"); _menu_map["GOTO"] = menu; menu = new FrameListMenu(theme, ICONMENU_TYPE, L"Focus Iconified Frame", "Icon"); _menu_map["ICON"] = menu; menu = new ActionMenu(ROOTMENU_TYPE, L"", "RootMenu"); _menu_map["ROOT"] = menu; menu = new ActionMenu(WINDOWMENU_TYPE, L"", "WindowMenu"); _menu_map["WINDOW"] = menu; createMenusLoadConfiguration(); } /** * Initial load of menu configuration. */ void MenuHandler::createMenusLoadConfiguration(void) { // Load configuration, pass specific section to loading CfgParser menu_cfg; if (menu_cfg.parse(Config::instance()->getMenuFile()) || menu_cfg.parse(string(SYSCONFDIR "/menu"))) { _cfg_files = menu_cfg.getCfgFiles(); CfgParser::Entry *root_entry = menu_cfg.getEntryRoot(); // Load standard menus map::iterator it = _menu_map.begin(); for (; it != _menu_map.end(); ++it) { it->second->reload(root_entry->findSection(it->second->getName())); } // Load standalone menus reloadStandaloneMenus(menu_cfg.getEntryRoot()); } } /** * (re)loads the menus in the menu configuration if the file has been * updated since last load. */ void MenuHandler::reloadMenus(void) { string menu_file(Config::instance()->getMenuFile()); if (! _cfg_files.requireReload(menu_file)) { return; } CfgParser cfg; bool cfg_ok = loadMenuConfig(menu_file, cfg); CfgParser::Entry *root = cfg.getEntryRoot(); // Update, delete standalone root menus, load decors on others map::iterator it(_menu_map.begin()); while (it != _menu_map.end()) { if (it->second->getMenuType() == ROOTMENU_STANDALONE_TYPE) { delete it->second; _menu_map.erase(it++); continue; } else if (cfg_ok) { // Only reload the menu if we got a ok configuration it->second->reload(root->findSection(it->second->getName())); } ++it; } // Update standalone root menus (name != ROOTMENU) reloadStandaloneMenus(root); } /** * Load menu configuration from menu_file resetting menu state. */ bool MenuHandler::loadMenuConfig(const std::string &menu_file, CfgParser &menu_cfg) { bool cfg_ok = true; if (! menu_cfg.parse(menu_file)) { if (! menu_cfg.parse(string(SYSCONFDIR "/menu"))) { cfg_ok = false; } } // Make sure menu is reloaded next time as content is dynamically // generated from the configuration file. if (! cfg_ok || menu_cfg.isDynamicContent()) { _cfg_files.clear(); } else { _cfg_files = menu_cfg.getCfgFiles(); } return cfg_ok; } /** * Updates standalone root menus */ void MenuHandler::reloadStandaloneMenus(CfgParser::Entry *section) { // Temporary name, as names are stored uppercase string menu_name_upper; // Go through all but reserved section names and create menus CfgParser::iterator it(section->begin()); for (; it != section->end(); ++it) { // Uppercase name menu_name_upper = (*it)->getName(); Util::to_upper(menu_name_upper); // Create new menu if the name is not used if (! getMenu(menu_name_upper)) { // Create, parse and add to map PMenu *menu = new ActionMenu(ROOTMENU_STANDALONE_TYPE, L"", (*it)->getName()); menu->reload((*it)->getSection()); _menu_map[menu_name_upper] = menu; } } } /** * Clears the menu map and frees up resources used by menus */ void MenuHandler::deleteMenus(void) { map::iterator it(_menu_map.begin()); for (; it != _menu_map.end(); ++it) { delete it->second; } _menu_map.clear(); } pekwm-release-0.1.18/src/MenuHandler.hh000066400000000000000000000031641374756504400176770ustar00rootroot00000000000000// // MenuHandler.hh for pekwm // Copyright © 2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifndef _MENUHANDLER_HH_ #define _MENUHANDLER_HH_ #include "config.h" #include #include #include "PMenu.hh" class Theme; /** * Menu manager, creates, reloads and delete menus. */ class MenuHandler { public: static PMenu *getMenu(const std::string &name) { std::map::iterator it = _menu_map.find(name); return (it != _menu_map.end()) ? it->second : 0; } /** * Return list with names of loaded menus. */ static vector getMenuNames(void) { vector menu_names; std::map::iterator it(_menu_map.begin()); for (; it != _menu_map.end(); ++it) { menu_names.push_back(it->second->getName()); } return menu_names; } static void createMenus(Theme *); static void hideAllMenus(void) { std::map::iterator it(_menu_map.begin()); for (; it != _menu_map.end(); ++it) { it->second->unmapAll(); } } static void reloadMenus(void); static void deleteMenus(void); private: static bool loadMenuConfig(const std::string &menu_file, CfgParser &menu_cfg); static void createMenusLoadConfiguration(void); static void reloadStandaloneMenus(CfgParser::Entry *section); static TimeFiles _cfg_files; static std::map _menu_map; /**< Map from menu name to menu */ }; #endif // _MENUHANDLER_HH_ pekwm-release-0.1.18/src/Observable.cc000066400000000000000000000016051374756504400175450ustar00rootroot00000000000000// // Observable.cc for pekwm // Copyright © 2009 Claes Nästen // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "config.h" #include #include "Observable.hh" #include "Observer.hh" using std::vector; /** * Notify all observers. */ void Observable::notifyObservers(Observation *observation) { vector::const_iterator it(_observers.begin()); vector::const_iterator end(_observers.end()); for (; it != end; ++it) { (*it)->notify(this, observation); } } /** * Add observer. */ void Observable::addObserver(Observer *observer) { _observers.push_back(observer); } /** * Remove observer from list. */ void Observable::removeObserver(Observer *observer) { _observers.erase(std::remove(_observers.begin(), _observers.end(), observer), _observers.end()); } pekwm-release-0.1.18/src/Observable.hh000066400000000000000000000013021374756504400175510ustar00rootroot00000000000000// // Observable.hh for pekwm // Copyright © 2009 Claes Nästen // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifndef _OBSERVABLE_HH_ #define _OBSERVABLE_HH_ #include class Observer; /** * Message sent to observer. */ class Observation { public: virtual ~Observation(void) { }; }; class Observable { public: Observable(void) { } virtual ~Observable(void) { } void notifyObservers(Observation *observation); void addObserver(Observer *observer); void removeObserver(Observer *observer); private: std::vector _observers; /**< List of observers. */ }; #endif // _OBSERVABLE_HH_ pekwm-release-0.1.18/src/Observer.hh000066400000000000000000000007271374756504400172660ustar00rootroot00000000000000// // Observer.hh for pekwm // Copyright © 2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifndef _OBSERVER_HH_ #define _OBSERVER_HH_ #include "config.h" class Observable; class Observation; class Observer { public: Observer(void) { } virtual ~Observer(void) { } virtual void notify(Observable *observable, Observation *observation) { } }; #endif // _OBSERVER_HH_ pekwm-release-0.1.18/src/PDecor.cc000066400000000000000000002024531374756504400166410ustar00rootroot00000000000000// // PDecor.cc for pekwm // Copyright © 2004-2016 the pekwm development team // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "config.h" #include #include using std::mem_fun; extern "C" { #include #include } #include "Debug.hh" #include "Compat.hh" #include "Config.hh" #include "PWinObj.hh" #include "PFont.hh" #include "PDecor.hh" #include "x11.hh" #include "PTexture.hh" #include "PTexturePlain.hh" // PTextureSolid #include "ActionHandler.hh" #include "StatusWindow.hh" #include "KeyGrabber.hh" #include "Theme.hh" #include "Workspaces.hh" using std::find; using std::map; using std::string; using std::vector; // PDecor::Button //! @brief PDecor::Button constructor PDecor::Button::Button(PWinObj *parent, Theme::PDecorButtonData *data, uint width, uint height) : PWinObj(true), _data(data), _state(BUTTON_STATE_UNFOCUSED), _left(_data->isLeft()) { _parent = parent; _gm.width = width; _gm.height = height; XSetWindowAttributes attr; attr.event_mask = EnterWindowMask|LeaveWindowMask; attr.override_redirect = True; _window = XCreateWindow(X11::getDpy(), _parent->getWindow(), -_gm.width, -_gm.height, _gm.width, _gm.height, 0, CopyFromParent, InputOutput, CopyFromParent, CWEventMask|CWOverrideRedirect, &attr); _bg = X11::createPixmap(_gm.width, _gm.height); setBackgroundPixmap(_bg); setState(_state); } //! @brief PDecor::Button destructor PDecor::Button::~Button(void) { XDestroyWindow(X11::getDpy(), _window); X11::freePixmap(_bg); } //! @brief Searches the PDecorButtonData for an action matching ev ActionEvent* PDecor::Button::findAction(XButtonEvent *ev) { vector::iterator it(_data->begin()); for (; it != _data->end(); ++it) { if (it->mod == ev->state && it->sym == ev->button) return &*it; } return 0; } //! @brief Sets the state of the button void PDecor::Button::setState(ButtonState state) { if (state == BUTTON_STATE_NO) { return; } // Only update if we don't hoover, we want to be able to turn back if (state != BUTTON_STATE_HOVER) { _state = state; } PTexture *texture = _data->getTexture(state); if (texture) { texture->render(_bg, 0, 0, _gm.width, _gm.height); #ifdef HAVE_SHAPE if (_data->setShape()) { // Get shape mask bool need_free; Pixmap shape = _data->getTexture(state)->getMask(0, 0, need_free); if (shape != None) { X11::shapeSetMask(_window, ShapeBounding, shape); if (need_free) { X11::freePixmap(shape); } } else { XRectangle rect = {0 /* x */, 0 /* y */, static_cast(_gm.width), static_cast(_gm.height) }; X11::shapeSetRect(_window, &rect); } } #endif // HAVE_SHAPE clear(); } } //! @brief Update visible version of title void PDecor::TitleItem::updateVisible(void) { // Start with empty string _visible = L""; // Add client info to title if ((_info != 0) && ((_info != INFO_ID) || Config::instance()->isShowClientID())) { _visible.append(L"["); if (infoIs(INFO_ID) && Config::instance()->isShowClientID()) { _visible.append(Util::to_wide_str(Util::to_string(_id))); } if (infoIs(INFO_MARKED)) { _visible.append(L"M"); } _visible.append(L"] "); } // Add title if (_user.size() > 0) { _visible.append(_user); } else if (_custom.size() > 0) { _visible.append(_custom); } else { _visible.append(_real); } // Add client number to title if (_count > 0) { _visible.append(Util::to_wide_str(Config::instance()->getClientUniqueNamePre())); _visible.append(Util::to_wide_str(Util::to_string(_count))); _visible.append(Util::to_wide_str(Config::instance()->getClientUniqueNamePost())); } } // PDecor const string PDecor::DEFAULT_DECOR_NAME = string("DEFAULT"); const string PDecor::DEFAULT_DECOR_NAME_BORDERLESS = string("BORDERLESS"); const string PDecor::DEFAULT_DECOR_NAME_TITLEBARLESS = string("TITLEBARLESS"); const string PDecor::DEFAULT_DECOR_NAME_ATTENTION = string("ATTENTION"); const string PDecor::DEFAULT_DECOR_NAME_TILING = string("TILING"); vector PDecor::_pdecors; //! @brief PDecor constructor //! @param dpy Display //! @param theme Theme //! @param decor_name String, if not DEFAULT_DECOR_NAME sets _decor_name_saved PDecor::PDecor(Theme *theme, const std::string &decor_name, const Window child_window) : PWinObj(true), _theme(theme), _decor_name(decor_name), _child(0), _button(0), _button_press_win(None), _pointer_x(0), _pointer_y(0), _click_x(0), _click_y(0), _decor_cfg_child_move_overloaded(false), _decor_cfg_bpr_replay_pointer(false), _decor_cfg_bpr_al_child(MOUSE_ACTION_LIST_CHILD_OTHER), _decor_cfg_bpr_al_title(MOUSE_ACTION_LIST_TITLE_OTHER), _maximized_vert(false), _maximized_horz(false), _fullscreen(false), _skip(0), _data(0), _border(true), _titlebar(true), _shaded(false), _attention(0), _need_shape(false), _real_height(1), _title_wo(true), _title_active(0), _titles_left(0), _titles_right(1) { if (_decor_name.empty()) { _decor_name = getDecorName(); } if (_decor_name != PDecor::DEFAULT_DECOR_NAME) { _decor_name_saved = _decor_name; } // we be reset in loadDecor later on, inlines using the _data used before // loadDecor needs this though _data = _theme->getPDecorData(_decor_name); if (! _data) { _data = _theme->getPDecorData(DEFAULT_DECOR_NAME); } CreateWindowParams window_params; createParentWindow(window_params, child_window); createTitle(window_params); createBorder(window_params); // sets buttons etc up loadDecor(); // map title and border windows XMapSubwindows(X11::getDpy(), _window); _pdecors.push_back(this); } /** * Create window attributes */ void PDecor::createParentWindow(CreateWindowParams ¶ms, Window child_window) { params.mask = CWOverrideRedirect|CWEventMask|CWBorderPixel|CWBackPixel; params.depth = CopyFromParent; params.visual = CopyFromParent; params.attr.override_redirect = True; params.attr.border_pixel = X11::getBlackPixel(); params.attr.background_pixel = X11::getBlackPixel(); if (child_window != None) { XWindowAttributes attr; if (X11::getWindowAttributes(child_window, &attr) && 32 != X11::getDepth() && attr.depth == 32) { params.mask |= CWColormap; params.depth = attr.depth; params.visual = attr.visual; params.attr.colormap = XCreateColormap(X11::getDpy(), X11::getRoot(), params.visual, AllocNone); } } params.attr.event_mask = ButtonPressMask|ButtonReleaseMask| ButtonMotionMask|EnterWindowMask|SubstructureRedirectMask| SubstructureNotifyMask; _window = XCreateWindow(X11::getDpy(), X11::getRoot(), _gm.x, _gm.y, _gm.width, _gm.height, 0, params.depth, InputOutput, params.visual, params.mask, ¶ms.attr); if (params.mask & CWColormap) { XFreeColormap(X11::getDpy(), params.attr.colormap); params.depth = X11::getDepth(); params.visual = X11::getVisual(); params.attr.colormap = X11::getColormap(); } } /** * Create title window. */ void PDecor::createTitle(CreateWindowParams ¶ms) { params.attr.event_mask = ButtonPressMask|ButtonReleaseMask| ButtonMotionMask|EnterWindowMask; Window title = XCreateWindow(X11::getDpy(), _window, borderLeft(), borderTop(), 1, 1, 0, params.depth, InputOutput, params.visual, params.mask, ¶ms.attr); _title_wo.setWindow(title); addChildWindow(_title_wo.getWindow()); _title_wo.mapWindow(); } /** * Create border windows */ void PDecor::createBorder(CreateWindowParams ¶ms) { params.attr.event_mask = ButtonPressMask|ButtonReleaseMask| ButtonMotionMask|EnterWindowMask; for (uint i = 0; i < BORDER_NO_POS; ++i) { params.attr.cursor = X11::getCursor(CursorType(i)); _border_win[i] = XCreateWindow(X11::getDpy(), _window, -1, -1, 1, 1, 0, params.depth, InputOutput, params.visual, params.mask|CWCursor, ¶ms.attr); addChildWindow(_border_win[i]); } } //! @brief PDecor destructor PDecor::~PDecor(void) { _pdecors.erase(std::remove(_pdecors.begin(), _pdecors.end(), this), _pdecors.end()); while (! _children.empty()) { removeChild(_children.back(), false); // Don't call delete this. } // Make things look smoother, buttons will be noticed as deleted // otherwise. Using X call directly to avoid re-drawing and other // special features not required when removing the window. X11::unmapWindow(_window); // free buttons unloadDecor(); removeChildWindow(_title_wo.getWindow()); XDestroyWindow(X11::getDpy(), _title_wo.getWindow()); for (uint i = 0; i < BORDER_NO_POS; ++i) { removeChildWindow(_border_win[i]); XDestroyWindow(X11::getDpy(), _border_win[i]); } XDestroyWindow(X11::getDpy(), _window); } // START - PWinObj interface. //! @brief Map decor and all children void PDecor::mapWindow(void) { if (! _mapped) { PWinObj::mapWindow(); for_each(_children.begin(), _children.end(), mem_fun(&PWinObj::mapWindow)); } } //! @brief Maps the window raised void PDecor::mapWindowRaised(void) { if (_mapped) { return; } mapWindow(); raise(); // XMapRaised wouldn't preserver layers } //! @brief Unmaps decor and all children void PDecor::unmapWindow(void) { if (_mapped) { if (_iconified) { for_each(_children.begin(), _children.end(), mem_fun(&PWinObj::iconify)); } else { for_each(_children.begin(), _children.end(), mem_fun(&PWinObj::unmapWindow)); } PWinObj::unmapWindow(); } } //! @brief Moves the decor void PDecor::move(int x, int y) { // update real position PWinObj::move(x, y); if (_child && (_decor_cfg_child_move_overloaded)) { _child->move(x + borderLeft(), y + borderTop() + getTitleHeight()); } } //! @brief Resizes the decor, and active child if any void PDecor::resize(uint width, uint height) { // If shaded, don't resize to the size specified just update width // and set _real_height to height if (_shaded) { _real_height = height; height = getTitleHeight(); // Shading in non full width title mode will make border go away if (! _data->getTitleWidthMin()) { height += borderTop() + borderBottom(); } } PWinObj::resize(width, height); // Update size before moving and shaping the rest as shaping // depends on the child window if (_child) { _child->resize(getChildWidth(), getChildHeight()); } // place / resize title and border resizeTitle(); placeBorder(); // Set and apply shape on window, all parts of the border can now // be shaped. setBorderShape(); applyBorderShape(); renderTitle(); renderBorder(); } //! @brief Move and resize window. void PDecor::moveResize(int x, int y, uint width, uint height) { // If shaded, don't resize to the size specified just update width // and set _real_height to height if (_shaded) { _real_height = height; height = getTitleHeight(); // Shading in non full width title mode will make border go away if (! _data->getTitleWidthMin()) { height += borderTop() + borderBottom(); } } PWinObj::moveResize(x, y, width, height); // Update size before moving and shaping the rest as shaping // depends on the child window if (_child) { _child->moveResize(x + borderLeft(), y + borderTop() + getTitleHeight(), getChildWidth(), getChildHeight()); // The client window may have its window gravity set to something different // than NorthWestGravity (see Xlib manual chapter 3.2.3). Therefore the // X server may not move its top left corner along with the decoration. // We correct these cases by calling alignChild(). It is called only for // _child and not all members of _children, because activateChild.*() // does it itself. alignChild(_child); } // Place and resize title and border resizeTitle(); placeBorder(); // Apply shape on window, all parts of the border can now be shaped. setBorderShape(); applyBorderShape(); renderTitle(); renderBorder(); } //! @brief void PDecor::resizeTitle(void) { if (getTitleHeight()) { _title_wo.resize(calcTitleWidth(), getTitleHeight()); calcTabsWidth(); } // place buttons, also updates title information placeButtons(); } //! @brief Raises the window, taking _layer into account void PDecor::raise(void) { Workspaces::raise(this); Workspaces::updateClientStackingList(); } //! @brief Lowers the window, taking _layer into account void PDecor::lower(void) { Workspaces::lower(this); Workspaces::updateClientStackingList(); } //! @brief void PDecor::setFocused(bool focused) { if (_focused != focused) { // save repaints PWinObj::setFocused(focused); renderTitle(); renderButtons(); renderBorder(); setBorderShape(); applyBorderShape(); } } //! @brief void PDecor::setWorkspace(uint workspace) { if (workspace != NET_WM_STICKY_WINDOW) { if (workspace >= Workspaces::size()) { LOG("this == " << this << " workspace == " << workspace << " >= number of workspaces == " << Workspaces::size()); workspace = Workspaces::size() - 1; } _workspace = workspace; } vector::const_iterator it(_children.begin()); for (; it != _children.end(); ++it) { (*it)->setWorkspace(workspace); } if (! _mapped && ! _iconified) { if (_sticky || (_workspace == Workspaces::getActive())) { mapWindow(); } } else if (! _sticky && (_workspace != Workspaces::getActive())) { unmapWindow(); } } //! @brief Gives decor input focus, fails if not mapped or not visible void PDecor::giveInputFocus(void) { if (_mapped && _child) { _child->giveInputFocus(); } else { LOG("this == " << this << " - reverting to root"); PWinObj::getRootPWinObj()->giveInputFocus(); } } /** * Handle button press events. */ ActionEvent* PDecor::handleButtonPress(XButtonEvent *ev) { ActionEvent *ae = 0; vector *actions = 0; // Remove state modifiers from event X11::stripStateModifiers(&ev->state); X11::stripButtonModifiers(&ev->state); // Try to do something about frame buttons if (ev->subwindow != None && (_button = findButton(ev->subwindow)) != 0) { ae = handleButtonPressButton(ev, _button); } else { // Record position, used in the motion handler when doing a window move. _click_x = _gm.x; _click_y = _gm.y; _pointer_x = ev->x_root; _pointer_y = ev->y_root; // Allow us to get clicks from anywhere on the window. if (_decor_cfg_bpr_replay_pointer) { XAllowEvents(X11::getDpy(), ReplayPointer, CurrentTime); } if (ev->window == _child->getWindow() || (ev->state == 0 && ev->subwindow == _child->getWindow())) { // Clicks on the child window // NOTE: If the we're matching against the subwindow we need to make // sure that the state is 0, meaning we didn't have any modifier // because if we don't care about the modifier we'll get two actions // performed when using modifiers. _button_press_win = _child->getWindow(); actions = Config::instance()->getMouseActionList(_decor_cfg_bpr_al_child); } else if (_title_wo == ev->window) { // Clicks on the decor title _button_press_win = ev->window; actions = Config::instance()->getMouseActionList(_decor_cfg_bpr_al_title); } else { // Clicks on the decor border, default case. Try both window and sub-window. uint pos = getBorderPosition(ev->window); if (pos != BORDER_NO_POS) { _button_press_win = ev->window; actions = Config::instance()->getBorderListFromPosition(pos); } } } if (! ae && actions) { ae = ActionHandler::findMouseAction(ev->button, ev->state, MOUSE_EVENT_PRESS, actions); } return ae; } /** * Handle button press events pressing decor buttons. */ ActionEvent* PDecor::handleButtonPressButton(XButtonEvent *ev, PDecor::Button *button) { // Keep track of pressed button. _button->setState(BUTTON_STATE_PRESSED); ActionEvent *ae = _button->findAction(ev); // if the button is used for resizing, we don't want to wait for release if (ae && ae->isOnlyAction(ACTION_RESIZE)) { _button->setState(_focused ? BUTTON_STATE_FOCUSED : BUTTON_STATE_UNFOCUSED); _button = 0; } else { ae = 0; } return ae; } /** * Handle button release events. */ ActionEvent* PDecor::handleButtonRelease(XButtonEvent *ev) { ActionEvent *ae = 0; vector *actions = 0; MouseEventType mb = MOUSE_EVENT_RELEASE; // Remove state modifiers from event X11::stripStateModifiers(&ev->state); X11::stripButtonModifiers(&ev->state); // handle titlebar buttons if (_button) { ae = handleButtonReleaseButton(ev, _button); } else { // Allow us to get clicks from anywhere on the window. if (_decor_cfg_bpr_replay_pointer) { XAllowEvents(X11::getDpy(), ReplayPointer, CurrentTime); } // clicks on the child window if (ev->window == _child->getWindow() || (ev->state == 0 && ev->subwindow == _child->getWindow())) { // NOTE: If the we're matching against the subwindow we need to make // sure that the state is 0, meaning we didn't have any modifier // because if we don't care about the modifier we'll get two actions // performed when using modifiers. if (_button_press_win == _child->getWindow()) { actions = Config::instance()->getMouseActionList(_decor_cfg_bpr_al_child); } } else if (_title_wo == ev->window) { if (_button_press_win == ev->window) { // Handle clicks on the decor title, checking double clicks first. if (X11::isDoubleClick(ev->window, ev->button - 1, ev->time, Config::instance()->getDoubleClickTime())) { X11::setLastClickID(ev->window); X11::setLastClickTime(ev->button - 1, 0); mb = MOUSE_EVENT_DOUBLE; } else { X11::setLastClickID(ev->window); X11::setLastClickTime(ev->button - 1, ev->time); } actions = Config::instance()->getMouseActionList(_decor_cfg_bpr_al_title); } } else { // Clicks on the decor border, check subwindow then window. uint pos = getBorderPosition(ev->window); if (pos != BORDER_NO_POS && (_button_press_win == ev->window)) { actions = Config::instance()->getBorderListFromPosition(pos); } } } if (! ae && actions) { ae = ActionHandler::findMouseAction(ev->button, ev->state, mb, actions); } return ae; } /** * Handle button release events when button is in pressed state. */ ActionEvent* PDecor::handleButtonReleaseButton(XButtonEvent *ev, PDecor::Button *button) { // First restore the pressed buttons state _button->setState(_focused ? BUTTON_STATE_FOCUSED : BUTTON_STATE_UNFOCUSED); ActionEvent *ae = 0; // Then see if the button was released over ( to execute an action ) if (*_button == ev->subwindow) { ae = _button->findAction(ev); // This is a little hack, resizing isn't wanted on both press and release if (ae && ae->isOnlyAction(ACTION_RESIZE)) { ae = 0; } } _button = 0; return ae; } //! @brief ActionEvent* PDecor::handleMotionEvent(XMotionEvent *ev) { uint button = X11::getButtonFromState(ev->state); return ActionHandler::findMouseAction(button, ev->state, MOUSE_EVENT_MOTION, Config::instance()->getMouseActionList(MOUSE_ACTION_LIST_OTHER)); } /** * Handle enter event, find action and toggle hoover state if enter * was on a button. */ ActionEvent* PDecor::handleEnterEvent(XCrossingEvent *ev) { PDecor::Button *button = findButton(ev->window); if (button) { button->setState(BUTTON_STATE_HOVER); } return ActionHandler::findMouseAction(BUTTON_ANY, ev->state, MOUSE_EVENT_ENTER, Config::instance()->getMouseActionList(MOUSE_ACTION_LIST_OTHER)); } /** * Handle leave event, find action and toggle hoover state if leave * was from a button. */ ActionEvent* PDecor::handleLeaveEvent(XCrossingEvent *ev) { PDecor::Button *button = findButton(ev->window); if (button) { button->setState(button->getState()); } return ActionHandler::findMouseAction(BUTTON_ANY, ev->state, MOUSE_EVENT_LEAVE, Config::instance()->getMouseActionList(MOUSE_ACTION_LIST_OTHER)); } // END - PWinObj interface. //! @brief Adds a children in another decor to this decor void PDecor::addDecor(PDecor *decor) { if (this == decor) { LOG("this == decor (" << this << ")"); return; } vector::const_iterator it(decor->begin()); for (; it != decor->end(); ++it) { addChild(*it); (*it)->setWorkspace(_workspace); } decor->_children.clear(); delete decor; } //! @return True on decor change, False if decor unchanged bool PDecor::updateDecor(void) { string name = getDecorName(); if (! _decor_name_saved.empty()) { _decor_name_saved = name; return false; } if (_decor_name == name) { return false; } _decor_name = name; loadDecor(); return true; } //! @brief Sets override decor name void PDecor::setDecorOverride(StateAction sa, const std::string &name) { if (sa == STATE_SET || (sa == STATE_TOGGLE && _decor_name_saved.empty())) { if (_decor_name_saved.empty()) { _decor_name_saved = _decor_name; } if (_decor_name != name) { _decor_name = name; loadDecor(); } } else if (! _decor_name_saved.empty()) { _decor_name = _decor_name_saved; _decor_name_saved.clear(); loadDecor(); } } //! @brief Load and update decor. void PDecor::loadDecor(void) { unloadDecor(); // Get decordata with name. _data = _theme->getPDecorData(_decor_name); if (! _data) { _data = _theme->getPDecorData(DEFAULT_DECOR_NAME); } LOG_IF(!_data, "_data == 0"); // Load decor. vector::const_iterator b_it(_data->buttonBegin()); for (; b_it != _data->buttonEnd(); ++b_it) { uint width = std::max(static_cast(1), (*b_it)->getWidth() ? (*b_it)->getWidth() : getTitleHeight()); uint height = std::max(static_cast(1), (*b_it)->getHeight() ? (*b_it)->getHeight() : getTitleHeight()); _buttons.push_back(new PDecor::Button(&_title_wo, *b_it, width, height)); _buttons.back()->mapWindow(); addChildWindow(_buttons.back()->getWindow()); } if (! _data->getTitleHeight() && ! _data->isTitleHeightAdapt()) { _title_wo.unmapWindow(); } else { _title_wo.mapWindow(); } // Update title position. if (_data->getTitleWidthMin() == 0) { _title_wo.move(borderTopLeft(), borderTop()); _need_shape = false; } else { _title_wo.move(0, 0); _need_shape = true; } // Update child positions. vector::const_iterator c_it(_children.begin()); for (; c_it != _children.end(); ++c_it) { alignChild(*c_it); } // Make sure it gets rendered correctly. _focused = ! _focused; setFocused(! _focused); // Update the dimension of the frame. if (_child) { resizeChild(_child->getWidth(), _child->getHeight()); } // Child theme change. loadTheme(); } //! @brief Frees resources used by PDecor. void PDecor::unloadDecor(void) { // Set active button to 0 as it can not be valid after deleting // the current buttons. _button = 0; vector::const_iterator it(_buttons.begin()); for (; it != _buttons.end(); ++it) { removeChildWindow((*it)->getWindow()); delete *it; } _buttons.clear(); } //! @brief PDecor::Button* PDecor::findButton(Window win) { vector::const_iterator it(_buttons.begin()); for (; it != _buttons.end(); ++it) { if (**it == win) { return *it; } } return 0; } //! @brief PWinObj* PDecor::getChildFromPos(int x) { if (_children.empty() || _children.size() != _titles.size()) { return 0; } if (_children.size() == 1) return _children.front(); if (x < static_cast(_titles_left)) { return _children.front(); } else if (x > static_cast(_title_wo.getWidth() - _titles_right)) { return _children.back(); } PTexture *t_sep = _data->getTextureSeparator(getFocusedState(false)); uint sepw = t_sep?t_sep->getWidth():0; uint pos = _titles_left, xx = x; for (uint i = 0; i < _titles.size(); ++i) { if (xx >= pos && xx <= pos + _titles[i]->getWidth() + sepw) { return _children[i]; } pos += _titles[i]->getWidth() + sepw; } return 0; } //! @brief Moves making the child be positioned at x y void PDecor::moveChild(int x, int y) { move(x - borderLeft(), y - borderTop() - getTitleHeight()); } //! @brief Resizes the decor, giving width x height space for the child void PDecor::resizeChild(uint width, uint height) { resize(width + borderLeft() + borderRight(), height + borderTop() + borderBottom() + getTitleHeight()); } //! @brief Sets border state of the decor void PDecor::setBorder(StateAction sa) { if (! ActionUtil::needToggle(sa, _border)) { return; } // If we are going to remove the border, we need to check carefully // that we don't try to make the window disappear. if (! _border) { _border = true; } else if (! _shaded || _titlebar) { _border = false; } restackBorder(); if (! updateDecor() && _child) { resizeChild(_child->getWidth(), _child->getHeight()); } } //! @brief Sets titlebar state of the decor void PDecor::setTitlebar(StateAction sa) { if (! ActionUtil::needToggle(sa, _titlebar)) return; // If we are going to remove the titlebar, we need to check carefully // that we don't try to make the window disappear. if (! _titlebar) { _title_wo.mapWindow(); _titlebar = true; } else if (! _shaded || _border) { _title_wo.unmapWindow(); _titlebar = false; } // If updateDecorName returns true, it already loaded decor stuff for us. if (! updateDecor() && _child) { alignChild(_child); resizeChild(_child->getWidth(), _child->getHeight()); } } //! @brief Calculate title height, 0 if titlebar is disabled. uint PDecor::getTitleHeight(void) const { if (! _titlebar) { return 0; } if (_data->isTitleHeightAdapt()) { return getFont(getFocusedState(false))->getHeight() + _data->getPad(PAD_UP) + _data->getPad(PAD_DOWN); } else { return _data->getTitleHeight(); } } //! @brief Adds a child to the decor, reparenting the window void PDecor::addChild(PWinObj *child, vector::iterator *it) { child->reparent(this, borderLeft(), borderTop() + getTitleHeight()); if (it == 0) { _children.push_back(child); } else { _children.insert(*it, child); } updatedChildOrder(); // Sync focused state if it is the first child, the child will be // activated later on. If there are children here already fit the // child into the decor. if (_children.size() == 1) { _focused = ! _focused; setFocused(! _focused); } else { alignChild(child); child->resize(getChildWidth(), getChildHeight()); } } //! @brief Removes PWinObj from this PDecor. //! @param child PWinObj to remove from the this PDecor. //! @param do_delete Wheter to call delete this when empty. (Defaults to true) void PDecor::removeChild(PWinObj *child, bool do_delete) { child->reparent(PWinObj::getRootPWinObj(), _gm.x + borderLeft(), _gm.y + borderTop() + getTitleHeight()); vector::iterator it(find(_children.begin(), _children.end(), child)); if (it == _children.end()) { LOG("this == " << this << " child == " << child << " - child not in _child_list, bailing out"); return; } it = _children.erase(it); if (! _children.empty()) { if (_child == child) { if (it == _children.end()) { --it; } activateChild(*it); } updatedChildOrder(); } else if (do_delete) { delete this; // no children, and we don't want empty PDecors } } //! @brief Activates the child, updating size and position void PDecor::activateChild(PWinObj *child) { // sync state _focusable = child->isFocusable(); alignChild(child); // place correct acording to border and title child->resize(getChildWidth(), getChildHeight()); child->raise(); _child = child; restackBorder(); updatedChildOrder(); } //! @brief void PDecor::getDecorInfo(wchar_t *buf, uint size) { swprintf(buf, size, L"%dx%d+%d+%d", _gm.width, _gm.height, _gm.x, _gm.y); } //! @brief void PDecor::activateChildNum(uint num) { if (num >= _children.size()) { LOG("this == " << this << " num == " << num << " >= _children.size() == " << _children.size()); return; } activateChild(_children[num]); } //! @brief void PDecor::activateChildRel(int off) { vector::size_type cur=0, size = _children.size(); for (; cur < size; ++cur) { if (_child == _children[cur]) { break; } } if (cur == size) { _child = _children.front(); cur = 0; } off = (off+signed(cur))%signed(size); if (off < 0) { off += size; } activateChild(_children[off]); } //! @brief Moves the current child off steps //! @param off - for left and + for right void PDecor::moveChildRel(int off) { vector::size_type idx=0, size = _children.size(); for (; idx < size; ++idx) { if (_child == _children[idx]) { break; } } if (idx == size) { if (_children.empty()) { ERR("_children is empty! off == " << off << " Please report."); return; } _child = _children.front(); idx = 0; } off = (off+idx)%size; if (off < 0) { off += size; } _children.erase(std::remove(_children.begin(), _children.end(), _child), _children.end()); _children.insert(_children.begin()+off, _child); updatedChildOrder(); } //! @brief Do move of Decor with the mouse. //! @param x_root X position of the pointer when event was triggered. //! @param y_root Y position of the pointer when event was triggered. void PDecor::doMove(int x_root, int y_root) { if (! allowMove()) { return; } StatusWindow *sw = StatusWindow::instance(); // convenience if (! X11::grabPointer(X11::getRoot(), ButtonMotionMask|ButtonReleaseMask, CURSOR_MOVE)) { return; } // Get relative position to root int x = x_root - _gm.x; int y = y_root - _gm.y; bool outline = ! Config::instance()->getOpaqueMove(); bool center_on_root = Config::instance()->isShowStatusWindowOnRoot(); EdgeType edge; // grab server, we don't want invert traces if (outline) { X11::grabServer(); } if (Config::instance()->isShowStatusWindow()) { sw->drawGeometry(_gm, center_on_root); sw->mapWindowRaised(); sw->drawGeometry(_gm, center_on_root); } Geometry last_gm(_gm); XEvent e; const long move_mask = ButtonPressMask|ButtonReleaseMask|PointerMotionMask; bool exit = false; while (! exit) { if (outline) { drawOutline(_gm); } XMaskEvent(X11::getDpy(), move_mask, &e); if (outline) { drawOutline(_gm); // clear } switch (e.type) { case MotionNotify: // Flush all pointer motion, no need to redraw and redraw. X11::removeMotionEvents(); _gm.x = e.xmotion.x_root - x; _gm.y = e.xmotion.y_root - y; checkSnap(); if (! outline && _gm != last_gm) { last_gm = _gm; XMoveWindow(X11::getDpy(), _window, _gm.x, _gm.y); } edge = doMoveEdgeFind(e.xmotion.x_root, e.xmotion.y_root); if (edge != SCREEN_EDGE_NO) { doMoveEdgeAction(&e.xmotion, edge); } if (Config::instance()->isShowStatusWindow()) { sw->drawGeometry(_gm, center_on_root); } break; case ButtonRelease: exit = true; break; } } move(_gm.x, _gm.y); // update child if (Config::instance()->isShowStatusWindow()) { sw->unmapWindow(); } // ungrab the server if (outline) { move(_gm.x, _gm.y); X11::ungrabServer(true); } X11::ungrabPointer(); Workspaces::layoutIfTiling(); } //! @brief Matches cordinates against screen edge EdgeType PDecor::doMoveEdgeFind(int x, int y) { EdgeType edge = SCREEN_EDGE_NO; if (x <= signed(Config::instance()->getScreenEdgeSize(SCREEN_EDGE_LEFT))) { edge = SCREEN_EDGE_LEFT; } else if (x >= signed(X11::getWidth() - Config::instance()->getScreenEdgeSize(SCREEN_EDGE_RIGHT))) { edge = SCREEN_EDGE_RIGHT; } else if (y <= signed(Config::instance()->getScreenEdgeSize(SCREEN_EDGE_TOP))) { edge = SCREEN_EDGE_TOP; } else if (y >= signed(X11::getHeight() - Config::instance()->getScreenEdgeSize(SCREEN_EDGE_BOTTOM))) { edge = SCREEN_EDGE_BOTTOM; } return edge; } //! @brief Finds and executes action if any void PDecor::doMoveEdgeAction(XMotionEvent *ev, EdgeType edge) { ActionEvent *ae; uint button = X11::getButtonFromState(ev->state); ae = ActionHandler::findMouseAction(button, ev->state, MOUSE_EVENT_ENTER_MOVING, Config::instance()->getEdgeListFromPosition(edge)); if (ae) { ActionPerformed ap(this, *ae); ap.type = ev->type; ap.event.motion = ev; ActionHandler::instance()->handleAction(ap); } } /** * Move and resize window with keybindings. */ void PDecor::doKeyboardMoveResize(void) { StatusWindow *sw = StatusWindow::instance(); // convenience if (! X11::grabPointer(X11::getRoot(), NoEventMask, CURSOR_MOVE)) { return; } if (! X11::grabKeyboard(X11::getRoot())) { X11::ungrabPointer(); return; } Geometry old_gm = _gm; // backup geometry if we cancel bool outline = (! Config::instance()->getOpaqueMove() || ! Config::instance()->getOpaqueResize()); ActionEvent *ae; vector::iterator it; bool center_on_root = Config::instance()->isShowStatusWindowOnRoot(); if (Config::instance()->isShowStatusWindow()) { sw->drawGeometry(_gm, center_on_root); sw->mapWindowRaised(); sw->drawGeometry(_gm, center_on_root); } if (outline) { X11::grabServer(); } XEvent e; bool exit = false; while (! exit) { if (outline) { drawOutline(_gm); } XMaskEvent(X11::getDpy(), KeyPressMask, &e); if (outline) { drawOutline(_gm); // clear } if ((ae = KeyGrabber::instance()->findMoveResizeAction(&e.xkey)) != 0) { for (it = ae->action_list.begin(); it != ae->action_list.end(); ++it) { switch (it->getAction()) { case MOVE_HORIZONTAL: _gm.x += it->getParamI(0); if (! outline) { move(_gm.x, _gm.y); } break; case MOVE_VERTICAL: _gm.y += it->getParamI(0); if (! outline) { move(_gm.x, _gm.y); } break; case RESIZE_HORIZONTAL: _gm.width += resizeHorzStep(it->getParamI(0)); if (! outline) { resize(_gm.width, _gm.height); } break; case RESIZE_VERTICAL: _gm.height += resizeVertStep(it->getParamI(0)); if (! outline) { resize(_gm.width, _gm.height); } break; case MOVE_SNAP: checkSnap(); if (! outline) { move(_gm.x, _gm.y); } break; case MOVE_CANCEL: _gm = old_gm; // restore position if (! outline) { move(_gm.x, _gm.y); resize(_gm.width, _gm.height); } exit = true; break; case MOVE_END: if (outline) { if ((_gm.x != old_gm.x) || (_gm.y != old_gm.y)) move(_gm.x, _gm.y); if ((_gm.width != old_gm.width) || (_gm.height != old_gm.height)) resize(_gm.width, _gm.height); } exit = true; break; default: // do nothing break; } if (Config::instance()->isShowStatusWindow()) { sw->drawGeometry(_gm, center_on_root); } } } } if (Config::instance()->isShowStatusWindow()) { sw->unmapWindow(); } if (outline) { X11::ungrabServer(true); } X11::ungrabKeyboard(); X11::ungrabPointer(); } //! @brief Sets shaded state void PDecor::setShaded(StateAction sa) { if (! ActionUtil::needToggle(sa, _shaded)) return; // If we are going to shade the window, we need to check carefully // that we don't try to make the window disappear. if (_shaded) { _gm.height = _real_height; _shaded = false; // If we have a titlebar OR border (border will only be visible in // full-width mode only) } else if (_titlebar || (_border && ! _data->getTitleWidthMin())) { _real_height = _gm.height; _gm.height = getTitleHeight(); // shading in non full width title mode will make border go away if (! _data->getTitleWidthMin()) { _gm.height += borderTop() + borderBottom(); } _shaded = true; } setBorderShape(); placeBorder(); restackBorder(); PWinObj::resize(_gm.width, _gm.height); } //! @brief Sets skip state. void PDecor::setSkip(uint skip) { _skip = skip; } /** * Returns the name of the decor for the current titlebar/border state. */ std::string PDecor::getDecorName(void) { if (Workspaces::isTiling(_workspace) && allowTiling()) { return DEFAULT_DECOR_NAME_TILING; } if (_attention) { return DEFAULT_DECOR_NAME_ATTENTION; } if (_titlebar && _border) { return DEFAULT_DECOR_NAME; } if (_border) { return DEFAULT_DECOR_NAME_TITLEBARLESS; } return DEFAULT_DECOR_NAME_BORDERLESS; } //! @brief Remove iconified state. void PDecor::deiconify(void) { if (_iconified) { if (_workspace == Workspaces::getActive()) { mapWindow(); } _iconified = false; } } //! @brief Renders and sets title background void PDecor::renderTitle(void) { if (! getTitleHeight()) { return; } if (_data->getTitleWidthMin()) { resizeTitle(); applyBorderShape(); // update title shape } else { calcTabsWidth(); } PTexture *t_sep = _data->getTextureSeparator(getFocusedState(false)); Pixmap title_bg = X11::createPixmap(_title_wo.getWidth(), _title_wo.getHeight()); // Render main background on pixmap _data->getTextureMain(getFocusedState(false))->render(title_bg, 0, 0, _title_wo.getWidth(), _title_wo.getHeight()); PFont *font; bool sel; // Current tab selected flag uint x = _titles_left; // Position uint pad_horiz = _data->getPad(PAD_LEFT) + _data->getPad(PAD_RIGHT); // Amount of horizontal padding uint size = _titles.size(); for (uint i = 0; i < size; ++i) { sel = (_title_active == i); // render tab _data->getTextureTab(getFocusedState(sel))->render(title_bg, x, 0, _titles[i]->getWidth(), _title_wo.getHeight()); font = getFont(getFocusedState(sel)); font->setColor(_data->getFontColor(getFocusedState(sel))); PFont::TrimType trim = PFont::FONT_TRIM_MIDDLE; if (_titles[i]->isCustom() || _titles[i]->isUserSet()) { trim = PFont::FONT_TRIM_END; } font->draw(title_bg, x + _data->getPad(PAD_LEFT), // X position _data->getPad(PAD_UP), // Y position _titles[i]->getVisible(), 0, // Text and max chars _titles[i]->getWidth() - pad_horiz, // Available width trim); // Type of trim // move to next tab (or separator if any) x += _titles[i]->getWidth(); // draw separator if (size > 1 && i < size - 1) { t_sep->render(title_bg, x, 0, 0, 0); x += t_sep->getWidth(); } } _title_wo.setBackgroundPixmap(title_bg); _title_wo.clear(); X11::freePixmap(title_bg); } //! @brief void PDecor::renderButtons(void) { vector::const_iterator it(_buttons.begin()); for (; it != _buttons.end(); ++it) { (*it)->setState(_focused ? BUTTON_STATE_FOCUSED : BUTTON_STATE_UNFOCUSED); } } //! @brief Renders the border of the decor. void PDecor::renderBorder(void) { if (! _border) { return; } PTexture *tex; FocusedState state = getFocusedState(false); uint width, height; Pixmap pix = None; for (int i=0; i < BORDER_NO_POS; ++i) { tex = _data->getBorderTexture(state, static_cast(i)); // Solid texture, get the color and set as bg, no need to render pixmap if (tex->getType() == PTexture::TYPE_SOLID) { XSetWindowBackground(X11::getDpy(), _border_win[i], static_cast(tex)->getColor()->pixel); } else { // not a solid texture, get pixmap, render, set as bg getBorderSize(static_cast(i), width, height); if (width > 0 && height > 0) { pix = X11::createPixmap(width, height); tex->render(pix, 0, 0, width, height); XSetWindowBackgroundPixmap(X11::getDpy(), _border_win[i], pix); X11::freePixmap(pix); } } XClearWindow(X11::getDpy(), _border_win[i]); } } //! @brief Sets shape on the border windows. void PDecor::setBorderShape(void) { #ifdef HAVE_SHAPE Pixmap pix; bool do_free; unsigned int width, height; PTexture *tex; FocusedState state = getFocusedState(false); XRectangle rect = {0, 0, 0, 0}; for (int i=0; i < BORDER_NO_POS; ++i) { // Get the size of the border at position getBorderSize(static_cast(i), width, height); tex = _data->getBorderTexture(state, static_cast(i)); pix = tex->getMask(width, height, do_free); if (pix != None) { _need_shape = true; X11::shapeSetMask(_border_win[i], ShapeBounding, pix); if (do_free) { X11::freePixmap(pix); } } else { rect.width = width; rect.height = height; X11::shapeSetRect(_border_win[i], &rect); } } #endif // HAVE_SHAPE } //! @brief Finds the Head closest to x y from the center of the decor uint PDecor::getNearestHead(void) { return X11::getNearestHead(_gm.x + (_gm.width / 2), _gm.y + (_gm.height / 2)); } //! @brief void PDecor::checkSnap(void) { if ((Config::instance()->getWOAttract() > 0) || (Config::instance()->getWOResist() > 0)) { checkWOSnap(); } if ((Config::instance()->getEdgeAttract() > 0) || (Config::instance()->getEdgeResist() > 0)) { checkEdgeSnap(); } } inline bool isBetween(int x1, int x2, int t1, int t2) { if (x1 > t1) { if (x1 < t2) { return true; } } else if (x2 > t1) { return true; } return false; } //! @brief //! @todo PDecor/PWinObj doesn't have _skip property void PDecor::checkWOSnap(void) { PDecor *decor; Geometry gm = _gm; int x = getRX(); int y = getBY(); int attract = Config::instance()->getWOAttract(); int resist = Config::instance()->getWOResist(); bool snapped; vector::reverse_iterator it = _wo_list.rbegin(); for (; it != _wo_list.rend(); ++it) { if (((*it) == this) || ! (*it)->isMapped() || ((*it)->getType() != PWinObj::WO_FRAME)) { continue; } // Skip snapping, only valid on PDecor and up. decor = dynamic_cast(*it); if (decor && decor->isSkip(SKIP_SNAP)) { continue; } snapped = false; // check snap if ((x >= ((*it)->getX() - attract)) && (x <= ((*it)->getX() + resist))) { if (isBetween(gm.y, y, (*it)->getY(), (*it)->getBY())) { _gm.x = (*it)->getX() - gm.width; snapped = true; } } else if ((gm.x >= signed((*it)->getRX() - resist)) && (gm.x <= signed((*it)->getRX() + attract))) { if (isBetween(gm.y, y, (*it)->getY(), (*it)->getBY())) { _gm.x = (*it)->getRX(); snapped = true; } } if (y >= ((*it)->getY() - attract) && (y <= (*it)->getY() + resist)) { if (isBetween(gm.x, x, (*it)->getX(), (*it)->getRX())) { _gm.y = (*it)->getY() - gm.height; if (snapped) break; } } else if ((gm.y >= signed((*it)->getBY() - resist)) && (gm.y <= signed((*it)->getBY() + attract))) { if (isBetween(gm.x, x, (*it)->getX(), (*it)->getRX())) { _gm.y = (*it)->getBY(); if (snapped) break; } } } } //! @brief Snaps decor agains head edges. Only updates _gm, no real move. //! @todo Add support for checking for harbour and struts void PDecor::checkEdgeSnap(void) { int attract = Config::instance()->getEdgeAttract(); int resist = Config::instance()->getEdgeResist(); Geometry head; X11::getHeadInfoWithEdge(X11::getNearestHead(_gm.x, _gm.y), head); if ((_gm.x >= (head.x - resist)) && (_gm.x <= (head.x + attract))) { _gm.x = head.x; } else if ((_gm.x + _gm.width) >= (head.x + head.width - attract) && ((_gm.x + _gm.width) <= (head.x + head.width + resist))) { _gm.x = head.x + head.width - _gm.width; } if ((_gm.y >= (head.y - resist)) && (_gm.y <= (head.y + attract))) { _gm.y = head.y; } else if (((_gm.y + _gm.height) >= (head.y + head.height - attract)) && ((_gm.y + _gm.height) <= (head.y + head.height + resist))) { _gm.y = head.y + head.height - _gm.height; } } /** * Move child into position with regards to title and border. */ void PDecor::alignChild(PWinObj *child) { if (child) { XMoveWindow(X11::getDpy(), child->getWindow(), borderLeft(), borderTop() + getTitleHeight()); } } //! @brief Draws outline of the decor with geometry gm void PDecor::drawOutline(const Geometry &gm) { XDrawRectangle(X11::getDpy(), X11::getRoot(), _theme->getInvertGC(), gm.x, gm.y, gm.width, _shaded ? _gm.height : gm.height); } //! @brief Places decor buttons void PDecor::placeButtons(void) { _titles_left = 0; _titles_right = 0; vector::const_iterator it(_buttons.begin()); for (; it != _buttons.end(); ++it) { if ((*it)->isLeft()) { (*it)->move(_titles_left, 0); _titles_left += (*it)->getWidth(); } else { _titles_right += (*it)->getWidth(); (*it)->move(_title_wo.getWidth() - _titles_right, 0); } } } //! @brief Places border windows void PDecor::placeBorder(void) { // if we have tab min == 0 then we have full width title and place the // border ontop, else we put the border under the title uint bt_off = (_data->getTitleWidthMin() > 0) ? getTitleHeight() : 0; if (borderTop() > 0) { XMoveResizeWindow(X11::getDpy(), _border_win[BORDER_TOP], borderTopLeft(), bt_off, _gm.width - borderTopLeft() - borderTopRight(), borderTop()); XMoveResizeWindow(X11::getDpy(), _border_win[BORDER_TOP_LEFT], 0, bt_off, borderTopLeft(), borderTopLeftHeight()); XMoveResizeWindow(X11::getDpy(), _border_win[BORDER_TOP_RIGHT], _gm.width - borderTopRight(), bt_off, borderTopRight(), borderTopRightHeight()); if (borderLeft()) { XMoveResizeWindow(X11::getDpy(), _border_win[BORDER_LEFT], 0, borderTopLeftHeight() + bt_off, borderLeft(), _gm.height - borderTopLeftHeight() - borderBottomLeftHeight()); } if (borderRight()) { XMoveResizeWindow(X11::getDpy(), _border_win[BORDER_RIGHT], _gm.width - borderRight(), borderTopRightHeight() + bt_off, borderRight(), _gm.height - borderTopRightHeight() - borderBottomRightHeight()); } } else { if (borderLeft()) { XMoveResizeWindow(X11::getDpy(), _border_win[BORDER_LEFT], 0, getTitleHeight(), borderLeft(), _gm.height - getTitleHeight() - borderBottom()); } if (borderRight()) { XMoveResizeWindow(X11::getDpy(), _border_win[BORDER_RIGHT], _gm.width - borderRight(), getTitleHeight(), borderRight(), _gm.height - getTitleHeight() - borderBottom()); } } if (borderBottom()) { XMoveResizeWindow(X11::getDpy(), _border_win[BORDER_BOTTOM], borderBottomLeft(), _gm.height - borderBottom(), _gm.width - borderBottomLeft() - borderBottomRight(), borderBottom()); XMoveResizeWindow(X11::getDpy(), _border_win[BORDER_BOTTOM_LEFT], 0, _gm.height - borderBottomLeftHeight(), borderBottomLeft(), borderBottomLeftHeight()); XMoveResizeWindow(X11::getDpy(), _border_win[BORDER_BOTTOM_RIGHT], _gm.width - borderBottomRight(), _gm.height - borderBottomRightHeight(), borderBottomRight(), borderBottomRightHeight()); } applyBorderShape(); } #ifdef HAVE_SHAPE /** * Apply shaping on the window based on the shape of the client and * the borders. */ void PDecor::applyBorderShape(int kind) { bool client_shape = _child?_child->hasShapeRegion(kind):false; XRectangle rect_square; rect_square.x = 0; rect_square.y = 0; rect_square.width = _gm.width; rect_square.height = _gm.height; if ((_need_shape && kind == ShapeBounding) || client_shape) { // if we have tab min == 0 then we have full width title and place the // border ontop, else we put the border under the title uint bt_off = (_data->getTitleWidthMin() > 0) ? getTitleHeight() : 0; Window shape; shape = XCreateSimpleWindow(X11::getDpy(), X11::getRoot(), 0, 0, _gm.width, _gm.height, 0, 0, 0); if (_child && ! _shaded) { X11::shapeCombine(shape, kind, borderLeft(), borderTop() + getTitleHeight(), _child->getWindow(), ShapeSet); } // Apply border shape. Need to be carefull wheter or not to include it. if (_border && ! (_shaded && bt_off) // Shaded in non-full-width mode removes border. && ! client_shape) { // Shaped clients should appear bordeless. // top if (borderTop() > 0) { X11::shapeCombine(shape, kind, 0, bt_off, _border_win[BORDER_TOP_LEFT], ShapeUnion); X11::shapeCombine(shape, kind, borderTopLeft(), bt_off, _border_win[BORDER_TOP], ShapeUnion); X11::shapeCombine(shape, kind, _gm.width - borderTopRight(), bt_off, _border_win[BORDER_TOP_RIGHT], ShapeUnion); } bool use_bt_off = bt_off || borderTop(); // Left border if (borderLeft() > 0) { X11::shapeCombine(shape, kind, 0, use_bt_off ? bt_off + borderTopLeftHeight() : getTitleHeight(), _border_win[BORDER_LEFT], ShapeUnion); } // Right border if (borderRight() > 0) { X11::shapeCombine(shape, kind, _gm.width - borderRight(), use_bt_off ? bt_off + borderTopRightHeight() : getTitleHeight(), _border_win[BORDER_RIGHT], ShapeUnion); } // bottom if (borderBottom() > 0) { X11::shapeCombine(shape, kind, 0, _gm.height - borderBottomLeftHeight(), _border_win[BORDER_BOTTOM_LEFT], ShapeUnion); X11::shapeCombine(shape, kind, borderBottomLeft(), _gm.height - borderBottom(), _border_win[BORDER_BOTTOM], ShapeUnion); X11::shapeCombine(shape, kind, _gm.width - borderBottomRight(), _gm.height - borderBottomRightHeight(), _border_win[BORDER_BOTTOM_RIGHT], ShapeUnion); } } if (_titlebar) { // apply title shape X11::shapeCombine(shape, kind, _title_wo.getX(), _title_wo.getY(), _title_wo.getWindow(), ShapeUnion); } // The borders might extend beyond the window area (causing // artifacts under xcompmgr), so we cut the shape down to the // original window size. X11::shapeIntersectRect(shape, &rect_square); // Apply the shape mask to the window X11::shapeCombine(_window, kind, 0, 0, shape, ShapeSet); XDestroyWindow(X11::getDpy(), shape); } else { // Reinstate default region X11::shapeSetMask(_window, kind, None); } } #endif // HAVE_SHAPE //! @brief Restacks child, title and border windows. void PDecor::restackBorder(void) { // List of windows, adding two possible for title and child window int extra = 0; Window windows[BORDER_NO_POS + 2]; // Only put the Child over if not shaded. if (_child && ! _shaded) { windows[extra++] = _child->getWindow(); } // Add title if any if (_titlebar) { windows[extra++] = _title_wo.getWindow(); } // Add border windows for (int i = 0; i < BORDER_NO_POS; ++i) { windows[i + extra] = _border_win[i]; } // Raise the top window so actual restacking is done. XRaiseWindow(X11::getDpy(), windows[0]); XRestackWindows(X11::getDpy(), windows, BORDER_NO_POS + extra); } /** * Get size of border at position. * * @param pos Position to get size for. * @param width Width of border at position. * @param height Height of border at position. */ void PDecor::getBorderSize(BorderPosition pos, uint &width, uint &height) { FocusedState state = getFocusedState(false); // convenience switch (pos) { case BORDER_TOP_LEFT: case BORDER_TOP_RIGHT: case BORDER_BOTTOM_LEFT: case BORDER_BOTTOM_RIGHT: width = _data->getBorderTexture(state, pos)->getWidth(); height = _data->getBorderTexture(state, pos)->getHeight(); break; case BORDER_TOP: if ((borderTopLeft() + borderTopRight()) < _gm.width) { width = _gm.width - borderTopLeft() - borderTopRight(); } else { width = 1; } height = _data->getBorderTexture(state, pos)->getHeight(); break; case BORDER_BOTTOM: if ((borderBottomLeft() + borderBottomRight()) < _gm.width) { width = _gm.width - borderBottomLeft() - borderBottomRight(); } else { width = 1; } height = _data->getBorderTexture(state, pos)->getHeight(); break; case BORDER_LEFT: width = _data->getBorderTexture(state, pos)->getWidth(); if ((borderTopLeftHeight() + borderBottomLeftHeight()) < _gm.height) { height = _gm.height - borderTopLeftHeight() - borderBottomLeftHeight(); } else { height = 1; } break; case BORDER_RIGHT: width = _data->getBorderTexture(state, pos)->getWidth(); if ((borderTopRightHeight() + borderBottomRightHeight()) < _gm.height) { height = _gm.height - borderTopRightHeight() - borderBottomRightHeight(); } else { height = 1; } break; default: LOG("this == " << this << " - invalid border position"); width = 1; height = 1; break; }; } /** * Calculate width of title, if width min is 0 use the full available * size minus borders. Else get width from content. */ uint PDecor::calcTitleWidth(void) { uint width = 0; if (_data->getTitleWidthMin() == 0) { width = _gm.width; if (width > (borderTopLeft() + borderTopRight())) { width -= borderTopLeft() + borderTopRight(); } } else { uint width_max = 0; // FIXME: what about selected tabs? PFont *font = getFont(getFocusedState(false)); if (_data->isTitleWidthSymetric()) { // Symetric mode, get max tab width, multiply with number of tabs vector::const_iterator it(_titles.begin()); for (; it != _titles.end(); ++it) { width = font->getWidth((*it)->getVisible()); if (width > width_max) { width_max = width; } } width = width_max + _data->getPad(PAD_LEFT) + _data->getPad(PAD_RIGHT); width *= _titles.size(); } else { // Asymetric mode, get individual widths vector::const_iterator it(_titles.begin()); for (; it != _titles.end(); ++it) { width += font->getWidth((*it)->getVisible()) + _data->getPad(PAD_LEFT) + _data->getPad(PAD_RIGHT); } } // Add width of separators and buttons width += (_titles.size() - 1) * _data->getTextureSeparator(getFocusedState(false))->getWidth(); width += _titles_left + _titles_right; // Validate sizes, make sure it is not less than width min // pixels and more than width max percent. if (width < static_cast(_data->getTitleWidthMin())) { width = _data->getTitleWidthMin(); } if (width > (_gm.width * _data->getTitleWidthMax() / 100)) { width = _gm.width * _data->getTitleWidthMax() / 100; } } return width; } /** * Calculate tab width, wrapper to choose correct algorithm.. */ void PDecor::calcTabsWidth(void) { if (! _titles.size()) { return; } if (_data->isTitleWidthSymetric()) { calcTabsWidthSymetric(); } else { calcTabsWidthAsymetric(); } } /** * Get available tabs width and average width of a single tab. * * @param width_avail Number of pixels available in the titlebar. * @param tab_width Width in pixels to use for one tab. * @param off Number of pixels left with tab_width pixels wide tabs. */ void PDecor::calcTabsGetAvailAndTabWidth(uint &width_avail, uint &tab_width, int &off) { // Calculate width width_avail = _title_wo.getWidth(); // Remove spacing if enough space is available if (width_avail > (_titles_left + _titles_right)) { width_avail -= _titles_left + _titles_right; } // Remove separators if enough space is available uint sep_width = (_titles.size() - 1) * _data->getTextureSeparator(getFocusedState(false))->getWidth(); if (width_avail > sep_width) { width_avail -= sep_width; } tab_width = width_avail / _titles.size(); off = width_avail % _titles.size(); } //! @brief Calculate tab width symetric, sets up _titles widths. void PDecor::calcTabsWidthSymetric(void) { int off; uint width_avail, tab_width; calcTabsGetAvailAndTabWidth(width_avail, tab_width, off); // Assign width to elements vector::const_iterator it(_titles.begin()); for (; it != _titles.end(); ++it) { (*it)->setWidth(tab_width + ((off-- > 0) ? 1 : 0)); } } /** * Calculate tab width asymmetrically. This is done with the following * priority: * * 1. Give tabs their required width, if it fits this is complete. * 2. Tabs did not fit, calculate average width. * 3. Add width of tabs requiring less space to average. * 4. Re-assign width equally to tabs using more than average. */ void PDecor::calcTabsWidthAsymetric(void) { int off; uint width, width_avail, tab_width; calcTabsGetAvailAndTabWidth(width_avail, tab_width, off); // Convenience PFont *font = getFont(getFocusedState(false)); // 1. give tabs their required width. uint width_total = 0; vector::const_iterator it(_titles.begin()); for (; it != _titles.end(); ++it) { // This should set the tab width to be only the size needed width = font->getWidth((*it)->getVisible().c_str()) + _data->getPad(PAD_LEFT) + _data->getPad(PAD_RIGHT) + ((off-- > 0) ? 1 : 0); width_total += width; (*it)->setWidth(width); } if (width_total > width_avail) { calcTabsWidthAsymetricShrink(width_avail, tab_width); } else if (width_total < static_cast(_data->getTitleWidthMin())) { calcTabsWidthAsymetricGrow(width_avail, tab_width); } } /** * This is called to shrink the tabs that are over the tab_width in * order to make room for all */ void PDecor::calcTabsWidthAsymetricShrink(uint width_avail, uint tab_width) { // 2. Tabs did not fit uint tabs_left = _titles.size(); vector::const_iterator it(_titles.begin()); for (; it != _titles.end(); ++it) { if ((*it)->getWidth() < tab_width) { // 3. Add width of tabs requiring less space to the average. tabs_left--; width_avail -= (*it)->getWidth(); } } // 4. Re-assign width equally to tabs using more than average tab_width = width_avail / tabs_left; uint off = width_avail % tabs_left; for (it = _titles.begin(); it != _titles.end(); ++it) { if ((*it)->getWidth() >= tab_width) { (*it)->setWidth(tab_width + ((off-- > 0) ? 1 : 0)); } } } /** * This is called when tabs in the decor are using less space than * width min, grow tabs that are smaller than the average. */ void PDecor::calcTabsWidthAsymetricGrow(uint width_avail, uint tab_width) { // FIXME: Implement growing of asymetric tabs. } pekwm-release-0.1.18/src/PDecor.hh000066400000000000000000000414001374756504400166440ustar00rootroot00000000000000// // PDecor.hh for pekwm // Copyright © 2004-2013 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifndef _PDECOR_HH_ #define _PDECOR_HH_ #include "config.h" #include "Config.hh" #include "PWinObj.hh" #include "Theme.hh" // for Theme::FrameData inlines #include "PTexture.hh" // for border/image inlines class ActionEvent; class PFont; class PWinObj; /** * Create window attributes. */ class CreateWindowParams { public: int depth; long mask; XSetWindowAttributes attr; Visual *visual; }; //! @brief PWinObj container class with fancy decor. class PDecor : public PWinObj { public: //! @brief Decor title button class. class Button : public PWinObj { public: Button(PWinObj *parent, Theme::PDecorButtonData *data, uint width, uint height); ~Button(void); ActionEvent *findAction(XButtonEvent *ev); ButtonState getState(void) const { return _state; } void setState(ButtonState state); //! @brief Returns wheter the button is positioned relative the left title edge. inline bool isLeft(void) const { return _left; } private: Theme::PDecorButtonData *_data; ButtonState _state; Pixmap _bg; bool _left; }; //! @brief Decor title item class. class TitleItem { public: //! Info bitmask enum. enum Info { INFO_MARKED = (1 << 1), INFO_ID = (1 << 2) }; TitleItem(void) : _count(0), _id(0), _info(0), _width(0) { } inline const std::wstring &getVisible(void) const { return _visible; } inline const std::wstring &getReal(void) const { return _real; } inline const std::wstring &getCustom(void) const { return _custom; } inline const std::wstring &getUser(void) const { return _user; } inline uint getCount(void) const { return _count; } inline uint getId(void) const { return _id; } inline bool isUserSet(void) const { return (_user.size() > 0); } inline bool isCustom(void) const { return (_custom.size() > 0); } inline uint getWidth(void) const { return _width; } inline void infoAdd(enum Info info) { _info |= info; } inline void infoRemove(enum Info info) { _info &= ~info; } inline bool infoIs(enum Info info) { return (_info&info); } void setReal(const std::wstring &real) { _real = real; if (! isUserSet() && ! isCustom()) { updateVisible(); } } void setCustom(const std::wstring &custom) { _custom = custom; if (_custom.size() > 0 && ! isUserSet()) { updateVisible(); } } void setUser(const std::wstring &user) { _user = user; updateVisible(); } void setCount(uint count) { _count = count; } void setId(uint id) { _id = id; } inline void setWidth(uint width) { _width = width; } void updateVisible(void); private: std::wstring _visible; //!< Visible version of title std::wstring _real; //!< Title from client std::wstring _custom; //!< Custom (title rule) set version of title std::wstring _user; //!< User set version of title uint _count; //!< Number of title uint _id; //!< ID of title uint _info; //!< Info bitmask for extra title info uint _width; }; PDecor(Theme *theme, const std::string &decor_name = DEFAULT_DECOR_NAME, const Window child_window = None); virtual ~PDecor(void); // START - PWinObj interface. virtual void mapWindow(void); virtual void mapWindowRaised(void); virtual void unmapWindow(void); virtual void move(int x, int y); virtual void resize(uint width, uint height); virtual void moveResize(int x, int y, uint width, uint height); virtual void raise(void); virtual void lower(void); virtual void setFocused(bool focused); virtual void setWorkspace(uint workspace); virtual void giveInputFocus(void); virtual ActionEvent *handleButtonPress(XButtonEvent *ev); virtual ActionEvent *handleButtonRelease(XButtonEvent *ev); virtual ActionEvent *handleMotionEvent(XMotionEvent *ev); virtual ActionEvent *handleEnterEvent(XCrossingEvent *ev); virtual ActionEvent *handleLeaveEvent(XCrossingEvent *ev); virtual bool operator == (const Window &window) { if ((_window == window) || (_title_wo == window) || findButton(window) || (getBorderPosition(window) != BORDER_NO_POS) || ((_child) ? (*_child == window) : false)) { return true; } return false; } virtual bool operator != (const Window &window) { return !(*this == window); } // END - PWinObj interface. // START - PDecor interface. virtual bool allowMove(void) const { return true; } virtual void addChild(PWinObj *child, vector::iterator *it = 0); virtual void removeChild(PWinObj *child, bool do_delete = true); virtual void activateChild(PWinObj *child); virtual void updatedChildOrder(void) { } virtual void updatedActiveChild(void) { } virtual bool allowTiling(void) { return ! isSticky(); } virtual void getDecorInfo(wchar_t *buf, uint size); virtual void setShaded(StateAction sa); virtual void setSkip(uint skip); virtual std::string getDecorName(void); // END - PDecor interface. static vector::const_iterator pdecor_begin(void) { return _pdecors.begin(); } static vector::const_iterator pdecor_end(void) { return _pdecors.end(); } inline bool isSkip(uint skip) const { return (_skip&skip); } void addDecor(PDecor *decor); /** * Updates _decor_name to represent decor state * \return true if decor was changed */ bool updateDecor(void); void setDecorOverride(StateAction sa, const std::string &name); void loadDecor(void); //! @brief Returns title Window. inline Window getTitleWindow(void) const { return _title_wo.getWindow(); } PDecor::Button *findButton(Window win); //! @brief Returns height of PDecor ignoring shaded state. inline uint getRealHeight(void) const { return (_shaded ? _real_height : _gm.height); } //! @brief Returns last click x root position. inline int getPointerX(void) const { return _pointer_x; } //! @brief Returns last click y root position. inline int getPointerY(void) const { return _pointer_y; } //! @brief Returns last click x window position. inline int getClickX(void) const { return _click_x; } //! @brief Returns last click y window position. inline int getClickY(void) const { return _click_y; } //! @brief Returns width of child container. inline uint getChildWidth(void) const { if ((borderLeft() + borderRight()) >= _gm.width) { return 1; } return (_gm.width - borderLeft() - borderRight()); } //! @brief Returns height of child container. inline uint getChildHeight(void) const { if ((borderTop() + borderBottom() + getTitleHeight()) >= getRealHeight()) { return 1; } return (getRealHeight() - borderTop() - borderBottom() - getTitleHeight()); } // child list actions //! @brief Returns number of children in PDecor. inline uint size(void) const { return _children.size(); } //! @brief Returns iterator to the first child in PDecor. inline vector::const_iterator begin(void) { return _children.begin(); } //! @brief Returns iterator to the last+1 child in PDecor. inline vector::const_iterator end(void) { return _children.end(); } //! @brief Returns pointer to active PWinObj. inline PWinObj *getActiveChild(void) { return _child; } PWinObj *getChildFromPos(int x); void activateChildNum(uint num); void activateChildRel(int off); // +/- relative from active void moveChildRel(int off); // +/- relative from active // title //! @brief Adds TitleItem to title list. inline void titleAdd(PDecor::TitleItem *ct) { _titles.push_back(ct); } //! @brief Removes all TitleItems from title list. inline void titleClear(void) { _titles.clear(); } //! @brief Sets active TitleItem. void titleSetActive(uint num) { _title_active = (num > _titles.size()) ? 0 : num; } // move and resize relative to the child instead of decor void moveChild(int x, int y); void resizeChild(uint width, uint height); // decor state //! @brief Returns wheter we have a border or not. inline bool hasBorder(void) const { return _border; } //! @brief Returns wheter we have a titlebar or not. inline bool hasTitlebar(void) const { return _titlebar; } //! @brief Returns wheter we are shaded or not. inline bool isShaded(void) const { return _shaded; } void setBorder(StateAction sa); void setTitlebar(StateAction sa); bool demandAttention(void) const { return _attention; } void incrAttention(void) { ++_attention; } void decrAttention(void) { if (_attention && ! --_attention) { updateDecor(); } } // decor element sizes uint getTitleHeight(void) const; // common actions like doMove void doMove(int x_root, int y_root); void doKeyboardMoveResize(void); // Only moveResize if any of the arguments is different than the current geometry. void checkMoveResize(int x, int y, uint width, uint height) { if (x != _gm.x || _gm.y != y || _gm.width != width || _gm.height != height) { moveResize(x, y, width, height); } } bool isFullscreen(void) const { return _fullscreen; } //! @brief Returns border position Window win is at. inline BorderPosition getBorderPosition(Window win) const { for (uint i = 0; i < BORDER_NO_POS; ++i) { if (_border_win[i] == win) { return BorderPosition(i); } } return BORDER_NO_POS; } inline uint borderTop(void) const { return (_border ? _data->getBorderTexture(getFocusedState(false), BORDER_TOP)->getHeight() : 0); } inline uint borderTopLeft(void) const { return (_border ? _data->getBorderTexture(getFocusedState(false), BORDER_TOP_LEFT)->getWidth() : 0); } inline uint borderTopLeftHeight(void) const { return (_border ? _data->getBorderTexture(getFocusedState(false), BORDER_TOP_LEFT)->getHeight() : 0); } inline uint borderTopRight(void) const { return (_border ? _data->getBorderTexture(getFocusedState(false), BORDER_TOP_RIGHT)->getWidth() : 0); } inline uint borderTopRightHeight(void) const { return (_border ? _data->getBorderTexture(getFocusedState(false), BORDER_TOP_RIGHT)->getHeight() : 0); } inline uint borderBottom(void) const { return (_border ? _data->getBorderTexture(getFocusedState(false), BORDER_BOTTOM)->getHeight() : 0); } inline uint borderBottomLeft(void) const { return (_border ? _data->getBorderTexture(getFocusedState(false), BORDER_BOTTOM_LEFT)->getWidth() : 0); } inline uint borderBottomLeftHeight(void) const { return (_border ? _data->getBorderTexture(getFocusedState(false), BORDER_BOTTOM_LEFT)->getHeight() : 0); } inline uint borderBottomRight(void) const { return (_border ? _data->getBorderTexture(getFocusedState(false), BORDER_BOTTOM_RIGHT)->getWidth() : 0); } inline uint borderBottomRightHeight(void) const { return (_border ? _data->getBorderTexture(getFocusedState(false), BORDER_BOTTOM_RIGHT)->getHeight() : 0); } inline uint borderLeft(void) const { return (_border ? _data->getBorderTexture(getFocusedState(false), BORDER_LEFT)->getWidth() : 0); } inline uint borderRight(void) const { return (_border ? _data->getBorderTexture(getFocusedState(false), BORDER_RIGHT)->getWidth() : 0); } void deiconify(void); protected: // START - PDecor interface. virtual void renderTitle(void); virtual void renderButtons(void); virtual void renderBorder(void); virtual void setBorderShape(void); // shapes border corners virtual void loadTheme(void) { } // called after loadDecor, render child virtual int resizeHorzStep(int diff) const { return diff; } virtual int resizeVertStep(int diff) const { return diff; } // END - PDecor interface. #ifdef HAVE_SHAPE void applyBorderShape(int kind=ShapeBounding); #else void applyBorderShape(int kind=0) {} #endif // HAVE_SHAPE void resizeTitle(void); //! @brief Returns font used at FocusedState state. inline PFont *getFont(FocusedState state) const { return _data->getFont(state); } uint getNearestHead(void); void checkSnap(void); void checkWOSnap(void); void checkEdgeSnap(void); void alignChild(PWinObj *child); void drawOutline(const Geometry &gm); inline FocusedState getFocusedState(bool selected) const { if (selected) { return (_focused) ? FOCUSED_STATE_FOCUSED_SELECTED : FOCUSED_STATE_UNFOCUSED_SELECTED; } else { return (_focused) ? FOCUSED_STATE_FOCUSED : FOCUSED_STATE_UNFOCUSED; } } private: void createParentWindow(CreateWindowParams ¶ms, Window child_window); void createTitle(CreateWindowParams ¶ms); void createBorder(CreateWindowParams ¶ms); void unloadDecor(void); ActionEvent *handleButtonPressButton(XButtonEvent *ev, PDecor::Button *button); ActionEvent *handleButtonPressBorder(XButtonEvent *ev); ActionEvent *handleButtonReleaseButton(XButtonEvent *ev, PDecor::Button *button); ActionEvent *handleButtonReleaseBorder(XButtonEvent *ev); EdgeType doMoveEdgeFind(int x, int y); void doMoveEdgeAction(XMotionEvent *ev, EdgeType edge); void placeButtons(void); void placeBorder(void); void shapeBorder(void); void restackBorder(void); // shaded, borderless, no border visible void getBorderSize(BorderPosition pos, uint &width, uint &height); uint calcTitleWidth(void); void calcTabsWidth(void); void calcTabsGetAvailAndTabWidth(uint &width_avail, uint &tab_width, int &off); void calcTabsWidthSymetric(void); void calcTabsWidthAsymetric(void); void calcTabsWidthAsymetricGrow(uint width_avail, uint tab_width); void calcTabsWidthAsymetricShrink(uint width_avail, uint tab_width); protected: Theme *_theme; //!< Pointer to Theme used by PDecor. std::string _decor_name; //!< Name of the active decoration std::string _decor_name_saved; //!< Original decor name if it is temp. overridden PWinObj *_child; //!< Pointer to active child in PDecor. vector _children; //!< List of children in PDecor. PDecor::Button *_button; /**< Active title button in PDecor. */ Window _button_press_win; /**< Active border window, for button release handling. */ // used for treshold calculation int _pointer_x; //!< Last click x root position. int _pointer_y; //!< Last click y root position. int _click_x; //!< Last click x window position. int _click_y; //!< Last click y window position. // how the decor should behave bool _decor_cfg_child_move_overloaded; //!< Boolean to set wheter ::move is overloaded. // button{press,release} handling cfg bool _decor_cfg_bpr_replay_pointer; //!< Boolean to configure wheter to call XReplayPointer on clicks. MouseActionListName _decor_cfg_bpr_al_child; //!< What list to search for child actions. MouseActionListName _decor_cfg_bpr_al_title; //!< What list to search for title actions. static const std::string DEFAULT_DECOR_NAME; //!< Default decor name in normal state. static const std::string DEFAULT_DECOR_NAME_BORDERLESS; //!< Default decor name in borderless state. static const std::string DEFAULT_DECOR_NAME_TITLEBARLESS; //!< Default decor name in titlebarless state. static const std::string DEFAULT_DECOR_NAME_ATTENTION; //!< Default decor name for demands attention state. static const std::string DEFAULT_DECOR_NAME_TILING; //!< Default decor name for tiling workspaces. // state switches, commonly not used by all decors bool _maximized_vert; bool _maximized_horz; bool _fullscreen; uint _skip; Window _border_win[BORDER_NO_POS]; /** Array of border windows. */ private: Theme::PDecorData *_data; // decor state bool _border, _titlebar, _shaded; uint _attention; // Number of children that demand attention bool _need_shape; uint _real_height; PWinObj _title_wo; vector _buttons; // variable decor data uint _title_active; vector _titles; uint _titles_left, _titles_right; // area where to put titles static vector _pdecors; /**< List of all PDecors */ }; #endif // _PDECOR_HH_ pekwm-release-0.1.18/src/PFont.cc000066400000000000000000000370011374756504400165060ustar00rootroot00000000000000// // PFont.cc for pekwm // Copyright © 2003-2009 Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "config.h" #include #include #include "PFont.hh" #include "x11.hh" #include "Util.hh" using std::cerr; using std::endl; using std::string; using std::vector; using std::wstring; wstring PFont::_trim_string = wstring(); const char *FALLBACK_FONT = "fixed"; // PFont //! @brief PFont constructor PFont::PFont(void) : _height(0), _ascent(0), _descent(0), _offset_x(0), _offset_y(0), _justify(FONT_JUSTIFY_LEFT) { } //! @brief PFont destructor PFont::~PFont(void) { unload(); } //! @brief Draws the text on the drawable. //! @param dest destination Drawable //! @param x x start position //! @param y y start position //! @param text text to draw //! @param max_chars max nr of chars, defaults to 0 == strlen(text) //! @param max_width max nr of pixels, defaults to 0 == infinity //! @param trim_type how to trim title if not enough space, defaults to FONT_TRIM_END void PFont::draw(Drawable dest, int x, int y, const std::wstring &text, uint max_chars, uint max_width, PFont::TrimType trim_type) { if (! text.size()) { return; } uint offset = x, chars = max_chars; wstring real_text(text); if (max_width > 0) { // If max width set, make sure text fits in max_width pixels. trim(real_text, trim_type, max_width); offset += justify(real_text, max_width, 0, (chars == 0) ? real_text.size() : chars); } else if (chars == 0) { // Just set to complete string. chars = real_text.size(); } // Draw shadowed font if x or y offset is specified if (_offset_x || _offset_y) { drawText(dest, offset + _offset_x, y + _ascent + _offset_y, real_text, chars, false); // false as in bg } // Draw main font drawText(dest, offset, y + _ascent, real_text, chars, true); // true as in fg } //! @brief Trims the text making it max max_width wide //! @param text //! @param trim_type //! @param max_width //! @param chars void PFont::trim(std::wstring &text, PFont::TrimType trim_type, uint max_width) { if (getWidth(text) > max_width) { if ((_trim_string.size() > 0) && (trim_type == FONT_TRIM_MIDDLE)) { // Trim middle before end if trim string is set. trimMiddle(text, max_width); } trimEnd(text, max_width); } } //! @brief Figures how many charachters to have before exceding max_width void PFont::trimEnd(std::wstring &text, uint max_width) { for (uint i = text.size(); i > 0; --i) { if (getWidth(text, i) <= max_width) { text = text.substr(0, i); break; } } } //! @brief Replace middle of string with _trim_string making it max_width wide void PFont::trimMiddle(std::wstring &text, uint max_width) { // Get max and separator width uint max_side = (max_width / 2); uint sep_width = getWidth(_trim_string.c_str(), _trim_string.size() / 2 + _trim_string.size() % 2); uint pos = 0; wstring dest; // If the trim string is too large, do nothing and let trimEnd handle this. if (max_side <= sep_width) { return; } // Add space for the trim string max_side -= sep_width; // Get numbers of chars before trim string (..) for (uint i = text.size(); i > 0; --i) { if (getWidth(text, i) < max_side) { pos = i; dest.insert(0, text.substr(0, i)); break; } } // get numbers of chars after ... if (pos < text.size()) { for (uint i = pos; i < text.size(); ++i) { wstring second_part(text.substr(i, text.size() - i)); if (getWidth(second_part, 0) < max_side) { dest.insert(dest.size(), second_part); break; } } // Got a char after and before, if not do nothing and trimEnd will handle // trimming after this call. if (dest.size() > 1) { if ((getWidth(dest) + getWidth(_trim_string)) < max_width) { dest.insert(pos, _trim_string); } // Update original string text = dest; } } } void PFont::setTrimString(const std::string &text) { _trim_string = Util::to_wide_str(text); } //! @brief Justifies the string based on _justify property of the Font uint PFont::justify(const std::wstring &text, uint max_width, uint padding, uint chars) { uint x; uint width = getWidth(text, chars); switch(_justify) { case FONT_JUSTIFY_CENTER: x = (max_width - width) / 2; break; case FONT_JUSTIFY_RIGHT: x = max_width - width - padding; break; default: x = padding; break; } return x; } // PFontX11 //! @brief PFontX11 constructor PFontX11::PFontX11(void) : PFont(), _font(0), _gc_fg(None), _gc_bg(None) { } //! @brief PFontX11 destructor PFontX11::~PFontX11(void) { unload(); } //! @brief Loads the X11 font font_name bool PFontX11::load(const std::string &font_name) { unload(); _font = XLoadQueryFont(X11::getDpy(), font_name.c_str()); if (! _font) { _font = XLoadQueryFont(X11::getDpy(), FALLBACK_FONT); if (! _font) { return false; } } _height = _font->ascent + _font->descent; _ascent = _font->ascent; _descent = _font->descent; // create GC's XGCValues gv; uint mask = GCFunction|GCFont; gv.function = GXcopy; gv.font = _font->fid; _gc_fg = XCreateGC(X11::getDpy(), X11::getRoot(), mask, &gv); _gc_bg = XCreateGC(X11::getDpy(), X11::getRoot(), mask, &gv); return true; } //! @brief Unloads font resources void PFontX11::unload(void) { if (_font) { XFreeFont(X11::getDpy(), _font); _font = 0; } if (_gc_fg != None) { XFreeGC(X11::getDpy(), _gc_fg); _gc_fg = None; } if (_gc_bg != None) { XFreeGC(X11::getDpy(), _gc_bg); _gc_bg = None; } } //! @brief Gets the width the text would take using this font uint PFontX11::getWidth(const wstring &text, uint max_chars) { if (! text.size()) { return 0; } // Make sure the max_chars has a decent value, if it's less than 1 wich it // defaults to set it to the numbers of chars in the string text if (! max_chars || (max_chars > text.size())) { max_chars = text.size(); } uint width = 0; if (_font) { // No UTF8 support, convert to locale encoding. string mb_text(Util::to_mb_str(text.substr(0, max_chars))); width = XTextWidth(_font, mb_text.c_str(), mb_text.size()); } return (width + _offset_x); } //! @brief Draws the text on dest //! @param dest Drawable to draw on //! @param chars Max numbers of characthers to print //! @param fg Bool, to use foreground or background colors void PFontX11::drawText(Drawable dest, int x, int y, const std::wstring &text, uint chars, bool fg) { GC gc = fg ? _gc_fg : _gc_bg; if (_font && (gc != None)) { string mb_text; if (chars != 0) { mb_text = Util::to_mb_str(text.substr(0, chars)); } else { mb_text = Util::to_mb_str(text); } XDrawString(X11::getDpy(), dest, gc, x, y, mb_text.c_str(), mb_text.size()); } } //! @brief Sets the color that should be used when drawing void PFontX11::setColor(PFont::Color *color) { if (color->hasFg()) { XSetForeground(X11::getDpy(), _gc_fg, color->getFg()->pixel); } if (color->hasBg()) { XSetForeground(X11::getDpy(), _gc_bg, color->getBg()->pixel); } } // PFontXmb const char* PFontXmb::DEFAULT_FONTSET = "fixed*"; //! @brief PFontXmb constructor PFontXmb::PFontXmb(void) : PFont(), _fontset(0), _gc_fg(None), _gc_bg(None) { } //! @brief PFontXmb destructor PFontXmb::~PFontXmb(void) { unload(); } //! @brief Loads Xmb font font_name bool PFontXmb::load(const std::string &font_name) { unload(); string basename(font_name); size_t pos = font_name.rfind(",*"); if (pos == string::npos || pos != (font_name.size() - 2)) { basename.append(",*"); } // Create GC XGCValues gv; uint mask = GCFunction; gv.function = GXcopy; _gc_fg = XCreateGC(X11::getDpy(), X11::getRoot(), mask, &gv); _gc_bg = XCreateGC(X11::getDpy(), X11::getRoot(), mask, &gv); // Try to load font char *def_string; char **missing_list, **font_names; int missing_count; _fontset = XCreateFontSet(X11::getDpy(), basename.c_str(), &missing_list, &missing_count, &def_string); if (! _fontset) { cerr << "PFontXmb::load(): Failed to create fontset for " << font_name << endl; _fontset = XCreateFontSet(X11::getDpy(), DEFAULT_FONTSET, &missing_list, &missing_count, &def_string); } if (_fontset) { for (int i = 0; i < missing_count; ++i) { cerr << "PFontXmb::load(): Missing charset" << missing_list[i] << endl; } XFreeStringList(missing_list); _ascent = _descent = 0; XFontStruct **fonts; int fnum = XFontsOfFontSet (_fontset, &fonts, &font_names); for (int i = 0; i < fnum; ++i) { if (signed(_ascent) < fonts[i]->ascent) { _ascent = fonts[i]->ascent; } if (signed(_descent) < fonts[i]->descent) { _descent = fonts[i]->descent; } } _height = _ascent + _descent; } else { return false; } return true; } //! @brief Unloads font resources void PFontXmb::unload(void) { if (_fontset) { XFreeFontSet(X11::getDpy(), _fontset); _fontset = 0; } if (_gc_fg != None) { XFreeGC(X11::getDpy(), _gc_fg); _gc_fg = None; } if (_gc_bg != None) { XFreeGC(X11::getDpy(), _gc_bg); _gc_bg = None; } } //! @brief Gets the width the text would take using this font uint PFontXmb::getWidth(const std::wstring &text, uint max_chars) { if (! text.size()) { return 0; } // Make sure the max_chars has a decent value, if it's less than 1 wich it // defaults to set it to the numbers of chars in the string text if (! max_chars || (max_chars > text.size())) { max_chars = text.size(); } uint width = 0; if (_fontset) { XRectangle ink, logical; XwcTextExtents(_fontset, text.c_str(), max_chars, &ink, &logical); width = logical.width; } return (width + _offset_x); } //! @brief Draws the text on dest //! @param dest Drawable to draw on //! @param chars Max numbers of characthers to print //! @param fg Bool, to use foreground or background colors void PFontXmb::drawText(Drawable dest, int x, int y, const std::wstring &text, uint chars, bool fg) { GC gc = fg ? _gc_fg : _gc_bg; if (_fontset && (gc != None)) { XwcDrawString(X11::getDpy(), dest, _fontset, gc, x, y, text.c_str(), chars ? chars : text.size()); } } //! @brief Sets the color that should be used when drawing void PFontXmb::setColor(PFont::Color *color) { if (color->hasFg()) { XSetForeground(X11::getDpy(), _gc_fg, color->getFg()->pixel); } if (color->hasBg()) { XSetForeground(X11::getDpy(), _gc_bg, color->getBg()->pixel); } } // PFontXft #ifdef HAVE_XFT //! @brief PFontXft constructor PFontXft::PFontXft(void) : PFont(), _draw(0), _font(0), _cl_fg(0), _cl_bg(0) { _draw = XftDrawCreate(X11::getDpy(), X11::getRoot(), X11::getVisual(), X11::getColormap()); } //! @brief PFontXft destructor PFontXft::~PFontXft(void) { unload(); XftDrawDestroy(_draw); if (_cl_fg) { XftColorFree(X11::getDpy(), X11::getVisual(), X11::getColormap(), _cl_fg); delete _cl_fg; } if (_cl_bg) { XftColorFree(X11::getDpy(), X11::getVisual(), X11::getColormap(), _cl_bg); delete _cl_bg; } } //! @brief Loads the Xft font font_name bool PFontXft::load(const std::string &font_name) { unload(); _font = XftFontOpenName(X11::getDpy(), X11::getScreenNum(), font_name.c_str()); if (! _font) { _font = XftFontOpenXlfd(X11::getDpy(), X11::getScreenNum(), font_name.c_str()); } if (_font) { _ascent = _font->ascent; _descent = _font->descent; _height = _font->height; return true; } return false; } //! @brief Unloads font resources void PFontXft::unload(void) { if (_font) { XftFontClose(X11::getDpy(), _font); _font = 0; } } //! @brief Gets the width the text would take using this font uint PFontXft::getWidth(const std::wstring &text, uint max_chars) { if (! text.size()) { return 0; } // Make sure the max_chars has a decent value, if it's less than 1 wich it // defaults to set it to the numbers of chars in the string text if (! max_chars || (max_chars > text.size())) { max_chars = text.size(); } uint width = 0; if (_font) { string utf8_text(Util::to_utf8_str(text.substr(0, max_chars))); XGlyphInfo extents; XftTextExtentsUtf8(X11::getDpy(), _font, reinterpret_cast(utf8_text.c_str()), utf8_text.size(), &extents); width = extents.xOff; } return (width + _offset_x); } //! @brief Draws the text on dest //! @param dest Drawable to draw on //! @param chars Max numbers of characthers to print //! @param fg Bool, to use foreground or background colors void PFontXft::drawText(Drawable dest, int x, int y, const std::wstring &text, uint chars, bool fg) { XftColor *cl = fg ? _cl_fg : _cl_bg; if (_font && cl) { string utf8_text; if (chars != 0) { utf8_text = Util::to_utf8_str(text.substr(0, chars)); } else { utf8_text = Util::to_utf8_str(text); } XftDrawChange(_draw, dest); XftDrawStringUtf8(_draw, cl, _font, x, y, reinterpret_cast(utf8_text.c_str()), utf8_text.size()); } } //! @brief Sets the color that should be used when drawing void PFontXft::setColor(PFont::Color *color) { if (_cl_fg) { XftColorFree(X11::getDpy(), X11::getVisual(), X11::getColormap(), _cl_fg); delete _cl_fg; _cl_fg = 0; } if (_cl_bg) { XftColorFree(X11::getDpy(), X11::getVisual(), X11::getColormap(), _cl_bg); delete _cl_bg; _cl_bg = 0; } if (color->hasFg()) { _xrender_color.red = color->getFg()->red; _xrender_color.green = color->getFg()->green; _xrender_color.blue = color->getFg()->blue; _xrender_color.alpha = color->getFgAlpha(); _cl_fg = new XftColor; XftColorAllocValue(X11::getDpy(), X11::getVisual(), X11::getColormap(), &_xrender_color, _cl_fg); } if (color->hasBg()) { _xrender_color.red = color->getBg()->red; _xrender_color.green = color->getBg()->green; _xrender_color.blue = color->getBg()->blue; _xrender_color.alpha = color->getBgAlpha(); _cl_bg = new XftColor; XftColorAllocValue(X11::getDpy(), X11::getVisual(), X11::getColormap(), &_xrender_color, _cl_bg); } } #endif // HAVE_XFT pekwm-release-0.1.18/src/PFont.hh000066400000000000000000000111361374756504400165210ustar00rootroot00000000000000// // PFont.hh for pekwm // Copyright © 2003-2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifndef _PFONT_HH_ #define _PFONT_HH_ #include "config.h" #include #ifdef HAVE_LIMITS #include #endif // HAVE_LIMITS #include "pekwm.hh" extern "C" { #ifdef HAVE_XFT #include #endif // HAVE_XFT } class PFont { public: enum Type { FONT_TYPE_X11, FONT_TYPE_XFT, FONT_TYPE_XMB, FONT_TYPE_NO }; enum TrimType { FONT_TRIM_END, FONT_TRIM_MIDDLE }; class Color { public: Color(void) : _has_fg(false), _has_bg(false), _fg_alpha(65535), _bg_alpha(65535) { } ~Color(void) { } inline XColor *getFg(void) { return _fg; } inline XColor *getBg(void) { return _bg; } inline void setFg(XColor *xc) { _fg = xc; } inline void setBg(XColor *xc) { _bg = xc; } inline uint getFgAlpha(void) const { return _fg_alpha; } inline uint getBgAlpha(void) const { return _bg_alpha; } inline void setFgAlpha(uint alpha) { _fg_alpha = alpha; } inline void setBgAlpha(uint alpha) { _bg_alpha = alpha; } inline bool hasFg(void) const { return _has_fg; } inline bool hasBg(void) const { return _has_bg; } inline void setHasFg(bool f) { _has_fg = f; } inline void setHasBg(bool b) { _has_bg = b; } private: XColor *_fg, *_bg; bool _has_fg, _has_bg; uint _fg_alpha, _bg_alpha; }; PFont(void); virtual ~PFont(void); inline uint getJustify(void) const { return _justify; } inline void setJustify(uint j) { _justify = j; } inline void setOffset(uint x, uint y) { _offset_x = x; _offset_y = y; } void draw(Drawable dest, int x, int y, const std::wstring &text, uint max_chars = 0, uint max_width = 0, PFont::TrimType trim_type = FONT_TRIM_END); void trim(std::wstring &text, TrimType trim_type, uint max_width); void trimEnd(std::wstring &text, uint max_width); void trimMiddle(std::wstring &text, uint max_width); static void setTrimString(const std::string &trim); uint justify(const std::wstring &text, uint max_width, uint padding, uint chars); // virtual interface virtual bool load(const std::string &font_name) { return true; } virtual void unload(void) { } virtual uint getWidth(const std::wstring &text, uint max_chars = 0) { return 0; } virtual uint getHeight(void) { return _height; } virtual void setColor(PFont::Color *color) { } private: virtual void drawText(Drawable dest, int x, int y, const std::wstring &text, uint chars, bool fg) { } protected: uint _height, _ascent, _descent; uint _offset_x, _offset_y, _justify; static std::wstring _trim_string; }; class PFontX11 : public PFont { public: PFontX11(void); virtual ~PFontX11(void); // virtual interface virtual bool load(const std::string &name); virtual void unload(void); virtual uint getWidth(const std::wstring &text, uint max_chars = 0); virtual void setColor(PFont::Color *color); private: virtual void drawText(Drawable dest, int x, int y, const std::wstring &text, uint chars, bool fg); private: XFontStruct *_font; GC _gc_fg, _gc_bg; }; class PFontXmb : public PFont { public: PFontXmb(void); virtual ~PFontXmb(void); // virtual interface virtual bool load(const std::string &name); virtual void unload(void); virtual uint getWidth(const std::wstring &text, uint max_chars = 0); virtual void setColor(PFont::Color *color); private: virtual void drawText(Drawable dest, int x, int y, const std::wstring &text, uint chars, bool fg); XFontSet _fontset; GC _gc_fg, _gc_bg; static const char *DEFAULT_FONTSET; /**< Default fallback fontset. */ }; #ifdef HAVE_XFT class PFontXft : public PFont { public: PFontXft(void); virtual ~PFontXft(void); // virtual interface virtual bool load(const std::string &font_name); virtual void unload(void); virtual uint getWidth(const std::wstring &text, uint max_chars = 0); virtual void setColor(PFont::Color *color); private: virtual void drawText(Drawable dest, int x, int y, const std::wstring &text, uint chars, bool fg); XftDraw *_draw; XftFont *_font; XftColor *_cl_fg, *_cl_bg; XRenderColor _xrender_color; }; #endif // HAVE_XFT #endif // _PFONT_HH_ pekwm-release-0.1.18/src/PImage.cc000066400000000000000000000347521374756504400166340ustar00rootroot00000000000000// // PImage.cc for pekwm // Copyright © 2005-2015 the pekwm development team // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "config.h" #include "PImage.hh" #include "x11.hh" #include "Util.hh" #include extern "C" { #include } using std::cerr; using std::endl; using std::string; vector PImage::_loaders; /** * PImage constructor, loads image if one is specified. * * @param dpy Display image is valid on. * @param path Path to image file, if specified this is loaded. */ PImage::PImage(const std::string &path) : _type(IMAGE_TYPE_NO), _pixmap(None), _mask(None), _width(0), _height(0), _data(0), _has_alpha(false), _use_alpha(false) { if (path.size()) { if (! load(path)) { throw LoadException(path.c_str()); } } } //! @brief PImage destructor. PImage::~PImage(void) { unload(); } //! @brief Loads image from file. //! @param file File to load. //! @return Returns true on success, else false. bool PImage::load(const std::string &file) { string ext(Util::getFileExt(file)); if (! ext.size()) { cerr << " *** WARNING: no file extension on " << file << "!" << endl; return false; } vector::const_iterator it(_loaders.begin()); for (; it != _loaders.end(); ++it) { if (! strcasecmp((*it)->getExt(), ext.c_str())) { _data = (*it)->load(file, _width, _height, _has_alpha, _use_alpha); if (_data) { _pixmap = createPixmap(_data, _width, _height); _mask = createMask(_data, _width, _height); break; } } } return (_data); } //! @brief Frees resources used by image. void PImage::unload(void) { if (_data) { delete [] _data; _data = 0; } if (_pixmap) { X11::freePixmap(_pixmap); } if (_mask) { X11::freePixmap(_mask); } _pixmap = None; _mask = None; _width = 0; _height = 0; } //! @brief Draws image on drawable. //! @param draw Drawable to draw on. //! @param x Destination x coordinate. //! @param y Destination y coordinate. //! @param width Destination width, defaults to 0 which expands to image size. //! @param height Destination height, defaults to 0 which expands to image size. void PImage::draw(Drawable draw, int x, int y, uint width, uint height) { if (! _data) { return; } // Expand variables. if (! width) { width = _width; } if (! height) { height = _height; } // Draw image, select correct drawing method depending on image type, // size and if alpha exists. if ((_type == IMAGE_TYPE_FIXED) || ((_type == IMAGE_TYPE_SCALED) && (_width == width) && (_height == height))) { if (_use_alpha) { drawAlphaFixed(draw, x, y, width, height); } else { drawFixed(draw, x, y, width, height); } } else if (_type == IMAGE_TYPE_SCALED) { if (_use_alpha) { drawAlphaScaled(draw, x, y, width, height); } else { drawScaled(draw, x, y, width, height); } } else if (_type == IMAGE_TYPE_TILED) { if (_use_alpha) { drawAlphaTiled(draw, x, y, width, height); } else { drawTiled(draw, x, y, width, height); } } } //! @brief Returns pixmap at sizen. //! @param need_free Is set to wheter shape mask returned needs to be freed. //! @param width Pixmap width, defaults to 0 which expands to image size. //! @param height Pixmap height, defaults to 0 which expands to image size. //! @return Returns pixmap at size or None on error. Pixmap PImage::getPixmap(bool &need_free, uint width, uint height) { // Default Pixmap pix = None; need_free = false; // Expand parameters. if (! width) { width = _width; } if (! height) { height = _height; } // Same size, return _pixmap. if ((width == _width) && (height == _height)) { pix = _pixmap; } else { uchar *scaled_data; scaled_data = getScaledData(width, height); if (scaled_data) { need_free = true; pix = createPixmap(scaled_data, width, height); delete [] scaled_data; } } return pix; } //! @brief Returns shape mask at size, if any. //! @param need_free Is set to wheter shape mask returned needs to be freed. //! @param width Shape mask width, defaults to 0 which expands to image size. //! @param height Shape mask height, defaults to 0 which expands to image size. //! @return Returns shape mask at size or None if there is no mask information. Pixmap PImage::getMask(bool &need_free, uint width, uint height) { Pixmap pix = None; need_free = false; if (! _has_alpha || ! _use_alpha) { return None; } // Expand parameters. if (! width) { width = _width; } if (! height) { height = _height; } // Same size, return _mask. if ((width == _width) && (height == _height)) { pix = _mask; } else { uchar *scaled_data; scaled_data = getScaledData(width, height); if (scaled_data) { need_free = true; pix = createMask(scaled_data, width, height); delete [] scaled_data; } } return pix; } //! @brief Scales image to size. //! @param width Width to scale image to. //! @param height Height to scale image to. void PImage::scale(uint width, uint height) { // Invalid width or height or no need to scale. if (! width || ! height || ((width == _width) && (height == _height))) { return; } uchar *scaled_data; scaled_data = getScaledData(width, height); if (scaled_data) { // Free old resources. unload(); // Set data pointer and create pixmap and mask at new size. _data = scaled_data; _pixmap = createPixmap(_data, width, height); _mask = createMask(_data, width, height); _width = width; _height = height; } } //! @brief Draw image at position, not scaling. void PImage::drawFixed(Drawable dest, int x, int y, uint width, uint height) { // Plain copy of the pixmap onto Drawable. XCopyArea(X11::getDpy(), _pixmap, dest, X11::getGC(), 0, 0, width, height, x, y); } //! @brief Draw image scaled to fit width and height. void PImage::drawScaled(Drawable dest, int x, int y, uint width, uint height) { uchar *scaled_data; // Create scaled representation of image. scaled_data = getScaledData(width, height); if (scaled_data) { Pixmap pix; // Create pixmap. pix = createPixmap(scaled_data, width, height); if (pix) { XCopyArea(X11::getDpy(), pix, dest, X11::getGC(), 0, 0, width, height, x, y); X11::freePixmap(pix); } delete [] scaled_data; } } //! @brief Draw image tiled to fit width and height. void PImage::drawTiled(Drawable dest, int x, int y, uint width, uint height) { // Create a GC with _pixmap as tile and tiled fill style. GC gc; XGCValues gv; gv.fill_style = FillTiled; gv.tile = _pixmap; gv.ts_x_origin = x; gv.ts_y_origin = y; gc = XCreateGC(X11::getDpy(), dest, GCFillStyle|GCTile|GCTileStipXOrigin|GCTileStipYOrigin, &gv); // Tile the image onto drawable. XFillRectangle(X11::getDpy(), dest, gc, x, y, width, height); XFreeGC(X11::getDpy(), gc); } //! @brief Draw image at position, not scaling. void PImage::drawAlphaFixed(Drawable dest, int x, int y, uint width, uint height, uchar *data) { XImage *dest_image = XGetImage(X11::getDpy(), dest, x, y, width, height, AllPlanes, ZPixmap); if (! dest_image) { cerr << " *** ERROR: failed to get image for destination." << endl; return; } // Get mask from visual Visual *visual = X11::getVisual(); dest_image->red_mask = visual->red_mask; dest_image->green_mask = visual->green_mask; dest_image->blue_mask = visual->blue_mask; uchar *src; uchar r, g, b, a; uchar d_r = 0, d_g = 0, d_b = 0; float a_percent, a_percent_inv; if (data) { src = data; } else { src = _data; width = std::min(width, _width); height = std::min(height, _height); } for (uint i_y = 0; i_y < height; ++i_y) { for (uint i_x = 0; i_x < width; ++i_x) { // Get pixel value, copy them directly if alpha is set to 255. r = *src++; g = *src++; b = *src++; a = *src++; // Alpha not 100% solid, blend if (a != 255) { // Get RGB values from pixel. getRgbFromPixel(dest_image, XGetPixel(dest_image, i_x, i_y), d_r, d_g, d_b); a_percent = static_cast(a) / 255; a_percent_inv = 1 - a_percent; r = static_cast((a_percent_inv * d_r) + (a_percent * r)); g = static_cast((a_percent_inv * d_g) + (a_percent * g)); b = static_cast((a_percent_inv * d_b) + (a_percent * b)); } XPutPixel(dest_image, i_x, i_y, getPixelFromRgb(dest_image, r, g, b)); } } XPutImage(X11::getDpy(), dest, X11::getGC(), dest_image, 0, 0, x, y, width, height); XDestroyImage(dest_image); } //! @brief Draw image scaled to fit width and height. void PImage::drawAlphaScaled(Drawable dest, int x, int y, uint width, uint height) { uchar *scaled_data = getScaledData(width, height); if (scaled_data) { drawAlphaFixed(dest, x, y, width, height, scaled_data); delete [] scaled_data; } } //! @brief Draw image tiled to fit width and height. void PImage::drawAlphaTiled(Drawable dest, int x, int y, uint width, uint height) { // FIXME: Implement tiled rendering with alpha support drawTiled(dest, x, y, width, height); } //! @brief Creates Pixmap from data. //! @param data Pointer to data to create pixmap from. //! @param width Width of image data is representing. //! @param height Height of image data is representing. //! @return Returns Pixmap on success, else None. Pixmap PImage::createPixmap(uchar *data, uint width, uint height) { XImage *ximage; Pixmap pix = None; ximage = createXImage(data, width, height); if (ximage) { pix = X11::createPixmap(width, height); XPutImage(X11::getDpy(), pix, X11::getGC(), ximage, 0, 0, 0, 0, width, height); delete [] ximage->data; ximage->data = 0; XDestroyImage(ximage); } return pix; } //! @brief Creates shape mask Pixmap from data. //! @param data Pointer to data to create mask from. //! @param width Width of image data is representing. //! @param height Height of image data is representing. //! @return Returns Pixmap mask on success, else None. Pixmap PImage::createMask(uchar *data, uint width, uint height) { if (! _has_alpha || ! _use_alpha) { return None; } // Create XImage XImage *ximage; ximage = XCreateImage(X11::getDpy(), X11::getVisual(), 1, ZPixmap, 0, 0, width, height, 32, 0); if (! ximage) { cerr << " *** WARNING: unable to create XImage!" << endl; return None; } // Alocate ximage data storage. ximage->data = new char[ximage->bytes_per_line * height / sizeof(char)]; uchar *src = data + 3; // Skip R, G and B. ulong pixel_trans, pixel_solid; pixel_trans = X11::getBlackPixel(); pixel_solid = X11::getWhitePixel(); for (uint y = 0; y < height; ++y) { for (uint x = 0; x < width; ++x) { XPutPixel(ximage, x, y, (*src > 127) ? pixel_solid : pixel_trans); src += 4; // Skip R, G, B and A } } Pixmap pix{X11::createPixmapMask(width, height)}; GC gc = XCreateGC(X11::getDpy(), pix, 0, 0); XPutImage(X11::getDpy(), pix, gc, ximage, 0, 0, 0, 0, width, height); XFreeGC(X11::getDpy(), gc); delete [] ximage->data; ximage->data = 0; XDestroyImage(ximage); return pix; } //! @brief Createx XImage from data. //! @param data Pointer to data to create XImage from. //! @param width Width of image data is representing. //! @param height Height of image data is representing. XImage* PImage::createXImage(uchar *data, uint width, uint height) { // Create XImage XImage *ximage; ximage = XCreateImage(X11::getDpy(), X11::getVisual(), X11::getDepth(), ZPixmap, 0, 0, width, height, 32, 0); if (! ximage) { cerr << " *** WARNING: unable to create XImage!" << endl; return 0; } // Allocate ximage data storage. ximage->data = new char[ximage->bytes_per_line * height / sizeof(char)]; uchar *src = data; uchar r, g, b; // Put data into XImage. for (uint y = 0; y < height; ++y) { for (uint x = 0; x < width; ++x) { r = *src++; g = *src++; b = *src++; if (_has_alpha) { src++; } XPutPixel(ximage, x, y, getPixelFromRgb(ximage, r, g, b)); } } return ximage; } //! @brief Scales image data and returns pointer to new data. //! @param width Width of image data to return. //! @param height Height of image data to return. //! @return Pointer to image data on success, else 0. //! @todo Implement decent scaling routine with data [] cache? uchar* PImage::getScaledData(uint width, uint height) { if (! width || ! height) { return 0; } // Calculate aspect ratio. float ratio_x, ratio_y; ratio_x = static_cast(_width) / static_cast(width); ratio_y = static_cast(_height) / static_cast(height); // Allocate memory. uchar *scaled_data, *dest; scaled_data = new uchar[width * height * (_has_alpha ? 4 : 3)]; dest = scaled_data; // Scale image. int i_src; float f_src; for (uint y = 0; y < height; ++y) { f_src = static_cast(ratio_y * y) * _width; for (uint x = 0; x < width; ++x) { i_src = static_cast(f_src); i_src *= (_has_alpha ? 4 : 3); *dest++ = _data[i_src++]; *dest++ = _data[i_src++]; *dest++ = _data[i_src++]; if (_has_alpha) { *dest++ = _data[i_src++]; } f_src += ratio_x; } } return scaled_data; } pekwm-release-0.1.18/src/PImage.hh000066400000000000000000000121151374756504400166330ustar00rootroot00000000000000// // PImage.hh for pekwm // Copyright © 2004-2009 Claes Nasten // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifndef _PIMAGE_HH_ #define _PIMAGE_HH_ #include "config.h" #include "pekwm.hh" #include "PImageLoader.hh" #include //! @brief Image baseclass defining interface for image handling. class PImage { public: //! @brief PImage constructor. PImage(const std::string &path=""); //! @brief PImage destructor. virtual ~PImage(void); //! @brief Add loader to loader list. static void loaderAdd(PImageLoader *loader) { _loaders.push_back(loader); } //! @brief Removes and frees all loaders. static void loaderClear(void) { while (_loaders.size()) { delete _loaders.back(); _loaders.pop_back(); } } //! @brief Returns type of image. inline ImageType getType(void) const { return _type; } //! @brief Sets type of image. inline void setType(ImageType type) { _type = type; } //! @brief Returns width of image. inline uint getWidth(void) const { return _width; } //! @brief Returns height of image. inline uint getHeight(void) const { return _height; } virtual bool load(const std::string &file); virtual void unload(void); virtual void draw(Drawable dest, int x, int y, uint width = 0, uint height = 0); virtual Pixmap getPixmap(bool &need_free, uint width = 0, uint height = 0); virtual Pixmap getMask(bool &need_free, uint width = 0, uint height = 0); virtual void scale(uint width, uint height); protected: void drawFixed(Drawable dest, int x, int y, uint width, uint height); void drawScaled(Drawable dest, int x, int y, uint widht, uint height); void drawTiled(Drawable dest, int x, int y, uint widht, uint height); void drawAlphaFixed(Drawable dest, int x, int y, uint widht, uint height, uchar *data = 0); void drawAlphaScaled(Drawable dest, int x, int y, uint widht, uint height); void drawAlphaTiled(Drawable dest, int x, int y, uint widht, uint height); Pixmap createPixmap(uchar *data, uint width, uint height); Pixmap createMask(uchar *data, uint width, uint height); private: XImage *createXImage(uchar *data, uint width, uint height); uchar *getScaledData(uint width, uint height); /** * Create pixel value suitable for ximage from R, G and B. */ inline ulong getPixelFromRgb(XImage *ximage, uchar r, uchar g, uchar b) { // 5 R, 5 G, 5 B (15 bit display) if ((ximage->red_mask == 0x7c00) && (ximage->green_mask == 0x3e0) && (ximage->blue_mask == 0x1f)) { return ((r << 7) & 0x7c00) | ((g << 2) & 0x03e0) | ((b >> 3) & 0x001f); // 5 R, 6 G, 5 B (16 bit display) } else if ((ximage->red_mask == 0xf800) && (ximage->green_mask == 0x07e0) && (ximage->blue_mask == 0x001f)) { return ((r << 8) & 0xf800) | ((g << 3) & 0x07e0) | ((b >> 3) & 0x001f); // 8 R, 8 G, 8 B (24/32 bit display) } else if ((ximage->red_mask == 0xff0000) && (ximage->green_mask == 0xff00) && (ximage->blue_mask == 0xff)) { return ((r << 16) & 0xff0000) | ((g << 8) & 0x00ff00) | (b & 0x0000ff); } else { return 0; } } /** * Fill in RGB values from pixel value from ximage. */ inline void getRgbFromPixel(XImage *ximage, ulong pixel, uchar &r, uchar &g, uchar &b) { // 5 R, 5 G, 5 B (15 bit display) if ((ximage->red_mask == 0x7c00) && (ximage->green_mask == 0x3e0) && (ximage->blue_mask == 0x1f)) { r = (pixel >> 7) & 0x7c; g = (pixel >> 2) & 0x3e; b = (pixel << 3) & 0x1f; // 5 R, 6 G, 5 B (16 bit display) } else if ((ximage->red_mask == 0xf800) && (ximage->green_mask == 0x07e0) && (ximage->blue_mask == 0x001f)) { r = (pixel >> 8) & 0xf8; g = (pixel >> 3) & 0x7e; b = (pixel << 3) & 0x1f; // 8 R, 8 G, 8 B (24/32 bit display) } else if ((ximage->red_mask == 0xff0000) && (ximage->green_mask == 0xff00) && (ximage->blue_mask == 0xff)) { r = (pixel >> 16) & 0xff; g = (pixel >> 8) & 0xff; b = pixel & 0xff; } else { r = 0; g = 0; b = 0; } } protected: ImageType _type; //!< Type of image. Pixmap _pixmap; //!< Pixmap representation of image. Pixmap _mask; //!< Pixmap representation of image shape mask. uint _width; //!< Width of image. uint _height; //!< Height of image. uchar *_data; //!< Data describing image. bool _has_alpha; //!< Wheter image has alpha channel. bool _use_alpha; //!< Wheter image has alpha < 100% private: static vector _loaders; //!< List of loaders. }; #endif // _PIMAGE_HH_ pekwm-release-0.1.18/src/PImageIcon.cc000066400000000000000000000041621374756504400174350ustar00rootroot00000000000000// // PImage.hh for pekwm // Copyright © 2007-2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "config.h" #include #include "PImageIcon.hh" #include "x11.hh" using std::cerr; using std::endl; //! @brief PImageIcon constructor. //! @param dpy Display to load icon from. PImageIcon::PImageIcon() : PImage() { _type = IMAGE_TYPE_SCALED; _has_alpha = true; _use_alpha = true; } //! @brief PImage destructor. PImageIcon::~PImageIcon(void) { } /** * Load icon from window (if atom is set) */ bool PImageIcon::loadFromWindow(Window win) { bool status = false; uchar *udata = 0; ulong expected = 2, actual; if (X11::getProperty(win, NET_WM_ICON, XA_CARDINAL, expected, &udata, &actual)) { if (actual >= expected) { status = setImageFromData(udata, actual); } XFree(udata); } return status; } /** * Do the actual reading and loading of the icon data in ARGB data. */ bool PImageIcon::setImageFromData(uchar *udata, ulong actual) { // Icon size successfully read, proceed with loading the actual icon data. long *from_data = reinterpret_cast(udata); uint width = from_data[0]; uint height = from_data[1]; if (actual < (width * height + 2)) { return false; } _width = width; _height = height; _data = new uchar[_width * _height * 4]; convertARGBtoRGBA(_width * _height, from_data, _data); _pixmap = createPixmap(_data, _width, _height); _mask = createMask(_data, _width, _height); return true; } /** * Convert data, source data is ARGB one pixel per 32bit and * destination is RGBA in 4x8bit. */ void PImageIcon::convertARGBtoRGBA(ulong size, long *from_data, uchar *to_data) { uchar *p = to_data; int pixel; for (ulong i = 2; i < size; i += 1) { pixel = from_data[i]; // in case 64bit system drop the unneeded bits *p++ = pixel >> 16 & 0xff; *p++ = pixel >> 8 & 0xff; *p++ = pixel & 0xff; *p++ = pixel >> 24 & 0xff; } } pekwm-release-0.1.18/src/PImageIcon.hh000066400000000000000000000012211374756504400174400ustar00rootroot00000000000000// // PImage.hh for pekwm // Copyright © 2007-2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifndef _PIMAGE_NATIVE_ICON_HH_ #define _PIMAGE_NATIVE_ICON_HH_ #include "config.h" #include "PImage.hh" //! @brief Image class with pekwm native backend. class PImageIcon : public PImage { public: PImageIcon(void); virtual ~PImageIcon(void); bool loadFromWindow(Window win); private: bool setImageFromData(uchar *data, ulong actual); static void convertARGBtoRGBA(ulong size, long *from_data, uchar *to_data); }; #endif // _PIMAGE_NATIVE_ICON_HH_ pekwm-release-0.1.18/src/PImageLoader.hh000066400000000000000000000016171374756504400177670ustar00rootroot00000000000000// // PImageLoader.hh for pekwm // Copyright © 2005-2009 Claes Nasten // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifndef _PIMAGE_NATIVE_LOADER_HH_ #define _PIMAGE_NATIVE_LOADER_HH_ #include "config.h" #include //! @brief Image loader base class. class PImageLoader { public: //! @brief PImageLoader constructor. PImageLoader(const char *ext) : _ext(ext) { } //! @brief PImageLoader destructor. virtual ~PImageLoader(void) { } //! @brief Return file extension matching loader. inline const char *getExt(void) const { return _ext; } //! @brief Loads file into data. (empty method, interface) virtual uchar *load(const std::string &file, uint &width, uint &height, bool &alpha, bool &use_alpha) { return 0; } private: const char *_ext; }; #endif // _PIMAGE_NATIVE_LOADER_HH_ pekwm-release-0.1.18/src/PImageLoaderJpeg.cc000066400000000000000000000043561374756504400205660ustar00rootroot00000000000000// // PImageLoaderJpeg.cc for pekwm // Copyright © 2005-2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "config.h" #ifdef HAVE_IMAGE_JPEG #include "PImageLoaderJpeg.hh" #include extern "C" { #include #include } using std::string; using std::cerr; using std::endl; //! @brief PImageLoaderJpeg constructor. PImageLoaderJpeg::PImageLoaderJpeg(void) : PImageLoader("JPG") { } //! @brief PImageLoaderJpeg destructor. PImageLoaderJpeg::~PImageLoaderJpeg(void) { } //! @brief Loads file into data. //! @param file File to load data from. //! @param width Set to the width of image. //! @param height Set to the height of image. //! @param alpha Set to wheter image has alpha channel. //! @return Pointer to data on success, else 0. uchar* PImageLoaderJpeg::load(const std::string &file, uint &width, uint &height, bool &alpha, bool &use_alpha) { FILE *fp; fp= fopen(file.c_str(), "rb"); if (! fp) { cerr << " *** WARNING: unable to open " << file << " for reading!" << endl; return 0; } struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; cinfo.err = jpeg_std_error(&jerr); jpeg_create_decompress(&cinfo); jpeg_stdio_src(&cinfo, fp); // Read jpeg header. jpeg_read_header(&cinfo, TRUE); // Make sure we get data in 24bit RGB. if (cinfo.out_color_space != JCS_RGB) cinfo.out_color_space = JCS_RGB; jpeg_start_decompress(&cinfo); uint channels; uint rowbytes; width = cinfo.output_width; height = cinfo.output_height; channels = cinfo.output_components; rowbytes = width * channels; // Allocate image data. uchar *data = new uchar[width * height * channels]; // Read image. JSAMPROW row; for (uint i = 0; i < height; ++i) { row = data + i * rowbytes; jpeg_read_scanlines(&cinfo, &row, 1); } // Clean up. jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); fclose(fp); alpha = false; // Jpeg doesn't support alpha. use_alpha = false; // Jpeg doesn't support alpha. return data; } #endif // HAVE_IMAGE_JPEG pekwm-release-0.1.18/src/PImageLoaderJpeg.hh000066400000000000000000000013421374756504400205700ustar00rootroot00000000000000// // PImageLoaderJpeg.hh for pekwm // Copyright © 2005-2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifndef _PIMAGE_NATIVE_LOADER_JPEG_HH_ #define _PIMAGE_NATIVE_LOADER_JPEG_HH_ #include "config.h" #ifdef HAVE_IMAGE_JPEG #include "pekwm.hh" #include "PImageLoader.hh" #include //! @brief Jpeg Loader class. class PImageLoaderJpeg : public PImageLoader { public: PImageLoaderJpeg(void); virtual ~PImageLoaderJpeg(void); virtual uchar *load(const std::string &file, uint &width, uint &height, bool &alpha, bool &use_alpha); }; #endif // HAVE_IMAGE_JPEG #endif // _PIMAGE_NATIVE_LOADER_JPEG_HH_ pekwm-release-0.1.18/src/PImageLoaderPng.cc000066400000000000000000000107771374756504400204310ustar00rootroot00000000000000// // PImageLoaderPng.cc for pekwm // Copyright © 2005-2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "config.h" #ifdef HAVE_IMAGE_PNG #include "PImageLoaderPng.hh" #include extern "C" { #include } using std::string; using std::cerr; using std::endl; const int PImageLoaderPng::PNG_SIG_BYTES = 8; //! @brief PImageLoaderPng constructor. PImageLoaderPng::PImageLoaderPng(void) : PImageLoader("PNG") { } //! @brief PImageLoaderPng destructor. PImageLoaderPng::~PImageLoaderPng(void) { } //! @brief Loads file into data. //! @param file File to load data from. //! @param width Set to the width of image. //! @param height Set to the height of image. //! @param alpha Set to wheter image has alpha channel. //! @return Pointer to data on success, else 0. uchar* PImageLoaderPng::load(const std::string &file, uint &width, uint &height, bool &alpha, bool &use_alpha) { FILE *fp; fp = fopen(file.c_str(), "rb"); if (! fp) { cerr << " *** WARNING: unable to open " << file << " for reading!" << endl; return 0; } if (! checkSignature(fp)) { cerr << " *** WARNING: " << file << " not a PNG file!" << endl; fclose(fp); return 0; } // Start PNG loading. png_structp png_ptr; png_infop info_ptr; png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); if (! png_ptr) { cerr << " *** ERROR: out of memory, png_create_read_struct failed!" << endl; fclose(fp); return 0; } info_ptr = png_create_info_struct(png_ptr); if (! info_ptr) { cerr << " *** ERROR: out of memory, png_create_info_struct failed!" << endl; png_destroy_read_struct(&png_ptr, 0, 0); fclose(fp); return 0; } // Setup error handling. if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, 0); fclose(fp); return 0; } png_init_io(png_ptr, fp); png_set_sig_bytes(png_ptr, PImageLoaderPng::PNG_SIG_BYTES); png_read_info(png_ptr, info_ptr); int color_type, bpp; png_uint_32 png_width = 1, png_height = 1; png_get_IHDR(png_ptr, info_ptr, &png_width, &png_height, &bpp, &color_type, 0, 0, 0); width = png_width; height = png_height; // Setup read information, we want to make sure data get read in // 16 bit RGB(A) // palette -> RGB mode if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); } // gray -> 8 bit gray if (color_type == PNG_COLOR_TYPE_GRAY && (bpp < 8)) { png_set_expand_gray_1_2_4_to_8(png_ptr); } if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png_ptr); } if (bpp == 16) { png_set_strip_16(png_ptr); } // gray, gray alpha -> to RGB if ((color_type == PNG_COLOR_TYPE_GRAY) || (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) { png_set_gray_to_rgb(png_ptr); } // Now load image data. uchar *data; size_t data_size; png_uint_32 rowbytes, channels; png_bytepp row_pointers; png_read_update_info(png_ptr, info_ptr); rowbytes = png_get_rowbytes(png_ptr, info_ptr); channels = png_get_channels(png_ptr, info_ptr); data_size = rowbytes * height / sizeof(uchar); data = new uchar[data_size]; row_pointers = new png_bytep[height]; for (png_uint_32 y = 0; y < height; ++y) { row_pointers[y] = data + y * rowbytes; } png_read_image(png_ptr, row_pointers); delete [] row_pointers; png_read_end(png_ptr, 0); // Clean up. png_destroy_read_struct(&png_ptr, &info_ptr, 0); fclose(fp); alpha = (channels == 4); use_alpha = false; if (alpha) { uchar *p = data + 3, *end = data + data_size; for (; p < end && ! use_alpha; p += 4) { if (*p != 255) { use_alpha = true; } } } return data; } //! @brief Checks file signature to see if it's a PNG file. //! @param fp Pointer to open (rb) FILE. //! @return true if fp is a PNG file, else false. bool PImageLoaderPng::checkSignature(FILE *fp) { int status; uchar sig[PImageLoaderPng::PNG_SIG_BYTES]; status = fread(sig, 1, PImageLoaderPng::PNG_SIG_BYTES, fp); if (status == PImageLoaderPng::PNG_SIG_BYTES) { return (png_sig_cmp(sig,0,PImageLoaderPng::PNG_SIG_BYTES) == 0); } return false; } #endif // HAVE_IMAGE_PNG pekwm-release-0.1.18/src/PImageLoaderPng.hh000066400000000000000000000014571374756504400204360ustar00rootroot00000000000000// // PImageLoaderPng.hh for pekwm // Copyright © 2005-2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifndef _PIMAGE_NATIVE_LOADER_PNG_HH_ #define _PIMAGE_NATIVE_LOADER_PNG_HH_ #include "config.h" #ifdef HAVE_IMAGE_PNG #include "pekwm.hh" #include "PImageLoader.hh" #include /** * PNG Loader class. */ class PImageLoaderPng : public PImageLoader { public: PImageLoaderPng(void); virtual ~PImageLoaderPng(void); virtual uchar *load(const std::string &file, uint &width, uint &height, bool &alpha, bool &use_alpha); private: bool checkSignature(std::FILE *fp); static const int PNG_SIG_BYTES; }; #endif // HAVE_IMAGE_PNG #endif // _PIMAGE_NATIVE_LOADER_PNG_HH_ pekwm-release-0.1.18/src/PImageLoaderXpm.cc000066400000000000000000000115061374756504400204400ustar00rootroot00000000000000// // PImageLoaderXpm.cc for pekwm // Copyright © 2005-2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "config.h" #ifdef HAVE_IMAGE_XPM #include "x11.hh" #include "PImageLoaderXpm.hh" #include #include #include using std::cerr; using std::endl; using std::string; using std::sscanf; using std::strlen; const uint PImageLoaderXpm::CHANNELS = 4; const uint PImageLoaderXpm::ALPHA_SOLID = 255; const uint PImageLoaderXpm::ALPHA_TRANSPARENT = 0; const char *PImageLoaderXpm::COLOR_DEFAULT = "#000000"; //! @brief PImageLoaderXpm constructor. PImageLoaderXpm::PImageLoaderXpm(void) : PImageLoader("XPM") { } //! @brief PImageLoaderXpm destructor. PImageLoaderXpm::~PImageLoaderXpm(void) { } //! @brief Loads file into data. //! @param file File to load data from. //! @param width Set to the width of image. //! @param height Set to the height of image. //! @param alpha Set to wheter image has alpha channel. //! @return Pointer to data on success, else 0. uchar* PImageLoaderXpm::load(const std::string &file, uint &width, uint &height, bool &alpha, bool &use_alpha) { XpmImage xpm_image; XpmInfo xpm_info; // Read XPM to XpmImage format. if (XpmReadFileToXpmImage((char*) file.c_str(), &xpm_image, &xpm_info) != Success) { cerr << " *** WARNING: " << file << " not a valid XPM file!" << endl; return 0; } if (! xpm_image.ncolors || ! xpm_image.data || ! xpm_image.width || ! xpm_image.height) { cerr << " *** WARNING: " << file << " invalid file information!" << endl; return 0; } // Build XpmColor -> RGBA Table. uchar *xpm_to_rgba; xpm_to_rgba = createXpmToRgbaTable(&xpm_image); width = xpm_image.width; height = xpm_image.height; // Allocate data. uchar *data, *dest; uint *src; data = new uchar[width * height * CHANNELS]; dest = data; src = xpm_image.data; alpha = true; use_alpha = false; // Fill data. for (uint y = 0; y < height; ++y) { for (uint x = 0; x < width; ++x) { *dest++ = xpm_to_rgba[*src * CHANNELS]; // R *dest++ = xpm_to_rgba[*src * CHANNELS + 1]; // G *dest++ = xpm_to_rgba[*src * CHANNELS + 2]; // B *dest++ = xpm_to_rgba[*src * CHANNELS + 3]; // A // Check for active use of alpha if (! use_alpha && xpm_to_rgba[*src * CHANNELS + 3] != 255) { use_alpha = true; } src++; } } // Cleanup. delete [] xpm_to_rgba; XpmFreeXpmImage(&xpm_image); XpmFreeXpmInfo(&xpm_info); return data; } //! @brief Creates an color number to RGBA conversion table. //! @param xpm_image Pointer to XpmImage. //! @return Pointer to color number to RGBA conversion table. uchar* PImageLoaderXpm::createXpmToRgbaTable(XpmImage *xpm_image) { uint c_tmp; // Temporary color value. char c_buf[3] = { '\0', '\0', '\0' }; // Temporary hex color string. const char *color; uchar *xpm_to_rgba, *dest; XColor xcolor_exact; xpm_to_rgba = new uchar[xpm_image->ncolors * CHANNELS]; dest = xpm_to_rgba; for (uint i = 0; i < xpm_image->ncolors; ++i) { if (xpm_image->colorTable[i].c_color) { color = xpm_image->colorTable[i].c_color; } else if (xpm_image->colorTable[i].g_color) { color = xpm_image->colorTable[i].g_color; } else if (xpm_image->colorTable[i].g4_color) { color = xpm_image->colorTable[i].g4_color; } else if (xpm_image->colorTable[i].m_color) { color = xpm_image->colorTable[i].m_color; } else { color = COLOR_DEFAULT; } if (color && color[0] == '#' && strlen(color) == 7) { // Color in format #RRGGBB for (uint j = 0; j < 3; ++j) { c_buf[0] = color[j * 2 + 1]; c_buf[1] = color[j * 2 + 2]; if (sscanf(c_buf, "%x", &c_tmp) == 1) { *dest++ = c_tmp; } else { *dest++ = 0; cerr << " *** WARNING: " << c_buf << " invalid color value!" << endl; } } *dest++ = ALPHA_SOLID; } else if (color && XParseColor(X11::getDpy(), X11::getColormap(), color, &xcolor_exact)) { *dest++ = xcolor_exact.red; *dest++ = xcolor_exact.green; *dest++ = xcolor_exact.blue; *dest++ = ALPHA_SOLID; } else { // Invalid format or None, set it transparent *dest++ = 0; // R *dest++ = 0; // G *dest++ = 0; // B *dest++ = ALPHA_TRANSPARENT; // A } } return xpm_to_rgba; } #endif // HAVE_IMAGE_XPM pekwm-release-0.1.18/src/PImageLoaderXpm.hh000066400000000000000000000021461374756504400204520ustar00rootroot00000000000000// // PImageLoaderXpm.hh for pekwm // Copyright © 2005-2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifndef _PIMAGE_NATIVE_LOADER_XPM_HH_ #define _PIMAGE_NATIVE_LOADER_XPM_HH_ #include "config.h" #ifdef HAVE_IMAGE_XPM #include "pekwm.hh" #include "PImageLoader.hh" extern "C" { #include } //! @brief Xpm Loader class. class PImageLoaderXpm : public PImageLoader { public: PImageLoaderXpm(void); virtual ~PImageLoaderXpm(void); virtual uchar *load(const std::string &file, uint &width, uint &height, bool &alpha, bool &use_alpha); private: uchar *createXpmToRgbaTable(XpmImage *xpm_image); private: static const uint CHANNELS; //!< Number of channels for Image data. static const uint ALPHA_SOLID; //!< Alpha value for no transperency. static const uint ALPHA_TRANSPARENT; //!< Alpha value for fully transperency. static const char *COLOR_DEFAULT; //!< Default Color if translation fails. }; #endif // HAVE_IMAGE_XPM #endif // _PIMAGE_NATIVE_LOADER_XPM_HH_ pekwm-release-0.1.18/src/PMenu.cc000066400000000000000000000750251374756504400165140ustar00rootroot00000000000000// // PMenu.cc for pekwm // Copyright © 2004-2016 the pekwm development team // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "config.h" #include "Debug.hh" #include "PWinObj.hh" #include "PDecor.hh" #include "PFont.hh" #include "PMenu.hh" #include "PTexture.hh" #include "PTexturePlain.hh" #include "ActionHandler.hh" #include "Config.hh" #include "TextureHandler.hh" #include "Theme.hh" #include "Workspaces.hh" #include "AutoProperties.hh" #include "x11.hh" #include #include using std::map; using std::string; using std::wstring; using std::find; PMenu::Item::Item(const std::wstring &name, PWinObj *wo_ref, PTexture *icon) : PWinObjReference(wo_ref), _x(0), _y(0), _name(name), _type(MENU_ITEM_NORMAL), _icon(icon), _creator(0) { if (_icon) { TextureHandler::instance()->referenceTexture(_icon); } } PMenu::Item::~Item(void) { if (_icon) { TextureHandler::instance()->returnTexture(_icon); } } map PMenu::_menu_map = map(); //! @brief Constructor for PMenu class PMenu::PMenu(Theme *theme, const std::wstring &title, const std::string &name, const std::string decor_name) : PDecor(theme, decor_name), _name(name), _menu_parent(0), _class_hint(L"pekwm", L"Menu", L"", L"", L""), _item_curr(0), _menu_wo(0), _menu_bg_fo(None), _menu_bg_un(None), _menu_bg_se(None), _menu_width(0), _item_height(0), _item_width_max(0), _item_width_max_avail(0), _icon_width(0), _icon_height(0), _separator_height(0), _rows(0), _cols(0), _scroll(false), _has_submenu(false) { // PWinObj attributes _type = PWinObj::WO_MENU; setLayer(LAYER_MENU); _hidden = true; // don't care about it when changing worskpace etc // create menu content child _menu_wo = new PWinObj(false); XSetWindowAttributes attr; attr.override_redirect = True; attr.event_mask = ButtonPressMask|ButtonReleaseMask|ButtonMotionMask| FocusChangeMask|KeyPressMask|KeyReleaseMask|PointerMotionMask; _menu_wo->setWindow(XCreateWindow(X11::getDpy(), _window, 0, 0, 1, 1, 0, CopyFromParent, InputOutput, CopyFromParent, CWOverrideRedirect|CWEventMask, &attr)); titleAdd(&_title); titleSetActive(0); setTitle(title); addChild(_menu_wo); addChildWindow(_menu_wo->getWindow()); activateChild(_menu_wo); _menu_wo->mapWindow(); Workspaces::insert(this); _menu_map[_window] = this; // add to menu map woListAdd(this); _wo_map[_window] = this; setOpacity(Config::instance()->getMenuFocusOpacity(), Config::instance()->getMenuUnfocusOpacity()); } //! @brief Destructor for PMenu class PMenu::~PMenu(void) { _wo_map.erase(_window); woListRemove(this); _menu_map.erase(_window); // remove from menu map Workspaces::remove(this); // Free resources if (_menu_wo) { _children.erase(std::remove(_children.begin(), _children.end(), _menu_wo), _children.end()); removeChildWindow(_menu_wo->getWindow()); XDestroyWindow(X11::getDpy(), _menu_wo->getWindow()); delete _menu_wo; } vector::const_iterator it(_items.begin()); for (; it != _items.end(); ++it) { delete *it; } X11::freePixmap(_menu_bg_fo); X11::freePixmap(_menu_bg_un); X11::freePixmap(_menu_bg_se); } // START - PWinObj interface. //! @brief Unmapping, deselecting current item and unsticking. void PMenu::unmapWindow(void) { _item_curr = _items.size(); _sticky = false; PDecor::unmapWindow(); } //! @brief void PMenu::setFocused(bool focused) { if (_focused != focused) { PDecor::setFocused(focused); _menu_wo->setBackgroundPixmap(_focused ? _menu_bg_fo : _menu_bg_un); _menu_wo->clear(); if (_item_curr < _items.size()) { vector::const_iterator item(_items.begin() + _item_curr); _item_curr = _items.size(); // Force selectItem(item) to redraw selectItem(item); } } } /** * Set focusable, includes the _menu_wo as well as the decor. */ void PMenu::setFocusable(bool focusable) { PDecor::setFocusable(focusable); _menu_wo->setFocusable(focusable); } //! @brief ActionEvent* PMenu::handleButtonPress(XButtonEvent *ev) { if (*_menu_wo == ev->window) { handleItemEvent(MOUSE_EVENT_PRESS, ev->x, ev->y); // update pointer position _pointer_x = ev->x_root; _pointer_y = ev->y_root; return ActionHandler::findMouseAction(ev->button, ev->state, MOUSE_EVENT_PRESS, Config::instance()->getMouseActionList(MOUSE_ACTION_LIST_MENU)); } else { return PDecor::handleButtonPress(ev); } } /** * Handle button release. */ ActionEvent* PMenu::handleButtonRelease(XButtonEvent *ev) { if (_window == ev->subwindow) { ev->window = _menu_wo->getWindow(); ev->x -= _gm.x; ev->y -= _gm.y + getTitleHeight(); } if (*_menu_wo == ev->window) { MouseEventType mb = MOUSE_EVENT_RELEASE; // first we check if it's a double click if (X11::isDoubleClick(ev->window, ev->button - 1, ev->time, Config::instance()->getDoubleClickTime())) { X11::setLastClickID(ev->window); X11::setLastClickTime(ev->button - 1, 0); mb = MOUSE_EVENT_DOUBLE; } else { X11::setLastClickID(ev->window); X11::setLastClickTime(ev->button - 1, ev->time); } handleItemEvent(mb, ev->x, ev->y); return ActionHandler::findMouseAction(ev->button, ev->state, mb, Config::instance()->getMouseActionList(MOUSE_ACTION_LIST_MENU)); } else { return PDecor::handleButtonRelease(ev); } } /** * Handle motion event, select buttons and execute actions. * * @param ev Handle motion event. */ ActionEvent* PMenu::handleMotionEvent(XMotionEvent *ev) { if (_window == ev->subwindow) { ev->window = _menu_wo->getWindow(); ev->x -= _gm.x; ev->y -= _gm.y + getTitleHeight(); } if (*_menu_wo == ev->window) { uint button = X11::getButtonFromState(ev->state); handleItemEvent(button ? MOUSE_EVENT_MOTION_PRESSED : MOUSE_EVENT_MOTION, ev->x, ev->y); ActionEvent *ae; X11::stripButtonModifiers(&ev->state); ae = ActionHandler::findMouseAction(button, ev->state, MOUSE_EVENT_MOTION, Config::instance()->getMouseActionList(MOUSE_ACTION_LIST_MENU)); // check motion threshold if (ae && (ae->threshold > 0)) { if (! ActionHandler::checkAEThreshold(ev->x_root, ev->y_root, _pointer_x, _pointer_y, ae->threshold)) { ae = 0; } } return ae; } else { return PDecor::handleMotionEvent(ev); } } //! @brief ActionEvent* PMenu::handleEnterEvent(XCrossingEvent *ev) { if (*_menu_wo == ev->window) { return ActionHandler::findMouseAction(BUTTON_ANY, ev->state, MOUSE_EVENT_ENTER, Config::instance()->getMouseActionList(MOUSE_ACTION_LIST_MENU)); } else { return PDecor::handleEnterEvent(ev); } } //! @brief ActionEvent* PMenu::handleLeaveEvent(XCrossingEvent *ev) { if (*_menu_wo == ev->window) { return ActionHandler::findMouseAction(BUTTON_ANY, ev->state, MOUSE_EVENT_LEAVE, Config::instance()->getMouseActionList(MOUSE_ACTION_LIST_MENU)); } else { return PDecor::handleLeaveEvent(ev); } } // END - PWinObj interface. // START - PDecor interface. void PMenu::loadTheme(void) { buildMenu(); } // END - PDecor interface. /** * Handle event on menu item at position, ignores event if no item * exists at the position. */ void PMenu::handleItemEvent(MouseEventType type, int x, int y) { PMenu::Item *item = findItem(x, y); if (! item) { return; } // Unmap submenu if we enter them on the same event as selecting. if ((_item_curr >= _items.size() || item != _items[_item_curr]) && Config::instance()->isMenuSelectOn(type)) { select(item, Config::instance()->isMenuEnterOn(type)); } if (Config::instance()->isMenuEnterOn(type)) { if (item->getWORef() && (item->getWORef()->getType() == PWinObj::WO_MENU)) { // Special case for motion, would flicker like crazy if we didn't check if ((type != MOUSE_EVENT_MOTION) && (type != MOUSE_EVENT_MOTION_PRESSED) && item->getWORef()->isMapped()) { static_cast(item->getWORef())->unmapSubmenus(); item->getWORef()->unmapWindow(); } else if (! item->getWORef()->isMapped()) { // unmap previous opened submenu if any unmapSubmenus(); mapSubmenu(static_cast(item->getWORef())); } } } // Submenus don't have any actions, so we don't exec ( and close them ) if (item->getAE().action_list.size() && Config::instance()->isMenuExecOn(type)) { exec(item); } } //! @brief Sets the position of the items and determine size of the menu void PMenu::buildMenu(void) { // calculate geometry, if to enable scrolling etc buildMenuCalculate(); // not necessary to do this if we don't have any visible items if (_size > 0) { // place menu items buildMenuPlace(); // render items on the menu buildMenuRender(); } } //! @brief Calculates how much space and how many rows/cols will be needed void PMenu::buildMenuCalculate(void) { _has_submenu = false; // Get how many visible objects we have unsigned int sep = 0; vector::const_iterator it(_items.begin()); for (_size = 0; it != _items.end(); ++it) { if ((*it)->getType() == PMenu::Item::MENU_ITEM_NORMAL) { ++_size; } else if ((*it)->getType() == PMenu::Item::MENU_ITEM_SEPARATOR) { ++sep; } } unsigned int width = 1, height = 1; buildMenuCalculateMaxWidth(width, height); // FIXME: Remove extra padding from calculation if (_menu_width) { _item_width_max = _menu_width; } // This is the available width for drawing text on, the rest is reserved // for submenu indicator, padding etc. _item_width_max_avail = _item_width_max; // Continue add padding etc. _item_width_max += _theme->getMenuData()->getPad(PAD_LEFT) + _theme->getMenuData()->getPad(PAD_RIGHT); if (Config::instance()->isDisplayMenuIcons()) { _item_width_max += _icon_width; } // If we have any submenus, increase the maximum width with arrow width + // right pad as we are going to pad the arrow from the text too. if (_has_submenu) { _item_width_max += _theme->getMenuData()->getPad(PAD_RIGHT) + _theme->getMenuData()->getTextureArrow(OBJECT_STATE_FOCUSED)->getWidth(); } // Remove padding etc from avail and item width. if (_menu_width) { unsigned int padding = _item_width_max - _item_width_max_avail; _item_width_max -= padding; _item_width_max_avail -= padding; } // Calculate item height _item_height = std::max(_theme->getMenuData()->getFont(OBJECT_STATE_FOCUSED)->getHeight(), _icon_height) + _theme->getMenuData()->getPad(PAD_UP) + _theme->getMenuData()->getPad(PAD_DOWN); _separator_height = _theme->getMenuData()->getTextureSeparator(OBJECT_STATE_FOCUSED)->getHeight(); height = (_item_height * _size) + (_separator_height * sep); if (_size) { _size += sep; } buildMenuCalculateColumns(width, height); // Check if we need to enable scrolling _scroll = (width > X11::getWidth()); resizeChild(width, height); } /** * Get maximum item width and icon size. */ void PMenu::buildMenuCalculateMaxWidth(unsigned int &width, unsigned int &height) { // Calculate max item width, to be used if/when splitting a menu // up in rows because of limited vertical space. _item_width_max = 1; _icon_width = _icon_height = 0; vector::const_iterator it(_items.begin()); for (; it != _items.end(); ++it) { // Only include standard items if ((*it)->getType() != PMenu::Item::MENU_ITEM_NORMAL) { continue; } // Check if we have a submenu item if (! _has_submenu && (*it)->getWORef() && ((*it)->getWORef()->getType() == PWinObj::WO_MENU)) { _has_submenu = true; } // Get icon height if any if ((*it)->getIcon()) { if ((*it)->getIcon()->getWidth() > _icon_width) { _icon_width = (*it)->getIcon()->getWidth(); } if ((*it)->getIcon()->getHeight() > _icon_height) { _icon_height = (*it)->getIcon()->getHeight(); } } width = _theme->getMenuData()->getFont(OBJECT_STATE_FOCUSED)->getWidth((*it)->getName().c_str()); if (width > _item_width_max) { _item_width_max = width; } } // Make sure icon width and height are not larger than configured. if (_icon_width) { _icon_width = Util::between(_icon_width, Config::instance()->getMenuIconLimit(_icon_width, WIDTH_MIN, _name), Config::instance()->getMenuIconLimit(_icon_width, WIDTH_MAX, _name)); _icon_height = Util::between(_icon_height, Config::instance()->getMenuIconLimit(_icon_height, HEIGHT_MIN, _name), Config::instance()->getMenuIconLimit(_icon_height, HEIGHT_MAX, _name)); } } /** * Calculate number of columns, this does not apply to static width * menus. */ void PMenu::buildMenuCalculateColumns(unsigned int &width, unsigned int &height) { // Check if the menu fits or is static width if (_menu_width || (height + getTitleHeight()) <= X11::getHeight()) { _cols = 1; width = _menu_width ? _menu_width : _item_width_max; _rows = _size; return; } _cols = height / (X11::getHeight() - getTitleHeight()); if ((height % (X11::getHeight() - getTitleHeight())) != 0) { ++_cols; } _rows = _size / _cols; if ((_size % _cols) != 0) { ++_rows; } width = _cols * _item_width_max; // need to calculate max height, the one with most separators if any if (_cols > 1) { uint i, j, row_height; height = 0; vector::const_iterator it(_items.begin()); for (i = 0, it = _items.begin(); i < _cols; ++i) { row_height = 0; for (j = 0; j < _rows && it != _items.end(); ++it, ++j) { switch ((*it)->getType()) { case PMenu::Item::MENU_ITEM_NORMAL: row_height += _item_height; break; case PMenu::Item::MENU_ITEM_SEPARATOR: row_height += _separator_height; break; case PMenu::Item::MENU_ITEM_HIDDEN: default: break; } } if (row_height > height) { height = row_height; } } } } //! @brief Places the items in the menu void PMenu::buildMenuPlace(void) { uint x, y; vector::const_iterator it; x = 0; it = _items.begin(); // cols for (uint i = 0; i < _cols; ++i) { y = 0; // rows for (uint j = 0; j < _rows && it != _items.end(); ++it) { if ((*it)->getType() != PMenu::Item::MENU_ITEM_HIDDEN) { (*it)->setX(x); (*it)->setY(y); if ((*it)->getType() == PMenu::Item::MENU_ITEM_NORMAL) { y += _item_height; ++j; // only count real menu items } else if ((*it)->getType() == PMenu::Item::MENU_ITEM_SEPARATOR) { y += _separator_height; } } } x += _item_width_max; } } //! @brief Renders focused, unfocused and selected pixmaps for menu void PMenu::buildMenuRender(void) { buildMenuRenderState(_menu_bg_fo, OBJECT_STATE_FOCUSED); buildMenuRenderState(_menu_bg_un, OBJECT_STATE_UNFOCUSED); buildMenuRenderState(_menu_bg_se, OBJECT_STATE_SELECTED); _menu_wo->setBackgroundPixmap(_focused ? _menu_bg_fo : _menu_bg_un); _menu_wo->clear(); } //! @brief Renders menu content on pix, with state state void PMenu::buildMenuRenderState(Pixmap &pix, ObjectState state) { // get a fresh pixmap for the menu X11::freePixmap(pix); pix = X11::createPixmap(getChildWidth(), getChildHeight()); PTexture *tex; PFont *font; tex = _theme->getMenuData()->getTextureMenu(state); tex->render(pix, 0, 0, getChildWidth(), getChildHeight()); font = _theme->getMenuData()->getFont(state); font->setColor(_theme->getMenuData()->getColor(state)); vector::const_iterator it(_items.begin()); for (; it != _items.end(); ++it) { if ((*it)->getType() != PMenu::Item::MENU_ITEM_HIDDEN) { buildMenuRenderItem(pix, state, *it); } } } //! @brief Renders item on pix, with state state void PMenu::buildMenuRenderItem(Pixmap pix, ObjectState state, PMenu::Item *item) { PTexture *tex; Theme::PMenuData *md = _theme->getMenuData(); if (item->getType() == PMenu::Item::MENU_ITEM_NORMAL) { tex = md->getTextureItem(state); tex->render(pix, item->getX(), item->getY(), _item_width_max, _item_height); uint start_x, start_y, icon_width, icon_height; // If entry has an icon, draw it if (item->getIcon() && Config::instance()->isDisplayMenuIcons()) { icon_width = Util::between(item->getIcon()->getWidth(), Config::instance()->getMenuIconLimit(_icon_width, WIDTH_MIN, _name), Config::instance()->getMenuIconLimit(_icon_width, WIDTH_MAX, _name)); icon_height = Util::between(item->getIcon()->getHeight(), Config::instance()->getMenuIconLimit(_icon_height, HEIGHT_MIN, _name), Config::instance()->getMenuIconLimit(_icon_height, HEIGHT_MAX, _name)); start_x = item->getX() + md->getPad(PAD_LEFT) + (_icon_width - icon_width) / 2; start_y = item->getY() + (_item_height - icon_height) / 2; item->getIcon()->render(pix, start_x, start_y, icon_width, icon_height); } else { icon_width = 0; icon_height = 0; } // If entry has a submenu, lets draw our submenu "arrow" if (item->getWORef() && (item->getWORef()->getType() == PWinObj::WO_MENU)) { tex = md->getTextureArrow(state); uint arrow_width = tex->getWidth(); uint arrow_height = tex->getHeight(); uint arrow_y = static_cast((_item_height / 2) - (arrow_height / 2)); start_x = item->getX() + _item_width_max - arrow_width - md->getPad(PAD_RIGHT); start_y = item->getY() + arrow_y; tex->render(pix, start_x, start_y, arrow_width, arrow_height); } PFont *font = md->getFont(state); start_x = item->getX() + md->getPad(PAD_LEFT); // Add icon width to starting x position if frame icons are enabled. if (Config::instance()->isDisplayMenuIcons()) { start_x += _icon_width; } start_y = item->getY() + md->getPad(PAD_UP) + (_item_height - font->getHeight() - md->getPad(PAD_UP) - md->getPad(PAD_DOWN)) / 2; // Render item text. font->draw(pix, start_x, start_y, item->getName().c_str(), 0, _item_width_max_avail); } else if ((item->getType() == PMenu::Item::MENU_ITEM_SEPARATOR) && (state < OBJECT_STATE_SELECTED)) { tex = md->getTextureSeparator(state); tex->render(pix, item->getX(), item->getY(), _item_width_max, _separator_height); } } #define COPY_ITEM_AREA(ITEM, PIX) \ XCopyArea(X11::getDpy(), PIX, _menu_wo->getWindow(), X11::getGC(), \ (ITEM)->getX(), (ITEM)->getY(), _item_width_max, _item_height, \ (ITEM)->getX(), (ITEM)->getY()); //! @brief Renders item as selected //! @param item Item to select //! @param unmap_submenu Defaults to true void PMenu::selectItem(vector::const_iterator item, bool unmap_submenu) { if (_item_curr < _items.size() && _items[_item_curr] == *item) { return; } deselectItem(unmap_submenu); _item_curr = item-_items.begin(); if (_mapped) { COPY_ITEM_AREA((*item), _menu_bg_se); } } //! @brief Deselects selected item //! @param unmap_submenu Defaults to true void PMenu::deselectItem(bool unmap_submenu) { // deselect previous item if (_item_curr < _items.size() && _items[_item_curr]->getType() != PMenu::Item::MENU_ITEM_HIDDEN) { if (_mapped) COPY_ITEM_AREA(_items[_item_curr], (_focused ? _menu_bg_fo : _menu_bg_un)); if (unmap_submenu && _items[_item_curr]->getWORef() && (_items[_item_curr]->getWORef()->getType() == PWinObj::WO_MENU)) { static_cast(_items[_item_curr]->getWORef())->unmapSubmenus(); _items[_item_curr]->getWORef()->unmapWindow(); } } } #undef COPY_ITEM_AREA //! @brief Selects next item ( wraps ). First item if none is selected. void PMenu::selectNextItem(void) { if (_size == 0) { return; } vector::const_iterator item(_items.begin() + (_item_curr<_items.size()?_item_curr:0)); // no item selected, select the first item if (item == _items.end()) { item = _items.begin(); } else { // select next item, wrap if needed ++item; if (item == _items.end()) { item = _items.begin(); } } // skip to next if separator/hidden if ((*item)->getType() != PMenu::Item::MENU_ITEM_NORMAL) { deselectItem(); // otherwise, last selected won't get deselcted _item_curr = item-_items.begin(); selectNextItem(); } else { selectItem(item); } } //! @brief Selects previous item ( wraps ). Last item if none is selected. void PMenu::selectPrevItem(void) { if (_size == 0) { return; } vector::const_iterator item(_items.begin() + (_item_curr<_items.size()?_item_curr:0)); // no item selected, select the last item OR // we're at the beginning and need to wrap to the end if (item == _items.end() || item == _items.begin()) { item = _items.end(); } --item; // skip to prev if separator/hidden if ((*item)->getType() != PMenu::Item::MENU_ITEM_NORMAL) { deselectItem(); // otherwise, last selected won't get deselcted _item_curr = item-_items.begin(); selectPrevItem(); } else { selectItem(item); } } //! @brief Sets title of the menu/decor void PMenu::setTitle(const std::wstring &title) { _title.setReal(title); // Apply title rules to allow title rewriting applyTitleRules(title); } /** * Applies title rules to menu. */ void PMenu::applyTitleRules(const std::wstring &title) { _class_hint.title = title; TitleProperty *data = AutoProperties::instance()->findTitleProperty(&_class_hint); if (data) { wstring new_title(title); if (data->getTitleRule().ed_s(new_title)) { _title.setCustom(new_title); } } } //! @brief Inserts item into the menu ( without rebuilding ) void PMenu::insert(PMenu::Item *item) { checkItemWORef(item); _items.push_back(item); } //! @brief Creates and inserts Item //! @param name Name of objet to create and insert //! @param wo_ref PWinObj to refer to, defaults to 0 void PMenu::insert(const std::wstring &name, PWinObj *wo_ref, PTexture *icon) { insert(new PMenu::Item(name, wo_ref, icon)); } //! @brief Creates and inserts Item //! @param name Name of object to create and insert //! @param ae ActionEvent for the object //! @param wo_ref PWinObj to refer to, defaults to 0 void PMenu::insert(const std::wstring &name, const ActionEvent &ae, PWinObj *wo_ref, PTexture *icon) { PMenu::Item *item = new PMenu::Item(name, wo_ref, icon); item->setAE(ae); insert(item); } //! @brief Removes an item from the menu, without rebuilding. void PMenu::remove(PMenu::Item *item) { if (! item) { WARN("trying to remove null item"); return; } if (_item_curr < _items.size() && item == _items[_item_curr]) { _item_curr = _items.size(); } delete item; _items.erase(std::remove(_items.begin(), _items.end(), item), _items.end()); } //! @brief Removes all items from the menu, without rebuilding. void PMenu::removeAll(void) { vector::const_iterator it(_items.begin()); for (; it != _items.end(); ++it) { delete *it; } _items.clear(); _item_curr = 0; } //! @brief Places the menu under the mouse and maps it. void PMenu::mapUnderMouse(void) { int x, y; X11::getMousePosition(x, y); // this might seem a bit silly but the menu won't get updated before // it has been mapped (if dynamic) so we're doing it twice to reduce the // "flickering" risk but it's not 100% so it's done twice. makeInsideScreen(x, y); mapWindowRaised(); makeInsideScreen(x, y); } //! @brief Maps menu relative to the this menu //! @param menu Submenu to map //! @param focus Give input focus and select first item. Defaults to false. void PMenu::mapSubmenu(PMenu *menu, bool focus) { int x, y; x = getRX(); if (_item_curr < _items.size()) { y = _gm.y + _items[_item_curr]->getY(); } else { y = _gm.y; } // this might seem a bit silly but the menu won't get updated before // it has been mapped (if dynamic) so we're doing it twice to reduce the // "flickering" risk but it's not 100% so it's done twice. menu->makeInsideScreen(x, y); menu->mapWindowRaised(); menu->makeInsideScreen(x, y); if (focus) { menu->giveInputFocus(); menu->selectItemNum(0); } } //! @brief Unmaps all ( recursive ) submenus open under this menu void PMenu::unmapSubmenus(void) { vector::iterator it(_items.begin()); for (; it != _items.end(); ++it) { if ((*it)->getWORef() && (*it)->getWORef()->getType() == PWinObj::WO_MENU) { // Sub-menus will be deleted when unmapping this, so no need // to continue. static_cast((*it)->getWORef())->unmapSubmenus(); (*it)->getWORef()->unmapWindow(); } } } //! @brief Unmaps all menus belonging to this menu void PMenu::unmapAll(void) { if (_menu_parent) { _menu_parent->unmapAll(); } else { unmapSubmenus(); unmapWindow(); } } //! @brief Gives input focus to parent and unmaps submenus void PMenu::gotoParentMenu(void) { if (! _menu_parent) { return; } _menu_parent->unmapSubmenus(); _menu_parent->giveInputFocus(); } //! @brief Selects item, if 0/not in list current item is deselected //! @param item Item to select //! @param unmap_submenu Defaults to true void PMenu::select(PMenu::Item *item, bool unmap_submenu) { selectItem(find(_items.begin(), _items.end(), item), unmap_submenu); } //! @brief Selects item number num in menu void PMenu::selectItemNum(uint num) { if (num >= _items.size()) { return; } selectItem(_items.begin() + num); } //! @brief Selects item relative to the selected void PMenu::selectItemRel(int off) { if (off == 0) { WARN("trying to select non existing relative (current) item number"); return; } // if no selected item, use first vector::const_iterator it(_items.begin() + (_item_curr < _items.size()?_item_curr:0)); int dir = (off > 0) ? 1 : -1; off = abs(off); for (int i = 0; i < off; ++i) { if (dir == 1) { // forward if (++it == _items.end()) { it = _items.begin(); } } else { // backward if (it == _items.begin()) { it = _items.end(); } --it; } } selectItem(it); } //! @brief Executes items action, sending it to the parent menu if availible void PMenu::exec(PMenu::Item *item) { if (_menu_parent) { _menu_parent->exec(item); } else { handleItemExec(item); if (! _sticky) { unmapAll(); } } } //! @brief Sets up children _menu_parent field, if item's _wo_ref is a menu void PMenu::checkItemWORef(PMenu::Item *item) { if (item->getWORef() && (item->getWORef()->getType() == PWinObj::WO_MENU)) { PMenu *child = static_cast(item->getWORef()); child->_menu_parent = this; } } //! @brief Searches for item at x, y PMenu::Item* PMenu::findItem(int x, int y) { vector::const_iterator it(_items.begin()); for (; it != _items.end(); ++it) { if (((*it)->getType() == PMenu::Item::MENU_ITEM_NORMAL) && (x >= (*it)->getX()) && (x <= signed((*it)->getX() + _item_width_max)) && (y >= (*it)->getY()) && (y <= signed((*it)->getY() + _item_height))) { return *it; } } return 0; } //! @brief Moves the menu relative to it's parent to make it fit on screen //! @param x Use x instead of _gm.x ( optional ) //! @param y Use y instead of _gm.y ( optional ) void PMenu::makeInsideScreen(int x, int y) { Geometry head; X11::getHeadInfo(X11::getCurrHead(), head); x = (x == -1) ? _gm.x : x; y = (y == -1) ? _gm.y : y; // we map on submenus on the right side so this only happens on the // top-level menu if (x < head.x) { x = head.x; } else if ((x + _gm.width) > (head.x + head.width)) { if (_menu_parent) { x = _menu_parent->_gm.x - _gm.width; // not using getX(), refers to child } else { x = head.x + head.width - _gm.width; } } if (y < head.y) { y = head.y; } else if ((y + _gm.height) > (head.y + head.height)) { y = head.y + head.height - _gm.height; } move(x, y); } pekwm-release-0.1.18/src/PMenu.hh000066400000000000000000000136631374756504400165260ustar00rootroot00000000000000// // PMenu.hh for pekwm // Copyright © 2004-2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifndef _PMENU_HH_ #define _PMENU_HH_ #include "config.h" #include #include #include "pekwm.hh" #include "AutoProperties.hh" #include "CfgParser.hh" #include "PDecor.hh" #include "PWinObjReference.hh" class PTexture; class ActionEvent; class Theme; class PMenu : public PDecor { public: class Item : public PWinObjReference { public: enum Type { MENU_ITEM_NORMAL, MENU_ITEM_SEPARATOR, MENU_ITEM_HIDDEN }; Item(const std::wstring &name, PWinObj *wo_ref = 0, PTexture *icon = 0); virtual ~Item(void); inline int getX(void) const { return _x; } inline int getY(void) const { return _y; } inline const std::wstring &getName(void) const { return _name; } inline const ActionEvent &getAE(void) const { return _ae; } inline PTexture *getIcon(void) { return _icon; } inline PMenu::Item::Type getType(void) const { return _type; } inline void setX(int x) { _x = x; } inline void setY(int y) { _y = y; } inline void setName(const std::wstring &name) { _name = name; } inline void setAE(const ActionEvent &ae) { _ae = ae; } inline void setType(PMenu::Item::Type type) { _type = type; } inline void setCreator(PMenu::Item *c) { _creator = c; } inline PMenu::Item *getCreator(void) const { return _creator; } private: int _x, _y; std::wstring _name; ActionEvent _ae; // used for specifying action of the entry PMenu::Item::Type _type; // normal, separator or hidden item PTexture *_icon; // icon texture. PMenu::Item *_creator; /**< pointer to the dynamic action item that created this item. */ }; PMenu(Theme *theme, const std::wstring &title, const std::string &name, const std::string decor_name = "MENU"); virtual ~PMenu(void); // START - PWinObj interface. virtual void unmapWindow(void); virtual void setFocused(bool focused); virtual void setFocusable(bool focusable); virtual ActionEvent *handleButtonPress(XButtonEvent *ev); virtual ActionEvent *handleButtonRelease(XButtonEvent *ev); virtual ActionEvent *handleMotionEvent(XMotionEvent *ev); virtual ActionEvent *handleEnterEvent(XCrossingEvent *ev); virtual ActionEvent *handleLeaveEvent(XCrossingEvent *ev); // END - PWinObj interface. // START - PDecor interface. virtual void loadTheme(void); // END - PDecor interface. static inline PMenu *findMenu(Window win) { std::map::iterator it = _menu_map.find(win); return (it != _menu_map.end()) ? it->second : 0; } inline const std::string &getName(void) { return _name; } inline PMenu::Item *getItemCurr(void) { return _item_curr<_items.size()?_items[_item_curr]:0; } void selectNextItem(void); void selectPrevItem(void); // modifying menu content void setTitle(const std::wstring &title); void setMenuWidth(uint width) { _menu_width = width; } virtual void insert(PMenu::Item *item); virtual void insert(const std::wstring &name, PWinObj *wo_ref = 0, PTexture *icon = 0); virtual void insert(const std::wstring &name, const ActionEvent &ae, PWinObj *wo_ref = 0, PTexture *icon = 0); virtual void remove(PMenu::Item *item); virtual void removeAll(void); virtual void reload(CfgParser::Entry *section) { } void buildMenu(void); inline uint size(void) const { return _items.size(); } inline vector::const_iterator m_begin(void) { return _items.begin(); } inline vector::const_iterator m_end(void) { return _items.end(); } inline MenuType getMenuType(void) const { return _menu_type; } virtual void handleItemExec(PMenu::Item *item) { } // control ( mapping, unmapping etc ) void mapUnderMouse(void); void mapSubmenu(PMenu *menu, bool focus = false); void unmapSubmenus(void); void unmapAll(void); void gotoParentMenu(void); void select(PMenu::Item *item, bool unmap_submenu = true); void selectItem(vector::const_iterator item, bool unmap_submenu = true); void deselectItem(bool unmap_submenu = true); void selectItemNum(uint num); void selectItemRel(int off); void exec(PMenu::Item *item); protected: void checkItemWORef(PMenu::Item *item); private: void handleItemEvent(MouseEventType type, int x, int y); void buildMenuCalculate(void); void buildMenuCalculateMaxWidth(unsigned int &width, unsigned int &height); void buildMenuCalculateColumns(unsigned int &width, unsigned int &height); void buildMenuPlace(void); void buildMenuRender(void); void buildMenuRenderState(Pixmap &pix, ObjectState state); void buildMenuRenderItem(Pixmap pix, ObjectState state, PMenu::Item *item); PMenu::Item *findItem(int x, int y); void makeInsideScreen(int x, int y); void applyTitleRules(const std::wstring &title); protected: std::string _name; //!< Name of menu, must be unique MenuType _menu_type; //!< Type of menu PMenu *_menu_parent; ClassHint _class_hint; /**< Class information for menu. */ // menu content data vector _items; vector::size_type _item_curr; private: static std::map _menu_map; PWinObj *_menu_wo; PDecor::TitleItem _title; // menu render data Pixmap _menu_bg_fo, _menu_bg_un, _menu_bg_se; // menu disp data uint _menu_width; /**< Static set menu width. */ uint _item_height, _item_width_max, _item_width_max_avail; uint _icon_width; uint _icon_height; uint _separator_height; uint _size; // size, hidden items excluded uint _rows, _cols; bool _scroll; bool _has_submenu; }; #endif // _PMENU_HH_ pekwm-release-0.1.18/src/PTexture.hh000066400000000000000000000023301374756504400172470ustar00rootroot00000000000000// // PTexture.cc for pekwm // Copyright (C) 2004-2009 Claes Nasten // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "config.h" #ifndef _PTEXTURE_HH_ #define _PTEXTURE_HH_ #include "pekwm.hh" class PTexture { public: enum Type { TYPE_SOLID, TYPE_SOLID_RAISED, TYPE_IMAGE, TYPE_EMPTY, TYPE_NO }; PTexture() : _ok(false), _width(0), _height(0), _type(PTexture::TYPE_NO) { } virtual ~PTexture(void) { } virtual void render(Drawable draw, int x, int y, uint width, uint height) { } virtual Pixmap getMask(uint width, uint height, bool &do_free) { return None; } inline bool isOk(void) const { return _ok; } inline uint getWidth(void) const { return _width; } inline uint getHeight(void) const { return _height; } inline PTexture::Type getType(void) const { return _type; } inline void setWidth(uint width) { _width = width; } inline void setHeight(uint height) { _height = height; } protected: bool _ok; // Texture successfully loaded uint _width, _height; // for images etc, 0 for infinite like in stretch PTexture::Type _type; // Type of texture }; #endif // _PTEXTURE_HH_ pekwm-release-0.1.18/src/PTexturePlain.cc000066400000000000000000000142231374756504400202250ustar00rootroot00000000000000// // PTexturePlain.cc for pekwm // Copyright © 2004-2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "config.h" #include "PTexture.hh" #include "PTexturePlain.hh" #include "PImage.hh" #include "ImageHandler.hh" #include "x11.hh" using std::string; // PTextureSolid //! @brief PTextureSolid constructor PTextureSolid::PTextureSolid(const std::string &color) : PTexture(), _xc(0) { // PTexture attributes _type = PTexture::TYPE_SOLID; XGCValues gv; gv.function = GXcopy; _gc = XCreateGC(X11::getDpy(), X11::getRoot(), GCFunction, &gv); setColor(color); } //! @brief PTextureSolid destructor PTextureSolid::~PTextureSolid(void) { XFreeGC(X11::getDpy(), _gc); unsetColor(); } // BEGIN - PTexture interface. //! @brief Renders texture on drawable draw void PTextureSolid::render(Drawable draw, int x, int y, uint width, uint height) { if (width == 0) { width = _width; } if (height == 0) { height = _height; } XFillRectangle(X11::getDpy(), draw, _gc, x, y, width, height); } // END - PTexture interface. //! @brief Loads color resources bool PTextureSolid::setColor(const std::string &color) { unsetColor(); // unload used resources _xc = X11::getColor(color); XSetForeground(X11::getDpy(), _gc, _xc->pixel); _ok = true; return _ok; } //! @brief Frees color resources used by texture void PTextureSolid::unsetColor(void) { if (_xc) { X11::returnColor(_xc); _xc = 0; _ok = false; } } // PTextureSolidRaised //! @brief PTextureSolidRaised constructor PTextureSolidRaised::PTextureSolidRaised(const std::string &base, const std::string &hi, const std::string &lo) : PTexture(), _xc_base(0), _xc_hi(0), _xc_lo(0), _lw(1), _loff(0), _loff2(0), _draw_top(true), _draw_bottom(true), _draw_left(true), _draw_right(true) { // PTexture attributes _type = PTexture::TYPE_SOLID_RAISED; XGCValues gv; gv.function = GXcopy; gv.line_width = _lw; _gc = XCreateGC(X11::getDpy(), X11::getRoot(), GCFunction|GCLineWidth, &gv); setColor(base, hi, lo); } //! @brief PTextureSolidRasied destructor PTextureSolidRaised::~PTextureSolidRaised(void) { XFreeGC(X11::getDpy(), _gc); unsetColor(); } // START - PTexture interface. //! @brief Renders texture on drawable draw void PTextureSolidRaised::render(Drawable draw, int x, int y, uint width, uint height) { if (width == 0) { width = _width; } if (height == 0) { height = _height; } // base rectangle XSetForeground(X11::getDpy(), _gc, _xc_base->pixel); XFillRectangle(X11::getDpy(), draw, _gc, x, y, width, height); // hi line ( consisting of two lines ) XSetForeground(X11::getDpy(), _gc, _xc_hi->pixel); if (_draw_top) { XDrawLine(X11::getDpy(), draw, _gc, x + _loff, y + _loff, x + width - _loff - _lw, y + _loff); } if (_draw_left) { XDrawLine(X11::getDpy(), draw, _gc, x + _loff, y + _loff, x + _loff, y + height - _loff - _lw); } // lo line ( consisting of two lines ) XSetForeground(X11::getDpy(), _gc, _xc_lo->pixel); if (_draw_bottom) { XDrawLine(X11::getDpy(), draw, _gc, x + _loff + _lw, y + height - _loff - (_lw ? _lw : 1), x + width - _loff - _lw, y + height - _loff - (_lw ? _lw : 1)); } if (_draw_right) { XDrawLine(X11::getDpy(), draw, _gc, x + width - _loff - (_lw ? _lw : 1), y + _loff + _lw, x + width - _loff - (_lw ? _lw : 1), y + height - _loff - _lw); } } // END - PTexture interface. //! @brief Sets line width void PTextureSolidRaised::setLineWidth(uint lw) { _lw = lw; // This is a hack to be able to rid the spacing lw == 1 does. if (! lw) { lw = 1; } XGCValues gv; gv.line_width = lw; XChangeGC(X11::getDpy(), _gc, GCLineWidth, &gv); } //! @brief Loads color resources bool PTextureSolidRaised::setColor(const std::string &base, const std::string &hi, const std::string &lo) { unsetColor(); // unload used resources _xc_base = X11::getColor(base); _xc_hi = X11::getColor(hi); _xc_lo = X11::getColor(lo); _ok = true; return _ok; } //! @brief Unloads color resources void PTextureSolidRaised::unsetColor(void) { _ok = false; X11::returnColor(_xc_base); X11::returnColor(_xc_hi); X11::returnColor(_xc_lo); _xc_base = _xc_hi = _xc_lo = 0; } // PTextureImage //! @brief PTextureImage constructor PTextureImage::PTextureImage(void) : PTexture(), _image(0) { // PTexture attributes _type = PTexture::TYPE_IMAGE; } //! @brief PTextureImage constructor PTextureImage::PTextureImage(const std::string &image) : PTexture(), _image(0) { // PTexture attributes _type = PTexture::TYPE_IMAGE; setImage(image); } //! @brief PTextureImage destructor PTextureImage::~PTextureImage(void) { unsetImage(); } //! @brief Renders texture on drawable draw void PTextureImage::render(Drawable draw, int x, int y, uint width, uint height) { _image->draw(draw, x, y, width, height); } //! @brief Pixmap PTextureImage::getMask(uint width, uint height, bool &do_free) { return _image->getMask(do_free, width, height); } //! @brief Loads image resources void PTextureImage::setImage(PImage *image) { unsetImage(); _image = image; _width = _image->getWidth(); _height = _image->getHeight(); _ok = true; } //! @brief Loads image resources bool PTextureImage::setImage(const std::string &image) { unsetImage(); _image = ImageHandler::instance()->getImage(image); if (_image) { _width = _image->getWidth(); _height = _image->getHeight(); _ok = true; } else { _ok = false; } return _ok; } //! @brief Unloads image resources void PTextureImage::unsetImage(void) { ImageHandler::instance()->returnImage(_image); _image = 0; _width = 1; _height = 1; _ok = false; } pekwm-release-0.1.18/src/PTexturePlain.hh000066400000000000000000000044431374756504400202420ustar00rootroot00000000000000// // PTexturePlain.hh for pekwm // Copyright © 2004-2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // // $Id$ // #ifndef _PTEXTURE_PLAIN_HH_ #define _PTEXTURE_PLAIN_HH_ #include "config.h" #include #include "pekwm.hh" #include "PTexture.hh" class PImage; // PTextureSolid class PTextureSolid : public PTexture { public: PTextureSolid(const std::string &color); virtual ~PTextureSolid(void); // START - PTexture interface. virtual void render(Drawable draw, int x, int y, uint width, uint height); // END - PTexture interface. inline XColor *getColor(void) { return _xc; } bool setColor(const std::string &color); void unsetColor(void); private: GC _gc; XColor *_xc; }; // PTextureSolidRaised class PTextureSolidRaised : public PTexture { public: PTextureSolidRaised(const std::string &base, const std::string &hi, const std::string &lo); virtual ~PTextureSolidRaised(void); // START - PTexture interface. virtual void render(Drawable draw, int x, int y, uint width, uint height); // END - PTexture interface. inline void setLineOff(uint loff) { _loff = loff; _loff2 = loff * 2; } inline void setDraw(bool top, bool bottom, bool left, bool right) { _draw_top = top; _draw_bottom = bottom; _draw_left = left; _draw_right = right; } void setLineWidth(uint lw); bool setColor(const std::string &base, const std::string &hi, const std::string &lo); void unsetColor(void); private: GC _gc; XColor *_xc_base, *_xc_hi, *_xc_lo; uint _lw, _loff, _loff2; bool _draw_top; bool _draw_bottom; bool _draw_left; bool _draw_right; }; // PTextureImage class PTextureImage : public PTexture { public: PTextureImage(void); PTextureImage(const std::string &image); virtual ~PTextureImage(void); // START - PTexture interface. virtual void render(Drawable draw, int x, int y, uint width, uint height); virtual Pixmap getMask(uint width, uint height, bool &do_free); // END - PTexture interface. bool setImage(const std::string &image); void setImage(PImage *image); void unsetImage(void); private: PImage *_image; }; #endif // _PTEXTURE_PLAIN_HH_ pekwm-release-0.1.18/src/PWinObj.cc000066400000000000000000000131571374756504400167760ustar00rootroot00000000000000// // PWinObj.cc for pekwm // Copyright © 2003-20013 Claes Nästen // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "config.h" #include #include #include "Debug.hh" #include "PWinObj.hh" using std::cerr; using std::endl; using std::find; using std::vector; using std::map; PWinObj* PWinObj::_focused_wo = (PWinObj*) 0; PWinObj* PWinObj::_root_wo = (PWinObj*) 0; vector PWinObj::_wo_list = vector(); map PWinObj::_wo_map = map(); //! @brief PWinObj constructor. PWinObj::PWinObj(bool keyboard_input) : _window(None), _parent(0), _type(WO_NO_TYPE), _lastActivity(X11::getLastEventTime()), _opaque(true), _workspace(0), _layer(LAYER_NORMAL), _mapped(false), _iconified(false), _hidden(false), _focused(false), _sticky(false), _focusable(true), _shape_bounding(false), _shape_input(false), _keyboard_input(keyboard_input) { } //! @brief PWinObj destructor. PWinObj::~PWinObj(void) { if (_focused_wo == this) { _focused_wo = 0; } notifyObservers(0); } //! @brief Sets the desired opacity values for focused/unfocused states void PWinObj::setOpacity(uint focused, uint unfocused, bool enabled) { _opacity.focused = focused; _opacity.unfocused = unfocused; _opaque = !enabled; updateOpacity(); } //! @brief Updates the opacity hint based on focused state void PWinObj::updateOpacity(void) { uint opacity; if (_opaque) { opacity = EWMH_OPAQUE_WINDOW; } else { opacity = isFocused()?_opacity.focused:_opacity.unfocused; } if (_opacity.current != opacity) { _opacity.current = opacity; X11::setLong(_window, NET_WM_WINDOW_OPACITY, opacity); } } //! @brief Maps the window and sets _mapped to true. void PWinObj::mapWindow(void) { if (_mapped) { return; } _mapped = true; _iconified = false; X11::mapWindow(_window); } //! @brief Maps the window and raises it void PWinObj::mapWindowRaised(void) { if (_mapped) { return; } _mapped = true; _iconified = false; XMapRaised(X11::getDpy(), _window); } //! @brief Unmaps the window and sets _mapped to false. void PWinObj::unmapWindow(void) { if (! _mapped) { return; } _mapped = false; // Make sure unmapped windows drops focus setFocused(false); X11::unmapWindow(_window); } //! @brief Only sets _iconified to true. void PWinObj::iconify(void) { if (_iconified) { return; } _iconified = true; } //! @brief Toggles _sticky void PWinObj::stick(void) { _sticky = !_sticky; } //! @brief Returns head PWinObj is on. uint PWinObj::getHead(void) { int x = _gm.x + (_gm.width / 2); int y = _gm.y + (_gm.height / 2); return X11::getNearestHead(x, y); } //! @brief Moves the window and updates _gm. //! @param x X position //! @param y Y position void PWinObj::move(int x, int y) { _gm.x = x; _gm.y = y; XMoveWindow(X11::getDpy(), _window, _gm.x, _gm.y); } //! @brief Resizes the window and updates _gm. void PWinObj::resize(uint width, uint height) { if (! width || ! height) { WARN("width " << width << " height " << height << ", invalid geometry"); return; } _gm.width = width; _gm.height = height; XResizeWindow(X11::getDpy(), _window, _gm.width, _gm.height); } //! @brief Move and resize window in one call. //! @param x X position. //! @param y Y Position. //! @param width Width. //! @param height Height. void PWinObj::moveResize(int x, int y, uint width, uint height) { if (! width || ! height) { WARN("Invalid geometry, width/height not set"); return; } _gm.x = x; _gm.y = y; _gm.width = width; _gm.height = height; XMoveResizeWindow(X11::getDpy(), _window, _gm.x, _gm.y, _gm.width, _gm.height); } //! @brief Only sets _workspace to workspace. void PWinObj::setWorkspace(uint workspace) { _workspace = workspace; } //! @brief Only sets _layer to layer. void PWinObj::setLayer(Layer layer) { _layer = layer; } //! @brief Sets _focused to focused and updates opacity as needed. void PWinObj::setFocused(bool focused) { _focused = focused; updateOpacity(); } //! @brief Only sets _sticky to sticky. void PWinObj::setSticky(bool sticky) { _sticky = sticky; } //! @brief Updates opaque state void PWinObj::setOpaque(bool opaque) { _opaque = opaque; updateOpacity(); } //! @brief Only sets _hidden to hidden. void PWinObj::setHidden(bool hidden) { _hidden = hidden; } //! @brief Executes XSetInputFocus on the appropriate window. void PWinObj::giveInputFocus(void) { if (! _mapped || ! _focusable) { WARN("trying to focus non focusable window. mapped " << _mapped << " focusable " << _focusable); return; } X11::setInputFocus(_window); } //! @brief Reparents and sets _parent member void PWinObj::reparent(PWinObj *wo, int x, int y) { _parent = wo; XReparentWindow(X11::getDpy(), _window, wo->getWindow(), x, y); } //! @brief Get required size to hold content for window //! @param request Geometry filled with size request. //! @return true if geometry is filled in, else false bool PWinObj::getSizeRequest(Geometry &request) { return false; } //! @brief Adds PWinObj to _wo_list. void PWinObj::woListAdd(PWinObj *wo) { _wo_list.push_back(wo); } //! @brief Remove PWinObj from _wo_list. void PWinObj::woListRemove(PWinObj *wo) { vector::iterator it(find(_wo_list.begin(), _wo_list.end(), wo)); if (it != _wo_list.end()) { _wo_list.erase(it); } } pekwm-release-0.1.18/src/PWinObj.hh000066400000000000000000000255411374756504400170100ustar00rootroot00000000000000// // PWinObj.hh for pekwm // Copyright © 2003-2013 Claes Nästen // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifndef _PWIN_OBJ_HH_ #define _PWIN_OBJ_HH_ #include "config.h" #include #include #include "pekwm.hh" #include "x11.hh" #include "Action.hh" #include "Observable.hh" //! @brief X11 Window wrapper class. class PWinObj : public Observable { public: //! @brief PWinObj inherited types. enum Type { WO_FRAME = (1<<1), //!< Frame type. WO_CLIENT = (1<<2), //!< Client type. WO_MENU = (1<<3), //!< PMenu type. WO_DOCKAPP = (1<<4), //!< DockApp type. WO_SCREEN_EDGE = (1<<5), //!< ScreenEdge type. WO_SCREEN_ROOT = (1<<6), //!< PWinObj type for root Window. WO_CMD_DIALOG = (1<<7), //!< CmdDialog type. WO_STATUS = (1<<8), //!< StatusWindow type. WO_WORKSPACE_INDICATOR = (1<<9), //!< WorkspaceIndicator type. WO_SCREEN_HINT = (1<<10), /**< Invisible hint window. */ WO_SEARCH_DIALOG = (1<<11), //!< SearchDialog type WO_NO_TYPE = 0 //!< No type. }; PWinObj(bool keyboard_input); virtual ~PWinObj(void); //! @brief Returns the focused PWinObj. static inline PWinObj *getFocusedPWinObj(void) { return _focused_wo; } //! @brief Returns the PWinObj representing the root Window. static inline PWinObj *getRootPWinObj(void) { return _root_wo; } //! @brief Sets the focused PWinObj. static inline void setFocusedPWinObj(PWinObj *wo) { _focused_wo = wo; } //! @brief Sets the PWinObj representing the root Window. static inline void setRootPWinObj(PWinObj *wo) { _root_wo = wo; } //! @brief Checks if focused window is of type static inline bool isFocusedPWinObj(Type type) { return _focused_wo ? _focused_wo->getType() == type : false; } //! @brief Searches for the PWinObj matching Window win. //! @param win Window to match PWinObjs against. //! @return PWinObj pointer on match, else 0. static inline PWinObj *findPWinObj(Window win) { std::map::iterator it(_wo_map.find(win)); return (it != _wo_map.end()) ? it->second : 0; } //! @brief Searches in PWinObj list if PWinObj wo exists. //! @param wo PWinObj to search for. //! @return true if found, else false. static inline bool windowObjectExists(PWinObj *wo) { vector::iterator it = std::find(_wo_list.begin(), _wo_list.end(), wo); if (it != _wo_list.end()) return true; return false; } //! @brief Return Window this PWinObj represents. inline Window getWindow(void) const { return _window; } //! @brief Sets Window this PWinObj represents. inline void setWindow(Window window) { _window = window; } //! @brief Returns parent PWinObj. inline PWinObj *getParent(void) const { return _parent; } //! @brief Sets parent PWinObj. inline void setParent(PWinObj *wo) { _parent = wo; } //! @brief Returns type of PWinObj. inline Type getType(void) const { return _type; } //! @brief Returns the last activity time for this window inline Time getLastActivity(void) const { return _lastActivity; } //! @brief Sets the last activity time for this window. inline void setLastActivity(Time lastActivity) { _lastActivity = lastActivity; } inline void addChildWindow(Window win) { _wo_map[win] = this; } inline void removeChildWindow(Window win) { _wo_map.erase(win); } //! @brief Returns x coordinate of PWinObj. inline int getX(void) const { return _gm.x; } //! @brief Returns y coordinate of PWinObj. inline int getY(void) const { return _gm.y; } //! @brief Returns right edge x coordinate of PWinObj. inline int getRX(void) const { return _gm.x + _gm.width; } //! @brief Returns bottom edge y coordinate of PWinObj. inline int getBY(void) const { return _gm.y + _gm.height; } //! @brief Returns width of PWinObj. inline uint getWidth(void) const { return _gm.width; } //! @brief Returns height of PWinObj: inline uint getHeight(void) const { return _gm.height; } //! @brief Sets gm to geometry of window. inline void getGeometry(Geometry &gm) const { gm = _gm; } uint getHead(void); //! @brief Returns workspace PWinObj is on. inline uint getWorkspace(void) const { return _workspace; } /** @brief Returns layer PWinObj is in. */ inline Layer getLayer(void) const { return _layer; } //! @brief Returns mapped state of PWinObj. inline bool isMapped(void) const { return _mapped; } //! @brief Returns iconofied state of PWinObj. inline bool isIconified(void) const { return _iconified; } //! @brief Returns hidden state of PWinObj. inline bool isHidden(void) const { return _hidden; } //! @brief Returns focused state of PWinObj. inline bool isFocused(void) const { return _focused; } //! @brief Returns sticky state of PWinObj. inline bool isSticky(void) const { return _sticky; } //! @brief Returns Focusable state of PWinObj. inline bool isFocusable(void) const { return _focusable; } //! @brief Returns true if the PWinObj is interested in keyboard input inline bool isKeyboardInput(void) const { return _keyboard_input; } //! @brief Returns transparency state of PWinObj inline bool isOpaque(void) const { return _opaque; } void setOpacity(uint focused, uint unfocused, bool enabled=true); inline void setOpacity(uint value) { setOpacity(value, value); } inline void setOpacity(PWinObj *child) { setOpacity(child->_opacity.focused, child->_opacity.unfocused, !child->_opaque); } void updateOpacity(void); void setOpaque(bool opaque); //! Returns true if a custom region of kind @kind (ShapeBounding //! or ShapeInput) was set via the shape extension for this window. inline bool hasShapeRegion(int kind) const { #ifdef HAVE_SHAPE if (kind == ShapeBounding) { return _shape_bounding; } else if (kind == ShapeInput) { return _shape_input; } #endif return false; } // interface virtual void mapWindow(void); virtual void mapWindowRaised(void); virtual void unmapWindow(void); virtual void iconify(void); virtual void stick(void); virtual void move(int x, int y); virtual void resize(uint width, uint height); virtual void moveResize(int x, int y, uint width, uint height); //! @brief Raises PWinObj without respect of layer. virtual void raise(void) { XRaiseWindow(X11::getDpy(), _window); } //! @brief Lowers PWinObj without respect of layer. virtual void lower(void) { XLowerWindow(X11::getDpy(), _window); } virtual void setWorkspace(uint workspace); virtual void setLayer(Layer layer); virtual void setFocused(bool focused); virtual void setSticky(bool sticky); /** Set focusable flag. */ virtual void setFocusable(bool focusable) { _focusable = focusable; } virtual void setHidden(bool hidden); virtual void giveInputFocus(void); virtual void reparent(PWinObj *parent, int x, int y); virtual bool getSizeRequest(Geometry &request); // event interface //! @brief Handles button press events, always return 0. virtual ActionEvent *handleButtonPress(XButtonEvent *ev) { return 0; } //! @brief Handles button release events, always return 0. virtual ActionEvent *handleButtonRelease(XButtonEvent *ev) { return 0; } //! @brief Handles key press events, always return 0. virtual ActionEvent *handleKeyPress(XKeyEvent *ev) { return 0; } //! @brief Handles key release vents, always return 0. virtual ActionEvent *handleKeyRelease(XKeyEvent *ev) { return 0; } //! @brief Handles motion events, always return 0. virtual ActionEvent *handleMotionEvent(XMotionEvent *ev) { return 0; } //! @brief Handles enter events, always return 0. virtual ActionEvent *handleEnterEvent(XCrossingEvent *ev) { return 0; } //! @brief Handles leave events, always return 0. virtual ActionEvent *handleLeaveEvent(XCrossingEvent *ev) { return 0; } //! @brief Handles expose events, always return 0. virtual ActionEvent *handleExposeEvent(XExposeEvent *ev) { return 0; } //! @brief Handles handle map request events, always return 0. virtual ActionEvent *handleMapRequest(XMapRequestEvent *ev) { return 0; } //! @brief Handles handle unmap events, always return 0. virtual ActionEvent *handleUnmapEvent(XUnmapEvent *ev) { return 0; } // operators //! @brief Operator matching against Window PWinObj represents.. virtual bool operator == (const Window &window) { return (_window == window); } //! @brief Operator matching against Window PWinObj represents. virtual bool operator != (const Window &window) { return (_window != window); } // other window commands //! @brief Clears Window causing a redraw. inline void clear(void) { XClearWindow(X11::getDpy(), _window); } //! @brief Sets Window background colour. inline void setBackground(long pixel) { XSetWindowBackground(X11::getDpy(), _window, pixel); } //! @brief Sets Window background pixmap. inline void setBackgroundPixmap(Pixmap pm) { XSetWindowBackgroundPixmap(X11::getDpy(), _window, pm); } protected: static void woListAdd(PWinObj *wo); static void woListRemove(PWinObj *wo); protected: Window _window; //!< Window PWinObj represents. PWinObj *_parent; //!< Parent PWinObj. Type _type; //!< Type of PWinObj. Time _lastActivity; //!< Last time PWinObj received input. // Opacity information class Opacity { public: Opacity(void) : current(EWMH_OPAQUE_WINDOW), focused(EWMH_OPAQUE_WINDOW), unfocused(EWMH_OPAQUE_WINDOW) { } uint current, focused, unfocused; } _opacity; bool _opaque; //!< Opaque set state of PWinObj Geometry _gm; //!< Geometry of PWinObj (always in absolute coordinates). uint _workspace; //!< Workspace PWinObj is on. Layer _layer; //!< Layer PWinObj is in. bool _mapped:1; //!< Mapped state of PWinObj. bool _iconified:1; //!< Iconified state of PWinObj. bool _hidden:1; //!< Hidden state of PWinObj. bool _focused:1; //!< Focused state of PWinObj. bool _sticky:1; //!< Sticky state of PWinObj. bool _focusable:1; //!< Focusable state of PWinObj. bool _shape_bounding:1; //!< _window has a custom bounding region (shape) bool _shape_input:1; //!< _window has a custom input region (shape) bool _keyboard_input:1; //!< PWinObj is consuming keyboard input. static PWinObj *_root_wo; //!< Static root PWinObj pointer. static PWinObj *_focused_wo; //!< Static focused PWinObj pointer. static vector _wo_list; //!< List of PWinObjs. static std::map _wo_map; //!< Mapping of Window to PWinObj }; #endif // _PWIN_OBJ_HH_ pekwm-release-0.1.18/src/PWinObjReference.cc000066400000000000000000000013671374756504400206150ustar00rootroot00000000000000// // PWinObjReference.cc for pekwm // Copyright © 2009 Claes Nästen // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "config.h" #include "PWinObjReference.hh" /** * Construct new window reference. */ PWinObjReference::PWinObjReference(PWinObj *wo_ref) : _wo_ref(0) { setWORef(wo_ref); } /** * Destruct refernce, remove observer. */ PWinObjReference::~PWinObjReference(void) { setWORef(0); } /** * Set the window reference and update observer. */ void PWinObjReference::setWORef(PWinObj *wo_ref) { if (_wo_ref != 0) { _wo_ref->removeObserver(this); } _wo_ref = wo_ref; if (_wo_ref != 0) { _wo_ref->addObserver(this); } } pekwm-release-0.1.18/src/PWinObjReference.hh000066400000000000000000000015601374756504400206220ustar00rootroot00000000000000// // PWinObjReference.hh for pekwm // Copyright © 2009 Claes Nästen // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifndef _PWIN_OBJ_REFERENCE_HH_ #define _PWIN_OBJ_REFERENCE_HH_ #include "config.h" #include "PWinObj.hh" #include "Observer.hh" class PWinObjReference : public Observer { public: PWinObjReference(PWinObj *wo_ref=0); virtual ~PWinObjReference(void); /** Notify about reference update, unset the reference. */ virtual void notify(Observable *observable, Observation *observation) { _wo_ref = 0; } /** Returns the PWinObj reference. */ PWinObj *getWORef(void) { return _wo_ref; } /** Sets the PWinObj reference. */ void setWORef(PWinObj *wo_ref); private: PWinObj *_wo_ref; /**< Window object reference. */ }; #endif // _PWIN_OBJ_REFERENCE_HH_ pekwm-release-0.1.18/src/ParseUtil.hh000066400000000000000000000030541374756504400174030ustar00rootroot00000000000000// // ParseUtil.hh for pekwm // Copyright © 2004-2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifndef _PARSE_UTIL_HH_ #define _PARSE_UTIL_HH_ #include "config.h" #include #include #include extern "C" { #include } namespace ParseUtil { class Entry { public: Entry(const char *text) : _text(text) { } // hacky, but we don't want to loose speed do we? Entry(const std::string &text) : _text(text.c_str()) { } ~Entry(void) { } /** Get text version of string. */ inline const char *get_text(void) const { return _text; } // operators inline bool operator==(const std::string &rhs) const { return (strcasecmp(rhs.c_str(), _text) == 0); } inline bool operator!=(const std::string &rhs) const { return (strcasecmp(rhs.c_str(), _text) != 0); } // < > needed for map searching inline bool operator<(const ParseUtil::Entry &rhs) const { return (strcasecmp(_text, rhs._text) < 0); } inline bool operator>(const ParseUtil::Entry &rhs) const { return (strcasecmp(_text, rhs._text) > 0); } private: const char *_text; }; //! @brief Finds item in map, returns "" in map if not found template inline T getValue(const std::string &text, typename std::map &val) { typename std::map::iterator it = val.find(text); return (it != val.end()) ? it->second : val[""]; } } #endif // _PARSE_UTIL_HH_ pekwm-release-0.1.18/src/RegexString.cc000066400000000000000000000143421374756504400177240ustar00rootroot00000000000000// // RegexString.cc for pekwm // Copyright © 2003-2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "config.h" #include #include #include "RegexString.hh" #include "Util.hh" using std::vector; using std::cerr; using std::endl; using std::string; using std::wstring; using std::strtol; const char RegexString::SEPARATOR = '/'; //! @brief RegexString constructor. RegexString::RegexString(void) : _reg_ok(false), _reg_inverted(false), _ref_max(1) { } //! @brief RegexString constructor with default search RegexString::RegexString(const std::wstring &str, bool full) : _reg_ok(false), _reg_inverted(false), _ref_max(1) { parse_match(str, full); } //! @brief RegexString destructor. RegexString::~RegexString(void) { free_regex(); } //! @brief Simple ed s command lookalike. bool RegexString::ed_s(std::wstring &str) { if (! _reg_ok) { return false; } string mb_str(Util::to_mb_str(str)); const char *c_str = mb_str.c_str(); regmatch_t *matches = new regmatch_t[_ref_max]; // Match if (regexec(&_regex, mb_str.c_str(), _ref_max, matches, 0)) { delete [] matches; return false; } string result; uint ref, size; vector::iterator it(_refs.begin()); for (; it != _refs.end(); ++it) { if (it->get_reference() >= 0) { ref = it->get_reference(); if (matches[ref].rm_so != -1) { size = matches[ref].rm_eo - matches[ref].rm_so; result.append(string(c_str + matches[ref].rm_so, size)); } } else { result.append(Util::to_mb_str(it->get_string())); } } // Replace area regexp matched. size = matches[0].rm_eo - matches[0].rm_so; mb_str.replace(matches[0].rm_so, size, result); str = Util::to_wide_str(mb_str); return true; } //! @brief Parses match part of regular expression. //! @param match Expression. //! @param full Full expression if true (including flags). Defaults to false. bool RegexString::parse_match(const std::wstring &match, bool full) { // Free resources if (_reg_ok) { free_regex(); } if (match.size()) { int flags = REG_EXTENDED; string expression; wstring expression_str; // Full regular expression syntax, parse out flags etc string::size_type pos; if (match[0] == SEPARATOR && (pos = match.find_last_of(SEPARATOR)) != string::npos) { // Main expression expression_str = match.substr(1, pos - 1); // Expression flags for (string::size_type i = pos + 1; i < match.size(); ++i) { switch (match[i]) { case 'i': flags |= REG_ICASE; break; case '!': _reg_inverted = true; break; default: cerr << "Invalid flag \"" << match[i] << "\" for regular expression." << endl; break; } } expression = Util::to_mb_str(expression_str); } else { if (full) { cerr << "Invalid format of regular expression, missing separator " << SEPARATOR << endl; } expression = Util::to_mb_str(match); } _reg_ok = ! regcomp(&_regex, expression.c_str(), flags); } else { _reg_ok = false; } return _reg_ok; } //! @brief Parses replace part of ed_s command. //! Expects input in the style of /replace/me/. / can be any character //! except \. References to sub expressions are made with \num. \0 Represents //! the part of the string that matched. bool RegexString::parse_replace(const std::wstring &replace) { _ref_max = 0; wstring part; wstring::size_type begin = 0, end = 0, last = 0; // Go through the string and split at \num points while ((end = replace.find_first_of('\\', begin)) != string::npos) { // Store string between references. if (end > last) { part = replace.substr(last, end - last); _refs.push_back(RegexString::Part(part)); } // Get reference number. for (begin = ++end; isdigit(replace[end]); end++) ; if (end > begin) { // Convert number and add item. part = replace.substr(begin, end - last); int ref = strtol(Util::to_mb_str(part).c_str(), 0, 10); if (ref >= 0) { _refs.push_back(RegexString::Part(L"", ref)); if (ref > _ref_max) { _ref_max = ref; } } } last = end; begin = last + 1; } if (begin < replace.size()) { part = replace.substr(begin, replace.size() - begin); _refs.push_back(RegexString::Part(part)); } _ref_max++; return true; } //! @brief Parses ed s style command. /from/to/ bool RegexString::parse_ed_s(const std::wstring &ed_s) { if (ed_s.size() < 3) { return false; } wchar_t c_delimeter = ed_s[0]; string::size_type middle, end; // Middle. for (middle = 1; middle < ed_s.size(); middle++) { if ((ed_s[middle] == c_delimeter) && (ed_s[middle - 1] != '\\')) { break; } } // End. for (end = middle + 1; end < ed_s.size(); end++) { if ((ed_s[end] == c_delimeter) && (ed_s[end - 1] != '\\')) { break; } } wstring match, replace; match = ed_s.substr(1, middle - 1); replace = ed_s.substr(middle + 1, end - middle - 1); parse_match(match); parse_replace(replace); return true; } //! @brief Matches RegexString against rhs, needs successfull parse_match. bool RegexString::operator==(const std::wstring &rhs) { if (! _reg_ok) { return false; } string mb_rhs(Util::to_mb_str(rhs)); bool match = ! regexec(&_regex, mb_rhs.c_str(), 0, 0, 0); return _reg_inverted ? ! match : match; } //! @brief Free resources used by RegexString. void RegexString::free_regex(void) { if (_reg_ok) { regfree(&_regex); _reg_ok = false; } _reg_inverted = false; } pekwm-release-0.1.18/src/RegexString.hh000066400000000000000000000041301374756504400177300ustar00rootroot00000000000000// // RegexString.hh for pekwm // Copyright © 2003-2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifndef _REGEX_STRING_HH_ #define _REGEX_STRING_HH_ #include "config.h" #include #include extern "C" { #include #include } #include "Types.hh" //! @brief POSIX regular expression wrapper. class RegexString { public: //! @brief Part of parsed replace data. class Part { public: //! @brief RegexString::Part constructor. Part(const std::wstring &str, int ref = -1) : _string(str), _ref(ref) { } //! @brief RegexString::Part destructor. ~Part(void) { } //! @brief Returns string data. const std::wstring &get_string(void) { return _string; } //! @brief Returns reference number. int get_reference(void) { return _ref; } private: std::wstring _string; //!< String data at item. int _ref; //!< Reference string should be replaced with. }; RegexString(void); RegexString(const std::wstring &string, bool full = false); ~RegexString(void); //! @brief Returns parse_match data status. bool is_match_ok(void) { return _reg_ok; } bool ed_s(std::wstring &str); bool parse_match(const std::wstring &match, bool full = false); bool parse_replace(const std::wstring &replace); bool parse_ed_s(const std::wstring &ed_s); bool operator==(const std::wstring &rhs); private: RegexString(const RegexString &); RegexString &operator=(const RegexString &); void free_regex (void); private: regex_t _regex; //!< Compiled regular expression holder. bool _reg_ok; //!< _regex compiled ok flag. bool _reg_inverted; /**< If true, a non-matching regexp is considered a match. */ int _ref_max; //!< Highest reference used. std::vector _refs; //!< Vector of RegexString::Part holding data generated by parse_replace. static const char SEPARATOR; /**< Regular expression seperator. */ }; #endif // _REGEX_STRING_HH_ pekwm-release-0.1.18/src/SearchDialog.cc000066400000000000000000000104141374756504400200040ustar00rootroot00000000000000// // SearchDialog.cc for pekwm // Copyright © 2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "config.h" #include "SearchDialog.hh" #include "Client.hh" #include "RegexString.hh" #include #include using std::cerr; using std::endl; using std::list; using std::wcerr; /** * SearchDialog constructor. */ SearchDialog::SearchDialog(Theme *theme) : InputDialog(theme, L"Search"), _result_menu(0) { _type = PWinObj::WO_SEARCH_DIALOG; // Set up ActionEvent _ae.action_list.back().setAction(ACTION_GOTO_CLIENT); // Set up menu for displaying results _result_menu = new PMenu(_theme, L"", ""); _result_menu->reparent(this, borderLeft(), borderTop() + getTitleHeight() + _text_wo->getHeight()); _result_menu->setLayer(LAYER_DESKTOP); // Ignore when placing _result_menu->setSticky(STATE_SET); _result_menu->setBorder(STATE_UNSET); _result_menu->setTitlebar(STATE_UNSET); _result_menu->setFocusable(false); _result_menu->mapWindow(); } /** * SearchDialog destructor. */ SearchDialog::~SearchDialog(void) { delete _result_menu; } /** * Run when INPUT_EXEC is entered in the dialog giving the selected * Client focus if any. */ ActionEvent* SearchDialog::exec(void) { // InputDialog::close() may have overwritten our action. _ae.action_list.back().setAction(ACTION_GOTO_CLIENT); PWinObj *wo_ref = 0; if (_result_menu->getItemCurr()) { wo_ref = _result_menu->getItemCurr()->getWORef(); } setWORef(wo_ref); return &_ae; } /** * Called whenever the buffer has changed. Updates the displayed clients. */ void SearchDialog::bufChanged(void) { InputDialog::bufChanged(); findClients(_buf); } /** * Focus next item in result menu. */ void SearchDialog::histNext(void) { _result_menu->selectItemRel(1); } /** * Focus previous item in result menu. */ void SearchDialog::histPrev(void) { _result_menu->selectItemRel(-1); } /** * Update size making sure result menu fits. */ void SearchDialog::updateSize(const Geometry &head) { InputDialog::updateSize(head); _result_menu->setMenuWidth(_text_wo->getWidth()); } /** * Search list of clients for matching titles. * * @param search Regexp to search, case insensitive * @return Number of matches */ uint SearchDialog::findClients(const std::wstring &search) { // Do nothing if search has not changed. if (_previous_search == search) { return _result_menu->size(); } _previous_search = search; _result_menu->removeAll(); if (search.size() > 0) { RegexString search_re(L"/" + search + L"/i"); if (! search_re.is_match_ok()) { return 0; } vector matches; vector::const_iterator it(Client::client_begin()); for (; it != Client::client_end(); ++it) { if ((*it)->isFocusable() && ! (*it)->isSkip(SKIP_FOCUS_TOGGLE) && search_re == (*it)->getTitle()->getReal()) { matches.push_back(*it); } } for (it = matches.begin(); it != matches.end(); ++it) { _result_menu->insert((*it)->getTitle()->getVisible(), *it, (*it)->getIcon()); } } // Rebuild menu and make room for it _result_menu->buildMenu(); Geometry head; X11::getHeadInfo(getHead(), head); unsigned int width, height; getInputSize(head, width, height); if (_result_menu->size()) { resizeChild(_text_wo->getWidth(), height + _result_menu->getHeight()); XRaiseWindow(X11::getDpy(), _result_menu->getWindow()); // Render first item as selected, needs to be done after map/raise. _result_menu->selectItemNum(0); } else { resizeChild(_text_wo->getWidth(), height); XLowerWindow(X11::getDpy(), _result_menu->getWindow()); } return 0; } /** * Unmap window and clear buffer, result menu and window reference. */ void SearchDialog::unmapWindow(void) { if (_mapped) { InputDialog::unmapWindow(); setWORef(0); bufClear(); // Clear the menu and hide it. _result_menu->clear(); _previous_search.clear(); XLowerWindow(X11::getDpy(), _result_menu->getWindow()); } } pekwm-release-0.1.18/src/SearchDialog.hh000066400000000000000000000020701374756504400200150ustar00rootroot00000000000000// // SearchDialog.cc for pekwm // Copyright © 2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifndef _SEARCH_DIALOG_HH_ #define _SEARCH_DIALOG_HH_ #include "config.h" #include "pekwm.hh" #include "InputDialog.hh" #include "Theme.hh" #include "PMenu.hh" #include /** * Search dialog providing a dialog for searching clients together * with a menu that shows clients matching the search. */ class SearchDialog : public InputDialog { public: SearchDialog(Theme *theme); virtual ~SearchDialog(void); void unmapWindow(void); protected: virtual ActionEvent *exec(void); virtual void bufChanged(void); virtual void histNext(void); virtual void histPrev(void); virtual void updateSize(const Geometry &head); private: uint findClients(const std::wstring &search); PMenu *_result_menu; /**< Menu for displaying results. */ std::wstring _previous_search; /**< Buffer with previous search string. */ }; #endif // _SEARCH_DIALOG_HH_ pekwm-release-0.1.18/src/StatusWindow.cc000066400000000000000000000066171374756504400201440ustar00rootroot00000000000000// // StatusWindow.cc for pekwm // Copyright © 2004-2016 the pekwm development team // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "config.h" #include "Debug.hh" #include "PWinObj.hh" #include "PDecor.hh" #include "StatusWindow.hh" #include "x11.hh" #include "PTexture.hh" #include "Theme.hh" #include "Workspaces.hh" #include StatusWindow *StatusWindow::_instance = 0; //! @brief StatusWindow constructor StatusWindow::StatusWindow(Theme *theme) : PDecor(theme, "STATUSWINDOW"), _bg(None) { if (_instance) { ERR("_instance already set: " << _instance); } _instance = this; // PWinObj attributes _type = PWinObj::WO_STATUS; setLayer(LAYER_NONE); // hack, goes over LAYER_MENU _hidden = true; // don't care about it when changing worskpace etc XSetWindowAttributes attr; attr.event_mask = None; _status_wo = new PWinObj(false); _status_wo->setWindow(XCreateWindow(X11::getDpy(), _window, 0, 0, 1, 1, 0, CopyFromParent, CopyFromParent, CopyFromParent, CWEventMask, &attr)); addChild(_status_wo); activateChild(_status_wo); _status_wo->mapWindow(); setTitlebar(STATE_UNSET); setFocused(true); // always draw as focused Workspaces::insert(this); } //! @brief StatusWindow destructor StatusWindow::~StatusWindow(void) { Workspaces::remove(this); // remove ourself from the decor manually, no need to reparent and stuff _children.erase(std::remove(_children.begin(), _children.end(), _status_wo), _children.end()); // free resources XDestroyWindow(X11::getDpy(), _status_wo->getWindow()); delete _status_wo; unloadTheme(); _instance = 0; } void StatusWindow::draw(const std::wstring &text, bool center, const Geometry *gm) { uint width, height; PFont *font = _theme->getStatusData()->getFont(); // convenience width = font->getWidth(text.c_str()) + 10; width = width - (width % 10); height = font->getHeight() + _theme->getStatusData()->getPad(PAD_UP) + _theme->getStatusData()->getPad(PAD_DOWN); if ((width != getChildWidth()) || (height != getChildHeight())) { resizeChild(width, height); render(); } if (center) { Geometry head; if (! gm) { X11::getHeadInfo(X11::getCurrHead(), head); gm = &head; } move(gm->x + (gm->width - _gm.width) / 2, gm->y + (gm->height - _gm.height) / 2); } font->setColor(_theme->getStatusData()->getColor()); _status_wo->clear(); font->draw(_status_wo->getWindow(), (width - font->getWidth(text.c_str())) / 2, _theme->getStatusData()->getPad(PAD_UP), text.c_str()); } //! @brief Renders and sets background void StatusWindow::loadTheme(void) { render(); } //! @brief Frees theme resources void StatusWindow::unloadTheme(void) { X11::freePixmap(_bg); } //! @brief Renders and sets background void StatusWindow::render(void) { X11::freePixmap(_bg); _bg = X11::createPixmap(_status_wo->getWidth(), _status_wo->getHeight()); _theme->getStatusData()->getTexture()->render(_bg, 0, 0, _status_wo->getWidth(), _status_wo->getHeight()); _status_wo->setBackgroundPixmap(_bg); _status_wo->clear(); } pekwm-release-0.1.18/src/StatusWindow.hh000066400000000000000000000022371374756504400201500ustar00rootroot00000000000000// // StatusWindow.hh for pekwm // Copyright © 2004-2009 Claes Nasten // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifndef _STATUS_WINDOW_HH_ #define _STATUS_WINDOW_HH_ #include "config.h" #include #include #include "pekwm.hh" class PDecor; //! @brief Status display window. class StatusWindow : public PDecor { public: StatusWindow(Theme *theme); virtual ~StatusWindow(void); //! @brief Returns the StatusWindow instance pointer. static StatusWindow *instance(void) { return _instance; } void drawGeometry(const Geometry &gm, bool center_root) { wchar_t buf[128]; swprintf(buf, 128, L"%dx%d+%d+%d", gm.width, gm.height, gm.x, gm.y); draw(buf, true, center_root?0:&gm); } void draw(const std::wstring &text, bool center=false, const Geometry *gm = 0); private: // BEGIN - PDecor interface virtual void loadTheme(void); // END - PDecor interface void unloadTheme(void); void render(void); private: PWinObj *_status_wo; Pixmap _bg; static StatusWindow *_instance; }; #endif // _STATUS_WINDOW_HH_ pekwm-release-0.1.18/src/TextureHandler.cc000066400000000000000000000144271374756504400204250ustar00rootroot00000000000000// // TextureHandler.cc for pekwm // Copyright © 2004-2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "config.h" #include "PTexture.hh" #include "TextureHandler.hh" #include "x11.hh" #include "PTexturePlain.hh" #include "Util.hh" #include using std::vector; using std::map; using std::string; using std::cerr; using std::endl; TextureHandler* TextureHandler::_instance = 0; map TextureHandler::_parse_map = map(); const int TextureHandler::LENGTH_MIN = 5; //! @brief TextureHandler constructor TextureHandler::TextureHandler(void) { #ifdef DEBUG if (_instance) { cerr << __FILE__ << "@" << __LINE__ << ": " << "TextureHandler(" << this << ")::TextureHandler()" << " *** _instance already set: " << _instance << endl; } #endif // DEBUG _instance = this; // fill parse map with values _parse_map[""] = PTexture::TYPE_NO; _parse_map["SOLID"] = PTexture::TYPE_SOLID; _parse_map["SOLIDRAISED"] = PTexture::TYPE_SOLID_RAISED; _parse_map["IMAGE"] = PTexture::TYPE_IMAGE; _parse_map["EMPTY"] = PTexture::TYPE_EMPTY; } //! @brief TextureHandler destructor TextureHandler::~TextureHandler(void) { _instance = 0; } //! @brief Gets or creates a PTexture PTexture* TextureHandler::getTexture(const std::string &texture) { // check for already existing entry vector::const_iterator it(_textures.begin()); for (; it != _textures.end(); ++it) { if (*(*it) == texture) { (*it)->incRef(); return (*it)->getTexture(); } } // parse texture PTexture *ptexture = parse(texture); if (ptexture) { // create new entry TextureHandler::Entry *entry = new TextureHandler::Entry(texture, ptexture); entry->incRef(); _textures.push_back(entry); } return ptexture; } //! @brief Add/Increment reference cont for texture. //! @return Pointer to texture referenced. PTexture* TextureHandler::referenceTexture(PTexture *texture) { // Check for already existing entry vector::const_iterator it(_textures.begin()); for (; it != _textures.end(); ++it) { if ((*it)->getTexture() == texture) { (*it)->incRef(); return texture; } } // Create new entry TextureHandler::Entry *entry = new TextureHandler::Entry("", texture); entry->incRef(); _textures.push_back(entry); return texture; } //! @brief Returns a texture void TextureHandler::returnTexture(PTexture *texture) { bool found = false; vector::iterator it(_textures.begin()); for (; it != _textures.end(); ++it) { if ((*it)->getTexture() == texture) { found = true; (*it)->decRef(); if ((*it)->getRef() == 0) { delete *it; _textures.erase(it); } break; } } if (! found) { delete texture; } } //! @brief Parses the string, and creates a texture PTexture* TextureHandler::parse(const std::string &texture) { PTexture *ptexture = 0; vector tok; PTexture::Type type; if (Util::splitString(texture, tok, " \t")) { type = ParseUtil::getValue(tok[0], _parse_map); } else { type = ParseUtil::getValue(texture, _parse_map); } // need at least type and parameter, except for EMPTY type if (tok.size() > 1) { tok.erase(tok.begin()); // remove type switch (type) { case PTexture::TYPE_SOLID: ptexture = parseSolid(tok); break; case PTexture::TYPE_SOLID_RAISED: ptexture = parseSolidRaised(tok); break; case PTexture::TYPE_IMAGE: ptexture = new PTextureImage(texture.substr(6)); // 6==strlen("IMAGE ") if (! ptexture->isOk()) { string::size_type pos = texture.find_first_not_of(" \t", 6); static_cast(ptexture)->setImage(texture.substr(pos)); } break; case PTexture::TYPE_NO: default: break; } // If it fails to load, set clean resources and set it to 0. if (ptexture && ! ptexture->isOk()) { delete ptexture; ptexture = 0; } } else if (type == PTexture::TYPE_EMPTY) { ptexture = new PTexture; } return ptexture; } //! @brief Parse and create PTextureSolid PTexture* TextureHandler::parseSolid(std::vector &tok) { if (tok.size() < 1) { cerr << "*** WARNING: not enough parameters to texture Solid" << endl; return 0; } PTextureSolid *tex = new PTextureSolid(tok[0]); tok.erase(tok.begin()); // check if we have size if (tok.size() == 1) { parseSize(tex, tok[0]); } return tex; } //! @brief Parse and create PTextureSolidRaised PTexture* TextureHandler::parseSolidRaised(std::vector &tok) { if (tok.size() < 3) { cerr << "*** WARNING: not enough parameters to texture SolidRaised" << endl; return 0; } PTextureSolidRaised *tex = new PTextureSolidRaised(tok[0], tok[1], tok[2]); tok.erase(tok.begin(), tok.begin() + 3); // Check if we have line width and offset. if (tok.size() > 2) { tex->setLineWidth(strtol(tok[0].c_str(), 0, 10)); tex->setLineOff(strtol(tok[1].c_str(), 0, 10)); tok.erase(tok.begin(), tok.begin() + 2); } // Check if have side draw specified. if (tok.size() > 4) { tex->setDraw(Util::isTrue(tok[0]), Util::isTrue(tok[1]), Util::isTrue(tok[2]), Util::isTrue(tok[3])); tok.erase(tok.begin(), tok.begin() + 4); } // Check if we have size if (tok.size() == 1) { parseSize(tex, tok[0]); } return tex; } //! @brief Parses size parameter, i.e. 10x20 void TextureHandler::parseSize(PTexture *tex, const std::string &size) { vector tok; if ((Util::splitString(size, tok, "x", 2, true)) == 2) { tex->setWidth(strtol(tok[0].c_str(), 0, 10)); tex->setHeight(strtol(tok[1].c_str(), 0, 10)); } } pekwm-release-0.1.18/src/TextureHandler.hh000066400000000000000000000035351374756504400204350ustar00rootroot00000000000000// // TextureHandler.hh for pekwm // Copyright © 2005 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifndef _TEXTURE_HANDLER_HH_ #define _TEXTURE_HANDLER_HH_ #include "config.h" #include "ParseUtil.hh" #include #include extern "C" { #include } class PTexture; class TextureHandler { public: class Entry { public: Entry(const std::string &name, PTexture *texture) : _name(name), _texture(texture), _ref(0) { } ~Entry(void) { delete _texture; } PTexture *getTexture(void) { return _texture; } inline uint getRef(void) const { return _ref; } inline void incRef(void) { ++_ref; } inline void decRef(void) { if (_ref > 0) { --_ref; } } inline bool operator==(const std::string &name) { return (::strcasecmp(_name.c_str(), name.c_str()) == 0); } private: std::string _name; PTexture *_texture; uint _ref; }; TextureHandler(void); ~TextureHandler(void); static TextureHandler *instance(void) { return _instance; } static int getLengthMin(void) { return LENGTH_MIN; } PTexture *getTexture(const std::string &texture); PTexture *referenceTexture(PTexture *texture); void returnTexture(PTexture *texture); private: PTexture *parse(const std::string &texture); PTexture *parseSolid(std::vector &tok); PTexture *parseSolidRaised(std::vector &tok); void parseSize(PTexture *tex, const std::string &size); private: static TextureHandler *_instance; static std::map _parse_map; static const int LENGTH_MIN; //!< Minimum texture name length. std::vector _textures; }; #endif // _TEXTURE_HANDLER_HH_ pekwm-release-0.1.18/src/Theme.cc000066400000000000000000000724021374756504400165260ustar00rootroot00000000000000// // Theme.cc for pekwm // Copyright © 2003-2013 the pekwm development team // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "config.h" #include "ParseUtil.hh" #include "Theme.hh" #include "Debug.hh" #include "x11.hh" #include "Config.hh" #include "PWinObj.hh" #include "PFont.hh" #include "PTexture.hh" #include "FontHandler.hh" #include "ImageHandler.hh" #include "TextureHandler.hh" #include "Util.hh" #include #include using std::cerr; using std::endl; using std::string; using std::vector; using std::map; // Theme::PDecorButtonData //! @brief Theme::PDecorButtonData constructor. Theme::PDecorButtonData::PDecorButtonData(void) : _shape(true), _left(false), _width(1), _height(1) { for (uint i = 0; i < BUTTON_STATE_NO; ++i) { _texture[i] = 0; } } //! @brief Theme::PDecorButtonData destructor. Theme::PDecorButtonData::~PDecorButtonData(void) { unload(); } //! @brief Parses CfgParser::Entry section, loads and verifies data. //! @param section CfgParser::Entry with button configuration. //! @return True if a valid button was parsed. bool Theme::PDecorButtonData::load(CfgParser::Entry *section) { if (*section == "LEFT") { _left = true; } else if (*section == "RIGHT") { _left = false; } else { return false; } // Get actions. ActionEvent ae; CfgParser::iterator it(section->begin()); for (; it != section->end(); ++it) { if (Config::instance()->parseActionEvent(*it, ae, BUTTONCLICK_OK, true)) { _aes.push_back (ae); } } // Got some actions, consider it to be a valid button. if (_aes.size() > 0) { TextureHandler *th = TextureHandler::instance(); CfgParser::Entry *value; value = section->findEntry("SETSHAPE"); if (value) { _shape = Util::isTrue(value->getValue()); } value = section->findEntry("FOCUSED"); if (value) { _texture[BUTTON_STATE_FOCUSED] = th->getTexture(value->getValue()); } value = section->findEntry("UNFOCUSED"); if (value) { _texture[BUTTON_STATE_UNFOCUSED] = th->getTexture(value->getValue()); } value = section->findEntry("PRESSED"); if (value) { _texture[BUTTON_STATE_PRESSED] = th->getTexture(value->getValue()); } // HOOVER has been kept around due to backwards compatibility. value = section->findEntry("HOVER"); if (! value) { value = section->findEntry("HOOVER"); } if (value) { _texture[BUTTON_STATE_HOVER] = th->getTexture(value->getValue()); } check(); return true; } return false; } //! @brief Unloads data. void Theme::PDecorButtonData::unload(void) { for (uint i = 0; i < BUTTON_STATE_NO; ++i) { TextureHandler::instance()->returnTexture(_texture[i]); _texture[i] = 0; } } //! @brief Verifies and makes sure no 0 textures exists. void Theme::PDecorButtonData::check(void) { for (uint i = 0; i < (BUTTON_STATE_NO - 1); ++i) { if (! _texture[i]) { _texture[i] = TextureHandler::instance()->getTexture("EMPTY"); } } _width = _texture[BUTTON_STATE_FOCUSED]->getWidth(); _height = _texture[BUTTON_STATE_FOCUSED]->getHeight(); } // Theme::PDecorData map Theme::PDecorData::_fs_map = map(); map Theme::PDecorData::_border_map = map(); //! @brief Theme::PDecorData constructor. Theme::PDecorData::PDecorData(const char *name) : _title_height(10), _title_width_min(0), _title_width_max(100), _title_width_symetric(true), _title_height_adapt(false) { if (name) { _name = name; } // init static data if (! _fs_map.size()) { _fs_map[FOCUSED_STATE_FOCUSED] = "FOCUSED"; _fs_map[FOCUSED_STATE_UNFOCUSED] = "UNFOCUSED"; _fs_map[FOCUSED_STATE_FOCUSED_SELECTED] = "FOCUSEDSELECTED"; _fs_map[FOCUSED_STATE_UNFOCUSED_SELECTED] = "UNFOCUSEDSELECTED"; } if (! _border_map.size()) { _border_map[BORDER_TOP_LEFT] = "TOPLEFT"; _border_map[BORDER_TOP] = "TOP"; _border_map[BORDER_TOP_RIGHT] = "TOPRIGHT"; _border_map[BORDER_LEFT] = "LEFT"; _border_map[BORDER_RIGHT] = "RIGHT"; _border_map[BORDER_BOTTOM_LEFT] = "BOTTOMLEFT"; _border_map[BORDER_BOTTOM] = "BOTTOM"; _border_map[BORDER_BOTTOM_RIGHT] = "BOTTOMRIGHT"; } // init arrays for (uint i = 0; i < PAD_NO; ++i) { _pad[i] = 0; } for (uint i = 0; i < FOCUSED_STATE_NO; ++i) { _texture_tab[i] = 0; _font[i] = 0; _font_color[i] = 0; } for (uint i = 0; i < FOCUSED_STATE_FOCUSED_SELECTED; ++i) { _texture_main[i] = 0; _texture_separator[i] = 0; } for (uint i = 0; i < FOCUSED_STATE_FOCUSED_SELECTED; ++i) { for (uint j = 0; j < BORDER_NO_POS; ++j) { _texture_border[i][j] = 0; } } } //! @brief Theme::PDecorData destructor. Theme::PDecorData::~PDecorData(void) { unload(); } //! @brief Parses CfgParser::Entry section, loads and verifies data. //! @param section CfgParser::Entry with pdecor configuration. //! @return True if a valid pdecor was parsed. bool Theme::PDecorData::load(CfgParser::Entry *section) { if (! section) { check(); return false; } CfgParser::Entry *value; _name = section->getValue(); if (! _name.size()) { cerr << " *** WARNING: no name identifying decor" << endl; return false; } CfgParser::Entry *title_section = section->findSection("TITLE"); if (! title_section) { cerr << " *** WARNING: no title section in decor: " << _name << endl; return false; } TextureHandler *th = TextureHandler::instance(); // convenience vector tok; vector keys; string value_pad, value_focused, value_unfocused; keys.push_back(new CfgParserKeyNumeric("HEIGHT", _title_height, 10, 0)); keys.push_back(new CfgParserKeyNumeric("WIDTHMIN", _title_width_min, 0)); keys.push_back(new CfgParserKeyNumeric("WIDTHMAX", _title_width_max, 100, 0, 100)); keys.push_back(new CfgParserKeyBool("WIDTHSYMETRIC", _title_width_symetric)); keys.push_back(new CfgParserKeyBool("HEIGHTADAPT", _title_height_adapt)); keys.push_back(new CfgParserKeyString("PAD", value_pad, "0 0 0 0", 7)); keys.push_back(new CfgParserKeyString("FOCUSED", value_focused, "Empty", th->getLengthMin())); keys.push_back(new CfgParserKeyString("UNFOCUSED", value_unfocused, "Empty", th->getLengthMin())); // Free up resources title_section->parseKeyValues(keys.begin(), keys.end()); for_each (keys.begin(), keys.end(), Util::Free()); keys.clear(); // Handle parsed data. _texture_main[FOCUSED_STATE_FOCUSED] = th->getTexture(value_focused); _texture_main[FOCUSED_STATE_UNFOCUSED] = th->getTexture(value_unfocused); if (Util::splitString(value_pad, tok, " \t", 4) == 4) { for (uint i = 0; i < PAD_NO; ++i) _pad[i] = strtol(tok[i].c_str(), 0, 10); } CfgParser::Entry *tab_section = title_section->findSection("TAB"); if (tab_section) { for (uint i = 0; i < FOCUSED_STATE_NO; ++i) { value = tab_section->findEntry(_fs_map[FocusedState(i)]); if (value) { _texture_tab[i] = th->getTexture(value->getValue()); } } } CfgParser::Entry *separator_section = title_section->findSection("SEPARATOR"); if (separator_section) { keys.push_back(new CfgParserKeyString("FOCUSED", value_focused, "Empty", th->getLengthMin())); keys.push_back(new CfgParserKeyString("UNFOCUSED", value_unfocused, "Empty", th->getLengthMin())); // Parse data separator_section->parseKeyValues(keys.begin(), keys.end()); // Free up resources for_each(keys.begin(), keys.end(), Util::Free()); keys.clear(); // Handle parsed data. _texture_separator[FOCUSED_STATE_FOCUSED] = th->getTexture(value_focused); _texture_separator[FOCUSED_STATE_UNFOCUSED] = th->getTexture(value_unfocused); } CfgParser::Entry *font_section = title_section->findSection("FONT"); if (font_section) { for (uint i = 0; i < FOCUSED_STATE_NO; ++i) { value = font_section->findEntry(_fs_map[FocusedState(i)]); if (value) { _font[i] = FontHandler::instance()->getFont(value->getValue()); } } } else { WARN("no font section in decor: " << _name); } CfgParser::Entry *fontcolor_section = title_section->findSection("FONTCOLOR"); if (fontcolor_section) { for (uint i = 0; i < FOCUSED_STATE_NO; ++i) { value = fontcolor_section->findEntry(_fs_map[FocusedState(i)]); if (value) { _font_color[i] = FontHandler::instance()->getColor(value->getValue()); } } } loadButtons(title_section->findSection("BUTTONS")); loadBorder(title_section->findSection("BORDER")); check(); return true; } //! @brief Unloads data. void Theme::PDecorData::unload(void) { TextureHandler *th = TextureHandler::instance(); for (uint i = 0; i < FOCUSED_STATE_NO; ++i) { th->returnTexture(_texture_tab[i]); FontHandler::instance()->returnFont(_font[i]); FontHandler::instance()->returnColor(_font_color[i]); _texture_tab[i] = 0; _font[i] = 0; _font_color[i] = 0; } for (uint i = 0; i < FOCUSED_STATE_FOCUSED_SELECTED; ++i) { th->returnTexture(_texture_main[i]); th->returnTexture(_texture_separator[i]); _texture_main[i] = 0; _texture_separator[i] = 0; for (uint j = 0; j < BORDER_NO_POS; ++j) { th->returnTexture(_texture_border[i][j]); _texture_border[i][j] = 0; } } vector::const_iterator it(_buttons.begin()); for (; it != _buttons.end(); ++it) { delete *it; } _buttons.clear(); } //! @brief Checks data properties, prints warning and tries to fix. void Theme::PDecorData::check(void) { // check values if (_title_width_max > 100) { WARN(_name << " WIDTHMAX > 100"); _title_width_max = 100; } checkTextures(); checkFonts(); checkBorder(); checkColors(); } //! @brief Loads border data. void Theme::PDecorData::loadBorder(CfgParser::Entry *section) { if (! section) { return; } TextureHandler *th = TextureHandler::instance(); // convenience CfgParser::Entry *sub, *value; sub = section->findSection("FOCUSED"); if (sub) { for (uint i = 0; i < BORDER_NO_POS; ++i) { value = sub->findEntry(_border_map[BorderPosition (i)]); if (value) { _texture_border[FOCUSED_STATE_FOCUSED][i] = th->getTexture(value->getValue()); } } } sub = section->findSection("UNFOCUSED"); if (sub) { for (uint i = 0; i < BORDER_NO_POS; ++i) { value = sub->findEntry(_border_map[BorderPosition (i)]); if (value) { _texture_border[FOCUSED_STATE_UNFOCUSED][i] = th->getTexture(value->getValue()); } } } } //! @brief Loads button data. void Theme::PDecorData::loadButtons(CfgParser::Entry *section) { if (! section) { return; } CfgParser::iterator it(section->begin()); for (; it != section->end(); ++it) { if (! (*it)->getSection()) { continue; } Theme::PDecorButtonData *btn = new Theme::PDecorButtonData(); if (btn->load((*it)->getSection())) { _buttons.push_back(btn); } else { delete btn; } } } //! @brief Checks for 0 textures, prints warning and sets empty texture void Theme::PDecorData::checkTextures(void) { for (uint i = 0; i < FOCUSED_STATE_NO; ++i) { if (! _texture_tab[i]) { WARN(_name << " missing tab texture state " << _fs_map[FocusedState(i)]); _texture_tab[i] = TextureHandler::instance()->getTexture("EMPTY"); } } for (uint i = 0; i < FOCUSED_STATE_FOCUSED_SELECTED; ++i) { if (! _texture_main[i]) { WARN(_name << " missing main texture state " << _fs_map[FocusedState(i)]); _texture_main[i] = TextureHandler::instance()->getTexture("EMPTY"); } if (! _texture_separator[i]) { WARN(_name << " missing tab texture state " << _fs_map[FocusedState(i)]); _texture_separator[i] = TextureHandler::instance()->getTexture("EMPTY"); } } } //! @brief Checks for 0 fonts, prints warning and sets empty font void Theme::PDecorData::checkFonts(void) { // the only font that's "obligatory" is the standard focused font, // others are only used if availible so we only check the focused font. if (! _font[FOCUSED_STATE_FOCUSED]) { WARN(_name << " missing font state " << _fs_map[FOCUSED_STATE_FOCUSED]); _font[FOCUSED_STATE_FOCUSED] = FontHandler::instance()->getFont(""); } } //! @brief Checks for 0 border PTextures. void Theme::PDecorData::checkBorder(void) { for (uint state = FOCUSED_STATE_FOCUSED; state < FOCUSED_STATE_FOCUSED_SELECTED; ++state) { for (uint i = 0; i < BORDER_NO_POS; ++i) { if (! _texture_border[state][i]) { WARN(_name << " missing border texture " << _border_map[BorderPosition(i)] << " " << _fs_map[FocusedState(state)]); _texture_border[state][i] = TextureHandler::instance()->getTexture("EMPTY"); } } } } //! @brief Checks for 0 colors, prints warning and sets empty color void Theme::PDecorData::checkColors(void) { for (uint i = 0; i < FOCUSED_STATE_NO; ++i) { if (! _font_color[i]) { WARN(_name << " missing font color state " << _fs_map[FocusedState(i)]); _font_color[i] = FontHandler::instance()->getColor("#000000"); } } } // Theme::PMenuData //! @brief PMenuData constructor Theme::PMenuData::PMenuData(void) { for (uint i = 0; i <= OBJECT_STATE_NO; ++i) { _font[i] = 0; _color[i] = 0; _tex_menu[i] = 0; _tex_item[i] = 0; _tex_arrow[i] = 0; } for (uint i = 0; i < OBJECT_STATE_NO; ++i) { _tex_sep[i] = 0; } for (uint i = 0; i < PAD_NO; ++i) { _pad[i] = 0; } } //! @brief PMenuData destructor Theme::PMenuData::~PMenuData(void) { unload(); } //! @brief Parses CfgParser::Entry section, loads and verifies data. //! @param section CfgParser::Entry with pmenu configuration. bool Theme::PMenuData::load(CfgParser::Entry *section) { if (! section) { check(); return false; } CfgParser::Entry *value; value = section->findEntry("PAD"); if (value) { vector tok; if (Util::splitString (value->getValue(), tok, " \t", 4) == 4) { for (int i = 0; i < PAD_NO; ++i) { _pad[i] = strtol (tok[i].c_str(), 0, 10); } } } value = section->findSection("FOCUSED"); if (value) { loadState(value, OBJECT_STATE_FOCUSED); } value = section->findSection("UNFOCUSED"); if (value) { loadState(value, OBJECT_STATE_UNFOCUSED); } value = section->findSection("SELECTED"); if (value) { loadState(value, OBJECT_STATE_SELECTED); } check(); return true; } //! @brief Unloads data. void Theme::PMenuData::unload(void) { for (uint i = 0; i <= OBJECT_STATE_NO; ++i) { FontHandler::instance()->returnFont(_font[i]); _font[i] = 0; FontHandler::instance()->returnColor(_color[i]); _color[i] = 0; TextureHandler::instance()->returnTexture(_tex_menu[i]); _tex_menu[i] = 0; TextureHandler::instance()->returnTexture(_tex_item[i]); _tex_item[i] = 0; TextureHandler::instance()->returnTexture(_tex_arrow[i]); _tex_arrow[i] = 0; } for (uint i = 0; i < OBJECT_STATE_NO; ++i) { TextureHandler::instance()->returnTexture(_tex_sep[i]); _tex_sep[i] = 0; } } //! @brief Check data properties, prints warning and tries to fix. void Theme::PMenuData::check(void) { for (uint i = 0; i <= OBJECT_STATE_NO; ++i) { if (! _font[i]) { _font[i] = FontHandler::instance()->getFont(""); } if (! _color[i]) { _color[i] = FontHandler::instance()->getColor("#000000"); } if (! _tex_menu[i]) { _tex_menu[i] = TextureHandler::instance()->getTexture("EMPTY"); } if (! _tex_item[i]) { _tex_item[i] = TextureHandler::instance()->getTexture("EMPTY"); } if (! _tex_arrow[i]) { _tex_arrow[i] = TextureHandler::instance()->getTexture("EMPTY"); } } for (uint i = 0; i < OBJECT_STATE_NO; ++i) { if (! _tex_sep[i]) { _tex_sep[i] = TextureHandler::instance()->getTexture("EMPTY"); } } } //! @brief void Theme::PMenuData::loadState(CfgParser::Entry *section, ObjectState state) { vector keys; string value_font, value_background, value_item; string value_text, value_arrow, value_separator; keys.push_back(new CfgParserKeyString("FONT", value_font)); keys.push_back(new CfgParserKeyString("BACKGROUND", value_background, "Solid #ffffff")); keys.push_back(new CfgParserKeyString("ITEM", value_item, "Solid #ffffff")); keys.push_back(new CfgParserKeyString("TEXT", value_text, "Solid #000000")); keys.push_back(new CfgParserKeyString("ARROW", value_arrow, "Solid #000000")); if (state < OBJECT_STATE_SELECTED) { keys.push_back(new CfgParserKeyString("SEPARATOR", value_separator, "Solid #000000")); } section->parseKeyValues(keys.begin(), keys.end()); for_each(keys.begin(), keys.end(), Util::Free()); TextureHandler *th = TextureHandler::instance(); // Handle parsed data. _font[state] = FontHandler::instance()->getFont(value_font); _tex_menu[state] = th->getTexture(value_background); _tex_item[state] = th->getTexture(value_item); _color[state] = FontHandler::instance()->getColor(value_text); _tex_arrow[state] = th->getTexture(value_arrow); if (state < OBJECT_STATE_SELECTED) { _tex_sep[state] = th->getTexture(value_separator); } } // Theme::TextDialogData //! @brief TextDialogData constructor. Theme::TextDialogData::TextDialogData(void) : _font(0), _color(0), _tex(0) { for (uint i = 0; i < PAD_NO; ++i) { _pad[i] = 0; } } //! @brief TextDialogData destructor. Theme::TextDialogData::~TextDialogData(void) { unload(); } //! @brief Parses CfgParser::Entry section, loads and verifies data. //! @param section CfgParser::Entry with textdialog configuration. bool Theme::TextDialogData::load(CfgParser::Entry *section) { if (! section) { check(); return false; } vector keys; string value_font, value_text, value_texture, value_pad; keys.push_back(new CfgParserKeyString("FONT", value_font)); keys.push_back(new CfgParserKeyString("TEXT", value_text, "#000000")); keys.push_back(new CfgParserKeyString("TEXTURE", value_texture, "Solid #ffffff")); keys.push_back(new CfgParserKeyString("PAD", value_pad, "0 0 0 0", 7)); section->parseKeyValues(keys.begin(), keys.end()); for_each(keys.begin(), keys.end(), Util::Free()); // Handle parsed data. _font = FontHandler::instance()->getFont(value_font); _color = FontHandler::instance()->getColor(value_text); _tex = TextureHandler::instance()->getTexture(value_texture); vector tok; if (Util::splitString(value_pad, tok, " \t", 4) == 4) { for (uint i = 0; i < PAD_NO; ++i) { _pad[i] = strtol(tok[i].c_str(), 0, 10); } } check(); return true; } //! @brief Unloads data. void Theme::TextDialogData::unload(void) { FontHandler::instance()->returnFont(_font); FontHandler::instance()->returnColor(_color); TextureHandler::instance()->returnTexture(_tex); _font = 0; _tex = 0; _color = 0; } //! @brief Check data properties, prints warning and tries to fix. //! @todo print warnings void Theme::TextDialogData::check(void) { if (! _font) { _font = FontHandler::instance()->getFont(""); } if (! _color) { _color = FontHandler::instance()->getColor("#000000"); } if (! _tex) { _tex = TextureHandler::instance()->getTexture("EMPTY"); } } // WorkspaceIndicatorData /** * WorkspaceIndicatorData constructor */ Theme::WorkspaceIndicatorData::WorkspaceIndicatorData(void) : font(0), font_color(0), texture_background(0), texture_workspace(0), texture_workspace_act(0), edge_padding(0), workspace_padding(0) { } /** * WorkspaceIndicatorData destructor */ Theme::WorkspaceIndicatorData::~WorkspaceIndicatorData(void) { unload(); } /** * Load theme data and check. */ bool Theme::WorkspaceIndicatorData::load(CfgParser::Entry *section) { if (! section) { check(); return false; } vector keys; string value_font, value_color, value_tex_bg; string value_tex_ws, value_tex_ws_act; keys.push_back(new CfgParserKeyString("FONT", value_font)); keys.push_back(new CfgParserKeyString("TEXT", value_color)); keys.push_back(new CfgParserKeyString("BACKGROUND", value_tex_bg)); keys.push_back(new CfgParserKeyString("WORKSPACE", value_tex_ws)); keys.push_back(new CfgParserKeyString("WORKSPACEACTIVE", value_tex_ws_act)); keys.push_back(new CfgParserKeyNumeric("EDGEPADDING", edge_padding, 5, 0)); keys.push_back(new CfgParserKeyNumeric("WORKSPACEPADDING", workspace_padding, 2, 0)); section->parseKeyValues(keys.begin(), keys.end()); for_each(keys.begin(), keys.end(), Util::Free()); font = FontHandler::instance()->getFont(value_font); font_color = FontHandler::instance()->getColor(value_color); texture_background = TextureHandler::instance()->getTexture(value_tex_bg); texture_workspace = TextureHandler::instance()->getTexture(value_tex_ws); texture_workspace_act = TextureHandler::instance()->getTexture(value_tex_ws_act); check(); return true; } /** * Unload loaded theme data. */ void Theme::WorkspaceIndicatorData::unload(void) { FontHandler::instance()->returnFont(font); FontHandler::instance()->returnColor(font_color); TextureHandler::instance()->returnTexture(texture_background); TextureHandler::instance()->returnTexture(texture_workspace); TextureHandler::instance()->returnTexture(texture_workspace_act); font = 0; font_color = 0; texture_background = 0; texture_workspace = 0; texture_workspace_act = 0; edge_padding = 0; workspace_padding = 0; } /** * Validate theme data loading */ void Theme::WorkspaceIndicatorData::check(void) { if (! font) { font = FontHandler::instance()->getFont("Sans#Center#XFT"); } if (! font_color) { font_color = FontHandler::instance()->getColor("#000000"); } if (! texture_background) { texture_background = TextureHandler::instance()->getTexture("Solid #ffffff"); } if (! texture_workspace) { texture_workspace = TextureHandler::instance()->getTexture("Solid #cccccc"); } if (! texture_workspace_act) { texture_workspace_act = TextureHandler::instance()->getTexture("Solid #aaaaaa"); } } /** * HarbourData constructor. */ Theme::HarbourData::HarbourData(void) : _texture(0) { } /** * HarbourData destructor, unload data. */ Theme::HarbourData::~HarbourData(void) { unload(); } /** * Load harbour data and validate state, unloading previously loaded * data if any. */ bool Theme::HarbourData::load(CfgParser::Entry *section) { if (! section) { check(); return false; } CfgParser::Entry *value; value = section->findEntry("TEXTURE"); if (value) { _texture = TextureHandler::instance()->getTexture(value->getValue()); } check(); return true; } /** * Unload harbour data. */ void Theme::HarbourData::unload(void) { if (_texture) { TextureHandler::instance()->returnTexture(_texture); _texture = 0; } } /** * Check state of harbour data. */ void Theme::HarbourData::check(void) { if (! _texture) { _texture = TextureHandler::instance()->getTexture("EMPTY"); } } // Theme //! @brief Theme constructor Theme::Theme(void) : _is_loaded(false), _invert_gc(None) { new ImageHandler(); // window gc's XGCValues gv; gv.function = GXinvert; gv.subwindow_mode = IncludeInferiors; gv.line_width = 1; _invert_gc = XCreateGC(X11::getDpy(), X11::getRoot(), GCFunction|GCSubwindowMode|GCLineWidth, &gv); X11::grabServer(); load(Config::instance()->getThemeFile()); X11::ungrabServer(true); } //! @brief Theme destructor Theme::~Theme(void) { unload(); // should clean things up XFreeGC(X11::getDpy(), _invert_gc); delete ImageHandler::instance(); } /** * Re-loads theme if needed, clears up previously used resources. */ bool Theme::load(const std::string &dir) { string norm_dir(dir); if (dir.size() && dir.at(dir.size() - 1) != '/') { norm_dir.append("/"); } string theme_file(norm_dir + string("theme")); if (! _cfg_files.requireReload(theme_file)) { return false; } if (_is_loaded) { unload(); } _theme_dir = norm_dir; if (! _theme_dir.size()) { cerr << " *** WARNING: empty theme directory name, using default." << endl; _theme_dir = DATADIR "/pekwm/themes/default/"; } bool theme_ok = true; CfgParser theme; if (! theme.parse(theme_file)) { _theme_dir = DATADIR "/pekwm/themes/default/"; theme_file = _theme_dir + string("theme"); if (! theme.parse(theme_file)) { cerr << " *** WARNING: couldn't load " << _theme_dir << " or default theme." << endl; theme_ok = false; } } // Setup quirks and requirements before parsing. if (theme_ok) { if (theme.isDynamicContent()) { _cfg_files.clear(); } else { _cfg_files = theme.getCfgFiles(); } loadThemeRequire(theme, theme_file); } // Set image basedir. ImageHandler::instance()->path_clear(); ImageHandler::instance()->path_push_back(_theme_dir); // Load decor data. CfgParser::Entry *section = theme.getEntryRoot()->findSection("PDECOR"); if (section) { CfgParser::iterator it(section->begin()); for (; it != section->end(); ++it) { Theme::PDecorData *data = new Theme::PDecorData(); if (data->load((*it)->getSection())) { _pdecordata_map[data->getName()] = data; } else { delete data; } } } if (! getPDecorData("DEFAULT")) { // Create DEFAULT decor, let check fill it up with empty but non-null data. WARN("Theme doesn't contain any DEFAULT decor."); Theme::PDecorData *decor_data = new Theme::PDecorData("DEFAULT"); decor_data->check(); _pdecordata_map["DEFAULT"] = decor_data; } if (! _menu_data.load(theme.getEntryRoot()->findSection("MENU"))) { WARN("Missing or malformed \"MENU\" section!"); } if (! _status_data.load(theme.getEntryRoot()->findSection("STATUS"))) { WARN("Missing \"STATUS\" section!"); } if (! _cmd_d_data.load(theme.getEntryRoot()->findSection("CMDDIALOG"))) { WARN("Missing \"CMDDIALOG\" section!"); } if (! _ws_indicator_data.load(theme.getEntryRoot()->findSection("WORKSPACEINDICATOR"))) { WARN("Missing \"WORKSPACEINDICATOR\" section!"); } if (! _harbour_data.load(theme.getEntryRoot()->findSection("HARBOUR"))) { WARN("Missing \"HARBOUR\" section!"); } _is_loaded = true; return true; } /** * Load template quirks. */ void Theme::loadThemeRequire(CfgParser &theme_cfg, std::string &file) { CfgParser::Entry *section; // Look for requires section, section = theme_cfg.getEntryRoot()->findSection("REQUIRE"); if (section) { vector keys; bool value_templates; keys.push_back(new CfgParserKeyBool("TEMPLATES", value_templates, false)); section->parseKeyValues(keys.begin(), keys.end()); for_each(keys.begin(), keys.end(), Util::Free()); // Re-load configuration with templates enabled. if (value_templates) { theme_cfg.clear(true); theme_cfg.parse(file, CfgParserSource::SOURCE_FILE, true); } } } /** * Unload theme data. */ void Theme::unload(void) { // Unload decors map::iterator p_it(_pdecordata_map.begin()); for (; p_it != _pdecordata_map.end(); ++p_it) { delete p_it->second; } _pdecordata_map.clear(); // Unload theme data _menu_data.unload(); _status_data.unload(); _cmd_d_data.unload(); _ws_indicator_data.unload(); _harbour_data.unload(); _is_loaded = false; } pekwm-release-0.1.18/src/Theme.hh000066400000000000000000000300271374756504400165350ustar00rootroot00000000000000// // Theme.hh for pekwm // Copyright © 2003-2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifndef _THEME_HH_ #define _THEME_HH_ #include "config.h" #include "pekwm.hh" #include "CfgParser.hh" #include "Action.hh" // ActionEvent #include "PFont.hh" // PFont::Color #include "ParseUtil.hh" class PTexture; class Button; class ButtonData; class ImageHandler; #include #include //! @brief Theme data parser and container. class Theme { public: //! @brief Theme data parser and container for PDecor::Button class PDecorButtonData { public: PDecorButtonData(void); ~PDecorButtonData(void); //! @brief Returns whether the shape (derived from the alpha channel) should be set. inline bool setShape(void) const { return _shape; } //! @brief Returns whether the button is positioned relative to the left title edge. inline bool isLeft(void) const { return _left; } //! @brief Returns width of button. inline uint getWidth(void) const { return _width; } //! @brief Returns height of button. inline uint getHeight(void) const { return _height; } //! @brief Returns PTexture used in ButtonState state. inline PTexture *getTexture(ButtonState state) { return _texture[(state != BUTTON_STATE_NO) ? state : 0]; } //! @brief Returns iterator to the first ActionEvent. inline vector::iterator begin(void) { return _aes.begin(); } //! @brief Return iterator to the last+1 ActionEvent. inline vector::iterator end(void) { return _aes.end(); } bool load(CfgParser::Entry *section); void unload(void); void check(void); private: vector _aes; PTexture *_texture[BUTTON_STATE_NO]; bool _shape:1, _left:1; uint _width, _height; }; //! @brief PDecor theme data container and parser. class PDecorData { public: PDecorData(const char *name=0); ~PDecorData(void); //! @brief Returns decor name. inline const std::string &getName(void) const { return _name; } //! @brief Sets decor name. inline void setName(const std::string &name) { _name = name; } //! @brief Returns title height. inline int getTitleHeight(void) const { return _title_height; } //! @brief Returns title minimum width (0 for full width title). inline int getTitleWidthMin(void) const { return _title_width_min; } //! @brief Returns title maximum width in procent. inline int getTitleWidthMax(void) const { return _title_width_max; } //! @brief Returns title text pad for dir. inline int getPad(PadType pad) const { return _pad[(pad != PAD_NO) ? pad : 0]; } //! @brief Returns wheter all items in the title have same width. inline bool isTitleWidthSymetric(void) const { return _title_width_symetric; } //! @brief Returns wheter titlebar height should be relative the font height inline bool isTitleHeightAdapt(void) const { return _title_height_adapt; } // Title textures //! @brief Returns background PTexture used in FocusedState state. inline PTexture *getTextureMain(FocusedState state) { return _texture_main[(state < FOCUSED_STATE_FOCUSED_SELECTED) ? state : 0]; } //! @brief Returns tab PTexture used in FocusedState state. inline PTexture *getTextureTab(FocusedState state) { return _texture_tab[(state != FOCUSED_STATE_NO) ? state : 0]; } //! @brief Returns separator PTexture used in FocusedState state. inline PTexture *getTextureSeparator(FocusedState state) { return _texture_separator[(state < FOCUSED_STATE_FOCUSED_SELECTED) ? state : 0]; } // font //! @brief Returns PFont used in FocusedState state. inline PFont *getFont(FocusedState state) const { return _font[((state == FOCUSED_STATE_NO) || ! _font[state]) ? FOCUSED_STATE_FOCUSED : state]; } //! @brief Return PFont::Color used in FocusedState state. inline PFont::Color *getFontColor(FocusedState state) { return _font_color[(state != FOCUSED_STATE_NO) ? state : 0]; } // border //! @brief Return border PTexture used in FocusedState state for pos. inline PTexture *getBorderTexture(FocusedState state, BorderPosition pos) { return _texture_border[(state < FOCUSED_STATE_FOCUSED_SELECTED) ? state : 0][pos]; } // button //! @brief Return iterator to the first Theme::PDecorButtonData. inline vector::const_iterator buttonBegin(void) { return _buttons.begin(); } //! @brief Return iterator to the last+1 Theme::PDecorButtonData. inline vector::const_iterator buttonEnd(void) { return _buttons.end(); } bool load(CfgParser::Entry *section); void unload(void); void check(void); private: void loadBorder(CfgParser::Entry *cs); void loadButtons(CfgParser::Entry *cs); void checkTextures(void); void checkFonts(void); void checkBorder(void); void checkColors(void); private: std::string _name; // size, padding etc int _title_height; int _title_width_min, _title_width_max; int _pad[PAD_NO]; bool _title_width_symetric; bool _title_height_adapt; // title PTexture *_texture_main[FOCUSED_STATE_FOCUSED_SELECTED]; PTexture *_texture_tab[FOCUSED_STATE_NO]; PTexture *_texture_separator[FOCUSED_STATE_FOCUSED_SELECTED]; // font PFont *_font[FOCUSED_STATE_NO]; PFont::Color *_font_color[FOCUSED_STATE_NO]; // border PTexture *_texture_border[FOCUSED_STATE_FOCUSED_SELECTED][BORDER_NO_POS]; vector _buttons; static std::map _fs_map; static std::map _border_map; }; //! @brief PMenu theme data container and parser. class PMenuData { public: PMenuData(void); ~PMenuData(void); //! @brief Returns PFont used in ObjectState state. inline PFont *getFont(ObjectState state) { return _font[state]; } //! @brief Returns PFont::Color used in ObjectState state. inline PFont::Color *getColor(ObjectState state) { return _color[state]; } //! @brief Returns menu PTexture used in ObjectState state. inline PTexture *getTextureMenu(ObjectState state) { return _tex_menu[state]; } //! @brief Returns item PTexture used in ObjectState state. inline PTexture *getTextureItem(ObjectState state) { return _tex_item[state]; } //! @brief Returns arrow PTexture used in ObjectState state. inline PTexture *getTextureArrow(ObjectState state) { return _tex_arrow[state]; } //! @brief Returns separator PTexture used in ObjectState state. inline PTexture *getTextureSeparator(ObjectState state) { return _tex_sep[(state < OBJECT_STATE_SELECTED) ? state : OBJECT_STATE_FOCUSED]; } //! @brief Returns text pad in PadType dir. inline uint getPad(PadType dir) const { return _pad[(dir != PAD_NO) ? dir : 0]; } bool load(CfgParser::Entry *section); void unload(void); void check(void); private: void loadState(CfgParser::Entry *cs, ObjectState state); private: PFont *_font[OBJECT_STATE_NO + 1]; PFont::Color *_color[OBJECT_STATE_NO + 1]; PTexture *_tex_menu[OBJECT_STATE_NO + 1]; PTexture *_tex_item[OBJECT_STATE_NO + 1]; PTexture *_tex_arrow[OBJECT_STATE_NO + 1]; PTexture *_tex_sep[OBJECT_STATE_NO]; uint _pad[PAD_NO]; }; //! @brief CmdDialog/StatusWindow theme data container and parser. class TextDialogData { public: TextDialogData(void); ~TextDialogData(void); //! @brief Returns PFont. inline PFont *getFont(void) { return _font; } //! @brief Returns PFont::Color. inline PFont::Color *getColor(void) { return _color; } //! @brief Returns background texture. inline PTexture *getTexture(void) { return _tex; } //! @brief Returns text pad in PadType dir. inline uint getPad(PadType dir) const { return _pad[(dir != PAD_NO) ? dir : 0]; } bool load(CfgParser::Entry *section); void unload(void); void check(void); private: PFont *_font; PFont::Color *_color; PTexture *_tex; uint _pad[PAD_NO]; }; /** * Class holding WorkspaceIndicator theme data. */ class WorkspaceIndicatorData { public: WorkspaceIndicatorData(void); ~WorkspaceIndicatorData(void); bool load(CfgParser::Entry *section); void unload(void); void check(void); public: PFont *font; PFont::Color *font_color; PTexture *texture_background; PTexture *texture_workspace; PTexture *texture_workspace_act; int edge_padding; int workspace_padding; }; /** * Class holding harbour theme data. */ class HarbourData { public: HarbourData(void); ~HarbourData(void); inline PTexture *getTexture(void) const { return _texture; } bool load(CfgParser::Entry *section); void unload(void); void check(void); private: PTexture *_texture; /**< Texture for rendering dockapps in the harbour. */ }; inline Theme::HarbourData *getHarbourData(void) { return &_harbour_data; } Theme(void); ~Theme(void); bool load(const std::string &dir); void unload(void); inline const GC &getInvertGC(void) const { return _invert_gc; } inline std::map::const_iterator decor_begin(void) { return _pdecordata_map.begin(); } inline std::map::const_iterator decor_end(void) { return _pdecordata_map.end(); } /** * Find PDecorData based on name. */ Theme::PDecorData *getPDecorData(const std::string &name) { std::map::iterator it = _pdecordata_map.begin(); for (; it != _pdecordata_map.end(); ++it) { if (strcasecmp(it->first.c_str(), name.c_str()) == 0) { return it->second; } } // Backwards compatibility, CMDDIALOG was used instead of // INPUTDIALOG previously. if (strcasecmp("INPUTDIALOG", name.c_str()) == 0) { return getPDecorData("CMDDIALOG"); } return 0; } Theme::WorkspaceIndicatorData &getWorkspaceIndicatorData(void) { return _ws_indicator_data; } // menu inline Theme::PMenuData *getMenuData(void) { return &_menu_data; } // status/cmd inline Theme::TextDialogData *getStatusData(void) { return &_status_data; } inline Theme::TextDialogData *getCmdDialogData(void) { return &_cmd_d_data; } private: void loadThemeRequire(CfgParser &theme_cfg, std::string &file); std::string _theme_dir; /**< Path to theme directory. */ TimeFiles _cfg_files; bool _is_loaded; // gc GC _invert_gc; // frame decors std::map _pdecordata_map; // menu Theme::PMenuData _menu_data; HarbourData _harbour_data; /**< Data for styling harbour. */ // status window TextDialogData _status_data, _cmd_d_data; WorkspaceIndicatorData _ws_indicator_data; }; #endif // _THEME_HH_ pekwm-release-0.1.18/src/Types.hh000066400000000000000000000010141374756504400165710ustar00rootroot00000000000000// // Types.hh for pekwm // Copyright (C) 2003-2009 Claes Nasten // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifndef _TYPES_HH_ #define _TYPES_HH_ extern "C" { #include } #ifndef ushort #define ushort unsigned short #endif // ushort #ifndef uint #define uint unsigned int #endif // uint #ifndef ulong #define ulong unsigned long #endif // ulong #ifndef uchar #define uchar unsigned char #endif // uchar #endif // _TYPES_HH_ pekwm-release-0.1.18/src/Util.cc000066400000000000000000000333571374756504400164070ustar00rootroot00000000000000// // Util.cc for pekwm // Copyright © 2002-2009 Claes Nästén // // misc.cc for aewm++ // Copyright (C) 2000 Frank Hale // http://sapphire.sourceforge.net/ // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "config.h" #include #include #include #include #include #include #include #include extern "C" { #include #include #include #include #include #include } #include "Util.hh" using std::back_inserter; using std::copy; using std::cerr; using std::endl; using std::ostringstream; using std::string; using std::transform; using std::vector; using std::wstring; using std::ifstream; using std::ofstream; using std::find; using std::map; using std::getenv; using std::wcstombs; using std::wmemset; using std::mbstowcs; using std::exit; namespace Util { #ifndef HOST_NAME_MAX #define HOST_NAME_MAX 255 #endif // HOST_NAME_MAX static iconv_t do_iconv_open(const char **from_names, const char **to_names); static size_t do_iconv(iconv_t ic, const char **inp, size_t *in_bytes, char **outp, size_t *out_bytes); // Initializers, members used for shared buffer unsigned int WIDE_STRING_COUNT = 0; iconv_t IC_TO_WC = reinterpret_cast(-1); iconv_t IC_TO_UTF8 = reinterpret_cast(-1); char *ICONV_BUF = 0; size_t ICONV_BUF_LEN = 0; // Constants, name of iconv internal names const char *ICONV_WC_NAMES[] = {"WCHAR_T", "UCS-4", 0}; const char *ICONV_UTF8_NAMES[] = {"UTF-8", "UTF8", 0}; const char *ICONV_UTF8_INVALID_STR = ""; const wchar_t *ICONV_WIDE_INVALID_STR = L""; // Constants, maximum number of bytes a single UTF-8 character can use. const size_t UTF8_MAX_BYTES = 6; //! @brief Fork and execute command with /bin/sh and execlp void forkExec(std::string command) { if (command.length() == 0) { #ifdef DEBUG cerr << __FILE__ << "@" << __LINE__ << ": " << "Util::forkExec() *** command length == 0" << endl; #endif // DEBUG return; } pid_t pid = fork(); switch (pid) { case 0: setsid(); execlp("/bin/sh", "sh", "-c", command.c_str(), (char *) 0); cerr << __FILE__ << "@" << __LINE__ << ": " << "Util::forkExec(" << command << ") execlp failed." << endl; exit(1); case -1: cerr << __FILE__ << "@" << __LINE__ << ": " << "Util::forkExec(" << command << ") fork failed." << endl; } } /** * Wrapper for gethostname returning a string instead of populating * char buffer. */ std::string getHostname(void) { string hostname; // Set WM_CLIENT_MACHINE char hostname_buf[HOST_NAME_MAX + 1]; if (! gethostname(hostname_buf, HOST_NAME_MAX)) { // Make sure it is null terminated hostname_buf[HOST_NAME_MAX] = '\0'; hostname = hostname_buf; } return hostname; } //! @brief Determines if the file exists bool isFile(const std::string &file) { if (file.size() == 0) { return false; } struct stat stat_buf; if (stat(file.c_str(), &stat_buf) == 0) { return (S_ISREG(stat_buf.st_mode)); } return false; } //! @brief Determines if the file is executable for the current user. bool isExecutable(const std::string &file) { if (file.size() == 0) { #ifdef DEBUG cerr << __FILE__ << "@" << __LINE__ << ": " << "Util::isExecutable() *** file length == 0" << endl; #endif // DEBUG return false; } struct stat stat_buf; if (! stat(file.c_str(), &stat_buf)) { if (stat_buf.st_uid == getuid()) { // user readable and executable if ((stat_buf.st_mode&S_IRUSR) && (stat_buf.st_mode&S_IXUSR)) { return true; } } if (getgid() == stat_buf.st_gid) { // group readable and executable if ((stat_buf.st_mode&S_IRGRP) && (stat_buf.st_mode&S_IXGRP)) { return true; } } if ((stat_buf.st_mode&S_IROTH) && (stat_buf.st_mode&S_IXOTH)) { return true; // other readable and executable } } return false; } /** * Get file mtime. */ time_t getMtime(const std::string &file) { struct stat stat_buf; if (! stat(file.c_str(), &stat_buf)) { return stat_buf.st_mtime; } else { return 0; } } /** * Copies a single text file. */ bool copyTextFile(const std::string &from, const std::string &to) { if ((from.length() == 0) || (to.length() == 0)) { return false; } ifstream stream_from(from.c_str()); if (! stream_from.good()) { cerr << __FILE__ << "@" << __LINE__ << ": " << "Can't copy: " << from << " to: " << to << endl; return false; } ofstream stream_to(to.c_str()); if (! stream_to.good()) { cerr << __FILE__ << "@" << __LINE__ << ": " << "Can't copy: " << from << " to: " << to << endl; return false; } stream_to << stream_from.rdbuf(); return true; } /** * Get name of the current user. */ string getUserName(void) { // Try to lookup current user with struct passwd *entry = getpwuid(geteuid()); if (entry && entry->pw_name) { return entry->pw_name; } else { if (getenv("USER")) { return getenv("USER"); } else { return "UNKNOWN"; } } } //! @brief Returns .extension of file std::string getFileExt(const std::string &file) { string::size_type pos = file.find_last_of('.'); if ((pos != string::npos) && (pos < file.size())) { return file.substr(pos + 1, file.size() - pos - 1); } else { return string(""); } } //! @brief Returns dir part of file std::string getDir(const std::string &file) { string::size_type pos = file.find_last_of('/'); if ((pos != string::npos) && (pos < file.size())) { return file.substr(0, pos); } else { return string(""); } } //! @brief Replaces the ~ with the complete homedir path. void expandFileName(std::string &file) { if (file.size() > 0) { if (file[0] == '~') { file.replace(0, 1, getenv("HOME")); } } } //! @brief Split the string str based on separator sep and put into vals //! //! This splits the string str into to max_tokens parts and puts in the vector //! vals. If max is 0 then it'll split it into as many tokens //! as possible, max defaults to 0. //! splitString returns the number of tokens it put into vals. //! //! @param str String to split //! @param vals Vector to put split values into //! @param sep Separators to use when splitting string //! @param max Maximum number of elements to put into vals (optional) //! @param include_empty Include empty elements, defaults to false. //! @param escape Escape character (optional) //! @return Number of tokens inserted into vals uint splitString(const string str, vector &toks, const char *sep, uint max, bool include_empty, char escape) { string::size_type start = str.find_first_not_of(" \t\n"); if (str.size() == 0 || start == string::npos) { return 0; } string token; token.reserve(str.size()); bool in_escape = false; uint num_tokens = 1; auto it = str.cbegin() + start; for (; it != str.cend() && (max == 0 || num_tokens < max); ++it) { if (in_escape) { token += *it; in_escape = false; } else if (*it == escape) { in_escape = true; } else if (strchr(sep, *it) != 0) { if (token.size() > 0 || include_empty) { toks.push_back(token); ++num_tokens; } token.clear(); } else { token += *it; } } // Get the last token (if any) if (it != str.cend()) { copy(it, str.cend(), back_inserter(token)); } if (token.size() > 0 || include_empty) { toks.push_back(token); ++num_tokens; } return num_tokens - 1; } //! @brief Converts wide-character string to multibyte version //! @param str String to convert. //! @return Returns multibyte version of string. std::string to_mb_str(const std::wstring &str) { size_t ret, num = str.size() * 6 + 1; char *buf = new char[num]; memset(buf, '\0', num); ret = wcstombs(buf, str.c_str(), num); if (ret == static_cast(-1)) { cerr << " *** WARNING: failed to convert wide string to multibyte string" << endl; } string ret_str(buf); delete [] buf; return ret_str; } //! @brief Converts multibyte string to wide-character version //! @param str String to convert. //! @return Returns wide-character version of string. std::wstring to_wide_str(const std::string &str) { size_t ret, num = str.size() + 1; wchar_t *buf = new wchar_t[num]; wmemset(buf, L'\0', num); ret = mbstowcs(buf, str.c_str(), num); if (ret == static_cast(-1)) { cerr << " *** WARNING: failed to convert multibyte string to wide string" << endl; } wstring ret_str(buf); delete [] buf; return ret_str; } //! @brief Open iconv handle with to/from names. //! @param from_names null terminated list of from name alternatives. //! @param to_names null terminated list of to name alternatives. //! @return iconv_t handle on success, else -1. iconv_t do_iconv_open(const char **from_names, const char **to_names) { iconv_t ic = reinterpret_cast(-1); // Try all combinations of from/to name's to get a working // conversion handle. for (unsigned int i = 0; from_names[i]; ++i) { for (unsigned int j = 0; to_names[j]; ++j) { ic = iconv_open(to_names[j], from_names[i]); if (ic != reinterpret_cast(-1)) { #ifdef HAVE_ICONVCTL int int_value_one = 1; iconvctl(ic, ICONV_SET_DISCARD_ILSEQ, &int_value_one); #endif // HAVE_ICONVCTL return ic; } } } return ic; } //! @brief Iconv wrapper to hide different definitions of iconv. //! @param ic iconv handle. //! @param inp Input pointer. //! @param in_bytes Input bytes. //! @param outp Output pointer. //! @param out_bytes Output bytes. //! @return number of bytes converted irreversible or -1 on error. size_t do_iconv(iconv_t ic, const char **inp, size_t *in_bytes, char **outp, size_t *out_bytes) { #ifdef ICONV_CONST return iconv(ic, inp, in_bytes, outp, out_bytes); #else // !ICONV_CONST return iconv(ic, const_cast(inp), in_bytes, outp, out_bytes); #endif // ICONV_CONST } //! @brief Init iconv conversion. void iconv_init(void) { // Cleanup previous init if any, being paranoid. iconv_deinit(); // Raise exception if this fails IC_TO_WC = do_iconv_open(ICONV_UTF8_NAMES, ICONV_WC_NAMES); IC_TO_UTF8 = do_iconv_open(ICONV_WC_NAMES, ICONV_UTF8_NAMES); // Equal mean if (IC_TO_WC != reinterpret_cast(-1) && IC_TO_UTF8 != reinterpret_cast(-1)) { // Create shared buffer. ICONV_BUF_LEN = 1024; ICONV_BUF = new char[ICONV_BUF_LEN]; } } //! @brief Deinit iconv conversion. void iconv_deinit(void) { // Cleanup resources if (IC_TO_WC != reinterpret_cast(-1)) { iconv_close(IC_TO_WC); } if (IC_TO_UTF8 != reinterpret_cast(-1)) { iconv_close(IC_TO_UTF8); } if (ICONV_BUF) { delete [] ICONV_BUF; } // Set members to safe values IC_TO_WC = reinterpret_cast(-1); IC_TO_UTF8 = reinterpret_cast(-1); ICONV_BUF = 0; ICONV_BUF_LEN = 0; } //! @brief Validate buffer size, grow if required. //! @param size Required size. void iconv_buf_grow(size_t size) { if (ICONV_BUF_LEN < size) { // Free resources, if any. if (ICONV_BUF) { delete [] ICONV_BUF; } // Calculate new buffer length and allocate new buffer for (; ICONV_BUF_LEN < size; ICONV_BUF_LEN *= 2) ; ICONV_BUF = new char[ICONV_BUF_LEN]; } } //! @brief Converts wide-character string to UTF-8 //! @param str String to convert. //! @return Returns UTF-8 representation of string. std::string to_utf8_str(const std::wstring &str) { string utf8_str; // Calculate length size_t in_bytes = str.size() * sizeof(wchar_t); size_t out_bytes = str.size() * UTF8_MAX_BYTES + 1; iconv_buf_grow(out_bytes); // Convert const char *inp = reinterpret_cast(str.c_str()); char *outp = ICONV_BUF; size_t len = do_iconv(IC_TO_UTF8, &inp, &in_bytes, &outp, &out_bytes); if (len != static_cast(-1)) { // Terminate string and cache result *outp = '\0'; utf8_str = ICONV_BUF; } else { cerr << " *** WARNING: to_utf8_str, failed with error " << strerror(errno) << endl; utf8_str = ICONV_UTF8_INVALID_STR; } return utf8_str; } //! @brief Converts to wide string from UTF-8 //! @param str String to convert. //! @return Returns wide representation of string. std::wstring from_utf8_str(const std::string &str) { wstring wide_str; // Calculate length size_t in_bytes = str.size(); size_t out_bytes = (in_bytes + 1) * sizeof(wchar_t); iconv_buf_grow(out_bytes); // Convert const char *inp = str.c_str(); char *outp = ICONV_BUF; size_t len = do_iconv(IC_TO_WC, &inp, &in_bytes, &outp, &out_bytes); if (len != static_cast(-1)) { // Terminate string and cache result *reinterpret_cast(outp) = L'\0'; wide_str = reinterpret_cast(ICONV_BUF); } else { cerr << " *** WARNING: from_utf8_str, failed on string \"" << str << "\"." << endl; wide_str = ICONV_WIDE_INVALID_STR; } return wide_str; } } // end namespace Util. pekwm-release-0.1.18/src/Util.hh000066400000000000000000000100341374756504400164040ustar00rootroot00000000000000// // Util.hh for pekwm // Copyright © 2002-2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifndef _UTIL_HH_ #define _UTIL_HH_ #include "config.h" #include "Types.hh" #include #include #include #include #include #include #include using std::vector; extern "C" { #include } /** * String utilities, convenience functions for making life easier * when working with strings. */ namespace String { /** Get safe version of position */ inline size_t safe_position(size_t pos, size_t fallback = 0, size_t add = 0) { return pos == std::wstring::npos ? fallback : (pos + add); } } //! @brief Namespace Util used for various small file/string tasks. namespace Util { void forkExec(std::string command); std::string getHostname(void); bool isFile(const std::string &file); bool isExecutable(const std::string &file); time_t getMtime(const std::string &file); bool copyTextFile(const std::string &from, const std::string &to); std::string getUserName(void); std::string getFileExt(const std::string &file); std::string getDir(const std::string &file); void expandFileName(std::string &file); uint splitString(const std::string str, vector &vals, const char *sep, uint max = 0, bool include_empty = false, char escape = '\0'); template std::string to_string(T t) { std::ostringstream oss; oss << t; return oss.str(); } /** * Converts string to uppercase * * @param str Reference to the string to convert */ inline void to_upper(std::string &str) { std::transform(str.begin(), str.end(), str.begin(), (int(*)(int)) std::toupper); } /** * Converts string to lowercase * * @param str Reference to the string to convert */ inline void to_lower(std::string &str) { std::transform(str.begin(), str.end(), str.begin(), (int(*)(int)) std::tolower); } /** * Converts wide string to uppercase * * @param str Reference to the string to convert */ inline void to_upper(std::wstring &str) { std::transform(str.begin(), str.end(), str.begin(), (int(*)(int)) std::towupper); } /** * Converts wide string to lowercase * * @param str Reference to the string to convert */ inline void to_lower(std::wstring &str) { std::transform(str.begin(), str.end(), str.begin(), (int(*)(int)) std::towlower); } std::string to_mb_str(const std::wstring &str); std::wstring to_wide_str(const std::string &str); void iconv_init(void); void iconv_deinit(void); /** * Return value within bounds of min and max value. */ template T between(T value, T min_val, T max_val) { if (value < min_val) { value = min_val; } else if (value > max_val) { value = max_val; } return value; } std::string to_utf8_str(const std::wstring &str); std::wstring from_utf8_str(const std::string &str); //! @brief Removes leading blanks( \n\t) from string. inline void trimLeadingBlanks(std::string &trim) { std::string::size_type first = trim.find_first_not_of(" \n\t"); if ((first != std::string::npos) && (first != (std::string::size_type) trim[0])) { trim = trim.substr(first, trim.size() - first); } } //! @brief Returns true if value represents true(1 or TRUE). inline bool isTrue(const std::string &value) { if (value.size() > 0) { if ((value[0] == '1') // check for 1 / 0 || ! ::strncasecmp(value.c_str(), "TRUE", 4)) { return true; } } return false; } //! @brief for_each delete utility. template struct Free : public std::unary_function { void operator ()(T t) { delete t; } }; } #endif // _UTIL_HH_ pekwm-release-0.1.18/src/WORefMenu.cc000066400000000000000000000030611374756504400172660ustar00rootroot00000000000000// // WORefMenu.hh for pekwm // Copyright © 2004-2009 Claes Nästen // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "config.h" #include "PWinObj.hh" #include "PDecor.hh" #include "PMenu.hh" #include "WORefMenu.hh" #include "Client.hh" using std::string; using std::wstring; //! @brief WORefMenu constructor //! @param theme Pointer to Theme //! @param title Title of menu //! @param name Name of menu //! @param decor_name Name of decor, defaults to MENU WORefMenu::WORefMenu(Theme *theme, const std::wstring &title, const std::string &name, const std::string &decor_name) : PMenu(theme, title, name, decor_name), PWinObjReference(0), _title_base(title), _title_pre(L" ["), _title_post(L"]") { } //! @brief WORefMenu destructor WORefMenu::~WORefMenu(void) { } /** * When notified, unmap all windows as window menu refers to object * being removed. */ void WORefMenu::notify(Observable *observable, Observation *observation) { PWinObjReference::notify(observable, observation); unmapAll(); } //! @brief Sets the reference and updates the title void WORefMenu::setWORef(PWinObj *wo_ref) { PWinObjReference::setWORef(wo_ref); wstring title(_title_base); // if of client type, add the clients named to the title if (wo_ref && (wo_ref->getType() == PWinObj::WO_CLIENT)) { Client *client = static_cast(wo_ref); title += _title_pre + client->getTitle()->getVisible() + _title_post; } setTitle(title); } pekwm-release-0.1.18/src/WORefMenu.hh000066400000000000000000000014721374756504400173040ustar00rootroot00000000000000// // WORefMenu.hh for pekwm // Copyright © 2004-2009 Claes Nästén // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifndef _WOREFMENU_HH_ #define _WOREFMENU_HH_ #include "config.h" #include #include "PWinObjReference.hh" class PWinObj; class PMenu; class Theme; class WORefMenu : public PMenu, public PWinObjReference { public: WORefMenu(Theme *theme, const std::wstring &title, const std::string &name, const std::string &decor_name = "MENU"); virtual ~WORefMenu(void); virtual void notify(Observable *observable, Observation *observation); virtual void setWORef(PWinObj *wo_ref); protected: std::wstring _title_base; std::wstring _title_pre, _title_post; }; #endif // _WOREFMENU_HH_ pekwm-release-0.1.18/src/WinLayouter.cc000066400000000000000000000331021374756504400177400ustar00rootroot00000000000000// // WinLayouter.cc for pekwm // Copyright © 2012-2013 Andreas Schlick // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "pekwm.hh" #include "WinLayouter.hh" #include "LayouterTiling.hh" #include "Client.hh" #include "Frame.hh" #include "Util.hh" #include "WindowManager.hh" #include "Workspaces.hh" #include "x11.hh" using std::string; static PWinObj* isEmptySpace(int x, int y, const PWinObj* wo, vector &wvec) { if (! wo) { return 0; } if (wvec.empty()) { // say that it's placed, now check if we are wrong! vector::iterator it(Workspaces::begin()); vector::iterator end(Workspaces::end()); for (; it != end; ++it) { // Skip ourselves, non-mapped and desktop objects. Iconified means // skip placement. if (wo == (*it) || ! (*it)->isMapped() || (*it)->isIconified() || ((*it)->getLayer() == LAYER_DESKTOP)) { continue; } // Also skip windows tagged as Maximized as they cause us to // automatically fail. if ((*it)->getType() == PWinObj::WO_FRAME) { Client *client = static_cast((*it))->getActiveClient(); if (client && (client->isFullscreen() || (client->isMaximizedVert() && client->isMaximizedHorz()))) { continue; } } wvec.push_back(*it); } } for (unsigned i=0; i < wvec.size(); ++i) { // Check if we are "intruding" on some other window's place if ((wvec[i]->getX() < signed(x + wo->getWidth())) && (signed(wvec[i]->getX() + wvec[i]->getWidth()) > x) && (wvec[i]->getY() < signed(y + wo->getHeight())) && (signed(wvec[i]->getY() + wvec[i]->getHeight()) > y)) { return wvec[i]; } } return 0; // we passed the test, no frames in the way } //! @brief Tries to find empty space to place the client in //! @return true if client got placed, else false //! @todo What should we do about Xinerama as when we don't have it enabled we care about the struts. class LayouterSmart : public WinLayouter { public: LayouterSmart() : WinLayouter(false) {} virtual ~LayouterSmart() {} private: virtual bool layout_impl(Frame *wo) { if (! wo) { return true; } PWinObj *wo_e; bool placed = false; vector wvec; int step_x = (Config::instance()->getPlacementLtR()) ? 1 : -1; int step_y = (Config::instance()->getPlacementTtB()) ? 1 : -1; int offset_x = (Config::instance()->getPlacementLtR()) ? Config::instance()->getPlacementOffsetX() : -Config::instance()->getPlacementOffsetX(); int offset_y = (Config::instance()->getPlacementTtB()) ? Config::instance()->getPlacementOffsetY() : -Config::instance()->getPlacementOffsetY(); int start_x, start_y, test_x = 0, test_y = 0; // Wrap these up, to get proper checking of space. uint wo_width = wo->getWidth() + Config::instance()->getPlacementOffsetX(); uint wo_height = wo->getHeight() + Config::instance()->getPlacementOffsetY(); start_x = Config::instance()->getPlacementLtR() ? _gm.x : _gm.x + _gm.width - wo_width; start_y = Config::instance()->getPlacementTtB() ? _gm.y : _gm.y + _gm.height - wo_height; if (Config::instance()->getPlacementRow()) { // row placement test_y = start_y; while (! placed && (Config::instance()->getPlacementTtB() ? test_y + wo_height <= _gm.y + _gm.height : test_y >= _gm.y)) { test_x = start_x; while (! placed && (Config::instance()->getPlacementLtR() ? test_x + wo_width <= _gm.x + _gm.width : test_x >= _gm.x)) { // see if we can place the window here if ((wo_e = isEmptySpace(test_x, test_y, wo, wvec))) { placed = false; test_x = Config::instance()->getPlacementLtR() ? wo_e->getX() + wo_e->getWidth() : wo_e->getX() - wo_width; } else { placed = true; wo->move(test_x + offset_x, test_y + offset_y); } } test_y += step_y; } } else { // column placement test_x = start_x; while (! placed && (Config::instance()->getPlacementLtR() ? test_x + wo_width <= _gm.x + _gm.width : test_x >= _gm.x)) { test_y = start_y; while (! placed && (Config::instance()->getPlacementTtB() ? test_y + wo_height <= _gm.y + _gm.height : test_y >= _gm.y)) { // see if we can place the window here if ((wo_e = isEmptySpace(test_x, test_y, wo, wvec))) { placed = false; test_y = Config::instance()->getPlacementTtB() ? wo_e->getY() + wo_e->getHeight() : wo_e->getY() - wo_height; } else { placed = true; wo->move(test_x + offset_x, test_y + offset_y); } } test_x += step_x; } } return placed; } }; //! @brief Places the wo in a corner of the screen not under the pointer class LayouterMouseNotUnder : public WinLayouter { public: LayouterMouseNotUnder() : WinLayouter(false) {} virtual ~LayouterMouseNotUnder() {} virtual bool layout_impl(Frame *wo) { if (! wo) { return true; } // compensate for head offset _ptr_x -= _gm.x; _ptr_y -= _gm.y; // divide the screen into four rectangles using the pointer as divider if (wo->getWidth() < unsigned(_ptr_x) && wo->getHeight() < _gm.height) { wo->move(_gm.x, _gm.y); return true; } if (wo->getWidth() < _gm.width && wo->getHeight() < unsigned(_ptr_y)) { wo->move(_gm.x + _gm.width - wo->getWidth(), _gm.y); return true; } if (wo->getWidth() < _gm.width - _ptr_x && wo->getHeight() < _gm.height) { wo->move(_gm.x + _gm.width - wo->getWidth(), _gm.y + _gm.height - wo->getHeight()); return true; } if (wo->getWidth() < _gm.width && wo->getHeight() < _gm.height - _ptr_y) { wo->move(_gm.x, _gm.y + _gm.height - wo->getHeight()); return true; } return false; } }; //! @brief Places the client centered under the mouse class LayouterMouseCentred : public WinLayouter { public: LayouterMouseCentred() : WinLayouter(false) {} ~LayouterMouseCentred() {} private: virtual bool layout_impl(Frame *wo) { if (wo) { Geometry gm(_ptr_x - (wo->getWidth() / 2), _ptr_y - (wo->getHeight() / 2), wo->getWidth(), wo->getHeight()); // make sure it's within the screen's border X11::placeInsideScreen(gm); wo->move(gm.x, gm.y); } return true; } }; //! @brief Places the client like the menu gets placed class LayouterMouseTopLeft : public WinLayouter { public: LayouterMouseTopLeft() : WinLayouter(false) {} private: virtual bool layout_impl(Frame *wo) { if (wo) { Geometry gm(_ptr_x, _ptr_y, wo->getWidth(), wo->getHeight()); X11::placeInsideScreen(gm); // make sure it's within the screen's border wo->move(gm.x, gm.y); } return true; } }; void WinLayouter::layout(Frame *frame, Window parent) { if (frame) { frame->updateDecor(); } if (_tiling) { layout_impl(frame); return; } if (frame && parent != None && Config::instance()->placeTransOnParent() && placeOnParent(frame, parent)) { return; } X11::getMousePosition(_ptr_x, _ptr_y); int head_nr = X11::getNearestHead(_ptr_x, _ptr_y); X11::getHeadInfoWithEdge(head_nr, _gm); // Collect the information which head has a fullscreen window. // To be conservative for now we ignore fullscreen windows on // the desktop or normal layer, because it might be a file // manager in desktop mode, for example. vector fsHead(X11::getNumHeads(), false); Workspaces::const_iterator it(Workspaces::begin()), end(Workspaces::end()); for (; it != end; ++it) { if ((*it)->isMapped() && (*it)->getType() == PWinObj::WO_FRAME) { Client *client = static_cast(*it)->getActiveClient(); if (client && client->isFullscreen() && client->getLayer()>LAYER_NORMAL) { fsHead[client->getHead()] = true; } } } // Try to place the window int i = head_nr; do { if (! fsHead[i]) { X11::getHeadInfoWithEdge(i, _gm); if (layout_impl(frame)) { return; } } i = (i+1)%X11::getNumHeads(); } while (i != head_nr); // We failed to place the window, so put it in the top-left // corner but still try to avoid heads with a fullscreen window on it. i = head_nr; do { if (! fsHead[i]) { break; } i = (i+1)%X11::getNumHeads(); } while (i != head_nr); X11::getHeadInfoWithEdge(i, _gm); frame->move(_gm.x, _gm.y); } void WinLayouter::setOption(vector &opt, Frame *frame) { vector::size_type nropts = opt.size(); // If frame == 0 (perhaps SetPlacementOption was called by a menu entry), // try to get a frame. if (! frame) { if (! (frame = dynamic_cast(PWinObj::getFocusedPWinObj()))) { vector::const_iterator it = WindowManager::instance()->mru_begin(); vector::const_iterator end = WindowManager::instance()->mru_begin(); for (; it != end; ++it) { if ((*it)->isMapped()) { frame = *it; break; } } if (! frame) { return; } } } if (! strcasecmp(opt[0].c_str(), "switchgeometry")) { Frame *last = frame; vector::const_iterator it, end; if (nropts > 1 && Util::isTrue(opt[1])) { it = WindowManager::instance()->mru_begin(); end = WindowManager::instance()->mru_end(); for (; it != end; ++it) { last = *it; if (last != frame && last->isMapped() && ! last->isShaded()) { break; } } } else { end = Frame::frame_end(); it = find(Frame::frame_begin(), end, frame); do { if (++it == end) it = Frame::frame_begin(); last = *it; } while (last != frame && (!last->isMapped() || last->isShaded())); } if (it != end && last != frame) { int x = frame->getX(); int y = frame->getY(); uint w = frame->getWidth(); uint h = frame->getHeight(); frame->moveResize(last->getX(), last->getY(), last->getWidth(), last->getHeight()); last->moveResize(x, y, w, h); if (nropts > 2 && Util::isTrue(opt[2])) { last->raise(); last->giveInputFocus(); } } } } bool WinLayouter::placeOnParent(Frame *wo, Window parent) { PWinObj *wo_s = PWinObj::findPWinObj(parent); if (wo_s) { wo->move(wo_s->getX() + wo_s->getWidth() / 2 - wo->getWidth() / 2, wo_s->getY() + wo_s->getHeight() / 2 - wo->getHeight() / 2); return true; } return false; } int WinLayouter::_ptr_x; int WinLayouter::_ptr_y; Geometry WinLayouter::_gm; WinLayouter *WinLayouterFactory(std::string l) { Util::to_upper(l); const char *str = l.c_str(); if (! strcmp(str, "SMART")) { return new LayouterSmart; } if (! strcmp(str, "MOUSENOTUNDER")) { return new LayouterMouseNotUnder; } if (! strcmp(str, "MOUSECENTERED")) { return new LayouterMouseCentred; } if (! strcmp(str, "MOUSETOPLEFT")) { return new LayouterMouseTopLeft; } if (! strncmp("TILE_", str, 5)) { str += 5; if (! strcmp("BOXED", str)) { return new LayouterBoxed(false); } if (! strcmp("CENTERONE", str)) { return new LayouterBoxed(true); } if (! strcmp("DWINDLE", str)) { return new LayouterDwindle; } if (! strcmp("FIBONACCI", str)) { return new LayouterFibonacci; } if (! strcmp("HORIZ", str)) { return new LayouterLayers(true); } if (! strcmp("STACKED", str)) { return new LayouterStacked; } if (! strcmp("TRIPLE", str)) { return new LayouterTriple; } if (! strcmp("VERT", str)) { return new LayouterLayers(false); } } return 0; } pekwm-release-0.1.18/src/WinLayouter.hh000066400000000000000000000017041374756504400177550ustar00rootroot00000000000000// // WinLayouter.hh for pekwm // Copyright © 2012-2013 Andreas Schlick // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #ifndef _WIN_LAYOUTER_HH_ #define _WIN_LAYOUTER_HH_ #include #include class Frame; class WinLayouter { public: WinLayouter(bool tiling) : _tiling(tiling) {} virtual ~WinLayouter() {} bool isTiling(void) const { return _tiling; } void layout(Frame *f, Window parent); virtual void setOption(std::vector &, Frame *); protected: // temp. variables that get filled in by layout() (if !_tiling). static int _ptr_x, _ptr_y; // mouse pointer coordinates static Geometry _gm; // geometry of the head private: bool placeOnParent(Frame *f, Window parent); bool _tiling; virtual bool layout_impl(Frame *f)=0; }; WinLayouter *WinLayouterFactory(std::string name); #endif // _WIN_LAYOUTER_HH_ pekwm-release-0.1.18/src/WindowManager.cc000066400000000000000000001335621374756504400202330ustar00rootroot00000000000000// // WindowManager.cc for pekwm // Copyright © 2002-2016 the pekwm development team // // windowmanager.cc for aewm++ // Copyright (C) 2000 Frank Hale // http://sapphire.sourceforge.net/ // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "config.h" #include "Debug.hh" #include "PWinObj.hh" #include "PDecor.hh" #include "Frame.hh" #include "Client.hh" #include "WindowManager.hh" #include "ActionHandler.hh" #include "AutoProperties.hh" #include "Config.hh" #include "Theme.hh" #include "PFont.hh" #include "PTexture.hh" #include "FontHandler.hh" #include "TextureHandler.hh" #include "Workspaces.hh" #include "Util.hh" #include "x11.hh" #include "RegexString.hh" #include "KeyGrabber.hh" #include "MenuHandler.hh" #include "Harbour.hh" #include "DockApp.hh" #include "CmdDialog.hh" #include "SearchDialog.hh" #include "StatusWindow.hh" #include "WorkspaceIndicator.hh" #include #include #include #include extern "C" { #include #include #include #include #include #include #include #include #ifdef HAVE_XRANDR #include #endif // HAVE_XRANDR } using std::cout; using std::cerr; using std::endl; using std::find; using std::map; using std::mem_fun; using std::string; using std::vector; using std::wstring; // Static initializers WindowManager *WindowManager::_instance = 0; extern "C" { static bool is_signal_hup = false; static bool is_signal_int_term = false; static bool is_signal_alrm = false; /** * Signal handler setting signal flags. */ static void sigHandler(int signal) { switch (signal) { case SIGHUP: is_signal_hup = true; break; case SIGINT: case SIGTERM: is_signal_int_term = true; break; case SIGCHLD: wait(0); break; case SIGALRM: // Do nothing, just used to break out of waiting is_signal_alrm = true; break; } } } // extern "C" // WindowManager /** * Create window manager instance and run main routine. */ WindowManager* WindowManager::start(const std::string &config_file, bool replace) { if (_instance) { delete _instance; } // Setup window manager _instance = new WindowManager(config_file); if (_instance->setupDisplay(replace)) { _instance->scanWindows(); Frame::resetFrameIDs(); _instance->_root_wo->setEwmhDesktopNames(); _instance->_root_wo->setEwmhDesktopLayout(); // add all frames to the MRU list _instance->_mru.resize(Frame::frame_size()); copy(Frame::frame_begin(), Frame::frame_end(), _instance->_mru.begin()); _instance->execStartFile(); } else { delete _instance; _instance = 0; } return _instance; } /** * Destroy current running window manager. */ void WindowManager::destroy(void) { delete _instance; _instance = 0; } //! @brief Constructor for WindowManager class WindowManager::WindowManager(const std::string &config_file) : _keygrabber(0), _config(0), _font_handler(0), _texture_handler(0), _theme(0), _action_handler(0), _autoproperties(0), _harbour(0), _cmd_dialog(0), _search_dialog(0), _status_window(0), _workspace_indicator(0), _startup(false), _shutdown(false), _reload(false), _restart(false), _allow_grouping(true), _hint_wo(0), _root_wo(0) { _screen_edges[0] = 0; _screen_edges[1] = 0; _screen_edges[2] = 0; _screen_edges[3] = 0; struct sigaction act; // Set up the signal handlers. act.sa_handler = sigHandler; act.sa_mask = sigset_t(); act.sa_flags = SA_NOCLDSTOP | SA_NODEFER; sigaction(SIGTERM, &act, 0); sigaction(SIGINT, &act, 0); sigaction(SIGHUP, &act, 0); sigaction(SIGCHLD, &act, 0); sigaction(SIGALRM, &act, 0); // construct _config = new Config(); _config->load(config_file); _config->loadMouseConfig(_config->getMouseConfigFile()); } //! @brief WindowManager destructor WindowManager::~WindowManager(void) { cleanup(); delete _cmd_dialog; delete _search_dialog; delete _status_window; delete _workspace_indicator; MenuHandler::deleteMenus(); delete _harbour; delete _root_wo; delete _hint_wo; delete _action_handler; delete _autoproperties; delete _keygrabber; delete _config; delete _theme; delete _font_handler; delete _texture_handler; X11::destruct(); } //! @brief Checks if the start file is executable then execs it. void WindowManager::execStartFile(void) { string start_file(_config->getStartFile()); bool exec = Util::isExecutable(start_file); if (! exec) { start_file = SYSCONFDIR "/start"; exec = Util::isExecutable(start_file); } if (exec) { Util::forkExec(start_file); } } //! @brief Cleans up, Maps windows etc. void WindowManager::cleanup(void) { // update all nonactive clients properties vector::const_iterator it_f(Frame::frame_begin()); for (; it_f != Frame::frame_end(); ++it_f) { (*it_f)->updateInactiveChildInfo(); } if (_harbour) { _harbour->removeAllDockApps(); } // To preserve stacking order when destroying the frames, we go through // the PWinObj list from the Workspaces and put all Frames into our own // list, then we delete the frames in order. vector frame_list; Workspaces::iterator it_w(Workspaces::begin()); for (; it_w != Workspaces::end(); ++it_w) { if ((*it_w)->getType() == PWinObj::WO_FRAME) { frame_list.push_back(static_cast(*it_w)); } } // Delete all Frames. This reparents the Clients. for (it_f = frame_list.begin(); it_f != frame_list.end(); ++it_f) { delete *it_f; } // Delete all Clients. while (Client::client_begin() != Client::client_end()) delete *Client::client_begin(); if (_keygrabber) { _keygrabber->ungrabKeys(X11::getRoot()); } // destroy screen edge for (int i=0; i < 4; ++i) { Workspaces::remove(_screen_edges[i]); delete _screen_edges[i]; _screen_edges[i]=0; } XInstallColormap(X11::getDpy(), X11::getColormap()); X11::setInputFocus(PointerRoot); } /** * Setup display and claim resources. */ bool WindowManager::setupDisplay(bool replace) { Display *dpy = XOpenDisplay(0); if (! dpy) { cerr << "Can not open display!" << endl << "Your DISPLAY variable currently is set to: " << getenv("DISPLAY") << endl; exit(1); } // Setup screen, init atoms and claim the display. X11::init(dpy, _config->isHonourRandr()); try { // Create hint window _before_ root window. _hint_wo = new HintWO(X11::getRoot(), replace); } catch (string &ex) { return false; } // Create root PWinObj _root_wo = new RootWO(X11::getRoot()); PWinObj::setRootPWinObj(_root_wo); _font_handler = new FontHandler(); _texture_handler = new TextureHandler(); _action_handler = new ActionHandler(); // load colors, fonts _theme = new Theme; _autoproperties = new AutoProperties(); _autoproperties->load(); Workspaces::setSize(_config->getWorkspaces()); Workspaces::setPerRow(_config->getWorkspacesPerRow()); _harbour = new Harbour; MenuHandler::createMenus(_theme); _cmd_dialog = new CmdDialog(_theme); _search_dialog = new SearchDialog(_theme); _status_window = new StatusWindow(_theme); _workspace_indicator = new WorkspaceIndicator{_theme}; XDefineCursor(dpy, X11::getRoot(), X11::getCursor(CURSOR_ARROW)); #ifdef HAVE_XRANDR XRRSelectInput(dpy, X11::getRoot(), RRScreenChangeNotifyMask); #endif // HAVE_XRANDR _keygrabber = new KeyGrabber; _keygrabber->load(_config->getKeyFile()); _keygrabber->grabKeys(X11::getRoot()); // Create screen edge windows screenEdgeCreate(); screenEdgeMapUnmap(); return true; } //! @brief Goes through the window and creates Clients/DockApps. void WindowManager::scanWindows(void) { if (_startup) { // only done once when we start return; } uint num_wins; Window d_win1, d_win2, *wins; // Lets create a list of windows on the display XQueryTree(X11::getDpy(), X11::getRoot(), &d_win1, &d_win2, &wins, &num_wins); vector win_list(wins, wins + num_wins); XFree(wins); vector::iterator it(win_list.begin()); // We filter out all windows with the the IconWindowHint // set not pointing to themselves, making DockApps // work as they are supposed to. for (; it != win_list.end(); ++it) { if (*it == None) { continue; } XWMHints *wm_hints = XGetWMHints(X11::getDpy(), *it); if (wm_hints) { if ((wm_hints->flags&IconWindowHint) && (wm_hints->icon_window != *it)) { vector::iterator i_it(find(win_list.begin(), win_list.end(), wm_hints->icon_window)); if (i_it != win_list.end()) *i_it = None; } XFree(wm_hints); } } for (it = win_list.begin(); it != win_list.end(); ++it) { if (*it != None) { createClient(*it, false); } } // Try to focus the ontop window, if no window we give root focus PWinObj *wo = Workspaces::getTopWO(PWinObj::WO_FRAME); if (wo && wo->isMapped()) { wo->giveInputFocus(); } else { _root_wo->giveInputFocus(); } // Try to find transients for all clients, on restarts ordering might // not be correct. vector::const_iterator it_client = Client::client_begin(); for (; it_client != Client::client_end(); ++it_client) { if ((*it_client)->isTransient() && ! (*it_client)->getTransientForClient()) { (*it_client)->findAndRaiseIfTransient(); } } // We won't be needing these anymore until next restart _autoproperties->removeApplyOnStart(); _startup = true; } //! @brief Creates and places screen edge void WindowManager::screenEdgeCreate(void) { bool indent = Config::instance()->getScreenEdgeIndent(); _screen_edges[0] = new EdgeWO(X11::getRoot(), SCREEN_EDGE_LEFT, indent && (_config->getScreenEdgeSize(SCREEN_EDGE_LEFT) > 0)); _screen_edges[1] = new EdgeWO(X11::getRoot(), SCREEN_EDGE_RIGHT, indent && (_config->getScreenEdgeSize(SCREEN_EDGE_RIGHT) > 0)); _screen_edges[2] = new EdgeWO(X11::getRoot(), SCREEN_EDGE_TOP, indent && (_config->getScreenEdgeSize(SCREEN_EDGE_TOP) > 0)); _screen_edges[3] = new EdgeWO(X11::getRoot(), SCREEN_EDGE_BOTTOM, indent && (_config->getScreenEdgeSize(SCREEN_EDGE_BOTTOM) > 0)); // make sure the edge stays ontop for (int i=0; i < 4; ++i) { Workspaces::insert(_screen_edges[i]); } screenEdgeResize(); } //! @brief void WindowManager::screenEdgeResize(void) { uint l_size = std::max(_config->getScreenEdgeSize(SCREEN_EDGE_LEFT), 1); uint r_size = std::max(_config->getScreenEdgeSize(SCREEN_EDGE_RIGHT), 1); uint t_size = std::max(_config->getScreenEdgeSize(SCREEN_EDGE_TOP), 1); uint b_size = std::max(_config->getScreenEdgeSize(SCREEN_EDGE_BOTTOM), 1); // Left edge _screen_edges[0]->moveResize(0, 0, l_size, X11::getHeight()); // Right edge _screen_edges[1]->moveResize(X11::getWidth() - r_size, 0, r_size, X11::getHeight()); // Top edge _screen_edges[2]->moveResize(l_size, 0, X11::getWidth() - l_size - r_size, t_size); // Bottom edge _screen_edges[3]->moveResize(l_size, X11::getHeight() - b_size, X11::getWidth() - l_size - r_size, b_size); for (int i=0; i<4; ++i) { _screen_edges[i]->configureStrut(_config->getScreenEdgeIndent() && _config->getScreenEdgeSize(_screen_edges[i]->getEdge()) > 0); } X11::updateStrut(); } void WindowManager::screenEdgeMapUnmap(void) { EdgeWO* edge; for (int i=0; i<4; ++i) { edge = _screen_edges[i]; if (_config->getScreenEdgeSize(edge->getEdge()) > 0 && _config->getEdgeListFromPosition(edge->getEdge())->size() > 0) { edge->mapWindow(); } else { edge->unmapWindow(); } } } //! @brief Reloads configuration and updates states. void WindowManager::doReload(void) { doReloadConfig(); doReloadTheme(); doReloadMouse(); doReloadKeygrabber(); doReloadAutoproperties(); MenuHandler::reloadMenus(); doReloadHarbour(); _root_wo->setEwmhDesktopNames(); _root_wo->setEwmhDesktopLayout(); _reload = false; } /** * Reload main config file. */ void WindowManager::doReloadConfig(void) { // If any of these changes, re-fetch of all names is required bool old_client_unique_name = _config->getClientUniqueName(); string old_client_unique_name_pre = _config->getClientUniqueNamePre(); string old_client_unique_name_post = _config->getClientUniqueNamePost(); // Reload configuration if (! _config->load(_config->getConfigFile())) { return; } // Update what might have changed in the cfg touching the hints Workspaces::setSize(_config->getWorkspaces()); Workspaces::setPerRow(_config->getWorkspacesPerRow()); Workspaces::setNames(); // Update the ClientUniqueNames if needed if ((old_client_unique_name != _config->getClientUniqueName()) || (old_client_unique_name_pre != _config->getClientUniqueNamePre()) || (old_client_unique_name_post != _config->getClientUniqueNamePost())) { for_each(Client::client_begin(), Client::client_end(), mem_fun(&Client::readName)); } // Resize the screen edge screenEdgeResize(); screenEdgeMapUnmap(); X11::updateStrut(); } /** * Reload theme file and update decorations. */ void WindowManager::doReloadTheme(void) { // Reload the theme if (! _theme->load(_config->getThemeFile())) { return; } // Reload the themes on all decors for_each(PDecor::pdecor_begin(), PDecor::pdecor_end(), mem_fun(&PDecor::loadDecor)); } /** * Reload mouse configuration and re-grab buttons on all windows. */ void WindowManager::doReloadMouse(void) { if (! _config->loadMouseConfig(_config->getMouseConfigFile())) { return; } for_each(Client::client_begin(), Client::client_end(), mem_fun(&Client::grabButtons)); } /** * Reload keygrabber configuration and re-grab keys on all windows. */ void WindowManager::doReloadKeygrabber(bool force) { // Reload the keygrabber if (! _keygrabber->load(_config->getKeyFile(), force)) { return; } _keygrabber->ungrabKeys(X11::getRoot()); _keygrabber->grabKeys(X11::getRoot()); // Regrab keys and buttons vector::const_iterator c_it(Client::client_begin()); for (; c_it != Client::client_end(); ++c_it) { (*c_it)->grabButtons(); _keygrabber->ungrabKeys((*c_it)->getWindow()); _keygrabber->grabKeys((*c_it)->getWindow()); } } /** * Reload autoproperties. */ void WindowManager::doReloadAutoproperties(void) { if (! _autoproperties->load()) { return; } // NOTE: we need to load autoproperties after decor have been updated // as otherwise old theme data pointer will be used and sig 11 pekwm. vector::const_iterator it_c(Client::client_begin()); for (; it_c != Client::client_end(); ++it_c) { (*it_c)->readAutoprops(APPLY_ON_RELOAD); } vector::const_iterator it_f(Frame::frame_begin()); for (; it_f != Frame::frame_end(); ++it_f) { (*it_f)->readAutoprops(APPLY_ON_RELOAD); } } /** * Reload harbour configuration. */ void WindowManager::doReloadHarbour(void) { _harbour->loadTheme(); _harbour->rearrange(); _harbour->restack(); _harbour->updateHarbourSize(); } //! @brief Exit pekwm and restart with the command command void WindowManager::restart(std::string command) { if (! command.empty()) { _restart_command = command; } _restart = true; _shutdown = true; } // Event handling routins beneath this ===================================== void WindowManager::doEventLoop(void) { XEvent ev; while (! _shutdown && ! is_signal_int_term) { // Handle timeouts if (is_signal_alrm) { is_signal_alrm = false; _workspace_indicator->unmapWindow(); } // Reload if requested if (is_signal_hup || _reload) { is_signal_hup = false; doReload(); } // Get next event, drop event handling if none was given if (X11::getNextEvent(ev)) { switch (ev.type) { case MapRequest: handleMapRequestEvent(&ev.xmaprequest); break; case UnmapNotify: handleUnmapEvent(&ev.xunmap); break; case DestroyNotify: handleDestroyWindowEvent(&ev.xdestroywindow); break; case ConfigureRequest: handleConfigureRequestEvent(&ev.xconfigurerequest); break; case ClientMessage: handleClientMessageEvent(&ev.xclient); break; case ColormapNotify: handleColormapEvent(&ev.xcolormap); break; case PropertyNotify: X11::setLastEventTime(ev.xproperty.time); handlePropertyEvent(&ev.xproperty); break; case MappingNotify: handleMappingEvent(&ev.xmapping); break; case Expose: handleExposeEvent(&ev.xexpose); break; case KeyPress: case KeyRelease: X11::setLastEventTime(ev.xkey.time); handleKeyEvent(&ev.xkey); break; case ButtonPress: X11::setLastEventTime(ev.xbutton.time); handleButtonPressEvent(&ev.xbutton); break; case ButtonRelease: X11::setLastEventTime(ev.xbutton.time); handleButtonReleaseEvent(&ev.xbutton); break; case MotionNotify: X11::setLastEventTime(ev.xmotion.time); handleMotionEvent(&ev.xmotion); break; case EnterNotify: X11::setLastEventTime(ev.xcrossing.time); handleEnterNotify(&ev.xcrossing); break; case LeaveNotify: X11::setLastEventTime(ev.xcrossing.time); handleLeaveNotify(&ev.xcrossing); break; case FocusIn: handleFocusInEvent(&ev.xfocus); break; case FocusOut: break; case SelectionClear: // Another window cerr << " *** INFO: Being replaced by another WM" << endl; _shutdown = true; break; default: #ifdef HAVE_SHAPE if (X11::hasExtensionShape() && ev.type == X11::getEventShape()) { XShapeEvent *sev = reinterpret_cast(&ev); X11::setLastEventTime(sev->time); Client *client = Client::findClient(sev->window); if (client) { client->handleShapeEvent(sev); } } #endif // HAVE_SHAPE #ifdef HAVE_XRANDR if (X11::hasExtensionXRandr()) { if (ev.type == X11::getEventXRandr() + RRScreenChangeNotify) { XRRScreenChangeNotifyEvent *scr_ev = reinterpret_cast(&ev); if (scr_ev->rotation == RR_Rotate_90 || scr_ev->rotation == RR_Rotate_270) { X11::updateGeometry(scr_ev->height, scr_ev->width); } else { X11::updateGeometry(scr_ev->width, scr_ev->height); } _harbour->updateGeometry(); screenEdgeResize(); // Make sure windows are visible after resize vector::const_iterator it(PDecor::pdecor_begin()); for (; it != PDecor::pdecor_end(); ++it) { Workspaces::placeWoInsideScreen(*it); } } } #endif // HAVE_XRANDR break; } } } } void WindowManager::showWSIndicator(void) const { auto timeout = Config::instance()->getShowWorkspaceIndicator(); if (timeout > 0) { _workspace_indicator->render(); _workspace_indicator->mapWindowRaised(); struct itimerval value; timerclear(&value.it_value); timerclear(&value.it_interval); value.it_value.tv_sec += timeout / 1000; value.it_value.tv_usec += (timeout % 1000) * 1000; setitimer(ITIMER_REAL, &value, 0); } } //! @brief Handle XKeyEvents void WindowManager::handleKeyEvent(XKeyEvent *ev) { bool matched = false; ActionEvent *ae = 0; PWinObj *wo, *wo_orig; wo = wo_orig = PWinObj::getFocusedPWinObj(); PWinObj::Type type = (wo) ? wo->getType() : PWinObj::WO_SCREEN_ROOT; if (wo && wo->getWindow() == ev->window) { wo->setLastActivity(ev->time); } switch (type) { case PWinObj::WO_CLIENT: case PWinObj::WO_FRAME: case PWinObj::WO_SCREEN_ROOT: case PWinObj::WO_MENU: if (ev->type == KeyPress) { ae = _keygrabber->findAction(ev, type, &matched); } break; case PWinObj::WO_CMD_DIALOG: case PWinObj::WO_SEARCH_DIALOG: if (ev->type == KeyPress) { ae = wo->handleKeyPress(ev); } else { ae = wo->handleKeyRelease(ev); } wo = static_cast(wo)->getWORef(); break; default: if (wo) { if (ev->type == KeyPress) { ae = wo->handleKeyPress(ev); } else { ae = wo->handleKeyRelease(ev); } } break; } handleKeyEventAction(ev, ae, wo, wo_orig); // Flush Enter events caused by keygrabbing if (matched) { XEvent e; while (X11::checkTypedEvent(EnterNotify, &e)) { if (! e.xcrossing.send_event) { X11::setLastEventTime(e.xcrossing.time); } } } } void WindowManager::handleKeyEventAction(XKeyEvent *ev, ActionEvent *ae, PWinObj *wo, PWinObj *wo_orig) { if (!ae) { return; } // HACK: Always close CmdDialog and SearchDialog before actions if (wo_orig && (wo_orig->getType() == PWinObj::WO_CMD_DIALOG || wo_orig->getType() == PWinObj::WO_SEARCH_DIALOG)) { ::Action close_action; ActionEvent close_ae; close_ae.action_list.push_back(close_action); close_ae.action_list.back().setAction(ACTION_CLOSE); ActionPerformed close_ap(wo_orig, close_ae); _action_handler->handleAction(close_ap); } ActionPerformed ap(wo, *ae); ap.type = ev->type; ap.event.key = ev; _action_handler->handleAction(ap); } void WindowManager::handleButtonPressEvent(XButtonEvent *ev) { // Clear event queue while (X11::checkTypedEvent(ButtonPress, (XEvent *) ev)) { if (! ev->send_event) { X11::setLastEventTime(ev->time); } } ActionEvent *ae = 0; PWinObj *wo = 0; wo = PWinObj::findPWinObj(ev->window); if (wo) { // Update all objects (and again if child found) wo->setLastActivity(ev->time); ae = wo->handleButtonPress(ev); if (wo->getType() == PWinObj::WO_FRAME) { // this is done so that clicking the titlebar executes action on // the client clicked on, doesn't apply when subwindow is set (meaning // a titlebar button beeing pressed) if ((ev->subwindow == None) && (ev->window == static_cast(wo)->getTitleWindow())) { wo = static_cast(wo)->getChildFromPos(ev->x); } else { wo = static_cast(wo)->getActiveChild(); } if (wo != 0) { wo->setLastActivity(ev->time); } } } if (ae) { ActionPerformed ap(wo, *ae); ap.type = ev->type; ap.event.button = ev; _action_handler->handleAction(ap); } else { DockApp *da = _harbour->findDockAppFromFrame(ev->window); if (da) { _harbour->handleButtonEvent(ev, da); } } } void WindowManager::handleButtonReleaseEvent(XButtonEvent *ev) { // Flush ButtonReleases while (X11::checkTypedEvent(ButtonRelease, (XEvent *) ev)) { if (! ev->send_event) { X11::setLastEventTime(ev->time); } } ActionEvent *ae = 0; PWinObj *wo = PWinObj::findPWinObj(ev->window); if (wo == _root_wo && ev->subwindow != None) { wo = PWinObj::findPWinObj(ev->subwindow); } if (wo) { // Kludge for the case that wo is freed by handleButtonRelease(.). PWinObj::Type wotype = wo->getType(); ae = wo->handleButtonRelease(ev); if (wotype == PWinObj::WO_FRAME) { // this is done so that clicking the titlebar executes action on // the client clicked on, doesn't apply when subwindow is set (meaning // a titlebar button beeing pressed) if ((ev->subwindow == None) && (ev->window == static_cast(wo)->getTitleWindow())) { wo = static_cast(wo)->getChildFromPos(ev->x); } else { wo = static_cast(wo)->getActiveChild(); } } if (ae) { ActionPerformed ap(wo, *ae); ap.type = ev->type; ap.event.button = ev; _action_handler->handleAction(ap); } } else { DockApp *da = _harbour->findDockAppFromFrame(ev->window); if (da) { _harbour->handleButtonEvent(ev, da); } } } void WindowManager::handleConfigureRequestEvent(XConfigureRequestEvent *ev) { Client *client = Client::findClientFromWindow(ev->window); if (client) { ((Frame*) client->getParent())->handleConfigureRequest(ev, client); } else { DockApp *da = _harbour->findDockApp(ev->window); if (da) { _harbour->handleConfigureRequestEvent(ev, da); } else { // Since this window isn't yet a client lets delegate // the configure request back to the window so it can use it. XWindowChanges wc; wc.x = ev->x; wc.y = ev->y; wc.width = ev->width; wc.height = ev->height; wc.sibling = ev->above; wc.stack_mode = ev->detail; XConfigureWindow(X11::getDpy(), ev->window, ev->value_mask, &wc); } } } /** * Handle motion event, match on event window expect when event window * is root and subwindow is set then also match on menus. */ void WindowManager::handleMotionEvent(XMotionEvent *ev) { ActionEvent *ae = 0; PWinObj *wo = PWinObj::findPWinObj(ev->window); if (wo == _root_wo && ev->subwindow != None) { wo = PWinObj::findPWinObj(ev->subwindow); } if (wo) { if (wo->getType() == PWinObj::WO_CLIENT) { ae = wo->getParent()->handleMotionEvent(ev); } else if (wo->getType() == PWinObj::WO_FRAME) { ae = wo->handleMotionEvent(ev); // this is done so that clicking the titlebar executes action on // the client clicked on if (ev->subwindow != None) { wo = static_cast(wo)->getActiveChild(); } else { wo = static_cast(wo)->getChildFromPos(ev->x); } } else { ae = wo->handleMotionEvent(ev); } if (ae) { ActionPerformed ap(wo, *ae); ap.type = ev->type; ap.event.motion = ev; _action_handler->handleAction(ap); } } else { DockApp *da = _harbour->findDockAppFromFrame(ev->window); if (da) { _harbour->handleMotionNotifyEvent(ev, da); } } } void WindowManager::handleMapRequestEvent(XMapRequestEvent *ev) { PWinObj *wo = PWinObj::findPWinObj(ev->window); if (wo) { wo->handleMapRequest(ev); } else { createClient(ev->window, true); } } //! @brief void WindowManager::handleUnmapEvent(XUnmapEvent *ev) { PWinObj *wo = PWinObj::findPWinObj(ev->window); PWinObj *wo_search = 0; PWinObj::Type wo_type = PWinObj::WO_NO_TYPE; if (wo) { wo_type = wo->getType(); if (wo_type == PWinObj::WO_CLIENT) { wo_search = wo->getParent(); } wo->handleUnmapEvent(ev); if (wo == PWinObj::getFocusedPWinObj()) { PWinObj::setFocusedPWinObj(0); } } else { DockApp *da = _harbour->findDockApp(ev->window); if (da) { if (ev->window == ev->event) { _harbour->removeDockApp(da); } } } if (wo_type != PWinObj::WO_MENU && wo_type != PWinObj::WO_CMD_DIALOG && wo_type != PWinObj::WO_SEARCH_DIALOG && ! PWinObj::getFocusedPWinObj()) { findWOAndFocus(wo_search); } Workspaces::layoutIfTiling(); } void WindowManager::handleDestroyWindowEvent(XDestroyWindowEvent *ev) { Client *client = Client::findClientFromWindow(ev->window); if (client) { PWinObj *wo_search = client->getParent(); client->handleDestroyEvent(ev); if (! PWinObj::getFocusedPWinObj()) { findWOAndFocus(wo_search); } } else { DockApp *da = _harbour->findDockApp(ev->window); if (da) { da->setAlive(false); _harbour->removeDockApp(da); } } } void WindowManager::handleEnterNotify(XCrossingEvent *ev) { // Clear event queue while (X11::checkTypedEvent(EnterNotify, (XEvent *) ev)) { if (! ev->send_event) { X11::setLastEventTime(ev->time); } } if ((ev->mode == NotifyGrab) || (ev->mode == NotifyUngrab)) { return; } PWinObj *wo = PWinObj::findPWinObj(ev->window); if (wo) { if (wo->getType() == PWinObj::WO_CLIENT) { wo = wo->getParent(); } ActionEvent *ae = wo->handleEnterEvent(ev); if (ae) { ActionPerformed ap(wo, *ae); ap.type = ev->type; ap.event.crossing = ev; _action_handler->handleAction(ap); } } } void WindowManager::handleLeaveNotify(XCrossingEvent *ev) { // Clear event queue while (X11::checkTypedEvent(LeaveNotify, (XEvent *) ev)) { if (! ev->send_event) { X11::setLastEventTime(ev->time); } } if ((ev->mode == NotifyGrab) || (ev->mode == NotifyUngrab)) { return; } PWinObj *wo = PWinObj::findPWinObj(ev->window); if (wo) { ActionEvent *ae = wo->handleLeaveEvent(ev); if (ae) { ActionPerformed ap(wo, *ae); ap.type = ev->type; ap.event.crossing = ev; _action_handler->handleAction(ap); } } } //! @brief Handles FocusIn Events. void WindowManager::handleFocusInEvent(XFocusChangeEvent *ev) { if (ev->mode == NotifyGrab || ev->mode == NotifyUngrab || ev->detail == NotifyVirtual) { return; } PWinObj *wo = PWinObj::findPWinObj(ev->window); if (wo) { // To simplify logic, changing client in frame wouldn't update the // focused window because wo != focused_wo woule be true. if (wo->getType() == PWinObj::WO_FRAME) { wo = static_cast(wo)->getActiveChild(); } if (! wo->isFocusable() || ! wo->isMapped()) { findWOAndFocus(0); } else if (wo != PWinObj::getFocusedPWinObj()) { // If it's a valid FocusIn event with accepatable target lets flush // all EnterNotify and LeaveNotify as they can interfere with // focusing if Sloppy or Follow like focus model is used. XEvent e_flush; while (X11::checkTypedEvent(EnterNotify, &e_flush)) { if (! e_flush.xcrossing.send_event) { X11::setLastEventTime(e_flush.xcrossing.time); } } while (X11::checkTypedEvent(LeaveNotify, &e_flush)) { if (! e_flush.xcrossing.send_event) { X11::setLastEventTime(e_flush.xcrossing.time); } } PWinObj *focused_wo = PWinObj::getFocusedPWinObj(); // convenience // unfocus last window if (focused_wo) { if (focused_wo->getType() == PWinObj::WO_CLIENT) { focused_wo->getParent()->setFocused(false); } else { focused_wo->setFocused(false); } Workspaces::setLastFocused(Workspaces::getActive(), focused_wo); } PWinObj::setFocusedPWinObj(wo); if (wo->getType() == PWinObj::WO_CLIENT) { wo->getParent()->setFocused(true); _root_wo->setEwmhActiveWindow(wo->getWindow()); // update the MRU list (except for skip focus windows, see #297) if (! static_cast(wo)->isSkip(SKIP_FOCUS_TOGGLE)) { addToMRUFront(static_cast(wo->getParent())); } } else { wo->setFocused(true); _root_wo->setEwmhActiveWindow(None); } } } } /** * Handle XClientMessageEvent events. * * @param ev Event to handle. */ void WindowManager::handleClientMessageEvent(XClientMessageEvent *ev) { if (ev->window == X11::getRoot()) { // root window messages if (ev->format == 32) { if (ev->message_type == X11::getAtom(NET_CURRENT_DESKTOP)) { Workspaces::setWorkspace(ev->data.l[0], true); } else if (ev->message_type == X11::getAtom(NET_NUMBER_OF_DESKTOPS)) { if (ev->data.l[0] > 0) { Workspaces::setSize(ev->data.l[0]); } } } } else { // client messages Client *client = Client::findClientFromWindow(ev->window); if (client) { static_cast(client->getParent())->handleClientMessage(ev, client); } } } void WindowManager::handleColormapEvent(XColormapEvent *ev) { Client *client = Client::findClient(ev->window); if (client) { client = static_cast(((Frame*) client->getParent())->getActiveChild()); client->handleColormapChange(ev); } } //! @brief Handles XPropertyEvents void WindowManager::handlePropertyEvent(XPropertyEvent *ev) { if (ev->window == X11::getRoot()) { if (ev->atom == X11::getAtom(NET_DESKTOP_NAMES)) { _root_wo->readEwmhDesktopNames(); Workspaces::setNames(); } return; } Client *client = Client::findClientFromWindow(ev->window); if (client) { ((Frame*) client->getParent())->handlePropertyChange(ev, client); } } //! @brief Handles XMappingEvent void WindowManager::handleMappingEvent(XMappingEvent *ev) { if (ev->request == MappingKeyboard || ev->request == MappingModifier) { XRefreshKeyboardMapping(ev); X11::setLockKeys(); InputDialog::reloadKeysymMap(); doReloadKeygrabber(true); } } void WindowManager::handleExposeEvent(XExposeEvent *ev) { ActionEvent *ae = 0; PWinObj *wo = PWinObj::findPWinObj(ev->window); if (wo) { ae = wo->handleExposeEvent(ev); } if (ae) { ActionPerformed ap(wo, *ae); ap.type = ev->type; ap.event.expose = ev; _action_handler->handleAction(ap); } } // Event handling routines stop ============================================ //! @brief Searches for a PWinObj to focus, and then gives it input focus void WindowManager::findWOAndFocus(PWinObj *search) { PWinObj *focus = 0; if (PWinObj::windowObjectExists(search) && (search->isMapped()) && (search->isFocusable())) { focus = search; } // search window object didn't exist, go through the MRU list if (! focus) { vector::const_iterator f_it = _mru.begin(); for (; ! focus && f_it != _mru.end(); ++f_it) { if ((*f_it)->isMapped() && (*f_it)->isFocusable()) { focus = *f_it; } } } if (focus) { focus->giveInputFocus(); } else if (! PWinObj::getFocusedPWinObj()) { _root_wo->giveInputFocus(); _root_wo->setEwmhActiveWindow(None); } } //! @brief Raises the client and all window having transient relationship with it //! @param client Client part of the famliy //! @param raise If true, raise frames, else lowers them void WindowManager::familyRaiseLower(Client *client, bool raise) { Client *parent; Window win_search; if (! client->getTransientForClient()) { parent = client; win_search = client->getWindow(); } else { parent = client->getTransientForClient(); win_search = client->getTransientForClientWindow(); } vector client_list; Client::findFamilyFromWindow(client_list, win_search); if (parent) { // make sure parent gets underneath the children if (raise) { client_list.insert(client_list.begin(), parent); } else { client_list.push_back(parent); } } Frame *frame; vector::const_iterator it(client_list.begin()); for (; it != client_list.end(); ++it) { frame = dynamic_cast((*it)->getParent()); if (frame) { if (raise) { frame->raise(); } else { frame->lower(); } } } } Client* WindowManager::createClient(Window window, bool is_new) { Client *client = 0; ClientInitConfig initConfig; XWindowAttributes attr; XGetWindowAttributes(X11::getDpy(), window, &attr); if (! attr.override_redirect && (is_new || attr.map_state != IsUnmapped)) { // We need to figure out whether or not this is a dockapp. XWMHints *wm_hints = XGetWMHints(X11::getDpy(), window); if (wm_hints) { if ((wm_hints->flags&StateHint) && (wm_hints->initial_state == WithdrawnState)) { _harbour->addDockApp(new DockApp(window)); } else { client = new Client(window, initConfig, is_new); } XFree(wm_hints); } else { client = new Client(window, initConfig, is_new); } } if (client) { if (client->isAlive()) { if (initConfig.parent_is_new) { Workspaces::insert(client->getParent(), true); } // Make sure the window is mapped, this is done after it has been // added to the decor/frame as otherwise IsViewable state won't // be correct and we don't know whether or not to place the window if (initConfig.map) { client->mapWindow(); } // Focus was requested by the configuration, look out for // focus stealing. if (initConfig.focus) { PWinObj *wo = PWinObj::getFocusedPWinObj(); Time time_protect = static_cast