missing
.dirstamp
openbox/openbox
-parser/obparser-3.0.pc
+parser/obparser-4.0.pc
po/Makefile.in.in
po/Makevars.template
po/POTFILES
po/en@quot.insert-header
po/remove-potcdate.sed
*.gmo
-render/obrender-3.0.pc
+obrender/obrender-3.5.pc
+obt/obt-3.5.pc
tools/gnome-panel-control/gnome-panel-control
tools/gdm-control/gdm-control
tools/obxprop/obxprop
tests/iconifydelay
tests/icons
tests/mapiconic
+tests/mingrow
tests/modal
tests/modal2
tests/modal3
tests/noresize
tests/override
+tests/overrideinputonly
tests/positioned
tests/resize
tests/restack
+3.5.0-rc1:
+
+3.4.9:
+ * Allow focus to move while inside an Openbox menu, or during an interactive
+ action such as window cycling.
+ * Fixed bug #3717 (Empty dock interfered with move/grow to edge actions).
+ * Fixed bug #4411 (Crash when switching desktops and window cycling).
+ * Fixed bug #4377 (Window resistance against struts).
+ * Fixed bug #4035 (Prevent focus from moving under the mouse after
+ activating a window with an Openbox menu.
+ * Correct the value provided by the _NET_WORKAREA hint, so desktop icons
+ will place across all monitors.
+ * Don't hide submenus immediately when moving through the parent menu.
+ (Resolves request #3762).
+ * Fix for showing Openbox menus with multiple monitors, don't restrict them
+ to the monitor where the mouse is.
+ * Fixed bug #4023 (Allow the user to have multiple keys which perform the
+ same function in Openbox menus/move/resize. E.g. two keys which are
+ both bound to Escape.
+ * Add a new obprop tool, which can be used to read the _OB_ROLE, _OB_NAME,
+ and _OB_CLASS (as well as any other UTF-8 window properties) off of a
+ window.
+ * Add _OB_ROLE, _OB_NAME, and _OB_CLASS hints on each window that show the
+ respective values for use in the rc.xml applications section, to modify
+ the window when it appears.
+ * Improve Openbox interoperability with gnome-session >= 2.24.
+ * Fixed bug #4040 (Remove desktop hints set by gdm in the openbox-session
+ scripts, so that Openbox can set the number of desktops (assuming
+ gnome-settings-daemon doesn't first)).
+ * Fix a bug in xdg-autostart preventing some .desktop files from working.
+ * Show the desktop pager popup on the primary monitor instead of on all
+ monitors.
+ * Add a new primaryMonitor config option, which is where Openbox popups
+ will appear. Defaults to a fixed monitor, but can be made to behave as
+ before with the "active" value for it.
+ * Correct edge detection for move/grow to edge to properly use monitor edges
+ for multi-monitor setups.
+ * Change default window placement policy to stay on the active monitor for
+ multi-monitor setups.
+ * Fixed bug #1149 (Crash with some window icon sizes).
+ * Respond to all strut changes, fixes moving/hiding panels.
+ * Fix internal code to focus windows on other desktops correctly (Fixes
+ bug #4413).
+ * Focus correctness fixups for switching desktops.
+ * Fixed bug #4373 (Decoration bug for shaded maximized windows).
+ * Fixed bug #4350 (Allow a window to be made skip_taskbar but still get
+ focused by the user's rc.xml).
+ * Fixed bug #4307 (Set a minimum time for screenEdgeWarpTime).
+ * Fixed bug #4253 (Support for Solaris in openbox-session scripts).
+ * Fixed bug #3851 (Allow transient windows to be above helper windows).
+
+3.4.8:
+ * Updated translations: Slovak.
+ * Allow windows to change their decorations at any time (Fix for
+ Google Chrome).
+ * Make openbox-session to respect the $XDG_CONFIG_HOME environment variable.
+ * Fixed bug #4344 where borders were given to windows that should not have
+ them.
+ * Merge the SessionLogout and Exit actions. They now test if connected to a
+ session manager and ask it to exit if so, or simply kill Openbox if not.
+ * Further tweaks to the _NET_ACTIVE_WINDOW message handling. Use the same
+ logic for focus-stealing as is used when mapping a new window.
+ * Don't go out of our way any more to prevent focus from moving while the
+ keyboard is grabbed.
+ * Fix openbox-gnome-session when using gnome-session > 2.22.
+
+3.4.8-rc2:
+ * Updated translations: Italian, Croatian, Ukrainian.
+ * When resizing a window while focus cycling with bar=no, the bar no longer
+ reappears.
+ * Correctly handle shaped windows using the ShapeInput kind, this is used
+ by many composited apps to pass through clicks in their transparent areas.
+ * Fix the <monitor> per-app setting.
+ * Avoid using anonymous unions.
+ * Windows that had their decorations removed by per-app settings were still
+ placed as if they still had their decorations.
+ * Fix event handling not to ignore events on a window when they have an unmap
+ event in the queue, if that unmap event doesn't cause the window to be
+ unmanaged.
+ * Show the desktop switch on every monitor in xinerama.
+ * Fix interpretation of struts in xinerama where the screens have different
+ sizes.
+ * Add "next" and "prev" as possible <monitor> targets in the moveto and
+ resizeto actions.
+ * Allow escaping the _ used to mark the shortcut character in menu labels.
+ You can now change the (first) _ in a label to __, this will be displayed
+ as a single underscore. The rest of the _ in the string will be unaffected,
+ so only double the first one.
+ * Only replace ~ with the home directory when it is preceded by whitespace or
+ is at the start of the string, and when it is followed by a space, slash, or
+ the end of the string. This is implemented with GRegex, and so the required
+ glib version has been bumped to 2.14.
+ * Some other small fixes.
+
+3.4.8-rc1:
+ * Updated translations: Basque, Catalan, Turkish, Italian, Spanish, Russian.
+ * New translations: Danish, Turkish, Lithuanian.
+ * Set the _MOTIF_WM_INFO atom so urxvt uses motif hints for borderless mode.
+ * Properly escape the xml used in session files.
+ * Correct a 64-bit issue related to comparing timestamps.
+ * There is a sneaky sentence right at the end of a big paragraph in the
+ wm-spec document that says windows mapping with _NET_WM_USER_TIME=0 should
+ not be focused initially, honor this request.
+ * When moving a window to another desktop with following on, bring the
+ window's helper windows (for example gimp image windows with the toolbox
+ set to utility window).
+ * Change the _NET_ACTIVE_WINDOW messages again, if they originate from the
+ app and the window is on another desktop, just set the demands_attention
+ flag. If the event came from the user (ie pager/panel), then the window
+ is still moved to the current desktop.
+
+3.4.7.2:
+ * The system I used to generate the dist tarball didn't have the
+ docbook-to-man command so the manpages were empty.
+
+3.4.7.1:
+ * Not to be outdone by the cairo team, I introduced a bug in the last release
+ which made resizing not give any feedback. This is now fixed.
+
+3.4.7:
+ * Fully updated Czech, Simplified Chinese, Traditional Chinese, German,
+ French, Hungarian, Norwegian, Vietnamese, Dutch, Swedish, Finnish,
+ Brazilian Portuguese, Japanese and Portuguese translations
+ * Partially updated Spanish translation
+ * Add an example of the "force" option for the per-app placement options to
+ the default rc.xml file
+ * Add a new xdg-autostart script. This will eventually end up in the PyXDG
+ distribution hopefully, but it is included in Openbox for now. This script
+ runs things based on the freedesktop.org autostart specification. You can
+ have it run GNOME, KDE, ROX, or XFCE specific things if you want. The
+ new default system-wide autostart.sh script runs it automatically
+ * Update the default menu.xml to include a lot of common apps
+ * Fix white font shadows (negative shadowtint)
+ * Update the autostart.sh to find gnome-settings-daemon correctly, as the
+ GNOME people have moved it to libexec
+ * Fix focus possibly getting stolen when using the Focus action
+ * Drastically speed up rendering of Vertical and SplitVertical gradients
+ * Speed improvements also for Horizonal and Pyramid gradients
+ * Add new theme options, menu.overlap.x and menu.overlap.y options, that let
+ you independently control the horizontal and vertical position of submenus
+ * Change _NET_ACTIVE_WINDOW messages to not change the current desktop, but
+ to bring the window to the current desktop instead. This is the industry
+ standard policy
+ * Use the pretty new openbox.png icon as the default window icon
+ * Allow matching per-application rules to windows by their window type
+ (normal, dialog, splash, etc). The default rc.xml has more details
+ * Add new Openbox-themed prompt windows. Use these prompt windows to ask
+ before killing off windows that aren't responding. This also means we
+ don't need to ping every window constantly forever
+ * Add a new <prompt> option to the Execute action. If this is set to a
+ string, a dialog will be shown with that string in it and "yes"/"no"
+ buttons. The command to be executed will only be run if the user selects
+ "yes" in the dialog
+ * Add a new <prompt> option to the Exit action, which is a boolean (not a
+ string). When true, Openbox will show a dialog confirming if you want to
+ exit. The default is to show the prompt
+ * Reduce Openbox's memory footprint and speed up rendering through the use
+ of a new icon cache, so that Openbox only needs to keep 1 copy of an icon
+ when 100 different windows share it
+ * Make Openbox menus have the "menu type" hint for compositors to see and use
+ * Fix the MoveResizeTo action for negative coords (opposite edges)
+ * Fix key bindings getting lost if multiple bindings at the same level could
+ not be translated (Fixes VMWare causing Openbox keybindings to stop
+ working)
+ * Fix the resize popup box for terminal windows with a base size of 0 (show
+ the right size values for urxvt terminals)
+ * Fix some off-by-one bugs with the edge growing/shrinking code
+ * Add new theme options for menu line separators: menu.separator.color,
+ menu.separator.width, menu.separator.padding.width,
+ menu.separator.padding.height
+ * Add xfce-mcs-manager to the default autostart.sh, and run it automatically
+ when gnome-settings-daemon is not present to have GTK apps inherit settings
+ from the XFCE configuration tools
+ * Make the send-to-desktop menu in the client-menu indicate which is the current
+ desktop for omnipresent windows, and don't close it if just toggling
+ omni-presence when ctrl-clicking
+ * Add a new SessionLogout action that logs out through the session manager,
+ when running Openbox within a session manager such as within an
+ GNOME/Openbox or KDE/Openbox session. The action includes a <prompt>
+ option which is similar to the Exit action's
+ * Add a new gdm-control command that lets you control gdm from within an X
+ session. The gdm-control lets you change GDM's behaviour for when you end
+ the current session. For instance, you can tell GDM to reboot, and
+ then immediately log out of the current session, and the computer will be
+ rebooted
+ * Show an information dialog when an error occurs for Openbox, such as when
+ the Execute action fails or when XML syntax errors are present in the
+ configuration files
+ * When making a window very narrow, don't draw buttons to the right of the title
+ on top of the ones on its left.
+
+3.4.6.1:
+ * Updated Clearlooks theme
+ * Add the force="yes/no" option for the per-app settings' <position> tag
+ * Raise and focus modal children and their direct parents together, improved
+ usability with direct modal transient windows
+ * Fix crash when using <raise> for NextWindow and there are no windows
+ to move focus to
+ * Add the <manageDesktops> option in the rc.xml <menu> section, which toggles
+ the "Manage Desktops" section appearing in the combined-client-list-menu
+ * Fix for menu headers showing the wrong text
+ * Fix for the <focusLast> behavior
+ * Treat modal direct children as one window with their parent consistently
+
+3.4.6:
+ * Added Basque translation
+ * Updated French, Vietnamese German, Simplified Chinese, Russian, Portuguese,
+ Brasilian Portuguese, Norwegian, and Finnish translations
+ * New Clearlooks theme, updated by David Barr
+ * Updated the previous Clearlooks theme, and renamed it to Clearlooks-3.4
+ * Allow dialog type windows to go fullscreen (Fixes Kpdf)
+ * Remove the extraneous top border for undecorated windows while maximized
+ * Fixes for keyboard modifiers (Alt-tab dialog getting stuck on screen for
+ some users)
+ * Automatically catch changes to the keyboard map and reconfigure the key
+ bindings on the fly
+ * Fix focus moving incorrectly sometimes with focus under mouse enabled
+ * Make default configuration focus the desktop when you right click
+ * Add the <bar> and <raise> options for all window cycling actions, allowing
+ you to have your target window temporarily raised above all others, and to
+ turn the focus target indicator bar off
+ * Improve the LastDesktop action to not remember desktops you skipped across
+ * Ignore mouse clicks that are made on override-redirect (unmanaged) windows
+ * When opening a menu with a key binding, don't use the key binding to run
+ something in the menu
+ * Add a <monitor> option for window placement, which gives you the option
+ to place new windows on the active monitor, or the monitor where the mouse
+ is, instead of on any monitor (for xinerama multihead setups)
+ * Add options for placing the window move/resize coordinate popup window in
+ a fixed position on screen, rather than relative to the window being
+ moved or resized
+ * Prevent the dock from auto-hiding completely offscreen if the theme has
+ no borders for it
+ * New icon
+ * Fix race condition when running things that want to grab the keyboard
+ (e.g. gnome-panel-control --main-menu)
+ * When dialog windows ask to not appear in the taskbar, still give them focus
+ in normal ways (fixes new GNOME session logout dialogs)
+ * Fix bug with resizing corners on certain parts of the window frame
+ * Ping applications to tell when they are running or have become frozen.
+ Show a [Not Responding] message in the title bar of windows which are
+ frozen.
+ * When closing a window which is [Not Responding], kill the window's process
+ if it is running on the same machine as Openbox. Otherwise, just
+ disconnect
+ the window from the X display. A second attempt to close a [Not
+ Responding]
+ window will kill it forcefully (kill -9).
+ * Fixes for internal timers
+ * Add a <wmclass> option for the execute action's startup-notification. This
+ lets you tell Openbox that the application will map a window with the
+ specified class - for applications that do not support startup-notification
+ natively.
+ * Fix for empty dock taking up space onscreen after a reconfigure
+ * Reduce Openbox's additional memory footprint per-window and per-menu
+ * Faster horizontal gradient rendering
+ * Don't deiconify windows that aren't allowed to be directly iconified on
+ restart (eg toolbars), as they can be iconified by other means
+ * Improve support for fullscreen windows in xinerama (TwinView) and
+ multiple-screen setups
+ * Add a --config-file command line option, to specify an alternate
+ configuration file path
+
+3.4.5:
+ * Added Hungarian translation
+ * Updated Finnish, Russian, German and French translations
+ * Fixed some very minor memory leaks
+ * Hide the desktop popup when showing the focus popup
+ * Fix a crash when trying to access the More... menu of
+ client-list-combined-menu
+ * Fix the coordinate popup only showing up on the first monitor in xinerama
+ * Add --exit to exit the currently running openbox instance
+
3.4.4:
* Updated Traditional Chinese translation
* Updated Norwegian translation
xsessionsdir = $(datadir)/xsessions
gnomewmfilesdir = $(datadir)/gnome/wm-properties
pkgconfigdir = $(libdir)/pkgconfig
-pubincludedir = $(includedir)/openbox/@OB_VERSION@/openbox
+obtpubincludedir= $(includedir)/openbox/@OBT_VERSION@/obt
+rrpubincludedir = $(includedir)/openbox/@RR_VERSION@/obrender
pixmapdir = $(datadir)/pixmaps
xsddir = $(datadir)/openbox
secretbindir = $(libdir)/openbox
INCLUDES = -I.
check_PROGRAMS = \
- render/rendertest
+ obrender/rendertest
lib_LTLIBRARIES = \
- parser/libobparser.la \
- render/libobrender.la
+ obt/libobt.la \
+ obrender/libobrender.la
bin_PROGRAMS = \
openbox/openbox \
data/xsession/openbox-gnome-session \
data/xsession/openbox-kde-session
-## render ##
+## obrender ##
-render_rendertest_CPPFLAGS = \
+obrender_rendertest_CPPFLAGS = \
$(PANGO_CFLAGS) \
- $(XFT_CFLAGS) \
$(GLIB_CFLAGS) \
-DG_LOG_DOMAIN=\"RenderTest\"
-render_rendertest_LDADD = \
- parser/libobparser.la \
- render/libobrender.la \
+obrender_rendertest_LDADD = \
+ obt/libobt.la \
+ obrender/libobrender.la \
$(GLIB_LIBS) \
$(PANGO_LIBS) \
- $(XFT_LIBS) \
$(XML_LIBS) \
$(X_LIBS)
-render_rendertest_SOURCES = render/test.c
+obrender_rendertest_SOURCES = obrender/test.c
-render_libobrender_la_CPPFLAGS = \
+obrender_libobrender_la_CPPFLAGS = \
$(X_CFLAGS) \
$(GLIB_CFLAGS) \
$(XML_CFLAGS) \
$(PANGO_CFLAGS) \
- $(XFT_CFLAGS) \
-DG_LOG_DOMAIN=\"ObRender\" \
-DDEFAULT_THEME=\"$(theme)\"
-render_libobrender_la_LDFLAGS = \
- -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
-render_libobrender_la_LIBADD = \
- parser/libobparser.la \
+obrender_libobrender_la_LDFLAGS = \
+ -version-info $(RR_CURRENT):$(RR_REVISION):$(RR_AGE)
+obrender_libobrender_la_LIBADD = \
+ obt/libobt.la \
$(X_LIBS) \
$(PANGO_LIBS) \
- $(XFT_LIBS) \
$(GLIB_LIBS) \
$(XML_LIBS)
-render_libobrender_la_SOURCES = \
+obrender_libobrender_la_SOURCES = \
gettext.h \
- render/color.h \
- render/color.c \
- render/font.h \
- render/font.c \
- render/geom.h \
- render/gradient.h \
- render/gradient.c \
- render/icon.h \
- render/image.h \
- render/image.c \
- render/imagecache.h \
- render/imagecache.c \
- render/instance.h \
- render/instance.c \
- render/mask.h \
- render/mask.c \
- render/render.h \
- render/render.c \
- render/theme.h \
- render/theme.c
-
-## parser ##
-
-parser_libobparser_la_CPPFLAGS = \
+ obrender/color.h \
+ obrender/color.c \
+ obrender/font.h \
+ obrender/font.c \
+ obrender/geom.h \
+ obrender/gradient.h \
+ obrender/gradient.c \
+ obrender/icon.h \
+ obrender/image.h \
+ obrender/image.c \
+ obrender/imagecache.h \
+ obrender/imagecache.c \
+ obrender/instance.h \
+ obrender/instance.c \
+ obrender/mask.h \
+ obrender/mask.c \
+ obrender/render.h \
+ obrender/render.c \
+ obrender/theme.h \
+ obrender/theme.c
+
+## obt ##
+
+obt_libobt_la_CPPFLAGS = \
+ $(XINERAMA_CFLAGS) \
+ $(XKB_CFLAGS) \
+ $(XRANDR_CFLAGS) \
+ $(XSHAPE_CFLAGS) \
+ $(XSYNC_CFLAGS) \
$(GLIB_CFLAGS) \
$(XML_CFLAGS) \
- -DG_LOG_DOMAIN=\"ObParser\" \
+ -DG_LOG_DOMAIN=\"Obt\" \
-DLOCALEDIR=\"$(localedir)\" \
-DDATADIR=\"$(datadir)\" \
-DCONFIGDIR=\"$(configdir)\"
-parser_libobparser_la_LDFLAGS = \
- -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
-parser_libobparser_la_LIBADD = \
+obt_libobt_la_LDFLAGS = \
+ -version-info $(OBT_CURRENT):$(OBT_REVISION):$(OBT_AGE)
+obt_libobt_la_LIBADD = \
+ $(XINERAMA_LIBS) \
+ $(XKB_LIBS) \
+ $(XRANDR_LIBS) \
+ $(XSHAPE_LIBS) \
+ $(XSYNC_LIBS) \
$(GLIB_LIBS) \
- $(XML_LIBS)
-parser_libobparser_la_SOURCES = \
- parser/parse.h \
- parser/parse.c
+ $(XML_LIBS)
+obt_libobt_la_SOURCES = \
+ obt/display.h \
+ obt/display.c \
+ obt/internal.h \
+ obt/keyboard.h \
+ obt/keyboard.c \
+ obt/mainloop.h \
+ obt/mainloop.c \
+ obt/xml.h \
+ obt/xml.c \
+ obt/paths.h \
+ obt/paths.c \
+ obt/prop.h \
+ obt/prop.c \
+ obt/util.h \
+ obt/xevent.h \
+ obt/xevent.c
## openbox ##
openbox_openbox_CPPFLAGS = \
$(SM_CFLAGS) \
- $(XINERAMA_CFLAGS) \
- $(XKB_CFLAGS) \
- $(XRANDR_CFLAGS) \
- $(XSHAPE_CFLAGS) \
- $(XSYNC_CFLAGS) \
$(X_CFLAGS) \
$(XCURSOR_CFLAGS) \
$(SM_CFLAGS) \
$(GLIB_CFLAGS) \
$(LIBSN_CFLAGS) \
$(XML_CFLAGS) \
+ $(IMLIB2_CFLAGS) \
-DLOCALEDIR=\"$(localedir)\" \
-DDATADIR=\"$(datadir)\" \
-DCONFIGDIR=\"$(configdir)\" \
-DG_LOG_DOMAIN=\"Openbox\"
openbox_openbox_LDADD = \
$(SM_LIBS) \
- $(XINERAMA_LIBS) \
- $(XKB_LIBS) \
- $(XRANDR_LIBS) \
- $(XSHAPE_LIBS) \
- $(XSYNC_LIBS) \
$(GLIB_LIBS) \
$(X_LIBS) \
$(XCURSOR_LIBS) \
$(XML_LIBS) \
$(EFENCE_LIBS) \
$(LIBINTL) \
- render/libobrender.la \
- parser/libobparser.la
+ $(IMLIB2_LIBS) \
+ obrender/libobrender.la \
+ obt/libobt.la
openbox_openbox_LDFLAGS = -export-dynamic
openbox_openbox_SOURCES = \
gettext.h \
openbox/actions/resizerelative.c \
openbox/actions/restart.c \
openbox/actions/shade.c \
+ openbox/actions/shadelowerraise.c \
openbox/actions/showdesktop.c \
openbox/actions/showmenu.c \
openbox/actions/unfocus.c \
openbox/dock.h \
openbox/event.c \
openbox/event.h \
- openbox/extensions.c \
- openbox/extensions.h \
openbox/focus.c \
openbox/focus.h \
openbox/focus_cycle.c \
openbox/keyboard.h \
openbox/keytree.c \
openbox/keytree.h \
- openbox/mainloop.c \
- openbox/mainloop.h \
openbox/menuframe.c \
openbox/menuframe.h \
openbox/menu.c \
openbox/menu.h \
openbox/misc.h \
- openbox/modkeys.c \
- openbox/modkeys.h \
openbox/mouse.c \
openbox/mouse.h \
openbox/moveresize.c \
openbox/prompt.h \
openbox/popup.c \
openbox/popup.h \
- openbox/prop.c \
- openbox/prop.h \
openbox/resist.c \
openbox/resist.h \
openbox/screen.c \
openbox/translate.c \
openbox/translate.h \
openbox/window.c \
- openbox/window.h \
- openbox/xerror.c \
- openbox/xerror.h
+ openbox/window.h
## gnome-panel-control ##
## public headers ##
-pubinclude_HEADERS = \
- render/color.h \
- render/font.h \
- render/geom.h \
- render/gradient.h \
- render/image.h \
- render/instance.h \
- render/mask.h \
- render/render.h \
- render/theme.h \
- parser/parse.h
-
-nodist_pubinclude_HEADERS = \
- version.h
+rrpubinclude_HEADERS = \
+ obrender/color.h \
+ obrender/font.h \
+ obrender/geom.h \
+ obrender/gradient.h \
+ obrender/image.h \
+ obrender/instance.h \
+ obrender/mask.h \
+ obrender/render.h \
+ obrender/theme.h \
+ obrender/version.h
+
+obtpubinclude_HEADERS = \
+ obt/display.h \
+ obt/keyboard.h \
+ obt/mainloop.h \
+ obt/xml.h \
+ obt/paths.h \
+ obt/prop.h \
+ obt/util.h \
+ obt/version.h \
+ obt/xevent.h
nodist_pkgconfig_DATA = \
- render/obrender-3.0.pc \
- parser/obparser-3.0.pc
+ obrender/obrender-3.5.pc \
+ obt/obt-3.5.pc
## data ##
data/xsession/openbox-kde.desktop
dist_noinst_DATA = \
- version.h.in \
data/autostart.sh.in \
data/rc.xsd \
data/menu.xsd \
doc/openbox-kde-session.1.in \
doc/obxprop.1.sgml \
doc/obxprop.1.in \
- render/obrender-3.0.pc.in \
- parser/obparser-3.0.pc.in \
+ obrender/version.h.in \
+ obrender/obrender-3.5.pc.in \
+ obt/obt-3.5.pc.in \
+ obt/version.h.in \
tools/themeupdate/themeupdate.py \
tests/hideshow.py \
tests/Makefile \
# $(MAKE) -$(MAKEFLAGS) -C doc/doxygen doc
distclean-local:
- for d in . m4 po render; do \
+ for d in . m4 po obrender parser obt openbox; do \
for p in core core.* gmon.out *\~ *.orig *.rej .\#*; do \
rm -f "$$d/$$p"; \
done \
A C Compiler (GNU GCC 3.2+ suggested)
GNU Gettext 0.14.4
GNU Autoconf 2.50+
-GNU Automake 1.9+
+GNU Automake 1.9 (no more, no less)
GNU Libtool
Xlib library/headers (devel package)
Pkg-Config
AC_PREREQ([2.54])
-AC_INIT([openbox], [3.999.0], [http://bugzilla.icculus.org])
+AC_INIT([openbox], [3.5.0-rc1], [http://bugzilla.icculus.org])
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([openbox/openbox.c])
+OB_VERSION=$PACKAGE_VERSION
+AC_SUBST(OB_VERSION)
+
dnl Making releases:
-dnl OB_MICRO_VERSION += 1;
-dnl OB_INTERFACE_AGE += 1;
-dnl OB_BINARY_AGE += 1;
-dnl if any functions have been added, set OB_INTERFACE_AGE to 0.
+dnl RR_MICRO_VERSION += 1;
+dnl RR_INTERFACE_AGE += 1;
+dnl R_BINARY_AGE += 1;
+dnl if any functions have been added, set RR_INTERFACE_AGE to 0.
dnl if backwards compatibility has been broken,
-dnl set OB_BINARY_AGE and OB_INTERFACE_AGE to 0.
+dnl set RR_BINARY_AGE and RR_INTERFACE_AGE to 0.
dnl
dnl if MAJOR or MINOR version changes, be sure to change AC_INIT above to match
dnl
-OB_MAJOR_VERSION=3
-OB_MINOR_VERSION=4
-OB_MICRO_VERSION=16
-OB_INTERFACE_AGE=0
-OB_BINARY_AGE=0
-OB_VERSION=$PACKAGE_VERSION
-
-AC_SUBST(OB_MAJOR_VERSION)
-AC_SUBST(OB_MINOR_VERSION)
-AC_SUBST(OB_MICRO_VERSION)
-AC_SUBST(OB_INTERFACE_AGE)
-AC_SUBST(OB_BINARY_AGE)
-AC_SUBST(OB_VERSION)
+RR_MAJOR_VERSION=3
+RR_MINOR_VERSION=5
+RR_MICRO_VERSION=27
+RR_INTERFACE_AGE=0
+RR_BINARY_AGE=0
+RR_VERSION=$RR_MAJOR_VERSION.$RR_MINOR_VERSION
+
+OBT_MAJOR_VERSION=3
+OBT_MINOR_VERSION=5
+OBT_MICRO_VERSION=0
+OBT_INTERFACE_AGE=0
+OBT_BINARY_AGE=0
+OBT_VERSION=$OBT_MAJOR_VERSION.$OBT_MINOR_VERSION
+
+AC_SUBST(RR_MAJOR_VERSION)
+AC_SUBST(RR_MINOR_VERSION)
+AC_SUBST(RR_MICRO_VERSION)
+AC_SUBST(RR_INTERFACE_AGE)
+AC_SUBST(RR_BINARY_AGE)
+AC_SUBST(RR_VERSION)
+AC_SUBST(OBT_MAJOR_VERSION)
+AC_SUBST(OBT_MINOR_VERSION)
+AC_SUBST(OBT_MICRO_VERSION)
+AC_SUBST(OBT_INTERFACE_AGE)
+AC_SUBST(OBT_BINARY_AGE)
+AC_SUBST(OBT_VERSION)
dnl Libtool versioning
-LT_RELEASE=$OB_MAJOR_VERSION.$OB_MINOR_VERSION
-LT_CURRENT=`expr $OB_MICRO_VERSION - $OB_INTERFACE_AGE`
-LT_REVISION=$OB_INTERFACE_AGE
-LT_AGE=`expr $OB_BINARY_AGE - $OB_INTERFACE_AGE`
-LT_CURRENT_MINUS_AGE=`expr $LT_CURRENT - $LT_AGE`
-
-AC_SUBST(LT_RELEASE)
-AC_SUBST(LT_CURRENT)
-AC_SUBST(LT_REVISION)
-AC_SUBST(LT_AGE)
-AC_SUBST(LT_CURRENT_MINUS_AGE)
+RR_RELEASE=$RR_MAJOR_VERSION.$RR_MINOR_VERSION
+RR_CURRENT=`expr $RR_MICRO_VERSION - $RR_INTERFACE_AGE`
+RR_REVISION=$RR_INTERFACE_AGE
+RR_AGE=`expr $RR_BINARY_AGE - $RR_INTERFACE_AGE`
+RR_CURRENT_MINUS_AGE=`expr $RR_CURRENT - $RR_AGE`
+
+OBT_RELEASE=$OBT_MAJOR_VERSION.$OBT_MINOR_VERSION
+OBT_CURRENT=`expr $OBT_MICRO_VERSION - $OBT_INTERFACE_AGE`
+OBT_REVISION=$OBT_INTERFACE_AGE
+OBT_AGE=`expr $OBT_BINARY_AGE - $OBT_INTERFACE_AGE`
+OBT_CURRENT_MINUS_AGE=`expr $OBT_CURRENT - $OBT_AGE`
+
+AC_SUBST(RR_RELEASE)
+AC_SUBST(RR_CURRENT)
+AC_SUBST(RR_REVISION)
+AC_SUBST(RR_AGE)
+AC_SUBST(RR_CURRENT_MINUS_AGE)
+AC_SUBST(OBT_RELEASE)
+AC_SUBST(OBT_CURRENT)
+AC_SUBST(OBT_REVISION)
+AC_SUBST(OBT_AGE)
+AC_SUBST(OBT_CURRENT_MINUS_AGE)
AC_PREFIX_DEFAULT([/usr/local])
test "$prefix" = "NONE" && prefix=$ac_default_prefix
AM_GNU_GETTEXT([external])
AC_CHECK_HEADERS(ctype.h fcntl.h locale.h signal.h string.h stdio.h stdlib.h)
-AC_CHECK_HEADERS(unistd.h sys/stat.h sys/select.h sys/time.h sys/wait.h)
+AC_CHECK_HEADERS(unistd.h sys/stat.h sys/select.h sys/socket.h sys/time.h)
+AC_CHECK_HEADERS(sys/wait.h)
# AC_HEADER_TIME
# AC_TYPE_SIGNAL
AC_SUBST(PANGO_CFLAGS)
AC_SUBST(PANGO_LIBS)
-PKG_CHECK_MODULES(XFT, [xft])
-AC_SUBST(XFT_CFLAGS)
-AC_SUBST(XFT_LIBS)
-
PKG_CHECK_MODULES(XML, [libxml-2.0 >= 2.6.0])
AC_SUBST(XML_CFLAGS)
AC_SUBST(XML_LIBS)
xcursor_found=no
fi
+AC_ARG_ENABLE(imlib2,
+ AC_HELP_STRING(
+ [--disable-imlib2],
+ [disable use of Imlib2 image library for loading icons. [[default=enabled]]]
+ ),
+ [enable_imlib2=$enableeval],
+ [enable_imlib2=yes]
+)
+
+if test "$enable_imlib2" = yes; then
+PKG_CHECK_MODULES(IMLIB2, [imlib2],
+ [
+ AC_DEFINE(USE_IMLIB2, [1], [Use Imlib2 image library])
+ AC_SUBST(IMLIB2_CFLAGS)
+ AC_SUBST(IMLIB2_LIBS)
+ imlib2_found=yes
+ ],
+ [
+ imlib2_found=no
+ ]
+)
+else
+ imlib2_found=no
+fi
+
+AM_CONDITIONAL(USE_IMLIB2, [test $imlib2_found = yes])
+
dnl Check for session management
X11_SM
Makefile
m4/Makefile
po/Makefile.in
- render/obrender-3.0.pc
- parser/obparser-3.0.pc
+ obrender/obrender-3.5.pc
+ obt/obt-3.5.pc
+ obrender/version.h
+ obt/version.h
version.h
])
AC_CONFIG_COMMANDS([doc],
Startup Notification... $sn_found
X Cursor Library... $xcursor_found
Session Management... $SM
+ Imlib2 library... $imlib2_found
])
AC_MSG_RESULT([configure complete, now type "make"])
<slant>normal</slant>
<!-- 'italic' or 'normal' -->
</font>
- <font place="OnScreenDisplay">
+ <font place="ActiveOnScreenDisplay">
+ <name>sans</name>
+ <size>9</size>
+ <!-- font size in points -->
+ <weight>bold</weight>
+ <!-- 'bold' or 'normal' -->
+ <slant>normal</slant>
+ <!-- 'italic' or 'normal' -->
+ </font>
+ <font place="InactiveOnScreenDisplay">
<name>sans</name>
<size>9</size>
<!-- font size in points -->
</action>
</keybind>
+ <!-- Keybindings for window switching with the arrow keys -->
+ <keybind key="W-S-Right">
+ <action name="DirectionalCycleWindows">
+ <direction>right</direction>
+ </action>
+ </keybind>
+ <keybind key="W-S-Left">
+ <action name="DirectionalCycleWindows">
+ <direction>left</direction>
+ </action>
+ </keybind>
+ <keybind key="W-S-Up">
+ <action name="DirectionalCycleWindows">
+ <direction>up</direction>
+ </action>
+ </keybind>
+ <keybind key="W-S-Down">
+ <action name="DirectionalCycleWindows">
+ <direction>down</direction>
+ </action>
+ </keybind>
+
<!-- Keybindings for running applications -->
<keybind key="W-e">
<action name="Execute">
</mousebind>
<mousebind button="Up" action="Click">
- <action name="Shade"/>
- <action name="FocusToBottom"/>
- <action name="Unfocus"/>
- <action name="Lower"/>
+ <action name="if">
+ <shaded>no</shaded>
+ <then>
+ <action name="Shade"/>
+ <action name="FocusToBottom"/>
+ <action name="Unfocus"/>
+ <action name="Lower"/>
+ </then>
+ </action>
</mousebind>
<mousebind button="Down" action="Click">
- <action name="Unshade"/>
- <action name="Raise"/>
+ <action name="if">
+ <shaded>yes</shaded>
+ <then>
+ <action name="Unshade"/>
+ <action name="Raise"/>
+ </then>
+ </action>
</mousebind>
<mousebind button="Right" action="Press">
</context>
<context name="Desktop">
- <mousebind button="Up" action="Press">
+ <mousebind button="Up" action="Click">
<action name="GoToDesktop"><to>previous</to></action>
</mousebind>
- <mousebind button="Down" action="Press">
+ <mousebind button="Down" action="Click">
<action name="GoToDesktop"><to>next</to></action>
</mousebind>
- <mousebind button="A-Up" action="Press">
+ <mousebind button="A-Up" action="Click">
<action name="GoToDesktop"><to>previous</to></action>
</mousebind>
- <mousebind button="A-Down" action="Press">
+ <mousebind button="A-Down" action="Click">
<action name="GoToDesktop"><to>next</to></action>
</mousebind>
- <mousebind button="C-A-Up" action="Press">
+ <mousebind button="C-A-Up" action="Click">
<action name="GoToDesktop"><to>previous</to></action>
</mousebind>
- <mousebind button="C-A-Down" action="Press">
+ <mousebind button="C-A-Down" action="Click">
<action name="GoToDesktop"><to>next</to></action>
</mousebind>
</context>
<context name="MoveResize">
- <mousebind button="Up" action="Press">
+ <mousebind button="Up" action="Click">
<action name="GoToDesktop"><to>previous</to></action>
</mousebind>
- <mousebind button="Down" action="Press">
+ <mousebind button="Down" action="Click">
<action name="GoToDesktop"><to>next</to></action>
</mousebind>
- <mousebind button="A-Up" action="Press">
+ <mousebind button="A-Up" action="Click">
<action name="GoToDesktop"><to>previous</to></action>
</mousebind>
- <mousebind button="A-Down" action="Press">
+ <mousebind button="A-Down" action="Click">
<action name="GoToDesktop"><to>next</to></action>
</mousebind>
</context>
<!--
# this is an example with comments through out. use these to make your
# own rules, but without the comments of course.
+ # you may use one or more of the name/class/role/type rules to specify
+ # windows to match
<application name="the window's _OB_APP_NAME property (see obxprop)"
class="the window's _OB_APP_CLASS property (see obxprop)"
<xsd:element minOccurs="0" name="underMouse" type="ob:bool"/>
<xsd:element minOccurs="0" name="focusDelay" type="xsd:integer"/>
<xsd:element minOccurs="0" name="raiseOnFocus" type="ob:bool"/>
+ <xsd:element minOccurs="0" name="unfocusOnLeave" type="ob:bool"/>
</xsd:all>
</xsd:complexType>
<xsd:complexType name="placement">
<xsd:element minOccurs="0" name="hideDelay" type="xsd:integer"/>
<xsd:element minOccurs="0" name="middle" type="ob:bool"/>
<xsd:element minOccurs="0" name="submenuShowDelay" type="xsd:integer"/>
- <xsd:element minOccurs="0" name="applicationIcons" type="ob:bool"/>
+ <xsd:element minOccurs="0" name="showIcons" type="ob:bool"/>
<xsd:element minOccurs="0" name="manageDesktops" type="ob:bool"/>
</xsd:sequence>
</xsd:complexType>
exit
fi
+# Set the prefix for the menu layout to use
+export XDG_MENU_PREFIX="kde-"
+
# Clean up after GDM
xprop -root -remove _NET_NUMBER_OF_DESKTOPS \
-remove _NET_DESKTOP_NAMES \
if test "$GCC" = "yes"; then
AC_MSG_RESULT([yes])
if test "$DEBUG" = "yes"; then
- FLAGS="$FLAGS -O0 -g3 -fno-inline -Wwrite-strings"
+ FLAGS="$FLAGS -O0 -ggdb -fno-inline -Wwrite-strings"
FLAGS="$FLAGS -Wall -Wsign-compare -Waggregate-return"
FLAGS="$FLAGS -Wcast-qual -Wbad-function-cast -Wpointer-arith"
# for Python.h
CPPFLAGS=$OLDCPPFLAGS
])
-
-AC_DEFUN([XFT_ERROR],
-[
- if test "$XFT_MIN"; then
- AC_MSG_ERROR([$PACKAGE requires the Xft font library >= $XFT_MIN.
- See http://www.fontconfig.org/
-])
- else
- AC_MSG_ERROR([$PACKAGE requires the Xft font library.
- See http://www.fontconfig.org/
-])
- fi
-])
-
-# XFT_DEVEL([required-version])
-#
-# Check for the XFT development package.
-# You can use the optional argument to check for a library of at least the
-# given version.
-# It provides the $(PYTHON_CFLAGS) $(PYTHON_LIBS) output variables.
-AC_DEFUN([XFT_DEVEL],
-[
- AC_REQUIRE([X11_DEVEL])
-
- if test "$1"; then
- XFT_MIN="$1"
- XFT_MIN_MAJOR=${XFT_MIN%.*.*}
- XFT_MIN_MINOR=${XFT_MIN%.*}
- XFT_MIN_MINOR=${XFT_MIN_MINOR#*.}
- XFT_MIN_REVISION=${XFT_MIN#*.*.}
- XFT_MIN="$XFT_MIN_MAJOR.$XFT_MIN_MINOR.$XFT_MIN_REVISION"
- else
- XFT_MIN=""
- fi
-
- if test -z "$XFT_MIN"; then
- AC_MSG_CHECKING([for Xft])
- if ! pkg-config xft; then
- AC_MSG_RESULT([no])
- XFT_ERROR
- fi
- else
- AC_MSG_CHECKING([for Xft version >= $XFT_MIN])
- if ! pkg-config --atleast-version $XFT_MIN xft; then
- AC_MSG_RESULT([no])
- XFT_ERROR
- fi
- fi
- AC_MSG_RESULT([yes])
-
-
- # Store these
- OLDLIBS=$LIBS
- OLDCPPFLAGS=$CPPFLAGS
-
- XFT_CFLAGS="`pkg-config --cflags xft`"
- XFT_LIBS="`pkg-config --libs xft`"
-
- # Set these for checking with the tests below. They'll be restored after
- LIBS="$LIBS $XFT_LIBS"
- CPPFLAGS="$XFT_CFLAGS $CPPFLAGS"
-
- AC_CHECK_LIB([Xft], [XftGetVersion], # this was not defined in < 2.0
- if test "$XFT_MIN"; then
- AC_MSG_CHECKING([for X11/Xft/Xft.h for Xft >= $XFT_MIN])
- AC_TRY_COMPILE(
- [
- #include <X11/Xlib.h>
- #include <X11/Xft/Xft.h>
- ],
- [
- #if !defined(XFT_MAJOR)
- # error Xft.h is too old
- #endif
- #if XFT_MAJOR < $XFT_MIN_MAJOR
- # error Xft.h is too old
- #endif
- #if XFT_MAJOR == $XFT_MIN_MAJOR
- # if XFT_MINOR < $XFT_MIN_MINOR
- # error Xft.h is too old
- # endif
- #endif
- #if XFT_MAJOR == $XFT_MIN_MAJOR
- # if XFT_MAJOR == $XFT_MIN_MINOR
- # if XFT_REVISION < $XFT_MIN_REVISION
- # error Xft.h is too old
- # endif
- # endif
- #endif
-
- int i = XFT_MAJOR;
- XftFont foo;
- ],
- [
- AC_MSG_RESULT([yes])
- ],
- [
- AC_MSG_RESULT([no])
- XFT_ERROR
- ])
- else
- AC_MSG_CHECKING([for X11/Xft/Xft.h])
- AC_TRY_COMPILE(
- [
- #include <X11/Xlib.h>
- #include <X11/Xft/Xft.h>
- ],
- [
- int i = XFT_MAJOR; /* make sure were using Xft 2, not 1 */
- XftFont foo;
- ],
- [
- AC_MSG_RESULT([yes])
- ],
- [
- AC_MSG_RESULT([no])
- XFT_ERROR
- ])
- fi
-
- AC_MSG_CHECKING([if we can compile with Xft])
- AC_TRY_LINK(
- [
- #include <X11/Xlib.h>
- #include <X11/Xft/Xft.h>
- ],
- [
- int i = XFT_MAJOR;
- XftFont foo
- ],
- [
- AC_MSG_RESULT([yes])
- ],
- [
- AC_MSG_RESULT([no])
- AC_MSG_ERROR([Unable to compile with the Xft font library.
-])
- ])
- )
-
- # Restore the old values. Use XFT_CFLAGS and XFT_LIBS in the Makefiles
- LIBS=$OLDLIBS
- CPPFLAGS=$OLDCPPFLAGS
-
- AC_SUBST([XFT_CFLAGS])
- AC_SUBST([XFT_LIBS])
-])
-
-
# X11_EXT_XKB()
#
# Check for the presence of the "Xkb" X Window System extension.
}
} else im->data = (gchar*) data;
break;
+ case 24:
+ {
+ /* reverse the ordering, shifting left 16bit should be the first byte
+ out of three, etc */
+ const guint roff = (16 - RrRedOffset(inst)) / 8;
+ const guint goff = (16 - RrGreenOffset(inst)) / 8;
+ const guint boff = (16 - RrBlueOffset(inst)) / 8;
+ gint outx;
+ for (y = 0; y < im->height; y++) {
+ for (x = 0, outx = 0; x < im->width; x++, outx += 3) {
+ r = (data[x] >> RrDefaultRedOffset) & 0xFF;
+ g = (data[x] >> RrDefaultGreenOffset) & 0xFF;
+ b = (data[x] >> RrDefaultBlueOffset) & 0xFF;
+ p8[outx+roff] = r;
+ p8[outx+goff] = g;
+ p8[outx+boff] = b;
+ }
+ data += im->width;
+ p8 += im->bytes_per_line;
+ }
+ break;
+ }
case 16:
for (y = 0; y < im->height; y++) {
for (x = 0; x < im->width; x++) {
}
break;
default:
- g_error("Your bit depth is currently unhandled\n");
+ g_error("This image bit depth (%i) is currently unhandled", im->bits_per_pixel);
}
}
void RrFontDraw(XftDraw *d, RrTextureText *t, RrRect *area)
{
- gint x,y,w,h;
+ gint x,y,w;
XftColor c;
gint mw;
PangoRectangle rect;
w = area->width;
if (t->flow) w = MAX(w, t->maxwidth);
w -= 4;
- h = area->height;
+ /* h = area->height; */
if (t->flow)
ell = PANGO_ELLIPSIZE_NONE;
case RR_ELLIPSIZE_END:
ell = PANGO_ELLIPSIZE_END;
break;
+ default:
+ g_assert_not_reached();
}
}
#include "image.h"
#include "color.h"
#include "imagecache.h"
+#ifdef USE_IMLIB2
+#include <Imlib2.h>
+#endif
#include <glib.h>
#define FLOOR(i) ((i) & (~0UL << FRACTION))
#define AVERAGE(a, b) (((((a) ^ (b)) & 0xfefefefeL) >> 1) + ((a) & (b)))
-void RrImagePicInit(RrImagePic *pic, gint w, gint h, RrPixel32 *data)
+void RrImagePicInit(RrImagePic *pic, const gchar *name,
+ gint w, gint h, RrPixel32 *data)
{
gint i;
pic->sum = 0;
for (i = w*h; i > 0; --i)
pic->sum += *(data++);
+ pic->name = g_strdup(name);
}
static void RrImagePicFree(RrImagePic *pic)
{
if (pic) {
g_free(pic->data);
+ g_free(pic->name);
g_free(pic);
}
}
g_assert(pic->width > 0 && pic->height > 0);
- g_assert(g_hash_table_lookup(self->cache->table, pic) == NULL);
+ if (pic->name)
+ g_assert(!g_hash_table_lookup(self->cache->name_table, pic->name));
+ else
+ g_assert(!g_hash_table_lookup(self->cache->pic_table, pic));
/* grow the list */
*list = g_renew(RrImagePic*, *list, ++*len);
/* set the new picture up at the front of the list */
(*list)[0] = pic;
- /* add the picture as a key to point to this image in the cache */
- g_hash_table_insert(self->cache->table, (*list)[0], self);
+ /* add the name or the picture as a key to point to this image in the
+ cache */
+ if (pic->name)
+ g_hash_table_insert(self->cache->name_table, pic->name, self);
+ else
+ g_hash_table_insert(self->cache->pic_table, (*list)[0], self);
/*
#ifdef DEBUG
- g_message("Adding %s picture to the cache:\n "
- "Image 0x%x, w %d h %d Hash %u",
- (*list == self->original ? "ORIGINAL" : "RESIZED"),
- (guint)self, pic->width, pic->height, RrImagePicHash(pic));
+ g_debug("Adding %s picture to the cache:\n "
+ "Image 0x%lx, w %d h %d Hash %u",
+ (*list == self->original ? "ORIGINAL" : "RESIZED"),
+ (gulong)self, pic->width, pic->height, RrImagePicHash(pic));
#endif
*/
}
/*
#ifdef DEBUG
- g_message("Removing %s picture from the cache:\n "
- "Image 0x%x, w %d h %d Hash %u",
- (*list == self->original ? "ORIGINAL" : "RESIZED"),
- (guint)self, (*list)[i]->width, (*list)[i]->height,
- RrImagePicHash((*list)[i]));
+ g_debug("Removing %s picture from the cache:\n "
+ "Image 0x%lx, w %d h %d Hash %u",
+ (*list == self->original ? "ORIGINAL" : "RESIZED"),
+ (gulong)self, (*list)[i]->width, (*list)[i]->height,
+ RrImagePicHash((*list)[i]));
#endif
*/
- /* remove the picture as a key in the cache */
- g_hash_table_remove(self->cache->table, (*list)[i]);
+ /* remove the name or picture as a key in the cache */
+ if ((*list)[i]->name)
+ g_hash_table_remove(self->cache->name_table, (*list)[i]->name);
+ else
+ g_hash_table_remove(self->cache->pic_table, (*list)[i]);
/* free the picture */
RrImagePicFree((*list)[i]);
}
pic = g_new(RrImagePic, 1);
- RrImagePicInit(pic, dstW, dstH, dststart);
+ RrImagePicInit(pic, NULL, dstW, dstH, dststart);
return pic;
}
return self;
}
+/*! Set function that will be called just before RrImage is destroyed. */
+void RrImageSetDestroyFunc(RrImage *image, RrImageDestroyFunc func,
+ gpointer data)
+{
+ image->destroy_func = func;
+ image->destroy_data = data;
+}
+
void RrImageRef(RrImage *self)
{
++self->ref;
if (self && --self->ref == 0) {
/*
#ifdef DEBUG
- g_message("Refcount to 0, removing ALL pictures from the cache:\n "
- "Image 0x%x", (guint)self);
+ g_debug("Refcount to 0, removing ALL pictures from the cache:\n "
+ "Image 0x%lx", (gulong)self);
#endif
*/
+ if (self->destroy_func)
+ self->destroy_func(self, self->destroy_data);
while (self->n_original > 0)
RemovePicture(self, &self->original, 0, &self->n_original);
while (self->n_resized > 0)
}
}
-/*! Add a new picture with the given RGBA pixel data and dimensions into the
- RrImage. This adds an "original" picture to the image.
-*/
-void RrImageAddPicture(RrImage *self, RrPixel32 *data, gint w, gint h)
+static void AddPictureFromData(RrImage *self, const char *name,
+ const RrPixel32 *data, gint w, gint h)
{
gint i;
RrImagePic *pic;
if (self->original[i]->width == w && self->original[i]->height == h) {
/*
#ifdef DEBUG
- g_message("Found duplicate ORIGINAL image:\n "
- "Image 0x%x, w %d h %d", (guint)self, w, h);
+ g_debug("Found duplicate ORIGINAL image:\n "
+ "Image 0x%lx, w %d h %d", (gulong)self, w, h);
#endif
*/
return;
/* add the new picture */
pic = g_new(RrImagePic, 1);
- RrImagePicInit(pic, w, h, g_memdup(data, w*h*sizeof(RrPixel32)));
+ RrImagePicInit(pic, name, w, h, g_memdup(data, w*h*sizeof(RrPixel32)));
AddPicture(self, &self->original, &self->n_original, pic);
}
+gboolean RrImageAddPictureName(RrImage *self, const gchar *name)
+{
+#ifdef USE_IMLIB2
+ Imlib_Image img;
+ gint w, h;
+ RrPixel32 *data;
+ gchar *path;
+
+ /* XXX find the path via freedesktop icon spec (use obt) ! */
+ path = g_strdup(name);
+
+ if (!(img = imlib_load_image(path)))
+ g_message("Cannot load image \"%s\" from file \"%s\"", name, path);
+ g_free(path);
+
+ if (!img)
+ return FALSE; /* failed to load it */
+
+ /* Get data and dimensions of the image.
+
+ WARNING: This stuff is NOT threadsafe !!
+ */
+ imlib_context_set_image(img);
+ data = imlib_image_get_data_for_reading_only();
+ w = imlib_image_get_width();
+ h = imlib_image_get_height();
+
+ /* add it to the RrImage, and set its name */
+ AddPictureFromData(self, name, data, w, h);
+
+ imlib_free_image();
+ return TRUE;
+#else
+ return FALSE;
+#endif
+}
+
+/*! Add a new picture with the given RGBA pixel data and dimensions into the
+ RrImage. This adds an "original" picture to the image.
+*/
+void RrImageAddPicture(RrImage *self, const RrPixel32 *data, gint w, gint h)
+{
+ AddPictureFromData(self, NULL, data, w, h);
+}
+
/*! Remove the picture from the RrImage which has the given dimensions. This
removes an "original" picture from the image.
*/
#include "geom.h"
/*! Initialize an RrImagePicture to the specified dimensions and pixel data */
-void RrImagePicInit(RrImagePic *pic, gint w, gint h, RrPixel32 *data);
+void RrImagePicInit(RrImagePic *pic, const gchar *path,
+ gint w, gint h, RrPixel32 *data);
void RrImageDrawImage(RrPixel32 *target, RrTextureImage *img,
gint target_w, gint target_h,
self = g_new(RrImageCache, 1);
self->ref = 1;
self->max_resized_saved = max_resized_saved;
- self->table = g_hash_table_new((GHashFunc)RrImagePicHash,
- (GEqualFunc)RrImagePicEqual);
+ self->pic_table = g_hash_table_new((GHashFunc)RrImagePicHash,
+ (GEqualFunc)RrImagePicEqual);
+ self->name_table = g_hash_table_new(g_str_hash, g_str_equal);
return self;
}
void RrImageCacheUnref(RrImageCache *self)
{
if (self && --self->ref == 0) {
- g_assert(g_hash_table_size(self->table) == 0);
- g_hash_table_unref(self->table);
+ g_assert(g_hash_table_size(self->pic_table) == 0);
+ g_hash_table_unref(self->pic_table);
+ self->pic_table = NULL;
+
+ g_assert(g_hash_table_size(self->name_table) == 0);
+ g_hash_table_destroy(self->name_table);
+ self->name_table = NULL;
g_free(self);
}
}
+RrImage* RrImageCacheFindName(RrImageCache *self, const gchar *name)
+{
+ return g_hash_table_lookup(self->name_table, name);
+}
+
/*! Finds an image in the cache, if it is already in there */
RrImage* RrImageCacheFind(RrImageCache *self,
RrPixel32 *data, gint w, gint h)
{
RrImagePic pic;
- RrImagePicInit(&pic, w, h, data);
- return g_hash_table_lookup(self->table, &pic);
+ RrImagePicInit(&pic, NULL, w, h, data);
+ return g_hash_table_lookup(self->pic_table, &pic);
}
#define hashsize(n) ((RrPixel32)1<<(n))
*/
gint max_resized_saved;
- GHashTable *table;
+ /*! A hash table of images in the cache that don't have a file name
+ attached to them, with their key being a hash of the contents of the
+ image. */
+ GHashTable *pic_table;
+
+ /*! Used to find out if an image file has already been loaded.
+ Provides a quick file_name -> RrImage lookup. */
+ GHashTable *name_table;
};
#endif
Name: ObRender
Description: Openbox Render Library
-Version: @VERSION@
-Requires: obparser-3.0 glib-2.0 xft pangoxft
+Version: @RR_VERSION@
+Requires: obt-3.5 glib-2.0 xft pangoxft
Libs: -L${libdir} -lobrender ${xlibs}
-Cflags: -I${includedir}/openbox/@OB_VERSION@ ${xcflags}
+Cflags: -I${includedir}/openbox/@RR_VERSION@ ${xcflags}
#ifndef __render_h
#define __render_h
-#include "geom.h"
-#include "version.h"
-
#include <X11/Xlib.h> /* some platforms dont include this as needed for Xft */
#include <pango/pangoxft.h>
#include <glib.h>
G_BEGIN_DECLS
+#include "obrender/geom.h"
+#include "obrender/version.h"
+
typedef union _RrTextureData RrTextureData;
typedef struct _RrAppearance RrAppearance;
typedef struct _RrSurface RrSurface;
/* The sum of all the pixels. This is used to compare pictures if their
hashes match. */
gint sum;
+ /* The name of the image. This is used to determine
+ if the named image already is loaded. May be NULL if the image
+ was not loaded from disk. */
+ gchar *name;
};
+typedef void (*RrImageDestroyFunc)(RrImage *image, gpointer data);
+
/*! An RrImage is a sort of meta-image. It can contain multiple versions of
an image at different sizes, which may or may not be completely different
pictures */
RrImage. */
RrImagePic **resized;
gint n_resized;
+
+ /* This function (if not NULL) will be called just before destroying
+ RrImage. */
+ RrImageDestroyFunc destroy_func;
+ gpointer destroy_data;
};
/* these are the same on all endian machines because it seems to be dependant
/*! Finds an image in the cache, if it is already in there */
RrImage* RrImageCacheFind(RrImageCache *self,
RrPixel32 *data, gint w, gint h);
+/*! Finds an image in the cache, by searching for the name of the image */
+RrImage* RrImageCacheFindName(RrImageCache *self,
+ const gchar *name);
RrImage* RrImageNew(RrImageCache *cache);
void RrImageRef(RrImage *im);
void RrImageUnref(RrImage *im);
-void RrImageAddPicture(RrImage *im, RrPixel32 *data, gint w, gint h);
+void RrImageAddPicture(RrImage *im, const RrPixel32 *data, gint w, gint h);
+/*! Adds a picture by name, from a file on disk.
+ @name Can be a full path to an image, or it can be a name as per the
+ freedesktop.org icon spec. */
+gboolean RrImageAddPictureName(RrImage *im, const gchar *name);
void RrImageRemovePicture(RrImage *im, gint w, gint h);
G_END_DECLS
#include "mask.h"
#include "theme.h"
#include "icon.h"
-#include "parser/parse.h"
+#include "obt/paths.h"
#include <X11/Xlib.h>
#include <X11/Xresource.h>
gboolean allow_fallback,
RrFont *active_window_font, RrFont *inactive_window_font,
RrFont *menu_title_font, RrFont *menu_item_font,
- RrFont *osd_font)
+ RrFont *active_osd_font, RrFont *inactive_osd_font)
{
XrmDatabase db = NULL;
RrJustify winjust, mtitlejust;
theme->a_menu_bullet_selected = RrAppearanceNew(inst, 1);
theme->a_clear = RrAppearanceNew(inst, 0);
theme->a_clear_tex = RrAppearanceNew(inst, 1);
- theme->osd_hilite_bg = RrAppearanceNew(inst, 0);
+ theme->osd_bg = RrAppearanceNew(inst, 0);
theme->osd_hilite_label = RrAppearanceNew(inst, 1);
- theme->osd_hilite_fg = RrAppearanceNew(inst, 0);
- theme->osd_unhilite_fg = RrAppearanceNew(inst, 0);
+ theme->osd_hilite_bg = RrAppearanceNew(inst, 0);
+ theme->osd_unhilite_label = RrAppearanceNew(inst, 1);
+ theme->osd_unhilite_bg = RrAppearanceNew(inst, 0);
/* load the font stuff */
theme->win_font_focused = get_font(active_window_font,
theme->menu_font = get_font(menu_item_font, &default_font, inst);
- theme->osd_font = get_font(osd_font, &default_font, inst);
+ theme->osd_font_hilite = get_font(active_osd_font, &default_font, inst);
+ theme->osd_font_unhilite = get_font(inactive_osd_font, &default_font,inst);
/* load direct dimensions */
if ((!read_int(db, "menu.overlap.x", &theme->menu_overlap_x) &&
"window.active.label.text.color",
&theme->title_focused_color))
theme->title_focused_color = RrColorNew(inst, 0x0, 0x0, 0x0);
- if (!read_color(db, inst, "osd.label.text.color", &theme->osd_color))
- theme->osd_color = RrColorNew(inst,
- theme->title_focused_color->r,
- theme->title_focused_color->g,
- theme->title_focused_color->b);
+ if (!read_color(db, inst, "osd.active.label.text.color",
+ &theme->osd_text_active_color) &&
+ !read_color(db, inst, "osd.label.text.color",
+ &theme->osd_text_active_color))
+ theme->osd_text_active_color =
+ RrColorNew(inst,
+ theme->title_focused_color->r,
+ theme->title_focused_color->g,
+ theme->title_focused_color->b);
if (!read_color(db, inst,
"window.inactive.label.text.color",
&theme->title_unfocused_color))
theme->title_unfocused_color = RrColorNew(inst, 0xff, 0xff, 0xff);
+ if (!read_color(db, inst, "osd.inactive.label.text.color",
+ &theme->osd_text_inactive_color))
+ theme->osd_text_inactive_color =
+ RrColorNew(inst,
+ theme->title_unfocused_color->r,
+ theme->title_unfocused_color->g,
+ theme->title_unfocused_color->b);
if (!read_color(db, inst,
"window.active.button.unpressed.image.color",
&theme->titlebut_focused_unpressed_color))
theme->menu_bullet_mask = RrPixmapMaskNew(inst, 4, 7, (gchar*)data);
}
+ /* up and down arrows */
+ {
+ guchar data[] = { 0xfe, 0x00, 0x7c, 0x00, 0x38, 0x00, 0x10, 0x00 };
+ theme->down_arrow_mask = RrPixmapMaskNew(inst, 9, 4, (gchar*)data);
+ }
+ {
+ guchar data[] = { 0x10, 0x00, 0x38, 0x00, 0x7c, 0x00, 0xfe, 0x00 };
+ theme->up_arrow_mask = RrPixmapMaskNew(inst, 9, 4, (gchar*)data);
+ }
+
/* setup the default window icon */
theme->def_win_icon = read_c_image(OB_DEFAULT_ICON_WIDTH,
OB_DEFAULT_ICON_HEIGHT,
RrAppearanceCopy(theme->a_menu_selected);
/* read appearances for non-decorations (on-screen-display) */
- if (!read_appearance(db, inst, "osd.bg", theme->osd_hilite_bg, FALSE)) {
- RrAppearanceFree(theme->osd_hilite_bg);
- theme->osd_hilite_bg = RrAppearanceCopy(theme->a_focused_title);
+ if (!read_appearance(db, inst, "osd.bg", theme->osd_bg, FALSE)) {
+ RrAppearanceFree(theme->osd_bg);
+ theme->osd_bg = RrAppearanceCopy(theme->a_focused_title);
}
- if (!read_appearance(db, inst, "osd.label.bg",
+ if (!read_appearance(db, inst, "osd.active.label.bg",
+ theme->osd_hilite_label, TRUE) &&
+ !read_appearance(db, inst, "osd.label.bg",
theme->osd_hilite_label, TRUE)) {
RrAppearanceFree(theme->osd_hilite_label);
theme->osd_hilite_label = RrAppearanceCopy(theme->a_focused_label);
}
+ if (!read_appearance(db, inst, "osd.inactive.label.bg",
+ theme->osd_unhilite_label, TRUE)) {
+ RrAppearanceFree(theme->osd_unhilite_label);
+ theme->osd_unhilite_label = RrAppearanceCopy(theme->a_unfocused_label);
+ }
/* osd_hilite_fg can't be parentrel */
if (!read_appearance(db, inst, "osd.hilight.bg",
- theme->osd_hilite_fg, FALSE)) {
- RrAppearanceFree(theme->osd_hilite_fg);
+ theme->osd_hilite_bg, FALSE)) {
+ RrAppearanceFree(theme->osd_hilite_bg);
if (theme->a_focused_label->surface.grad != RR_SURFACE_PARENTREL)
- theme->osd_hilite_fg = RrAppearanceCopy(theme->a_focused_label);
+ theme->osd_hilite_bg = RrAppearanceCopy(theme->a_focused_label);
else
- theme->osd_hilite_fg = RrAppearanceCopy(theme->a_focused_title);
+ theme->osd_hilite_bg = RrAppearanceCopy(theme->a_focused_title);
}
/* osd_unhilite_fg can't be parentrel either */
if (!read_appearance(db, inst, "osd.unhilight.bg",
- theme->osd_unhilite_fg, FALSE)) {
- RrAppearanceFree(theme->osd_unhilite_fg);
+ theme->osd_unhilite_bg, FALSE)) {
+ RrAppearanceFree(theme->osd_unhilite_bg);
if (theme->a_unfocused_label->surface.grad != RR_SURFACE_PARENTREL)
- theme->osd_unhilite_fg=RrAppearanceCopy(theme->a_unfocused_label);
+ theme->osd_unhilite_bg=RrAppearanceCopy(theme->a_unfocused_label);
else
- theme->osd_unhilite_fg=RrAppearanceCopy(theme->a_unfocused_title);
+ theme->osd_unhilite_bg=RrAppearanceCopy(theme->a_unfocused_title);
}
/* read buttons textures */
theme->osd_hilite_label->texture[0].type = RR_TEXTURE_TEXT;
theme->osd_hilite_label->texture[0].data.text.justify = RR_JUSTIFY_LEFT;
- theme->osd_hilite_label->texture[0].data.text.font = theme->osd_font;
- theme->osd_hilite_label->texture[0].data.text.color = theme->osd_color;
+ theme->osd_hilite_label->texture[0].data.text.font =
+ theme->osd_font_hilite;
+ theme->osd_hilite_label->texture[0].data.text.color =
+ theme->osd_text_active_color;
- if (read_string(db, "osd.label.text.font", &str)) {
+ if (read_string(db, "osd.active.label.text.font", &str) ||
+ read_string(db, "osd.label.text.font", &str))
+ {
char *p;
gint i = 0;
gint j;
i = parse_inline_number(p + strlen("shadowoffset="));
else
i = 1;
- theme->a_focused_label->texture[0].data.text.shadow_offset_x = i;
- theme->a_focused_label->texture[0].data.text.shadow_offset_y = i;
theme->osd_hilite_label->texture[0].data.text.shadow_offset_x = i;
theme->osd_hilite_label->texture[0].data.text.shadow_offset_y = i;
}
j = (i > 0 ? 0 : 255);
i = ABS(i*255/100);
- theme->osd_shadow_color = RrColorNew(inst, j, j, j);
- theme->osd_shadow_alpha = i;
+ theme->osd_text_active_shadow_color = RrColorNew(inst, j, j, j);
+ theme->osd_text_active_shadow_alpha = i;
} else {
- theme->osd_shadow_color = RrColorNew(inst, 0, 0, 0);
- theme->osd_shadow_alpha = 50;
+ theme->osd_text_active_shadow_color = RrColorNew(inst, 0, 0, 0);
+ theme->osd_text_active_shadow_alpha = 50;
}
} else {
/* inherit the font settings from the focused label */
theme->osd_hilite_label->texture[0].data.text.shadow_offset_y =
theme->a_focused_label->texture[0].data.text.shadow_offset_y;
if (theme->title_focused_shadow_color)
- theme->osd_shadow_color =
+ theme->osd_text_active_shadow_color =
RrColorNew(inst,
theme->title_focused_shadow_color->r,
theme->title_focused_shadow_color->g,
theme->title_focused_shadow_color->b);
else
- theme->osd_shadow_color = RrColorNew(inst, 0, 0, 0);
- theme->osd_shadow_alpha = theme->title_focused_shadow_alpha;
+ theme->osd_text_active_shadow_color = RrColorNew(inst, 0, 0, 0);
+ theme->osd_text_active_shadow_alpha =
+ theme->title_focused_shadow_alpha;
}
theme->osd_hilite_label->texture[0].data.text.shadow_color =
- theme->osd_shadow_color;
+ theme->osd_text_active_shadow_color;
theme->osd_hilite_label->texture[0].data.text.shadow_alpha =
- theme->osd_shadow_alpha;
+ theme->osd_text_active_shadow_alpha;
theme->a_unfocused_label->texture[0].type = RR_TEXTURE_TEXT;
theme->a_unfocused_label->texture[0].data.text.justify = winjust;
theme->a_unfocused_label->texture[0].data.text.shadow_alpha =
theme->title_unfocused_shadow_alpha;
+ theme->osd_unhilite_label->texture[0].type = RR_TEXTURE_TEXT;
+ theme->osd_unhilite_label->texture[0].data.text.justify = RR_JUSTIFY_LEFT;
+ theme->osd_unhilite_label->texture[0].data.text.font =
+ theme->osd_font_unhilite;
+ theme->osd_unhilite_label->texture[0].data.text.color =
+ theme->osd_text_inactive_color;
+
+ if (read_string(db, "osd.inactive.label.text.font", &str))
+ {
+ char *p;
+ gint i = 0;
+ gint j;
+ if (strstr(str, "shadow=y")) {
+ if ((p = strstr(str, "shadowoffset=")))
+ i = parse_inline_number(p + strlen("shadowoffset="));
+ else
+ i = 1;
+ theme->osd_unhilite_label->texture[0].data.text.shadow_offset_x=i;
+ theme->osd_unhilite_label->texture[0].data.text.shadow_offset_y=i;
+ }
+ if ((p = strstr(str, "shadowtint=")))
+ {
+ i = parse_inline_number(p + strlen("shadowtint="));
+ j = (i > 0 ? 0 : 255);
+ i = ABS(i*255/100);
+
+ theme->osd_text_inactive_shadow_color = RrColorNew(inst, j, j, j);
+ theme->osd_text_inactive_shadow_alpha = i;
+ } else {
+ theme->osd_text_inactive_shadow_color = RrColorNew(inst, 0, 0, 0);
+ theme->osd_text_inactive_shadow_alpha = 50;
+ }
+ } else {
+ /* inherit the font settings from the unfocused label */
+ theme->osd_unhilite_label->texture[0].data.text.shadow_offset_x =
+ theme->a_unfocused_label->texture[0].data.text.shadow_offset_x;
+ theme->osd_unhilite_label->texture[0].data.text.shadow_offset_y =
+ theme->a_unfocused_label->texture[0].data.text.shadow_offset_y;
+ if (theme->title_unfocused_shadow_color)
+ theme->osd_text_inactive_shadow_color =
+ RrColorNew(inst,
+ theme->title_unfocused_shadow_color->r,
+ theme->title_unfocused_shadow_color->g,
+ theme->title_unfocused_shadow_color->b);
+ else
+ theme->osd_text_inactive_shadow_color = RrColorNew(inst, 0, 0, 0);
+ theme->osd_text_inactive_shadow_alpha =
+ theme->title_unfocused_shadow_alpha;
+ }
+
+ theme->osd_unhilite_label->texture[0].data.text.shadow_color =
+ theme->osd_text_inactive_shadow_color;
+ theme->osd_unhilite_label->texture[0].data.text.shadow_alpha =
+ theme->osd_text_inactive_shadow_alpha;
+
theme->a_menu_text_title->texture[0].type = RR_TEXTURE_TEXT;
theme->a_menu_text_title->texture[0].data.text.justify = mtitlejust;
theme->a_menu_text_title->texture[0].data.text.font =
RrColorFree(theme->menu_disabled_selected_color);
RrColorFree(theme->title_focused_shadow_color);
RrColorFree(theme->title_unfocused_shadow_color);
- RrColorFree(theme->osd_color);
- RrColorFree(theme->osd_shadow_color);
+ RrColorFree(theme->osd_text_active_color);
+ RrColorFree(theme->osd_text_inactive_color);
+ RrColorFree(theme->osd_text_active_shadow_color);
+ RrColorFree(theme->osd_text_inactive_shadow_color);
RrColorFree(theme->menu_title_shadow_color);
RrColorFree(theme->menu_text_normal_shadow_color);
RrColorFree(theme->menu_text_selected_shadow_color);
RrPixmapMaskFree(theme->close_hover_mask);
RrPixmapMaskFree(theme->close_pressed_mask);
RrPixmapMaskFree(theme->menu_bullet_mask);
+ RrPixmapMaskFree(theme->down_arrow_mask);
+ RrPixmapMaskFree(theme->up_arrow_mask);
RrFontClose(theme->win_font_focused);
RrFontClose(theme->win_font_unfocused);
RrFontClose(theme->menu_title_font);
RrFontClose(theme->menu_font);
- RrFontClose(theme->osd_font);
+ RrFontClose(theme->osd_font_hilite);
+ RrFontClose(theme->osd_font_unhilite);
RrAppearanceFree(theme->a_disabled_focused_max);
RrAppearanceFree(theme->a_disabled_unfocused_max);
RrAppearanceFree(theme->a_menu_bullet_selected);
RrAppearanceFree(theme->a_clear);
RrAppearanceFree(theme->a_clear_tex);
+ RrAppearanceFree(theme->osd_bg);
RrAppearanceFree(theme->osd_hilite_bg);
- RrAppearanceFree(theme->osd_hilite_fg);
RrAppearanceFree(theme->osd_hilite_label);
- RrAppearanceFree(theme->osd_unhilite_fg);
+ RrAppearanceFree(theme->osd_unhilite_bg);
+ RrAppearanceFree(theme->osd_unhilite_label);
g_free(theme);
}
*path = g_path_get_dirname(s);
g_free(s);
} else {
+ ObtPaths *p;
+
+ p = obt_paths_new();
+
/* XXX backwards compatibility, remove me sometime later */
s = g_build_filename(g_get_home_dir(), ".themes", name,
"openbox-3", "themerc", NULL);
*path = g_path_get_dirname(s);
g_free(s);
- for (it = parse_xdg_data_dir_paths(); !db && it;
- it = g_slist_next(it))
+ for (it = obt_paths_data_dirs(p); !db && it; it = g_slist_next(it))
{
s = g_build_filename(it->data, "themes", name,
"openbox-3", "themerc", NULL);
*path = g_path_get_dirname(s);
g_free(s);
}
+
+ obt_paths_unref(p);
}
if (db == NULL) {
RrFont *win_font_unfocused;
RrFont *menu_title_font;
RrFont *menu_font;
- RrFont *osd_font;
+ RrFont *osd_font_hilite;
+ RrFont *osd_font_unhilite;
/* style settings - geometry */
gint paddingx;
gchar title_focused_shadow_alpha;
RrColor *title_unfocused_shadow_color;
gchar title_unfocused_shadow_alpha;
- RrColor *osd_color;
- RrColor *osd_shadow_color;
- gchar osd_shadow_alpha;
+ RrColor *osd_text_active_color;
+ RrColor *osd_text_inactive_color;
+ RrColor *osd_text_active_shadow_color;
+ RrColor *osd_text_inactive_shadow_color;
+ gchar osd_text_active_shadow_alpha;
+ gchar osd_text_inactive_shadow_alpha;
RrColor *menu_title_shadow_color;
gchar menu_title_shadow_alpha;
RrColor *menu_text_normal_shadow_color;
RrPixmapMask *menu_toggle_mask; /* menu boolean */
#endif
+ RrPixmapMask *down_arrow_mask;
+ RrPixmapMask *up_arrow_mask;
+
/* global appearances */
RrAppearance *a_disabled_focused_max;
RrAppearance *a_disabled_unfocused_max;
RrAppearance *a_clear; /* clear with no texture */
RrAppearance *a_clear_tex; /* clear with a texture */
+ RrAppearance *osd_bg; /* can never be parent relative */
RrAppearance *osd_hilite_bg; /* can never be parent relative */
- RrAppearance *osd_hilite_fg; /* can never be parent relative */
RrAppearance *osd_hilite_label; /* can be parent relative */
- RrAppearance *osd_unhilite_fg; /* can never be parent relative */
+ RrAppearance *osd_unhilite_bg; /* can never be parent relative */
+ RrAppearance *osd_unhilite_label; /* can be parent relative */
gchar *name;
};
gboolean allow_fallback,
RrFont *active_window_font, RrFont *inactive_window_font,
RrFont *menu_title_font, RrFont *menu_item_font,
- RrFont *osd_font);
+ RrFont *active_osd_font, RrFont *inactive_osd_font);
void RrThemeFree(RrTheme *theme);
G_END_DECLS
--- /dev/null
+#ifndef rr__version_h
+#define rr__version_h
+
+#define RR_MAJOR_VERSION @RR_MAJOR_VERSION@
+#define RR_MINOR_VERSION @RR_MINOR_VERSION@
+#define RR_MICRO_VERSION @RR_MICRO_VERSION@
+#define RR_VERSION RR_MAJOR_VERSION.RR_MINOR_VERSION.RR_MICRO_VERSION
+
+#define RR_CHECK_VERSION(major,minor,micro) \
+ (RR_MAJOR_VERSION > (major) || \
+ (RR_MAJOR_VERSION == (major) && RR_MINOR_VERSION > (minor)) || \
+ (RR_MAJOR_VERSION == (major) && RR_MINOR_VERSION == (minor) && \
+ RR_MICRO_VERSION >= (micro)))
+
+#endif
--- /dev/null
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ obt/display.c for the Openbox window manager
+ Copyright (c) 2007 Dana Jansens
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ See the COPYING file for a copy of the GNU General Public License.
+*/
+
+#include "obt/display.h"
+#include "obt/prop.h"
+#include "obt/internal.h"
+#include "obt/keyboard.h"
+
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+Display* obt_display = NULL;
+
+gboolean obt_display_error_occured = FALSE;
+
+gboolean obt_display_extension_xkb = FALSE;
+gint obt_display_extension_xkb_basep;
+gboolean obt_display_extension_shape = FALSE;
+gint obt_display_extension_shape_basep;
+gboolean obt_display_extension_xinerama = FALSE;
+gint obt_display_extension_xinerama_basep;
+gboolean obt_display_extension_randr = FALSE;
+gint obt_display_extension_randr_basep;
+gboolean obt_display_extension_sync = FALSE;
+gint obt_display_extension_sync_basep;
+
+static gint xerror_handler(Display *d, XErrorEvent *e);
+
+static gboolean xerror_ignore = FALSE;
+
+gboolean obt_display_open(const char *display_name)
+{
+ gchar *n;
+ Display *d = NULL;
+
+ n = display_name ? g_strdup(display_name) : NULL;
+ obt_display = d = XOpenDisplay(n);
+ if (d) {
+ gint junk;
+ (void)junk;
+
+ if (fcntl(ConnectionNumber(d), F_SETFD, 1) == -1)
+ g_message("Failed to set display as close-on-exec");
+ XSetErrorHandler(xerror_handler);
+
+ /* read what extensions are present */
+#ifdef XKB
+ obt_display_extension_xkb =
+ XkbQueryExtension(d, &junk,
+ &obt_display_extension_xkb_basep, &junk,
+ NULL, NULL);
+ if (!obt_display_extension_xkb)
+ g_message("XKB extension is not present on the server");
+#endif
+
+#ifdef SHAPE
+ obt_display_extension_shape =
+ XShapeQueryExtension(d, &obt_display_extension_shape_basep,
+ &junk);
+ if (!obt_display_extension_shape)
+ g_message("X Shape extension is not present on the server");
+#endif
+
+#ifdef XINERAMA
+ obt_display_extension_xinerama =
+ XineramaQueryExtension(d,
+ &obt_display_extension_xinerama_basep,
+ &junk) && XineramaIsActive(d);
+ if (!obt_display_extension_xinerama)
+ g_message("Xinerama extension is not present on the server");
+#endif
+
+#ifdef XRANDR
+ obt_display_extension_randr =
+ XRRQueryExtension(d, &obt_display_extension_randr_basep,
+ &junk);
+ if (!obt_display_extension_randr)
+ g_message("XRandR extension is not present on the server");
+#endif
+
+#ifdef SYNC
+ obt_display_extension_sync =
+ XSyncQueryExtension(d, &obt_display_extension_sync_basep,
+ &junk) && XSyncInitialize(d, &junk, &junk);
+ if (!obt_display_extension_sync)
+ g_message("X Sync extension is not present on the server or is an "
+ "incompatible version");
+#endif
+
+ obt_prop_startup();
+ obt_keyboard_reload();
+ }
+ g_free(n);
+
+ return obt_display != NULL;
+}
+
+void obt_display_close(void)
+{
+ obt_keyboard_shutdown();
+ if (obt_display) XCloseDisplay(obt_display);
+}
+
+static gint xerror_handler(Display *d, XErrorEvent *e)
+{
+#ifdef DEBUG
+ gchar errtxt[128];
+
+ XGetErrorText(d, e->error_code, errtxt, 127);
+ if (!xerror_ignore) {
+ if (e->error_code == BadWindow)
+ /*g_debug(_("X Error: %s\n"), errtxt)*/;
+ else
+ g_error("X Error: %s", errtxt);
+ } else
+ g_debug("Ignoring XError code %d '%s'", e->error_code, errtxt);
+#else
+ (void)d; (void)e;
+#endif
+
+ obt_display_error_occured = TRUE;
+ return 0;
+}
+
+void obt_display_ignore_errors(gboolean ignore)
+{
+ XSync(obt_display, FALSE);
+ xerror_ignore = ignore;
+ if (ignore) obt_display_error_occured = FALSE;
+}
--- /dev/null
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ obt/display.h for the Openbox window manager
+ Copyright (c) 2007 Dana Jansens
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ See the COPYING file for a copy of the GNU General Public License.
+*/
+
+#ifndef __obt_display_h
+#define __obt_display_h
+
+#include <X11/Xlib.h>
+#include <glib.h>
+
+#include <X11/Xutil.h> /* shape.h uses Region which is in here */
+#ifdef XKB
+#include <X11/XKBlib.h>
+#endif
+#ifdef SHAPE
+#include <X11/extensions/shape.h>
+#endif
+#ifdef XINERAMA
+#include <X11/extensions/Xinerama.h>
+#endif
+#ifdef XRANDR
+#include <X11/extensions/Xrandr.h>
+#endif
+#ifdef SYNC
+#include <X11/extensions/sync.h>
+#endif
+
+G_BEGIN_DECLS
+
+extern gboolean obt_display_error_occured;
+
+extern gboolean obt_display_extension_xkb;
+extern gint obt_display_extension_xkb_basep;
+extern gboolean obt_display_extension_shape;
+extern gint obt_display_extension_shape_basep;
+extern gboolean obt_display_extension_xinerama;
+extern gint obt_display_extension_xinerama_basep;
+extern gboolean obt_display_extension_randr;
+extern gint obt_display_extension_randr_basep;
+extern gboolean obt_display_extension_sync;
+extern gint obt_display_extension_sync_basep;
+
+extern Display* obt_display;
+
+gboolean obt_display_open(const char *display_name);
+void obt_display_close(void);
+
+void obt_display_ignore_errors(gboolean ignore);
+
+#define obt_root(screen) (RootWindow(obt_display, screen))
+
+G_END_DECLS
+
+#endif /*__obt_display_h*/
/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
- xerror.h for the Openbox window manager
+ obt/internal.h for the Openbox window manager
+ Copyright (c) 2006 Mikael Magnusson
Copyright (c) 2003-2007 Dana Jansens
This program is free software; you can redistribute it and/or modify
See the COPYING file for a copy of the GNU General Public License.
*/
-#ifndef __xerror_h
-#define __xerror_h
+#ifndef __obt_internal_h
+#define __obt_internal_h
-#include <X11/Xlib.h>
-#include <glib.h>
+void obt_prop_startup(void);
-/* can be used to track errors */
-extern gboolean xerror_occured;
+void obt_keyboard_shutdown(void);
-gint xerror_handler(Display *, XErrorEvent *);
-
-void xerror_set_ignore(gboolean ignore);
-
-#endif
+#endif /* __obt_internal_h */
/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
- modkeys.c for the Openbox window manager
+ obt/keyboard.c for the Openbox window manager
Copyright (c) 2007 Dana Jansens
This program is free software; you can redistribute it and/or modify
See the COPYING file for a copy of the GNU General Public License.
*/
-#include "modkeys.h"
-#include "openbox.h"
+#include "obt/display.h"
+#include "obt/keyboard.h"
#include <X11/Xlib.h>
#include <X11/keysym.h>
#define nth_mask(n) (1 << n)
static void set_modkey_mask(guchar mask, KeySym sym);
+void obt_keyboard_shutdown();
static XModifierKeymap *modmap;
static KeySym *keymap;
static gint min_keycode, max_keycode, keysyms_per_keycode;
/* This is a bitmask of the different masks for each modifier key */
-static guchar modkeys_keys[OB_MODKEY_NUM_KEYS];
+static guchar modkeys_keys[OBT_KEYBOARD_NUM_MODKEYS];
static gboolean alt_l = FALSE;
static gboolean meta_l = FALSE;
static gboolean super_l = FALSE;
static gboolean hyper_l = FALSE;
-void modkeys_startup(gboolean reconfigure)
+static gboolean started = FALSE;
+
+void obt_keyboard_reload(void)
{
gint i, j, k;
+ if (started) obt_keyboard_shutdown(); /* free stuff */
+ started = TRUE;
+
/* reset the keys to not be bound to any masks */
- for (i = 0; i < OB_MODKEY_NUM_KEYS; ++i)
+ for (i = 0; i < OBT_KEYBOARD_NUM_MODKEYS; ++i)
modkeys_keys[i] = 0;
- modmap = XGetModifierMapping(ob_display);
+ modmap = XGetModifierMapping(obt_display);
g_assert(modmap->max_keypermod > 0);
- XDisplayKeycodes(ob_display, &min_keycode, &max_keycode);
- keymap = XGetKeyboardMapping(ob_display, min_keycode,
+ XDisplayKeycodes(obt_display, &min_keycode, &max_keycode);
+ keymap = XGetKeyboardMapping(obt_display, min_keycode,
max_keycode - min_keycode + 1,
&keysyms_per_keycode);
}
/* CapsLock, Shift, and Control are special and hard-coded */
- modkeys_keys[OB_MODKEY_KEY_CAPSLOCK] = LockMask;
- modkeys_keys[OB_MODKEY_KEY_SHIFT] = ShiftMask;
- modkeys_keys[OB_MODKEY_KEY_CONTROL] = ControlMask;
+ modkeys_keys[OBT_KEYBOARD_MODKEY_CAPSLOCK] = LockMask;
+ modkeys_keys[OBT_KEYBOARD_MODKEY_SHIFT] = ShiftMask;
+ modkeys_keys[OBT_KEYBOARD_MODKEY_CONTROL] = ControlMask;
}
-void modkeys_shutdown(gboolean reconfigure)
+void obt_keyboard_shutdown(void)
{
XFreeModifiermap(modmap);
+ modmap = NULL;
XFree(keymap);
+ keymap = NULL;
+ started = FALSE;
}
-guint modkeys_keycode_to_mask(guint keycode)
+guint obt_keyboard_keycode_to_modmask(guint keycode)
{
gint i, j;
guint mask = 0;
return mask;
}
-guint modkeys_only_modifier_masks(guint mask)
+guint obt_keyboard_only_modmasks(guint mask)
{
mask &= ALL_MASKS;
/* strip off these lock keys. they shouldn't affect key bindings */
because you could bind it to something else and it
should work as that modifier then. i think capslock
is weird in xkb. */
- mask &= ~modkeys_key_to_mask(OB_MODKEY_KEY_NUMLOCK);
- mask &= ~modkeys_key_to_mask(OB_MODKEY_KEY_SCROLLLOCK);
+ mask &= ~obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_NUMLOCK);
+ mask &= ~obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_SCROLLLOCK);
return mask;
}
-guint modkeys_key_to_mask(ObModkeysKey key)
+guint obt_keyboard_modkey_to_modmask(ObtModkeysKey key)
{
return modkeys_keys[key];
}
/* find what key this is, and bind it to the mask */
if (sym == XK_Num_Lock)
- modkeys_keys[OB_MODKEY_KEY_NUMLOCK] |= mask;
+ modkeys_keys[OBT_KEYBOARD_MODKEY_NUMLOCK] |= mask;
else if (sym == XK_Scroll_Lock)
- modkeys_keys[OB_MODKEY_KEY_SCROLLLOCK] |= mask;
+ modkeys_keys[OBT_KEYBOARD_MODKEY_SCROLLLOCK] |= mask;
else if (sym == XK_Super_L && super_l)
- modkeys_keys[OB_MODKEY_KEY_SUPER] |= mask;
+ modkeys_keys[OBT_KEYBOARD_MODKEY_SUPER] |= mask;
else if (sym == XK_Super_L && !super_l)
/* left takes precident over right, so erase any masks the right
key may have set */
- modkeys_keys[OB_MODKEY_KEY_SUPER] = mask, super_l = TRUE;
+ modkeys_keys[OBT_KEYBOARD_MODKEY_SUPER] = mask, super_l = TRUE;
else if (sym == XK_Super_R && !super_l)
- modkeys_keys[OB_MODKEY_KEY_SUPER] |= mask;
+ modkeys_keys[OBT_KEYBOARD_MODKEY_SUPER] |= mask;
else if (sym == XK_Hyper_L && hyper_l)
- modkeys_keys[OB_MODKEY_KEY_HYPER] |= mask;
+ modkeys_keys[OBT_KEYBOARD_MODKEY_HYPER] |= mask;
else if (sym == XK_Hyper_L && !hyper_l)
- modkeys_keys[OB_MODKEY_KEY_HYPER] = mask, hyper_l = TRUE;
+ modkeys_keys[OBT_KEYBOARD_MODKEY_HYPER] = mask, hyper_l = TRUE;
else if (sym == XK_Hyper_R && !hyper_l)
- modkeys_keys[OB_MODKEY_KEY_HYPER] |= mask;
+ modkeys_keys[OBT_KEYBOARD_MODKEY_HYPER] |= mask;
else if (sym == XK_Alt_L && alt_l)
- modkeys_keys[OB_MODKEY_KEY_ALT] |= mask;
+ modkeys_keys[OBT_KEYBOARD_MODKEY_ALT] |= mask;
else if (sym == XK_Alt_L && !alt_l)
- modkeys_keys[OB_MODKEY_KEY_ALT] = mask, alt_l = TRUE;
+ modkeys_keys[OBT_KEYBOARD_MODKEY_ALT] = mask, alt_l = TRUE;
else if (sym == XK_Alt_R && !alt_l)
- modkeys_keys[OB_MODKEY_KEY_ALT] |= mask;
+ modkeys_keys[OBT_KEYBOARD_MODKEY_ALT] |= mask;
else if (sym == XK_Meta_L && meta_l)
- modkeys_keys[OB_MODKEY_KEY_META] |= mask;
+ modkeys_keys[OBT_KEYBOARD_MODKEY_META] |= mask;
else if (sym == XK_Meta_L && !meta_l)
- modkeys_keys[OB_MODKEY_KEY_META] = mask, meta_l = TRUE;
+ modkeys_keys[OBT_KEYBOARD_MODKEY_META] = mask, meta_l = TRUE;
else if (sym == XK_Meta_R && !meta_l)
- modkeys_keys[OB_MODKEY_KEY_META] |= mask;
+ modkeys_keys[OBT_KEYBOARD_MODKEY_META] |= mask;
/* CapsLock, Shift, and Control are special and hard-coded */
}
-KeyCode* modkeys_sym_to_code(KeySym sym)
+KeyCode* obt_keyboard_keysym_to_keycode(KeySym sym)
{
KeyCode *ret;
gint i, j, n;
}
return ret;
}
+
+gchar *obt_keyboard_keycode_to_string(guint keycode)
+{
+ KeySym sym;
+
+ if ((sym = XKeycodeToKeysym(obt_display, keycode, 0)) != NoSymbol)
+ return g_locale_to_utf8(XKeysymToString(sym), -1, NULL, NULL, NULL);
+ return NULL;
+}
+
+gunichar obt_keyboard_keycode_to_unichar(guint keycode)
+{
+ gunichar unikey = 0;
+ char *key;
+
+ if ((key = obt_keyboard_keycode_to_string(keycode)) != NULL &&
+ /* don't accept keys that aren't a single letter, like "space" */
+ key[1] == '\0')
+ {
+ unikey = g_utf8_get_char_validated(key, -1);
+ if (unikey == (gunichar)-1 || unikey == (gunichar)-2 || unikey == 0)
+ unikey = 0;
+ }
+ g_free(key);
+ return unikey;
+}
/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
- masks.h for the Openbox window manager
+ obt/keyboard.h for the Openbox window manager
Copyright (c) 2007 Dana Jansens
This program is free software; you can redistribute it and/or modify
See the COPYING file for a copy of the GNU General Public License.
*/
-#ifndef ob__modkeys_h
-#define ob__modkeys_h
+#ifndef __obt_keyboard_h
+#define __obt_keyboard_h
#include <glib.h>
#include <X11/Xlib.h>
+G_BEGIN_DECLS
+
/*! These keys are bound to the modifier masks in any fashion,
except for CapsLock, Shift, and Control. */
typedef enum {
- OB_MODKEY_KEY_CAPSLOCK,
- OB_MODKEY_KEY_NUMLOCK,
- OB_MODKEY_KEY_SCROLLLOCK,
- OB_MODKEY_KEY_SHIFT,
- OB_MODKEY_KEY_CONTROL,
- OB_MODKEY_KEY_SUPER,
- OB_MODKEY_KEY_HYPER,
- OB_MODKEY_KEY_META,
- OB_MODKEY_KEY_ALT,
-
- OB_MODKEY_NUM_KEYS
-} ObModkeysKey;
-
-void modkeys_startup(gboolean reconfigure);
-void modkeys_shutdown(gboolean reconfigure);
-
-/*! Get the modifier masks for a keycode. (eg. a keycode bound to Alt_L could
+ OBT_KEYBOARD_MODKEY_CAPSLOCK,
+ OBT_KEYBOARD_MODKEY_NUMLOCK,
+ OBT_KEYBOARD_MODKEY_SCROLLLOCK,
+ OBT_KEYBOARD_MODKEY_SHIFT,
+ OBT_KEYBOARD_MODKEY_CONTROL,
+ OBT_KEYBOARD_MODKEY_SUPER,
+ OBT_KEYBOARD_MODKEY_HYPER,
+ OBT_KEYBOARD_MODKEY_META,
+ OBT_KEYBOARD_MODKEY_ALT,
+
+ OBT_KEYBOARD_NUM_MODKEYS
+} ObtModkeysKey;
+
+void obt_keyboard_reload(void);
+
+/*! Get the modifier mask(s) for a KeyCode. (eg. a keycode bound to Alt_L could
return a mask of (Mod1Mask | Mask3Mask)) */
-guint modkeys_keycode_to_mask(guint keycode);
+guint obt_keyboard_keycode_to_modmask(guint keycode);
/*! Strip off all modifiers except for the modifier keys. This strips stuff
- like Button1Mask, and also LockMask, NumLockMask, and ScrollLockMask */
-guint modkeys_only_modifier_masks(guint mask);
+ like Button1Mask, and also LockMask, NumlockMask, and ScrolllockMask */
+guint obt_keyboard_only_modmasks(guint mask);
/*! Get the modifier masks for a modifier key. This includes both the left and
right keys when there are both. */
-guint modkeys_key_to_mask(ObModkeysKey key);
+guint obt_keyboard_modkey_to_modmask(ObtModkeysKey key);
/*! Convert a KeySym to all the KeyCodes which generate it. */
-KeyCode* modkeys_sym_to_code(KeySym sym);
+KeyCode* obt_keyboard_keysym_to_keycode(KeySym sym);
+
+/*! Give the string form of a KeyCode */
+gchar *obt_keyboard_keycode_to_string(guint keycode);
+
+/*! Translate a KeyCode to the unicode character it represents */
+gunichar obt_keyboard_keycode_to_unichar(guint keycode);
+
+
+G_END_DECLS
-#endif
+#endif /* __obt_keyboard_h */
/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
- mainloop.c for the Openbox window manager
+ obt/mainloop.c for the Openbox window manager
Copyright (c) 2006 Mikael Magnusson
Copyright (c) 2003-2007 Dana Jansens
See the COPYING file for a copy of the GNU General Public License.
*/
-#include "mainloop.h"
-#include "event.h"
+#include "obt/mainloop.h"
+#include "obt/display.h"
+#include "obt/util.h"
+#ifdef HAVE_STDIO_H
#include <stdio.h>
+#endif
+#ifdef HAVE_STDLIB_H
#include <stdlib.h>
+#endif
+#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_SIGNAL_H
#include <signal.h>
+#endif
-typedef struct _ObMainLoopTimer ObMainLoopTimer;
-typedef struct _ObMainLoopSignal ObMainLoopSignal;
-typedef struct _ObMainLoopSignalHandlerType ObMainLoopSignalHandlerType;
-typedef struct _ObMainLoopXHandlerType ObMainLoopXHandlerType;
-typedef struct _ObMainLoopFdHandlerType ObMainLoopFdHandlerType;
+typedef struct _ObtMainLoopTimer ObtMainLoopTimer;
+typedef struct _ObtMainLoopSignal ObtMainLoopSignal;
+typedef struct _ObtMainLoopSignalHandlerType ObtMainLoopSignalHandlerType;
+typedef struct _ObtMainLoopXHandlerType ObtMainLoopXHandlerType;
+typedef struct _ObtMainLoopFdHandlerType ObtMainLoopFdHandlerType;
/* this should be more than the number of possible signals on any
architecture... */
#define NUM_SIGNALS 99
-/* all created ObMainLoops. Used by the signal handler to pass along signals */
+/* all created ObtMainLoops. Used by the signal handler to pass along
+ signals */
static GSList *all_loops;
/* signals are global to all loops */
#define NUM_CORE_SIGNALS (sizeof(core_signals) / sizeof(core_signals[0]))
static void sighandler(gint sig);
-static void timer_dispatch(ObMainLoop *loop, GTimeVal **wait);
+static void timer_dispatch(ObtMainLoop *loop, GTimeVal **wait);
static void fd_handler_destroy(gpointer data);
+static void calc_max_fd(ObtMainLoop *loop);
-struct _ObMainLoop
+struct _ObtMainLoop
{
+ gint ref;
Display *display;
gboolean run; /* do keep running */
GSList *signal_handlers[NUM_SIGNALS];
};
-struct _ObMainLoopTimer
+struct _ObtMainLoopTimer
{
gulong delay;
GSourceFunc func;
gboolean fired;
};
-struct _ObMainLoopSignalHandlerType
+struct _ObtMainLoopSignalHandlerType
{
- ObMainLoop *loop;
+ ObtMainLoop *loop;
gint signal;
gpointer data;
- ObMainLoopSignalHandler func;
+ ObtMainLoopSignalHandler func;
GDestroyNotify destroy;
};
-struct _ObMainLoopXHandlerType
+struct _ObtMainLoopXHandlerType
{
- ObMainLoop *loop;
+ ObtMainLoop *loop;
gpointer data;
- ObMainLoopXHandler func;
+ ObtMainLoopXHandler func;
GDestroyNotify destroy;
};
-struct _ObMainLoopFdHandlerType
+struct _ObtMainLoopFdHandlerType
{
- ObMainLoop *loop;
+ ObtMainLoop *loop;
gint fd;
gpointer data;
- ObMainLoopFdHandler func;
+ ObtMainLoopFdHandler func;
GDestroyNotify destroy;
};
-ObMainLoop *ob_main_loop_new(Display *display)
+ObtMainLoop *obt_main_loop_new(void)
{
- ObMainLoop *loop;
+ ObtMainLoop *loop;
- loop = g_new0(ObMainLoop, 1);
- loop->display = display;
- loop->fd_x = ConnectionNumber(display);
+ loop = g_new0(ObtMainLoop, 1);
+ loop->ref = 1;
FD_ZERO(&loop->fd_set);
- FD_SET(loop->fd_x, &loop->fd_set);
- loop->fd_max = loop->fd_x;
+ loop->fd_x = -1;
+ loop->fd_max = -1;
loop->fd_handlers = g_hash_table_new_full(g_int_hash, g_int_equal,
NULL, fd_handler_destroy);
return loop;
}
-void ob_main_loop_destroy(ObMainLoop *loop)
+void obt_main_loop_ref(ObtMainLoop *loop)
+{
+ ++loop->ref;
+}
+
+void obt_main_loop_unref(ObtMainLoop *loop)
{
guint i;
GSList *it, *next;
- if (loop) {
+ if (loop && --loop->ref == 0) {
g_assert(loop->running == FALSE);
for (it = loop->x_handlers; it; it = next) {
- ObMainLoopXHandlerType *h = it->data;
+ ObtMainLoopXHandlerType *h = it->data;
next = g_slist_next(it);
- ob_main_loop_x_remove(loop, h->func);
+ obt_main_loop_x_remove(loop, h->func);
}
g_hash_table_destroy(loop->fd_handlers);
for (it = loop->timers; it; it = g_slist_next(it)) {
- ObMainLoopTimer *t = it->data;
+ ObtMainLoopTimer *t = it->data;
if (t->destroy) t->destroy(t->data);
g_free(t);
}
for (i = 0; i < NUM_SIGNALS; ++i)
for (it = loop->signal_handlers[i]; it; it = next) {
- ObMainLoopSignalHandlerType *h = it->data;
+ ObtMainLoopSignalHandlerType *h = it->data;
next = g_slist_next(it);
- ob_main_loop_signal_remove(loop, h->func);
+ obt_main_loop_signal_remove(loop, h->func);
}
all_loops = g_slist_remove(all_loops, loop);
}
}
- g_free(loop);
+ obt_free0(loop, ObtMainLoop, 1);
}
}
gpointer value,
gpointer data)
{
- ObMainLoopFdHandlerType *h = value;
+ ObtMainLoopFdHandlerType *h = value;
fd_set *set = data;
if (FD_ISSET(h->fd, set))
h->func(h->fd, h->data);
}
-void ob_main_loop_run(ObMainLoop *loop)
+void obt_main_loop_run(ObtMainLoop *loop)
{
XEvent e;
struct timeval *wait;
while (loop->signals_fired[i]) {
for (it = loop->signal_handlers[i];
it; it = g_slist_next(it)) {
- ObMainLoopSignalHandlerType *h = it->data;
+ ObtMainLoopSignalHandlerType *h = it->data;
h->func(i, h->data);
}
loop->signals_fired[i]--;
loop->signal_fired = FALSE;
sigprocmask(SIG_SETMASK, &oldset, NULL);
- } else if (XPending(loop->display)) {
+ } else if (loop->display && XPending(loop->display)) {
do {
XNextEvent(loop->display, &e);
for (it = loop->x_handlers; it; it = g_slist_next(it)) {
- ObMainLoopXHandlerType *h = it->data;
+ ObtMainLoopXHandlerType *h = it->data;
h->func(&e, h->data);
}
} while (XPending(loop->display) && loop->run);
loop->running = FALSE;
}
-void ob_main_loop_exit(ObMainLoop *loop)
+void obt_main_loop_exit(ObtMainLoop *loop)
{
loop->run = FALSE;
}
/*** XEVENT WATCHERS ***/
-void ob_main_loop_x_add(ObMainLoop *loop,
- ObMainLoopXHandler handler,
- gpointer data,
- GDestroyNotify notify)
+void obt_main_loop_x_add(ObtMainLoop *loop,
+ ObtMainLoopXHandler handler,
+ gpointer data,
+ GDestroyNotify notify)
{
- ObMainLoopXHandlerType *h;
+ ObtMainLoopXHandlerType *h;
- h = g_new(ObMainLoopXHandlerType, 1);
+ h = g_new(ObtMainLoopXHandlerType, 1);
h->loop = loop;
h->func = handler;
h->data = data;
h->destroy = notify;
+
+ if (!loop->x_handlers) {
+ g_assert(obt_display); /* is the display open? */
+
+ loop->display = obt_display;
+ loop->fd_x = ConnectionNumber(loop->display);
+ FD_SET(loop->fd_x, &loop->fd_set);
+ calc_max_fd(loop);
+ }
+
loop->x_handlers = g_slist_prepend(loop->x_handlers, h);
}
-void ob_main_loop_x_remove(ObMainLoop *loop,
- ObMainLoopXHandler handler)
+void obt_main_loop_x_remove(ObtMainLoop *loop,
+ ObtMainLoopXHandler handler)
{
GSList *it, *next;
for (it = loop->x_handlers; it; it = next) {
- ObMainLoopXHandlerType *h = it->data;
+ ObtMainLoopXHandlerType *h = it->data;
next = g_slist_next(it);
if (h->func == handler) {
loop->x_handlers = g_slist_delete_link(loop->x_handlers, it);
g_free(h);
}
}
+
+ if (!loop->x_handlers) {
+ FD_CLR(loop->fd_x, &loop->fd_set);
+ calc_max_fd(loop);
+ }
}
/*** SIGNAL WATCHERS ***/
}
for (it = all_loops; it; it = g_slist_next(it)) {
- ObMainLoop *loop = it->data;
+ ObtMainLoop *loop = it->data;
loop->signal_fired = TRUE;
loop->signals_fired[sig]++;
}
}
-void ob_main_loop_signal_add(ObMainLoop *loop,
- gint signal,
- ObMainLoopSignalHandler handler,
- gpointer data,
- GDestroyNotify notify)
+void obt_main_loop_signal_add(ObtMainLoop *loop,
+ gint signal,
+ ObtMainLoopSignalHandler handler,
+ gpointer data,
+ GDestroyNotify notify)
{
- ObMainLoopSignalHandlerType *h;
+ ObtMainLoopSignalHandlerType *h;
g_return_if_fail(signal < NUM_SIGNALS);
- h = g_new(ObMainLoopSignalHandlerType, 1);
+ h = g_new(ObtMainLoopSignalHandlerType, 1);
h->loop = loop;
h->signal = signal;
h->func = handler;
all_signals[signal].installed++;
}
-void ob_main_loop_signal_remove(ObMainLoop *loop,
- ObMainLoopSignalHandler handler)
+void obt_main_loop_signal_remove(ObtMainLoop *loop,
+ ObtMainLoopSignalHandler handler)
{
guint i;
GSList *it, *next;
for (i = 0; i < NUM_SIGNALS; ++i) {
for (it = loop->signal_handlers[i]; it; it = next) {
- ObMainLoopSignalHandlerType *h = it->data;
+ ObtMainLoopSignalHandlerType *h = it->data;
next = g_slist_next(it);
static void max_fd_func(gpointer key, gpointer value, gpointer data)
{
- ObMainLoop *loop = data;
+ ObtMainLoop *loop = data;
/* key is the fd */
loop->fd_max = MAX(loop->fd_max, *(gint*)key);
}
-static void calc_max_fd(ObMainLoop *loop)
+static void calc_max_fd(ObtMainLoop *loop)
{
loop->fd_max = loop->fd_x;
g_hash_table_foreach(loop->fd_handlers, max_fd_func, loop);
}
-void ob_main_loop_fd_add(ObMainLoop *loop,
- gint fd,
- ObMainLoopFdHandler handler,
- gpointer data,
- GDestroyNotify notify)
+void obt_main_loop_fd_add(ObtMainLoop *loop,
+ gint fd,
+ ObtMainLoopFdHandler handler,
+ gpointer data,
+ GDestroyNotify notify)
{
- ObMainLoopFdHandlerType *h;
+ ObtMainLoopFdHandlerType *h;
- h = g_new(ObMainLoopFdHandlerType, 1);
+ h = g_new(ObtMainLoopFdHandlerType, 1);
h->loop = loop;
h->fd = fd;
h->func = handler;
static void fd_handler_destroy(gpointer data)
{
- ObMainLoopFdHandlerType *h = data;
+ ObtMainLoopFdHandlerType *h = data;
FD_CLR(h->fd, &h->loop->fd_set);
h->destroy(h->data);
}
-void ob_main_loop_fd_remove(ObMainLoop *loop,
- gint fd)
+void obt_main_loop_fd_remove(ObtMainLoop *loop,
+ gint fd)
{
g_hash_table_remove(loop->fd_handlers, &fd);
+ calc_max_fd(loop);
}
/*** TIMEOUTS ***/
#define NEAREST_TIMEOUT(loop) \
- (((ObMainLoopTimer*)(loop)->timers->data)->timeout)
+ (((ObtMainLoopTimer*)(loop)->timers->data)->timeout)
static glong timecompare(GTimeVal *a, GTimeVal *b)
{
return a->tv_usec - b->tv_usec;
}
-static void insert_timer(ObMainLoop *loop, ObMainLoopTimer *ins)
+static void insert_timer(ObtMainLoop *loop, ObtMainLoopTimer *ins)
{
GSList *it;
for (it = loop->timers; it; it = g_slist_next(it)) {
- ObMainLoopTimer *t = it->data;
+ ObtMainLoopTimer *t = it->data;
if (timecompare(&ins->timeout, &t->timeout) <= 0) {
loop->timers = g_slist_insert_before(loop->timers, it, ins);
break;
loop->timers = g_slist_append(loop->timers, ins);
}
-void ob_main_loop_timeout_add(ObMainLoop *loop,
- gulong microseconds,
- GSourceFunc handler,
- gpointer data,
- GEqualFunc cmp,
- GDestroyNotify notify)
+void obt_main_loop_timeout_add(ObtMainLoop *loop,
+ gulong microseconds,
+ GSourceFunc handler,
+ gpointer data,
+ GEqualFunc cmp,
+ GDestroyNotify notify)
{
- ObMainLoopTimer *t = g_new(ObMainLoopTimer, 1);
+ ObtMainLoopTimer *t = g_new(ObtMainLoopTimer, 1);
g_assert(microseconds > 0); /* if it's 0 it'll cause an infinite loop */
insert_timer(loop, t);
}
-void ob_main_loop_timeout_remove(ObMainLoop *loop,
- GSourceFunc handler)
+void obt_main_loop_timeout_remove(ObtMainLoop *loop,
+ GSourceFunc handler)
{
GSList *it;
for (it = loop->timers; it; it = g_slist_next(it)) {
- ObMainLoopTimer *t = it->data;
+ ObtMainLoopTimer *t = it->data;
if (t->func == handler)
t->del_me = TRUE;
}
}
-void ob_main_loop_timeout_remove_data(ObMainLoop *loop, GSourceFunc handler,
- gpointer data, gboolean cancel_dest)
+void obt_main_loop_timeout_remove_data(ObtMainLoop *loop, GSourceFunc handler,
+ gpointer data, gboolean cancel_dest)
{
GSList *it;
for (it = loop->timers; it; it = g_slist_next(it)) {
- ObMainLoopTimer *t = it->data;
+ ObtMainLoopTimer *t = it->data;
if (t->func == handler && t->equal(t->data, data)) {
t->del_me = TRUE;
if (cancel_dest)
}
/* find the time to wait for the nearest timeout */
-static gboolean nearest_timeout_wait(ObMainLoop *loop, GTimeVal *tm)
+static gboolean nearest_timeout_wait(ObtMainLoop *loop, GTimeVal *tm)
{
if (loop->timers == NULL)
return FALSE;
return TRUE;
}
-static void timer_dispatch(ObMainLoop *loop, GTimeVal **wait)
+static void timer_dispatch(ObtMainLoop *loop, GTimeVal **wait)
{
GSList *it, *next;
g_get_current_time(&loop->now);
for (it = loop->timers; it; it = next) {
- ObMainLoopTimer *curr;
+ ObtMainLoopTimer *curr;
next = g_slist_next(it);
--- /dev/null
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ obt/mainloop.h for the Openbox window manager
+ Copyright (c) 2006 Mikael Magnusson
+ Copyright (c) 2003-2007 Dana Jansens
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ See the COPYING file for a copy of the GNU General Public License.
+*/
+
+#ifndef __obt_mainloop_h
+#define __obt_mainloop_h
+
+#include <X11/Xlib.h>
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct _ObtMainLoop ObtMainLoop;
+
+ObtMainLoop *obt_main_loop_new(void);
+void obt_main_loop_ref(ObtMainLoop *loop);
+void obt_main_loop_unref(ObtMainLoop *loop);
+
+typedef void (*ObtMainLoopXHandler) (const XEvent *e, gpointer data);
+
+void obt_main_loop_x_add(ObtMainLoop *loop,
+ ObtMainLoopXHandler handler,
+ gpointer data,
+ GDestroyNotify notify);
+void obt_main_loop_x_remove(ObtMainLoop *loop,
+ ObtMainLoopXHandler handler);
+
+typedef void (*ObtMainLoopFdHandler) (gint fd, gpointer data);
+
+void obt_main_loop_fd_add(ObtMainLoop *loop,
+ gint fd,
+ ObtMainLoopFdHandler handler,
+ gpointer data,
+ GDestroyNotify notify);
+void obt_main_loop_fd_remove(ObtMainLoop *loop,
+ gint fd);
+
+typedef void (*ObtMainLoopSignalHandler) (gint signal, gpointer data);
+
+void obt_main_loop_signal_add(ObtMainLoop *loop,
+ gint signal,
+ ObtMainLoopSignalHandler handler,
+ gpointer data,
+ GDestroyNotify notify);
+void obt_main_loop_signal_remove(ObtMainLoop *loop,
+ ObtMainLoopSignalHandler handler);
+
+void obt_main_loop_timeout_add(ObtMainLoop *loop,
+ gulong microseconds,
+ GSourceFunc handler,
+ gpointer data,
+ GEqualFunc cmp,
+ GDestroyNotify notify);
+void obt_main_loop_timeout_remove(ObtMainLoop *loop,
+ GSourceFunc handler);
+void obt_main_loop_timeout_remove_data(ObtMainLoop *loop,
+ GSourceFunc handler,
+ gpointer data,
+ gboolean cancel_dest);
+
+void obt_main_loop_run(ObtMainLoop *loop);
+void obt_main_loop_exit(ObtMainLoop *loop);
+
+G_END_DECLS
+
+#endif
--- /dev/null
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+xcflags=@X_CFLAGS@
+xlibs=@X_LIBS@
+
+Name: Obt
+Description: Openbox Toolkit Library
+Version: @OBT_VERSION@
+Requires: glib-2.0
+Libs: -L${libdir} -lobrender ${xlibs}
+Cflags: -I${includedir}/openbox/@OBT_VERSION@ ${xcflags}
--- /dev/null
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ obt/paths.c for the Openbox window manager
+ Copyright (c) 2003-2007 Dana Jansens
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ See the COPYING file for a copy of the GNU General Public License.
+*/
+
+#include "obt/paths.h"
+#include "obt/util.h"
+
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif
+
+struct _ObtPaths
+{
+ gint ref;
+ gchar *config_home;
+ gchar *data_home;
+ gchar *cache_home;
+ GSList *config_dirs;
+ GSList *data_dirs;
+};
+
+static gint slist_path_cmp(const gchar *a, const gchar *b)
+{
+ return strcmp(a, b);
+}
+
+typedef GSList* (*GSListFunc) (gpointer list, gconstpointer data);
+
+static GSList* slist_path_add(GSList *list, gpointer data, GSListFunc func)
+{
+ g_assert(func);
+
+ if (!data)
+ return list;
+
+ if (!g_slist_find_custom(list, data, (GCompareFunc) slist_path_cmp))
+ list = func(list, data);
+ else
+ g_free(data);
+
+ return list;
+}
+
+static GSList* split_paths(const gchar *paths)
+{
+ GSList *list = NULL;
+ gchar **spl, **it;
+
+ if (!paths)
+ return NULL;
+ spl = g_strsplit(paths, ":", -1);
+ for (it = spl; *it; ++it)
+ list = slist_path_add(list, *it, (GSListFunc) g_slist_append);
+ g_free(spl);
+ return list;
+}
+
+ObtPaths* obt_paths_new(void)
+{
+ ObtPaths *p;
+ const gchar *path;
+
+ p = g_new0(ObtPaths, 1);
+ p->ref = 1;
+
+ path = g_getenv("XDG_CONFIG_HOME");
+ if (path && path[0] != '\0') /* not unset or empty */
+ p->config_home = g_build_filename(path, NULL);
+ else
+ p->config_home = g_build_filename(g_get_home_dir(), ".config", NULL);
+
+ path = g_getenv("XDG_DATA_HOME");
+ if (path && path[0] != '\0') /* not unset or empty */
+ p->data_home = g_build_filename(path, NULL);
+ else
+ p->data_home = g_build_filename(g_get_home_dir(), ".local",
+ "share", NULL);
+
+ path = g_getenv("XDG_CACHE_HOME");
+ if (path && path[0] != '\0') /* not unset or empty */
+ p->cache_home = g_build_filename(path, NULL);
+ else
+ p->cache_home = g_build_filename(g_get_home_dir(), ".cache", NULL);
+
+ path = g_getenv("XDG_CONFIG_DIRS");
+ if (path && path[0] != '\0') /* not unset or empty */
+ p->config_dirs = split_paths(path);
+ else {
+ p->config_dirs = slist_path_add(p->config_dirs,
+ g_strdup(CONFIGDIR),
+ (GSListFunc) g_slist_append);
+ p->config_dirs = slist_path_add(p->config_dirs,
+ g_build_filename
+ (G_DIR_SEPARATOR_S,
+ "etc", "xdg", NULL),
+ (GSListFunc) g_slist_append);
+ }
+ p->config_dirs = slist_path_add(p->config_dirs,
+ g_strdup(p->config_home),
+ (GSListFunc) g_slist_prepend);
+
+ path = g_getenv("XDG_DATA_DIRS");
+ if (path && path[0] != '\0') /* not unset or empty */
+ p->data_dirs = split_paths(path);
+ else {
+ p->data_dirs = slist_path_add(p->data_dirs,
+ g_strdup(DATADIR),
+ (GSListFunc) g_slist_append);
+ p->data_dirs = slist_path_add(p->data_dirs,
+ g_build_filename
+ (G_DIR_SEPARATOR_S,
+ "usr", "local", "share", NULL),
+ (GSListFunc) g_slist_append);
+ p->data_dirs = slist_path_add(p->data_dirs,
+ g_build_filename
+ (G_DIR_SEPARATOR_S,
+ "usr", "share", NULL),
+ (GSListFunc) g_slist_append);
+ }
+ p->data_dirs = slist_path_add(p->data_dirs,
+ g_strdup(p->data_home),
+ (GSListFunc) g_slist_prepend);
+ return p;
+}
+
+void obt_paths_ref(ObtPaths *p)
+{
+ ++p->ref;
+}
+
+void obt_paths_unref(ObtPaths *p)
+{
+ if (p && --p->ref == 0) {
+ GSList *it;
+
+ for (it = p->config_dirs; it; it = g_slist_next(it))
+ g_free(it->data);
+ g_slist_free(p->config_dirs);
+ for (it = p->data_dirs; it; it = g_slist_next(it))
+ g_free(it->data);
+ g_slist_free(p->data_dirs);
+ g_free(p->config_home);
+ g_free(p->data_home);
+ g_free(p->cache_home);
+
+ obt_free0(p, ObtPaths, 1);
+ }
+}
+
+gchar *obt_paths_expand_tilde(const gchar *f)
+{
+ gchar *ret;
+ GRegex *regex;
+
+ if (!f)
+ return NULL;
+
+ regex = g_regex_new("(?:^|(?<=[ \\t]))~(?=[/ \\t$])", G_REGEX_MULTILINE | G_REGEX_RAW, 0, NULL);
+ ret = g_regex_replace_literal(regex, f, -1, 0, g_get_home_dir(), 0, NULL);
+ g_regex_unref(regex);
+
+ return ret;
+}
+
+gboolean obt_paths_mkdir(const gchar *path, gint mode)
+{
+ gboolean ret = TRUE;
+
+ g_return_val_if_fail(path != NULL, FALSE);
+ g_return_val_if_fail(path[0] != '\0', FALSE);
+
+ if (!g_file_test(path, G_FILE_TEST_IS_DIR))
+ if (mkdir(path, mode) == -1)
+ ret = FALSE;
+
+ return ret;
+}
+
+gboolean obt_paths_mkdir_path(const gchar *path, gint mode)
+{
+ gboolean ret = TRUE;
+
+ g_return_val_if_fail(path != NULL, FALSE);
+ g_return_val_if_fail(path[0] == '/', FALSE);
+
+ if (!g_file_test(path, G_FILE_TEST_IS_DIR)) {
+ gchar *c, *e;
+
+ c = g_strdup(path);
+ e = c;
+ while ((e = strchr(e + 1, '/'))) {
+ *e = '\0';
+ if (!(ret = obt_paths_mkdir(c, mode)))
+ goto parse_mkdir_path_end;
+ *e = '/';
+ }
+ ret = obt_paths_mkdir(c, mode);
+
+ parse_mkdir_path_end:
+ g_free(c);
+ }
+
+ return ret;
+}
+
+const gchar* obt_paths_config_home(ObtPaths *p)
+{
+ return p->config_home;
+}
+
+const gchar* obt_paths_data_home(ObtPaths *p)
+{
+ return p->data_home;
+}
+
+const gchar* obt_paths_cache_home(ObtPaths *p)
+{
+ return p->cache_home;
+}
+
+GSList* obt_paths_config_dirs(ObtPaths *p)
+{
+ return p->config_dirs;
+}
+
+GSList* obt_paths_data_dirs(ObtPaths *p)
+{
+ return p->data_dirs;
+}
--- /dev/null
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ obt/paths.h for the Openbox window manager
+ Copyright (c) 2003-2007 Dana Jansens
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ See the COPYING file for a copy of the GNU General Public License.
+*/
+
+#ifndef __obt_paths_h
+#define __obt_paths_h
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct _ObtPaths ObtPaths;
+
+ObtPaths* obt_paths_new(void);
+void obt_paths_ref(ObtPaths *p);
+void obt_paths_unref(ObtPaths *p);
+
+const gchar* obt_paths_config_home(ObtPaths *p);
+const gchar* obt_paths_data_home(ObtPaths *p);
+const gchar* obt_paths_cache_home(ObtPaths *p);
+GSList* obt_paths_config_dirs(ObtPaths *p);
+GSList* obt_paths_data_dirs(ObtPaths *p);
+
+gchar *obt_paths_expand_tilde(const gchar *f);
+gboolean obt_paths_mkdir(const gchar *path, gint mode);
+gboolean obt_paths_mkdir_path(const gchar *path, gint mode);
+
+G_END_DECLS
+
+#endif
--- /dev/null
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ obt/prop.c for the Openbox window manager
+ Copyright (c) 2006 Mikael Magnusson
+ Copyright (c) 2003-2007 Dana Jansens
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ See the COPYING file for a copy of the GNU General Public License.
+*/
+
+#include "obt/prop.h"
+#include "obt/display.h"
+
+#include <X11/Xatom.h>
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif
+
+Atom prop_atoms[OBT_PROP_NUM_ATOMS];
+gboolean prop_started = FALSE;
+
+#define CREATE_NAME(var, name) (prop_atoms[OBT_PROP_##var] = \
+ XInternAtom((obt_display), (name), FALSE))
+#define CREATE(var) CREATE_NAME(var, #var)
+#define CREATE_(var) CREATE_NAME(var, "_" #var)
+
+void obt_prop_startup(void)
+{
+ if (prop_started) return;
+ prop_started = TRUE;
+
+ g_assert(obt_display);
+
+ CREATE(CARDINAL);
+ CREATE(WINDOW);
+ CREATE(PIXMAP);
+ CREATE(ATOM);
+ CREATE(STRING);
+ CREATE_NAME(UTF8, "UTF8_STRING");
+
+ CREATE(MANAGER);
+
+ CREATE(WM_COLORMAP_WINDOWS);
+ CREATE(WM_PROTOCOLS);
+ CREATE(WM_STATE);
+ CREATE(WM_CHANGE_STATE);
+ CREATE(WM_DELETE_WINDOW);
+ CREATE(WM_TAKE_FOCUS);
+ CREATE(WM_NAME);
+ CREATE(WM_ICON_NAME);
+ CREATE(WM_CLASS);
+ CREATE(WM_WINDOW_ROLE);
+ CREATE(WM_CLIENT_MACHINE);
+ CREATE(WM_COMMAND);
+ CREATE(WM_CLIENT_LEADER);
+ CREATE(WM_TRANSIENT_FOR);
+ CREATE_(MOTIF_WM_HINTS);
+ CREATE_(MOTIF_WM_INFO);
+
+ CREATE(SM_CLIENT_ID);
+
+ CREATE_(NET_WM_FULL_PLACEMENT);
+
+ CREATE_(NET_SUPPORTED);
+ CREATE_(NET_CLIENT_LIST);
+ CREATE_(NET_CLIENT_LIST_STACKING);
+ CREATE_(NET_NUMBER_OF_DESKTOPS);
+ CREATE_(NET_DESKTOP_GEOMETRY);
+ CREATE_(NET_DESKTOP_VIEWPORT);
+ CREATE_(NET_CURRENT_DESKTOP);
+ CREATE_(NET_DESKTOP_NAMES);
+ CREATE_(NET_ACTIVE_WINDOW);
+/* CREATE_(NET_RESTACK_WINDOW);*/
+ CREATE_(NET_WORKAREA);
+ CREATE_(NET_SUPPORTING_WM_CHECK);
+ CREATE_(NET_DESKTOP_LAYOUT);
+ CREATE_(NET_SHOWING_DESKTOP);
+
+ CREATE_(NET_CLOSE_WINDOW);
+ CREATE_(NET_WM_MOVERESIZE);
+ CREATE_(NET_MOVERESIZE_WINDOW);
+ CREATE_(NET_REQUEST_FRAME_EXTENTS);
+ CREATE_(NET_RESTACK_WINDOW);
+
+ CREATE_(NET_STARTUP_ID);
+
+ CREATE_(NET_WM_NAME);
+ CREATE_(NET_WM_VISIBLE_NAME);
+ CREATE_(NET_WM_ICON_NAME);
+ CREATE_(NET_WM_VISIBLE_ICON_NAME);
+ CREATE_(NET_WM_DESKTOP);
+ CREATE_(NET_WM_WINDOW_TYPE);
+ CREATE_(NET_WM_STATE);
+ CREATE_(NET_WM_STRUT);
+ CREATE_(NET_WM_STRUT_PARTIAL);
+ CREATE_(NET_WM_ICON);
+ CREATE_(NET_WM_ICON_GEOMETRY);
+ CREATE_(NET_WM_PID);
+ CREATE_(NET_WM_ALLOWED_ACTIONS);
+ CREATE_(NET_WM_USER_TIME);
+/* CREATE_(NET_WM_USER_TIME_WINDOW); */
+ CREATE_(KDE_NET_WM_FRAME_STRUT);
+ CREATE_(NET_FRAME_EXTENTS);
+
+ CREATE_(NET_WM_PING);
+#ifdef SYNC
+ CREATE_(NET_WM_SYNC_REQUEST);
+ CREATE_(NET_WM_SYNC_REQUEST_COUNTER);
+#endif
+
+ CREATE_(NET_WM_WINDOW_TYPE_DESKTOP);
+ CREATE_(NET_WM_WINDOW_TYPE_DOCK);
+ CREATE_(NET_WM_WINDOW_TYPE_TOOLBAR);
+ CREATE_(NET_WM_WINDOW_TYPE_MENU);
+ CREATE_(NET_WM_WINDOW_TYPE_UTILITY);
+ CREATE_(NET_WM_WINDOW_TYPE_SPLASH);
+ CREATE_(NET_WM_WINDOW_TYPE_DIALOG);
+ CREATE_(NET_WM_WINDOW_TYPE_NORMAL);
+ CREATE_(NET_WM_WINDOW_TYPE_POPUP_MENU);
+
+ prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_SIZE_TOPLEFT] = 0;
+ prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_SIZE_TOP] = 1;
+ prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_SIZE_TOPRIGHT] = 2;
+ prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_SIZE_RIGHT] = 3;
+ prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT] = 4;
+ prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_SIZE_BOTTOM] = 5;
+ prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT] = 6;
+ prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_SIZE_LEFT] = 7;
+ prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_MOVE] = 8;
+ prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_SIZE_KEYBOARD] = 9;
+ prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_MOVE_KEYBOARD] = 10;
+ prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_CANCEL] = 11;
+
+ CREATE_(NET_WM_ACTION_MOVE);
+ CREATE_(NET_WM_ACTION_RESIZE);
+ CREATE_(NET_WM_ACTION_MINIMIZE);
+ CREATE_(NET_WM_ACTION_SHADE);
+ CREATE_(NET_WM_ACTION_MAXIMIZE_HORZ);
+ CREATE_(NET_WM_ACTION_MAXIMIZE_VERT);
+ CREATE_(NET_WM_ACTION_FULLSCREEN);
+ CREATE_(NET_WM_ACTION_CHANGE_DESKTOP);
+ CREATE_(NET_WM_ACTION_CLOSE);
+ CREATE_(NET_WM_ACTION_ABOVE);
+ CREATE_(NET_WM_ACTION_BELOW);
+
+ CREATE_(NET_WM_STATE_MODAL);
+/* CREATE_(NET_WM_STATE_STICKY);*/
+ CREATE_(NET_WM_STATE_MAXIMIZED_VERT);
+ CREATE_(NET_WM_STATE_MAXIMIZED_HORZ);
+ CREATE_(NET_WM_STATE_SHADED);
+ CREATE_(NET_WM_STATE_SKIP_TASKBAR);
+ CREATE_(NET_WM_STATE_SKIP_PAGER);
+ CREATE_(NET_WM_STATE_HIDDEN);
+ CREATE_(NET_WM_STATE_FULLSCREEN);
+ CREATE_(NET_WM_STATE_ABOVE);
+ CREATE_(NET_WM_STATE_BELOW);
+ CREATE_(NET_WM_STATE_DEMANDS_ATTENTION);
+
+ prop_atoms[OBT_PROP_NET_WM_STATE_ADD] = 1;
+ prop_atoms[OBT_PROP_NET_WM_STATE_REMOVE] = 0;
+ prop_atoms[OBT_PROP_NET_WM_STATE_TOGGLE] = 2;
+
+ prop_atoms[OBT_PROP_NET_WM_ORIENTATION_HORZ] = 0;
+ prop_atoms[OBT_PROP_NET_WM_ORIENTATION_VERT] = 1;
+ prop_atoms[OBT_PROP_NET_WM_TOPLEFT] = 0;
+ prop_atoms[OBT_PROP_NET_WM_TOPRIGHT] = 1;
+ prop_atoms[OBT_PROP_NET_WM_BOTTOMRIGHT] = 2;
+ prop_atoms[OBT_PROP_NET_WM_BOTTOMLEFT] = 3;
+
+ CREATE_(KDE_WM_CHANGE_STATE);
+ CREATE_(KDE_NET_WM_WINDOW_TYPE_OVERRIDE);
+
+/*
+ CREATE_NAME(ROOTPMAPId, "_XROOTPMAP_ID");
+ CREATE_NAME(ESETROOTId, "ESETROOT_PMAP_ID");
+*/
+
+ CREATE_(OPENBOX_PID);
+ CREATE_(OB_THEME);
+ CREATE_(OB_CONFIG_FILE);
+ CREATE_(OB_WM_ACTION_UNDECORATE);
+ CREATE_(OB_WM_STATE_UNDECORATED);
+ CREATE_(OB_CONTROL);
+ CREATE_(OB_VERSION);
+ CREATE_(OB_APP_ROLE);
+ CREATE_(OB_APP_NAME);
+ CREATE_(OB_APP_CLASS);
+ CREATE_(OB_APP_TYPE);
+}
+
+Atom obt_prop_atom(ObtPropAtom a)
+{
+ g_assert(prop_started);
+ g_assert(a < OBT_PROP_NUM_ATOMS);
+ return prop_atoms[a];
+}
+
+static gboolean get_prealloc(Window win, Atom prop, Atom type, gint size,
+ guchar *data, gulong num)
+{
+ gboolean ret = FALSE;
+ gint res;
+ guchar *xdata = NULL;
+ Atom ret_type;
+ gint ret_size;
+ gulong ret_items, bytes_left;
+ glong num32 = 32 / size * num; /* num in 32-bit elements */
+
+ res = XGetWindowProperty(obt_display, win, prop, 0l, num32,
+ FALSE, type, &ret_type, &ret_size,
+ &ret_items, &bytes_left, &xdata);
+ if (res == Success && ret_items && xdata) {
+ if (ret_size == size && ret_items >= num) {
+ guint i;
+ for (i = 0; i < num; ++i)
+ switch (size) {
+ case 8:
+ data[i] = xdata[i];
+ break;
+ case 16:
+ ((guint16*)data)[i] = ((gushort*)xdata)[i];
+ break;
+ case 32:
+ ((guint32*)data)[i] = ((gulong*)xdata)[i];
+ break;
+ default:
+ g_assert_not_reached(); /* unhandled size */
+ }
+ ret = TRUE;
+ }
+ XFree(xdata);
+ }
+ return ret;
+}
+
+static gboolean get_all(Window win, Atom prop, Atom type, gint size,
+ guchar **data, guint *num)
+{
+ gboolean ret = FALSE;
+ gint res;
+ guchar *xdata = NULL;
+ Atom ret_type;
+ gint ret_size;
+ gulong ret_items, bytes_left;
+
+ res = XGetWindowProperty(obt_display, win, prop, 0l, G_MAXLONG,
+ FALSE, type, &ret_type, &ret_size,
+ &ret_items, &bytes_left, &xdata);
+ if (res == Success) {
+ if (ret_size == size && ret_items > 0) {
+ guint i;
+
+ *data = g_malloc(ret_items * (size / 8));
+ for (i = 0; i < ret_items; ++i)
+ switch (size) {
+ case 8:
+ (*data)[i] = xdata[i];
+ break;
+ case 16:
+ ((guint16*)*data)[i] = ((gushort*)xdata)[i];
+ break;
+ case 32:
+ ((guint32*)*data)[i] = ((gulong*)xdata)[i];
+ break;
+ default:
+ g_assert_not_reached(); /* unhandled size */
+ }
+ *num = ret_items;
+ ret = TRUE;
+ }
+ XFree(xdata);
+ }
+ return ret;
+}
+
+static gboolean get_stringlist(Window win, Atom prop, gchar ***list, gint *nstr)
+{
+ XTextProperty tprop;
+ gboolean ret = FALSE;
+
+ if (XGetTextProperty(obt_display, win, &tprop, prop) && tprop.nitems) {
+ if (XTextPropertyToStringList(&tprop, list, nstr))
+ ret = TRUE;
+ XFree(tprop.value);
+ }
+ return ret;
+}
+
+gboolean obt_prop_get32(Window win, Atom prop, Atom type, guint32 *ret)
+{
+ return get_prealloc(win, prop, type, 32, (guchar*)ret, 1);
+}
+
+gboolean obt_prop_get_array32(Window win, Atom prop, Atom type, guint32 **ret,
+ guint *nret)
+{
+ return get_all(win, prop, type, 32, (guchar**)ret, nret);
+}
+
+gboolean obt_prop_get_string_locale(Window win, Atom prop, gchar **ret)
+{
+ gchar **list;
+ gint nstr;
+ gchar *s;
+
+ if (get_stringlist(win, prop, &list, &nstr) && nstr) {
+ s = g_locale_to_utf8(list[0], -1, NULL, NULL, NULL);
+ XFreeStringList(list);
+ if (s) {
+ *ret = s;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+gboolean obt_prop_get_strings_locale(Window win, Atom prop, gchar ***ret)
+{
+ GSList *strs = NULL, *it;
+ gchar *raw, *p;
+ guint num, i, count = 0;
+
+ if (get_all(win, prop, OBT_PROP_ATOM(STRING), 8,
+ (guchar**)&raw, &num))
+ {
+ p = raw;
+ while (p < raw + num) {
+ ++count;
+ strs = g_slist_append(strs, p);
+ p += strlen(p) + 1; /* next string */
+ }
+
+ *ret = g_new0(gchar*, count + 1);
+ (*ret)[count] = NULL; /* null terminated list */
+
+ for (i = 0, it = strs; it; ++i, it = g_slist_next(it)) {
+ (*ret)[i] = g_locale_to_utf8(it->data, -1, NULL, NULL, NULL);
+ /* make sure translation did not fail */
+ if (!(*ret)[i])
+ (*ret)[i] = g_strdup("");
+ }
+ g_free(raw);
+ g_slist_free(strs);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+gboolean obt_prop_get_string_utf8(Window win, Atom prop, gchar **ret)
+{
+ gchar *raw;
+ gchar *str;
+ guint num;
+
+ if (get_all(win, prop, OBT_PROP_ATOM(UTF8), 8,
+ (guchar**)&raw, &num))
+ {
+ str = g_strndup(raw, num); /* grab the first string from the list */
+ g_free(raw);
+ if (g_utf8_validate(str, -1, NULL)) {
+ *ret = str;
+ return TRUE;
+ }
+ g_free(str);
+ }
+ return FALSE;
+}
+
+gboolean obt_prop_get_strings_utf8(Window win, Atom prop, gchar ***ret)
+{
+ GSList *strs = NULL, *it;
+ gchar *raw, *p;
+ guint num, i, count = 0;
+
+ if (get_all(win, prop, OBT_PROP_ATOM(UTF8), 8,
+ (guchar**)&raw, &num))
+ {
+ p = raw;
+ while (p < raw + num) {
+ ++count;
+ strs = g_slist_append(strs, p);
+ p += strlen(p) + 1; /* next string */
+ }
+
+ *ret = g_new0(gchar*, count + 1);
+
+ for (i = 0, it = strs; it; ++i, it = g_slist_next(it)) {
+ if (g_utf8_validate(it->data, -1, NULL))
+ (*ret)[i] = g_strdup(it->data);
+ else
+ (*ret)[i] = g_strdup("");
+ }
+ g_free(raw);
+ g_slist_free(strs);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void obt_prop_set32(Window win, Atom prop, Atom type, gulong val)
+{
+ XChangeProperty(obt_display, win, prop, type, 32, PropModeReplace,
+ (guchar*)&val, 1);
+}
+
+void obt_prop_set_array32(Window win, Atom prop, Atom type, gulong *val,
+ guint num)
+{
+ XChangeProperty(obt_display, win, prop, type, 32, PropModeReplace,
+ (guchar*)val, num);
+}
+
+void obt_prop_set_string_locale(Window win, Atom prop, const gchar *val)
+{
+ gchar const *s[2] = { val, NULL };
+ obt_prop_set_strings_locale(win, prop, s);
+}
+
+void obt_prop_set_strings_locale(Window win, Atom prop, const gchar **strs)
+{
+ gint i, count;
+ gchar **lstrs;
+ XTextProperty tprop;
+
+ /* count the strings in strs, and convert them to the locale format */
+ for (count = 0; strs[count]; ++count);
+ lstrs = g_new0(char*, count);
+ for (i = 0; i < count; ++i) {
+ lstrs[i] = g_locale_from_utf8(strs[i], -1, NULL, NULL, NULL);
+ if (!lstrs[i]) {
+ lstrs[i] = g_strdup(""); /* make it an empty string */
+ g_warning("Unable to translate string '%s' from UTF8 to locale "
+ "format", strs[i]);
+ }
+ }
+
+
+ XStringListToTextProperty(lstrs, count, &tprop);
+ XSetTextProperty(obt_display, win, &tprop, prop);
+ XFree(tprop.value);
+}
+
+void obt_prop_set_string_utf8(Window win, Atom prop, const gchar *val)
+{
+ XChangeProperty(obt_display, win, prop, OBT_PROP_ATOM(UTF8), 8,
+ PropModeReplace, (const guchar*)val, strlen(val));
+}
+
+void obt_prop_set_strings_utf8(Window win, Atom prop, const gchar **strs)
+{
+ GString *str;
+ gchar const **s;
+
+ str = g_string_sized_new(0);
+ for (s = strs; *s; ++s) {
+ str = g_string_append(str, *s);
+ str = g_string_append_c(str, '\0');
+ }
+ XChangeProperty(obt_display, win, prop, obt_prop_atom(OBT_PROP_UTF8), 8,
+ PropModeReplace, (guchar*)str->str, str->len);
+ g_string_free(str, TRUE);
+}
+
+void obt_prop_erase(Window win, Atom prop)
+{
+ XDeleteProperty(obt_display, win, prop);
+}
+
+void obt_prop_message(gint screen, Window about, Atom messagetype,
+ glong data0, glong data1, glong data2, glong data3,
+ glong data4, glong mask)
+{
+ obt_prop_message_to(obt_root(screen), about, messagetype,
+ data0, data1, data2, data3, data4, mask);
+}
+
+void obt_prop_message_to(Window to, Window about,
+ Atom messagetype,
+ glong data0, glong data1, glong data2, glong data3,
+ glong data4, glong mask)
+{
+ XEvent ce;
+ ce.xclient.type = ClientMessage;
+ ce.xclient.message_type = messagetype;
+ ce.xclient.display = obt_display;
+ ce.xclient.window = about;
+ ce.xclient.format = 32;
+ ce.xclient.data.l[0] = data0;
+ ce.xclient.data.l[1] = data1;
+ ce.xclient.data.l[2] = data2;
+ ce.xclient.data.l[3] = data3;
+ ce.xclient.data.l[4] = data4;
+ XSendEvent(obt_display, to, FALSE, mask, &ce);
+}
--- /dev/null
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ obt/prop.h for the Openbox window manager
+ Copyright (c) 2006 Mikael Magnusson
+ Copyright (c) 2003-2007 Dana Jansens
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ See the COPYING file for a copy of the GNU General Public License.
+*/
+
+#ifndef __obt_prop_h
+#define __obt_prop_h
+
+#include <X11/Xlib.h>
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef enum {
+ /* types */
+ OBT_PROP_CARDINAL, /*!< The atom which represents the Cardinal data type */
+ OBT_PROP_WINDOW, /*!< The atom which represents window ids */
+ OBT_PROP_PIXMAP, /*!< The atom which represents pixmap ids */
+ OBT_PROP_ATOM, /*!< The atom which represents atom values */
+ OBT_PROP_STRING, /*!< The atom which represents ascii strings */
+ OBT_PROP_UTF8, /*!< The atom which represents utf8-encoded strings */
+
+ /* selection stuff */
+ OBT_PROP_MANAGER,
+
+ /* window hints */
+ OBT_PROP_WM_COLORMAP_WINDOWS,
+ OBT_PROP_WM_PROTOCOLS,
+ OBT_PROP_WM_STATE,
+ OBT_PROP_WM_DELETE_WINDOW,
+ OBT_PROP_WM_TAKE_FOCUS,
+ OBT_PROP_WM_CHANGE_STATE,
+ OBT_PROP_WM_NAME,
+ OBT_PROP_WM_ICON_NAME,
+ OBT_PROP_WM_CLASS,
+ OBT_PROP_WM_WINDOW_ROLE,
+ OBT_PROP_WM_CLIENT_MACHINE,
+ OBT_PROP_WM_COMMAND,
+ OBT_PROP_WM_CLIENT_LEADER,
+ OBT_PROP_WM_TRANSIENT_FOR,
+ OBT_PROP_MOTIF_WM_HINTS,
+ OBT_PROP_MOTIF_WM_INFO,
+
+ /* SM atoms */
+ OBT_PROP_SM_CLIENT_ID,
+
+ /* NETWM atoms */
+
+ /* Atoms that are used inside messages - these don't go in net_supported */
+
+ OBT_PROP_NET_WM_MOVERESIZE_SIZE_TOPLEFT,
+ OBT_PROP_NET_WM_MOVERESIZE_SIZE_TOP,
+ OBT_PROP_NET_WM_MOVERESIZE_SIZE_TOPRIGHT,
+ OBT_PROP_NET_WM_MOVERESIZE_SIZE_RIGHT,
+ OBT_PROP_NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT,
+ OBT_PROP_NET_WM_MOVERESIZE_SIZE_BOTTOM,
+ OBT_PROP_NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT,
+ OBT_PROP_NET_WM_MOVERESIZE_SIZE_LEFT,
+ OBT_PROP_NET_WM_MOVERESIZE_MOVE,
+ OBT_PROP_NET_WM_MOVERESIZE_SIZE_KEYBOARD,
+ OBT_PROP_NET_WM_MOVERESIZE_MOVE_KEYBOARD,
+ OBT_PROP_NET_WM_MOVERESIZE_CANCEL,
+
+ OBT_PROP_NET_WM_STATE_ADD,
+ OBT_PROP_NET_WM_STATE_REMOVE,
+ OBT_PROP_NET_WM_STATE_TOGGLE,
+
+ OBT_PROP_NET_WM_ORIENTATION_HORZ,
+ OBT_PROP_NET_WM_ORIENTATION_VERT,
+ OBT_PROP_NET_WM_TOPLEFT,
+ OBT_PROP_NET_WM_TOPRIGHT,
+ OBT_PROP_NET_WM_BOTTOMRIGHT,
+ OBT_PROP_NET_WM_BOTTOMLEFT,
+
+ OBT_PROP_NET_WM_WINDOW_TYPE_POPUP_MENU,
+
+ OBT_PROP_PRIVATE_PADDING1,
+ OBT_PROP_PRIVATE_PADDING2,
+ OBT_PROP_PRIVATE_PADDING3,
+ OBT_PROP_PRIVATE_PADDING4,
+ OBT_PROP_PRIVATE_PADDING5,
+ OBT_PROP_PRIVATE_PADDING6,
+ OBT_PROP_PRIVATE_PADDING7,
+ OBT_PROP_PRIVATE_PADDING8,
+ OBT_PROP_PRIVATE_PADDING9,
+ OBT_PROP_PRIVATE_PADDING10,
+ OBT_PROP_PRIVATE_PADDING11,
+ OBT_PROP_PRIVATE_PADDING12,
+
+ /* Everything below here must go in net_supported on the root window */
+
+ /* root window properties */
+ OBT_PROP_NET_SUPPORTED,
+ OBT_PROP_NET_CLIENT_LIST,
+ OBT_PROP_NET_CLIENT_LIST_STACKING,
+ OBT_PROP_NET_NUMBER_OF_DESKTOPS,
+ OBT_PROP_NET_DESKTOP_GEOMETRY,
+ OBT_PROP_NET_DESKTOP_VIEWPORT,
+ OBT_PROP_NET_CURRENT_DESKTOP,
+ OBT_PROP_NET_DESKTOP_NAMES,
+ OBT_PROP_NET_ACTIVE_WINDOW,
+/* Atom net_restack_window;*/
+ OBT_PROP_NET_WORKAREA,
+ OBT_PROP_NET_SUPPORTING_WM_CHECK,
+ OBT_PROP_NET_DESKTOP_LAYOUT,
+ OBT_PROP_NET_SHOWING_DESKTOP,
+
+ /* root window messages */
+ OBT_PROP_NET_CLOSE_WINDOW,
+ OBT_PROP_NET_WM_MOVERESIZE,
+ OBT_PROP_NET_MOVERESIZE_WINDOW,
+ OBT_PROP_NET_REQUEST_FRAME_EXTENTS,
+ OBT_PROP_NET_RESTACK_WINDOW,
+
+ /* helpful hints to apps that aren't used for anything */
+ OBT_PROP_NET_WM_FULL_PLACEMENT,
+
+ /* startup-notification extension */
+ OBT_PROP_NET_STARTUP_ID,
+
+ /* application window properties */
+ OBT_PROP_NET_WM_NAME,
+ OBT_PROP_NET_WM_VISIBLE_NAME,
+ OBT_PROP_NET_WM_ICON_NAME,
+ OBT_PROP_NET_WM_VISIBLE_ICON_NAME,
+ OBT_PROP_NET_WM_DESKTOP,
+ OBT_PROP_NET_WM_WINDOW_TYPE,
+ OBT_PROP_NET_WM_STATE,
+ OBT_PROP_NET_WM_STRUT,
+ OBT_PROP_NET_WM_STRUT_PARTIAL,
+ OBT_PROP_NET_WM_ICON,
+ OBT_PROP_NET_WM_ICON_GEOMETRY,
+ OBT_PROP_NET_WM_PID,
+ OBT_PROP_NET_WM_ALLOWED_ACTIONS,
+ OBT_PROP_NET_WM_USER_TIME,
+/* OBT_PROP_NET_WM_USER_TIME_WINDOW, */
+ OBT_PROP_NET_FRAME_EXTENTS,
+
+ /* application protocols */
+ OBT_PROP_NET_WM_PING,
+#ifdef SYNC
+ OBT_PROP_NET_WM_SYNC_REQUEST,
+ OBT_PROP_NET_WM_SYNC_REQUEST_COUNTER,
+#endif
+
+ OBT_PROP_NET_WM_WINDOW_TYPE_DESKTOP,
+ OBT_PROP_NET_WM_WINDOW_TYPE_DOCK,
+ OBT_PROP_NET_WM_WINDOW_TYPE_TOOLBAR,
+ OBT_PROP_NET_WM_WINDOW_TYPE_MENU,
+ OBT_PROP_NET_WM_WINDOW_TYPE_UTILITY,
+ OBT_PROP_NET_WM_WINDOW_TYPE_SPLASH,
+ OBT_PROP_NET_WM_WINDOW_TYPE_DIALOG,
+ OBT_PROP_NET_WM_WINDOW_TYPE_NORMAL,
+
+ OBT_PROP_NET_WM_ACTION_MOVE,
+ OBT_PROP_NET_WM_ACTION_RESIZE,
+ OBT_PROP_NET_WM_ACTION_MINIMIZE,
+ OBT_PROP_NET_WM_ACTION_SHADE,
+/* OBT_PROP_NET_WM_ACTION_STICK,*/
+ OBT_PROP_NET_WM_ACTION_MAXIMIZE_HORZ,
+ OBT_PROP_NET_WM_ACTION_MAXIMIZE_VERT,
+ OBT_PROP_NET_WM_ACTION_FULLSCREEN,
+ OBT_PROP_NET_WM_ACTION_CHANGE_DESKTOP,
+ OBT_PROP_NET_WM_ACTION_CLOSE,
+ OBT_PROP_NET_WM_ACTION_ABOVE,
+ OBT_PROP_NET_WM_ACTION_BELOW,
+
+ OBT_PROP_NET_WM_STATE_MODAL,
+/* OBT_PROP_NET_WM_STATE_STICKY,*/
+ OBT_PROP_NET_WM_STATE_MAXIMIZED_VERT,
+ OBT_PROP_NET_WM_STATE_MAXIMIZED_HORZ,
+ OBT_PROP_NET_WM_STATE_SHADED,
+ OBT_PROP_NET_WM_STATE_SKIP_TASKBAR,
+ OBT_PROP_NET_WM_STATE_SKIP_PAGER,
+ OBT_PROP_NET_WM_STATE_HIDDEN,
+ OBT_PROP_NET_WM_STATE_FULLSCREEN,
+ OBT_PROP_NET_WM_STATE_ABOVE,
+ OBT_PROP_NET_WM_STATE_BELOW,
+ OBT_PROP_NET_WM_STATE_DEMANDS_ATTENTION,
+
+ /* KDE atoms */
+
+ OBT_PROP_KDE_WM_CHANGE_STATE,
+ OBT_PROP_KDE_NET_WM_FRAME_STRUT,
+ OBT_PROP_KDE_NET_WM_WINDOW_TYPE_OVERRIDE,
+
+/*
+ OBT_PROP_ROOTPMAPID,
+ OBT_PROP_ESETROOTID,
+*/
+
+ /* Openbox specific atoms */
+
+ OBT_PROP_OB_WM_ACTION_UNDECORATE,
+ OBT_PROP_OB_WM_STATE_UNDECORATED,
+ OBT_PROP_OPENBOX_PID, /* this is depreecated in favour of ob_control */
+ OBT_PROP_OB_THEME,
+ OBT_PROP_OB_CONFIG_FILE,
+ OBT_PROP_OB_CONTROL,
+ OBT_PROP_OB_VERSION,
+ OBT_PROP_OB_APP_ROLE,
+ OBT_PROP_OB_APP_NAME,
+ OBT_PROP_OB_APP_CLASS,
+ OBT_PROP_OB_APP_TYPE,
+
+ OBT_PROP_NUM_ATOMS
+} ObtPropAtom;
+
+Atom obt_prop_atom(ObtPropAtom a);
+
+gboolean obt_prop_get32(Window win, Atom prop, Atom type, guint32 *ret);
+gboolean obt_prop_get_array32(Window win, Atom prop, Atom type, guint32 **ret,
+ guint *nret);
+gboolean obt_prop_get_string_locale(Window win, Atom prop, gchar **ret);
+gboolean obt_prop_get_string_utf8(Window win, Atom prop, gchar **ret);
+gboolean obt_prop_get_strings_locale(Window win, Atom prop, gchar ***ret);
+gboolean obt_prop_get_strings_utf8(Window win, Atom prop, gchar ***ret);
+
+void obt_prop_set32(Window win, Atom prop, Atom type, gulong val);
+void obt_prop_set_array32(Window win, Atom prop, Atom type, gulong *val,
+ guint num);
+void obt_prop_set_string_locale(Window win, Atom prop, const gchar *val);
+void obt_prop_set_string_utf8(Window win, Atom prop, const gchar *val);
+void obt_prop_set_strings_locale(Window win, Atom prop, const gchar **strs);
+void obt_prop_set_strings_utf8(Window win, Atom prop, const gchar **strs);
+
+void obt_prop_erase(Window win, Atom prop);
+
+void obt_prop_message(gint screen, Window about, Atom messagetype,
+ glong data0, glong data1, glong data2, glong data3,
+ glong data4, glong mask);
+void obt_prop_message_to(Window to, Window about, Atom messagetype,
+ glong data0, glong data1, glong data2, glong data3,
+ glong data4, glong mask);
+
+#define OBT_PROP_ATOM(prop) obt_prop_atom(OBT_PROP_##prop)
+
+#define OBT_PROP_GET32(win, prop, type, ret) \
+ (obt_prop_get32(win, OBT_PROP_ATOM(prop), OBT_PROP_ATOM(type), ret))
+#define OBT_PROP_GETA32(win, prop, type, ret, nret) \
+ (obt_prop_get_array32(win, OBT_PROP_ATOM(prop), OBT_PROP_ATOM(type), \
+ ret, nret))
+#define OBT_PROP_GETS(win, prop, type, ret) \
+ (obt_prop_get_string_##type(win, OBT_PROP_ATOM(prop), ret))
+#define OBT_PROP_GETSS(win, prop, type, ret) \
+ (obt_prop_get_strings_##type(win, OBT_PROP_ATOM(prop), ret))
+
+#define OBT_PROP_SET32(win, prop, type, val) \
+ (obt_prop_set32(win, OBT_PROP_ATOM(prop), OBT_PROP_ATOM(type), val))
+#define OBT_PROP_SETA32(win, prop, type, val, num) \
+ (obt_prop_set_array32(win, OBT_PROP_ATOM(prop), OBT_PROP_ATOM(type), \
+ val, num))
+#define OBT_PROP_SETS(win, prop, type, val) \
+ (obt_prop_set_string_##type(win, OBT_PROP_ATOM(prop), val))
+#define OBT_PROP_SETSS(win, prop, type, strs) \
+ (obt_prop_set_strings_##type(win, OBT_PROP_ATOM(prop), strs))
+
+#define OBT_PROP_ERASE(win, prop) (obt_prop_erase(win, OBT_PROP_ATOM(prop)))
+
+#define OBT_PROP_MSG(screen, about, msgtype, data0, data1, data2, data3, \
+ data4) \
+ (obt_prop_message(screen, about, OBT_PROP_ATOM(msgtype), \
+ data0, data1, data2, data3, data4, \
+ SubstructureNotifyMask | SubstructureRedirectMask))
+
+#define OBT_PROP_MSG_TO(to, about, msgtype, data0, data1, data2, data3, \
+ data4, mask) \
+ (obt_prop_message_to(to, about, OBT_PROP_ATOM(msgtype), \
+ data0, data1, data2, data3, data4, mask))
+
+G_END_DECLS
+
+#endif /* __obt_prop_h */
--- /dev/null
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ obt/util.h for the Openbox window manager
+ Copyright (c) 2007 Dana Jansens
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ See the COPYING file for a copy of the GNU General Public License.
+*/
+
+#ifndef __obt_util_h
+#define __obt_util_h
+
+#include <glib.h>
+
+#ifdef HAVE_STRING_H
+# include <string.h> /* for memset() */
+#endif
+
+G_BEGIN_DECLS
+
+/* Util funcs */
+#define obt_free g_free
+#define obt_free0(p, type, num) memset((p), 0, sizeof(type) * (num)), g_free(p)
+
+G_END_DECLS
+
+
+#endif /*__obt_util_h*/
--- /dev/null
+#ifndef obt__version_h
+#define obt__version_h
+
+#define OBT_MAJOR_VERSION @OBT_MAJOR_VERSION@
+#define OBT_MINOR_VERSION @OBT_MINOR_VERSION@
+#define OBT_MICRO_VERSION @OBT_MICRO_VERSION@
+#define OBT_VERSION OBT_MAJOR_VERSION.OBT_MINOR_VERSION.OBT_MICRO_VERSION
+
+#define OBT_CHECK_VERSION(major,minor,micro) \
+ (OBT_MAJOR_VERSION > (major) || \
+ (OBT_MAJOR_VERSION == (major) && OBT_MINOR_VERSION > (minor)) || \
+ (OBT_MAJOR_VERSION == (major) && OBT_MINOR_VERSION == (minor) && \
+ OBT_MICRO_VERSION >= (micro)))
+
+#endif
--- /dev/null
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ obt/xevent.c for the Openbox window manager
+ Copyright (c) 2007 Dana Jansens
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ See the COPYING file for a copy of the GNU General Public License.
+*/
+
+#include "obt/xevent.h"
+#include "obt/mainloop.h"
+#include "obt/util.h"
+
+typedef struct _ObtXEventBinding ObtXEventBinding;
+
+struct _ObtXEventHandler
+{
+ gint ref;
+ ObtMainLoop *loop;
+
+ /* An array of hash tables where the key is the window, and the value is
+ the ObtXEventBinding */
+ GHashTable **bindings;
+ gint num_event_types; /* the length of the bindings array */
+};
+
+struct _ObtXEventBinding
+{
+ Window win;
+ ObtXEventCallback func;
+ gpointer data;
+};
+
+static void xevent_handler(const XEvent *e, gpointer data);
+static guint window_hash(Window *w) { return *w; }
+static gboolean window_comp(Window *w1, Window *w2) { return *w1 == *w2; }
+
+ObtXEventHandler* xevent_new(void)
+{
+ ObtXEventHandler *h;
+
+ h = g_new0(ObtXEventHandler, 1);
+ h->ref = 1;
+
+ return h;
+}
+
+void xevent_ref(ObtXEventHandler *h)
+{
+ ++h->ref;
+}
+
+void xevent_unref(ObtXEventHandler *h)
+{
+ if (h && --h->ref == 0) {
+ gint i;
+
+ if (h->loop)
+ obt_main_loop_x_remove(h->loop, xevent_handler);
+ for (i = 0; i < h->num_event_types; ++i)
+ g_hash_table_destroy(h->bindings[i]);
+ g_free(h->bindings);
+
+ obt_free0(h, ObtXEventHandler, 1);
+ }
+}
+
+void xevent_register(ObtXEventHandler *h, ObtMainLoop *loop)
+{
+ h->loop = loop;
+ obt_main_loop_x_add(loop, xevent_handler, h, NULL);
+}
+
+void xevent_set_handler(ObtXEventHandler *h, gint type, Window win,
+ ObtXEventCallback func, gpointer data)
+{
+ ObtXEventBinding *b;
+
+ g_assert(func);
+
+ /* make sure we have a spot for the event */
+ if (type + 1 < h->num_event_types) {
+ gint i;
+ h->bindings = g_renew(GHashTable*, h->bindings, type + 1);
+ for (i = h->num_event_types; i < type + 1; ++i)
+ h->bindings[i] = g_hash_table_new_full((GHashFunc)window_hash,
+ (GEqualFunc)window_comp,
+ NULL, g_free);
+ h->num_event_types = type + 1;
+ }
+
+ b = g_new(ObtXEventBinding, 1);
+ b->win = win;
+ b->func = func;
+ b->data = data;
+ g_hash_table_replace(h->bindings[type], &b->win, b);
+}
+
+void xevent_remove_handler(ObtXEventHandler *h, gint type, Window win)
+{
+ g_assert(type < h->num_event_types);
+ g_assert(win);
+
+ g_hash_table_remove(h->bindings[type], &win);
+}
+
+static void xevent_handler(const XEvent *e, gpointer data)
+{
+ ObtXEventHandler *h;
+ ObtXEventBinding *b;
+
+ h = data;
+
+ if (e->type < h->num_event_types) {
+ const gint all = OBT_XEVENT_ALL_WINDOWS;
+ /* run the all_windows handler first */
+ b = g_hash_table_lookup(h->bindings[e->xany.type], &all);
+ if (b) b->func(e, b->data);
+ /* then run the per-window handler */
+ b = g_hash_table_lookup(h->bindings[e->xany.type], &e->xany.window);
+ if (b) b->func(e, b->data);
+ }
+ else
+ g_message("Unhandled X Event type %d", e->xany.type);
+}
--- /dev/null
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ obt/xevent.h for the Openbox window manager
+ Copyright (c) 2007 Dana Jansens
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ See the COPYING file for a copy of the GNU General Public License.
+*/
+
+#ifndef __obt_xevent_h
+#define __obt_xevent_h
+
+#include <X11/Xlib.h>
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+struct _ObtMainLoop;
+
+typedef struct _ObtXEventHandler ObtXEventHandler;
+
+typedef void (*ObtXEventCallback) (const XEvent *e, gpointer data);
+
+ObtXEventHandler* xevent_new(void);
+void xevent_ref(ObtXEventHandler *h);
+void xevent_unref(ObtXEventHandler *h);
+
+void xevent_register(ObtXEventHandler *h,
+ struct _ObtMainLoop *loop);
+
+#define OBT_XEVENT_ALL_WINDOWS None
+
+void xevent_set_handler(ObtXEventHandler *h, gint type, Window win,
+ ObtXEventCallback func, gpointer data);
+void xevent_remove_handler(ObtXEventHandler *h, gint type, Window win);
+
+G_END_DECLS
+
+#endif /*__obt_xevent_h*/
--- /dev/null
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ obt/xml.c for the Openbox window manager
+ Copyright (c) 2003-2007 Dana Jansens
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ See the COPYING file for a copy of the GNU General Public License.
+*/
+
+#include "obt/xml.h"
+#include "obt/paths.h"
+
+#include <glib.h>
+
+#ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+struct Callback {
+ gchar *tag;
+ ObtXmlCallback func;
+ gpointer data;
+};
+
+struct _ObtXmlInst {
+ gint ref;
+ ObtPaths *xdg_paths;
+ GHashTable *callbacks;
+ xmlDocPtr doc;
+ xmlNodePtr root;
+ gchar *path;
+};
+
+static void destfunc(struct Callback *c)
+{
+ g_free(c->tag);
+ g_free(c);
+}
+
+ObtXmlInst* obt_xml_instance_new(void)
+{
+ ObtXmlInst *i = g_new(ObtXmlInst, 1);
+ i->ref = 1;
+ i->xdg_paths = obt_paths_new();
+ i->callbacks = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
+ (GDestroyNotify)destfunc);
+ i->doc = NULL;
+ i->root = NULL;
+ i->path = NULL;
+ return i;
+}
+
+void obt_xml_instance_ref(ObtXmlInst *i)
+{
+ ++i->ref;
+}
+
+void obt_xml_instance_unref(ObtXmlInst *i)
+{
+ if (i && --i->ref == 0) {
+ obt_paths_unref(i->xdg_paths);
+ g_hash_table_destroy(i->callbacks);
+ g_free(i);
+ }
+}
+
+xmlDocPtr obt_xml_doc(ObtXmlInst *i)
+{
+ g_assert(i->doc); /* a doc is open? */
+ return i->doc;
+}
+
+xmlNodePtr obt_xml_root(ObtXmlInst *i)
+{
+ g_assert(i->doc); /* a doc is open? */
+ return i->root;
+}
+
+void obt_xml_register(ObtXmlInst *i, const gchar *tag,
+ ObtXmlCallback func, gpointer data)
+{
+ struct Callback *c;
+
+ if (g_hash_table_lookup(i->callbacks, tag)) {
+ g_error("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(i->callbacks, c->tag, c);
+}
+
+static gboolean load_file(ObtXmlInst *i,
+ const gchar *domain,
+ const gchar *filename,
+ const gchar *root_node,
+ GSList *paths)
+{
+ GSList *it;
+ gboolean r = FALSE;
+
+ g_assert(i->doc == NULL); /* another doc isn't open already? */
+
+ for (it = paths; !r && it; it = g_slist_next(it)) {
+ gchar *path;
+ struct stat s;
+
+ if (!domain && !filename) /* given a full path to the file */
+ path = g_strdup(it->data);
+ else
+ path = g_build_filename(it->data, domain, filename, NULL);
+
+ if (stat(path, &s) >= 0) {
+ /* XML_PARSE_BLANKS is needed apparently, or the tree can end up
+ with extra nodes in it. */
+ i->doc = xmlReadFile(path, NULL, (XML_PARSE_NOBLANKS |
+ XML_PARSE_RECOVER));
+ if (i->doc) {
+ i->root = xmlDocGetRootElement(i->doc);
+ if (!i->root) {
+ xmlFreeDoc(i->doc);
+ i->doc = NULL;
+ g_message("%s is an empty XML document", path);
+ }
+ else if (xmlStrcmp(i->root->name,
+ (const xmlChar*)root_node)) {
+ xmlFreeDoc(i->doc);
+ i->doc = NULL;
+ i->root = NULL;
+ g_message("XML document %s is of wrong type. Root "
+ "node is not '%s'", path, root_node);
+ }
+ else {
+ i->path = g_strdup(path);
+ r = TRUE; /* ok! */
+ }
+ }
+ }
+
+ g_free(path);
+ }
+
+ return r;
+}
+
+gboolean obt_xml_load_file(ObtXmlInst *i,
+ const gchar *path,
+ const gchar *root_node)
+{
+ GSList *paths;
+ gboolean r;
+
+ paths = g_slist_append(NULL, g_strdup(path));
+
+ r = load_file(i, NULL, NULL, root_node, paths);
+
+ while (paths) {
+ g_free(paths->data);
+ paths = g_slist_delete_link(paths, paths);
+ }
+ return r;
+}
+
+gboolean obt_xml_load_config_file(ObtXmlInst *i,
+ const gchar *domain,
+ const gchar *filename,
+ const gchar *root_node)
+{
+ GSList *it, *paths = NULL;
+ gboolean r;
+
+ for (it = obt_paths_config_dirs(i->xdg_paths); it; it = g_slist_next(it))
+ paths = g_slist_append(paths, g_strdup(it->data));
+
+ r = load_file(i, domain, filename, root_node, paths);
+
+ while (paths) {
+ g_free(paths->data);
+ paths = g_slist_delete_link(paths, paths);
+ }
+ return r;
+}
+
+gboolean obt_xml_load_data_file(ObtXmlInst *i,
+ const gchar *domain,
+ const gchar *filename,
+ const gchar *root_node)
+{
+ GSList *it, *paths = NULL;
+ gboolean r;
+
+ for (it = obt_paths_data_dirs(i->xdg_paths); it; it = g_slist_next(it))
+ paths = g_slist_append(paths, g_strdup(it->data));
+
+ r = load_file(i, domain, filename, root_node, paths);
+
+ while (paths) {
+ g_free(paths->data);
+ paths = g_slist_delete_link(paths, paths);
+ }
+ return r;
+}
+
+gboolean obt_xml_load_theme_file(ObtXmlInst *i,
+ const gchar *theme,
+ const gchar *domain,
+ const gchar *filename,
+ const gchar *root_node)
+{
+ GSList *it, *paths = NULL;
+ gboolean r;
+
+ /* use ~/.themes for backwards compatibility */
+ paths = g_slist_append
+ (paths, g_build_filename(g_get_home_dir(), ".themes", theme, NULL));
+
+ for (it = obt_paths_data_dirs(i->xdg_paths); it; it = g_slist_next(it))
+ paths = g_slist_append
+ (paths, g_build_filename(it->data, "themes", theme, NULL));
+
+ r = load_file(i, domain, filename, root_node, paths);
+
+ while (paths) {
+ g_free(paths->data);
+ paths = g_slist_delete_link(paths, paths);
+ }
+ return r;
+}
+
+
+gboolean obt_xml_load_mem(ObtXmlInst *i,
+ gpointer data, guint len, const gchar *root_node)
+{
+ gboolean r = FALSE;
+
+ g_assert(i->doc == NULL); /* another doc isn't open already? */
+
+ i->doc = xmlParseMemory(data, len);
+ if (i) {
+ i->root = xmlDocGetRootElement(i->doc);
+ if (!i->root) {
+ xmlFreeDoc(i->doc);
+ i->doc = NULL;
+ g_message("Given memory is an empty document");
+ }
+ else if (xmlStrcmp(i->root->name, (const xmlChar*)root_node)) {
+ xmlFreeDoc(i->doc);
+ i->doc = NULL;
+ i->root = NULL;
+ g_message("XML Document in given memory is of wrong "
+ "type. Root node is not '%s'\n", root_node);
+ }
+ else
+ r = TRUE; /* ok ! */
+ }
+ return r;
+}
+
+gboolean obt_xml_save_file(ObtXmlInst *inst,
+ const gchar *path,
+ gboolean pretty)
+{
+ return xmlSaveFormatFile(path, inst->doc, pretty) != -1;
+}
+
+void obt_xml_close(ObtXmlInst *i)
+{
+ if (i && i->doc) {
+ xmlFreeDoc(i->doc);
+ g_free(i->path);
+ i->doc = NULL;
+ i->root = NULL;
+ i->path = NULL;
+ }
+}
+
+void obt_xml_tree(ObtXmlInst *i, xmlNodePtr node)
+{
+ g_assert(i->doc); /* a doc is open? */
+
+ while (node) {
+ struct Callback *c = g_hash_table_lookup(i->callbacks, node->name);
+ if (c) c->func(node, c->data);
+ node = node->next;
+ }
+}
+
+void obt_xml_tree_from_root(ObtXmlInst *i)
+{
+ obt_xml_tree(i, i->root->children);
+}
+
+gchar *obt_xml_node_string(xmlNodePtr node)
+{
+ xmlChar *c = xmlNodeGetContent(node);
+ gchar *s;
+ if (c) g_strstrip((char*)c); /* strip leading/trailing whitespace */
+ s = g_strdup(c ? (gchar*)c : "");
+ xmlFree(c);
+ return s;
+}
+
+gint obt_xml_node_int(xmlNodePtr node)
+{
+ xmlChar *c = xmlNodeGetContent(node);
+ gint i;
+ if (c) g_strstrip((char*)c); /* strip leading/trailing whitespace */
+ i = c ? atoi((gchar*)c) : 0;
+ xmlFree(c);
+ return i;
+}
+
+gboolean obt_xml_node_bool(xmlNodePtr node)
+{
+ xmlChar *c = xmlNodeGetContent(node);
+ gboolean b = FALSE;
+ if (c) g_strstrip((char*)c); /* strip leading/trailing whitespace */
+ if (c && !xmlStrcasecmp(c, (const xmlChar*) "true"))
+ b = TRUE;
+ else if (c && !xmlStrcasecmp(c, (const xmlChar*) "yes"))
+ b = TRUE;
+ else if (c && !xmlStrcasecmp(c, (const xmlChar*) "on"))
+ b = TRUE;
+ xmlFree(c);
+ return b;
+}
+
+gboolean obt_xml_node_contains(xmlNodePtr node, const gchar *val)
+{
+ xmlChar *c = xmlNodeGetContent(node);
+ gboolean r;
+ if (c) g_strstrip((char*)c); /* strip leading/trailing whitespace */
+ r = !xmlStrcasecmp(c, (const xmlChar*) val);
+ xmlFree(c);
+ return r;
+}
+
+xmlNodePtr obt_xml_find_node(xmlNodePtr node, const gchar *tag)
+{
+ while (node) {
+ if (!xmlStrcmp(node->name, (const xmlChar*) tag))
+ return node;
+ node = node->next;
+ }
+ return NULL;
+}
+
+gboolean obt_xml_attr_bool(xmlNodePtr node, const gchar *name,
+ gboolean *value)
+{
+ xmlChar *c = xmlGetProp(node, (const xmlChar*) name);
+ gboolean r = FALSE;
+ if (c) {
+ g_strstrip((char*)c); /* strip leading/trailing whitespace */
+ if (!xmlStrcasecmp(c, (const xmlChar*) "true"))
+ *value = TRUE, r = TRUE;
+ else if (!xmlStrcasecmp(c, (const xmlChar*) "yes"))
+ *value = TRUE, r = TRUE;
+ else if (!xmlStrcasecmp(c, (const xmlChar*) "on"))
+ *value = TRUE, r = TRUE;
+ else if (!xmlStrcasecmp(c, (const xmlChar*) "false"))
+ *value = FALSE, r = TRUE;
+ else if (!xmlStrcasecmp(c, (const xmlChar*) "no"))
+ *value = FALSE, r = TRUE;
+ else if (!xmlStrcasecmp(c, (const xmlChar*) "off"))
+ *value = FALSE, r = TRUE;
+ }
+ xmlFree(c);
+ return r;
+}
+
+gboolean obt_xml_attr_int(xmlNodePtr node, const gchar *name, gint *value)
+{
+ xmlChar *c = xmlGetProp(node, (const xmlChar*) name);
+ gboolean r = FALSE;
+ if (c) {
+ g_strstrip((char*)c); /* strip leading/trailing whitespace */
+ *value = atoi((gchar*)c);
+ r = TRUE;
+ }
+ xmlFree(c);
+ return r;
+}
+
+gboolean obt_xml_attr_string(xmlNodePtr node, const gchar *name,
+ gchar **value)
+{
+ xmlChar *c = xmlGetProp(node, (const xmlChar*) name);
+ gboolean r = FALSE;
+ if (c) {
+ g_strstrip((char*)c); /* strip leading/trailing whitespace */
+ *value = g_strdup((gchar*)c);
+ r = TRUE;
+ }
+ xmlFree(c);
+ return r;
+}
+
+gboolean obt_xml_attr_contains(xmlNodePtr node, const gchar *name,
+ const gchar *val)
+{
+ xmlChar *c = xmlGetProp(node, (const xmlChar*) name);
+ gboolean r = FALSE;
+ if (c) {
+ g_strstrip((char*)c); /* strip leading/trailing whitespace */
+ r = !xmlStrcasecmp(c, (const xmlChar*) val);
+ }
+ xmlFree(c);
+ return r;
+}
--- /dev/null
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ obt/xml.h for the Openbox window manager
+ Copyright (c) 2003-2007 Dana Jansens
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ See the COPYING file for a copy of the GNU General Public License.
+*/
+
+#ifndef __obt_xml_h
+#define __obt_xml_h
+
+#include <libxml/parser.h>
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct _ObtXmlInst ObtXmlInst;
+
+typedef void (*ObtXmlCallback)(xmlNodePtr node, gpointer data);
+
+ObtXmlInst* obt_xml_instance_new(void);
+void obt_xml_instance_ref(ObtXmlInst *inst);
+void obt_xml_instance_unref(ObtXmlInst *inst);
+
+gboolean obt_xml_load_file(ObtXmlInst *inst,
+ const gchar *path,
+ const gchar *root_node);
+gboolean obt_xml_load_config_file(ObtXmlInst *inst,
+ const gchar *domain,
+ const gchar *filename,
+ const gchar *root_node);
+gboolean obt_xml_load_data_file(ObtXmlInst *inst,
+ const gchar *domain,
+ const gchar *filename,
+ const gchar *root_node);
+gboolean obt_xml_load_theme_file(ObtXmlInst *inst,
+ const gchar *theme,
+ const gchar *domain,
+ const gchar *filename,
+ const gchar *root_node);
+gboolean obt_xml_load_mem(ObtXmlInst *inst,
+ gpointer data, guint len, const gchar *root_node);
+
+gboolean obt_xml_save_file(ObtXmlInst *inst,
+ const gchar *path,
+ gboolean pretty);
+
+xmlDocPtr obt_xml_doc(ObtXmlInst *inst);
+xmlNodePtr obt_xml_root(ObtXmlInst *inst);
+
+void obt_xml_close(ObtXmlInst *inst);
+
+void obt_xml_register(ObtXmlInst *inst, const gchar *tag,
+ ObtXmlCallback func, gpointer data);
+void obt_xml_tree(ObtXmlInst *i, xmlNodePtr node);
+void obt_xml_tree_from_root(ObtXmlInst *i);
+
+
+/* helpers */
+
+xmlNodePtr obt_xml_find_node (xmlNodePtr node, const gchar *name);
+
+gboolean obt_xml_node_contains (xmlNodePtr node, const gchar *val);
+gchar *obt_xml_node_string (xmlNodePtr node);
+gint obt_xml_node_int (xmlNodePtr node);
+gboolean obt_xml_node_bool (xmlNodePtr node);
+
+gboolean obt_xml_attr_contains (xmlNodePtr node, const gchar *name,
+ const gchar *val);
+gboolean obt_xml_attr_string (xmlNodePtr node, const gchar *name,
+ gchar **value);
+gboolean obt_xml_attr_int (xmlNodePtr node, const gchar *name,
+ gint *value);
+gboolean obt_xml_attr_bool (xmlNodePtr node, const gchar *name,
+ gboolean *value);
+
+G_END_DECLS
+
+#endif
gchar *name;
- ObActionsDataSetupFunc setup;
+ gboolean canbeinteractive;
+ union {
+ ObActionsIDataSetupFunc i;
+ ObActionsDataSetupFunc n;
+ } setup;
ObActionsDataFreeFunc free;
ObActionsRunFunc run;
- ObActionsInteractiveInputFunc i_input;
- ObActionsInteractiveCancelFunc i_cancel;
};
struct _ObActionsAct {
guint ref;
ObActionsDefinition *def;
+ ObActionsIPreFunc i_pre;
+ ObActionsIInputFunc i_input;
+ ObActionsICancelFunc i_cancel;
+ ObActionsIPostFunc i_post;
gpointer options;
};
}
}
-gboolean actions_register(const gchar *name,
- ObActionsDataSetupFunc setup,
- ObActionsDataFreeFunc free,
- ObActionsRunFunc run,
- ObActionsInteractiveInputFunc i_input,
- ObActionsInteractiveCancelFunc i_cancel)
+ObActionsDefinition* do_register(const gchar *name,
+ ObActionsDataFreeFunc free,
+ ObActionsRunFunc run)
{
GSList *it;
ObActionsDefinition *def;
g_assert(run != NULL);
- g_assert((i_input == NULL) == (i_cancel == NULL));
for (it = registered; it; it = g_slist_next(it)) {
def = it->data;
if (!g_ascii_strcasecmp(name, def->name)) /* already registered */
- return FALSE;
+ return NULL;
}
def = g_new(ObActionsDefinition, 1);
def->ref = 1;
def->name = g_strdup(name);
- def->setup = setup;
def->free = free;
def->run = run;
- def->i_input = i_input;
- def->i_cancel = i_cancel;
registered = g_slist_prepend(registered, def);
+ return def;
+}
- return TRUE;
+gboolean actions_register_i(const gchar *name,
+ ObActionsIDataSetupFunc setup,
+ ObActionsDataFreeFunc free,
+ ObActionsRunFunc run)
+{
+ ObActionsDefinition *def = do_register(name, free, run);
+ if (def) {
+ def->canbeinteractive = TRUE;
+ def->setup.i = setup;
+ }
+ return def != NULL;
+}
+
+gboolean actions_register(const gchar *name,
+ ObActionsDataSetupFunc setup,
+ ObActionsDataFreeFunc free,
+ ObActionsRunFunc run)
+{
+ ObActionsDefinition *def = do_register(name, free, run);
+ if (def) {
+ def->canbeinteractive = FALSE;
+ def->setup.n = setup;
+ }
+ return def != NULL;
}
static void actions_definition_ref(ObActionsDefinition *def)
act->ref = 1;
act->def = def;
actions_definition_ref(act->def);
+ act->i_pre = NULL;
+ act->i_input = NULL;
+ act->i_cancel = NULL;
+ act->i_post = NULL;
act->options = NULL;
} else
g_message(_("Invalid action \"%s\" requested. No such action exists."),
{
ObActionsAct *act = NULL;
- if ((act = actions_build_act_from_string(name)))
- if (act->def->setup)
- act->options = act->def->setup(NULL, NULL, NULL);
+ if ((act = actions_build_act_from_string(name))) {
+ if (act->def->canbeinteractive) {
+ if (act->def->setup.i)
+ act->options = act->def->setup.i(NULL,
+ &act->i_pre,
+ &act->i_input,
+ &act->i_cancel,
+ &act->i_post);
+ }
+ else {
+ if (act->def->setup.n)
+ act->options = act->def->setup.n(NULL);
+ }
+ }
+
return act;
}
-ObActionsAct* actions_parse(ObParseInst *i,
- xmlDocPtr doc,
- xmlNodePtr node)
+ObActionsAct* actions_parse(xmlNodePtr node)
{
gchar *name;
ObActionsAct *act = NULL;
- if (parse_attr_string("name", node, &name)) {
- if ((act = actions_build_act_from_string(name)))
+ if (obt_xml_attr_string(node, "name", &name)) {
+ if ((act = actions_build_act_from_string(name))) {
/* there is more stuff to parse here */
- if (act->def->setup)
- act->options = act->def->setup(i, doc, node->xmlChildrenNode);
-
+ if (act->def->canbeinteractive) {
+ if (act->def->setup.i)
+ act->options = act->def->setup.i(node->children,
+ &act->i_pre,
+ &act->i_input,
+ &act->i_cancel,
+ &act->i_post);
+ }
+ else {
+ if (act->def->setup.n)
+ act->options = act->def->setup.n(node->children);
+ }
+ }
g_free(name);
}
gboolean actions_act_is_interactive(ObActionsAct *act)
{
- return act->def->i_cancel != NULL;
+ return act->i_input != NULL;
}
void actions_act_ref(ObActionsAct *act)
/* cancel the old one */
if (interactive_act)
actions_interactive_cancel_act();
- ok = actions_interactive_begin_act(act, state);
+ if (act->i_pre)
+ if (!act->i_pre(state, act->options))
+ act->i_input = NULL; /* remove the interactivity */
}
+ /* check again cuz it might have been cancelled */
+ if (actions_act_is_interactive(act))
+ ok = actions_interactive_begin_act(act, state);
}
/* fire the action's run function with this data */
actions_interactive_end_act();
} else {
/* make sure its interactive if it returned TRUE */
- g_assert(act->def->i_cancel && act->def->i_input);
+ g_assert(act->i_input);
/* no actions are run after the interactive one */
break;
void actions_interactive_cancel_act(void)
{
if (interactive_act) {
- interactive_act->def->i_cancel(interactive_act->options);
+ if (interactive_act->i_cancel)
+ interactive_act->i_cancel(interactive_act->options);
actions_interactive_end_act();
}
}
if (interactive_act) {
ungrab_keyboard();
+ if (interactive_act->i_post)
+ interactive_act->i_post(interactive_act->options);
+
actions_act_unref(interactive_act);
interactive_act = NULL;
}
{
gboolean used = FALSE;
if (interactive_act) {
- if (!interactive_act->def->i_input(interactive_initial_state, e,
- interactive_act->options, &used))
+ if (!interactive_act->i_input(interactive_initial_state, e,
+ interactive_act->options, &used))
{
used = TRUE; /* if it cancelled the action then it has to of
been used */
are ignored during a grab, so don't force fake ones when they
should be ignored
*/
- if ((c = client_under_pointer()) && c != data->client &&
- !grab_on_pointer())
- {
- ob_debug_type(OB_DEBUG_FOCUS,
- "Generating fake enter because we did a "
- "mouse-event action");
- event_enter_client(c);
+ if (!grab_on_pointer()) {
+ if ((c = client_under_pointer()) && c != data->client) {
+ ob_debug_type(OB_DEBUG_FOCUS,
+ "Generating fake enter because we did a "
+ "mouse-event action");
+ event_enter_client(c);
+ }
+ else if (!c && c != data->client) {
+ ob_debug_type(OB_DEBUG_FOCUS,
+ "Generating fake leave because we did a "
+ "mouse-event action");
+ event_enter_client(data->client);
+ }
}
}
else if (!data->button && !config_focus_under_mouse)
#include "misc.h"
#include "frame.h"
-#include "parser/parse.h"
+#include "obt/xml.h"
+
#include <glib.h>
#include <X11/Xlib.h>
typedef struct _ObActionsClientData ObActionsClientData;
typedef struct _ObActionsSelectorData ObActionsSelectorData;
-typedef gpointer (*ObActionsDataSetupFunc)(ObParseInst *i,
- xmlDocPtr doc, xmlNodePtr node);
typedef void (*ObActionsDataFreeFunc)(gpointer options);
typedef gboolean (*ObActionsRunFunc)(ObActionsData *data,
gpointer options);
-typedef gboolean (*ObActionsInteractiveInputFunc)(guint initial_state,
+typedef gpointer (*ObActionsDataSetupFunc)(xmlNodePtr node);
+
+/* functions for interactive actions */
+/* return TRUE if the action is going to be interactive, or false to change
+ your mind and make it not */
+typedef gboolean (*ObActionsIPreFunc)(guint initial_state, gpointer options);
+typedef void (*ObActionsIPostFunc)(gpointer options);
+typedef gboolean (*ObActionsIInputFunc)(guint initial_state,
XEvent *e,
gpointer options,
gboolean *used);
-typedef void (*ObActionsInteractiveCancelFunc)(gpointer options);
+typedef void (*ObActionsICancelFunc)(gpointer options);
+typedef gpointer (*ObActionsIDataSetupFunc)(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post);
struct _ObActionsData {
ObUserAction uact;
void actions_startup(gboolean reconfigure);
void actions_shutdown(gboolean reconfigure);
-/*! If the action is interactive, then i_input and i_cancel are not NULL.
- Otherwise, they should both be NULL. */
+/*! Use this if the actions created from this name may be interactive */
+gboolean actions_register_i(const gchar *name,
+ ObActionsIDataSetupFunc setup,
+ ObActionsDataFreeFunc free,
+ ObActionsRunFunc run);
+
gboolean actions_register(const gchar *name,
ObActionsDataSetupFunc setup,
ObActionsDataFreeFunc free,
- ObActionsRunFunc run,
- ObActionsInteractiveInputFunc i_input,
- ObActionsInteractiveCancelFunc i_cancel);
+ ObActionsRunFunc run);
-ObActionsAct* actions_parse(ObParseInst *i,
- xmlDocPtr doc,
- xmlNodePtr node);
+ObActionsAct* actions_parse(xmlNodePtr node);
ObActionsAct* actions_parse_string(const gchar *name);
gboolean actions_act_is_interactive(ObActionsAct *act);
void actions_set_need_pointer_replay_before_move(gboolean replay);
/*! Returns if a ReplayPointer is still needed. If it was called while running
actions then this will be false */
-gboolean actions_get_need_pointer_replay_before_move();
+gboolean actions_get_need_pointer_replay_before_move(void);
/*! Pass in a GSList of ObActionsAct's to be run. */
void actions_run_acts(GSList *acts,
ObFrameContext con,
struct _ObClient *client);
-gboolean actions_interactive_act_running();
-void actions_interactive_cancel_act();
+gboolean actions_interactive_act_running(void);
+void actions_interactive_cancel_act(void);
gboolean actions_interactive_input_event(XEvent *e);
gboolean add;
} Options;
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node);
-static gpointer setup_add_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node);
-static gpointer setup_remove_func(ObParseInst *i,
- xmlDocPtr doc, xmlNodePtr node);
-static void free_func(gpointer options);
+static gpointer setup_func(xmlNodePtr node);
+static gpointer setup_add_func(xmlNodePtr node);
+static gpointer setup_remove_func(xmlNodePtr node);
static gboolean run_func(ObActionsData *data, gpointer options);
+/* 3.4-compatibility */
+static gpointer setup_addcurrent_func(xmlNodePtr node);
+static gpointer setup_addlast_func(xmlNodePtr node);
+static gpointer setup_removecurrent_func(xmlNodePtr node);
+static gpointer setup_removelast_func(xmlNodePtr node);
void action_addremovedesktop_startup(void)
{
- actions_register("AddDesktop",
- setup_add_func,
- free_func,
- run_func,
- NULL, NULL);
- actions_register("RemoveDesktop",
- setup_remove_func,
- free_func,
- run_func,
- NULL, NULL);
+ actions_register("AddDesktop", setup_add_func, g_free, run_func);
+ actions_register("RemoveDesktop", setup_remove_func, g_free, run_func);
+
+ /* 3.4-compatibility */
+ actions_register("AddDesktopLast", setup_addlast_func, g_free, run_func);
+ actions_register("RemoveDesktopLast", setup_removelast_func,
+ g_free, run_func);
+ actions_register("AddDesktopCurrent", setup_addcurrent_func,
+ g_free, run_func);
+ actions_register("RemoveDesktopCurrent", setup_removecurrent_func,
+ g_free, run_func);
}
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
+static gpointer setup_func(xmlNodePtr node)
{
xmlNodePtr n;
Options *o;
o = g_new0(Options, 1);
- if ((n = parse_find_node("where", node))) {
- gchar *s = parse_string(doc, n);
+ if ((n = obt_xml_find_node(node, "where"))) {
+ gchar *s = obt_xml_node_string(n);
if (!g_ascii_strcasecmp(s, "last"))
o->current = FALSE;
else if (!g_ascii_strcasecmp(s, "current"))
return o;
}
-static gpointer setup_add_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
+static gpointer setup_add_func(xmlNodePtr node)
{
- Options *o = setup_func(i, doc, node);
+ Options *o = setup_func(node);
o->add = TRUE;
return o;
}
-static gpointer setup_remove_func(ObParseInst *i,
- xmlDocPtr doc, xmlNodePtr node)
+static gpointer setup_remove_func(xmlNodePtr node)
{
- Options *o = setup_func(i, doc, node);
+ Options *o = setup_func(node);
o->add = FALSE;
return o;
}
-static void free_func(gpointer options)
-{
- Options *o = options;
-
- g_free(o);
-}
-
/* Always return FALSE because its not interactive */
static gboolean run_func(ObActionsData *data, gpointer options)
{
return FALSE;
}
+
+/* 3.4-compatibility */
+static gpointer setup_addcurrent_func(xmlNodePtr node)
+{
+ Options *o = setup_add_func(node);
+ o->current = TRUE;
+ return o;
+}
+
+static gpointer setup_addlast_func(xmlNodePtr node)
+{
+ Options *o = setup_add_func(node);
+ o->current = FALSE;
+ return o;
+}
+
+static gpointer setup_removecurrent_func(xmlNodePtr node)
+{
+ Options *o = setup_remove_func(node);
+ o->current = TRUE;
+ return o;
+}
+
+static gpointer setup_removelast_func(xmlNodePtr node)
+{
+ Options *o = setup_remove_func(node);
+ o->current = FALSE;
+ return o;
+}
action_growtoedge_startup();
action_if_startup();
action_focustobottom_startup();
+ /* 3.4-compatibility */
+ action_shadelowerraise_startup();
}
#ifndef __actions_all_h
#define __actions_all_h
-void action_all_startup();
+void action_all_startup(void);
-void action_execute_startup();
-void action_debug_startup();
-void action_showmenu_startup();
-void action_showdesktop_startup();
-void action_reconfigure_startup();
-void action_exit_startup();
-void action_restart_startup();
-void action_cyclewindows_startup();
-void action_breakchroot_startup();
-void action_close_startup();
-void action_move_startup();
-void action_focus_startup();
-void action_raise_startup();
-void action_lower_startup();
-void action_raiselower_startup();
-void action_unfocus_startup();
-void action_iconify_startup();
-void action_fullscreen_startup();
-void action_maximize_startup();
-void action_moveresizeto_startup();
-void action_moverelative_startup();
-void action_shade_startup();
-void action_kill_startup();
-void action_omnipresent_startup();
-void action_directionalwindows_startup();
-void action_resize_startup();
-void action_decorations_startup();
-void action_desktop_startup();
-void action_resizerelative_startup();
-void action_addremovedesktop_startup();
-void action_dockautohide_startup();
-void action_layer_startup();
-void action_movetoedge_startup();
-void action_growtoedge_startup();
-void action_if_startup();
-void action_focustobottom_startup();
+void action_execute_startup(void);
+void action_debug_startup(void);
+void action_showmenu_startup(void);
+void action_showdesktop_startup(void);
+void action_reconfigure_startup(void);
+void action_exit_startup(void);
+void action_restart_startup(void);
+void action_cyclewindows_startup(void);
+void action_breakchroot_startup(void);
+void action_close_startup(void);
+void action_move_startup(void);
+void action_focus_startup(void);
+void action_raise_startup(void);
+void action_lower_startup(void);
+void action_raiselower_startup(void);
+void action_unfocus_startup(void);
+void action_iconify_startup(void);
+void action_fullscreen_startup(void);
+void action_maximize_startup(void);
+void action_moveresizeto_startup(void);
+void action_moverelative_startup(void);
+void action_shade_startup(void);
+void action_kill_startup(void);
+void action_omnipresent_startup(void);
+void action_directionalwindows_startup(void);
+void action_resize_startup(void);
+void action_decorations_startup(void);
+void action_desktop_startup(void);
+void action_resizerelative_startup(void);
+void action_addremovedesktop_startup(void);
+void action_dockautohide_startup(void);
+void action_layer_startup(void);
+void action_movetoedge_startup(void);
+void action_growtoedge_startup(void);
+void action_if_startup(void);
+void action_focustobottom_startup(void);
+/* 3.4-compatibility */
+void action_shadelowerraise_startup(void);
#endif
{
actions_register("BreakChroot",
NULL, NULL,
- run_func,
- NULL, NULL);
+ run_func);
}
/* Always return FALSE because its not interactive */
{
actions_register("Close",
NULL, NULL,
- run_func,
- NULL, NULL);
+ run_func);
}
/* Always return FALSE because its not interactive */
typedef struct {
gboolean linear;
- gboolean dialog;
gboolean dock_windows;
gboolean desktop_windows;
gboolean all_desktops;
gboolean forward;
gboolean bar;
gboolean raise;
+ ObFocusCyclePopupMode dialog_mode;
GSList *actions;
-} Options;
-static gboolean cycling = FALSE;
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node);
-static gpointer setup_forward_func(ObParseInst *i, xmlDocPtr doc,
- xmlNodePtr node);
-static gpointer setup_backward_func(ObParseInst *i, xmlDocPtr doc,
- xmlNodePtr node);
+ /* options for after we're done */
+ gboolean cancel; /* did the user cancel or not */
+ guint state; /* keyboard state when finished */
+} Options;
+
+static gpointer setup_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *in,
+ ObActionsICancelFunc *c,
+ ObActionsIPostFunc *post);
+static gpointer setup_forward_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *in,
+ ObActionsICancelFunc *c,
+ ObActionsIPostFunc *post);
+static gpointer setup_backward_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *in,
+ ObActionsICancelFunc *c,
+ ObActionsIPostFunc *post);
static void free_func(gpointer options);
static gboolean run_func(ObActionsData *data, gpointer options);
static gboolean i_input_func(guint initial_state,
gpointer options,
gboolean *used);
static void i_cancel_func(gpointer options);
-
-static void end_cycle(gboolean cancel, guint state, Options *o);
+static void i_post_func(gpointer options);
void action_cyclewindows_startup(void)
{
- actions_register("NextWindow", setup_forward_func, free_func,
- run_func, i_input_func, i_cancel_func);
- actions_register("PreviousWindow", setup_backward_func, free_func,
- run_func, i_input_func, i_cancel_func);
+ actions_register_i("NextWindow", setup_forward_func, free_func, run_func);
+ actions_register_i("PreviousWindow", setup_backward_func, free_func,
+ run_func);
}
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
+static gpointer setup_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post)
{
xmlNodePtr n;
Options *o;
o = g_new0(Options, 1);
- o->dialog = TRUE;
o->bar = TRUE;
-
- if ((n = parse_find_node("linear", node)))
- o->linear = parse_bool(doc, n);
- if ((n = parse_find_node("dialog", node)))
- o->dialog = parse_bool(doc, n);
- if ((n = parse_find_node("bar", node)))
- o->bar = parse_bool(doc, n);
- if ((n = parse_find_node("raise", node)))
- o->raise = parse_bool(doc, n);
- if ((n = parse_find_node("panels", node)))
- o->dock_windows = parse_bool(doc, n);
- if ((n = parse_find_node("desktop", node)))
- o->desktop_windows = parse_bool(doc, n);
- if ((n = parse_find_node("allDesktops", node)))
- o->all_desktops = parse_bool(doc, n);
-
- if ((n = parse_find_node("finalactions", node))) {
+ o->dialog_mode = OB_FOCUS_CYCLE_POPUP_MODE_LIST;
+
+ if ((n = obt_xml_find_node(node, "linear")))
+ o->linear = obt_xml_node_bool(n);
+ if ((n = obt_xml_find_node(node, "dialog"))) {
+ if (obt_xml_node_contains(n, "none"))
+ o->dialog_mode = OB_FOCUS_CYCLE_POPUP_MODE_NONE;
+ else if (obt_xml_node_contains(n, "icons"))
+ o->dialog_mode = OB_FOCUS_CYCLE_POPUP_MODE_ICONS;
+ }
+ if ((n = obt_xml_find_node(node, "bar")))
+ o->bar = obt_xml_node_bool(n);
+ if ((n = obt_xml_find_node(node, "raise")))
+ o->raise = obt_xml_node_bool(n);
+ if ((n = obt_xml_find_node(node, "panels")))
+ o->dock_windows = obt_xml_node_bool(n);
+ if ((n = obt_xml_find_node(node, "desktop")))
+ o->desktop_windows = obt_xml_node_bool(n);
+ if ((n = obt_xml_find_node(node, "allDesktops")))
+ o->all_desktops = obt_xml_node_bool(n);
+
+ if ((n = obt_xml_find_node(node, "finalactions"))) {
xmlNodePtr m;
- m = parse_find_node("action", n->xmlChildrenNode);
+ m = obt_xml_find_node(n->children, "action");
while (m) {
- ObActionsAct *action = actions_parse(i, doc, m);
+ ObActionsAct *action = actions_parse(m);
if (action) o->actions = g_slist_append(o->actions, action);
- m = parse_find_node("action", m->next);
+ m = obt_xml_find_node(m->next, "action");
}
}
else {
actions_parse_string("Unshade"));
}
+ *input = i_input_func;
+ *cancel = i_cancel_func;
+ *post = i_post_func;
return o;
}
-static gpointer setup_forward_func(ObParseInst *i, xmlDocPtr doc,
- xmlNodePtr node)
+static gpointer setup_forward_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post)
{
- Options *o = setup_func(i, doc, node);
+ Options *o = setup_func(node, pre, input, cancel, post);
o->forward = TRUE;
return o;
}
-static gpointer setup_backward_func(ObParseInst *i, xmlDocPtr doc,
- xmlNodePtr node)
+static gpointer setup_backward_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post)
{
- Options *o = setup_func(i, doc, node);
+ Options *o = setup_func(node, pre, input, cancel, post);
o->forward = FALSE;
return o;
}
o->linear,
TRUE,
o->bar,
- o->dialog,
+ o->dialog_mode,
FALSE, FALSE);
- cycling = TRUE;
stacking_restore();
if (o->raise && ft) stacking_temp_raise(CLIENT_AS_WINDOW(ft));
gpointer options,
gboolean *used)
{
+ Options *o = options;
+
if (e->type == KeyPress) {
/* Escape cancels no matter what */
if (ob_keycode_match(e->xkey.keycode, OB_KEY_ESCAPE)) {
- end_cycle(TRUE, e->xkey.state, options);
+ o->cancel = TRUE;
+ o->state = e->xkey.state;
return FALSE;
}
else if (ob_keycode_match(e->xkey.keycode, OB_KEY_RETURN) &&
!initial_state)
{
- end_cycle(FALSE, e->xkey.state, options);
+ o->cancel = FALSE;
+ o->state = e->xkey.state;
return FALSE;
}
}
else if (e->type == KeyRelease && initial_state &&
(e->xkey.state & initial_state) == 0)
{
- end_cycle(FALSE, e->xkey.state, options);
+ o->cancel = FALSE;
+ o->state = e->xkey.state;
return FALSE;
}
static void i_cancel_func(gpointer options)
{
- /* we get cancelled when we move focus, but we're not cycling anymore, so
- just ignore that */
- if (cycling)
- end_cycle(TRUE, 0, options);
+ Options *o = options;
+ o->cancel = TRUE;
+ o->state = 0;
}
-static void end_cycle(gboolean cancel, guint state, Options *o)
+static void i_post_func(gpointer options)
{
+ Options *o = options;
struct _ObClient *ft;
ft = focus_cycle(o->forward,
o->linear,
TRUE,
o->bar,
- o->dialog,
- TRUE, cancel);
- cycling = FALSE;
+ o->dialog_mode,
+ TRUE, o->cancel);
if (ft)
actions_run_acts(o->actions, OB_USER_ACTION_KEYBOARD_KEY,
- state, -1, -1, 0, OB_FRAME_CONTEXT_NONE, ft);
+ o->state, -1, -1, 0, OB_FRAME_CONTEXT_NONE, ft);
stacking_restore();
}
gchar *str;
} Options;
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node);
+static gpointer setup_func(xmlNodePtr node);
static void free_func(gpointer options);
static gboolean run_func(ObActionsData *data, gpointer options);
void action_debug_startup(void)
{
- actions_register("Debug",
- setup_func,
- free_func,
- run_func,
- NULL, NULL);
+ actions_register("Debug", setup_func, free_func, run_func);
}
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
+static gpointer setup_func(xmlNodePtr node)
{
xmlNodePtr n;
Options *o;
o = g_new0(Options, 1);
- if ((n = parse_find_node("string", node)))
- o->str = parse_string(doc, n);
+ if ((n = obt_xml_find_node(node, "string")))
+ o->str = obt_xml_node_string(n);
return o;
}
static void free_func(gpointer options)
{
Options *o = options;
-
- if (o) {
- g_free(o->str);
- g_free(o);
- }
+ g_free(o->str);
+ g_free(o);
}
/* Always return FALSE because its not interactive */
void action_decorations_startup(void)
{
- actions_register("Decorate", NULL, NULL, run_func_on, NULL, NULL);
- actions_register("Undecorate", NULL, NULL, run_func_off, NULL, NULL);
- actions_register("ToggleDecorations", NULL, NULL, run_func_toggle,
- NULL, NULL);
+ actions_register("Decorate", NULL, NULL, run_func_on);
+ actions_register("Undecorate", NULL, NULL, run_func_off);
+ actions_register("ToggleDecorations", NULL, NULL, run_func_toggle);
}
/* Always return FALSE because its not interactive */
#include "openbox/actions.h"
#include "openbox/screen.h"
#include "openbox/client.h"
+#include "openbox/openbox.h"
#include <glib.h>
typedef enum {
} u;
gboolean send;
gboolean follow;
+ gboolean interactive;
} Options;
-static gpointer setup_go_func(ObParseInst *i, xmlDocPtr doc,
- xmlNodePtr node);
-static gpointer setup_send_func(ObParseInst *i, xmlDocPtr doc,
- xmlNodePtr node);
+static gpointer setup_go_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post);
+static gpointer setup_send_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post);
static gboolean run_func(ObActionsData *data, gpointer options);
+static gboolean i_pre_func(guint state, gpointer options);
+static gboolean i_input_func(guint initial_state,
+ XEvent *e,
+ gpointer options,
+ gboolean *used);
+static void i_post_func(gpointer options);
+
+/* 3.4-compatibility */
+static gpointer setup_go_last_func(xmlNodePtr node);
+static gpointer setup_send_last_func(xmlNodePtr node);
+static gpointer setup_go_abs_func(xmlNodePtr node);
+static gpointer setup_send_abs_func(xmlNodePtr node);
+static gpointer setup_go_next_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post);
+static gpointer setup_send_next_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post);
+static gpointer setup_go_prev_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post);
+static gpointer setup_send_prev_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post);
+static gpointer setup_go_left_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post);
+static gpointer setup_send_left_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post);
+static gpointer setup_go_right_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post);
+static gpointer setup_send_right_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post);
+static gpointer setup_go_up_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post);
+static gpointer setup_send_up_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post);
+static gpointer setup_go_down_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post);
+static gpointer setup_send_down_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post);
+
void action_desktop_startup(void)
{
- actions_register("GoToDesktop", setup_go_func, g_free, run_func,
- NULL, NULL);
- actions_register("SendToDesktop", setup_send_func, g_free, run_func,
- NULL, NULL);
+ actions_register_i("GoToDesktop", setup_go_func, g_free, run_func);
+ actions_register_i("SendToDesktop", setup_send_func, g_free, run_func);
+ /* 3.4-compatibility */
+ actions_register("DesktopLast", setup_go_last_func, g_free, run_func);
+ actions_register("SendToDesktopLast", setup_send_last_func,
+ g_free, run_func);
+ actions_register("Desktop", setup_go_abs_func, g_free, run_func);
+ actions_register("SendToDesktop", setup_send_abs_func, g_free, run_func);
+ actions_register_i("DesktopNext", setup_go_next_func, g_free, run_func);
+ actions_register_i("SendToDesktopNext", setup_send_next_func,
+ g_free, run_func);
+ actions_register_i("DesktopPrevious", setup_go_prev_func,
+ g_free, run_func);
+ actions_register_i("SendToDesktopPrevious", setup_send_prev_func,
+ g_free, run_func);
+ actions_register_i("DesktopLeft", setup_go_left_func, g_free, run_func);
+ actions_register_i("SendToDesktopLeft", setup_send_left_func,
+ g_free, run_func);
+ actions_register_i("DesktopRight", setup_go_right_func, g_free, run_func);
+ actions_register_i("SendToDesktopRight", setup_send_right_func,
+ g_free, run_func);
+ actions_register_i("DesktopUp", setup_go_up_func, g_free, run_func);
+ actions_register_i("SendToDesktopUp", setup_send_up_func,
+ g_free, run_func);
+ actions_register_i("DesktopDown", setup_go_down_func, g_free, run_func);
+ actions_register_i("SendToDesktopDown", setup_send_down_func,
+ g_free, run_func);
}
-static gpointer setup_go_func(ObParseInst *i, xmlDocPtr doc,
- xmlNodePtr node)
+static gpointer setup_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post)
{
xmlNodePtr n;
Options *o;
o = g_new0(Options, 1);
- /* don't go anywhere if theres no options given */
+ /* don't go anywhere if there are no options given */
o->type = ABSOLUTE;
o->u.abs.desktop = screen_desktop;
/* wrap by default - it's handy! */
o->u.rel.wrap = TRUE;
- if ((n = parse_find_node("to", node))) {
- gchar *s = parse_string(doc, n);
+ if ((n = obt_xml_find_node(node, "to"))) {
+ gchar *s = obt_xml_node_string(n);
if (!g_ascii_strcasecmp(s, "last"))
o->type = LAST;
else if (!g_ascii_strcasecmp(s, "next")) {
g_free(s);
}
- if ((n = parse_find_node("wrap", node)))
- o->u.rel.wrap = parse_bool(doc, n);
+ if ((n = obt_xml_find_node(node, "wrap")))
+ o->u.rel.wrap = obt_xml_node_bool(n);
return o;
}
-static gpointer setup_send_func(ObParseInst *i, xmlDocPtr doc,
- xmlNodePtr node)
+
+static gpointer setup_go_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post)
+{
+ Options *o;
+
+ o = setup_func(node, pre, input, cancel, post);
+ if (o->type == RELATIVE) {
+ o->interactive = TRUE;
+ *pre = i_pre_func;
+ *input = i_input_func;
+ *post = i_post_func;
+ }
+
+ return o;
+}
+
+static gpointer setup_send_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post)
{
xmlNodePtr n;
Options *o;
- o = setup_go_func(i, doc, node);
+ o = setup_func(node, pre, input, cancel, post);
o->send = TRUE;
o->follow = TRUE;
- if ((n = parse_find_node("follow", node)))
- o->follow = parse_bool(doc, n);
+ if ((n = obt_xml_find_node(node, "follow")))
+ o->follow = obt_xml_node_bool(n);
+
+ if (o->type == RELATIVE && o->follow) {
+ o->interactive = TRUE;
+ *pre = i_pre_func;
+ *input = i_input_func;
+ *post = i_post_func;
+ }
return o;
}
d = screen_find_desktop(screen_desktop,
o->u.rel.dir, o->u.rel.wrap, o->u.rel.linear);
break;
+ default:
+ g_assert_not_reached();
}
if (d < screen_num_desktops && d != screen_desktop) {
actions_client_move(data, FALSE);
}
- return FALSE;
+
+ return o->interactive;
+}
+
+static gboolean i_input_func(guint initial_state,
+ XEvent *e,
+ gpointer options,
+ gboolean *used)
+{
+ if (e->type == KeyPress) {
+ /* Escape cancels no matter what */
+ if (ob_keycode_match(e->xkey.keycode, OB_KEY_ESCAPE)) {
+ return FALSE;
+ }
+
+ /* There were no modifiers and they pressed enter */
+ else if (ob_keycode_match(e->xkey.keycode, OB_KEY_RETURN) &&
+ !initial_state)
+ {
+ return FALSE;
+ }
+ }
+ /* They released the modifiers */
+ else if (e->type == KeyRelease && initial_state &&
+ (e->xkey.state & initial_state) == 0)
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean i_pre_func(guint initial_state, gpointer options)
+{
+ if (!initial_state) {
+ Options *o = options;
+ o->interactive = FALSE;
+ return FALSE;
+ }
+ else {
+ screen_show_desktop_popup(screen_desktop, TRUE);
+ return TRUE;
+ }
+}
+
+static void i_post_func(gpointer options)
+{
+ screen_hide_desktop_popup();
+}
+
+/* 3.4-compatilibity */
+static gpointer setup_follow(xmlNodePtr node)
+{
+ xmlNodePtr n;
+ Options *o = g_new0(Options, 1);
+ o->send = TRUE;
+ o->follow = TRUE;
+ if ((n = obt_xml_find_node(node, "follow")))
+ o->follow = obt_xml_node_bool(n);
+ return o;
+}
+
+static gpointer setup_go_last_func(xmlNodePtr node)
+{
+ Options *o = g_new0(Options, 1);
+ o->type = LAST;
+ return o;
+}
+
+static gpointer setup_send_last_func(xmlNodePtr node)
+{
+ Options *o = setup_follow(node);
+ o->type = LAST;
+ return o;
+}
+
+static gpointer setup_go_abs_func(xmlNodePtr node)
+{
+ xmlNodePtr n;
+ Options *o = g_new0(Options, 1);
+ o->type = ABSOLUTE;
+ if ((n = obt_xml_find_node(node, "desktop")))
+ o->u.abs.desktop = obt_xml_node_int(n) - 1;
+ else
+ o->u.abs.desktop = screen_desktop;
+ return o;
+}
+
+static gpointer setup_send_abs_func(xmlNodePtr node)
+{
+ xmlNodePtr n;
+ Options *o = setup_follow(node);
+ o->type = ABSOLUTE;
+ if ((n = obt_xml_find_node(node, "desktop")))
+ o->u.abs.desktop = obt_xml_node_int(n) - 1;
+ else
+ o->u.abs.desktop = screen_desktop;
+ return o;
+}
+
+static void setup_rel(Options *o, xmlNodePtr node, gboolean lin,
+ ObDirection dir,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsIPostFunc *post)
+{
+ xmlNodePtr n;
+
+ o->type = RELATIVE;
+ o->u.rel.linear = lin;
+ o->u.rel.dir = dir;
+ o->u.rel.wrap = TRUE;
+
+ if ((n = obt_xml_find_node(node, "wrap")))
+ o->u.rel.wrap = obt_xml_node_bool(n);
+
+ if (input) {
+ o->interactive = TRUE;
+ *pre = i_pre_func;
+ *input = i_input_func;
+ *post = i_post_func;
+ }
+}
+
+static gpointer setup_go_next_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post)
+{
+ Options *o = g_new0(Options, 1);
+ setup_rel(o, node, TRUE, OB_DIRECTION_EAST, pre, input, post);
+ return o;
+}
+
+static gpointer setup_send_next_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post)
+{
+ Options *o = setup_follow(node);
+ setup_rel(o, node, TRUE, OB_DIRECTION_EAST,
+ pre, (o->follow ? input : NULL), post);
+ return o;
+}
+
+static gpointer setup_go_prev_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post)
+{
+ Options *o = g_new0(Options, 1);
+ setup_rel(o, node, TRUE, OB_DIRECTION_WEST, pre, input, post);
+ return o;
+}
+
+static gpointer setup_send_prev_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post)
+{
+ Options *o = setup_follow(node);
+ setup_rel(o, node, TRUE, OB_DIRECTION_WEST,
+ pre, (o->follow ? input : NULL), post);
+ return o;
+}
+
+static gpointer setup_go_left_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post)
+{
+ Options *o = g_new0(Options, 1);
+ setup_rel(o, node, FALSE, OB_DIRECTION_WEST, pre, input, post);
+ return o;
+}
+
+static gpointer setup_send_left_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post)
+{
+ Options *o = setup_follow(node);
+ setup_rel(o, node, FALSE, OB_DIRECTION_WEST,
+ pre, (o->follow ? input : NULL), post);
+ return o;
+}
+
+static gpointer setup_go_right_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post)
+{
+ Options *o = g_new0(Options, 1);
+ setup_rel(o, node, FALSE, OB_DIRECTION_EAST, pre, input, post);
+ return o;
+}
+
+static gpointer setup_send_right_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post)
+{
+ Options *o = setup_follow(node);
+ setup_rel(o, node, FALSE, OB_DIRECTION_EAST,
+ pre, (o->follow ? input : NULL), post);
+ return o;
+}
+
+static gpointer setup_go_up_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post)
+{
+ Options *o = g_new0(Options, 1);
+ setup_rel(o, node, FALSE, OB_DIRECTION_NORTH, pre, input, post);
+ return o;
+}
+
+static gpointer setup_send_up_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post)
+{
+ Options *o = setup_follow(node);
+ setup_rel(o, node, FALSE, OB_DIRECTION_NORTH,
+ pre, (o->follow ? input : NULL), post);
+ return o;
+}
+
+static gpointer setup_go_down_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post)
+{
+ Options *o = g_new0(Options, 1);
+ setup_rel(o, node, FALSE, OB_DIRECTION_SOUTH, pre, input, post);
+ return o;
+}
+
+static gpointer setup_send_down_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post)
+{
+ Options *o = setup_follow(node);
+ setup_rel(o, node, FALSE, OB_DIRECTION_SOUTH,
+ pre, (o->follow ? input : NULL), post);
+ return o;
}
static gboolean cycling = FALSE;
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node);
-static gpointer setup_cycle_func(ObParseInst *i, xmlDocPtr doc,
- xmlNodePtr node);
-static gpointer setup_target_func(ObParseInst *i, xmlDocPtr doc,
- xmlNodePtr node);
+static gpointer setup_func(xmlNodePtr node);
+static gpointer setup_cycle_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post);
+static gpointer setup_target_func(xmlNodePtr node);
static void free_func(gpointer options);
static gboolean run_func(ObActionsData *data, gpointer options);
static gboolean i_input_func(guint initial_state,
static void end_cycle(gboolean cancel, guint state, Options *o);
+/* 3.4-compatibility */
+static gpointer setup_north_cycle_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *in,
+ ObActionsICancelFunc *c,
+ ObActionsIPostFunc *post);
+static gpointer setup_south_cycle_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *in,
+ ObActionsICancelFunc *c,
+ ObActionsIPostFunc *post);
+static gpointer setup_east_cycle_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *in,
+ ObActionsICancelFunc *c,
+ ObActionsIPostFunc *post);
+static gpointer setup_west_cycle_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *in,
+ ObActionsICancelFunc *c,
+ ObActionsIPostFunc *post);
+static gpointer setup_northwest_cycle_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *in,
+ ObActionsICancelFunc *c,
+ ObActionsIPostFunc *post);
+static gpointer setup_northeast_cycle_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *in,
+ ObActionsICancelFunc *c,
+ ObActionsIPostFunc *post);
+static gpointer setup_southwest_cycle_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *in,
+ ObActionsICancelFunc *c,
+ ObActionsIPostFunc *post);
+static gpointer setup_southeast_cycle_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *in,
+ ObActionsICancelFunc *c,
+ ObActionsIPostFunc *post);
+static gpointer setup_north_target_func(xmlNodePtr node);
+static gpointer setup_south_target_func(xmlNodePtr node);
+static gpointer setup_east_target_func(xmlNodePtr node);
+static gpointer setup_west_target_func(xmlNodePtr node);
+static gpointer setup_northwest_target_func(xmlNodePtr node);
+static gpointer setup_northeast_target_func(xmlNodePtr node);
+static gpointer setup_southwest_target_func(xmlNodePtr node);
+static gpointer setup_southeast_target_func(xmlNodePtr node);
+
void action_directionalwindows_startup(void)
{
- actions_register("DirectionalCycleWindows", setup_cycle_func, free_func,
- run_func, i_input_func, i_cancel_func);
+ actions_register_i("DirectionalCycleWindows", setup_cycle_func, free_func,
+ run_func);
actions_register("DirectionalTargetWindow", setup_target_func, free_func,
- run_func, NULL, NULL);
+ run_func);
+ /* 3.4-compatibility */
+ actions_register_i("DirectionalFocusNorth", setup_north_cycle_func,
+ free_func, run_func);
+ actions_register_i("DirectionalFocusSouth", setup_south_cycle_func,
+ free_func, run_func);
+ actions_register_i("DirectionalFocusWest", setup_west_cycle_func,
+ free_func, run_func);
+ actions_register_i("DirectionalFocusEast", setup_east_cycle_func,
+ free_func, run_func);
+ actions_register_i("DirectionalFocusNorthWest", setup_northwest_cycle_func,
+ free_func, run_func);
+ actions_register_i("DirectionalFocusNorthEast", setup_northeast_cycle_func,
+ free_func, run_func);
+ actions_register_i("DirectionalFocusSouthWest", setup_southwest_cycle_func,
+ free_func, run_func);
+ actions_register_i("DirectionalFocusSouthEast", setup_southeast_cycle_func,
+ free_func, run_func);
+ actions_register("DirectionalTargetNorth", setup_north_target_func,
+ free_func, run_func);
+ actions_register("DirectionalTargetSouth", setup_south_target_func,
+ free_func, run_func);
+ actions_register("DirectionalTargetWest", setup_west_target_func,
+ free_func, run_func);
+ actions_register("DirectionalTargetEast", setup_east_target_func,
+ free_func, run_func);
+ actions_register("DirectionalTargetNorthWest", setup_northwest_target_func,
+ free_func, run_func);
+ actions_register("DirectionalTargetNorthEast", setup_northeast_target_func,
+ free_func, run_func);
+ actions_register("DirectionalTargetSouthWest", setup_southwest_target_func,
+ free_func, run_func);
+ actions_register("DirectionalTargetSouthEast", setup_southeast_target_func,
+ free_func, run_func);
}
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
+static gpointer setup_func(xmlNodePtr node)
{
xmlNodePtr n;
Options *o;
o->dialog = TRUE;
o->bar = TRUE;
- if ((n = parse_find_node("dialog", node)))
- o->dialog = parse_bool(doc, n);
- if ((n = parse_find_node("bar", node)))
- o->bar = parse_bool(doc, n);
- if ((n = parse_find_node("raise", node)))
- o->raise = parse_bool(doc, n);
- if ((n = parse_find_node("panels", node)))
- o->dock_windows = parse_bool(doc, n);
- if ((n = parse_find_node("desktop", node)))
- o->desktop_windows = parse_bool(doc, n);
- if ((n = parse_find_node("direction", node))) {
- gchar *s = parse_string(doc, n);
+ if ((n = obt_xml_find_node(node, "dialog")))
+ o->dialog = obt_xml_node_bool(n);
+ if ((n = obt_xml_find_node(node, "bar")))
+ o->bar = obt_xml_node_bool(n);
+ if ((n = obt_xml_find_node(node, "raise")))
+ o->raise = obt_xml_node_bool(n);
+ if ((n = obt_xml_find_node(node, "panels")))
+ o->dock_windows = obt_xml_node_bool(n);
+ if ((n = obt_xml_find_node(node, "desktop")))
+ o->desktop_windows = obt_xml_node_bool(n);
+ if ((n = obt_xml_find_node(node, "direction"))) {
+ gchar *s = obt_xml_node_string(n);
if (!g_ascii_strcasecmp(s, "north") ||
!g_ascii_strcasecmp(s, "up"))
o->direction = OB_DIRECTION_NORTH;
g_free(s);
}
- if ((n = parse_find_node("finalactions", node))) {
+ if ((n = obt_xml_find_node(node, "finalactions"))) {
xmlNodePtr m;
- m = parse_find_node("action", n->xmlChildrenNode);
+ m = obt_xml_find_node(n->children, "action");
while (m) {
- ObActionsAct *action = actions_parse(i, doc, m);
+ ObActionsAct *action = actions_parse(m);
if (action) o->actions = g_slist_append(o->actions, action);
- m = parse_find_node("action", m->next);
+ m = obt_xml_find_node(m->next, "action");
}
}
else {
return o;
}
-static gpointer setup_cycle_func(ObParseInst *i, xmlDocPtr doc,
- xmlNodePtr node)
+static gpointer setup_cycle_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post)
{
- Options *o = setup_func(i, doc, node);
+ Options *o = setup_func(node);
o->interactive = TRUE;
+ *input = i_input_func;
+ *cancel = i_cancel_func;
return o;
}
-static gpointer setup_target_func(ObParseInst *i, xmlDocPtr doc,
- xmlNodePtr node)
+static gpointer setup_target_func(xmlNodePtr node)
{
- Options *o = setup_func(i, doc, node);
+ Options *o = setup_func(node);
o->interactive = FALSE;
return o;
}
stacking_restore();
}
+
+/* 3.4-compatibility */
+static gpointer setup_north_cycle_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post)
+{
+ Options *o = setup_cycle_func(node, pre, input, cancel, post);
+ o->direction = OB_DIRECTION_NORTH;
+ return o;
+}
+
+static gpointer setup_south_cycle_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post)
+{
+ Options *o = setup_cycle_func(node, pre, input, cancel, post);
+ o->direction = OB_DIRECTION_SOUTH;
+ return o;
+}
+
+static gpointer setup_east_cycle_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post)
+{
+ Options *o = setup_cycle_func(node, pre, input, cancel, post);
+ o->direction = OB_DIRECTION_EAST;
+ return o;
+}
+
+static gpointer setup_west_cycle_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post)
+{
+ Options *o = setup_cycle_func(node, pre, input, cancel, post);
+ o->direction = OB_DIRECTION_WEST;
+ return o;
+}
+
+static gpointer setup_northwest_cycle_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post)
+{
+ Options *o = setup_cycle_func(node, pre, input, cancel, post);
+ o->direction = OB_DIRECTION_NORTHWEST;
+ return o;
+}
+
+static gpointer setup_northeast_cycle_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post)
+{
+ Options *o = setup_cycle_func(node, pre, input, cancel, post);
+ o->direction = OB_DIRECTION_EAST;
+ return o;
+}
+
+static gpointer setup_southwest_cycle_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post)
+{
+ Options *o = setup_cycle_func(node, pre, input, cancel, post);
+ o->direction = OB_DIRECTION_SOUTHWEST;
+ return o;
+}
+
+static gpointer setup_southeast_cycle_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post)
+{
+ Options *o = setup_cycle_func(node, pre, input, cancel, post);
+ o->direction = OB_DIRECTION_SOUTHEAST;
+ return o;
+}
+
+static gpointer setup_north_target_func(xmlNodePtr node)
+{
+ Options *o = setup_target_func(node);
+ o->direction = OB_DIRECTION_NORTH;
+ return o;
+}
+
+static gpointer setup_south_target_func(xmlNodePtr node)
+{
+ Options *o = setup_target_func(node);
+ o->direction = OB_DIRECTION_SOUTH;
+ return o;
+}
+
+static gpointer setup_east_target_func(xmlNodePtr node)
+{
+ Options *o = setup_target_func(node);
+ o->direction = OB_DIRECTION_EAST;
+ return o;
+}
+
+static gpointer setup_west_target_func(xmlNodePtr node)
+{
+ Options *o = setup_target_func(node);
+ o->direction = OB_DIRECTION_WEST;
+ return o;
+}
+
+static gpointer setup_northwest_target_func(xmlNodePtr node)
+{
+ Options *o = setup_target_func(node);
+ o->direction = OB_DIRECTION_NORTHWEST;
+ return o;
+}
+
+static gpointer setup_northeast_target_func(xmlNodePtr node)
+{
+ Options *o = setup_target_func(node);
+ o->direction = OB_DIRECTION_NORTHEAST;
+ return o;
+}
+
+static gpointer setup_southwest_target_func(xmlNodePtr node)
+{
+ Options *o = setup_target_func(node);
+ o->direction = OB_DIRECTION_SOUTHWEST;
+ return o;
+}
+
+static gpointer setup_southeast_target_func(xmlNodePtr node)
+{
+ Options *o = setup_target_func(node);
+ o->direction = OB_DIRECTION_SOUTHEAST;
+ return o;
+}
+
{
actions_register("ToggleDockAutoHide",
NULL, NULL,
- run_func,
- NULL, NULL);
+ run_func);
}
/* Always return FALSE because its not interactive */
#include "openbox/actions.h"
#include "openbox/event.h"
#include "openbox/startupnotify.h"
+#include "openbox/client.h"
#include "openbox/prompt.h"
#include "openbox/screen.h"
+#include "obt/paths.h"
#include "gettext.h"
#ifdef HAVE_STDLIB_H
gchar *prompt;
} Options;
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node);
+static gpointer setup_func(xmlNodePtr node);
static void free_func(gpointer options);
static gboolean run_func(ObActionsData *data, gpointer options);
/*
void action_execute_startup(void)
{
- actions_register("Execute",
- setup_func,
- free_func,
- run_func,
- NULL, NULL);
+ actions_register("Execute", setup_func, free_func, run_func);
}
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
+static gpointer setup_func(xmlNodePtr node)
{
xmlNodePtr n;
Options *o;
o = g_new0(Options, 1);
- if ((n = parse_find_node("command", node)) ||
- (n = parse_find_node("execute", node)))
+ if ((n = obt_xml_find_node(node, "command")) ||
+ (n = obt_xml_find_node(node, "execute")))
{
- gchar *s = parse_string(doc, n);
- o->cmd = parse_expand_tilde(s);
+ gchar *s = obt_xml_node_string(n);
+ o->cmd = obt_paths_expand_tilde(s);
g_free(s);
}
- if ((n = parse_find_node("prompt", node)))
- o->prompt = parse_string(doc, n);
+ if ((n = obt_xml_find_node(node, "prompt")))
+ o->prompt = obt_xml_node_string(n);
- if ((n = parse_find_node("startupnotify", node))) {
+ if ((n = obt_xml_find_node(node, "startupnotify"))) {
xmlNodePtr m;
- if ((m = parse_find_node("enabled", n->xmlChildrenNode)))
- o->sn = parse_bool(doc, m);
- if ((m = parse_find_node("name", n->xmlChildrenNode)))
- o->sn_name = parse_string(doc, m);
- if ((m = parse_find_node("icon", n->xmlChildrenNode)))
- o->sn_icon = parse_string(doc, m);
- if ((m = parse_find_node("wmclass", n->xmlChildrenNode)))
- o->sn_wmclass = parse_string(doc, m);
+ if ((m = obt_xml_find_node(n->children, "enabled")))
+ o->sn = obt_xml_node_bool(m);
+ if ((m = obt_xml_find_node(n->children, "name")))
+ o->sn_name = obt_xml_node_string(m);
+ if ((m = obt_xml_find_node(n->children, "icon")))
+ o->sn_icon = obt_xml_node_string(m);
+ if ((m = obt_xml_find_node(n->children, "wmclass")))
+ o->sn_wmclass = obt_xml_node_string(m);
}
return o;
}
/* Always return FALSE because its not interactive */
static gboolean run_func(ObActionsData *data, gpointer options)
{
- GError *e = NULL;
+ GError *e;
gchar **argv = NULL;
gchar *cmd;
Options *o = options;
return FALSE;
}
+ if (data->client) {
+ gchar *c, *before, *expand;
+
+ /* replace occurrences of $pid and $wid */
+
+ expand = NULL;
+ before = cmd;
+
+ while ((c = strchr(before, '$'))) {
+ if ((c[1] == 'p' || c[1] == 'P') &&
+ (c[2] == 'i' || c[2] == 'I') &&
+ (c[3] == 'd' || c[3] == 'D') &&
+ !g_ascii_isalnum(c[4]))
+ {
+ /* found $pid */
+ gchar *tmp;
+
+ *c = '\0';
+ tmp = expand;
+ expand = g_strdup_printf("%s%s%u",
+ (expand ? expand : ""),
+ before,
+ data->client->pid);
+ g_free(tmp);
+
+ before = c + 4; /* 4 = strlen("$pid") */
+ }
+ else if ((c[1] == 'w' || c[1] == 'W') &&
+ (c[2] == 'i' || c[2] == 'I') &&
+ (c[3] == 'd' || c[3] == 'D') &&
+ !g_ascii_isalnum(c[4]))
+ {
+ /* found $wid */
+ gchar *tmp;
+
+ *c = '\0';
+ tmp = expand;
+ expand = g_strdup_printf("%s%s%lu",
+ (expand ? expand : ""),
+ before,
+ data->client->window);
+ g_free(tmp);
+
+ before = c + 4; /* 4 = strlen("$wid") */
+ }
+ else
+ before = c + 1; /* no infinite loops plz */
+ }
+
+ if (expand) {
+ gchar *tmp;
+
+ /* add on the end of the string after the last replacement */
+ tmp = expand;
+ expand = g_strconcat(expand, before, NULL);
+ g_free(tmp);
+
+ /* replace the command with the expanded one */
+ g_free(cmd);
+ cmd = expand;
+ }
+ }
+
/* If there is a keyboard grab going on then we need to cancel
it so the application can grab things */
event_cancel_all_key_grabs();
+ e = NULL;
if (!g_shell_parse_argv(cmd, NULL, &argv, &e)) {
g_message(e->message, o->cmd);
g_error_free(e);
}
else {
gchar *program = NULL;
+ gboolean ok;
if (o->sn) {
program = g_path_get_basename(argv[0]);
screen_desktop);
}
- if (!g_spawn_async(NULL, argv, NULL,
- G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
- NULL, NULL, NULL, &e))
- {
+ e = NULL;
+ ok = g_spawn_async(NULL, argv, NULL,
+ G_SPAWN_SEARCH_PATH |
+ G_SPAWN_DO_NOT_REAP_CHILD,
+ NULL, NULL, NULL, &e);
+ if (!ok) {
g_message(e->message, o->cmd);
g_error_free(e);
-
- if (o->sn)
- sn_spawn_cancel();
}
- if (o->sn)
+
+ if (o->sn) {
+ if (!ok) sn_spawn_cancel();
unsetenv("DESKTOP_STARTUP_ID");
+ }
g_free(program);
g_strfreev(argv);
gboolean prompt;
} Options;
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node);
+static gpointer setup_func(xmlNodePtr node);
static gboolean run_func(ObActionsData *data, gpointer options);
void action_exit_startup(void)
{
- actions_register("Exit", setup_func, NULL, run_func, NULL, NULL);
- actions_register("SessionLogout", setup_func, NULL, run_func, NULL, NULL);
+ actions_register("Exit", setup_func, NULL, run_func);
+ actions_register("SessionLogout", setup_func, NULL, run_func);
}
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
+static gpointer setup_func(xmlNodePtr node)
{
xmlNodePtr n;
Options *o;
o = g_new0(Options, 1);
o->prompt = TRUE;
- if ((n = parse_find_node("prompt", node)))
- o->prompt = parse_bool(doc, n);
+ if ((n = obt_xml_find_node(node, "prompt")))
+ o->prompt = obt_xml_node_bool(n);
return o;
}
gboolean stop_int;
} Options;
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node);
-static void free_func(gpointer options);
+static gpointer setup_func(xmlNodePtr node);
static gboolean run_func(ObActionsData *data, gpointer options);
void action_focus_startup(void)
{
- actions_register("Focus",
- setup_func,
- free_func,
- run_func,
- NULL, NULL);
+ actions_register("Focus", setup_func, g_free, run_func);
}
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
+static gpointer setup_func(xmlNodePtr node)
{
xmlNodePtr n;
Options *o;
o = g_new0(Options, 1);
o->stop_int = TRUE;
- if ((n = parse_find_node("here", node)))
- o->here = parse_bool(doc, n);
- if ((n = parse_find_node("stopInteractive", node)))
- o->stop_int = parse_bool(doc, n);
+ if ((n = obt_xml_find_node(node, "here")))
+ o->here = obt_xml_node_bool(n);
+ if ((n = obt_xml_find_node(node, "stopInteractive")))
+ o->stop_int = obt_xml_node_bool(n);
return o;
}
-static void free_func(gpointer options)
-{
- Options *o = options;
-
- g_free(o);
-}
-
/* Always return FALSE because its not interactive */
static gboolean run_func(ObActionsData *data, gpointer options)
{
void action_focustobottom_startup(void)
{
- actions_register("FocusToBottom", NULL, NULL, run_func, NULL, NULL);
+ actions_register("FocusToBottom", NULL, NULL, run_func);
}
/* Always return FALSE because its not interactive */
void action_fullscreen_startup(void)
{
- actions_register("ToggleFullscreen", NULL, NULL, run_func_toggle,
- NULL, NULL);
+ actions_register("ToggleFullscreen", NULL, NULL, run_func_toggle);
}
/* Always return FALSE because its not interactive */
typedef struct {
ObDirection dir;
+ gboolean shrink;
} Options;
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node);
-static void free_func(gpointer options);
+static gpointer setup_func(xmlNodePtr node);
+static gpointer setup_shrink_func(xmlNodePtr node);
static gboolean run_func(ObActionsData *data, gpointer options);
+/* 3.4-compatibility */
+static gpointer setup_north_func(xmlNodePtr node);
+static gpointer setup_south_func(xmlNodePtr node);
+sta