Importing pekwm as alternative wm. Adopting it to ede build system including autoconf checks.

Also center ede-launch window.
This commit is contained in:
Sanel Zukan 2011-10-23 00:10:40 +00:00
parent dd008c9ac3
commit eed5749909
171 changed files with 37768 additions and 27 deletions

52
AUTHORS.pekwm Normal file
View File

@ -0,0 +1,52 @@
-- AUTHORS for pekwm
Author:
* Claes Nasten <pekdon{@}pekdon{.}net>
Patchers:
* Andreas <ioerror{@}lavabit{.}com>
- Bug fixing.
- Code cleanup.
* Jyri Jokinen <shared{@}suffi{.}net>
- Documentation since 0.1.3.
* Rando Christensen <rando{@}babblica{.}net>
- Autoconf scripts.
- Documentation since 0.1.1.
- Ideas, bug reports and moral support.
* Lurene Frenier <lurene{@}daemonkitty{.}net>
- Make file patches.
Moral support:
* Alexandra Walford <chroma{@}delusion{.}de>
- Moral support.
- English and CSS support.
* Christoph Strake <me{@}chr1z{.}de>
- Default Theme author.
- WWW design consultant.
Testers and Requsters:
* Ashwin <ashwind{@}cyberwaveindia{.}com>
- Beta testing, many good bug reports.
* Michael ? <themadmind{@}optushome{.}com{.}au>
- GCC-3.1.0 compile verification.
-- AUTHORS for aewm++ 1.0.16
Author:
* Frank Hale <frankhale{@}yahoo{.}com>
-- AUTHORS for aewm
Author:
* Decklin Foster <decklin{@}red-bean{.}com>

View File

@ -60,6 +60,11 @@ EDE_PANEL_APPLETS_DIR ?= "$(EDE_DATA_DIR)/$(EDE_PREFIX_SUBDIR)/panel-applets" ;
DBUS_SERVICE_DIR ?= "$(datarootdir)/dbus-1/services" ;
XSESSIONS_DIR ?= "$(datarootdir)/xsessions" ;
PEKWM_CONFIG_DIR ?= "$(sysconfdir)/pekwm" ;
PEKWM_DATA_DIR ?= "$(datadir)/pekwm" ;
PEKWM_CXXFLAGS ?= "@PEKWM_CXXFLAGS@" ;
PEKWM_LIBS ?= "@PEKWM_LIBS@" ;
OPTIMFLAGS ?= @EDE_OPTIM_FLAGS@ ;
DEBUGFLAGS ?= @EDE_DEBUG_FLAGS@ ;
LARGEFILEFLAGS ?= @LARGEFILE@ ;

View File

