ECKS EM ELL

This commit is contained in:
Dana Jansens 2003-05-24 15:35:26 +00:00
parent f7df74b9cc
commit d2857b1194
19 changed files with 974 additions and 827 deletions

View file

@ -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
View file

@ -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>

View file

@ -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 .\#*

View file

@ -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()

View file

@ -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();

View file

@ -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;
}

View file

@ -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

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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..

View file

@ -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

View file

@ -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 &&

View file

@ -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

View file

@ -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) &&

View file

@ -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../..

View file

@ -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);

View file

@ -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();

View file

@ -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)

View file

@ -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)