ECKS EM ELL
This commit is contained in:
parent
f7df74b9cc
commit
d2857b1194
19 changed files with 974 additions and 827 deletions
|
@ -53,6 +53,10 @@ PKG_CHECK_MODULES(XFT, [xft])
|
|||
AC_SUBST(XFT_CFLAGS)
|
||||
AC_SUBST(XFT_LIBS)
|
||||
|
||||
PKG_CHECK_MODULES(XML, [libxml-2.0])
|
||||
AC_SUBST(XML_CFLAGS)
|
||||
AC_SUBST(XML_LIBS)
|
||||
|
||||
PKG_CHECK_MODULES(LIBSN, [libstartup-notification-1.0],
|
||||
[
|
||||
AC_DEFINE(USE_LIBSN)
|
||||
|
|
461
data/rc3
461
data/rc3
|
@ -1,191 +1,296 @@
|
|||
[resistance]
|
||||
<?xml version="1.0"?>
|
||||
|
||||
# amount of resistance to provide at edges
|
||||
#strength=10
|
||||
<!-- Do not edit this file, it will be overwritten on install. Edit the file
|
||||
in $HOME/.openbox/ instead. -->
|
||||
|
||||
# resistance against other windows
|
||||
#windows=true
|
||||
<openbox_config>
|
||||
|
||||
[placement]
|
||||
<resistance>
|
||||
<strength>10</strength>
|
||||
<windows>yes</windows>
|
||||
</resistance>
|
||||
|
||||
# place windows where they were last
|
||||
#remember = yes
|
||||
<placement>
|
||||
<remember>yes</remember>
|
||||
</placement>
|
||||
|
||||
[focus]
|
||||
<focus>
|
||||
<focusNew>yes</focusNew>
|
||||
<followMouse>no</followMouse>
|
||||
<focusLast>yes</focusLast>
|
||||
<focusLastOnDesktop>yes</focusLastOnDesktop>
|
||||
<cyclingDialog>yes</cyclingDialog>
|
||||
</focus>
|
||||
|
||||
# focus new windows when they appear
|
||||
#focusNew = yes
|
||||
<theme>
|
||||
<theme>operation</theme>
|
||||
</theme>
|
||||
|
||||
# does focus follow the mouse pointer when it enters a window
|
||||
#followMouse = no
|
||||
<desktops>
|
||||
<number>4</number>
|
||||
<names>
|
||||
<name>one</name>
|
||||
<name>two</name>
|
||||
<name>three</name>
|
||||
<name>four</name>
|
||||
</names>
|
||||
</desktops>
|
||||
|
||||
# when no windows are left with focus, focus the last window on the desktop
|
||||
# to previously have focus
|
||||
#focusLast = yes
|
||||
<moveresize>
|
||||
<opaqueMove>yes</opaqueMove>
|
||||
<opaqueResize>yes</opaqueResize>
|
||||
</moveresize>
|
||||
|
||||
# a special case of focusLast that applies when switching between desktops; if
|
||||
# set, the previously focused window on the desktop is focused when switching
|
||||
#focusLastOnDesktop = yes
|
||||
<dock>
|
||||
<position>topleft</position>
|
||||
<stacking>top</stacking>
|
||||
<direction>vertical</direction>
|
||||
<floatingX>0</floatingX>
|
||||
<floatingY>0</floatingY>
|
||||
<autoHide>no</autoHide>
|
||||
<hideTimeout>300</hideTimeout>
|
||||
</dock>
|
||||
|
||||
# shows a helpful dialog while cycling focus
|
||||
#cyclingDialog = yes
|
||||
<keyboard>
|
||||
<keybind key="A-F10">
|
||||
<action name="MaximizeFull"></action>
|
||||
</keybind>
|
||||
<keybind key="A-F5">
|
||||
<action name="UnmaximizeFull"></action>
|
||||
</keybind>
|
||||
<keybind key="A-F12">
|
||||
<action name="ToggleShaded"></action>
|
||||
</keybind>
|
||||
<keybind key="C-A-Left">
|
||||
<action name="DesktopLeft"></action>
|
||||
</keybind>
|
||||
<keybind key="C-A-Right">
|
||||
<action name="DesktopRight"></action>
|
||||
</keybind>
|
||||
<keybind key="C-A-Up">
|
||||
<action name="DesktopUp"></action>
|
||||
</keybind>
|
||||
<keybind key="C-A-Down">
|
||||
<action name="DesktopDown"></action>
|
||||
</keybind>
|
||||
<keybind key="S-A-Left">
|
||||
<action name="SendToDesktopLeft"></action>
|
||||
</keybind>
|
||||
<keybind key="S-A-Right">
|
||||
<action name="SendToDesktopRight"></action>
|
||||
</keybind>
|
||||
<keybind key="S-A-Up">
|
||||
<action name="SendToDesktopUp"></action>
|
||||
</keybind>
|
||||
<keybind key="S-A-Down">
|
||||
<action name="SendToDesktopDown"></action>
|
||||
</keybind>
|
||||
<keybind key="C-A-d">
|
||||
<action name="ToggleShowDesktop"></action>
|
||||
</keybind>
|
||||
<keybind key="A-F4">
|
||||
<action name="Close"></action>
|
||||
</keybind>
|
||||
<keybind key="A-Tab">
|
||||
<action name="NextWindow"></action>
|
||||
</keybind>
|
||||
<keybind key="A-S-Tab">
|
||||
<action name="PreviousWindow"></action>
|
||||
</keybind>
|
||||
<keybind key="A-F7">
|
||||
<action name="KeyboardMove"></action>
|
||||
</keybind>
|
||||
<keybind key="A-F8">
|
||||
<action name="KeyboardResize"></action>
|
||||
</keybind>
|
||||
<keybind key="A-F9">
|
||||
<action name="Iconify"></action>
|
||||
</keybind>
|
||||
</keyboard>
|
||||
|
||||
[desktops]
|
||||
<mouse>
|
||||
<dragThreshold>3</dragThreshold>
|
||||
<doubleClickTime>200</doubleClickTime>
|
||||
|
||||
# The number of virtual desktops to use
|
||||
#number = 4
|
||||
<context name="frame">
|
||||
<mousebind button="A-Left" action="drag">
|
||||
<action name="move"/>
|
||||
</mousebind>
|
||||
<mousebind button="A-Left" action="click">
|
||||
<action name="raise"/>
|
||||
</mousebind>
|
||||
<mousebind button="A-Left" action="press">
|
||||
<action name="focus"/>
|
||||
</mousebind>
|
||||
<mousebind button="A-Middle" action="drag">
|
||||
<action name="resize"/>
|
||||
</mousebind>
|
||||
<mousebind button="A-Middle" action="click">
|
||||
<action name="lower"/>
|
||||
</mousebind>
|
||||
<mousebind button="A-Right" action="press">
|
||||
<action name="showmenu"><menu>client-menu</menu></action>
|
||||
</mousebind>
|
||||
<mousebind button="A-Up" action="click">
|
||||
<action name="desktopright"/>
|
||||
</mousebind>
|
||||
<mousebind button="A-Down" action="click">
|
||||
<action name="desktopleft"/>
|
||||
</mousebind>
|
||||
<mousebind button="C-A-Up" action="click">
|
||||
<action name="sendtodesktopright"/>
|
||||
</mousebind>
|
||||
<mousebind button="C-A-Down" action="click">
|
||||
<action name="sendtodesktopleft"/>
|
||||
</mousebind>
|
||||
</context>
|
||||
<context name="titlebar">
|
||||
<mousebind button="Left" action="drag">
|
||||
<action name="move"/>
|
||||
</mousebind>
|
||||
<mousebind button="Left" action="click">
|
||||
<action name="raise"/>
|
||||
</mousebind>
|
||||
<mousebind button="Left" action="press">
|
||||
<action name="focus"/>
|
||||
</mousebind>
|
||||
<mousebind button="Left" action="doubleclick">
|
||||
<action name="toggleshade"/>
|
||||
</mousebind>
|
||||
<mousebind button="Middle" action="press">
|
||||
<action name="lower"/>
|
||||
</mousebind>
|
||||
<mousebind button="Up" action="click">
|
||||
<action name="shade"/>
|
||||
</mousebind>
|
||||
<mousebind button="Down" action="click">
|
||||
<action name="unshade"/>
|
||||
</mousebind>
|
||||
<mousebind button="Right" action="press">
|
||||
<action name="showmenu"><menu>client-menu</menu></action>
|
||||
</mousebind>
|
||||
</context>
|
||||
<context name="handle">
|
||||
<mousebind button="Left" action="drag">
|
||||
<action name="move"/>
|
||||
</mousebind>
|
||||
<mousebind button="Left" action="click">
|
||||
<action name="raise"/>
|
||||
</mousebind>
|
||||
<mousebind button="Left" action="press">
|
||||
<action name="focus"/>
|
||||
</mousebind>
|
||||
<mousebind button="Middle" action="press">
|
||||
<action name="lower"/>
|
||||
</mousebind>
|
||||
</context>
|
||||
<context name="blcorner">
|
||||
<mousebind button="Left" action="drag">
|
||||
<action name="resize"/>
|
||||
</mousebind>
|
||||
<mousebind button="Left" action="press">
|
||||
<action name="focus"/>
|
||||
</mousebind>
|
||||
</context>
|
||||
<context name="brcorner">
|
||||
<mousebind button="Left" action="drag">
|
||||
<action name="resize"/>
|
||||
</mousebind>
|
||||
<mousebind button="Left" action="press">
|
||||
<action name="focus"/>
|
||||
</mousebind>
|
||||
</context>
|
||||
<context name="client">
|
||||
<mousebind button="Left" action="press">
|
||||
<action name="focus"/>
|
||||
</mousebind>
|
||||
<mousebind button="Middle" action="press">
|
||||
<action name="focus"/>
|
||||
</mousebind>
|
||||
<mousebind button="Right" action="press">
|
||||
<action name="focus"/>
|
||||
</mousebind>
|
||||
</context>
|
||||
<context name="icon">
|
||||
<mousebind button="Left" action="press">
|
||||
<action name="focus"/>
|
||||
</mousebind>
|
||||
<mousebind button="Left" action="click">
|
||||
<action name="showmenu"><menu>client-menu</menu></action>
|
||||
</mousebind>
|
||||
<mousebind button="Left" action="doubleclick">
|
||||
<action name="close"/>
|
||||
</mousebind>
|
||||
</context>
|
||||
<context name="alldesktops">
|
||||
<mousebind button="Left" action="press">
|
||||
<action name="focus"/>
|
||||
</mousebind>
|
||||
<mousebind button="Left" action="click">
|
||||
<action name="toggleomnipresent"/>
|
||||
</mousebind>
|
||||
</context>
|
||||
<context name="shade">
|
||||
<mousebind button="Left" action="press">
|
||||
<action name="focus"/>
|
||||
</mousebind>
|
||||
<mousebind button="Left" action="click">
|
||||
<action name="toggleshade"/>
|
||||
</mousebind>
|
||||
</context>
|
||||
<context name="iconify">
|
||||
<mousebind button="Left" action="press">
|
||||
<action name="focus"/>
|
||||
</mousebind>
|
||||
<mousebind button="Left" action="click">
|
||||
<action name="iconify"/>
|
||||
</mousebind>
|
||||
</context>
|
||||
<context name="maximize">
|
||||
<mousebind button="Left" action="press">
|
||||
<action name="focus"/>
|
||||
</mousebind>
|
||||
<mousebind button="Middle" action="press">
|
||||
<action name="focus"/>
|
||||
</mousebind>
|
||||
<mousebind button="Right" action="press">
|
||||
<action name="focus"/>
|
||||
</mousebind>
|
||||
<mousebind button="Left" action="click">
|
||||
<action name="togglemaximizefull"/>
|
||||
</mousebind>
|
||||
<mousebind button="Middle" action="click">
|
||||
<action name="togglemaximizevert"/>
|
||||
</mousebind>
|
||||
<mousebind button="Right" action="click">
|
||||
<action name="togglemaximizehorz"/>
|
||||
</mousebind>
|
||||
</context>
|
||||
<context name="close">
|
||||
<mousebind button="Left" action="press">
|
||||
<action name="focus"/>
|
||||
</mousebind>
|
||||
<mousebind button="Left" action="click">
|
||||
<action name="close"/>
|
||||
</mousebind>
|
||||
</context>
|
||||
<context name="root">
|
||||
<mousebind button="Up" action="click">
|
||||
<action name="desktopright"/>
|
||||
</mousebind>
|
||||
<mousebind button="Down" action="click">
|
||||
<action name="desktopleft"/>
|
||||
</mousebind>
|
||||
<mousebind button="A-Up" action="click">
|
||||
<action name="desktopright"/>
|
||||
</mousebind>
|
||||
<mousebind button="A-Down" action="click">
|
||||
<action name="desktopleft"/>
|
||||
</mousebind>
|
||||
<mousebind button="Middle" action="press">
|
||||
<action name="showmenu"><menu>root</menu></action>
|
||||
</mousebind>
|
||||
</context>
|
||||
</mouse>
|
||||
|
||||
# A list of names for the desktops
|
||||
names = ("one" "two" "three" "four")
|
||||
|
||||
[moveresize]
|
||||
|
||||
# When true windows are moved opaquely, when false just an outline is shown
|
||||
# while they are moved
|
||||
#opaque_move = yes
|
||||
|
||||
# When true windows are resized opaquely, when false just an outline is shown
|
||||
# while they are resized
|
||||
#opaque_resize = yes
|
||||
|
||||
[theme]
|
||||
|
||||
# the theme to display
|
||||
#theme = "operation"
|
||||
|
||||
[dock]
|
||||
# The position on the screen to place the dock. Options are:
|
||||
# TopLeft, Top, TopRight, Right, BottomRight, Bottom, BottomLeft, Left
|
||||
# - the appropriate corner/edge of the screen
|
||||
# Floating - uses the floatingX and floatingY options to position itself
|
||||
#position = "TopLeft"
|
||||
|
||||
# When position is "Floating", this specifies the x-coordinate to place the
|
||||
# the dock at.
|
||||
#floatingX = 0
|
||||
|
||||
# When position is "Floating", this specifies the y-coordinate to place the
|
||||
# the dock at.
|
||||
#floatingY = 0
|
||||
|
||||
# The stacking layer that the dock will be in. Options are:
|
||||
# Top - above all normal windows, same layer as panels
|
||||
# Normal - can be above and below normal windows
|
||||
# Bottom - below all normal windows
|
||||
#stacking = "Top"
|
||||
|
||||
# When true, the dock will grow horizontally when dock apps are added to it,
|
||||
# otherwise it will grow vertically.
|
||||
#horizontal = no
|
||||
|
||||
# When true, the dock will hide itself while the pointer is not over it, and
|
||||
# will show itself when the pointer is.
|
||||
#autoHide = no
|
||||
|
||||
# The number of milliseconds to wait before hiding the dock when the pointer
|
||||
# leaves it, if the autoHide option is on.
|
||||
#hideTimeout = 3000
|
||||
|
||||
[keyboard]
|
||||
|
||||
#kbind (Key [Key...]) Action [Parameter]
|
||||
|
||||
kbind (F12) execute "xterm"
|
||||
|
||||
kbind (A-Left) PreviousDesktopWrap
|
||||
kbind (A-Right) NextDesktopWrap
|
||||
|
||||
kbind (A-1) Desktop 1
|
||||
kbind (A-2) Desktop 2
|
||||
kbind (A-3) Desktop 3
|
||||
kbind (A-4) Desktop 4
|
||||
|
||||
kbind (C-A-1) SendToDesktop 1
|
||||
kbind (C-A-2) SendToDesktop 2
|
||||
kbind (C-A-3) SendToDesktop 3
|
||||
kbind (C-A-4) SendToDesktop 4
|
||||
|
||||
kbind (C-S-x x) ToggleMaximizeFull
|
||||
kbind (C-S-x Up) ToggleMaximizeVert
|
||||
kbind (C-S-x Right) ToggleMaximizeHorz
|
||||
|
||||
kbind (C-A-Left) MoveRelativeHorz -3
|
||||
kbind (C-A-Right) MoveRelativeHorz 3
|
||||
kbind (C-A-Up) MoveRelativeVert -3
|
||||
kbind (C-A-Down) MoveRelativeVert 3
|
||||
|
||||
kbind (A-F4) Close
|
||||
|
||||
kbind (W-D) ToggleDecorations
|
||||
|
||||
kbind (A-Tab) NextWindow
|
||||
kbind (S-A-Tab) PreviousWindow
|
||||
|
||||
[mouse]
|
||||
|
||||
# the distance a drag must go before it is recognized
|
||||
#dragThreshold = 3
|
||||
|
||||
# the amount of time in milliseconds in which two clicks must occur to cause a
|
||||
# doubleclick event
|
||||
#doubleClickTime = 200
|
||||
|
||||
#mbind Context Event Button Action [Parameter]
|
||||
|
||||
mbind Titlebar Drag Left Move
|
||||
mbind Handle Drag Left Move
|
||||
mbind Frame Drag A-Left Move
|
||||
|
||||
mbind BLCorner Drag Left Resize
|
||||
mbind BRCorner Drag Left Resize
|
||||
mbind Frame Drag A-Middle Resize
|
||||
|
||||
mbind Titlebar Click Left Raise
|
||||
mbind Titlebar Press Middle Lower
|
||||
mbind Handle Click Left Raise
|
||||
mbind Handle Press Middle Lower
|
||||
mbind Frame Click A-Left Raise
|
||||
mbind Frame Click A-Middle Lower
|
||||
|
||||
mbind Titlebar Press Left Focus
|
||||
mbind Handle Press Left Focus
|
||||
mbind BLCorner Press Left Focus
|
||||
mbind BRCorner Press Left Focus
|
||||
mbind Maximize Press Left Focus
|
||||
mbind Maximize Press Middle Focus
|
||||
mbind Maximize Press Right Focus
|
||||
mbind Iconify Press Left Focus
|
||||
mbind Icon Press Left Focus
|
||||
mbind Close Press Left Focus
|
||||
mbind AllDesktops Press Left Focus
|
||||
mbind Shade Press Left Focus
|
||||
mbind Client Press Left FocusRaise
|
||||
mbind Client Press Middle Focus
|
||||
mbind Client Press Right Focus
|
||||
mbind Frame Press A-Left Focus
|
||||
|
||||
mbind Titlebar DoubleClick Left ToggleShade
|
||||
mbind Titlebar Click Up Shade
|
||||
mbind Titlebar Click Down UnShade
|
||||
|
||||
mbind Maximize Click Left ToggleMaximizeFull
|
||||
mbind Maximize Click Middle ToggleMaximizeVert
|
||||
mbind Maximize Click Right ToggleMaximizeHorz
|
||||
mbind Iconify Click Left Iconify
|
||||
mbind Icon DoubleClick Left Close
|
||||
mbind Close Click Left Close
|
||||
mbind Close Click Middle Kill
|
||||
mbind AllDesktops Click Left ToggleOmnipresent
|
||||
mbind Shade Click Left ToggleShade
|
||||
|
||||
mbind Root Click Up NextDesktopWrap
|
||||
mbind Root Click Down PreviousDesktopWrap
|
||||
mbind Root Click A-Up NextDesktopWrap
|
||||
mbind Root Click A-Down PreviousDesktopWrap
|
||||
mbind Frame Click A-Up NextDesktopWrap
|
||||
mbind Frame Click A-Down PreviousDesktopWrap
|
||||
mbind Frame Click C-A-Up SendToNextDesktopWrap
|
||||
mbind Frame Click C-A-Down SendToPreviousDesktopWrap
|
||||
|
||||
mbind Root Click Right ShowMenu "root"
|
||||
mbind Frame Click Right ShowMenu "client-menu"
|
||||
</openbox_config>
|
||||
|
|
|
@ -6,7 +6,7 @@ binary=openbox3
|
|||
url=http://icculus.org/openbox
|
||||
|
||||
CPPFLAGS=$(X_CFLAGS) $(XFT_CFLAGS) $(GLIB_CFLAGS) $(GMODULE_CFLAGS) \
|
||||
$(LIBSN_CFLAGS) $(GL_CFLAGS) @CPPFLAGS@ \
|
||||
$(LIBSN_CFLAGS) $(GL_CFLAGS) $(XML_CFLAGS) @CPPFLAGS@ \
|
||||
-DLOCALEDIR=\"$(localedir)\" \
|
||||
-DRCDIR=\"$(rcdir)\" \
|
||||
-DPLUGINDIR=\"$(plugindir)\" \
|
||||
|
@ -16,38 +16,25 @@ CPPFLAGS=$(X_CFLAGS) $(XFT_CFLAGS) $(GLIB_CFLAGS) $(GMODULE_CFLAGS) \
|
|||
INCLUDES=-I..
|
||||
LIBS=$(X_LIBS) $(XFT_LIBS) $(XINERAMA_LIBS) $(XKB_LIBS) $(XRANDR_LIBS) \
|
||||
$(VIDMODE_LIBS) $(XSHAPE_LIBS) $(GLIB_LIBS) $(GMODULE_LIBS) \
|
||||
$(LIBSN_LIBS) @LIBS@ @LIBINTL@
|
||||
$(LIBSN_LIBS) $(XML_LIBS) @LIBS@ @LIBINTL@
|
||||
|
||||
bin_PROGRAMS=$(binary)
|
||||
|
||||
openbox3_LDADD=-lobrender -L../render
|
||||
openbox3_LDFLAGS=-export-dynamic
|
||||
openbox3_SOURCES=parse.tab.c parse.lex.c action.c client.c config.c \
|
||||
openbox3_SOURCES=action.c client.c config.c parse.c \
|
||||
extensions.c focus.c frame.c grab.c menu.c menu_render.c \
|
||||
openbox.c framerender.c parse.c plugin.c prop.c screen.c \
|
||||
openbox.c framerender.c plugin.c prop.c screen.c \
|
||||
stacking.c dispatch.c event.c group.c timer.c xerror.c \
|
||||
moveresize.c startup.c popup.c dock.c window.c
|
||||
|
||||
noinst_HEADERS=action.h client.h config.h dispatch.h event.h extensions.h \
|
||||
focus.h frame.h framerender.h geom.h gettext.h grab.h group.h \
|
||||
menu.h openbox.h parse.h parse.tab.h plugin.h prop.h screen.h \
|
||||
menu.h openbox.h plugin.h prop.h screen.h \
|
||||
stacking.h timer.h xerror.h moveresize.h startup.h popup.h \
|
||||
dock.h window.h
|
||||
|
||||
# kill the implicit .c.y rule
|
||||
%.c: %.y
|
||||
@
|
||||
|
||||
%.lex.c: %.l
|
||||
$(FLEX) -o$@ $<
|
||||
|
||||
%.tab.c: %.y
|
||||
$(BISON) -d -o $@ $<
|
||||
dock.h window.h parse.h
|
||||
|
||||
MAINTAINERCLEANFILES=Makefile.in
|
||||
|
||||
clean-local:
|
||||
$(RM) parse.lex.c parse.tab.c parse.tab.h
|
||||
|
||||
distclean-local:
|
||||
$(RM) *\~ *.orig *.rej .\#*
|
||||
|
|
264
openbox/config.c
264
openbox/config.c
|
@ -23,182 +23,114 @@ gboolean config_dock_horz;
|
|||
gboolean config_dock_hide;
|
||||
guint config_dock_hide_timeout;
|
||||
|
||||
static void parse_focus(char *name, ParseToken *value)
|
||||
static void parse_focus(xmlDocPtr doc, xmlNodePtr node, void *d)
|
||||
{
|
||||
if (!g_ascii_strcasecmp(name, "focusnew")) {
|
||||
if (value->type != TOKEN_BOOL)
|
||||
yyerror("invalid value");
|
||||
else {
|
||||
config_focus_new = value->data.bool;
|
||||
}
|
||||
} else if (!g_ascii_strcasecmp(name, "followmouse")) {
|
||||
if (value->type != TOKEN_BOOL)
|
||||
yyerror("invalid value");
|
||||
else {
|
||||
config_focus_follow = value->data.bool;
|
||||
}
|
||||
} else if (!g_ascii_strcasecmp(name, "focuslast")) {
|
||||
if (value->type != TOKEN_BOOL)
|
||||
yyerror("invalid value");
|
||||
else {
|
||||
config_focus_last = value->data.bool;
|
||||
}
|
||||
} else if (!g_ascii_strcasecmp(name, "focuslastondesktop")) {
|
||||
if (value->type != TOKEN_BOOL)
|
||||
yyerror("invalid value");
|
||||
else {
|
||||
config_focus_last_on_desktop = value->data.bool;
|
||||
}
|
||||
} else if (!g_ascii_strcasecmp(name, "cyclingdialog")) {
|
||||
if (value->type != TOKEN_BOOL)
|
||||
yyerror("invalid value");
|
||||
else {
|
||||
config_focus_popup = value->data.bool;
|
||||
}
|
||||
} else
|
||||
yyerror("invalid option");
|
||||
parse_free_token(value);
|
||||
xmlNodePtr n;
|
||||
|
||||
if ((n = parse_find_node("focusNew", node)))
|
||||
config_focus_new = parse_bool(doc, n);
|
||||
if ((n = parse_find_node("followMouse", node)))
|
||||
config_focus_follow = parse_bool(doc, n);
|
||||
if ((n = parse_find_node("focusLast", node)))
|
||||
config_focus_last = parse_bool(doc, n);
|
||||
if ((n = parse_find_node("focusLastOnDesktop", node)))
|
||||
config_focus_last_on_desktop = parse_bool(doc, n);
|
||||
if ((n = parse_find_node("cyclingDialog", node)))
|
||||
config_focus_popup = parse_bool(doc, n);
|
||||
}
|
||||
|
||||
static void parse_theme(char *name, ParseToken *value)
|
||||
static void parse_theme(xmlDocPtr doc, xmlNodePtr node, void *d)
|
||||
{
|
||||
if (!g_ascii_strcasecmp(name, "theme")) {
|
||||
if (value->type != TOKEN_STRING)
|
||||
yyerror("invalid value");
|
||||
else {
|
||||
g_free(config_theme);
|
||||
config_theme = g_strdup(value->data.string);
|
||||
}
|
||||
} else
|
||||
yyerror("invalid option");
|
||||
parse_free_token(value);
|
||||
xmlNodePtr n;
|
||||
|
||||
if ((n = parse_find_node("theme", node))) {
|
||||
g_free(config_theme);
|
||||
config_theme = parse_string(doc, n);
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_desktops(char *name, ParseToken *value)
|
||||
static void parse_desktops(xmlDocPtr doc, xmlNodePtr node, void *d)
|
||||
{
|
||||
GList *it;
|
||||
xmlNodePtr n;
|
||||
|
||||
if (!g_ascii_strcasecmp(name, "number")) {
|
||||
if (value->type != TOKEN_INTEGER)
|
||||
yyerror("invalid value");
|
||||
else {
|
||||
config_desktops_num = value->data.integer;
|
||||
if ((n = parse_find_node("number", node)))
|
||||
config_desktops_num = parse_int(doc, n);
|
||||
if ((n = parse_find_node("names", node))) {
|
||||
GSList *it;
|
||||
xmlNodePtr nname;
|
||||
|
||||
for (it = config_desktops_names; it; it = it->next)
|
||||
g_free(it->data);
|
||||
g_slist_free(config_desktops_names);
|
||||
config_desktops_names = NULL;
|
||||
|
||||
nname = parse_find_node("name", n->xmlChildrenNode);
|
||||
while (nname) {
|
||||
config_desktops_names = g_slist_append(config_desktops_names,
|
||||
parse_string(doc, nname));
|
||||
nname = parse_find_node("name", nname->next);
|
||||
}
|
||||
} else if (!g_ascii_strcasecmp(name, "names")) {
|
||||
if (value->type == TOKEN_LIST) {
|
||||
for (it = value->data.list; it; it = it->next)
|
||||
if (((ParseToken*)it->data)->type != TOKEN_STRING) break;
|
||||
if (it == NULL) {
|
||||
/* build a string list */
|
||||
g_free(config_desktops_names);
|
||||
for (it = value->data.list; it; it = it->next)
|
||||
config_desktops_names =
|
||||
g_slist_append(config_desktops_names,
|
||||
g_strdup
|
||||
(((ParseToken*)it->data)->data.string));
|
||||
} else {
|
||||
yyerror("invalid string in names list");
|
||||
}
|
||||
} else {
|
||||
yyerror("syntax error (expected list of strings)");
|
||||
}
|
||||
} else
|
||||
yyerror("invalid option");
|
||||
parse_free_token(value);
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_moveresize(char *name, ParseToken *value)
|
||||
static void parse_moveresize(xmlDocPtr doc, xmlNodePtr node, void *d)
|
||||
{
|
||||
if (!g_ascii_strcasecmp(name, "opaque_move")) {
|
||||
if (value->type != TOKEN_BOOL)
|
||||
yyerror("invalid value");
|
||||
else {
|
||||
config_opaque_move = value->data.integer;
|
||||
}
|
||||
} else if (!g_ascii_strcasecmp(name, "opaque_resize")) {
|
||||
if (value->type != TOKEN_BOOL)
|
||||
yyerror("invalid value");
|
||||
else {
|
||||
config_opaque_resize = value->data.integer;
|
||||
}
|
||||
} else
|
||||
yyerror("invalid option");
|
||||
parse_free_token(value);
|
||||
xmlNodePtr n;
|
||||
|
||||
if ((n = parse_find_node("opaqueMove", node)))
|
||||
config_opaque_move = parse_bool(doc, n);
|
||||
if ((n = parse_find_node("opaqueResize", node)))
|
||||
config_opaque_resize = parse_bool(doc, n);
|
||||
}
|
||||
|
||||
static void parse_dock(char *name, ParseToken *value)
|
||||
static void parse_dock(xmlDocPtr doc, xmlNodePtr node, void *d)
|
||||
{
|
||||
if (!g_ascii_strcasecmp(name, "stacking")) {
|
||||
if (value->type != TOKEN_STRING)
|
||||
yyerror("invalid value");
|
||||
else {
|
||||
if (!g_ascii_strcasecmp(value->data.string, "bottom"))
|
||||
config_dock_layer = Layer_Below;
|
||||
else if (!g_ascii_strcasecmp(value->data.string, "normal"))
|
||||
config_dock_layer = Layer_Normal;
|
||||
else if (!g_ascii_strcasecmp(value->data.string, "top"))
|
||||
config_dock_layer = Layer_Top;
|
||||
else
|
||||
yyerror("invalid layer");
|
||||
}
|
||||
} else if (!g_ascii_strcasecmp(name, "position")) {
|
||||
if (value->type != TOKEN_STRING)
|
||||
yyerror("invalid value");
|
||||
else {
|
||||
if (!g_ascii_strcasecmp(value->data.string, "topleft"))
|
||||
config_dock_pos = DockPos_TopLeft;
|
||||
else if (!g_ascii_strcasecmp(value->data.string, "top"))
|
||||
config_dock_pos = DockPos_Top;
|
||||
else if (!g_ascii_strcasecmp(value->data.string, "topright"))
|
||||
config_dock_pos = DockPos_TopRight;
|
||||
else if (!g_ascii_strcasecmp(value->data.string, "right"))
|
||||
config_dock_pos = DockPos_Right;
|
||||
else if (!g_ascii_strcasecmp(value->data.string, "bottomright"))
|
||||
config_dock_pos = DockPos_BottomRight;
|
||||
else if (!g_ascii_strcasecmp(value->data.string, "bottom"))
|
||||
config_dock_pos = DockPos_Bottom;
|
||||
else if (!g_ascii_strcasecmp(value->data.string, "bottomleft"))
|
||||
config_dock_pos = DockPos_BottomLeft;
|
||||
else if (!g_ascii_strcasecmp(value->data.string, "left"))
|
||||
config_dock_pos = DockPos_Left;
|
||||
else if (!g_ascii_strcasecmp(value->data.string, "floating"))
|
||||
config_dock_pos = DockPos_Floating;
|
||||
else
|
||||
yyerror("invalid position");
|
||||
}
|
||||
} else if (!g_ascii_strcasecmp(name, "floatingx")) {
|
||||
if (value->type != TOKEN_INTEGER)
|
||||
yyerror("invalid value");
|
||||
else {
|
||||
config_dock_x = value->data.integer;
|
||||
}
|
||||
} else if (!g_ascii_strcasecmp(name, "floatingy")) {
|
||||
if (value->type != TOKEN_INTEGER)
|
||||
yyerror("invalid value");
|
||||
else {
|
||||
config_dock_y = value->data.integer;
|
||||
}
|
||||
} else if (!g_ascii_strcasecmp(name, "horizontal")) {
|
||||
if (value->type != TOKEN_BOOL)
|
||||
yyerror("invalid value");
|
||||
else {
|
||||
config_dock_horz = value->data.bool;
|
||||
}
|
||||
} else if (!g_ascii_strcasecmp(name, "autohide")) {
|
||||
if (value->type != TOKEN_BOOL)
|
||||
yyerror("invalid value");
|
||||
else {
|
||||
config_dock_hide = value->data.bool;
|
||||
}
|
||||
} else if (!g_ascii_strcasecmp(name, "hidetimeout")) {
|
||||
if (value->type != TOKEN_INTEGER)
|
||||
yyerror("invalid value");
|
||||
else {
|
||||
config_dock_hide_timeout = value->data.integer;
|
||||
}
|
||||
} else
|
||||
yyerror("invalid option");
|
||||
parse_free_token(value);
|
||||
xmlNodePtr n;
|
||||
|
||||
if ((n = parse_find_node("position", node))) {
|
||||
if (parse_contains("TopLeft", doc, n))
|
||||
config_dock_pos = DockPos_TopLeft;
|
||||
else if (parse_contains("Top", doc, n))
|
||||
config_dock_pos = DockPos_Top;
|
||||
else if (parse_contains("TopRight", doc, n))
|
||||
config_dock_pos = DockPos_TopRight;
|
||||
else if (parse_contains("Right", doc, n))
|
||||
config_dock_pos = DockPos_Right;
|
||||
else if (parse_contains("BottomRight", doc, n))
|
||||
config_dock_pos = DockPos_BottomRight;
|
||||
else if (parse_contains("Bottom", doc, n))
|
||||
config_dock_pos = DockPos_Bottom;
|
||||
else if (parse_contains("BottomLeft", doc, n))
|
||||
config_dock_pos = DockPos_BottomLeft;
|
||||
else if (parse_contains("Left", doc, n))
|
||||
config_dock_pos = DockPos_Left;
|
||||
else if (parse_contains("Floating", doc, n))
|
||||
config_dock_pos = DockPos_Floating;
|
||||
}
|
||||
if (config_dock_pos == DockPos_Floating) {
|
||||
if ((n = parse_find_node("floatingX", node)))
|
||||
config_dock_x = parse_int(doc, n);
|
||||
if ((n = parse_find_node("floatingY", node)))
|
||||
config_dock_y = parse_int(doc, n);
|
||||
}
|
||||
if ((n = parse_find_node("stacking", node))) {
|
||||
if (parse_contains("top", doc, n))
|
||||
config_dock_layer = Layer_Top;
|
||||
else if (parse_contains("normal", doc, n))
|
||||
config_dock_layer = Layer_Normal;
|
||||
else if (parse_contains("bottom", doc, n))
|
||||
config_dock_layer = Layer_Below;
|
||||
}
|
||||
if ((n = parse_find_node("direction", node))) {
|
||||
if (parse_contains("horizontal", doc, n))
|
||||
config_dock_horz = TRUE;
|
||||
else if (parse_contains("vertical", doc, n))
|
||||
config_dock_horz = FALSE;
|
||||
}
|
||||
if ((n = parse_find_node("autoHide", node)))
|
||||
config_dock_hide = parse_bool(doc, n);
|
||||
if ((n = parse_find_node("hideTimeout", node)))
|
||||
config_dock_hide_timeout = parse_int(doc, n);
|
||||
}
|
||||
|
||||
void config_startup()
|
||||
|
@ -209,21 +141,21 @@ void config_startup()
|
|||
config_focus_last_on_desktop = TRUE;
|
||||
config_focus_popup = TRUE;
|
||||
|
||||
parse_reg_section("focus", NULL, parse_focus);
|
||||
parse_register("focus", parse_focus, NULL);
|
||||
|
||||
config_theme = NULL;
|
||||
|
||||
parse_reg_section("theme", NULL, parse_theme);
|
||||
parse_register("theme", parse_theme, NULL);
|
||||
|
||||
config_desktops_num = 4;
|
||||
config_desktops_names = NULL;
|
||||
|
||||
parse_reg_section("desktops", NULL, parse_desktops);
|
||||
parse_register("desktops", parse_desktops, NULL);
|
||||
|
||||
config_opaque_move = TRUE;
|
||||
config_opaque_resize = TRUE;
|
||||
|
||||
parse_reg_section("moveresize", NULL, parse_moveresize);
|
||||
parse_register("moveresize", parse_moveresize, NULL);
|
||||
|
||||
config_dock_layer = Layer_Top;
|
||||
config_dock_pos = DockPos_TopRight;
|
||||
|
@ -233,7 +165,7 @@ void config_startup()
|
|||
config_dock_hide = FALSE;
|
||||
config_dock_hide_timeout = 3000;
|
||||
|
||||
parse_reg_section("dock", NULL, parse_dock);
|
||||
parse_register("dock", parse_dock, NULL);
|
||||
}
|
||||
|
||||
void config_shutdown()
|
||||
|
|
|
@ -180,7 +180,7 @@ int main(int argc, char **argv)
|
|||
/* set up the kernel config shit */
|
||||
config_startup();
|
||||
/* parse/load user options */
|
||||
parse_rc();
|
||||
parse_config();
|
||||
/* we're done with parsing now, kill it */
|
||||
parse_shutdown();
|
||||
|
||||
|
|
271
openbox/parse.c
271
openbox/parse.c
|
@ -1,86 +1,243 @@
|
|||
#include "parse.h"
|
||||
#include <glib.h>
|
||||
|
||||
static GHashTable *reg = NULL;
|
||||
struct Callback {
|
||||
char *tag;
|
||||
ParseCallback func;
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct Functions {
|
||||
ParseFunc f;
|
||||
AssignParseFunc af;
|
||||
} *funcs;
|
||||
static GHashTable *callbacks;
|
||||
static xmlDocPtr doc_config = NULL;
|
||||
|
||||
void destshit(gpointer shit) { g_free(shit); }
|
||||
static void destfunc(struct Callback *c)
|
||||
{
|
||||
g_free(c->tag);
|
||||
g_free(c);
|
||||
}
|
||||
|
||||
void parse_startup()
|
||||
{
|
||||
reg = g_hash_table_new_full(g_str_hash, g_str_equal, destshit, destshit);
|
||||
funcs = NULL;
|
||||
callbacks = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
|
||||
(GDestroyNotify)destfunc);
|
||||
}
|
||||
|
||||
void parse_shutdown()
|
||||
{
|
||||
g_hash_table_destroy(reg);
|
||||
xmlFree(doc_config);
|
||||
doc_config = NULL;
|
||||
|
||||
g_hash_table_destroy(callbacks);
|
||||
}
|
||||
|
||||
void parse_reg_section(char *section, ParseFunc func, AssignParseFunc afunc)
|
||||
void parse_register(const char *tag, ParseCallback func, void *data)
|
||||
{
|
||||
struct Functions *f = g_new(struct Functions, 1);
|
||||
f->f = func;
|
||||
f->af = afunc;
|
||||
g_hash_table_insert(reg, g_ascii_strdown(section, -1), f);
|
||||
struct Callback *c;
|
||||
|
||||
if ((c = g_hash_table_lookup(callbacks, tag))) {
|
||||
g_warning("tag '%s' already registered", tag);
|
||||
return;
|
||||
}
|
||||
|
||||
c = g_new(struct Callback, 1);
|
||||
c->tag = g_strdup(tag);
|
||||
c->func = func;
|
||||
c->data = data;
|
||||
g_hash_table_insert(callbacks, c->tag, c);
|
||||
}
|
||||
|
||||
void parse_free_token(ParseToken *token)
|
||||
void parse_config()
|
||||
{
|
||||
GList *it;
|
||||
char *path;
|
||||
xmlNodePtr node = NULL;
|
||||
|
||||
switch (token->type) {
|
||||
case TOKEN_STRING:
|
||||
g_free(token->data.string);
|
||||
break;
|
||||
case TOKEN_IDENTIFIER:
|
||||
g_free(token->data.identifier);
|
||||
break;
|
||||
case TOKEN_LIST:
|
||||
for (it = token->data.list; it; it = it->next) {
|
||||
parse_free_token(it->data);
|
||||
g_free(it->data);
|
||||
xmlLineNumbersDefault(1);
|
||||
|
||||
path = g_build_filename(g_get_home_dir(), ".openbox", "rc3", NULL);
|
||||
if ((doc_config = xmlParseFile(path))) {
|
||||
node = xmlDocGetRootElement(doc_config);
|
||||
if (!node) {
|
||||
xmlFreeDoc(doc_config);
|
||||
doc_config = NULL;
|
||||
g_warning("%s is an empty document", path);
|
||||
} else {
|
||||
if (xmlStrcasecmp(node->name, (const xmlChar*)"openbox_config")) {
|
||||
xmlFreeDoc(doc_config);
|
||||
doc_config = NULL;
|
||||
g_warning("document %s is of wrong type. root node is "
|
||||
"not 'openbox_config'", path);
|
||||
}
|
||||
}
|
||||
g_list_free(token->data.list);
|
||||
break;
|
||||
case TOKEN_REAL:
|
||||
case TOKEN_INTEGER:
|
||||
case TOKEN_BOOL:
|
||||
case TOKEN_LBRACE:
|
||||
case TOKEN_RBRACE:
|
||||
case TOKEN_COMMA:
|
||||
case TOKEN_NEWLINE:
|
||||
break;
|
||||
}
|
||||
g_free(path);
|
||||
if (!doc_config) {
|
||||
path = g_build_filename(RCDIR, "rc3", NULL);
|
||||
if ((doc_config = xmlParseFile(path))) {
|
||||
node = xmlDocGetRootElement(doc_config);
|
||||
if (!node) {
|
||||
xmlFreeDoc(doc_config);
|
||||
doc_config = NULL;
|
||||
g_warning("%s is an empty document", path);
|
||||
} else {
|
||||
if (xmlStrcasecmp(node->name,
|
||||
(const xmlChar*)"openbox_config")) {
|
||||
xmlFreeDoc(doc_config);
|
||||
doc_config = NULL;
|
||||
g_warning("document %s is of wrong type. root node is "
|
||||
"not 'openbox_config'", path);
|
||||
}
|
||||
}
|
||||
}
|
||||
g_free(path);
|
||||
}
|
||||
if (!doc_config) {
|
||||
g_message("unable to find a valid config file, using defaults");
|
||||
} else {
|
||||
parse_tree(doc_config, node->xmlChildrenNode, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void parse_set_section(char *section)
|
||||
void parse_tree(xmlDocPtr doc, xmlNodePtr node, void *nothing)
|
||||
{
|
||||
char *sec;
|
||||
sec = g_ascii_strdown(section, -1);
|
||||
funcs = g_hash_table_lookup(reg, sec);
|
||||
g_free(sec);
|
||||
}
|
||||
while (node) {
|
||||
struct Callback *c = g_hash_table_lookup(callbacks, node->name);
|
||||
|
||||
void parse_token(ParseToken *token)
|
||||
{
|
||||
if (funcs) {
|
||||
if (funcs->f)
|
||||
funcs->f(token);
|
||||
else if (token->type != TOKEN_NEWLINE)
|
||||
yyerror("syntax error");
|
||||
if (c)
|
||||
c->func(doc, node->xmlChildrenNode, c->data);
|
||||
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
|
||||
void parse_assign(char *name, ParseToken *value)
|
||||
char *parse_string(xmlDocPtr doc, xmlNodePtr node)
|
||||
{
|
||||
if (funcs) {
|
||||
if (funcs->af)
|
||||
funcs->af(name, value);
|
||||
else
|
||||
yyerror("syntax error");
|
||||
}
|
||||
xmlChar *c = xmlNodeListGetString(doc, node->xmlChildrenNode, TRUE);
|
||||
char *s = g_strdup((char*)c);
|
||||
xmlFree(c);
|
||||
return s;
|
||||
}
|
||||
|
||||
int parse_int(xmlDocPtr doc, xmlNodePtr node)
|
||||
{
|
||||
xmlChar *c = xmlNodeListGetString(doc, node->xmlChildrenNode, TRUE);
|
||||
int i = atoi((char*)c);
|
||||
xmlFree(c);
|
||||
return i;
|
||||
}
|
||||
|
||||
gboolean parse_bool(xmlDocPtr doc, xmlNodePtr node)
|
||||
{
|
||||
xmlChar *c = xmlNodeListGetString(doc, node->xmlChildrenNode, TRUE);
|
||||
gboolean b = FALSE;
|
||||
if (!xmlStrcasecmp(c, (const xmlChar*) "true"))
|
||||
b = TRUE;
|
||||
else if (!xmlStrcasecmp(c, (const xmlChar*) "yes"))
|
||||
b = TRUE;
|
||||
else if (!xmlStrcasecmp(c, (const xmlChar*) "on"))
|
||||
b = TRUE;
|
||||
xmlFree(c);
|
||||
return b;
|
||||
}
|
||||
|
||||
gboolean parse_contains(const char *val, xmlDocPtr doc, xmlNodePtr node)
|
||||
{
|
||||
xmlChar *c = xmlNodeListGetString(doc, node->xmlChildrenNode, TRUE);
|
||||
gboolean r;
|
||||
r = !xmlStrcasecmp(c, (const xmlChar*) val);
|
||||
xmlFree(c);
|
||||
return r;
|
||||
}
|
||||
|
||||
xmlNodePtr parse_find_node(const char *tag, xmlNodePtr node)
|
||||
{
|
||||
while (node) {
|
||||
if (!xmlStrcasecmp(node->name, (const xmlChar*) tag))
|
||||
return node;
|
||||
node = node->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gboolean parse_attr_int(const char *name, xmlNodePtr node, int *value)
|
||||
{
|
||||
xmlChar *c = xmlGetProp(node, (const xmlChar*) name);
|
||||
gboolean r = FALSE;
|
||||
if (c) {
|
||||
*value = atoi((char*)c);
|
||||
r = TRUE;
|
||||
}
|
||||
xmlFree(c);
|
||||
return r;
|
||||
}
|
||||
|
||||
gboolean parse_attr_string(const char *name, xmlNodePtr node, char **value)
|
||||
{
|
||||
xmlChar *c = xmlGetProp(node, (const xmlChar*) name);
|
||||
gboolean r = FALSE;
|
||||
if (c) {
|
||||
*value = g_strdup((char*)c);
|
||||
r = TRUE;
|
||||
}
|
||||
xmlFree(c);
|
||||
return r;
|
||||
}
|
||||
|
||||
Action *parse_action(xmlDocPtr doc, xmlNodePtr node)
|
||||
{
|
||||
char *actname;
|
||||
Action *act = NULL;
|
||||
xmlNodePtr n;
|
||||
|
||||
if (parse_attr_string("name", node, &actname)) {
|
||||
if ((act = action_from_string(actname))) {
|
||||
if (act->func == action_execute || act->func == action_restart) {
|
||||
if ((n = parse_find_node("execute", node->xmlChildrenNode)))
|
||||
act->data.execute.path = parse_string(doc, n);
|
||||
} else if (act->func == action_showmenu) {
|
||||
if ((n = parse_find_node("menu", node->xmlChildrenNode)))
|
||||
act->data.showmenu.name = parse_string(doc, n);
|
||||
} else if (act->func == action_desktop) {
|
||||
if ((n = parse_find_node("desktop", node->xmlChildrenNode)))
|
||||
act->data.desktop.desk = parse_int(doc, n);
|
||||
if (act->data.desktop.desk > 0) act->data.desktop.desk--;
|
||||
} else if (act->func == action_send_to_desktop) {
|
||||
if ((n = parse_find_node("desktop", node->xmlChildrenNode)))
|
||||
act->data.sendto.desk = parse_int(doc, n);
|
||||
if (act->data.sendto.desk > 0) act->data.sendto.desk--;
|
||||
} else if (act->func == action_move_relative_horz ||
|
||||
act->func == action_move_relative_vert ||
|
||||
act->func == action_resize_relative_horz ||
|
||||
act->func == action_resize_relative_vert) {
|
||||
if ((n = parse_find_node("delta", node->xmlChildrenNode)))
|
||||
act->data.relative.delta = parse_int(doc, n);
|
||||
} else if (act->func == action_desktop_right ||
|
||||
act->func == action_desktop_left ||
|
||||
act->func == action_desktop_up ||
|
||||
act->func == action_desktop_down) {
|
||||
if ((n = parse_find_node("wrap", node->xmlChildrenNode))) {
|
||||
g_message("WRAP %d", parse_bool(doc, n));
|
||||
act->data.desktopdir.wrap = parse_bool(doc, n);
|
||||
}
|
||||
} else if (act->func == action_send_to_desktop_right ||
|
||||
act->func == action_send_to_desktop_left ||
|
||||
act->func == action_send_to_desktop_up ||
|
||||
act->func == action_send_to_desktop_down) {
|
||||
if ((n = parse_find_node("wrap", node->xmlChildrenNode)))
|
||||
act->data.sendtodir.wrap = parse_bool(doc, n);
|
||||
if ((n = parse_find_node("follow", node->xmlChildrenNode)))
|
||||
act->data.sendtodir.follow = parse_bool(doc, n);
|
||||
}
|
||||
}
|
||||
}
|
||||
return act;
|
||||
}
|
||||
|
||||
gboolean parse_attr_contains(const char *val, xmlNodePtr node,
|
||||
const char *name)
|
||||
{
|
||||
xmlChar *c = xmlGetProp(node, (const xmlChar*) name);
|
||||
gboolean r;
|
||||
r = !xmlStrcasecmp(c, (const xmlChar*) val);
|
||||
xmlFree(c);
|
||||
return r;
|
||||
}
|
||||
|
|
|
@ -1,48 +1,38 @@
|
|||
#ifndef __parse_h
|
||||
#define __parse_h
|
||||
|
||||
#include "action.h"
|
||||
|
||||
#include <libxml/parser.h>
|
||||
#include <glib.h>
|
||||
#ifndef NO_TAB_H
|
||||
#include "parse.tab.h"
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
TOKEN_REAL = REAL,
|
||||
TOKEN_INTEGER = INTEGER,
|
||||
TOKEN_STRING = STRING,
|
||||
TOKEN_IDENTIFIER = IDENTIFIER,
|
||||
TOKEN_BOOL = BOOLEAN,
|
||||
TOKEN_LIST,
|
||||
TOKEN_LBRACE = '{',
|
||||
TOKEN_RBRACE = '}',
|
||||
TOKEN_COMMA = ',',
|
||||
TOKEN_NEWLINE = '\n'
|
||||
} ParseTokenType;
|
||||
|
||||
typedef struct {
|
||||
ParseTokenType type;
|
||||
union ParseTokenData data;
|
||||
} ParseToken;
|
||||
|
||||
typedef void (*ParseFunc)(ParseToken *token);
|
||||
typedef void (*AssignParseFunc)(char *name, ParseToken *value);
|
||||
typedef void (*ParseCallback)(xmlDocPtr doc, xmlNodePtr node, void *data);
|
||||
|
||||
void parse_startup();
|
||||
void parse_shutdown();
|
||||
|
||||
/* Parse the RC file
|
||||
found in parse.yacc
|
||||
*/
|
||||
void parse_rc();
|
||||
void parse_register(const char *tag, ParseCallback func, void *data);
|
||||
|
||||
void parse_reg_section(char *section, ParseFunc func, AssignParseFunc afunc);
|
||||
void parse_config();
|
||||
|
||||
void parse_tree(xmlDocPtr doc, xmlNodePtr node, void *nothing);
|
||||
|
||||
|
||||
/* Free a parsed token's allocated memory */
|
||||
void parse_free_token(ParseToken *token);
|
||||
/* helpers */
|
||||
|
||||
/* Display an error message while parsing.
|
||||
found in parse.yacc */
|
||||
void yyerror(char *err);
|
||||
xmlNodePtr parse_find_node(const char *tag, xmlNodePtr node);
|
||||
|
||||
char *parse_string(xmlDocPtr doc, xmlNodePtr node);
|
||||
int parse_int(xmlDocPtr doc, xmlNodePtr node);
|
||||
gboolean parse_bool(xmlDocPtr doc, xmlNodePtr node);
|
||||
|
||||
gboolean parse_contains(const char *val, xmlDocPtr doc, xmlNodePtr node);
|
||||
gboolean parse_attr_contains(const char *val, xmlNodePtr node,
|
||||
const char *name);
|
||||
|
||||
gboolean parse_attr_string(const char *name, xmlNodePtr node, char **value);
|
||||
gboolean parse_attr_int(const char *name, xmlNodePtr node, int *value);
|
||||
|
||||
Action *parse_action(xmlDocPtr doc, xmlNodePtr node);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
%{
|
||||
#include "parse.h"
|
||||
#ifdef HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
#endif
|
||||
|
||||
extern int lineno;
|
||||
%}
|
||||
|
||||
real [-0-9][0-9]*\.[0-9]+
|
||||
integer [-0-9][0-9]*
|
||||
string \"[^"\n]*\"
|
||||
identifier [a-zA-Z][-.a-zA-Z0-9_]*
|
||||
bool ([tT][rR][uU][eE]|[fF][aA][lL][sS][eE]|[yY][eE][sS]|[nN][oO]|[oO][nN]|[oO][fF][fF])
|
||||
|
||||
%%
|
||||
|
||||
^[ \t]*#.*\n /* comment */ { ++lineno; }
|
||||
^[ \t]*#.* /* comment */
|
||||
^[ \t]*\n /* empty lines */ { ++lineno; }
|
||||
[ \t] /* whitespace */
|
||||
{real} { yylval.real = atof(yytext); return REAL; }
|
||||
{integer} { yylval.integer = atoi(yytext); return INTEGER; }
|
||||
{string} { yylval.string = g_strdup(yytext+1); /* drop the left quote */
|
||||
if (yylval.string[yyleng-2] != '"')
|
||||
yyerror("improperly terminated string on line %d");
|
||||
else
|
||||
yylval.string[yyleng-2] = '\0';
|
||||
return STRING;
|
||||
}
|
||||
{bool} { yylval.bool = (!g_ascii_strcasecmp("true", yytext) ||
|
||||
!g_ascii_strcasecmp("yes", yytext) ||
|
||||
!g_ascii_strcasecmp("on", yytext));
|
||||
return BOOLEAN;
|
||||
}
|
||||
{identifier} { yylval.identifier = g_strdup(yytext); return IDENTIFIER; }
|
||||
[{}()\[\]=,] { yylval.character = *yytext; return *yytext; }
|
||||
\n { yylval.character = *yytext; return *yytext; }
|
||||
. { return INVALID; }
|
||||
|
||||
%%
|
||||
|
||||
int yywrap() {
|
||||
return 1;
|
||||
}
|
146
openbox/parse.y
146
openbox/parse.y
|
@ -1,146 +0,0 @@
|
|||
%{
|
||||
#include <glib.h>
|
||||
#ifdef HAVE_STDIO_H
|
||||
# include <stdio.h>
|
||||
#endif
|
||||
|
||||
%}
|
||||
|
||||
%union ParseTokenData {
|
||||
float real;
|
||||
int integer;
|
||||
char *string;
|
||||
char *identifier;
|
||||
gboolean bool;
|
||||
char character;
|
||||
GList *list;
|
||||
}
|
||||
|
||||
%{
|
||||
#define NO_TAB_H
|
||||
#include "parse.h"
|
||||
#undef NO_TAB_H
|
||||
|
||||
extern int yylex();
|
||||
extern int yyparse();
|
||||
void yyerror(char *err);
|
||||
|
||||
extern int lineno;
|
||||
extern FILE *yyin;
|
||||
|
||||
static char *path;
|
||||
static ParseToken t;
|
||||
|
||||
/* in parse.c */
|
||||
void parse_token(ParseToken *token);
|
||||
void parse_assign(char *name, ParseToken *token);
|
||||
void parse_set_section(char *section);
|
||||
%}
|
||||
|
||||
%token <real> REAL
|
||||
%token <integer> INTEGER
|
||||
%token <string> STRING
|
||||
%token <identifier> IDENTIFIER
|
||||
%token <bool> BOOLEAN
|
||||
%token <character> '('
|
||||
%token <character> ')'
|
||||
%token <character> '{'
|
||||
%token <character> '}'
|
||||
%token <character> '='
|
||||
%token <character> ','
|
||||
%token <character> '\n'
|
||||
%token INVALID
|
||||
|
||||
%type <list> list
|
||||
%type <list> listtokens
|
||||
|
||||
%%
|
||||
|
||||
sections:
|
||||
| sections '[' IDENTIFIER ']' { parse_set_section($3); } '\n'
|
||||
{ ++lineno; } lines
|
||||
;
|
||||
|
||||
lines:
|
||||
| lines tokens { t.type='\n'; t.data.character='\n'; parse_token(&t); } '\n'
|
||||
{ ++lineno; }
|
||||
| lines IDENTIFIER '=' listtoken { parse_assign($2, &t); } '\n'
|
||||
{ ++lineno; }
|
||||
;
|
||||
|
||||
tokens:
|
||||
tokens token { parse_token(&t); }
|
||||
| token { parse_token(&t); }
|
||||
;
|
||||
|
||||
token:
|
||||
REAL { t.type = TOKEN_REAL; t.data.real = $1; }
|
||||
| INTEGER { t.type = TOKEN_INTEGER; t.data.integer = $1; }
|
||||
| STRING { t.type = TOKEN_STRING; t.data.string = $1; }
|
||||
| IDENTIFIER { t.type = TOKEN_IDENTIFIER; t.data.identifier = $1; }
|
||||
| BOOLEAN { t.type = TOKEN_BOOL; t.data.bool = $1; }
|
||||
| list { t.type = TOKEN_LIST; t.data.list = $1; }
|
||||
| '{' { t.type = $1; t.data.character = $1; }
|
||||
| '}' { t.type = $1; t.data.character = $1; }
|
||||
| ',' { t.type = $1; t.data.character = $1; }
|
||||
;
|
||||
|
||||
list:
|
||||
'(' listtokens ')' { $$ = $2; }
|
||||
;
|
||||
|
||||
listtokens:
|
||||
listtokens listtoken { ParseToken *nt = g_new(ParseToken, 1);
|
||||
nt->type = t.type;
|
||||
nt->data = t.data;
|
||||
$$ = g_list_append($1, nt);
|
||||
}
|
||||
| listtoken { ParseToken *nt = g_new(ParseToken, 1);
|
||||
nt->type = t.type;
|
||||
nt->data = t.data;
|
||||
$$ = g_list_append(NULL, nt);
|
||||
}
|
||||
;
|
||||
|
||||
listtoken:
|
||||
REAL { t.type = TOKEN_REAL; t.data.real = $1; }
|
||||
| INTEGER { t.type = TOKEN_INTEGER; t.data.integer = $1; }
|
||||
| STRING { t.type = TOKEN_STRING; t.data.string = $1; }
|
||||
| IDENTIFIER { t.type = TOKEN_IDENTIFIER; t.data.identifier = $1; }
|
||||
| BOOLEAN { t.type = TOKEN_BOOL; t.data.bool = $1; }
|
||||
| list { t.type = TOKEN_LIST; t.data.list = $1; }
|
||||
| '{' { t.type = $1; t.data.character = $1; }
|
||||
| '}' { t.type = $1; t.data.character = $1; }
|
||||
| ',' { t.type = $1; t.data.character = $1; }
|
||||
;
|
||||
|
||||
|
||||
%%
|
||||
|
||||
int lineno;
|
||||
|
||||
void yyerror(char *err) {
|
||||
g_message("%s:%d: %s", path, lineno, err);
|
||||
}
|
||||
|
||||
void parse_rc()
|
||||
{
|
||||
/* try the user's rc */
|
||||
path = g_build_filename(g_get_home_dir(), ".openbox", "rc3", NULL);
|
||||
if ((yyin = fopen(path, "r")) == NULL) {
|
||||
g_free(path);
|
||||
/* try the system wide rc */
|
||||
path = g_build_filename(RCDIR, "rc3", NULL);
|
||||
if ((yyin = fopen(path, "r")) == NULL) {
|
||||
g_warning("No rc2 file found!");
|
||||
g_free(path);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
lineno = 1;
|
||||
|
||||
yyparse();
|
||||
|
||||
g_free(path);
|
||||
}
|
|
@ -2,7 +2,8 @@ plugindir=$(libdir)/openbox/plugins
|
|||
|
||||
SUBDIRS = keyboard mouse placement menu
|
||||
|
||||
CPPFLAGS=$(XFT_CFLAGS) $(GLIB_CFLAGS) $(LIBSN_CFLAGS) $(GL_CFLAGS) @CPPFLAGS@ \
|
||||
CPPFLAGS=$(XFT_CFLAGS) $(GLIB_CFLAGS) $(LIBSN_CFLAGS) $(GL_CFLAGS) \
|
||||
$(XML_CFLAGS) @CPPFLAGS@ \
|
||||
-DPLUGINDIR=\"$(plugindir)\"
|
||||
|
||||
INCLUDES=-I..
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
plugindir=$(libdir)/openbox/plugins
|
||||
|
||||
CPPFLAGS=$(XFT_CFLAGS) $(GLIB_CFLAGS) $(LIBSN_CFLAGS) $(GL_CFLAGS) @CPPFLAGS@ \
|
||||
CPPFLAGS=$(XFT_CFLAGS) $(GLIB_CFLAGS) $(LIBSN_CFLAGS) $(GL_CFLAGS) \
|
||||
$(XML_CFLAGS) @CPPFLAGS@ \
|
||||
-DG_LOG_DOMAIN=\"Plugin-Keyboard\"
|
||||
|
||||
INCLUDES=-I../..
|
||||
|
@ -8,7 +9,7 @@ INCLUDES=-I../..
|
|||
plugin_LTLIBRARIES=keyboard.la
|
||||
|
||||
keyboard_la_LDFLAGS=-module -avoid-version
|
||||
keyboard_la_SOURCES=keyboard.c keyparse.c translate.c tree.c
|
||||
keyboard_la_SOURCES=keyboard.c translate.c tree.c
|
||||
|
||||
noinst_HEADERS=keyboard.h keyparse.h translate.h tree.h
|
||||
|
||||
|
|
|
@ -4,17 +4,74 @@
|
|||
#include "kernel/event.h"
|
||||
#include "kernel/grab.h"
|
||||
#include "kernel/action.h"
|
||||
#include "kernel/prop.h"
|
||||
#include "kernel/parse.h"
|
||||
#include "kernel/timer.h"
|
||||
#include "tree.h"
|
||||
#include "keyboard.h"
|
||||
#include "keyparse.h"
|
||||
#include "translate.h"
|
||||
#include <glib.h>
|
||||
|
||||
/*
|
||||
|
||||
<keybind key="C-x">
|
||||
<action name="ChangeDesktop">
|
||||
<desktop>3</desktop>
|
||||
</action>
|
||||
</keybind>
|
||||
|
||||
*/
|
||||
|
||||
static void parse_key(xmlDocPtr doc, xmlNodePtr node, GList *keylist)
|
||||
{
|
||||
char *key;
|
||||
Action *action;
|
||||
xmlNodePtr n, nact;
|
||||
GList *it;
|
||||
|
||||
n = parse_find_node("keybind", node);
|
||||
while (n) {
|
||||
if (parse_attr_string("key", n, &key)) {
|
||||
keylist = g_list_append(keylist, key);
|
||||
|
||||
parse_key(doc, n->xmlChildrenNode, keylist);
|
||||
|
||||
it = g_list_last(keylist);
|
||||
g_free(it->data);
|
||||
keylist = g_list_delete_link(keylist, it);
|
||||
}
|
||||
n = parse_find_node("keybind", n->next);
|
||||
}
|
||||
if (keylist) {
|
||||
nact = parse_find_node("action", node);
|
||||
while (nact) {
|
||||
if ((action = parse_action(doc, nact))) {
|
||||
/* validate that its okay for a key binding */
|
||||
if (action->func == action_moveresize &&
|
||||
action->data.moveresize.corner !=
|
||||
prop_atoms.net_wm_moveresize_move_keyboard &&
|
||||
action->data.moveresize.corner !=
|
||||
prop_atoms.net_wm_moveresize_size_keyboard) {
|
||||
action_free(action);
|
||||
action = NULL;
|
||||
}
|
||||
|
||||
if (action)
|
||||
kbind(keylist, action);
|
||||
}
|
||||
nact = parse_find_node("action", nact->next);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_xml(xmlDocPtr doc, xmlNodePtr node, void *d)
|
||||
{
|
||||
parse_key(doc, node, NULL);
|
||||
}
|
||||
|
||||
void plugin_setup_config()
|
||||
{
|
||||
parse_reg_section("keyboard", keyparse, NULL);
|
||||
parse_register("keyboard", parse_xml, NULL);
|
||||
}
|
||||
|
||||
KeyBindingTree *firstnode = NULL;
|
||||
|
@ -160,6 +217,7 @@ static void event(ObEvent *e, void *foo)
|
|||
act->data.cycle.cancel = FALSE;
|
||||
}
|
||||
|
||||
act->data.any.c = focus_client;
|
||||
act->func(&act->data);
|
||||
|
||||
if (act->func == action_cycle_windows &&
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
plugindir=$(libdir)/openbox/plugins
|
||||
|
||||
CPPFLAGS=$(XFT_CFLAGS) $(GLIB_CFLAGS) $(LIBSN_CFLAGS) $(GL_CFLAGS) @CPPFLAGS@ \
|
||||
CPPFLAGS=$(XFT_CFLAGS) $(GLIB_CFLAGS) $(LIBSN_CFLAGS) $(GL_CFLAGS) \
|
||||
$(XML_CFLAGS) @CPPFLAGS@ \
|
||||
-DG_LOG_DOMAIN=\"Plugin-Mouse\"
|
||||
|
||||
INCLUDES=-I../..
|
||||
|
@ -8,9 +9,9 @@ INCLUDES=-I../..
|
|||
plugin_LTLIBRARIES=mouse.la
|
||||
|
||||
mouse_la_LDFLAGS=-module -avoid-version
|
||||
mouse_la_SOURCES=mouse.c mouseparse.c translate.c
|
||||
mouse_la_SOURCES=mouse.c translate.c
|
||||
|
||||
noinst_HEADERS=mouse.h mouseparse.h translate.h
|
||||
noinst_HEADERS=mouse.h translate.h
|
||||
|
||||
MAINTAINERCLEANFILES=Makefile.in
|
||||
|
||||
|
|
|
@ -9,38 +9,97 @@
|
|||
#include "kernel/frame.h"
|
||||
#include "translate.h"
|
||||
#include "mouse.h"
|
||||
#include "mouseparse.h"
|
||||
#include <glib.h>
|
||||
|
||||
static int threshold;
|
||||
static int dclicktime;
|
||||
|
||||
static void parse_assign(char *name, ParseToken *value)
|
||||
/*
|
||||
|
||||
<context name="Titlebar">
|
||||
<mousebind button="Left" action="Press">
|
||||
<action name="Raise"></action>
|
||||
</mousebind>
|
||||
</context>
|
||||
|
||||
*/
|
||||
|
||||
static void parse_xml(xmlDocPtr doc, xmlNodePtr node, void *d)
|
||||
{
|
||||
if (!g_ascii_strcasecmp(name, "dragthreshold")) {
|
||||
if (value->type != TOKEN_INTEGER)
|
||||
yyerror("invalid value");
|
||||
else {
|
||||
if (value->data.integer >= 0)
|
||||
threshold = value->data.integer;
|
||||
xmlNodePtr n, nbut, nact;
|
||||
char *buttonstr;
|
||||
char *contextstr;
|
||||
MouseAction mact;
|
||||
Action *action;
|
||||
|
||||
if ((n = parse_find_node("dragThreshold", node)))
|
||||
threshold = parse_int(doc, n);
|
||||
if ((n = parse_find_node("doubleClickTime", node)))
|
||||
dclicktime = parse_int(doc, n);
|
||||
|
||||
n = parse_find_node("context", node);
|
||||
while (n) {
|
||||
if (!parse_attr_string("name", n, &contextstr))
|
||||
goto next_n;
|
||||
nbut = parse_find_node("mousebind", n->xmlChildrenNode);
|
||||
while (nbut) {
|
||||
if (!parse_attr_string("button", nbut, &buttonstr))
|
||||
goto next_nbut;
|
||||
if (parse_attr_contains("press", nbut, "action"))
|
||||
mact = MouseAction_Press;
|
||||
else if (parse_attr_contains("release", nbut, "action"))
|
||||
mact = MouseAction_Release;
|
||||
else if (parse_attr_contains("click", nbut, "action"))
|
||||
mact = MouseAction_Click;
|
||||
else if (parse_attr_contains("doubleclick", nbut,"action"))
|
||||
mact = MouseAction_DClick;
|
||||
else if (parse_attr_contains("drag", nbut, "action"))
|
||||
mact = MouseAction_Motion;
|
||||
else
|
||||
goto next_nbut;
|
||||
nact = parse_find_node("action", nbut->xmlChildrenNode);
|
||||
while (nact) {
|
||||
if ((action = parse_action(doc, nact))) {
|
||||
/* validate that its okay for a mouse binding*/
|
||||
if (mact == MouseAction_Motion) {
|
||||
if (action->func != action_moveresize ||
|
||||
action->data.moveresize.corner ==
|
||||
prop_atoms.net_wm_moveresize_move_keyboard ||
|
||||
action->data.moveresize.corner ==
|
||||
prop_atoms.net_wm_moveresize_size_keyboard) {
|
||||
action_free(action);
|
||||
action = NULL;
|
||||
}
|
||||
} else {
|
||||
if (action->func == action_moveresize &&
|
||||
action->data.moveresize.corner !=
|
||||
prop_atoms.net_wm_moveresize_move_keyboard &&
|
||||
action->data.moveresize.corner !=
|
||||
prop_atoms.net_wm_moveresize_size_keyboard) {
|
||||
action_free(action);
|
||||
action = NULL;
|
||||
}
|
||||
}
|
||||
if (action)
|
||||
mbind(buttonstr, contextstr, mact, action);
|
||||
}
|
||||
nact = parse_find_node("action", nact->next);
|
||||
}
|
||||
g_free(buttonstr);
|
||||
next_nbut:
|
||||
nbut = parse_find_node("mousebind", nbut->next);
|
||||
}
|
||||
} else if (!g_ascii_strcasecmp(name, "doubleclicktime")) {
|
||||
if (value->type != TOKEN_INTEGER)
|
||||
yyerror("invalid value");
|
||||
else {
|
||||
if (value->data.integer >= 0)
|
||||
dclicktime = value->data.integer;
|
||||
}
|
||||
} else
|
||||
yyerror("invalid option");
|
||||
parse_free_token(value);
|
||||
g_free(contextstr);
|
||||
next_n:
|
||||
n = parse_find_node("context", n->next);
|
||||
}
|
||||
}
|
||||
|
||||
void plugin_setup_config()
|
||||
{
|
||||
threshold = 3;
|
||||
dclicktime = 200;
|
||||
parse_reg_section("mouse", mouseparse, parse_assign);
|
||||
parse_register("mouse", parse_xml, NULL);
|
||||
}
|
||||
|
||||
/* Array of GSList*s of PointerBinding*s. */
|
||||
|
@ -240,11 +299,11 @@ static void event(ObEvent *e, void *foo)
|
|||
e->data.x.e->xbutton.window);
|
||||
if (e->data.x.e->xbutton.button == button) {
|
||||
/* clicks are only valid if its released over the window */
|
||||
int junk;
|
||||
int junk1, junk2;
|
||||
Window wjunk;
|
||||
guint ujunk, b, w, h;
|
||||
XGetGeometry(ob_display, e->data.x.e->xbutton.window,
|
||||
&wjunk, &junk, &junk, &w, &h, &b, &ujunk);
|
||||
&wjunk, &junk1, &junk2, &w, &h, &b, &ujunk);
|
||||
if (e->data.x.e->xbutton.x >= (signed)-b &&
|
||||
e->data.x.e->xbutton.y >= (signed)-b &&
|
||||
e->data.x.e->xbutton.x < (signed)(w+b) &&
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
plugindir=$(libdir)/openbox/plugins
|
||||
|
||||
CPPFLAGS=$(XFT_CFLAGS) $(GLIB_CFLAGS) $(LIBSN_CFLAGS) $(GL_CFLAGS) @CPPFLAGS@ \
|
||||
CPPFLAGS=$(XFT_CFLAGS) $(GLIB_CFLAGS) $(LIBSN_CFLAGS) $(GL_CFLAGS) \
|
||||
$(XML_CFLAGS) @CPPFLAGS@ \
|
||||
-DG_LOG_DOMAIN=\"Plugin-Placement\"
|
||||
|
||||
INCLUDES=-I../..
|
||||
|
|
|
@ -3,41 +3,47 @@
|
|||
#include "kernel/frame.h"
|
||||
#include "kernel/client.h"
|
||||
#include "kernel/screen.h"
|
||||
#include "kernel/parse.h"
|
||||
#include "history.h"
|
||||
#include <glib.h>
|
||||
#include <string.h>
|
||||
#ifdef HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#define PLACED (1 << 0)
|
||||
|
||||
#define HAVE_POSITION (1 << 1)
|
||||
#define HAVE_SIZE (1 << 2)
|
||||
#define HAVE_DESKTOP (1 << 3)
|
||||
|
||||
struct HistoryItem {
|
||||
char *name;
|
||||
char *class;
|
||||
char *role;
|
||||
int x;
|
||||
int y;
|
||||
gboolean placed;
|
||||
|
||||
int flags;
|
||||
|
||||
int x, y;
|
||||
int w, h;
|
||||
guint desk;
|
||||
};
|
||||
|
||||
static GSList *history = NULL;
|
||||
static GSList *history_list = NULL;
|
||||
static char *history_path = NULL;
|
||||
|
||||
static struct HistoryItem *find_history(Client *c)
|
||||
static struct HistoryItem *history_find(const char *name, const char *class,
|
||||
const char *role)
|
||||
{
|
||||
GSList *it;
|
||||
struct HistoryItem *hi = NULL;
|
||||
|
||||
/* find the client */
|
||||
for (it = history; it != NULL; it = it->next) {
|
||||
for (it = history_list; it != NULL; it = it->next) {
|
||||
hi = it->data;
|
||||
g_assert(hi->name != NULL);
|
||||
g_assert(hi->class != NULL);
|
||||
g_assert(hi->role != NULL);
|
||||
g_assert(c->name != NULL);
|
||||
g_assert(c->class != NULL);
|
||||
g_assert(c->role != NULL);
|
||||
if (!strcmp(hi->name, c->name) &&
|
||||
!strcmp(hi->class, c->class) &&
|
||||
!strcmp(hi->role, c->role))
|
||||
if (!g_utf8_collate(hi->name, name) &&
|
||||
!g_utf8_collate(hi->class, class) &&
|
||||
!g_utf8_collate(hi->role, role))
|
||||
return hi;
|
||||
}
|
||||
return NULL;
|
||||
|
@ -46,57 +52,65 @@ static struct HistoryItem *find_history(Client *c)
|
|||
gboolean place_history(Client *c)
|
||||
{
|
||||
struct HistoryItem *hi;
|
||||
int x, y;
|
||||
int x, y, w, h;
|
||||
|
||||
hi = find_history(c);
|
||||
hi = history_find(c->name, c->class, c->role);
|
||||
|
||||
if (hi != NULL && !hi->placed) {
|
||||
hi->placed = TRUE;
|
||||
if (hi && !(hi->flags & PLACED)) {
|
||||
hi->flags |= PLACED;
|
||||
if (ob_state != State_Starting) {
|
||||
x = hi->x;
|
||||
y = hi->y;
|
||||
|
||||
frame_frame_gravity(c->frame, &x, &y); /* get where the client
|
||||
should be */
|
||||
client_configure(c, Corner_TopLeft, x, y,
|
||||
c->area.width, c->area.height,
|
||||
TRUE, TRUE);
|
||||
if (hi->flags & HAVE_POSITION ||
|
||||
hi->flags & HAVE_SIZE) {
|
||||
if (hi->flags & HAVE_POSITION) {
|
||||
x = hi->x;
|
||||
y = hi->y;
|
||||
/* get where the client should be */
|
||||
frame_frame_gravity(c->frame, &x, &y);
|
||||
} else {
|
||||
x = c->area.x;
|
||||
y = c->area.y;
|
||||
}
|
||||
if (hi->flags & HAVE_SIZE) {
|
||||
w = hi->w * c->size_inc.width;
|
||||
h = hi->h * c->size_inc.height;
|
||||
} else {
|
||||
w = c->area.width;
|
||||
h = c->area.height;
|
||||
}
|
||||
client_configure(c, Corner_TopLeft, x, y, w, h,
|
||||
TRUE, TRUE);
|
||||
}
|
||||
if (hi->flags & HAVE_DESKTOP) {
|
||||
client_set_desktop(c, hi->desk, FALSE);
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
return hi->flags & HAVE_POSITION;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void strip_tabs(char *s)
|
||||
{
|
||||
while (*s != '\0') {
|
||||
if (*s == '\t')
|
||||
*s = ' ';
|
||||
++s;
|
||||
}
|
||||
}
|
||||
|
||||
static void set_history(Client *c)
|
||||
{
|
||||
struct HistoryItem *hi;
|
||||
|
||||
hi = find_history(c);
|
||||
hi = history_find(c->name, c->class, c->role);
|
||||
|
||||
if (hi == NULL) {
|
||||
hi = g_new(struct HistoryItem, 1);
|
||||
history = g_slist_append(history, hi);
|
||||
history_list = g_slist_append(history_list, hi);
|
||||
hi->name = g_strdup(c->name);
|
||||
strip_tabs(hi->name);
|
||||
hi->class = g_strdup(c->class);
|
||||
strip_tabs(hi->class);
|
||||
hi->role = g_strdup(c->role);
|
||||
strip_tabs(hi->role);
|
||||
hi->flags = HAVE_POSITION;
|
||||
}
|
||||
|
||||
hi->x = c->frame->area.x;
|
||||
hi->y = c->frame->area.y;
|
||||
hi->placed = FALSE;
|
||||
if (hi->flags & HAVE_POSITION) {
|
||||
hi->x = c->frame->area.x;
|
||||
hi->y = c->frame->area.y;
|
||||
}
|
||||
|
||||
hi->flags &= ~PLACED;
|
||||
}
|
||||
|
||||
static void event(ObEvent *e, void *foo)
|
||||
|
@ -106,104 +120,140 @@ static void event(ObEvent *e, void *foo)
|
|||
set_history(e->data.c.client);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
<entry name="name" class="class" role="role">
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>300</width>
|
||||
<height>200</height>
|
||||
<desktop>1</desktop>
|
||||
</entry>
|
||||
|
||||
*/
|
||||
|
||||
static void save_history()
|
||||
{
|
||||
GError *err = NULL;
|
||||
GIOChannel *io;
|
||||
GString *buf;
|
||||
xmlDocPtr doc;
|
||||
xmlNodePtr root, node;
|
||||
char *s;
|
||||
GSList *it;
|
||||
struct HistoryItem *hi;
|
||||
gsize ret;
|
||||
|
||||
io = g_io_channel_new_file(history_path, "w", &err);
|
||||
if (io != NULL) {
|
||||
for (it = history; it != NULL; it = it->next) {
|
||||
hi = it->data;
|
||||
buf = g_string_sized_new(0);
|
||||
buf=g_string_append(buf, hi->name);
|
||||
g_string_append_c(buf, '\t');
|
||||
buf=g_string_append(buf, hi->class);
|
||||
g_string_append_c(buf, '\t');
|
||||
buf=g_string_append(buf, hi->role);
|
||||
g_string_append_c(buf, '\t');
|
||||
g_string_append_printf(buf, "%d", hi->x);
|
||||
buf=g_string_append_c(buf, '\t');
|
||||
g_string_append_printf(buf, "%d", hi->y);
|
||||
buf=g_string_append_c(buf, '\n');
|
||||
if (g_io_channel_write_chars(io, buf->str, buf->len, &ret, &err) !=
|
||||
G_IO_STATUS_NORMAL)
|
||||
break;
|
||||
g_string_free(buf, TRUE);
|
||||
doc = xmlNewDoc(NULL);
|
||||
root = xmlNewNode(NULL, (const xmlChar*) "openbox_history");
|
||||
xmlDocSetRootElement(doc, root);
|
||||
|
||||
for (it = history_list; it; it = g_slist_next(it)) {
|
||||
struct HistoryItem *hi = it->data;
|
||||
g_message("adding %s", hi->name);
|
||||
node = xmlNewChild(root, NULL, (const xmlChar*) "entry", NULL);
|
||||
xmlNewProp(node, (const xmlChar*) "name", (const xmlChar*) hi->name);
|
||||
xmlNewProp(node, (const xmlChar*) "class", (const xmlChar*) hi->class);
|
||||
xmlNewProp(node, (const xmlChar*) "role", (const xmlChar*) hi->role);
|
||||
if (hi->flags & HAVE_POSITION) {
|
||||
s = g_strdup_printf("%d", hi->x);
|
||||
xmlNewTextChild(node, NULL,
|
||||
(const xmlChar*) "x", (const xmlChar*) s);
|
||||
g_free(s);
|
||||
s = g_strdup_printf("%d", hi->y);
|
||||
xmlNewTextChild(node, NULL,
|
||||
(const xmlChar*) "y", (const xmlChar*) s);
|
||||
g_free(s);
|
||||
}
|
||||
if (hi->flags & HAVE_SIZE) {
|
||||
s = g_strdup_printf("%d", hi->w);
|
||||
xmlNewTextChild(node, NULL,
|
||||
(const xmlChar*) "width", (const xmlChar*) s);
|
||||
g_free(s);
|
||||
s = g_strdup_printf("%d", hi->h);
|
||||
xmlNewTextChild(node, NULL,
|
||||
(const xmlChar*) "height", (const xmlChar*) s);
|
||||
g_free(s);
|
||||
}
|
||||
if (hi->flags & HAVE_DESKTOP) {
|
||||
s = g_strdup_printf("%d", hi->desk < 0 ? hi->desk : hi->desk + 1);
|
||||
xmlNewTextChild(node, NULL,
|
||||
(const xmlChar*) "desktop", (const xmlChar*) s);
|
||||
g_free(s);
|
||||
}
|
||||
g_io_channel_unref(io);
|
||||
}
|
||||
|
||||
xmlIndentTreeOutput = 1;
|
||||
xmlSaveFormatFile(history_path, doc, 1);
|
||||
|
||||
xmlFree(doc);
|
||||
}
|
||||
|
||||
static void load_history()
|
||||
{
|
||||
GError *err = NULL;
|
||||
GIOChannel *io;
|
||||
char *buf = NULL;
|
||||
char *b, *c;
|
||||
struct HistoryItem *hi = NULL;
|
||||
xmlDocPtr doc;
|
||||
xmlNodePtr node, n;
|
||||
char *name;
|
||||
char *class;
|
||||
char *role;
|
||||
struct HistoryItem *hi;
|
||||
|
||||
io = g_io_channel_new_file(history_path, "r", &err);
|
||||
if (io != NULL) {
|
||||
while (g_io_channel_read_line(io, &buf, NULL, NULL, &err) ==
|
||||
G_IO_STATUS_NORMAL) {
|
||||
hi = g_new0(struct HistoryItem, 1);
|
||||
if (!(doc = xmlParseFile(history_path)))
|
||||
return;
|
||||
if (!(node = xmlDocGetRootElement(doc))) {
|
||||
xmlFreeDoc(doc);
|
||||
doc = NULL;
|
||||
return;
|
||||
}
|
||||
if (xmlStrcasecmp(node->name, (const xmlChar*)"openbox_history")) {
|
||||
xmlFreeDoc(doc);
|
||||
doc = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
b = buf;
|
||||
if ((c = strchr(b, '\t')) == NULL) break;
|
||||
*c = '\0';
|
||||
hi->name = g_strdup(b);
|
||||
node = parse_find_node("entry", node->xmlChildrenNode);
|
||||
while (node) {
|
||||
name = class = role = NULL;
|
||||
if (parse_attr_string("name", node, &name) &&
|
||||
parse_attr_string("class", node, &class) &&
|
||||
parse_attr_string("role", node, &role)) {
|
||||
|
||||
b = c + 1;
|
||||
if ((c = strchr(b, '\t')) == NULL) break;
|
||||
*c = '\0';
|
||||
hi->class = g_strdup(b);
|
||||
hi = history_find(name, class, role);
|
||||
if (!hi) {
|
||||
hi = g_new(struct HistoryItem, 1);
|
||||
hi->name = g_strdup(name);
|
||||
hi->class = g_strdup(class);
|
||||
hi->role = g_strdup(role);
|
||||
hi->flags = 0;
|
||||
}
|
||||
if ((n = parse_find_node("x", node->xmlChildrenNode))) {
|
||||
hi->x = parse_int(doc, n);
|
||||
if ((n = parse_find_node("y", node->xmlChildrenNode))) {
|
||||
hi->y = parse_int(doc, n);
|
||||
hi->flags |= HAVE_POSITION;
|
||||
}
|
||||
}
|
||||
if ((n = parse_find_node("width", node->xmlChildrenNode))) {
|
||||
hi->w = parse_int(doc, n);
|
||||
if ((n = parse_find_node("height", node->xmlChildrenNode))) {
|
||||
hi->h = parse_int(doc, n);
|
||||
hi->flags |= HAVE_SIZE;
|
||||
}
|
||||
}
|
||||
if ((n = parse_find_node("desktop", node->xmlChildrenNode))) {
|
||||
hi->desk = parse_int(doc, n);
|
||||
if (hi->desk > 0) --hi->desk;
|
||||
hi->flags |= HAVE_DESKTOP;
|
||||
}
|
||||
|
||||
b = c + 1;
|
||||
if ((c = strchr(b, '\t')) == NULL) break;
|
||||
*c = '\0';
|
||||
hi->role = g_strdup(b);
|
||||
|
||||
b = c + 1;
|
||||
if ((c = strchr(b, '\t')) == NULL) break;
|
||||
*c = '\0';
|
||||
hi->x = atoi(b);
|
||||
|
||||
b = c + 1;
|
||||
if ((c = strchr(b, '\n')) == NULL) break;
|
||||
*c = '\0';
|
||||
hi->y = atoi(b);
|
||||
|
||||
hi->placed = FALSE;
|
||||
|
||||
g_free(buf);
|
||||
buf = NULL;
|
||||
|
||||
history = g_slist_append(history, hi);
|
||||
hi = NULL;
|
||||
history_list = g_slist_append(history_list, hi);
|
||||
}
|
||||
g_io_channel_unref(io);
|
||||
g_free(name); g_free(class); g_free(role);
|
||||
node = parse_find_node("entry", node->next);
|
||||
}
|
||||
|
||||
g_free(buf);
|
||||
|
||||
if (hi != NULL) {
|
||||
g_free(hi->name);
|
||||
g_free(hi->class);
|
||||
g_free(hi->role);
|
||||
}
|
||||
g_free(hi);
|
||||
xmlFree(doc);
|
||||
}
|
||||
|
||||
void history_startup()
|
||||
{
|
||||
char *path;
|
||||
|
||||
history = NULL;
|
||||
history_list = NULL;
|
||||
|
||||
path = g_build_filename(g_get_home_dir(), ".openbox", "history", NULL);
|
||||
history_path = g_strdup_printf("%s.%d", path, ob_screen);
|
||||
|
@ -219,9 +269,14 @@ void history_shutdown()
|
|||
GSList *it;
|
||||
|
||||
save_history(); /* save to the historydb file */
|
||||
for (it = history; it != NULL; it = it->next)
|
||||
g_free(it->data);
|
||||
g_slist_free(history);
|
||||
for (it = history_list; it != NULL; it = it->next) {
|
||||
struct HistoryItem *hi = it->data;
|
||||
g_free(hi->name);
|
||||
g_free(hi->class);
|
||||
g_free(hi->role);
|
||||
g_free(hi);
|
||||
}
|
||||
g_slist_free(history_list);
|
||||
|
||||
dispatch_register(0, (EventHandler)event, NULL);
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef __plugin_placement_history_h
|
||||
#define __plugin_placement_history_h
|
||||
|
||||
#include "../../kernel/client.h"
|
||||
#include "kernel/client.h"
|
||||
#include <glib.h>
|
||||
|
||||
void history_startup();
|
||||
|
|
|
@ -9,23 +9,19 @@
|
|||
|
||||
static gboolean history;
|
||||
|
||||
static void parse_assign(char *name, ParseToken *value)
|
||||
static void parse_xml(xmlDocPtr doc, xmlNodePtr node, void *d)
|
||||
{
|
||||
if (!g_ascii_strcasecmp(name, "remember")) {
|
||||
if (value->type != TOKEN_BOOL)
|
||||
yyerror("invalid value");
|
||||
else
|
||||
history = value->data.bool;
|
||||
} else
|
||||
yyerror("invalid option");
|
||||
parse_free_token(value);
|
||||
xmlNodePtr n;
|
||||
|
||||
if ((n = parse_find_node("remember", node)))
|
||||
history = parse_bool(doc, n);
|
||||
}
|
||||
|
||||
void plugin_setup_config()
|
||||
{
|
||||
history = TRUE;
|
||||
|
||||
parse_reg_section("placement", NULL, parse_assign);
|
||||
parse_register("placement", parse_xml, NULL);
|
||||
}
|
||||
|
||||
static void place_random(Client *c)
|
||||
|
|
|
@ -9,23 +9,14 @@
|
|||
static int resistance;
|
||||
static gboolean resist_windows;
|
||||
|
||||
static void parse_assign(char *name, ParseToken *value)
|
||||
static void parse_xml(xmlDocPtr doc, xmlNodePtr node, void *d)
|
||||
{
|
||||
if (!g_ascii_strcasecmp(name, "strength")) {
|
||||
if (value->type != TOKEN_INTEGER)
|
||||
yyerror("invalid value");
|
||||
else {
|
||||
if (value->data.integer >= 0)
|
||||
resistance = value->data.integer;
|
||||
}
|
||||
} else if (!g_ascii_strcasecmp(name, "windows")) {
|
||||
if (value->type != TOKEN_BOOL)
|
||||
yyerror("invalid value");
|
||||
else
|
||||
resist_windows = value->data.bool;
|
||||
} else
|
||||
yyerror("invalid option");
|
||||
parse_free_token(value);
|
||||
xmlNodePtr n;
|
||||
|
||||
if ((n = parse_find_node("strength", node)))
|
||||
resistance = parse_int(doc, n);
|
||||
if ((n = parse_find_node("windows", node)))
|
||||
resist_windows = parse_bool(doc, n);
|
||||
}
|
||||
|
||||
void plugin_setup_config()
|
||||
|
@ -33,7 +24,7 @@ void plugin_setup_config()
|
|||
resistance = 10;
|
||||
resist_windows = TRUE;
|
||||
|
||||
parse_reg_section("resistance", NULL, parse_assign);
|
||||
parse_register("resistance", parse_xml, NULL);
|
||||
}
|
||||
|
||||
static void resist_move(Client *c, int *x, int *y)
|
||||
|
|
Loading…
Reference in a new issue