@ -44,8 +44,7 @@ if ! $(SUN_COMPILER) {
SubInclude TOP ede-panel ;
}
# they will not be compiled if eFLTK wasn't found
SubInclude TOP edewm ;
SubInclude TOP pekwm ;
# efiler is not compileable at all
if $(WITH_EFILER) = 1 {

View File

@ -108,10 +108,10 @@ else
fi
if test -n "$with_edelib_path"; then
PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$with_edelib_path"
export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$with_edelib_path"
else
dnl TODO: remove this in release
PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/opt/ede/lib/pkgconfig"
export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/opt/ede/lib/pkgconfig"
fi
PKG_CHECK_MODULES(EDELIB, [edelib],, [have_edelib=no])
@ -230,8 +230,8 @@ AC_TRY_LINK([
],[have_xkbrules=yes],[])
AC_LANG_RESTORE
CFLAGS="ac_save_CFLAGS"
LIBS="ac_save_LIBS"
CFLAGS="$ac_save_CFLAGS"
LIBS="$ac_save_LIBS"
if test "$have_xkbrules" = "yes"; then
AC_DEFINE(HAVE_XKBRULES, 1, [Define to 1 if you have XKB extension])
@ -256,6 +256,9 @@ else
AC_MSG_RESULT(no)
fi
dnl pekwm specific macros
EDE_CHECK_PEKWM_DEPENDENCIES
dnl expand variables before EDE_INIT_JAM convert them to jam variables
EDE_EXPAND(sysconfdir, "NONE", my_sysconfdir)
@ -276,6 +279,8 @@ AC_SUBST(CURL_LIBS)
AC_SUBST(LARGEFILE)
AC_SUBST(XKB_LIBS)
AC_SUBST(my_sysconfdir)
AC_SUBST(PEKWM_CXXFLAGS)
AC_SUBST(PEKWM_LIBS)
AC_OUTPUT([
Jamconfig

View File

@ -23,3 +23,4 @@ SubInclude TOP data mime-types ;
SubInclude TOP data icon-themes ;
SubInclude TOP data menu ;
SubInclude TOP data desktop-links ;
SubInclude TOP data pekwm ;

24
data/pekwm/Jamfile Normal file
View File

@ -0,0 +1,24 @@
#
# $Id: Jamfile 2858 2009-10-03 07:24:06Z karijes $
#
# Part of Equinox Desktop Environment (EDE).
# Copyright (c) 2009-2011 EDE Authors.
#
# This program is licensed under terms of the
# GNU General Public License version 2 or newer.
# See COPYING for details.
SubDir TOP data pekwm ;
InstallData $(PEKWM_CONFIG_DIR) :
autoproperties
autoproperties_typerules
config
keys
menu
mouse
start
vars ;
SubInclude TOP data pekwm themes ;
SubInclude TOP data pekwm scripts ;

248
data/pekwm/autoproperties Normal file
View File

@ -0,0 +1,248 @@
/*
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"
# }
# }

View File

@ -0,0 +1,44 @@
/*
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" {
}

108
data/pekwm/config Normal file
View File

@ -0,0 +1,108 @@
Files {
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 = "4"
WorkspacesPerRow = "4"
WorkspaceNames = "Main;Web;E-mail;Music"
ShowFrameList = "True"
ShowStatusWindow = "True"
ShowStatusWindowCenteredOnRoot = "False"
ShowClientID = "False"
ShowWorkspaceIndicator = "500"
PlaceNew = "True"
FocusNew = "True"
ReportAllClients = "False"
TrimTitle = "..."
FullscreenAbove = "True"
FullscreenDetect = "True"
HonourRandr = "True"
HonourAspectRatio = "True"
EdgeSize = "1 1 1 1"
EdgeIndent = "False"
PixmapCacheSize = "20"
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"
}
}

315
data/pekwm/keys Normal file
View File

@ -0,0 +1,315 @@
INCLUDE = "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 = "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 = "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" }
}
}
# 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 = "Left" { Actions = "LeaveSubmenu" }
KeyPress = "Right" { Actions = "EnterSubmenu" }
KeyPress = "Return" { Actions = "Select" }
KeyPress = "space" { Actions = "Select" }
KeyPress = "Escape" { Actions = "Close" }
KeyPress = "Q" { Actions = "Close" }
}

147
data/pekwm/menu Normal file
View File

@ -0,0 +1,147 @@
# Menu config for pekwm
# Variables
INCLUDE = "vars"
RootMenu = "Pekwm" {
Entry = "Terminal" { Actions = "Exec $TERM &" }
Entry = "Run.." { Actions = "ShowCmdDialog" }
Separator {}
Submenu = "Editors" {
Entry = "vim" { Actions = "Exec $TERM -title vim -e vim &" }
Entry = "gvim" { Actions = "Exec gvim &" }
Entry = "Emacs" { Actions = "Exec emacs &" }
Entry = "Emacs Terminal" { Actions = "Exec $TERM -title emacs -e emacs -nw &" }
Entry = "Kate" { Actions = "Exec kate &" }
}
Submenu = "Graphics" {
Entry = "display" { Actions = "Exec display &" }
Entry = "Gimp" { Actions = "Exec gimp &" }
Entry = "Gv" { Actions = "Exec gv &" }
Entry = "Xpdf" { Actions = "Exec xpdf &" }
Entry = "gqview" { Actions = "Exec gqview &" }
}
Submenu = "Multimedia" {
Entry = "Amarok" { Actions = "Exec amarok &" }
Entry = "Quod Libet" { Actions = "Exec quodlibet &" }
Entry = "Xmms" { Actions = "Exec xmms &" }
Entry = "MPlayer" { Actions = "Exec gnome-mplayer &" }
Entry = "Xine" { Actions = "Exec xine &" }
Entry = "xawtv" { Actions = "Exec xawtv &" }
Entry = "Totem" { actions = "exec totem &" }
Entry = "alsamixer" { Actions = "Exec $TERM -title alsamixer -e alsamixer &" }
}
Submenu = "Utils" {
Entry = "Calculator" { Actions = "Exec gcalctool &" }
Entry = "Xpdf" { Actions = "Exec xpdf &" }
Entry = "Evince" { Actions = "Exec evince &" }
Entry = "gucharmap" { Actions = "Exec gucharmap &" }
Entry = "Gkrellm" { Actions = "Exec gkrellm &" }
}
Submenu = "WWW" {
Entry = "Dillo" { Actions = "Exec dillo &" }
Entry = "Konqueror" { Actions = "Exec konqueror &" }
Entry = "Firefox" { Actions = "Exec firefox &" }
}
Submenu = "FTP" {
Entry = "gftp" { Actions = "Exec gftp &" }
Entry = "lftp" { Actions = "Exec $TERM -title lftp -e lftp &" }
}
Submenu = "Communication" {
Entry = "Mutt" { Actions = "Exec $TERM -title mutt -e mutt &" }
Entry = "Alpine" { Actions = "Exec $TERM -title alpine -e alpine &" }
Entry = "Thunderbird" { Actions = "Exec thunderbird &" }
Entry = "Evolution" { Actions = "Exec evolution &" }
Entry = "KMail" { Actions = "Exec kmail &" }
Entry = "Pidgin" { Actions = "Exec pidgin &" }
Entry = "Irssi" { Actions = "Exec $TERM -title irssi -e irssi &" }
Entry = "Kopete" { Actions = "Exec kopete &" }
}
Submenu = "Office" {
Entry = "KOffice Workspace" { Actions = "Exec koshell &" }
Entry = "OpenOffice" { Actions = "Exec ooffice &" }
}
Submenu = "Development" {
Entry = "Anjuta" { Actions = "Exec anjuta &" }
Entry = "Eclipse" { Actions = "Exec eclipse &" }
Entry = "KDevelop" { Actions = "Exec kdevelop &" }
}
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" } }
}

182
data/pekwm/mouse Normal file
View File

@ -0,0 +1,182 @@
FrameTitle {
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" }
# Remove the following line if you want to use click to focus.
#Enter = "Any Any" { Actions = "Focus" }
}
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" }
# Remove the following line if you want to use click to focus.
#Enter = "Any Any" { Actions = "Focus" }
}
Border {
TopLeft {
# Remove the following line if you want to use click to focus.
#Enter = "Any Any" { Actions = "Focus" }
ButtonPress = "1" { Actions = "Focus; Resize TopLeft" } }
Top {
# Remove the following line if you want to use click to focus.
#Enter = "Any Any" { Actions = "Focus" }
ButtonPress = "1" { Actions = "Focus; Resize Top" } }
TopRight {
# Remove the following line if you want to use click to focus.
#Enter = "Any Any" { Actions = "Focus" }
ButtonPress = "1" { Actions = "Focus; Resize TopRight" } }
Left {
# Remove the following line if you want to use click to focus.
#Enter = "Any Any" { Actions = "Focus" }
ButtonPress = "1" { Actions = "Focus; Resize Left" } }
Right {
# Remove the following line if you want to use click to focus.
#Enter = "Any Any" { Actions = "Focus" }
ButtonPress = "1" { Actions = "Focus; Resize Right" } }
BottomLeft {
# Remove the following line if you want to use click to focus.
#Enter = "Any Any" { Actions = "Focus" }
ButtonPress = "1" { Actions = "Focus; Resize BottomLeft" } }
Bottom {
# Remove the following line if you want to use click to focus.
#Enter = "Any Any" { Actions = "Focus" }
ButtonPress = "1" { Actions = "Focus; Resize Bottom" } }
BottomRight {
# Remove the following line if you want to use click to focus.
#Enter = "Any Any" { Actions = "Focus" }
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 {
# Remove the following line and uncomment the alternative if windows should raise when clicked.
#ButtonPress = "1" { Actions = "Focus" }
# Uncomment the following line if windows should raise when clicked.
ButtonPress = "1" { Actions = "Focus; Raise" }
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" }
# Remove the following line if you want to use click to focus.
#Enter = "Any Any" { Actions = "Focus" }
}
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" }
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" }
}

View File

@ -0,0 +1,13 @@
#
# $Id: Jamfile 2858 2009-10-03 07:24:06Z karijes $
#
# Part of Equinox Desktop Environment (EDE).
# Copyright (c) 2009-2011 EDE Authors.
#
# This program is licensed under terms of the
# GNU General Public License version 2 or newer.
# See COPYING for details.
SubDir TOP data pekwm scripts ;
InstallProgram "$(PEKWM_DATA_DIR)/scripts" : pekwm_themeset.sh pekwm_ws_menu.sh ;

View File

@ -0,0 +1,65 @@
#!/bin/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}" | /bin/sed -e "s@^${HOME}@~@" | /bin/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
/bin/sed -e "s/^\([^#]*\)[Tt][Hh][Ee][Mm][Ee]\ =\ \"[^\"]*\"/\\1Theme\ =\ \"${theme}\"/" "${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

View File

@ -0,0 +1,31 @@
#!/bin/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

18
data/pekwm/start Normal file
View File

@ -0,0 +1,18 @@
#!/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

13
data/pekwm/themes/Jamfile Normal file
View File

@ -0,0 +1,13 @@
#
# $Id: Jamfile 2858 2009-10-03 07:24:06Z karijes $
#
# Part of Equinox Desktop Environment (EDE).
# Copyright (c) 2009-2011 EDE Authors.
#
# This program is licensed under terms of the
# GNU General Public License version 2 or newer.
# See COPYING for details.
SubDir TOP data pekwm themes ;
SubInclude TOP data pekwm themes default ;

View File

@ -0,0 +1,216 @@
# 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"
}

View File

@ -0,0 +1,15 @@
#
# $Id: Jamfile 2858 2009-10-03 07:24:06Z karijes $
#
# Part of Equinox Desktop Environment (EDE).
# Copyright (c) 2009-2011 EDE Authors.
#
# This program is licensed under terms of the
# GNU General Public License version 2 or newer.
# See COPYING for details.
SubDir TOP data pekwm themes default ;
IMAGES = [ Wildcard *.png ] ;
InstallData "$(PEKWM_DATA_DIR)/themes/default" : $(IMAGES) theme ;

Binary file not shown.

After

Width:  |  Height:  |  Size: 679 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 679 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 875 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 679 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 607 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 607 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 562 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 392 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 392 B

View File

@ -0,0 +1,225 @@
# 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#Center"
Require {
Templates = "True"
}
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"
FocusedSelected = "white"
Unfocused = "#777777"
UnfocusedSelected = "#777777"
}
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 = "BaseButtons" {
Buttons {
Right = "Close" {
Focused = "Image button.png"
Unfocused = "Image button_unfocus.png"
Hoover = "Image button_hover.png"
Pressed = "Image button_press.png"
Button = "1" { Actions = "Close" }
Button = "3" { Actions = "Kill" }
}
Right = "Maximize" {
Focused = "Image button.png"
Unfocused = "Image button_unfocus.png"
Hoover = "Image button_hover.png"
Pressed = "Image button_press.png"
Button = "1" { Actions = "Toggle Maximized 1 1" }
}
Right = "Iconify" {
Focused = "Image button.png"
Unfocused = "Image button_unfocus.png"
Hoover = "Image button_hover.png"
Pressed = "Image button_press.png"
Button = "1" { Actions = "Set Iconified" }
}
Left = "Shade" {
Focused = "Image button.png"
Unfocused = "Image button_unfocus.png"
Hoover = "Image button_hover.png"
Pressed = "Image button_press.png"
Button = "1" { Actions = "Toggle Shaded" }
}
}
}
Define = "EmptyDecor" {
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"
}
}
}
PDecor {
Decor = "Default" {
Title {
@BaseDecor
@BaseButtons
}
}
Decor = "Menu" {
Title {
@BaseDecor
}
}
Decor = "Titlebarless" {
Title {
@EmptyDecor
}
}
Decor = "Statuswindow" {
Title {
@EmptyDecor
}
}
}
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"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 305 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 550 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 550 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 550 B

1
data/pekwm/vars Normal file
View File

@ -0,0 +1 @@
$TERM="xterm -fn fixed +sb -bg white -fg black"

View File

@ -41,6 +41,7 @@
#include <edelib/MessageBox.h>
#include <edelib/String.h>
#include <edelib/File.h>
#include <edelib/WindowUtils.h>
#include <edelib/Ede.h>
#include "icons/run.xpm"
@ -58,6 +59,7 @@ EDELIB_NS_USING(run_sync)
EDELIB_NS_USING(run_async)
EDELIB_NS_USING(alert)
EDELIB_NS_USING(file_path)
EDELIB_NS_USING(window_center_on_screen)
static Fl_Pixmap image_run((const char**)run_xpm);
static Fl_Input* dialog_input;
@ -363,6 +365,7 @@ static int start_dialog(int argc, char** argv) {
cancel->callback(cancel_cb, win);
win->end();
win->window_icon(run_xpm);
window_center_on_screen(win);
win->show(argc, argv);
return Fl::run();

View File

@ -8,81 +8,82 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2005-02-04 12:33+0100\n"
"POT-Creation-Date: 2011-10-22 12:11+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
#: Desktop.cpp:138 Desktop.cpp:180
#: edewm/Desktop.cpp:138 edewm/Desktop.cpp:180
#, c-format
msgid "Workspace %d"
msgstr ""
#: Frame.cpp:106
#: edewm/Frame.cpp:146
msgid "Untitled"
msgstr ""
#: Frame.cpp:938
#: edewm/Frame.cpp:977
#, c-format
msgid "EDEWM: Internal bug, when restacking (%d != %d)! Exiting... "
msgstr ""
#: Titlebar.cpp:215
#: edewm/Titlebar.cpp:225
msgid "Sticky"
msgstr ""
#: Titlebar.cpp:275 Titlebar.cpp:320
#: edewm/Titlebar.cpp:285 edewm/Titlebar.cpp:330
msgid "Set size"
msgstr ""
#: Titlebar.cpp:276
#: edewm/Titlebar.cpp:286
msgid "Set size to window:"
msgstr ""
#: Titlebar.cpp:285
#: edewm/Titlebar.cpp:295
msgid "width:"
msgstr ""
#: Titlebar.cpp:287
#: edewm/Titlebar.cpp:297
msgid "height:"
msgstr ""
#: Titlebar.cpp:291
#: edewm/Titlebar.cpp:301
msgid "&OK"
msgstr ""
#: Titlebar.cpp:294
#: edewm/Titlebar.cpp:304
msgid "&Cancel"
msgstr ""
#: Titlebar.cpp:318 Titlebar.cpp:331
#: edewm/Titlebar.cpp:328 edewm/Titlebar.cpp:341
msgid "Maximize"
msgstr ""
#: Titlebar.cpp:319
#: edewm/Titlebar.cpp:329
msgid "Minimize"
msgstr ""
#: Titlebar.cpp:321
#: edewm/Titlebar.cpp:331
msgid "To Desktop"
msgstr ""
#: Titlebar.cpp:322
#: edewm/Titlebar.cpp:332
msgid "Kill"
msgstr ""
#: Titlebar.cpp:323
#: edewm/Titlebar.cpp:333
msgid "Close"
msgstr ""
#: Titlebar.cpp:330
#: edewm/Titlebar.cpp:340
msgid "Restore"
msgstr ""
#: Windowmanager.cpp:90
#: edewm/Windowmanager.cpp:90
#, c-format
msgid "Another window manager is running. You must exit it before running %s."
msgstr ""

View File

@ -1,10 +1,10 @@
# default ede-startup configuration
[Startup]
start_order = edewm,ede-desktop,ede-panel,emountd,xscreensaver,autostart
start_order = wm,ede-desktop,ede-panel,emountd,xscreensaver,autostart
splash_theme = scape
[edewm]
exec = edewm
[wm]
exec = pekwm
icon = edewm.png
description = Starting window manager...

200
m4/pekwm.m4 Normal file
View File

@ -0,0 +1,200 @@
dnl
dnl $Id: xlib.m4 1856 2007-03-17 11:28:25Z karijes $
dnl
dnl Part of Equinox Desktop Environment (EDE).
dnl Copyright (c) pekwm authors.
dnl
dnl This program is licenced under terms of the
dnl GNU General Public Licence version 2 or newer.
dnl See COPYING for details.
dnl all dependencies needed for pekwm
AC_DEFUN([EDE_CHECK_PEKWM_DEPENDENCIES], [
AC_LANG_SAVE
AC_LANG_CPLUSPLUS
dnl Check for iconv
dnl AM_ICONV
dnl if test "x$am_cv_func_iconv" != "xyes"; then
dnl AC_MSG_ERROR([Could not find iconv.])
dnl fi
dnl
dnl PEKWM_LIBS="$LIBS $LIBICONV"
dnl PEKWM_CXXFLAGS="$CXXFLAGS $INCICONV"
dnl PEKWM_FEATURES=""
dnl
dnl Check for iconvctl
AC_CHECK_FUNC(iconvctl, [AC_DEFINE(HAVE_ICONVCTL, [1], [Define to 1 if you the iconvctl call])], )
dnl Check for Xinerama support
AC_MSG_CHECKING([whether to build support for the Xinerama extension])
AC_CHECK_LIB(Xinerama, XineramaQueryScreens,
AC_DEFINE(HAVE_XINERAMA, [1], [Define to 1 if you want Xinerama support to be])
PEKWM_LIBS="$PEKWM_LIBS -lXinerama"
PEKWM_FEATURES="$PEKWM_FEATURES Xinerama")
dnl Check for Xft support
AC_MSG_CHECKING([whether to support Xft fonts])
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])
PEKWM_LIBS="$PEKWM_LIBS $xft_LIBS"
PEKWM_CXXFLAGS="$PEKWM_CXXFLAGS $xft_CFLAGS"
PEKWM_FEATURES="$PEKWM_FEATURES Xft";
else
AC_MSG_WARN([Couldn't find Xft >= 2.0.0])
fi
if test "x$HAVE_LIBPNG" = "xyes"; then
THEME="default"
else
THEME="default-plain"
fi
AC_SUBST([THEME])
dnl Check for XRANDR support
AC_MSG_CHECKING([wheter to build support for the XRANDR extension])
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])
PEKWM_LIBS="$PEKWM_LIBS $xrandr_LIBS"
PEKWM_CXXFLAGS="$PEKWM_CXXFLAGS $xrandr_CFLAGS"
PEKWM_FEATURES="$PEKWM_FEATURES Xrandr"
else
AC_MSG_WARN([Couldn't find Xrandr >= 1.2.0])
fi
dnl Check for header files
AC_STDC_HEADERS
AC_CHECK_HEADERS([limits slist ext/slist])
dnl Check that at least one of slist or ext/slist exists
if test "x$av_cv_header_slist" = "xno" \
&& test "x$av_cv_header_ext_slist" = "xno"; then
AC_MSG_ERROR([Could not find slist or ext/slist include.])
fi
dnl Detect namespace slist is available in
AC_TRY_COMPILE([
#ifdef HAVE_SLIST
#include <slist>
#else // HAVE_EXT_SLIST
#include <ext/slist>
#endif // HAVE_SLIST
],[std::slist<int> test;],
AC_DEFINE(SLIST_NAMESPACE, [std], [Name of namespace slist is in])
slist_std_namespace=yes, [])
if test "x$slist_std_namespace" != "xyes"; then
AC_TRY_COMPILE([
#ifdef HAVE_SLIST
#include <slist>
#else // HAVE_EXT_SLIST
#include <ext/slist>
#endif // HAVE_SLIST
],[__gnu_cxx::slist<int> test;],
AC_DEFINE(SLIST_NAMESPACE, [__gnu_cxx], [Name of namespace slist is in]), [])
fi
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_TRY_LINK([#include <sys/time.h>],
[struct timeval *a; timersub(a, a, a);],
[have_timersub=yes],[])
if test "x$have_timersub" = "xyes"; then
AC_MSG_RESULT(yes)
AC_DEFINE([HAVE_TIMERSUB], 1, [Define to 1 if your system defines timersub.])
else
AC_MSG_RESULT(no)
fi
dnl Check for XPM support
AC_MSG_CHECKING([wheter to build support XPM images])
AC_CHECK_LIB(Xpm, XpmReadFileToPixmap,
AC_MSG_CHECKING([for X11/xpm.h])
AC_TRY_COMPILE(
#include <X11/xpm.h>
, int foo = XpmSuccess,
AC_MSG_RESULT([yes])
AC_DEFINE(HAVE_IMAGE_XPM, [1], [Define to 1 if you libXpm])
PEKWM_LIBS="$PEKWM_LIBS -lXpm"
PEKWM_FEATURES="$PEKWM_FEATURES image-xpm",
AC_MSG_RESULT([no])))
dnl Check for JPEG support
AC_CHECK_LIB(jpeg, jpeg_read_header,
AC_MSG_CHECKING([for jpeglib.h])
AC_TRY_CPP([#include <jpeglib.h>],
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])
PEKWM_LIBS="$PEKWM_LIBS -ljpeg"
PEKWM_FEATURES="$PEKWM_FEATURES image-jpeg"
fi,
AC_MSG_RESULT([no]))
dnl Check for PNG support
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])
PEKWM_LIBS="$PEKWM_LIBS $libpng12_LIBS"
PEKWM_CXXFLAGS="$PEKWM_CXXFLAGS $libpng12_CFLAGS"
PEKWM_FEATURES="$PEKWM_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])
PEKWM_LIBS="PEKWM_$LIBS $libpng_LIBS"
PEKWM_CXXFLAGS="$PEKWM_CXXFLAGS $libpng_CFLAGS"
PEKWM_FEATURES="$PEKWM_FEATURES image-png"
else
AC_MSG_RESULT([no])
fi
fi
dnl Check whether to include debugging code
dnl AC_MSG_CHECKING([whether to include verbose debugging code])
dnl AC_ARG_ENABLE(debug,
dnl AC_HELP_STRING([--enable-debug],
dnl [include verbose debugging code [default=no]]), ,
dnl [enable_debug=no])
dnl if test "x$enable_debug" = "xyes"; then
dnl AC_MSG_RESULT([yes])
dnl AC_DEFINE(DEBUG, [1], [Define to 1 to compile in debug information])
dnl FEATURES="$FEATURES debug"
dnl else
dnl AC_MSG_RESULT([no])
dnl fi
dnl
dnl dnl Check wheter to use strict warnings
dnl AC_MSG_CHECKING([whether to use strict compile-time warnings])
dnl AC_ARG_ENABLE(pedantic,
dnl AC_HELP_STRING([--enable-pedantic],
dnl [turn on strict compile-time warnings [default=no]]), ,
dnl [enable_pedantic=no])
dnl if test "$enable_pedantic" = "yes"; then
dnl AC_MSG_RESULT([yes])
dnl if test "x$GXX" = "xyes"; then
dnl CXXFLAGS="-Wall -Werror -pedantic $CXXFLAGS"
dnl fi
dnl FEATURES="$FEATURES pedantic"
dnl else
dnl AC_MSG_RESULT([no])
dnl fi
dnl
AC_DEFINE(OPACITY, [1], [Define to 1 to compile in support for opacity hinting])
EVO=`date`
AC_DEFINE_UNQUOTED(FEATURES, "$PEKWM_FEATURES", [Build info for pekwm, do not touch])
AC_DEFINE_UNQUOTED(EXTRA_VERSION_INFO, " Built on $EVO", [Build info for pekwm, do not touch])
AC_LANG_RESTORE
])

243
pekwm/Action.hh Normal file
View File

@ -0,0 +1,243 @@
//
// Action.hh for pekwm
// Copyright (C) 2003-2009 Claes Nästén <me{@}pekdon{.}net>
//
// This program is licensed under the GNU GPL.
// See the LICENSE file for more information.
//
#ifndef _ACTION_HH_
#define _ACTION_HH_
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include "Types.hh"
#include <list>
#include <string>
#include <cstring>
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_MINIMIZE = 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_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_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_HIDE_WORKSPACE_INDICATOR,
ACTION_SEND_KEY,
#ifdef OPACITY
ACTION_SET_OPACITY,
#endif // OPACITY
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,
#ifdef OPACITY
ACTION_STATE_OPAQUE,
#endif // OPACITY
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) : _action(ACTION_UNSET)
{
_param_i[0] = _param_i[1] = _param_i[2] = 0;
}
Action(uint action) : _action(action)
{
_param_i[0] = _param_i[1] = _param_i[2] = 0;
}
Action(uint action, int param_i[3]) : _action(action)
{
std::memcpy(_param_i, param_i, sizeof(param_i));
}
Action(uint action, const std::string &param_s)
: _action(action), _param_s(param_s)
{
_param_i[0] = _param_i[1] = _param_i[2] = 0;
}
~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(); _param_i[0] = _param_i[1] = _param_i[2] = 0; }
private:
uint _action;
int _param_i[3];
std::string _param_s;
};
class ActionEvent {
public:
ActionEvent(void)
{
}
~ActionEvent(void)
{
}
inline bool isOnlyAction(uint action) const {
if ((action_list.size() == 1) &&
(action_list.front().getAction() == action)) {
return true;
}
return false;
}
public:
uint mod, sym; // event matching
uint type, threshold; // more matching, press, release etc
std::list<Action> 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_

1038
pekwm/ActionHandler.cc Normal file

File diff suppressed because it is too large Load Diff

78
pekwm/ActionHandler.hh Normal file
View File

@ -0,0 +1,78 @@
//
// ActionHandler.hh for pekwm
// Copyright © 2003-2009 Claes Nästén <me@pekdon.net>
//
// This program is licensed under the GNU GPL.
// See the LICENSE file for more information.
//
#ifndef _ACTIONHANDLER_HH_
#define _ACTIONHANDLER_HH_
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include "pekwm.hh"
#include "Action.hh"
#include <string>
#include <list>
#include <map>
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,
std::list<ActionEvent> *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);
#ifdef OPACITY
static void actionSetOpacity(PWinObj *client, PWinObj *frame, uint focus, uint unfocus);
#endif // OPACITY
void actionShowMenu(const std::string &name, bool stick, uint e_type, PWinObj *wo_ref);
// action helpers
Client *findClientFromTitle(const std::wstring &title);
void gotoClient(Client *client);
PMenu *createNextPrevMenu(bool show_iconified);
PMenu *createMRUMenu(bool show_iconified);
bool createMenuInclude(Frame *frame, bool show_iconified);
void initSendKeyEvent(XEvent &ev, PWinObj *wo);
private:
std::map<uint, uint> _state_to_keycode; /**< Map translating state modifiers to keycode. */
static ActionHandler *_instance; /**< Instance pointer for ActionHandler. */
};
#endif // _ACTIONHANDLER_HH_

370
pekwm/ActionMenu.cc Normal file
View File

@ -0,0 +1,370 @@
//
// ActionMenu.cc for pekwm
// Copyright © 2002-2009 Claes Nästén <me@pekdon.net>
//
// This program is licensed under the GNU GPL.
// See the LICENSE file for more information.
//
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include <cstdio>
#include <iostream>
#include <set>
#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::list;
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()->getScreen(),
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 = _item_list.begin();
_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 = _item_list.size();
rebuildDynamic();
if (size_before != _item_list.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 = _item_list.begin();
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);
_insert_at = _item_list.insert(++_insert_at, item);
}
//! @brief Non-shadowing PMenu::insert
void
ActionMenu::insert(const std::wstring &name, PWinObj *wo_ref, PTexture *icon)
{
PMenu::insert(name, wo_ref, icon);
}
//! @brief Non-shadowing PMenu::insert
void
ActionMenu::insert(const std::wstring &name, const ActionEvent &ae, PWinObj *wo_ref, PTexture *icon)
{
PMenu::insert(name, ae, wo_ref);
}
//! @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 (_item_list.size() > 0) {
remove(_item_list.back());
}
}
//! @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->get_value().size()) {
wstring title(Util::to_wide_str(section->get_value()));
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)->get_section();
if (sub_section) {
icon = getIcon(sub_section->find_entry("ICON"));
submenu = new ActionMenu(_menu_type, Util::to_wide_str((*it)->get_value()), (*it)->get_value());
submenu->_menu_parent = this;
submenu->parse(sub_section, parent);
submenu->buildMenu();
item = new PMenu::Item(Util::to_wide_str(sub_section->get_value()), 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)->get_section();
if (sub_section) {
// Inside of the Entry = "foo" { ... } section, here
// Actions and Icon are the valid options.
value = sub_section->find_entry("ACTIONS");
if (value && Config::instance()->parseActions(value->get_value(), ae, _action_ok)) {
icon = getIcon(sub_section->find_entry("ICON"));
item = new PMenu::Item(Util::to_wide_str(sub_section->get_value()), 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) {
ActionMenu::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->get_value().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->get_value());
if (! icon) {
icon = TextureHandler::instance()->getTexture("IMAGE " + value->get_value() + "#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<Client*>(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;
list<PMenu::Item*>::iterator it;
for (it = _item_list.begin(); it != _item_list.end(); ++it) {
if ((*it)->getAE().isOnlyAction(ACTION_MENU_DYN)) {
_insert_at = it;
item = *it;
CfgParser dynamic;
if (dynamic.parse((*it)->getAE().action_list.front().getParamS(),
CfgParserSource::SOURCE_COMMAND)) {
_has_dynamic = true;
parse(dynamic.get_entry_root()->find_section("DYNAMIC"), *it);
}
it = find(_item_list.begin(), _item_list.end(), item);
_insert_at = _item_list.end();
}
}
// 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<PMenu::Item *> dynlist;
list<PMenu::Item*>::iterator it(_item_list.begin());
for (; it != _item_list.end(); ++it) {
if ((*it)->getType() == PMenu::Item::MENU_ITEM_HIDDEN) {
dynlist.insert(*it);
}
}
it = _item_list.begin();
for (; it != _item_list.end();) {
if (dynlist.find((*it)->getCreator()) != dynlist.end()) {
if ((*it)->getWORef() && ((*it)->getWORef()->getType() == WO_MENU)) {
delete (*it)->getWORef();
}
delete (*it);
it = _item_list.erase(it);
} else {
++it;
}
}
}

70
pekwm/ActionMenu.hh Normal file
View File

@ -0,0 +1,70 @@
//
// ActionMenu.hh for pekwm
// Copyright © 2002-2009 Claes Nästén <me{@}pekdon{.}net>
//
// This program is licensed under the GNU GPL.
// See the LICENSE file for more information.
//
#ifndef _ACTIONMENU_HH_
#define _ACTIONMENU_HH_
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include "pekwm.hh"
#include "Action.hh" // For ActionOk
#include "CfgParser.hh"
#include "PMenu.hh"
#include <string>
#include <list>
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);
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 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;
std::list<PMenu::Item*>::iterator _insert_at;
bool _has_dynamic; /**< Set to true if any of the entries in the menu is dynamic. */
};
#endif // _ACTIONMENU_HH_

373
pekwm/Atoms.cc Normal file
View File

@ -0,0 +1,373 @@
//
// Atoms.cc for pekwm
// Copyright © 2003-2009 Claes Nästén <me@pekdon.net>
//
// This program is licensed under the GNU GPL.
// See the LICENSE file for more information.
//
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include "Atoms.hh"
#include "PScreen.hh"
#include "Util.hh"
extern "C" {
#include <X11/Xutil.h>
}
using std::string;
using std::map;
static const char *atomnames[] = {
// EWMH atoms
"_NET_SUPPORTED",
"_NET_CLIENT_LIST", "_NET_CLIENT_LIST_STACKING",
"_NET_NUMBER_OF_DESKTOPS",
"_NET_DESKTOP_GEOMETRY", "_NET_DESKTOP_VIEWPORT",
"_NET_CURRENT_DESKTOP", "_NET_DESKTOP_NAMES",
"_NET_ACTIVE_WINDOW", "_NET_WORKAREA",
"_NET_DESKTOP_LAYOUT", "_NET_SUPPORTING_WM_CHECK",
"_NET_CLOSE_WINDOW",
"_NET_WM_NAME", "_NET_WM_VISIBLE_NAME",
"_NET_WM_ICON_NAME", "_NET_WM_VISIBLE_ICON_NAME",
"_NET_WM_ICON", "_NET_WM_DESKTOP",
"_NET_WM_STRUT", "_NET_WM_PID",
"_NET_WM_WINDOW_OPACITY",
"_NET_WM_WINDOW_TYPE",
"_NET_WM_WINDOW_TYPE_DESKTOP", "_NET_WM_WINDOW_TYPE_DOCK",
"_NET_WM_WINDOW_TYPE_TOOLBAR", "_NET_WM_WINDOW_TYPE_MENU",
"_NET_WM_WINDOW_TYPE_UTILITY", "_NET_WM_WINDOW_TYPE_SPLASH",
"_NET_WM_WINDOW_TYPE_DIALOG", "_NET_WM_WINDOW_TYPE_NORMAL",
"_NET_WM_STATE",
"_NET_WM_STATE_MODAL", "_NET_WM_STATE_STICKY",
"_NET_WM_STATE_MAXIMIZED_VERT", "_NET_WM_STATE_MAXIMIZED_HORZ",
"_NET_WM_STATE_SHADED",
"_NET_WM_STATE_SKIP_TASKBAR", "_NET_WM_STATE_SKIP_PAGER",
"_NET_WM_STATE_HIDDEN", "_NET_WM_STATE_FULLSCREEN",
"_NET_WM_STATE_ABOVE", "_NET_WM_STATE_BELOW",
"_NET_WM_STATE_DEMANDS_ATTENTION",
"_NET_WM_ALLOWED_ACTIONS",
"_NET_WM_ACTION_MOVE", "_NET_WM_ACTION_RESIZE",
"_NET_WM_ACTION_MINIMIZE", "_NET_WM_ACTION_SHADE",
"_NET_WM_ACTION_STICK",
"_NET_WM_ACTION_MAXIMIZE_VERT", "_NET_WM_ACTION_MAXIMIZE_HORZ",
"_NET_WM_ACTION_FULLSCREEN", "_NET_WM_ACTION_CHANGE_DESKTOP",
"_NET_WM_ACTION_CLOSE",
"UTF8_STRING", // When adding an ewmh atom after this,
// fix setEwmhAtomsSupport(Window)
"STRING", "MANAGER",
// pekwm atoms
"_PEKWM_FRAME_ID",
"_PEKWM_FRAME_ORDER",
"_PEKWM_FRAME_ACTIVE",
"_PEKWM_FRAME_DECOR",
"_PEKWM_FRAME_SKIP",
"_PEKWM_TITLE",
// ICCCM atoms
"WM_NAME",
"WM_ICON_NAME",
"WM_CLASS",
"WM_STATE",
"WM_CHANGE_STATE",
"WM_PROTOCOLS",
"WM_DELETE_WINDOW",
"WM_COLORMAP_WINDOWS",
"WM_TAKE_FOCUS",
"WM_WINDOW_ROLE",
"WM_CLIENT_MACHINE",
// miscellaneous atoms
"_MOTIF_WM_HINTS"
};
//! @brief initialise the atoms mappings
void
Atoms::init(void)
{
const uint num = sizeof(atomnames) / sizeof(char*);
Atom *atoms = new Atom[num];
XInternAtoms(PScreen::instance()->getDpy(),
const_cast<char**>(atomnames), num, 0, atoms);
for (uint i = 0; i < num; ++i) {
_atoms[AtomName(i)] = atoms[i];
}
delete [] atoms;
}
//! @brief Builds a array of all atoms in the map.
void
Atoms::setEwmhAtomsSupport(Window win)
{
Atom *atoms = new Atom[UTF8_STRING+1];
for (uint i = 0; i <= UTF8_STRING; ++i) {
atoms[i] = _atoms[AtomName(i)];
}
AtomUtil::setAtoms(win, getAtom(NET_SUPPORTED), atoms, UTF8_STRING+1);
delete [] atoms;
}
std::map<AtomName, Atom> Atoms::_atoms;
namespace AtomUtil {
//! @brief Get unknown property
bool
getProperty(Window win, Atom atom, Atom type,
ulong expected, uchar** data, ulong *actual)
{
Atom r_type;
int r_format, status;
ulong read = 0, left = 0;
*data = 0;
do {
if (*data) {
XFree(*data);
*data = 0;
}
expected += left;
status =
XGetWindowProperty(PScreen::instance()->getDpy(), win, atom,
0L, expected, False, type,
&r_type, &r_format, &read, &left, data);
if (status != Success || type != r_type || read == 0) {
if (*data) {
XFree(*data);
*data = 0;
}
left = 0;
}
} while (left);
if (actual) {
*actual = read;
}
return (*data != 0);
}
//! @brief Set XA_ATOM, one value
void
setAtom(Window win, Atom atom, Atom value)
{
XChangeProperty(PScreen::instance()->getDpy(), win, atom, XA_ATOM, 32,
PropModeReplace, (uchar *) &value, 1);
}
//! @brief Set XA_ATOM, multiple values
void
setAtoms(Window win, Atom atom, Atom *values, int size)
{
XChangeProperty(PScreen::instance()->getDpy(), win, atom, XA_ATOM, 32,
PropModeReplace, (uchar *) values, size);
}
//! @brief Set XA_WINDOW, one value
void
setWindow(Window win, Atom atom, Window value)
{
XChangeProperty(PScreen::instance()->getDpy(), win, atom, XA_WINDOW, 32,
PropModeReplace, (uchar *) &value, 1);
}
//! @brief Set XA_WINDOW, multiple values
void
setWindows(Window win, Atom atom, Window *values, int size)
{
XChangeProperty(PScreen::instance()->getDpy(), win, atom, XA_WINDOW, 32,
PropModeReplace, (uchar *) values, size);
}
//! @brief Get XA_CARDINAL
bool
getLong(Window win, Atom atom, long &value)
{
long *data = 0;
uchar *udata = 0;
if (getProperty(win, atom, XA_CARDINAL, 1L, &udata, 0)) {
data = reinterpret_cast<long*>(udata);
value = *data;
XFree(udata);
return true;
}
return false;
}
//! @brief Set XA_CARDINAL
void
setLong(Window win, Atom atom, long value)
{
XChangeProperty(PScreen::instance()->getDpy(), win, atom, XA_CARDINAL, 32,
PropModeReplace, (uchar *) &value, 1);
}
/**
* Set array of longs as Cardinal/32.
*
* @param win Window to set longs on.
* @param atom Atom to set longs as.
* @param values Array of longs to set.
* @param size Number of elements in array.
*/
void
setLongs(Window win, Atom atom, long *values, int size)
{
XChangeProperty(PScreen::instance()->getDpy(), win, atom, XA_CARDINAL, 32,
PropModeReplace, reinterpret_cast<unsigned char*>(values), size);
}
//! @brief Get XA_STRING property
bool
getString(Window win, Atom atom, string &value)
{
uchar *data = 0;
if (getProperty(win, atom, XA_STRING, 64L, &data, 0)) {
value = string((const char*) data);
XFree(data);
return true;
}
return false;
}
//! @brief Get UTF-8 string.
bool
getUtf8String(Window win, Atom atom, std::wstring &value)
{
bool status = false;
unsigned char *data = 0;
if (getProperty(win, atom, Atoms::getAtom(UTF8_STRING),
32, &data, 0)) {
status = true;
string utf8_str(reinterpret_cast<char*>(data));
value = Util::from_utf8_str(utf8_str);
XFree(data);
}
return status;
}
//! @brief Set UTF-8 string.
void
setUtf8String(Window win, Atom atom, const std::wstring &value)
{
string utf8_string(Util::to_utf8_str(value));
XChangeProperty(PScreen::instance()->getDpy(), win, atom,
Atoms::getAtom(UTF8_STRING), 8,
PropModeReplace,
reinterpret_cast<const uchar*>(utf8_string.c_str()),
utf8_string.size());
}
/**
* Set array of UTF-8 strings.
*
* @param win Window to set string on.
* @param atom Atom to set array value.
* @param values Array of strings.
* @param length Number of elements in value.
*/
void
setUtf8StringArray(Window win, Atom atom, unsigned char *values, unsigned int length)
{
XChangeProperty(PScreen::instance()->getDpy(), win, atom, Atoms::getAtom(UTF8_STRING),
8, PropModeReplace, values, length);
}
//! @brief Set XA_STRING property
void
setString(Window win, Atom atom, const string &value)
{
XChangeProperty(PScreen::instance()->getDpy(), win, atom, XA_STRING, 8,
PropModeReplace, (uchar*) value.c_str(), value.size());
}
/**
* Read text property.
*
* @param win Window to get property from.
* @param atom Atom holding the property.
* @param value Return string.
* @return true if property was successfully read.
*/
bool
getTextProperty(Window win, Atom atom, std::string &value)
{
// Read text property, return if it fails.
XTextProperty text_property;
if (! XGetTextProperty(PScreen::instance()->getDpy(), win, &text_property, atom)
|| ! text_property.value || ! text_property.nitems) {
return false;
}
if (text_property.encoding == XA_STRING) {
value = reinterpret_cast<const char*>(text_property.value);
} else {
char **mb_list;
int num;
XmbTextPropertyToTextList(PScreen::instance()->getDpy(), &text_property, &mb_list, &num);
if (mb_list && num > 0) {
value = *mb_list;
XFreeStringList(mb_list);
}
}
XFree(text_property.value);
return true;
}
//! @brief
void*
getEwmhPropData(Window win, Atom prop, Atom type, int &num)
{
Atom type_ret;
int format_ret;
ulong items_ret, after_ret;
uchar *prop_data = 0;
XGetWindowProperty(PScreen::instance()->getDpy(), win, prop, 0, 0x7fffffff,
False, type, &type_ret, &format_ret, &items_ret,
&after_ret, &prop_data);
num = items_ret;
return prop_data;
}
/**
* Remove property from window.
*/
void
unsetProperty(Window win, Atom prop)
{
XDeleteProperty(PScreen::instance()->getDpy(), win, prop);
}
} // end namespace AtomUtil

142
pekwm/Atoms.hh Normal file
View File

@ -0,0 +1,142 @@
//
// Atoms.hh for pekwm
// Copyright © 2003-2009 Claes Nästén <me@pekdon.net>
//
// This program is licensed under the GNU GPL.
// See the LICENSE file for more information.
//
#ifndef _ATOMS_HH_
#define _ATOMS_HH_
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include "Types.hh"
#include <string>
#include <map>
extern "C" {
#include <X11/Xlib.h>
#include <X11/Xatom.h>
}
enum AtomName {
// Ewmh Atom Names
NET_SUPPORTED,
NET_CLIENT_LIST, NET_CLIENT_LIST_STACKING,
NET_NUMBER_OF_DESKTOPS,
NET_DESKTOP_GEOMETRY, NET_DESKTOP_VIEWPORT,
NET_CURRENT_DESKTOP, NET_DESKTOP_NAMES,
NET_ACTIVE_WINDOW, NET_WORKAREA,
NET_DESKTOP_LAYOUT, NET_SUPPORTING_WM_CHECK,
NET_CLOSE_WINDOW,
NET_WM_NAME, NET_WM_VISIBLE_NAME,
NET_WM_ICON_NAME, NET_WM_VISIBLE_ICON_NAME,
NET_WM_ICON, NET_WM_DESKTOP,
NET_WM_STRUT, NET_WM_PID,
NET_WM_WINDOW_OPACITY,
WINDOW_TYPE,
WINDOW_TYPE_DESKTOP, WINDOW_TYPE_DOCK,
WINDOW_TYPE_TOOLBAR, WINDOW_TYPE_MENU,
WINDOW_TYPE_UTILITY, WINDOW_TYPE_SPLASH,
WINDOW_TYPE_DIALOG, WINDOW_TYPE_NORMAL,
STATE,
STATE_MODAL, STATE_STICKY,
STATE_MAXIMIZED_VERT, STATE_MAXIMIZED_HORZ,
STATE_SHADED,
STATE_SKIP_TASKBAR, STATE_SKIP_PAGER,
STATE_HIDDEN, STATE_FULLSCREEN,
STATE_ABOVE, STATE_BELOW,
STATE_DEMANDS_ATTENTION,
EWMH_ALLOWED_ACTIONS,
EWMH_ACTION_MOVE, EWMH_ACTION_RESIZE,
EWMH_ACTION_MINIMIZE, EWMH_ACTION_SHADE,
EWMH_ACTION_STICK,
EWHM_ACTION_MAXIMIZE_VERT, EWMH_ACTION_MAXIMIZE_HORZ,
EWMH_ACTION_FULLSCREEN, ACTION_CHANGE_DESKTOP,
EWMH_ACTION_CLOSE,
UTF8_STRING, // When adding an ewmh atom after this,
// fix setEwmhAtomsSupport(Window)
STRING, MANAGER,
// pekwm atom names
PEKWM_FRAME_ID,
PEKWM_FRAME_ORDER,
PEKWM_FRAME_ACTIVE,
PEKWM_FRAME_DECOR,
PEKWM_FRAME_SKIP,
PEKWM_TITLE,
// ICCCM Atom Names
WM_NAME,
WM_ICON_NAME,
WM_CLASS,
WM_STATE,
WM_CHANGE_STATE,
WM_PROTOCOLS,
WM_DELETE_WINDOW,
WM_COLORMAP_WINDOWS,
WM_TAKE_FOCUS,
WM_WINDOW_ROLE,
WM_CLIENT_MACHINE,
// List of non PEKWM, ICCCM and EWMH atoms.
MOTIF_WM_HINTS
};
// Atoms class
class Atoms {
public:
static void init();
static inline Atom getAtom(AtomName name) {
std::map<AtomName, Atom>::const_iterator it = _atoms.find(name);
if (it != _atoms.end()) {
return it->second;
}
return None;
}
static void setEwmhAtomsSupport(Window win);
private:
static std::map<AtomName, Atom> _atoms;
};
namespace AtomUtil {
bool getProperty(Window win, Atom atom, Atom type,
ulong expected, uchar **data, ulong *actual);
void setAtom(Window win, Atom atom, Atom value);
void setAtoms(Window win, Atom atom, Atom *values, int size);
void setWindow(Window win, Atom atom, Window value);
void setWindows(Window win, Atom atom, Window *values, int size);
bool getLong(Window win, Atom atom, long &value);
void setLong(Window win, Atom atom, long value);
void setLongs(Window win, Atom atom, long *values, int size);
bool getString(Window win, Atom atom, std::string &value);
void setString(Window win, Atom atom, const std::string &value);
bool getUtf8String(Window win, Atom atom, std::wstring &value);
void setUtf8String(Window win, Atom atom, const std::wstring &value);
void setUtf8StringArray(Window win, Atom atom, unsigned char *values, unsigned int length);
bool getTextProperty(Window win, Atom atom, std::string &value);
void *getEwmhPropData(Window win, Atom prop, Atom type, int &num);
void unsetProperty(Window win, Atom prop);
}
#endif // _FONT_HH_

916
pekwm/AutoProperties.cc Normal file
View File

@ -0,0 +1,916 @@
//
// AutoProperties.cc for pekwm
// Copyright © 2003-2009 Claes Nästén <me@pekdon.net>
//
// This program is licensed under the GNU GPL.
// See the LICENSE file for more information.
//
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include <algorithm>
#include <vector>
#include <iostream>
#include "AutoProperties.hh"
#include "Config.hh"
#include "Util.hh"
using std::cerr;
using std::endl;
using std::find;
using std::list;
using std::map;
using std::string;
using std::vector;
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_NONE;
_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;
#ifdef OPACITY
_property_map["OPACITY"] = AP_OPACITY;
#endif // OPACITY
// 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 (! Util::requireReload(_cfg_state, 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.is_dynamic_content()) {
_cfg_state.clear();
} else {
_cfg_state = a_cfg.get_file_list();
}
// reset values
_apply_on_start = true;
vector<string> tokens;
vector<string>::iterator token_it;
list<uint> workspaces;
CfgParser::iterator it(a_cfg.get_entry_root()->begin());
for (; it != a_cfg.get_entry_root()->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)->get_section();
CfgParser::Entry *value = workspace->find_entry("WORKSPACE");
if (! value) {
continue; // Need workspace numbers.
}
tokens.clear();
if (Util::splitString(value->get_value(), 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) - 1);
// 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.get_entry_root()->find_section("REQUIRE");
if (section) {
list<CfgParserKey*> key_list;
key_list.push_back(new CfgParserKeyBool("TEMPLATES", _extended, false));
section->parse_key_values(key_list.begin(), key_list.end());
for_each(key_list.begin(), key_list.end(), Util::Free<CfgParserKey*>());
// 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)
{
list<Property*>::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<AtomName, AutoProperty*>::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,
std::list<Property*>* prop_list, int ws, uint type)
{
// Allready remove apply on start
if (! _apply_on_start && (type == APPLY_ON_START))
return 0;
list<Property*>::iterator it(prop_list->begin());
list<uint>::iterator w_it;
// start searching for a suitable property
for (bool ok = false; it != prop_list->end(); ++it, ok = false) {
// see if the type matches, if we have one
if ((type != 0) && ! (*it)->isApplyOn(type))
continue;
if (matchAutoClass(*class_hint, *it)) {
// make sure it applies on the correct workspace
if ((*it)->getWsList().size()) {
w_it = find((*it)->getWsList().begin(), (*it)->getWsList().end(),
unsigned(ws));
if (w_it != (*it)->getWsList().end()) {
return *it;
}
} else {
return *it;
}
}
}
return 0;
}
/**
* Parse regex_str and set on regex, outputting warning with name if
* it fails.
*/
bool
AutoProperties::parseRegexpOrWarning(RegexString &regex, 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.
//! @param extended Extended syntax including role and title in the name, defaults to true.
//! @return true on success, else false.
bool
AutoProperties::parsePropertyMatch(const std::string &str, Property *prop, bool extended)
{
bool status = false;
// Format of property matches are regexp,regexp . Split up in class
// and role regexps.
vector<string> 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->find_entry ("TITLE");
if (value) {
parseRegexpOrWarning(prop->getTitle(), value->get_value(), "title");
}
value = section->find_entry ("ROLE");
if (value) {
parseRegexpOrWarning(prop->getRole(), value->get_value(), "role");
}
// Parse apply on mask.
value = section->find_entry ("APPLYON");
if (value) {
parsePropertyApplyOn(value->get_value(), prop);
}
return true;
}
/**
* Parse property apply on.
*/
void
AutoProperties::parsePropertyApplyOn(const std::string &apply_on, Property *prop)
{
vector<string> tokens;
if ((Util::splitString(apply_on, tokens, " \t", 5))) {
vector<string>::iterator it(tokens.begin());
for (; it != tokens.end(); ++it) {
prop->applyAdd(static_cast<unsigned int>(ParseUtil::getValue<ApplyOn>(*it, _apply_on_map)));
}
}
}
//! @brief Parses AutopProperty
void
AutoProperties::parseAutoProperty(CfgParser::Entry *section, std::list<uint>* ws)
{
// Get sub section
section = section->get_section();
if (! section) {
return;
}
AutoProperty* property = new AutoProperty();
parsePropertyMatch(section->get_value(), property, _extended);
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->get_value().size()) {
property->group_name = Util::to_wide_str(section->get_value());
}
PropertyType property_type;
CfgParser::iterator it(section->begin());
for (; it != section->end(); ++it) {
property_type = ParseUtil::getValue<PropertyType>((*it)->get_name(), _group_property_map);
switch (property_type) {
case AP_GROUP_SIZE:
property->group_size = strtol((*it)->get_value().c_str(), 0, 10);
break;
case AP_GROUP_BEHIND:
property->group_behind = Util::isTrue((*it)->get_value());
break;
case AP_GROUP_FOCUSED_FIRST:
property->group_focused_first = Util::isTrue((*it)->get_value());
break;
case AP_GROUP_GLOBAL:
property->group_global = Util::isTrue((*it)->get_value());
break;
case AP_GROUP_RAISE:
property->group_raise = Util::isTrue((*it)->get_value());
break;
default:
// do nothing
break;
}
}
}
/**
* Parses a title property section.
*/
void
AutoProperties::parseTitleProperty(CfgParser::Entry *section)
{
section = section->get_section();
TitleProperty *title_property;
CfgParser::Entry *title_section;
CfgParser::iterator it(section->begin());
for (; it != section->end(); ++it) {
title_section = (*it)->get_section();
if (! title_section) {
continue;
}
title_property = new TitleProperty();
parsePropertyMatch(title_section->get_value(), title_property, _extended);
if (parseProperty(title_section, title_property)) {
CfgParser::Entry *value = title_section->find_entry("RULE");
if (value && title_property->getTitleRule().parse_ed_s(Util::to_wide_str(value->get_value()))) {
_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->get_section();
DecorProperty *decor_property;
CfgParser::Entry *decor_section;
CfgParser::iterator it(section->begin());
for (; it != section->end(); ++it) {
decor_section = (*it)->get_section ();
if (! decor_section) {
continue;
}
decor_property = new DecorProperty();
parsePropertyMatch(decor_section->get_value (), decor_property, _extended);
if (parseProperty(decor_section, decor_property)) {
CfgParser::Entry *value = decor_section->find_entry("DECOR");
if (value) {
decor_property->applyAdd(APPLY_ON_START);
decor_property->setName(value->get_value());
_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->get_section();
// 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)->get_section();
if (! dock_section) {
continue;
}
dock_property = new DockAppProperty();
parsePropertyMatch(dock_section->get_value(), dock_property, _extended);
if (parseProperty(dock_section, dock_property)) {
CfgParser::Entry *value = dock_section->find_entry("POSITION");
if (value) {
_harbour_sort = true;
int position = strtol(value->get_value().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->get_section();
AtomName atom;
AutoProperty *type_property;
CfgParser::Entry *type_section;
map<AtomName, AutoProperty*>::iterator atom_it;
// Look for all type properties
CfgParser::iterator it(section->begin());
for (; it != section->end(); ++it) {
type_section = (*it)->get_section();
if (! type_section) {
continue;
}
// Create new property and try to parse
type_property = new AutoProperty();
atom = ParseUtil::getValue<AtomName>(type_section->get_value(), _window_type_map);
if (atom == WINDOW_TYPE) {
cerr << " *** WARNING: unknown type " << type_section->get_value() << " 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->get_value() << 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, std::list<uint> *ws)
{
// Copy workspaces, if any
if (ws) {
prop->getWsList().assign(ws->begin(), ws->end());
}
// See if we have a group section
CfgParser::Entry *group_section(section->find_section ("GROUP"));
if (group_section) {
parseAutoGroup(group_section, prop);
}
// start parsing of values
string name, value;
vector<string> tokens;
vector<string>::iterator token_it;
PropertyType property_type;
CfgParser::iterator it(section->begin());
for (; it != section->end(); ++it) {
property_type = ParseUtil::getValue<PropertyType>((*it)->get_name(), _property_map);
switch (property_type) {
case AP_STICKY:
prop->maskAdd(AP_STICKY);
prop->sticky = Util::isTrue((*it)->get_value());
break;
case AP_SHADED:
prop->maskAdd(AP_SHADED);
prop->shaded = Util::isTrue((*it)->get_value());
break;
case AP_MAXIMIZED_VERTICAL:
prop->maskAdd(AP_MAXIMIZED_VERTICAL);
prop->maximized_vertical = Util::isTrue((*it)->get_value());
break;
case AP_MAXIMIZED_HORIZONTAL:
prop->maskAdd(AP_MAXIMIZED_HORIZONTAL);
prop->maximized_horizontal = Util::isTrue((*it)->get_value());
break;
case AP_ICONIFIED:
prop->maskAdd(AP_ICONIFIED);
prop->iconified = Util::isTrue((*it)->get_value());
break;
case AP_BORDER:
prop->maskAdd(AP_BORDER);
prop->border = Util::isTrue((*it)->get_value());
break;
case AP_TITLEBAR:
prop->maskAdd(AP_TITLEBAR);
prop->titlebar = Util::isTrue((*it)->get_value());
break;
case AP_FRAME_GEOMETRY:
prop->maskAdd(AP_FRAME_GEOMETRY);
prop->frame_gm_mask =
XParseGeometry((char*) (*it)->get_value().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)->get_value().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)->get_value());
if (prop->layer != LAYER_NONE) {
prop->maskAdd(AP_LAYER);
}
break;
case AP_WORKSPACE:
prop->maskAdd(AP_WORKSPACE);
prop->workspace = unsigned(strtol((*it)->get_value().c_str(), 0, 10) - 1);
break;
case AP_SKIP:
prop->maskAdd(AP_SKIP);
tokens.clear();
if ((Util::splitString((*it)->get_value(), 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)->get_value());
break;
case AP_PLACE_NEW:
prop->maskAdd(AP_PLACE_NEW);
prop->place_new = Util::isTrue((*it)->get_value());
break;
case AP_FOCUS_NEW:
prop->maskAdd(AP_FOCUS_NEW);
prop->focus_new = Util::isTrue((*it)->get_value());
break;
case AP_FOCUSABLE:
prop->maskAdd(AP_FOCUSABLE);
prop->focusable = Util::isTrue((*it)->get_value());
break;
case AP_CFG_DENY:
prop->maskAdd(AP_CFG_DENY);
tokens.clear();
if ((Util::splitString((*it)->get_value(), 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)->get_value(), prop->allowed_actions);
break;
case AP_DISALLOWED_ACTIONS:
prop->maskAdd(AP_DISALLOWED_ACTIONS);
Config::instance()->parseActionAccessMask((*it)->get_value(), prop->disallowed_actions);
break;
#ifdef OPACITY
case AP_OPACITY:
prop->maskAdd(AP_OPACITY);
Config::parseOpacity((*it)->get_value(), prop->focus_opacity, prop->unfocus_opacity);
break;
#endif // OPACITY
default:
// do nothing
break;
}
}
}
//! @brief Searches the _prop_list for a property
AutoProperty*
AutoProperties::findAutoProperty(const ClassHint* class_hint, int ws, uint type)
{
return static_cast<AutoProperty*>(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<TitleProperty*>(findProperty(class_hint, &_title_prop_list, -1, 0));
}
//! @brief
DecorProperty*
AutoProperties::findDecorProperty(const ClassHint* class_hint)
{
return static_cast<DecorProperty*>(findProperty(class_hint, &_decor_prop_list, -1, 0));
}
DockAppProperty*
AutoProperties::findDockAppProperty(const ClassHint *class_hint)
{
return static_cast<DockAppProperty*>(findProperty(class_hint, &_dock_app_prop_list, -1, 0));
}
//! @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<AtomName, AutoProperty*>::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)
{
list<Property*>::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;
}

278
pekwm/AutoProperties.hh Normal file
View File

@ -0,0 +1,278 @@
//
// AutoProperties.hh for pekwm
// Copyright © 2003-2009 Claes Nästén <me@pekdon.net>
//
// This program is licensed under the GNU GPL.
// See the LICENSE file for more information.
//
#ifndef _AUTOPROPERTIES_HH_
#define _AUTOPROPERTIES_HH_
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include "pekwm.hh"
#include "Atoms.hh"
#include "CfgParser.hh"
#include "RegexString.hh"
#include "ParseUtil.hh"
#include <string>
#include <list>
/**
* 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),
#ifdef OPACITY
AP_OPACITY = (1L << 20),
#endif // OPACITY
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 std::list<uint> getWsList(void) { return _ws_list; }
private:
RegexString _hint_name, _hint_class;
RegexString _role, _title;
uint _apply_mask;
std::list<uint> _ws_list;
};
// 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, layer, skip, cfg_deny;
#ifdef OPACITY
uint focus_opacity, unfocus_opacity;
#endif //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, uint type = 0);
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,
std::list<Property*>* prop_list,
int ws, uint type);
void loadRequire(CfgParser &a_cfg, std::string &file);
bool parsePropertyMatch(const std::string &str, Property *prop, bool extended = true);
void parsePropertyApplyOn(const std::string &apply_on, Property *prop);
bool parseRegexpOrWarning(RegexString &regex, const std::string regex_str, const std::string &name);
bool parseProperty(CfgParser::Entry *section, Property *prop);
void parseAutoProperty(CfgParser::Entry *section, std::list<uint>* 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, std::list<uint> *ws);
void parseDockAppProperty(CfgParser::Entry *section);
void parseTypeProperty(CfgParser::Entry *section);
void setDefaultTypeProperties(void);
private:
std::map <std::string, time_t> _cfg_state; /**< Map of file mtime for all files touched by a configuration. */
bool _extended; /**< Extended syntax enabled for autoproperties? */
std::map<AtomName, AutoProperty*> _window_type_prop_map;
std::list<Property*> _prop_list;
std::list<Property*> _title_prop_list;
std::list<Property*> _decor_prop_list;
std::list<Property*> _dock_app_prop_list;
bool _harbour_sort;
bool _apply_on_start;
std::map<ParseUtil::Entry, ApplyOn> _apply_on_map;
std::map<ParseUtil::Entry, PropertyType> _property_map;
std::map<ParseUtil::Entry, PropertyType> _group_property_map;
std::map<ParseUtil::Entry, AtomName> _window_type_map;
static AutoProperties *_instance;
};
#endif // _AUTOPROPS_HH_

737
pekwm/CfgParser.cc Normal file
View File

@ -0,0 +1,737 @@
//
// Copyright © 2005-2009 Claes Nästén <me@pekdon.net>
//
// This program is licensed under the GNU GPL.
// See the LICENSE file for more information.
//
#include "CfgParser.hh"
#include "Compat.hh"
#include "Util.hh"
#include <algorithm>
#include <iostream>
#include <memory>
#include <cassert>
#include <cstring>
enum {
PARSE_BUF_SIZE = 1024
};
using std::cerr;
using std::endl;
using std::list;
using std::map;
using std::set;
using std::string;
using std::auto_ptr;
const string CfgParser::_root_source_name = string("");
const char *CP_PARSE_BLANKS = " \t\n";
//! @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(_source_name)
{
list<CfgParser::Entry*>::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<CfgParser::Entry*>());
if (_section) {
delete _section;
_section = 0;
}
}
/**
* Append Entry to the end of Entry list at current depth.
*/
CfgParser::Entry*
CfgParser::Entry::add_entry(CfgParser::Entry *entry, bool overwrite)
{
CfgParser::Entry *entry_search = 0;
if (overwrite) {
if (entry->get_section()) {
entry_search = find_entry(entry->get_name(), true, entry->get_section()->get_value().c_str());
} else {
entry_search = find_entry(entry->get_name(), 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->get_section()
|| strcasecmp(entry->get_value().c_str(), entry_search->get_value().c_str()) == 0)) {
entry_search->_value = entry->get_value();
entry_search->set_section(entry->get_section(), 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::add_entry(const std::string &source_name, int line,
const std::string &name, const std::string &value,
CfgParser::Entry *section, bool overwrite)
{
return add_entry(new Entry(source_name, line, name, value, section), overwrite);
}
/**
* Set section, copy section entires over if overwrite.
*/
CfgParser::Entry*
CfgParser::Entry::set_section(CfgParser::Entry *section, bool overwrite)
{
if (_section) {
if (overwrite) {
_section->copy_tree_into(section);
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::find_entry(const std::string &name, bool include_sections, const char *value)
{
CfgParser::Entry *value_check;
list<CfgParser::Entry*>::iterator it(_entries.begin());
for (; it != _entries.end(); ++it) {
value_check = include_sections ? (*it)->get_section() : (*it);
if (*(*it) == name.c_str()
&& (! (*it)->get_section() || include_sections)
&& (! value || (value_check && value_check->get_value() == 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::find_section(const std::string &name, const char *value)
{
list<CfgParser::Entry*>::iterator it(_entries.begin());
for (; it != _entries.end(); ++it) {
if ((*it)->get_section() && *(*it) == name.c_str()
&& (! value || (*it)->get_section()->get_value() == value)) {
return (*it)->get_section();
}
}
return 0;
}
//! @brief Sets and validates data specified by key list.
void
CfgParser::Entry::parse_key_values(std::list<CfgParserKey*>::iterator begin,
std::list<CfgParserKey*>::iterator end)
{
CfgParser::Entry *value;
list<CfgParserKey*>::iterator it;
for (it = begin; it != end; ++it) {
value = find_entry((*it)->get_name());
if (value) {
try {
(*it)->parse_value(value->get_value());
} catch (string &ex) {
cerr << " *** WARNING " << ex << endl << " " << *value << endl;
}
}
}
}
/**
* Copy tree into current entry, overwrite entries if overwrite is
* true.
*/
void
CfgParser::Entry::copy_tree_into(CfgParser::Entry *from, bool overwrite)
{
// Copy section
if (from->get_section()) {
if (_section) {
_section->copy_tree_into(from->get_section(), overwrite);
} else {
_section = new Entry(*(from->get_section()));
}
}
// Copy elements
CfgParser::iterator it(from->begin());
for (; it != from->end(); ++it) {
CfgParser::Entry *entry_section = 0;
if ((*it)->get_section()) {
entry_section = new Entry(*((*it)->get_section()));
}
add_entry((*it)->get_source_name(), (*it)->get_line(), (*it)->get_name(), (*it)->get_value(),
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.get_source_name() << "@" << entry.get_line()
<< " " << entry.get_name() << " = " << entry.get_value();
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
_source_list.clear();
_source_name_list.clear();
_source_name_set.clear();
_section_list.clear();
_var_map.clear();
// Remove sections
map<string, CfgParser::Entry*>::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.
parse_source_new(src, type);
if (_source_list.size() == 0) {
return false;
}
int c, next;
while (_source_list.size()) {
_source = _source_list.back();
if (_source->is_dynamic()) {
_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 = parse_skip_blank(_source);
if (next != '{') {
parse_entry_finish(buf, value);
}
break;
case ';':
parse_entry_finish(buf, value);
break;
case '{':
if (parse_name(buf)) {
parse_section_finish(buf, value);
} else {
cerr << "Ignoring section as name is empty." << endl;
}
buf.clear();
value.clear();
break;
case '}':
if (_section_list.size() > 0) {
if (buf.size() && parse_name(buf)) {
parse_entry_finish(buf, value);
buf.clear();
value.clear();
}
_section = _section_list.back();
_section_list.pop_back();
} else {
cerr << "Extra } character found, ignoring." << endl;
}
break;
case '=':
value.clear();
parse_value(_source, value);
break;
case '#':
parse_comment_line(_source);
break;
case '/':
next = _source->getc();
if (next == '/') {
parse_comment_line(_source);
} else if (next == '*') {
parse_comment_c(_source);
} else {
buf += c;
_source->ungetc(next);
}
break;
default:
buf += c;
break;
}
}
try {
_source->close();
} catch (string &ex) {
cerr << ex << endl;
}
delete _source;
_source_list.pop_back();
_source_name_list.pop_back();
}
if (buf.size()) {
parse_entry_finish(buf, value);
}
return true;
}
//! @brief Creates and opens new CfgParserSource.
void
CfgParser::parse_source_new(const std::string &name_orig, CfgParserSource::Type type)
{
int done = 0;
string name(name_orig);
do {
CfgParserSource *source = source_new(name, type);
assert(source);
// Open and set as active, delete if fails.
try {
source->open();
// Add source to file list if file
if (type == CfgParserSource::SOURCE_FILE) {
_file_list[name] = Util::getMtime(name);
}
_source = source;
_source_list.push_back(_source);
done = 1;
} catch (string &ex) {
delete source;
// Previously added in source_new
_source_name_list.pop_back();
// Display error message on second try
if (done) {
cerr << ex << endl;
}
// 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_name_list.size() && (name[0] != '/')) {
name = Util::getDir(_source_name_list.back());
name += "/" + name_orig;
}
}
}
} while (! done++ && (type == CfgParserSource::SOURCE_FILE));
}
//! @brief Parses from beginning to first blank.
bool
CfgParser::parse_name(std::string &buf)
{
if (! buf.size()) {
cerr << "Unable to parse empty name." << endl;
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 from = to end of " pair.
void
CfgParser::parse_value(CfgParserSource *source, 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 to a " or found EOF first.
if (c == EOF) {
cerr << "Reached EOF before opening \" in value." << endl;
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;
}
if (c == EOF) {
cerr << "Reached EOF before closing \" in value." << endl;
}
// If the value is empty, parse_entry_finish() 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::parse_entry_finish(std::string &buf, std::string &value)
{
if (value.size()) {
parse_entry_finish_standard(buf, value);
} else {
// Template handling, expand or define template.
if (buf.size() && parse_name(buf) && buf[0] == '@') {
parse_entry_finish_template(buf);
}
buf.clear();
}
}
/**
* Finish standard entry.
*/
void
CfgParser::parse_entry_finish_standard(std::string &buf, std::string &value)
{
if (parse_name(buf)) {
if (buf[0] == '$') {
variable_define(buf, value);
} else {
variable_expand(value);
if (buf == "INCLUDE") {
parse_source_new(value, CfgParserSource::SOURCE_FILE);
} else if (buf == "COMMAND") {
parse_source_new(value, CfgParserSource::SOURCE_COMMAND);
} else {
_section->add_entry(_source->get_name(), _source->get_line(), buf, value, 0, _overwrite);
}
}
} else {
cerr << "Dropping entry with empty name." << endl;
}
value.clear();
buf.clear();
}
/**
* Finish template entry, copy data into current section.
*/
void
CfgParser::parse_entry_finish_template(std::string &name)
{
map<string, CfgParser::Entry*>::iterator it(_section_map.find(name.c_str() + 1));
if (it == _section_map.end()) {
cerr << " *** WARNING: No such template " << name << endl;
return;
}
_section->copy_tree_into(it->second);
}
//! @brief Creates new Section on {
void
CfgParser::parse_section_finish(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<string, CfgParser::Entry*>::iterator it(_section_map.find(value));
if (it != _section_map.end()) {
delete it->second;
_section_map.erase(it);
}
section = new Entry(_source->get_name(), _source->get_line(), buf, value);
_section_map[value] = section;
} else {
// Create Entry for sub-section.
section = new Entry(_source->get_name(), _source->get_line(), 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->add_entry(_source->get_name(), _source->get_line(),
buf, value, section, _overwrite);
section = parent->get_section();
}
// Set current Entry to newly created Section.
_section_list.push_back(_section);
_section = section;
}
//! @brief Parses Source until end of line discarding input.
void
CfgParser::parse_comment_line(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::parse_comment_c(CfgParserSource *source)
{
int c;
while ((c = source->getc()) != EOF) {
if (c == '*') {
if ((c = source->getc()) == '/') {
break;
} else if (c != EOF) {
source->ungetc(c);
}
}
}
if (c == EOF) {
cerr << "Reached EOF before closing */ in comment." << endl;
}
}
//! @brief Parses Source until next non whitespace char is found.
char
CfgParser::parse_skip_blank(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::source_new(const std::string &name, CfgParserSource::Type type)
{
CfgParserSource *source = 0;
// Create CfgParserSource.
_source_name_list.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::variable_define(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::variable_expand(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 = variable_expand_name(var, begin, end) || did_expand;
}
} while (did_expand);
}
bool
CfgParser::variable_expand_name(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 {
cerr << "Trying to use undefined environment variable: " << var_name << endl;;
}
} else {
map<string, string>::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 {
cerr << "Trying to use undefined variable: " << var_name << endl;
}
}
return did_expand;
}

154
pekwm/CfgParser.hh Normal file
View File

@ -0,0 +1,154 @@
//
// Copyright © 2005-2009 Claes Nasten <me{@}pekdon{.}net>
//
// 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_
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include "CfgParserKey.hh"
#include "CfgParserSource.hh"
#include <list>
#include <map>
#include <set>
#include <string>
#include <cstring>
#include <iostream>
#include <cstdlib>
//! @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);
std::list<CfgParser::Entry*>::iterator begin(void) { return _entries.begin(); }
std::list<CfgParser::Entry*>::iterator end(void) { return _entries.end(); }
//! @brief Returns the name.
const std::string &get_name(void) const { return _name; }
//! @brief Returns the value.
const std::string &get_value(void) const { return _value; }
//! @brief Returns the linenumber in the source this was parsed.
int get_line(void) const { return _line; }
//! @brief Returns the name of the source this was parsed.
const std::string &get_source_name(void) const { return _source_name; }
Entry *add_entry(Entry *entry, bool overwrite=false);
Entry *add_entry(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 *get_section(void) { return _section; }
Entry *set_section(Entry *section, bool overwrite=false);
Entry *find_entry(const std::string &name, bool include_sections=false, const char *value=0);
Entry *find_section(const std::string &name, const char *value=0);
void parse_key_values(std::list<CfgParserKey*>::iterator begin,
std::list<CfgParserKey*>::iterator end);
void copy_tree_into(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:
std::list<CfgParser::Entry*> _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::list<CfgParser::Entry*>::iterator iterator;
CfgParser(void);
~CfgParser(void);
/** Return map of file / mtime */
const std::map<std::string, time_t> &get_file_list(void) const { return _file_list; }
//! @brief Returns the root Entry node.
Entry *get_entry_root(void) { return _root_entry; }
/** Return true if data parsed included dynamic content such as from COMMAND. */
bool is_dynamic_content(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 parse_source_new(const std::string &name, CfgParserSource::Type type);
bool parse_name(std::string &buf);
void parse_value(CfgParserSource *source, std::string &value);
void parse_entry_finish(std::string &buf, std::string &value);
void parse_entry_finish_standard(std::string &buf, std::string &value);
void parse_entry_finish_template(std::string &name);
void parse_section_finish(std::string &buf, std::string &value);
void parse_comment_line(CfgParserSource *source);
void parse_comment_c(CfgParserSource *source);
char parse_skip_blank(CfgParserSource *source);
CfgParserSource *source_new(const std::string &name, CfgParserSource::Type type);
void variable_define(const std::string &name, const std::string &value);
void variable_expand(std::string &var);
bool variable_expand_name(std::string &var,
std::string::size_type begin, std::string::size_type &end);
private:
CfgParserSource *_source;
std::map<std::string, time_t> _file_list; //!< Map of source, mtime of loaded files. */
std::list<CfgParserSource*> _source_list; //!< List of sources, for recursive parsing.
std::list<std::string> _source_name_list; //!< List of source names, to keep track of current source.
std::set<std::string> _source_name_set; //!< Set of source names, source of memory usage on long-going CfgParser objects.
std::list<Entry*> _section_list; //!< List sections, for recursive parsing.
std::map<std::string, std::string> _var_map; //!< Map of $VARS
std::map<std::string, CfgParser::Entry*> _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_

74
pekwm/CfgParserKey.cc Normal file
View File

@ -0,0 +1,74 @@
//
// Copyright © 2005-2009 Claes Nästén <me@pekdon.net>
//
// This program is licensed under the GNU GPL.
// See the LICENSE file for more information.
//
#include "CfgParserKey.hh"
#include "Util.hh"
#include <iostream>
#include <cstdlib>
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::parse_value(const std::string &value)
throw (std::string&)
{
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::parse_value(const std::string &value)
throw (std::string&)
{
_set = value;
if ((_length_min != numeric_limits<int>::min())
&& (static_cast<int>(_set.size()) < _length_min)) {
_set = _default;
throw string("string too short, min length " + Util::to_string<int>(_length_min));
}
if ((_length_max != numeric_limits<int>::max())
&& (static_cast<int>(_set.size()) > _length_max)) {
_set = _default;
throw string("string too long, max length " + Util::to_string<int>(_length_max));
}
}
//! @brief Parses value and sets _set.
//! @param value Value to parse.
//! @return true on success, else false and _set set to _default.
void
CfgParserKeyPath::parse_value(const std::string &value)
throw (std::string&)
{
if (value.size()) {
_set = value;
Util::expandFileName(_set);
} else {
_set = _default;
throw string("path too short");
}
}

189
pekwm/CfgParserKey.hh Normal file
View File

@ -0,0 +1,189 @@
//
// Copyright © 2005-2009 Claes Nästén <me@pekdon.net>
//
// 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 <string>
#include <limits>
#include <cstdlib>
#include "Util.hh"
//! @brief CfgParserKey value type.
enum CfgParserKeyType {
KEY_SECTION, //!< Subsection.
KEY_BOOL, //!< Boolean value.
KEY_NUMERIC, //!< Integer value.
KEY_STRING, //!< String value.
KEY_PATH //!< Path value.
};
//! @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 *get_name(void) const { return _name; }
//! @brief Returns Key type.
const CfgParserKeyType get_type(void) const { return _type; }
//! @brief Parses value and sets Key value.
virtual void parse_value(const std::string &value) throw (std::string&) { }
protected:
CfgParserKeyType _type; //!< Key type.
const char *_name; //!< Key name.
};
/**
* CfgParserKey numeric type with minimum, maximum and default
* value. The type must be available in numeric_limits.
*/
template<typename T>
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<T>::min().
* @param value_min Maximum value for key, defaults to limits<T>::max().
*/
CfgParserKeyNumeric(const char *name, T &set, const T default_val = 0,
const T value_min = std::numeric_limits<T>::min(),
const T value_max = std::numeric_limits<T>::max())
: CfgParserKey(name),
_set(set), _default(default_val),
_value_min(value_min), _value_max(value_max)
{
_type = KEY_NUMERIC;
}
/**
* CfgParserKeyNumeric destructor.
*/
virtual ~CfgParserKeyNumeric(void) { }
/**
* Parses and store integer value.
*
* @param value Reference to string representing integer value.
*/
virtual void
parse_value(const std::string &value_str)
throw (std::string&)
{
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<T>(value);
if (value_for_type < _value_min) {
_set = _value_min;
throw std::string("value to low, min value " + Util::to_string<T>(_value_min));
} if (value_for_type > _value_max) {
_set = _value_max;
throw std::string("value to high, max value " + Util::to_string<T>(_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)
{
_type = KEY_BOOL;
}
//! @brief CfgParserKeyBool destructor.
virtual ~CfgParserKeyBool(void) { }
virtual void parse_value(const std::string &value) throw (std::string&);
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 int length_min = std::numeric_limits<int>::min(),
const int length_max = std::numeric_limits<int>::max())
: CfgParserKey(name),
_set(set), _default(default_val),
_length_min(length_min), _length_max(length_max)
{
_type = KEY_STRING;
}
//! @brief CfgParserKeyString destructor.
virtual ~CfgParserKeyString(void) { }
virtual void parse_value(const std::string &value) throw (std::string&);
private:
std::string &_set; //!< Reference to store parsed value in.
const std::string _default; //!< Default value.
const int _length_min; //!< Minimum lenght of string.
const int _length_max; //!< Maximum 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)
{
_type = KEY_PATH;
Util::expandFileName(_default);
}
//! @brief CfgParserKeyPath destructor.
virtual ~CfgParserKeyPath(void) { }
virtual void parse_value(const std::string &value) throw (std::string&);
private:
std::string &_set; //!< Reference to store parsed value in.
std::string _default; //!< Default value.
};
#endif // _CFG_PARSER_KEY_HH_

148
pekwm/CfgParserSource.cc Normal file
View File

@ -0,0 +1,148 @@
//
// Copyright © 2005-2009 Claes Nästén <me@pekdon.net>
//
// This program is licensed under the GNU GPL.
// See the LICENSE file for more information.
//
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include "CfgParserSource.hh"
#include "Util.hh"
#include <iostream>
#include <cstdio>
#include <cstdlib>
extern "C" {
#include <stdio.h>
#include <unistd.h>
}
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)
throw (std::string&)
{
if (_file) {
throw string("TRYING TO OPEN ALLREADY OPEN SOURCE");
}
_file = fopen(_name.c_str(), "r");
if (! _file) {
throw string("failed to open file " + _name);
}
return true;
}
void
CfgParserSourceFile::close(void)
throw (std::string&)
{
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)
throw (std::string&)
{
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)
throw (std::string&)
{
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<int>(_pid));
}
}

125
pekwm/CfgParserSource.hh Normal file
View File

@ -0,0 +1,125 @@
//
// Copyright © 2005-2009 Claes Nästén <me@pekdon.net>
//
// 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 <string>
#include <cstdio>
extern "C" {
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
}
/**
* Base class for configuration sources defining the interface and
* common methods.
*/
class CfgParserSource
{
public:
//! @brief 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 &get_name(void) const { return _name; }
/**< return type of source. */
CfgParserSource::Type get_type(void) const { return _type; }
/**< Get current line from source. */
unsigned int get_line(void) const { return _line; }
/**< Return true if current source is dynamic. */
bool is_dynamic(void) const { return _is_dynamic; }
virtual bool open(void) throw (std::string&) { return false; }
virtual void close(void) throw (std::string&) { }
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) throw (std::string&);
virtual void close(void) throw (std::string&);
};
/**
* 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) throw (std::string&);
virtual void close(void) throw (std::string&);
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_

1958
pekwm/Client.cc Normal file

File diff suppressed because it is too large Load Diff

413
pekwm/Client.hh Normal file
View File

@ -0,0 +1,413 @@
//
// Client.hh for pekwm
// Copyright © 2003-2009 Claes Nästén <me{@}pekdon{.}net>
//
// client.hh for aewm++
// Copyright (C) 2002 Frank Hale <frankhale@yahoo.com>
// 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_
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include "pekwm.hh"
#include "Observer.hh"
#include "PTexturePlain.hh"
#include "PDecor.hh"
class PScreen;
class Strut;
class PWinObj;
class ClassHint;
class AutoProperty;
class Frame;
#include <string>
extern "C" {
#include <X11/Xutil.h>
}
class LayerObservation : public Observation {
public:
LayerObservation(enum Layer _layer) : layer(_layer) { };
virtual ~LayerObservation(void) { };
public:
const enum Layer layer; /**< Layer client changed to. */
};
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, 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.
// 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(std::list<Client*> &client_list, Window win);
static void mapOrUnmapTransients(Window win, bool hide);
// START - Iterators
static uint client_size(void) { return _client_list.size(); }
static std::list<Client*>::iterator client_begin(void) {
return _client_list.begin();
}
static std::list<Client*>::iterator client_end(void) {
return _client_list.end();
}
static std::list<Client*>::reverse_iterator client_rbegin(void) {
return _client_list.rbegin();
}
static std::list<Client*>::reverse_iterator client_rend(void) {
return _client_list.rend();
}
unsigned int transient_size(void) { return _transient_clients.size(); }
std::list<Client*>::iterator transient_begin(void) {
return _transient_clients.begin(); }
std::list<Client*>::iterator transient_end(void) {
return _transient_clients.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; }
/**< Return title item for client icon name. */
inline PDecor::TitleItem *getIconName(void) { return &_icon_name; }
inline const ClassHint* getClassHint(void) const { return _class_hint; }
bool isTransient(void) const { return _transient_window != None; }
Client *getTransientClient(void) const { return _transient; }
Window getTransientClientWindow(void) const { return _transient_window; }
void findAndRaiseIfTransient(void);
inline XSizeHints* getXSizeHints(void) const { return _size; }
bool isViewable(void);
bool setPUPosition(void);
inline bool hasTitlebar(void) const { return (_state.decor&DECOR_TITLEBAR); }
inline bool hasBorder(void) const { return (_state.decor&DECOR_BORDER); }
inline bool isShaped(void) const { return _shaped; }
inline bool hasStrut(void) const { return (_strut); }
Strut *getStrut(void) const { return _strut; }
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 allowMinimize(void) const { return _actions.minimize; }
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 allowChangeDesktop(void) const { return _actions.change_desktop; }
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;
}
void setStateDemandsAttention(StateAction sa, bool attention);
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;
}
}
/** Set shaped flag on Client. */
inline void setShaped(bool shaped) {
_shaped = shaped;
}
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);
void getWMNormalHints(void);
void getWMProtocols(void);
void getTransientForHint(void);
void getStrutHint(void);
void readName(void);
void readIconName(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(uint type = 0);
private:
bool getAndUpdateWindowAttributes(void);
void findOrCreateFrame(AutoProperty *autoproperty);
bool findTaggedFrame(void);
bool findPreviousFrame(void);
bool findAutoGroupFrame(AutoProperty *autoproperty);
void setInitialState(void);
void setMappedStateAndFocus(bool is_new, AutoProperty *autoproperty);
bool titleApplyRule(std::wstring &wtitle);
uint titleFindID(std::wstring &wtitle);
void setWmState(ulong state);
long getWmState(void);
int sendXMessage(Window window, Atom atom, long mask,
long v1 = 0l, long v2 = 0l, long v3 = 0l,
long v4 = 0l, long v5 = 0l);
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, Cursor curs);
void readHints(void);
ulong readWmHints(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; //<! Unique ID of the Client.
XSizeHints *_size;
Colormap _cmap;
Client *_transient; /**< Client for which this client is transient for */
Window _transient_window;
std::list<Client*> _transient_clients; /**< List of transient clients. */
Strut *_strut;
PDecor::TitleItem _title; /**< Name of the client. */
PDecor::TitleItem _icon_name; /**< Name of the client when iconified. */
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;
bool _alive, _marked;
bool _send_focus_message, _send_close_message, _wm_hints_input;
bool _cfg_request_lock;
bool _shaped;
bool _extended_net_name;
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), demands_attention(true) { }
~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;
bool demands_attention; /**< If true, the client requires attention from the user. */
} _state;
class Actions {
public:
Actions(void) : move(true), resize(true), minimize(true),
shade(true), stick(true), maximize_horz(true),
maximize_vert(true), fullscreen(true),
change_desktop(true), close(true) { }
~Actions(void) { }
bool move;
bool resize;
bool minimize; // iconify
bool shade;
bool stick;
bool maximize_horz;
bool maximize_vert;
bool fullscreen;
bool change_desktop; // workspace
bool close;
} _actions;
static std::list<Client*> _client_list; //!< List of all Clients.
static std::vector<uint> _clientid_list; //!< List of free Client IDs.
};
#endif // _CLIENT_HH_

145
pekwm/CmdDialog.cc Normal file
View File

@ -0,0 +1,145 @@
//
// CmdDialog.cc for pekwm
// Copyright © 2004-2009 Claes Nästén <me@pekdon.net>
//
// This program is licensed under the GNU GPL.
// See the LICENSE file for more information.
//
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include <iostream>
#include <list>
#include <cwctype>
extern "C" {
#include <X11/Xlib.h>
#include <X11/Xutil.h> // XLookupString
#include <X11/keysym.h>
}
#include "PWinObj.hh"
#include "PDecor.hh"
#include "CmdDialog.hh"
#include "Config.hh"
#include "PScreen.hh"
#include "PixmapHandler.hh"
#include "KeyGrabber.hh"
#include "ScreenResources.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"),
_completer(L";"), _exec_count(0)
{
_type = PWinObj::WO_CMD_DIALOG;
// Setup completer
_completer.add_method(new ActionCompleterMethod());
_completer.add_method(new PathCompleterMethod());
if (Config::instance()->getCmdDialogHistoryFile().size() > 0) {
_hist_list.load(Config::instance()->getCmdDialogHistoryFile());
}
}
/**
* CmdDialog de-structor, clean up and save history file.
*/
CmdDialog::~CmdDialog(void)
{
if (Config::instance()->getCmdDialogHistoryFile().size() > 0) {
_hist_list.save(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()) {
_hist_list.push_back_unique(_buf);
} else {
_hist_list.push_back(_buf);
}
if (_hist_list.size() > static_cast<uint>(Config::instance()->getCmdDialogHistorySize())) {
_hist_list.pop_front();
}
// Persist changes
if (Config::instance()->getCmdDialogHistorySaveInterval() > 0
&& Config::instance()->getCmdDialogHistoryFile().size() > 0
&& ++_exec_count > Config::instance()->getCmdDialogHistorySaveInterval()) {
_hist_list.save(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, bool focus, PWinObj *wo_ref)
{
if (wo_ref != 0) {
setWORef(wo_ref);
}
InputDialog::mapCentered(buf, focus, wo_ref);
}

49
pekwm/CmdDialog.hh Normal file
View File

@ -0,0 +1,49 @@
//
// CmdDialog.hh for pekwm
// Copyright © 2004-2009 Claes Nästén <me{@}pekdon{.}net>
//
// This program is licensed under the GNU GPL.
// See the LICENSE file for more information.
//
#ifndef _CMD_DIALOG_HH_
#define _CMD_DIALOG_HH_
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include "Action.hh"
#include "Completer.hh"
#include "InputDialog.hh"
#include "Theme.hh"
#include <list>
#include <string>
//! @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, bool focus, 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_

141
pekwm/ColorHandler.cc Normal file
View File

@ -0,0 +1,141 @@
//
// Copyright © 2004-2009 Claes Nästén <me{@}pekdon{.}net>
//
// This program is licensed under the GNU GPL.
// See the LICENSE file for more information.
//
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include "ColorHandler.hh"
#include "PScreen.hh"
#include <cstring>
#ifdef DEBUG
#include <iostream>
using std::cerr;
using std::endl;
#endif // DEBUG
using std::list;
using std::string;
ColorHandler* ColorHandler::_instance = 0;
//! @brief ColorHandler constructor
ColorHandler::ColorHandler(Display *dpy)
: _dpy(dpy),
_free_on_return(false)
{
#ifdef DEBUG
if (_instance) {
cerr << __FILE__ << "@" << __LINE__ << ": " << endl
<< "ColorHandler(" << this << ")::ColorHandler(" << _dpy << ")"
<< endl << " *** _instance already set" << endl;
}
#endif // DEBUG
_instance = this;
// setup default color
_xc_default.pixel = PScreen::instance()->getBlackPixel();
_xc_default.red = _xc_default.green = _xc_default.blue = 0;
}
//! @brief ColorHandler destructor
ColorHandler::~ColorHandler(void)
{
freeColors(true);
_instance = 0;
}
//! @brief Gets or allocs a color
XColor*
ColorHandler::getColor(const std::string &color)
{
// check for already existing entry
list<ColorHandler::Entry*>::iterator it(_color_list.begin());
if (strcasecmp(color.c_str(), "EMPTY") == 0) {
return &_xc_default;
}
for (; it != _color_list.end(); ++it) {
if (*(*it) == color) {
(*it)->incRef();
return (*it)->getColor();
}
}
// create new entry
ColorHandler::Entry *entry = new ColorHandler::Entry(color);
entry->incRef();
// X alloc
XColor dummy;
if (XAllocNamedColor(_dpy, PScreen::instance()->getColormap(),
color.c_str(), entry->getColor(), &dummy) == 0) {
#ifdef DEBUG
cerr << __FILE__ << "@" << __LINE__ << ": "
<< "ColorHandler(" << this << ")::getColor(" << color << ")" << endl
<< " *** failed to alloc color: " << color << endl;
#endif // DEBUG
delete entry;
entry = 0;
} else {
_color_list.push_back(entry);
}
return (entry) ? entry->getColor() : &_xc_default;
}
//! @brief Returns a color
void
ColorHandler::returnColor(XColor *xc)
{
if (&_xc_default == xc) { // no need to return default color
return;
}
list<ColorHandler::Entry*>::iterator it(_color_list.begin());
for (; it != _color_list.end(); ++it) {
if ((*it)->getColor() == xc) {
(*it)->decRef();
if (_free_on_return && ((*it)->getRef() == 0)) {
ulong pixels[1] = { (*it)->getColor()->pixel };
XFreeColors(_dpy, PScreen::instance()->getColormap(), pixels, 1, 0);
delete *it;
_color_list.erase(it);
}
break;
}
}
}
//! @brief Frees color allocated by ColorHandler
//! @param all If false free on only unref colors
void
ColorHandler::freeColors(bool all)
{
list<ulong> pixel_list;
list<ColorHandler::Entry*>::iterator it(_color_list.begin());
for (; it != _color_list.end(); ++it) {
if (all || ((*it)->getRef() == 0)) {
pixel_list.push_back((*it)->getColor()->pixel);
delete *it;
}
}
if (pixel_list.size() > 0) {
ulong *pixels = new ulong[pixel_list.size()];
copy(pixel_list.begin(), pixel_list.end(), pixels);
XFreeColors(_dpy, PScreen::instance()->getColormap(),
pixels, pixel_list.size(), 0);
delete [] pixels;
}
}

74
pekwm/ColorHandler.hh Normal file
View File

@ -0,0 +1,74 @@
//
// ColorHandler.hh for pekwm
// Copyright © 2004-2009 Claes Nästén <me@pekdon.net>
//
// This program is licensed under the GNU GPL.
// See the LICENSE file for more information.
//
#ifndef _COLOR_HANDLER_HH_
#define _COLOR_HANDLER_HH_
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include "pekwm.hh"
#include <list>
#include <string>
#include <cstring>
extern "C" {
#include <string.h>
}
class ColorHandler {
public:
class Entry {
public:
Entry(const std::string &name) : _name(name), _ref(0) { }
~Entry(void) { }
inline XColor *getColor(void) { return &_xc; }
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;
XColor _xc;
uint _ref;
};
ColorHandler(Display *dpy);
~ColorHandler(void);
static ColorHandler *instance(void) { return _instance; }
inline bool isFreeOnReturn(void) const { return _free_on_return; }
inline void setFreeOnReturn(bool free) { _free_on_return = free; }
XColor *getColor(const std::string &color);
void returnColor(XColor *xc);
void freeColors(bool all);
private:
Display *_dpy;
XColor _xc_default; // when allocating fails
std::list<ColorHandler::Entry*> _color_list;
bool _free_on_return; // used when returning many colours
static ColorHandler *_instance;
};
#endif // _COLOR_HANDLER_HH_

120
pekwm/Compat.cc Normal file
View File

@ -0,0 +1,120 @@
//
// Compat.cc for pekwm
// Copyright © 2009 Claes Nästén <me@pekdon.net>
//
// This program is licensed under the GNU GPL.
// See the LICENSE file for more information.
//
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include "Compat.hh"
#include "Util.hh"
#include <string>
#include <cstring>
extern "C" {
#include <stdarg.h>
#include <wchar.h>
}
#ifndef HAVE_UNSETENV
#include <errno.h>
#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

53
pekwm/Compat.hh Normal file
View File

@ -0,0 +1,53 @@
//
// Compat.hh for pekwm
// Copyright © 2009 Claes Nästén <me@pekdon.net>
//
// This program is licensed under the GNU GPL.
// See the LICENSE file for more information.
//
#ifndef _COMPAT_HH_
#define _COMPAT_HH_
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include <cwchar>
#include <cstddef>
#ifndef HAVE_SWPRINTF
namespace std {
int swprintf(wchar_t *wcs, size_t maxlen, const wchar_t *format, ...);
}
#endif // HAVE_SWPRINTF
#ifdef HAVE_SETENV
extern "C" {
#include <stdlib.h>
}
#else // ! HAVE_SETENV
int setenv(const char *name, const char *value, int overwrite);
#endif // HAVE_SETENV
#ifdef HAVE_UNSETENV
extern "C" {
#include <stdlib.h>
}
#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_

344
pekwm/Completer.cc Normal file
View File

@ -0,0 +1,344 @@
//
// Completer.cc for pekwm
// Copyright © 2009 Claes Nästén <me@pekdon.net>
//
// This program is licensed under the GNU GPL.
// See the LICENSE file for more information.
//
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include <cstdlib>
#include <algorithm>
#include <iostream>
#include <list>
#include <vector>
#include <string>
extern "C" {
#include <sys/types.h>
#include <dirent.h>
#include <stdlib.h>
}
#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::list;
using std::vector;
using std::string;
using std::wstring;
using std::pair;
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")
};
/**
* Find matches for word in completions_list and add to completions.
*/
unsigned int
CompleterMethod::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;
}
/**
* Complete str with available path elements.
*/
unsigned int
PathCompleterMethod::complete(CompletionState &completion_state)
{
return complete_word(_path_list,
completion_state.completions,
completion_state.word);
}
/**
* Refresh available completions.
*/
void
PathCompleterMethod::refresh(void)
{
// Clear out previous data
_path_list.clear();
vector<string> path_parts;
Util::splitString(getenv("PATH") ? getenv("PATH") : "", path_parts, ":");
vector<string>::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);
}
}
_path_list.unique();
_path_list.sort();
}
/**
* Refresh single directory.
*/
void
PathCompleterMethod::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<wstring, wstring>(name, name));
_path_list.push_back(pair<wstring, wstring>(path + L"/" + name,
path + L"/" + name));
}
}
/**
* Check if str matches state prefix.
*/
bool
ActionCompleterMethod::StateMatch::is_state(const wstring &str, size_t pos)
{
if (str.size() - pos < _prefix_len) {
return false;
} else {
return str.compare(pos, _prefix_len, _prefix, _prefix_len) == 0;
}
}
/**
* Complete action.
*/
unsigned int
ActionCompleterMethod::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.
*/
void
ActionCompleterMethod::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::instance()->getMenuNames(),
_menu_list);
}
/**
* Build completions_list from a list with strings.
*/
void
ActionCompleterMethod::completions_list_from_name_list(std::list<std::string> name_list,
completions_list &completions_list)
{
completions_list.clear();
list<string>::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<wstring, wstring>(name_lower, name));
}
completions_list.unique();
completions_list.sort();
}
/**
* Detect state being completed
*/
ActionCompleterMethod::State
ActionCompleterMethod::find_state(CompletionState &completion_state)
{
State state = STATE_ACTION;
if (completion_state.word_begin != 0) {
state = find_state_match(completion_state.part_lower,
completion_state.part_begin);
}
return state;
}
/**
* Find matching state.
*/
ActionCompleterMethod::State
ActionCompleterMethod::find_state_match(const std::wstring &str, size_t pos)
{
for (int i = 0; i < STATE_NUM; ++i) {
if (STATE_MATCHES[i].is_state(str, pos)) {
return STATE_MATCHES[i].get_state();
}
}
return STATE_NO;
}
/**
* Completer destructor, free up resources used by methods.
*/
Completer::~Completer(void)
{
list<CompleterMethod*>::iterator it(_methods.begin());
for (; it != _methods.end(); ++it) {
delete *it;
}
}
/**
* 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);
// Go through completer methods and add completions.
list<CompleterMethod*>::iterator it(_methods.begin());
for (; it != _methods.end(); ++it) {
if ((*it)->can_complete(state.part)) {
(*it)->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)
{
// If no separators are defined, do nothing.
if (! _separators.size()) {
return str;
}
// Get beginning and end of string, add 1 for removal of separator
part_begin = String::safe_position(str.find_last_of(_separators, pos), 0, 1);
part_end = String::safe_position(str.find_first_of(_separators, 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);
}

194
pekwm/Completer.hh Normal file
View File

@ -0,0 +1,194 @@
//
// Completer.cc for pekwm
// Copyright © 2009 Claes Nästén <me@pekdon.net>
//
// This program is licensed under the GNU GPL.
// See the LICENSE file for more information.
//
#ifndef _COMPLETER_HH_
#define _COMPLETER_HH_
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include <list>
#include <string>
extern "C" {
#include <sys/types.h>
#include <dirent.h>
}
typedef std::list<std::wstring> complete_list;
typedef complete_list::iterator complete_it;
typedef std::list<std::pair<std::wstring, std::wstring> > 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;
};
/**
* 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) { }
/** Return true if method can complete. */
virtual bool can_complete(const std::wstring &str) { return false; }
/** Find completions for string. */
virtual unsigned int complete(CompletionState &completion_state) { return 0; }
/** Refresh completion list. */
virtual void refresh(void) { }
protected:
unsigned int complete_word(completions_list &completions_list,
complete_list &completions,
const std::wstring &word);
};
/**
* Null completer, provides no completion independent of input.
*/
class NullCompleterMethod : public CompleterMethod
{
public:
/** Null completer can always complete. */
virtual bool can_complete(const std::wstring &str) { return true; }
/** Find completions, does nothing. */
virtual unsigned int complete(CompletionState &completion_state) { return 0; }
};
/**
* 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) { }
/** Path completer can always complete. */
virtual bool can_complete(const std::wstring &str) { return true; }
virtual unsigned int complete(CompletionState &completion_state);
virtual void refresh(void);
private:
void refresh_path(DIR *dh, const std::wstring path);
private:
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; }
bool is_state(const std::wstring &str, size_t pos);
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) { }
/** Path completer can always complete. */
virtual bool can_complete(const std::wstring &str) { return true; }
virtual unsigned int complete(CompletionState &completion_state);
virtual void refresh(void);
private:
void completions_list_from_name_list(std::list<std::string> name_list,
completions_list &completions_list);
State find_state(CompletionState &completion_state);
size_t find_state_word_start(const std::wstring &str);
State find_state_match(const std::wstring &str, size_t pos);
private:
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. */
};
/**
* 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(const std::wstring separators = L"") : _separators(separators) { }
/** Completer destructor. */
~Completer(void);
/** Add method to completer. */
void add_method(CompleterMethod *method) { _methods.push_back(method); }
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);
private:
std::list<CompleterMethod*> _methods; /**< List of CompleterMethods. */
const std::wstring _separators; /**< String with separator characters. */
};
#endif // _COMPLETER_HH_

1882
pekwm/Config.cc Normal file

File diff suppressed because it is too large Load Diff

373
pekwm/Config.hh Normal file
View File

@ -0,0 +1,373 @@
//
// Config.hh for pekwm
// Copyright © 2002-2009 Claes Nasten <me@pekdon.net>
//
// This program is licensed under the GNU GPL.
// See the LICENSE file for more information.
//
#ifndef _CONFIG_HH_
#define _CONFIG_HH_
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include "pekwm.hh"
#include "Action.hh"
#include "CfgParser.hh"
#include "ParseUtil.hh"
#include <list>
#include <string>
#include <vector>
#include <map>
#include <utility>
/**
* 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.
#ifdef OPACITY
#define CONV_OPACITY(X)\
X = (X == 100)?EWMH_OPAQUE_WINDOW:X*(EWMH_OPAQUE_WINDOW/100)
#else
#define CONV_OPACITY(X)
#endif
/**
* 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 list with available keyboard actions names. */
std::list<std::string> getActionNameList(void) {
std::list<std::string> action_names;
std::map<ParseUtil::Entry, std::pair<ActionType, uint> >::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 list with available state action names. */
std::list<std::string> getStateNameList(void) {
std::list<std::string> state_names;
std::map<ParseUtil::Entry, ActionStateType>::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 getScreenPixmapCacheSize(void) const { return _screen_pixmap_cache_size; }
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 const std::wstring &getTrimTitle(void) const { return _screen_trim_title; }
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; }
#ifdef OPACITY
uint getWorkspaceIndicatorOpacity(void) const { return _screen_workspace_indicator_opacity; }
#endif // 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 bool isHonourRandr(void) const { return _screen_honour_randr; }
inline bool isHonourAspectRatio(void) const { return _screen_honour_aspectratio; }
inline std::list<uint>::iterator getPlacementModelBegin(void) { return _screen_placementmodels.begin(); }
inline std::list<uint>::iterator getPlacementModelEnd(void) { return _screen_placementmodels.end(); }
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; }
#ifdef OPACITY
inline uint getMenuFocusOpacity(void) const { return _menu_focus_opacity; }
inline uint getMenuUnfocusOpacity(void) const { return _menu_unfocus_opacity; }
#endif // 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; }
#ifdef OPACITY
inline uint getHarbourOpacity(void) const { return _harbour_opacity; }
#endif // OPACITY
inline std::list<ActionEvent> *getMouseActionList(MouseActionListName name)
{ return _mouse_action_map[name]; }
std::list<ActionEvent> *getBorderListFromPosition(uint pos);
std::list<ActionEvent> *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, _layer_map); }
inline Skip getSkip(const std::string &skip) { return ParseUtil::getValue<Skip>(skip, _skip_map); }
inline CfgDeny getCfgDeny(const std::string &deny) { return ParseUtil::getValue<CfgDeny>(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<std::string, SizeLimits>::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<uint>(mod, _mod_map); }
uint getMouseButton(const std::string& button);
#ifdef OPACITY
static bool parseOpacity(const std::string value, uint &focused, uint &unfocused);
#endif // OPACITY
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, std::list<ActionEvent>* mouse_list, ActionOk action_ok);
int parseWorkspaceNumber(const std::string &workspace);
private:
std::string _config_file; /**< Path to config file last loaded. */
std::map <std::string, time_t> _cfg_state; /**< Map of file mtime for all files touched by a configuration. */
std::map <std::string, time_t> _mouse_state; /**< Map of file mtime for all files touched by a configuration. */
// 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, _screen_pixmap_cache_size;
int _screen_workspaces_per_row;
std::vector<std::wstring> _screen_workspace_names;
std::wstring _screen_workspace_name_default;
std::vector<int> _screen_edge_sizes;
bool _screen_edge_indent;
int _screen_doubleclicktime;
std::wstring _screen_trim_title;
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
#ifdef OPACITY
uint _screen_workspace_indicator_opacity;
#endif // OPACITY
bool _screen_place_new, _screen_focus_new, _screen_focus_new_child;
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;
std::list<uint> _screen_placementmodels;
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. */
#ifdef OPACITY
uint _menu_focus_opacity, _menu_unfocus_opacity;
#endif // OPACITY
std::map<std::string, SizeLimits> _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;
#ifdef OPACITY
uint _harbour_opacity;
#endif // OPACITY
std::map<MouseActionListName, std::list<ActionEvent>* > _mouse_action_map;
std::map<ParseUtil::Entry, std::pair<ActionType, uint> > _action_map;
std::map<ParseUtil::Entry, ActionAccessMask> _action_access_mask_map;
std::map<ParseUtil::Entry, PlacementModel> _placement_map;
std::map<ParseUtil::Entry, OrientationType> _edge_map;
std::map<ParseUtil::Entry, Raise> _raise_map;
std::map<ParseUtil::Entry, Skip> _skip_map;
std::map<ParseUtil::Entry, Layer> _layer_map;
std::map<ParseUtil::Entry, MoveResizeActionType> _moveresize_map;
std::map<ParseUtil::Entry, InputDialogAction> _inputdialog_map;
std::map<ParseUtil::Entry, DirectionType> _direction_map;
std::map<ParseUtil::Entry, WorkspaceChangeType> _workspace_change_map;
std::map<ParseUtil::Entry, BorderPosition> _borderpos_map;
std::map<ParseUtil::Entry, MouseEventType> _mouse_event_map;
std::map<ParseUtil::Entry, uint> _mod_map;
std::map<ParseUtil::Entry, ActionStateType> _action_state_map;
std::map<ParseUtil::Entry, CfgDeny> _cfg_deny_map;
std::map<ParseUtil::Entry, ActionType> _menu_action_map;
std::map<ParseUtil::Entry, HarbourPlacement> _harbour_placement_map;
std::map<ParseUtil::Entry, Orientation> _harbour_orientation_map;
static Config *_instance; /**< Singleton Config pointer. */
};
#endif // _CONFIG_HH_

79
pekwm/DecorMenu.cc Normal file
View File

@ -0,0 +1,79 @@
//
// FrameListMenu.cc for pekwm
// Copyright (C) 2002-2009 Claes Nasten <pekdon{@}pekdon{.}net>
//
// 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 "DecorMenu.hh"
#include "Workspaces.hh"
#include "ActionHandler.hh"
#include "Theme.hh"
#include <map>
#ifdef DEBUG
#include <iostream>
using std::cerr;
using std::endl;
#endif // DEBUG
using std::string;
using std::map;
//! @brief Constructor for DecorMenu.
DecorMenu::DecorMenu(PScreen *scr, Theme *theme, ActionHandler *act,
const std::string &name) :
WORefMenu(scr, theme, L"Decor Menu", name),
_act(act)
{
_menu_type = DECORMENU_TYPE;
}
//! @brief Destructor for DecorMenu
DecorMenu::~DecorMenu(void)
{
}
//! @brief Handles button1 release
void
DecorMenu::handleItemExec(PMenu::Item *item)
{
if (! item) {
return;
}
ActionPerformed ap(getWORef(), item->getAE());
_act->handleAction(ap);
}
//! @brief Rebuilds the menu.
void
DecorMenu::reload(CfgParser::Entry *section)
{
// clear the menu before loading
removeAll();
// setup dummy action
Action action;
ActionEvent ae;
action.setAction(ACTION_SET);
action.setParamI(0, ACTION_STATE_DECOR);
ae.action_list.push_back(action);
map<string, Theme::PDecorData*>::const_iterator it(_theme->decor_begin());
for (; it != _theme->decor_end(); ++it) {
ae.action_list.back().setParamS(it->first);
insert(Util::to_wide_str(it->first), ae, 0);
}
buildMenu(); // rebuild the menu
}

40
pekwm/DecorMenu.hh Normal file
View File

@ -0,0 +1,40 @@
//
// DecorMenu.hh for pekwm
// Copyright © 2003-2009 Claes Nästén <me{@}pekdon{.}net>
//
// This program is licensed under the GNU GPL.
// See the LICENSE file for more information.
//
#ifndef _DECORMENU_HH_
#define _DECORMENU_HH_
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include "pekwm.hh"
#include "PMenu.hh"
#include <string>
class WORefMenu;
class PScreen;
class Theme;
class ActionHandler;
class DecorMenu : public WORefMenu
{
public:
DecorMenu(PScreen *scr, Theme *theme, ActionHandler *act,
const std::string &name);
virtual ~DecorMenu(void);
virtual void handleItemExec(PMenu::Item *item);
virtual void reload(CfgParser::Entry *section);
private:
ActionHandler *_act;
};
#endif // _DECORMENU_HH_

297
pekwm/DockApp.cc Normal file
View File

@ -0,0 +1,297 @@
//
// Dockapp.cc for pekwm
// Copyright (C) 2003-2009 Claes Nasten <pekdon{@}pekdon{.}net>
//
// 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 "PScreen.hh"
#include "PTexture.hh"
#include "PDecor.hh"
#include "ScreenResources.hh"
#include "Theme.hh"
#include "PixmapHandler.hh"
#include "AutoProperties.hh"
extern "C" {
#include <X11/Xutil.h>
}
#ifdef DEBUG
#include <iostream>
using std::cerr;
using std::endl;
#endif // DEBUG
const uint DOCKAPP_DEFAULT_SIDE = 64;
const uint DOCKAPP_BORDER_WIDTH = 2;
//! @brief DockApp constructor
DockApp::DockApp(PScreen *s, Theme *t, Window win) :
PWinObj(),
_scr(s), _theme(t),
_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(_dpy, _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.
XUnmapWindow(_dpy, _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(_dpy, _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(_dpy, _scr->getRoot(),
_gm.x, _gm.y, _gm.width, _gm.height, 0,
CopyFromParent, InputOutput, CopyFromParent,
CWOverrideRedirect|CWEventMask, &sattr);
// initial makeup
repaint();
XSetWindowBorderWidth(_dpy, _dockapp_window, 0);
// move the dockapp to it's new parent, making sure we don't
// get any UnmapEvents
XSelectInput(_dpy, _dockapp_window, NoEventMask);
XReparentWindow(_dpy, _dockapp_window, _window, _c_gm.x, _c_gm.y);
XSelectInput(_dpy, _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) {
_scr->grabServer();
if (_icon_window != None) {
XUnmapWindow(_dpy, _icon_window);
}
// move the dockapp back to the root window, making sure we don't
// get any UnmapEvents
XSelectInput(_dpy, _dockapp_window, NoEventMask);
XReparentWindow(_dpy, _dockapp_window, _scr->getRoot(), _gm.x, _gm.y);
XMapWindow(_dpy, _client_window);
_scr->ungrabServer(false);
}
// clean up
ScreenResources::instance()->getPixmapHandler()->returnPixmap(_background);
XDestroyWindow(_dpy, _window);
}
// START - PWinObj interface.
//! @brief Maps the DockApp
void
DockApp::mapWindow(void)
{
if (_mapped) {
return;
}
_mapped = true;
XSelectInput(_dpy, _dockapp_window, NoEventMask);
XMapWindow(_dpy, _window);
XMapWindow(_dpy, _dockapp_window);
XSelectInput(_dpy, _dockapp_window,
StructureNotifyMask|SubstructureNotifyMask);
}
//! @brief Unmaps the DockApp
void
DockApp::unmapWindow(void)
{
if (! _mapped) {
return;
}
_mapped = false;
XSelectInput(_dpy, _dockapp_window, NoEventMask);
XUnmapWindow(_dpy, _dockapp_window);
XUnmapWindow(_dpy, _window);
XSelectInput(_dpy, _dockapp_window,
StructureNotifyMask|SubstructureNotifyMask);
}
// END - PWinObj interface.
//! @brief Kills the DockApp
void
DockApp::kill(void)
{
XKillClient(_dpy, _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(_dpy, _window,
_gm.x, _gm.y, _gm.width, _gm.height);
XMoveResizeWindow(_dpy, _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)
{
PixmapHandler *pm = ScreenResources::instance()->getPixmapHandler();
pm->returnPixmap(_background);
_background = pm->getPixmap(_gm.width, _gm.height, _scr->getDepth());
_theme->getHarbourData()->getTexture()->render(_background, 0, 0, _gm.width, _gm.height);
XSetWindowBackgroundPixmap(_dpy, _window, _background);
XClearWindow(_dpy, _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<uint>(cfg->getHarbourDAMinSide())) {
_gm.width = cfg->getHarbourDAMinSide();
}
if (_gm.height < static_cast<uint>(cfg->getHarbourDAMinSide())) {
_gm.height = cfg->getHarbourDAMinSide();
}
}
if (cfg->getHarbourDAMaxSide() > 0) {
if (_gm.width > static_cast<uint>(cfg->getHarbourDAMaxSide())) {
_gm.width = cfg->getHarbourDAMaxSide();
}
if (_gm.height > static_cast<uint>(cfg->getHarbourDAMaxSide())) {
_gm.height = cfg->getHarbourDAMaxSide();
}
}
}
//! @brief Reads XClassHint of client.
void
DockApp::readClassHint(void)
{
XClassHint x_class_hint;
if (XGetClassHint(_dpy, _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();
}
}

89
pekwm/DockApp.hh Normal file
View File

@ -0,0 +1,89 @@
//
// DockApp.hh for pekwm
// Copyright © 2003-2009 Claes Nästén <me{@}pekdon{.}net>
//
// This program is licensed under the GNU GPL.
// See the LICENSE file for more information.
//
#ifndef _DOCKAPP_HH_
#define _DOCKAPP_HH_
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include "pekwm.hh"
#include "AutoProperties.hh"
class PScreen;
class Theme;
class PWinObj;
//! @brief DockApp handling class.
class DockApp : public PWinObj
{
public:
DockApp(PScreen *scr, Theme *theme, 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);
private:
PScreen *_scr;
Theme *_theme;
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_

32
pekwm/Exception.hh Normal file
View File

@ -0,0 +1,32 @@
//
// PDecor.hh for pekwm
// Copyright © 2009 Claes Nästén <me@pekdon.net>
//
// This program is licensed under the GNU GPL.
// See the LICENSE file for more information.
//
#ifndef _EXCEPTION_H_
#define _EXCEPTION_H_
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_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_

278
pekwm/FontHandler.cc Normal file
View File

@ -0,0 +1,278 @@
//
// FontHandler.cc for pekwm
// Copyright © 2004-2009 Claes Nästén <me@pekdon.net>
//
// This program is licensed under the GNU GPL.
// See the LICENSE file for more information.
//
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include <cctype>
#include <iostream>
#include "PScreen.hh"
#include "ColorHandler.hh"
#include "FontHandler.hh"
#include "Util.hh"
using std::cerr;
using std::endl;
using std::map;
using std::list;
using std::vector;
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)
{
list<HandlerEntry<PFont*> >::iterator it_f(_font_list.begin());
for (; it_f != _font_list.end(); ++it_f) {
delete it_f->getData();
}
list<HandlerEntry<PFont::Color*> >::iterator it_c(_color_list.begin());
for (; it_c != _color_list.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
list<HandlerEntry<PFont*> >::iterator it(_font_list.begin());
for (; it != _font_list.end(); ++it) {
if (*it == font) {
it->incRef();
return it->getData();
}
}
// create new
PFont *pfont = 0;
vector<string> tok;
vector<string>::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<PFont::Type>(*tok_it, _map_type);
if (type == PFont::FONT_TYPE_NO) {
tok_it = tok.end() - 1;
type = ParseUtil::getValue<PFont::Type>(*tok_it, _map_type);
}
switch (type) {
case PFont::FONT_TYPE_XMB:
pfont = new PFontXmb(PScreen::instance());
tok.erase(tok_it);
break;
#ifdef HAVE_XFT
case PFont::FONT_TYPE_XFT:
pfont = new PFontXft(PScreen::instance());
tok.erase(tok_it);
break;
#endif // HAVE_XFT
case PFont::FONT_TYPE_X11:
pfont = new PFontX11(PScreen::instance());
tok.erase(tok_it);
break;
default:
pfont = new PFontXmb(PScreen::instance());
break;
};
pfont->load(tok.front());
// Remove used fields, type and
tok.erase(tok.begin());
// fields left for justify and offset
vector<string>::iterator s_it(tok.begin());
for (; s_it != tok.end(); ++s_it) {
if (isdigit((*s_it)[0])) { // number
vector<string> 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<FontJustify>(*s_it, _map_justify);
if (justify == FONT_JUSTIFY_NO) {
justify = FONT_JUSTIFY_LEFT;
}
pfont->setJustify(justify);
}
}
} else {
pfont = new PFontXmb(PScreen::instance());
pfont->load(font);
}
// create new entry
HandlerEntry<PFont*> entry(font);
entry.incRef();
entry.setData(pfont);
_font_list.push_back(entry);
return pfont;
}
//! @brief Returns a font
void
FontHandler::returnFont(PFont *font)
{
list<HandlerEntry<PFont*> >::iterator it(_font_list.begin());
for (; it != _font_list.begin(); ++it) {
if (it->getData() == font) {
it->decRef();
if (! it->getRef()) {
delete it->getData();
_font_list.erase(it);
}
break;
}
}
}
//! @brief Gets or allocs a color
PFont::Color*
FontHandler::getColor(const std::string &color)
{
// check cache
list<HandlerEntry<PFont::Color*> >::iterator it(_color_list.begin());
for (; it != _color_list.end(); ++it) {
if (*it == color) {
it->incRef();
return it->getData();
}
}
// create new
PFont::Color *font_color = new PFont::Color();
font_color->setHasFg(true);
vector<string> 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<PFont::Color*> entry(color);
entry.incRef();
entry.setData(font_color);
_color_list.push_back(entry);
return font_color;
}
//! @brief Returns a color
void
FontHandler::returnColor(PFont::Color *color)
{
list<HandlerEntry<PFont::Color*> >::iterator it(_color_list.begin());
for (; it != _color_list.begin(); ++it) {
if (it->getData() == color) {
it->decRef();
if (! it->getRef()) {
delete it->getData();
_color_list.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<string> tok;
if (Util::splitString(color, tok, ",", 2, true) == 2) {
uint alpha = static_cast<uint>(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<uint>(65535 * (static_cast<float>(alpha) / 100));
if (fg) {
font_color->setFgAlpha(alpha);
} else {
font_color->setBgAlpha(alpha);
}
xc = ColorHandler::instance()->getColor(tok[0]);
} else {
xc = ColorHandler::instance()->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()) {
ColorHandler::instance()->returnColor(font_color->getFg());
}
if (font_color->hasBg()) {
ColorHandler::instance()->returnColor(font_color->getBg());
}
delete font_color;
}

52
pekwm/FontHandler.hh Normal file
View File

@ -0,0 +1,52 @@
//
// FontHandler.hh for pekwm
// Copyright (C) 2004-2009 Claes Nasten <pekdon{@}pekdon{.}net>
//
// 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 <map>
#include <list>
#include <string>
//! @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:
std::list<HandlerEntry<PFont*> > _font_list;
std::list<HandlerEntry<PFont::Color*> > _color_list;
std::map<ParseUtil::Entry, PFont::Type> _map_type;
std::map<ParseUtil::Entry, FontJustify> _map_justify;
//! @brief Pointer to FontHandler instance, should only be one.
static FontHandler *_instance;
};
#endif // _FONT_HANDLER_HH_

2325
pekwm/Frame.cc Normal file

File diff suppressed because it is too large Load Diff

208
pekwm/Frame.hh Normal file
View File

@ -0,0 +1,208 @@
//
// Frame.hh for pekwm
// Copyright © 2003-2009 Claes Nästén <me{@}pekdon{.}net>
//
// This program is licensed under the GNU GPL.
// See the LICENSE file for more information.
//
#ifndef _FRAME_HH_
#define _FRAME_HH_
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include "pekwm.hh"
#include "Action.hh"
#include "PDecor.hh"
class PScreen;
class PWinObj;
class Strut;
class Theme;
class ClassHint;
class AutoProperty;
class Client;
#include <string>
#include <list>
#include <vector>
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 raise(void);
virtual void setWorkspace(unsigned int workspace);
virtual void setLayer(unsigned int 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.
virtual void handleShapeEvent(XAnyEvent *ev);
// START - PDecor interface.
virtual bool allowMove(void) const;
virtual void addChild(PWinObj *child, std::list<PWinObj*>::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 void getDecorInfo(wchar_t *buf, uint size);
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 _frame_list.size(); }
static std::list<Frame*>::iterator frame_begin(void) {
return _frame_list.begin();
}
static std::list<Frame*>::iterator frame_end(void) {
return _frame_list.end();
}
static std::list<Frame*>::reverse_iterator frame_rbegin(void) {
return _frame_list.rbegin();
}
static std::list<Frame*>::reverse_iterator frame_rend(void) {
return _frame_list.rend();
}
// 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 growDirection(uint direction);
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);
#ifdef OPACITY
void setStateOpaque(StateAction sa);
#endif // OPACITY
void close(void);
void readAutoprops(uint 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;
// 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);
void handleConfigureRequestGeometry(XConfigureRequestEvent *ev, Client *client);
bool isRequestGeometryFullscreen(XConfigureRequestEvent *ev, Client *client);
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 calcGravityPosition(int gravity, int x, int y, int &g_x, int &g_y);
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 applyAPGeometry(Geometry &gm, const Geometry &ap_gm, int mask);
void setActiveTitle(void);
static uint findFrameID(void);
static void returnFrameID(uint id);
static std::string getClientDecorName(Client *client);
private:
PScreen *_scr;
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?
uint _non_fullscreen_layer;
// ID list, list of free Frame ids.
static std::list<Frame*> _frame_list; //!< List of all Frames.
static std::vector<uint> _frameid_list; //!< List 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_

296
pekwm/FrameListMenu.cc Normal file
View File

@ -0,0 +1,296 @@
//
// FrameListMenu.cc for pekwm
// Copyright © 2002-2009 Claes Nästén <me@pekdon.net>
//
// This program is licensed under the GNU GPL.
// See the LICENSE file for more information.
//
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include <algorithm>
#include <cstdio>
#include <cwchar>
#include <iostream>
#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;
using std::swprintf;
//! @brief FrameListMenu constructor.
//! @param scr Pointer to PScreen.
//! @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(PScreen *scr, Theme *theme,
MenuType type,
const std::wstring &title, const std::string &name,
const std::string &decor_name)
: WORefMenu(scr, 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<Client*>(item->getWORef());
Client *wo_ref_client = dynamic_cast<Client*>(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;
}
list<Frame*>::const_iterator it;
// if we have 1 workspace, we won't put an workspace indicator
buf[0] = '\0';
for (uint i = 0; i < Workspaces::instance()->size(); ++i) {
if (Workspaces::instance()->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<Client*>((*it)->getActiveChild())->getTitle()->getVisible());
insert(name, ae, (*it)->getActiveChild(),
static_cast<Client*>((*it)->getActiveChild())->getIcon());
}
}
}
}
// remove the last separator, not needed
if (show_clients && (size() > 0)) {
remove(_item_list.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
list<PWinObj*>::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<Client*>(*it)->getTitle()->getVisible());
insert(name, ae, *it, static_cast<Client*>(*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<Frame*>(client->getParent());
// make sure it's on correct workspace
if (! frame->isSticky() &&
(frame->getWorkspace() != Workspaces::instance()->getActive())) {
Workspaces::instance()->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<Frame*>(client->getParent());
// make sure it's on the current workspace
if (frame->getWorkspace() != Workspaces::instance()->getActive()) {
frame->setWorkspace(Workspaces::instance()->getActive());
}
frame->raise();
frame->mapWindow();
}
//! @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<Frame*>(client_to->getParent());
Frame *frame_from = static_cast<Frame*>(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();
}
}

56
pekwm/FrameListMenu.hh Normal file
View File

@ -0,0 +1,56 @@
//
// FrameListMenu.hh for pekwm
// Copyright © 2003-2009 Claes Nästén <me{@}pekdon{.}net>
//
// This program is licensed under the GNU GPL.
// See the LICENSE file for more information.
//
#ifndef _FRAMELISTMENU_HH_
#define _FRAMELISTMENU_HH_
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include "pekwm.hh"
#include "PMenu.hh"
#include <string>
#include <list>
class WORefMenu;
class PScreen;
class Theme;
class Frame;
class Client;
class FrameListMenu : public WORefMenu
{
public:
FrameListMenu(PScreen *scr, 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_

43
pekwm/Handler.hh Normal file
View File

@ -0,0 +1,43 @@
//
// Handler.hh for pekwm
// Copyright (C) 2004-2009 Claes Nasten <pekdon{@}pekdon{.}net>
//
// 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 <string>
template<class T>
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_

630
pekwm/Harbour.cc Normal file
View File

@ -0,0 +1,630 @@
//
// Harbour.cc for pekwm
// Copyright © 2003-2009 Claes Nästen <me@pekdon.net>
//
// This program is licensed under the GNU GPL.
// See the LICENSE file for more information.
//
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include "Harbour.hh"
#include "PScreen.hh"
#include "Config.hh"
#include "PWinObj.hh"
#include "DockApp.hh"
#include "Workspaces.hh"
#include "AutoProperties.hh"
#include "PDecor.hh"
#include "PMenu.hh"
#include "HarbourMenu.hh"
#include <algorithm>
#include <functional>
using std::list;
using std::mem_fun;
using std::find;
#ifdef DEBUG
#include <iostream>
using std::cerr;
using std::endl;
#endif // DEBUG
//! @brief Harbour constructor
Harbour::Harbour(PScreen *s, Theme *t, Workspaces *w) :
_scr(s), _theme(t), _workspaces(w),
_harbour_menu(0),
_hidden(false), _size(0), _strut(0),
_last_button_x(0), _last_button_y(0)
{
_strut = new Strut();
_scr->addStrut(_strut);
_strut->head = Config::instance()->getHarbourHead();
_harbour_menu = new HarbourMenu(_scr, _theme, this);
}
//! @brief Harbour destructor
Harbour::~Harbour(void)
{
removeAllDockApps();
_scr->removeStrut(_strut);
delete _strut;
delete _harbour_menu;
}
//! @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 {
_da_list.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();
}
#ifdef OPACITY
da->setOpacity(Config::instance()->getHarbourOpacity());
#endif // OPACITY
updateHarbourSize();
}
//! @brief Removes a DockApp from the Harbour
void
Harbour::removeDockApp(DockApp *da)
{
if (! da)
return;
list<DockApp*>::iterator it(find(_da_list.begin(), _da_list.end(), da));
if (it != _da_list.end()) {
_da_list.remove(da);
_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)
{
list<DockApp*>::iterator it(_da_list.begin());
for (; it != _da_list.end(); ++it) {
_workspaces->remove(*it); // remove the dockapp to the stacking list
delete (*it);
}
_da_list.clear();
}
//! @brief Tries to find a dockapp which uses the window win
DockApp*
Harbour::findDockApp(Window win)
{
DockApp *dockapp = 0;
list<DockApp*>::iterator it(_da_list.begin());
for (; it != _da_list.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;
list<DockApp*>::iterator it(_da_list.begin());
for (; it != _da_list.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)
{
list<DockApp*>::iterator it(_da_list.begin());
for (; it != _da_list.end(); ++it) {
placeDockAppInsideScreen(*it);
}
}
#endif // HAVE_XRANDR
//! @brief Lowers or Raises all the DockApps in the harbour.
void
Harbour::restack(void)
{
PScreen::instance()->removeStrut(_strut);
if (Config::instance()->isHarbourOntop() ||
! Config::instance()->isHarbourMaximizeOver()) {
PScreen::instance()->addStrut(_strut);
}
uint l = Config::instance()->isHarbourOntop() ? LAYER_DOCK : LAYER_DESKTOP;
list<DockApp*>::iterator it(_da_list.begin());
for (; it != _da_list.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
{
list<DockApp*>::iterator it (_da_list.begin ());
for (; it != _da_list.end (); ++it)
placeDockApp (*it);
}
}
//! @brief Repaints all dockapps with the new theme
void
Harbour::loadTheme(void)
{
for_each(_da_list.begin(), _da_list.end(), mem_fun(&DockApp::loadTheme));
}
//! @brief Updates the harbour max size variable.
void
Harbour::updateHarbourSize(void)
{
_size = 0;
list<DockApp*>::iterator it(_da_list.begin());
for (; it != _da_list.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(_da_list.begin(), _da_list.end(), mem_fun(&DockApp::mapWindow));
} else {
// Hide if currently visible.
for_each(_da_list.begin(), _da_list.end(), mem_fun(&DockApp::unmapWindow));
}
_hidden = !_hidden;
}
//! @brief Updates Harbour strut size.
void
Harbour::updateStrutSize(void)
{
_strut->left = _strut->right = _strut->top = _strut->bottom = 0;
if (! Config::instance()->isHarbourMaximizeOver()) {
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;
}
}
_scr->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;
// FIXME: Make configurable
if (ev->type == ButtonPress) {
if (ev->button == BUTTON3) {
if (_harbour_menu->isMapped()) {
_harbour_menu->unmapWindow();
} else {
_harbour_menu->setDockApp(da);
_harbour_menu->mapUnderMouse();
}
} else if (_harbour_menu->isMapped()) {
_harbour_menu->unmapWindow();
}
}
}
//! @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;
_scr->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;
}
list<DockApp*>::iterator it(find(_da_list.begin(), _da_list.end(), da));
if (it != _da_list.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 || ! _da_list.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;
PScreen::instance()->getHeadInfo(Config::instance()->getHarbourHead(), head);
getPlaceStartPosition (da, x, y, x_place);
if (right) {
if (x_place) {
x -= da->getWidth ();
} else {
y -= da->getHeight ();
}
}
list<DockApp*>::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 = _da_list.begin();
for (; placed && (it != _da_list.end()); ++it) {
if ((*it) == da) {
continue; // exclude ourselves
}
if (((*it)->getX() < static_cast<signed>(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 = _da_list.begin();
for (; placed && (it != _da_list.end()); ++it) {
if ((*it) == da) {
continue; // exclude ourselves
}
if (((*it)->getY() < static_cast<signed>(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 (! _da_list.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 (_da_list.front (), x_real, y_real, inc_x);
list<DockApp*>::iterator it (_da_list.begin ());
for (; it != _da_list.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;
PScreen::instance()->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<signed>(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<signed>(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<signed>(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<signed>(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;
PScreen::instance()->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)
{
list<DockApp*>::iterator it(_da_list.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 != _da_list.end ()) && ((*it)->getPosition () >= 0); ++it)
;
// Beginning of the list.
} else if (da->getPosition () > 0) {
for (; it != _da_list.end (); ++it) {
if (((*it)->getPosition () < 1) || // got to 0 or less
(da->getPosition () <= (*it)->getPosition ())) {
break;
}
}
// end of the list
} else {
for (; (it != _da_list.end ()) && ((*it)->getPosition () >= 0); ++it)
;
for (; (it != _da_list.end ()) && (da->getPosition () >= (*it)->getPosition ()); ++it)
;
}
_da_list.insert (it, da);
}

84
pekwm/Harbour.hh Normal file
View File

@ -0,0 +1,84 @@
//
// Harbour.hh for pekwm
// Copyright (C) 2003-2009 Claes Nasten <pekdon{@}pekdon{.}net>
//
// 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 PScreen;
class Theme;
class Workspaces;
class DockApp;
class Strut;
class BaseMenu;
class HarbourMenu;
#include "Action.hh"
#include <list>
class Harbour
{
public:
Harbour(PScreen *s, Theme *t, Workspaces *w);
~Harbour(void);
void addDockApp(DockApp* da);
void removeDockApp(DockApp* da);
void removeAllDockApps(void);
DockApp* findDockApp(Window win);
DockApp* findDockAppFromFrame(Window win);
HarbourMenu* getHarbourMenu(void) { return _harbour_menu; }
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);
private:
PScreen *_scr;
Theme *_theme;
Workspaces *_workspaces;
std::list<DockApp*> _da_list;
HarbourMenu *_harbour_menu;
bool _hidden;
uint _size;
Strut *_strut;
int _last_button_x, _last_button_y;
};
#endif // _HARBOUR_HH_

62
pekwm/HarbourMenu.cc Normal file
View File

@ -0,0 +1,62 @@
//
// HarbourMenu.cc for pekwm
// Copyright © 2003-2009 Claes Nästen <me@pekdon.net>
//
// This program is licensed under the GNU GPL.
// See the LICENSE file for more information.
//
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include "PWinObj.hh"
#include "PDecor.hh"
#include "PMenu.hh"
#include "PScreen.hh"
//#include "Action.hh"
#include "HarbourMenu.hh"
#include "DockApp.hh"
//! @brief HarbourMenu constructor
HarbourMenu::HarbourMenu(PScreen *scr, Theme *theme, Harbour *harbour)
: PMenu(theme, L"Harbour", "HARBOUR"),
_harbour(harbour), _dockapp(0)
{
ActionEvent ae;
Action action;
action.setAction(ACTION_SET);
action.setParamI(0, ACTION_STATE_ICONIFIED);
ae.action_list.clear();
ae.action_list.push_back(action);
action.setAction(ACTION_CLOSE);
ae.action_list.clear();
ae.action_list.push_back(action);
buildMenu();
}
//! @brief HarbourMenu destructor
HarbourMenu::~HarbourMenu(void)
{
}
//! @brief
void
HarbourMenu::handleItemExec(PMenu::Item *item)
{
if (! item || ! _dockapp) {
return;
}
if (item->getAE().isOnlyAction(ACTION_SET)) {
_dockapp->iconify();
} else if (item->getAE().isOnlyAction(ACTION_CLOSE)) {
_dockapp->kill();
_dockapp = 0;
}
}

40
pekwm/HarbourMenu.hh Normal file
View File

@ -0,0 +1,40 @@
//
// HarbourMenu.hh for pekwm
// Copyright © 2003-2009 Claes Nästén <me{@}pekdon{.}net>
//
// This program is licensed under the GNU GPL.
// See the LICENSE file for more information.
//
#ifndef _HARBOURMENU_HH_
#define _HARBOURMENU_HH_
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include "pekwm.hh"
#include "PMenu.hh"
class WORefMenu;
class PScreen;
class Theme;
class Harbour;
class DockApp;
class HarbourMenu : public PMenu
{
public:
HarbourMenu(PScreen *scr, Theme *theme, Harbour *harbour);
virtual ~HarbourMenu(void);
virtual void handleItemExec(PMenu::Item *item);
inline void setDockApp(DockApp *da) { _dockapp = da; }
private:
Harbour *_harbour;
DockApp *_dockapp;
};
#endif // _HARBOURMENU_HH_

192
pekwm/ImageHandler.cc Normal file
View File

@ -0,0 +1,192 @@
//
// ImageHandler.cc for pekwm
// Copyright © 2003-2009 Claes Nästén <me@pekdon.net>
//
// This program is licensed under the GNU GPL.
// See the LICENSE file for more information.
//
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include <iostream>
#include "Config.hh"
#include "PImage.hh"
#include "ImageHandler.hh"
#include "PImage.hh"
#include "PImageLoaderJpeg.hh"
#include "PImageLoaderPng.hh"
#include "PImageLoaderXpm.hh"
#include "PScreen.hh"
#include "Util.hh"
using std::cerr;
using std::endl;
using std::list;
using std::vector;
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 (_image_list.size()) {
cerr << " *** WARNING: ImageHandler not empty, " << _image_list.size() << " entries left:" << endl;
while (_image_list.size()) {
cerr << " * " << _image_list.back().getName() << endl;
delete _image_list.back().getData();
_image_list.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.
vector<string> tok;
if ((Util::splitString(file, tok, "#", 2, true)) == 2) {
real_file = tok[0];
image_type = ParseUtil::getValue<ImageType>(tok[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 {
list<string>::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.
list<HandlerEntry<PImage*> >::iterator it(_image_list.begin());
for (; it != _image_list.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(PScreen::instance()->getDpy(), file);
} catch (LoadException&) {
image = 0;
}
// Create new PImage and handler entry for it.
if (image) {
HandlerEntry<PImage*> entry(file);
entry.incRef();
entry.setData(image);
_image_list.push_back(entry);
}
return image;
}
//! @brief Returns a Image
void
ImageHandler::returnImage(PImage *image)
{
bool found = false;
list<HandlerEntry<PImage*> >::iterator it(_image_list.begin());
for (; it != _image_list.end(); ++it) {
if (it->getData() == image) {
found = true;
it->decRef();
if (_free_on_return || ! it->getRef()) {
delete it->getData();
_image_list.erase(it);
}
break;
}
}
if (! found) {
delete image;
}
}
//! @brief Frees all images not beeing in use
void
ImageHandler::freeUnref(void)
{
list<HandlerEntry<PImage*> >::iterator it(_image_list.begin());
while (it != _image_list.end()) {
if (it->getRef() == 0) {
delete it->getData();
it = _image_list.erase(it);
} else {
++it;
}
}
}

Some files were not shown because too many files have changed in this diff Show More