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)
-[resistance]
-
-# amount of resistance to provide at edges
-#strength=10
-
-# resistance against other windows
-#windows=true
-
-[placement]
-
-# place windows where they were last
-#remember = yes
-
-[focus]
-
-# focus new windows when they appear
-#focusNew = yes
-
-# does focus follow the mouse pointer when it enters a window
-#followMouse = no
-
-# when no windows are left with focus, focus the last window on the desktop
-# to previously have focus
-#focusLast = yes
-
-# 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
-
-# shows a helpful dialog while cycling focus
-#cyclingDialog = yes
-
-[desktops]
-
-# The number of virtual desktops to use
-#number = 4
-
-# 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"
+<?xml version="1.0"?>
+
+<!-- Do not edit this file, it will be overwritten on install. Edit the file
+ in $HOME/.openbox/ instead. -->
+
+<openbox_config>
+
+<resistance>
+ <strength>10</strength>
+ <windows>yes</windows>
+</resistance>
+
+<placement>
+ <remember>yes</remember>
+</placement>
+
+<focus>
+ <focusNew>yes</focusNew>
+ <followMouse>no</followMouse>
+ <focusLast>yes</focusLast>
+ <focusLastOnDesktop>yes</focusLastOnDesktop>
+ <cyclingDialog>yes</cyclingDialog>
+</focus>
+
+<theme>
+ <theme>operation</theme>
+</theme>
+
+<desktops>
+ <number>4</number>
+ <names>
+ <name>one</name>
+ <name>two</name>
+ <name>three</name>
+ <name>four</name>
+ </names>
+</desktops>
+
+<moveresize>
+ <opaqueMove>yes</opaqueMove>
+ <opaqueResize>yes</opaqueResize>
+</moveresize>
+
+<dock>
+ <position>topleft</position>
+ <stacking>top</stacking>
+ <direction>vertical</direction>
+ <floatingX>0</floatingX>
+ <floatingY>0</floatingY>
+ <autoHide>no</autoHide>
+ <hideTimeout>300</hideTimeout>
+</dock>
+
+<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>
+
+<mouse>
+ <dragThreshold>3</dragThreshold>
+ <doubleClickTime>200</doubleClickTime>
+
+ <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>
+
+</openbox_config>
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)\" \
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 .\#*
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;
-
- if (!g_ascii_strcasecmp(name, "number")) {
- if (value->type != TOKEN_INTEGER)
- yyerror("invalid value");
- else {
- config_desktops_num = value->data.integer;
- }
- } 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);
+ xmlNodePtr n;
+
+ 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);
+ }
+ }
}
-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()
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;
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()
/* 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();
#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;
-
- 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);
+ char *path;
+ xmlNodePtr node = NULL;
+
+ 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_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_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) {
+ g_message("unable to find a valid config file, using defaults");
+ } else {
+ parse_tree(doc_config, node->xmlChildrenNode, NULL);
+ }
+}
+
+void parse_tree(xmlDocPtr doc, xmlNodePtr node, void *nothing)
+{
+ while (node) {
+ struct Callback *c = g_hash_table_lookup(callbacks, node->name);
+
+ if (c)
+ c->func(doc, node->xmlChildrenNode, c->data);
+
+ node = node->next;
+ }
+}
+
+char *parse_string(xmlDocPtr doc, xmlNodePtr node)
+{
+ xmlChar *c = xmlNodeListGetString(doc, node->xmlChildrenNode, TRUE);
+ char *s = g_strdup((char*)c);
+ xmlFree(c);
+ return s;
}
-void parse_set_section(char *section)
+int parse_int(xmlDocPtr doc, xmlNodePtr node)
{
- char *sec;
- sec = g_ascii_strdown(section, -1);
- funcs = g_hash_table_lookup(reg, sec);
- g_free(sec);
+ xmlChar *c = xmlNodeListGetString(doc, node->xmlChildrenNode, TRUE);
+ int i = atoi((char*)c);
+ xmlFree(c);
+ return i;
}
-void parse_token(ParseToken *token)
+gboolean parse_bool(xmlDocPtr doc, xmlNodePtr node)
{
- if (funcs) {
- if (funcs->f)
- funcs->f(token);
- else if (token->type != TOKEN_NEWLINE)
- yyerror("syntax error");
+ 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;
}
-void parse_assign(char *name, ParseToken *value)
+gboolean parse_attr_string(const char *name, xmlNodePtr node, char **value)
{
- if (funcs) {
- if (funcs->af)
- funcs->af(name, value);
- else
- yyerror("syntax error");
+ 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;
}
#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_config();
+
+void parse_tree(xmlDocPtr doc, xmlNodePtr node, void *nothing);
+
+
+/* helpers */
+
+xmlNodePtr parse_find_node(const char *tag, xmlNodePtr node);
-void parse_reg_section(char *section, ParseFunc func, AssignParseFunc afunc);
+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);
-/* Free a parsed token's allocated memory */
-void parse_free_token(ParseToken *token);
+gboolean parse_attr_string(const char *name, xmlNodePtr node, char **value);
+gboolean parse_attr_int(const char *name, xmlNodePtr node, int *value);
-/* Display an error message while parsing.
- found in parse.yacc */
-void yyerror(char *err);
+Action *parse_action(xmlDocPtr doc, xmlNodePtr node);
#endif
+++ /dev/null
-%{
-#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;
-}
+++ /dev/null
-%{
-#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);
-}
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..
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../..
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
#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;
act->data.cycle.cancel = FALSE;
}
+ act->data.any.c = focus_client;
act->func(&act->data);
if (act->func == action_cycle_windows &&
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../..
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
#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;
- }
- } 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;
+ 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
- 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. */
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) &&
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../..
#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;
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;
+ }
+
+ if (hi->flags & HAVE_POSITION) {
+ hi->x = c->frame->area.x;
+ hi->y = c->frame->area.y;
}
- hi->x = c->frame->area.x;
- hi->y = c->frame->area.y;
- hi->placed = FALSE;
+ hi->flags &= ~PLACED;
}
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;
-
- 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);
-
- b = buf;
- if ((c = strchr(b, '\t')) == NULL) break;
- *c = '\0';
- hi->name = g_strdup(b);
-
- b = c + 1;
- if ((c = strchr(b, '\t')) == NULL) break;
- *c = '\0';
- hi->class = g_strdup(b);
-
- 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;
+ xmlDocPtr doc;
+ xmlNodePtr node, n;
+ char *name;
+ char *class;
+ char *role;
+ struct HistoryItem *hi;
- history = g_slist_append(history, hi);
- hi = NULL;
- }
- g_io_channel_unref(io);
+ 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;
}
-
- g_free(buf);
- if (hi != NULL) {
- g_free(hi->name);
- g_free(hi->class);
- g_free(hi->role);
+ 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)) {
+
+ 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;
+ }
+
+ history_list = g_slist_append(history_list, hi);
+ }
+ g_free(name); g_free(class); g_free(role);
+ node = parse_find_node("entry", node->next);
}
- 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);
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);
#ifndef __plugin_placement_history_h
#define __plugin_placement_history_h
-#include "../../kernel/client.h"
+#include "kernel/client.h"
#include <glib.h>
void history_startup();
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)
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()
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)