Importing pekwm as alternative wm. Adopting it to ede build system including autoconf checks.
Also center ede-launch window.
52
AUTHORS.pekwm
Normal 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>
|
@ -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@ ;
|
||||
|
3
Jamfile
@ -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 {
|
||||
|
13
configure.in
@ -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
|
||||
|
@ -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
@ -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
@ -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"
|
||||
# }
|
||||
# }
|
||||
|
44
data/pekwm/autoproperties_typerules
Normal 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
@ -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
@ -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
@ -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
@ -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" }
|
||||
}
|
13
data/pekwm/scripts/Jamfile
Normal 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 ;
|
65
data/pekwm/scripts/pekwm_themeset.sh
Normal 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
|
31
data/pekwm/scripts/pekwm_ws_menu.sh
Normal 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
@ -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
@ -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 ;
|
216
data/pekwm/themes/default-plain/theme
Normal 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"
|
||||
}
|
15
data/pekwm/themes/default/Jamfile
Normal 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 ;
|
BIN
data/pekwm/themes/default/arrow.png
Normal file
After Width: | Height: | Size: 679 B |
BIN
data/pekwm/themes/default/arrow_focus.png
Normal file
After Width: | Height: | Size: 679 B |
BIN
data/pekwm/themes/default/bottom-border.png
Normal file
After Width: | Height: | Size: 194 B |
BIN
data/pekwm/themes/default/bottom-border_unfocus.png
Normal file
After Width: | Height: | Size: 194 B |
BIN
data/pekwm/themes/default/bottom-left.png
Normal file
After Width: | Height: | Size: 194 B |
BIN
data/pekwm/themes/default/bottom-left_unfocus.png
Normal file
After Width: | Height: | Size: 194 B |
BIN
data/pekwm/themes/default/bottom-right.png
Normal file
After Width: | Height: | Size: 194 B |
BIN
data/pekwm/themes/default/bottom-right_unfocus.png
Normal file
After Width: | Height: | Size: 194 B |
BIN
data/pekwm/themes/default/button.png
Normal file
After Width: | Height: | Size: 875 B |
BIN
data/pekwm/themes/default/button_hover.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
data/pekwm/themes/default/button_press.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
data/pekwm/themes/default/button_unfocus.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
data/pekwm/themes/default/item.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
data/pekwm/themes/default/item_focus.png
Normal file
After Width: | Height: | Size: 679 B |
BIN
data/pekwm/themes/default/left-border.png
Normal file
After Width: | Height: | Size: 239 B |
BIN
data/pekwm/themes/default/left-border_unfocus.png
Normal file
After Width: | Height: | Size: 203 B |
BIN
data/pekwm/themes/default/menu-bottom.png
Normal file
After Width: | Height: | Size: 607 B |
BIN
data/pekwm/themes/default/menu-bottom_unfocus.png
Normal file
After Width: | Height: | Size: 607 B |
BIN
data/pekwm/themes/default/menuline.png
Normal file
After Width: | Height: | Size: 562 B |
BIN
data/pekwm/themes/default/right-border.png
Normal file
After Width: | Height: | Size: 239 B |
BIN
data/pekwm/themes/default/right-border_unfocus.png
Normal file
After Width: | Height: | Size: 203 B |
BIN
data/pekwm/themes/default/tab-separator.png
Normal file
After Width: | Height: | Size: 392 B |
BIN
data/pekwm/themes/default/tab-separator_unfocus.png
Normal file
After Width: | Height: | Size: 392 B |
225
data/pekwm/themes/default/theme
Normal 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"
|
||||
}
|
BIN
data/pekwm/themes/default/title.png
Normal file
After Width: | Height: | Size: 236 B |
BIN
data/pekwm/themes/default/title_unfocus.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
data/pekwm/themes/default/top-border.png
Normal file
After Width: | Height: | Size: 218 B |
BIN
data/pekwm/themes/default/top-border_unfocus.png
Normal file
After Width: | Height: | Size: 234 B |
BIN
data/pekwm/themes/default/top-left.png
Normal file
After Width: | Height: | Size: 305 B |
BIN
data/pekwm/themes/default/top-left_unfocus.png
Normal file
After Width: | Height: | Size: 550 B |
BIN
data/pekwm/themes/default/top-right.png
Normal file
After Width: | Height: | Size: 550 B |
BIN
data/pekwm/themes/default/top-right_unfocus.png
Normal file
After Width: | Height: | Size: 550 B |
1
data/pekwm/vars
Normal file
@ -0,0 +1 @@
|
||||
$TERM="xterm -fn fixed +sb -bg white -fg black"
|
@ -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();
|
||||
|
@ -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 ""
|
||||
|
@ -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
@ -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
@ -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 ¶m_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
78
pekwm/ActionHandler.hh
Normal 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
@ -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
@ -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
@ -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
@ -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
@ -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 ®ex, const std::string regex_str, const std::string &name)
|
||||
{
|
||||
if (! regex_str.size() || regex.parse_match(Util::to_wide_str(regex_str))) {
|
||||
return true;
|
||||
} else {
|
||||
cerr << " *** WARNING: invalid regexp " << regex_str << " for autoproperty " << name << endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//! @brief Parses a property match rule
|
||||
//! @param str String to parse.
|
||||
//! @param prop Property to place result in.
|
||||
//! @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
@ -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 ®ex, 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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
413
pekwm/Client.hh
Normal 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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
373
pekwm/Config.hh
Normal 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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
208
pekwm/Frame.hh
Normal 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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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;
|
||||
}
|
||||
}
|
||||
}
|