Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

initial commit

moved dzen to github
  • Loading branch information...
commit 982023f29efddc5968d697d6b4438df0fc51e6be 0 parents
Robert Manea authored
Showing with 5,666 additions and 0 deletions.
  1. +29 −0 CREDITS
  2. +25 −0 INSTALL
  3. +21 −0 LICENSE
  4. +56 −0 Makefile
  5. +608 −0 README
  6. +591 −0 README.dzen
  7. +24 −0 TODO
  8. +571 −0 action.c
  9. +86 −0 action.h
  10. +6 −0 bitmaps/alert.xbm
  11. +8 −0 bitmaps/ball.xbm
  12. +6 −0 bitmaps/battery.xbm
  13. +6 −0 bitmaps/envelope.xbm
  14. +7 −0 bitmaps/music.xbm
  15. +7 −0 bitmaps/pause.xbm
  16. +7 −0 bitmaps/play.xbm
  17. +6 −0 bitmaps/volume.xbm
  18. +73 −0 config.mk
  19. +1,051 −0 draw.c
  20. +180 −0 dzen.h
  21. +72 −0 gadgets/Makefile
  22. +72 −0 gadgets/README.dbar
  23. +43 −0 gadgets/README.gcpubar
  24. +35 −0 gadgets/README.gdbar
  25. +14 −0 gadgets/README.kittscanner
  26. +9 −0 gadgets/README.textwidth
  27. +18 −0 gadgets/config.mk
  28. +86 −0 gadgets/dbar-main.c
  29. +181 −0 gadgets/dbar.c
  30. +39 −0 gadgets/dbar.h
  31. +184 −0 gadgets/gcpubar.c
  32. +100 −0 gadgets/gdbar.c
  33. +71 −0 gadgets/kittscanner.sh
  34. +27 −0 gadgets/noisyalert.sh
  35. +117 −0 gadgets/textwidth.c
  36. +11 −0 help
  37. +1,153 −0 main.c
  38. +66 −0 util.c
29 CREDITS
@@ -0,0 +1,29 @@
+==================================
+ dzen, (c) 2007 by Robert Manea
+==================================
+
+
+The following people have contributed especially to dzen:
+
+
+Cyrille Bagard <nocbos at gmail dot com>
+ * patch allowing to use EWMH for docking dzen.
+
+Jason Creighton <jcreigh at gmail dot com>
+ * XINERAMA support
+ * _NET_WM_STRUT_PARTIAL support
+
+Adam Langley <agl at imperialviolet dot org>
+ * patch to add optional timeout to '-p'
+
+Mauke <mauke at ...>
+ * Code clean ups to remove compiler warnings
+
+Alexander V. Inyukhin <shurick at sectorb dot msk dot ru>
+ * fix to action handling
+
+Valery V. Vorotyntsev <valery dot vv at gmail.com>
+ * patch to correctly handle the -geometry and -y options for
+ dzen at the bottom of the screen
+ * cosmetic code clean ups
+
25 INSTALL
@@ -0,0 +1,25 @@
+==================================
+ dzen, (c) 2007 by Robert Manea
+==================================
+
+
+Edit config.mk to match your local setup (dzen is installed into
+the /usr/local namespace by default).
+
+Afterwards enter the following command to build and install dzen (if
+necessary as root):
+
+ make clean install
+
+
+Optionally if you want to use dzen's gadgets:
+
+ cd gadgets
+ make clean install
+
+
+Note: By default dzen will not be compiled with Xinerama and XPM support.
+ Uncomment the respective lines in config.mk to change this.
+
+
+Use "./help" to view a nicely formated version of the documentation.
21 LICENSE
@@ -0,0 +1,21 @@
+MIT/X Consortium License
+
+(C)opyright MMVII Robert Manea <rob dot manea at gmail dot com>
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
56 Makefile
@@ -0,0 +1,56 @@
+# dzen2
+# (C)opyright MMVII Robert Manea
+
+include config.mk
+
+SRC = draw.c main.c util.c action.c
+OBJ = ${SRC:.c=.o}
+
+all: options dzen2
+
+options:
+ @echo dzen2 build options:
+ @echo "CFLAGS = ${CFLAGS}"
+ @echo "LDFLAGS = ${LDFLAGS}"
+ @echo "CC = ${CC}"
+ @echo "LD = ${LD}"
+
+.c.o:
+ @echo CC $<
+ @${CC} -c ${CFLAGS} $<
+
+${OBJ}: dzen.h action.h config.mk
+
+dzen2: ${OBJ}
+ @echo LD $@
+ @${LD} -o $@ ${OBJ} ${LDFLAGS}
+ @strip $@
+ @echo "Run ./help for documentation"
+
+clean:
+ @echo cleaning
+ @rm -f dzen2 ${OBJ} dzen2-${VERSION}.tar.gz
+
+dist: clean
+ @echo creating dist tarball
+ @mkdir -p dzen2-${VERSION}
+ @mkdir -p dzen2-${VERSION}/gadgets
+ @mkdir -p dzen2-${VERSION}/bitmaps
+ @cp -R CREDITS LICENSE Makefile INSTALL README.dzen README help config.mk action.h dzen.h ${SRC} dzen2-${VERSION}
+ @cp -R gadgets/Makefile gadgets/config.mk gadgets/README.dbar gadgets/textwidth.c gadgets/README.textwidth gadgets/dbar.c gadgets/gdbar.c gadgets/README.gdbar gadgets/gcpubar.c gadgets/README.gcpubar gadgets/kittscanner.sh gadgets/README.kittscanner gadgets/noisyalert.sh dzen2-${VERSION}/gadgets
+ @cp -R bitmaps/alert.xbm bitmaps/ball.xbm bitmaps/battery.xbm bitmaps/envelope.xbm bitmaps/volume.xbm bitmaps/pause.xbm bitmaps/play.xbm bitmaps/music.xbm dzen2-${VERSION}/bitmaps
+ @tar -cf dzen2-${VERSION}.tar dzen2-${VERSION}
+ @gzip dzen2-${VERSION}.tar
+ @rm -rf dzen2-${VERSION}
+
+install: all
+ @echo installing executable file to ${DESTDIR}${PREFIX}/bin
+ @mkdir -p ${DESTDIR}${PREFIX}/bin
+ @cp -f dzen2 ${DESTDIR}${PREFIX}/bin
+ @chmod 755 ${DESTDIR}${PREFIX}/bin/dzen2
+
+uninstall:
+ @echo removing executable file from ${DESTDIR}${PREFIX}/bin
+ @rm -f ${DESTDIR}${PREFIX}/bin/dzen2
+
+.PHONY: all options clean dist install uninstall
608 README
@@ -0,0 +1,608 @@
+====================================
+ dzen, (c) 2007-2010 by Robert Manea
+====================================
+
+Dzen is a general purpose messaging, notification and menuing program for X11.
+It was designed to be fast, tiny and scriptable in any language.
+
+
+Features
+--------
+
+ * Small, fast, very tiny set of dependencies (Xlib only by default)
+ * Scriptable in any language
+ * Sophisticated formating language - including colours, icons, graphics
+ * Versatile - display all sorts of information
+ * Interactive - user defined mouse and keyboard actions
+ * Optional XFT support
+ * Optional XINERAMA support
+
+
+Requirements
+------------
+In order to build dzen you need the Xlib header files.
+
+
+Installation
+------------
+Edit config.mk to match your local setup (dzen is installed into
+the /usr/local namespace by default).
+
+Afterwards enter the following command to build and install dzen (if
+necessary as root):
+
+ make clean install
+
+
+Optionally if you want to use dzen's gadgets:
+
+ cd gadgets
+ make clean install
+
+
+Note: By default dzen will not be compiled with Xinerama and XPM support.
+ Uncomment the respective lines in config.mk to change this.
+
+
+Contact:
+--------
+Feature requests, patches or anything else related to dzen can be send
+to: rob dot manea at gmail dot com
+
+
+Running dzen
+------------
+dzen accepts a couple of options:
+
+ -fg foreground color
+ -bg background color
+ -fn font
+ -ta alignement of title window content
+ l(eft), c(center), r(ight)
+ -tw title window width
+ -sa alignment of slave window, see "-ta"
+ -l lines, see (1)
+ -e events and actions, see (2)
+ -m menu mode, see (3)
+ -u update contents of title and
+ slave window simultaneously, see (4)
+ -p persist EOF (optional timeout in seconds)
+ -x x position
+ -y y position
+ -h line height (default: fontheight + 2 pixels)
+ -w width
+ -xs number of Xinerama screen
+ -v version information
+
+ see (5) for the in-text formating language.
+
+
+
+X resources
+-----------
+
+Dzen is able to read font and color setting from X resources.
+As an example you can add following lines to ~/.Xresources
+
+dzen2.font: -*-fixed-*-*-*-*-*-*-*-*-*-*-*-*
+dzen2.foreground: #22EE11
+dzen2.background: black
+
+
+
+Window layout
+-------------
+
+Dzen's window layout is as follows:
+
+ ------------------------------------------
+ | Title window, single line |
+ `------------------------------------------´
+ | |
+ | scrollable |
+ | Slave window |
+ | multiple lines |
+ | lines to display simultaneously |
+ | controlled with the |
+ | '-l' option |
+ | |
+ | |
+ `------------------------------------------´
+
+The first line you provide to dzen always goes to the title window,
+all other consecutive lines will be drawn to the slave window unless
+you explicitly overide this with the (5) In-text formating language
+command ^tw().
+
+
+QA:
+---
+
+Q1: I don't want a slave window, what to do?
+
+A1: Do not provide the '-l' option, all lines will be displayed
+ in the title window, this is the default behaviour.
+
+
+Q2: I used the '-l' option but no slave window appears.
+
+A2: With the default event/action handling the slave window will
+ only be displayed if you hoover with the mouse over the title
+ window. See "(2) Events and actions" if you'd like to change
+ this.
+
+
+Q3: If I echo some text or cat a file dzen closes itself imediatelly.
+
+A3: There are 2 different approaches dzen uses to terminate itself,
+ see next section "Termination".
+
+
+Q4: Ok, the title and slave thing works, can I update the
+ contents of both windows at the same time?
+
+A4: Sure, see "(4) Simultaneous updates" or use the in-text
+ command "^tw()" to explicitly draw to the title windwow.
+ See section (5) for further details
+
+
+Q5: Can i chnage color of my input at runtime?
+
+A5: Yes, you can change both background and foreground colors and
+ much more See "(5) In-Text formating language"
+
+
+Q6: Can I use dzen as a menu?
+
+A6: Yes, both vertical and horizontal menus are supported.
+ See "(3) Menu" for further details.
+
+
+
+
+Termination:
+------------
+dzen uses two different approaches to terminate itself:
+
+ * Timed termination: if EOF is received -> terminate
+ - unless the '-p' option is set
+ · '-p' without argument persist forever
+ · '-p' with argument n persist for n seconds
+
+ * Interactive termination: if mouse button3 is clicked -> terminate
+ - this is the default behaviour, see (2)
+ - in some modes the Escape key terminates too, see (2)
+
+
+
+Return values:
+--------------
+0 - dzen received EOF
+1 - some error occured, inspect the error message
+user defined - set with 'exit:retval' action, see (2)
+
+
+
+(1) Option "-l": Slave window
+--------------------------------
+
+Enables support for displaying multiple lines. The parameter to "-l"
+specifies the number of lines to be displayed.
+
+These lines of input are held in the slave window which becomes active as soon
+as the pointer enters the title (default action) window.
+
+If the mouse leaves the slave window it will be hidden unless it is set
+sticky by clicking with Button2 into it (default action).
+
+Button4 and Button5 (mouse wheel) will scroll the slave window up
+and down if the content exceeds the window height (default action).
+
+
+
+(2) Option '-e': Events and actions
+-----------------------------------
+
+dzen allows the user to associate actions to events.
+
+The command line syntax is as follows:
+-e 'event1=action1:option1:...option<n>,...,action<m>;...;event<l>'
+
+Every event can take any number of actions and every action can take any number
+of options. (By default limited to 64 each, easily changable in action.h)
+
+An example:
+ -e 'button1=exec:xterm:firefox;entertitle=uncollapse,unhide;button3=exit'
+
+ Meaning:
+
+ button1=exec:xterm:firefox;
+ on Button1 event (Button1 press on the mouse) execute xterm and
+ firefox.
+ Note: xterm and firefox are options to the exec action
+
+ entertitle=uncollapse,unhide;
+ on entertitle (mouse pointer enters the title window) uncollapse
+ slave window and unhide the title window
+
+ button3=exit
+ on button3 event exit dzen
+
+
+Supported events:
+-----------------
+
+ onstart Perform actions right after startup
+ onexit Perform actions just before exiting
+ onnewinput Perform actions if there is new input for the slave window
+ button1 Mouse button1 released
+ button2 Mouse button2 released
+ button3 Mouse button3 released
+ button4 Mouse button4 released (usually scrollwheel)
+ button5 Mouse button5 released (usually scrollwheel)
+ button6 Mouse button6 released
+ button7 Mouse button7 released
+ entertitle Mouse enters the title window
+ leavetitle Mouse leaves the title window
+ enterslave Mouse enters the slave window
+ leaveslave Mouse leaves the slave window
+ sigusr1 SIGUSR1 received
+ sigusr2 SIGUSR2 received
+ key_KEYNAME Keyboard events (*)
+
+
+ (*) Keyboard events:
+ --------------------
+
+ Every key can be bound to an action (see below). The format is:
+ key_KEYNAME where KEYNAME is the name of the key as defined in
+ keysymdef.h (usually: /usr/include/X11/keysymdef.h). The part
+ after 'XK_' in keysymdef.h must be used for KEYNAME.
+
+
+
+Supported actions:
+------------------
+
+ exec:command1:..:n execute all given options
+ menuexec executes selected menu entry
+ exit:retval exit dzen and return 'retval'
+ print:str1:...:n write all given options to STDOUT
+ menuprint write selected menu entry to STDOUT
+ collapse collapse (roll-up) slave window
+ uncollapse uncollapse (roll-down) slave window
+ togglecollapse toggle collapsed state
+ stick stick slave window
+ unstick unstick slave window
+ togglestick toggle sticky state
+ hide hide title window
+ unhide unhide title window
+ togglehide toggle hide state
+ raise raise window to view (above all others)
+ lower lower window (behind all others)
+ scrollhome show head of input
+ scrollend show tail of input
+ scrollup:n scroll slave window n lines up (default n=1)
+ scrolldown:n scroll slave window n lines down (default n=1)
+ grabkeys enable keyboard support
+ ungrabkeys disable keyboard support
+ grabmouse enable mouse support
+ only needed with specific windowmanagers, such as fluxbox
+ ungrabmouse release mouse
+ only needed with specific windowmanagers, such as fluxbox
+
+
+Note: If no events/actions are specified dzen defaults to:
+
+ Title only mode:
+ ----------------
+
+ -e 'button3=exit:13'
+
+
+ Multiple lines and vertical menu mode:
+ --------------------------------------
+
+ -e 'entertitle=uncollapse,grabkeys;
+ enterslave=grabkeys;leaveslave=collapse,ungrabkeys;
+ button1=menuexec;button2=togglestick;button3=exit:13;
+ button4=scrollup;button5=scrolldown;
+ key_Escape=ungrabkeys,exit'
+
+
+ Horizontal menu mode:
+ ---------------------
+
+ -e 'enterslave=grabkeys;leaveslave=ungrabkeys;
+ button4=scrollup;button5=scrolldown;
+ key_Left=scrollup;key_Right=scrolldown;
+ button1=menuexec;button3=exit:13
+ key_Escape=ungrabkeys,exit'
+
+
+ If you define any events/actions, there is no default behaviour,
+ i.e. you will have to specify _all_ events/actions you want to
+ use.
+
+
+
+(3) Option '-m', Menu
+---------------------
+
+Dzen provides two menu modes, vertical and horizontal menus. You can
+access these modes by adding 'v'(ertical) or 'h'(horizontal) to the
+'-m' option. If nothing is specified dzen defaults to vertical menus.
+
+Vertical menu, both invocations are equivalent:
+ dzen2 -p -l 4 -m < file
+ dzen2 -p -l 4 -m v < file
+
+Horizontal menu:
+ dzen2 -p -l 4 -m h < file
+
+
+All actions beginning with "menu" work on the selected menu entry.
+
+Note: Menu mode only makes sense if '-l <n>' is specified!
+
+ Horizontal menus have no title window, so all actions
+ affecting the title window will be silently discarded
+ in this mode.
+
+
+
+(4) Option '-u', Simultaneous updates
+-------------------------------------
+
+** DEPRECATED **
+
+This option provides facilities to update the title and slave window at
+the same time.
+
+The way it works is best described by an example:
+
+ Motivation:
+
+ We want to display an updating clock in the title and some log
+ output in the slave window.
+
+ Solution:
+
+ while true; do
+ date # output goes to the title window
+ dmesg | tail -n 10 # output goes to the slave window
+ sleep 1
+ done | dzen2 -l 10 -u
+
+For this to work correctly it is essential to provide exactly the number
+of lines to the slave window as defined by the parameter to '-l'.
+
+
+
+(5) In-text formating & control language:
+-----------------------------------------
+
+This feature allows to dynamically (at runtime) format the text dzen
+displays and control its behaviour.
+
+Currently the following commands are supported:
+
+
+Note: Doubling the '^' character ('^^') will remove the special meaning from it.
+
+
+Colors:
+-------
+
+ ^fg(color) set foreground color
+ ^fg() without arguments, sets default fg color
+ ^bg(color) set background color
+ ^bg() without arguments, sets default bg color
+
+Graphics:
+---------
+
+ ^i(path) draw icon specified by path
+ Supported formats: XBM and optionally XPM
+
+ ^r(WIDTHxHEIGHT) draw a rectangle with the dimensions
+ WIDTH and HEIGHT
+ ^ro(WIDTHxHEIGHT) rectangle outline
+
+ ^c(RADIUS) draw a circle with size RADIUS pixels
+ ^co(RADIUS) circle outline
+
+Positioning:
+------------
+
+ ^p(ARGUMENT) position next input amount of PIXELs to the right
+ or left of the current position
+ a.k.a. relative positioning
+
+ ^pa(ARGUMENT) position next input at PIXEL
+ a.k.a. absolute positioning
+
+ ARGUMENT:
+
+ ^p(+-X) move X pixels to the right or left of the current position (on the X axis)
+
+ ^p(+-X;+-Y) move X pixels to the right or left and Y pixels up or down of the current
+ position (on the X and Y axis)
+
+ ^p(;+-Y) move Y pixels up or down of the current position (on the Y axis)
+
+ ^p() without parameters resets the Y position to its default
+
+ ^pa() takes the same parameters as described above but positions at
+ the absolute X and Y coordinates
+
+ Further ^p() also takes some symbolic names as argument:
+
+ _LOCK_X Lock the current X position, useful if you want to
+ align things vertically
+ _UNLOCK_X Unlock the X position
+ _LEFT Move current x-position to the left edge
+ _RIGHT Move current x-position to the right edge
+ _TOP Move current y-position to the top edge
+ _CENTER Move current x-position to center of the window
+ _BOTTOM Move current y-position to the bottom edge
+
+Interaction:
+------------
+
+ ^ca(BTN, CMD) ... ^ca()
+
+ Used to define 'clickable areas' anywhere inside the
+ title window.
+ - 'BTN' denotes the mouse button (1=left, 2=right, 3=middle, etc.)
+ - 'CMD' denotes the command that should be spawned when the specific
+ area has been clicked with the defined button
+ - '...' denotes any text or formating commands dzen accepts
+ - '^ca()' without arguments denotes the end of this clickable area
+
+ Example:
+ foo ^ca(1, echo one)^fg(red)click me and i'll echo one^fg()^ca() bar
+
+Actions as commands:
+--------------------
+
+ ^togglecollapse()
+ ^collapse()
+ ^uncollapse()
+ ^togglestick()
+ ^stick() See section (2) 'Events and actions' for a detailed description
+ ^unstick() of each command.
+ ^togglehide()
+ ^hide()
+ ^unhide()
+ ^raise()
+ ^lower()
+ ^scrollhome()
+ ^scrollend()
+ ^exit()
+
+Other:
+------
+
+ ^tw() draw to title window
+ This command has some annoyances, as only
+ the input after the command will be drawn
+ to the title window, so it is best used
+ only once and as first command per line.
+
+ ^cs() clear slave window
+ This command must be the first and only command
+ per line.
+
+ ^ib(VALUE) ignore background setting, VALUE can be either
+ 1 to ignore or 0 to not ignore the bg color set
+ with ^bg(color).
+ This command is useful in combination with ^p()
+ and ^pa() in order to position the input inside
+ other already drawn input.
+
+ Example:
+ ^ib(1)^fg(red)^ro(100x15)^p(-98)^fg(blue)^r(20x10)^fg(orange)^p(3)^r(40x10)^p(4)^fg(darkgreen)^co(12)^p(2)^c(10)
+
+
+
+These commands can appear anywhere and in any combination in dzen's
+input.
+
+The color can be specified either as symbolic name (e.g. red,
+darkgreen, etc.) or as #rrggbb hex-value (e.g. #ffffaa).
+
+Icons must be in the XBM or optionally XPM format, see the "bitmaps"
+directory for some sample icons. With the standard "bitmap" application
+you can easily draw your own icons.
+
+
+
+Some examples:
+
+ Input:
+ ^fg(red)I'm red text ^fg(blue)I am blue
+
+
+ Input:
+ ^bg(#ffaaaa)The ^fg(yellow)text to ^bg(blue)^fg(orange)colorize
+
+
+ Input:
+ ^fg(grey70)Some text containing ^^ characters
+
+
+ Input for icons:
+ ^i(bitmaps/envelope.xbm) I am an envelope ^fg(yellow)and ^i(bitmaps/battery.xbm) I'm a baterry.
+
+
+ Input for rectangles:
+ 6x4 rectangle ^r(6x4) ^fg(red)12x8 ^r(12x8) ^fg(yellow)and finally 100x15 ^r(100x15)
+
+
+ Input for relative positioning:
+ Some text^p(100)^fg(yellow)100 pixels to the right^p(50)^fg(red)50 more pixels to the right
+
+
+
+
+Examples:
+---------
+
+* Display message and timeout after 10 seconds:
+ (echo "This is a message"; sleep 10) | dzen2 -bg darkred -fg grey80 -fn fixed
+
+
+* Display message and never timeout:
+ echo "This is a message"| dzen2 -p
+
+
+* Display updating single line message:
+ for i in $(seq 1 20); do A=${A}'='; print $A; sleep 1; done | dzen2
+
+
+* Display header and a message with multiple lines:
+ (echo Header; cal; sleep 20) | dzen2 -l 8
+
+ Displays "Header" in the title window and the output of cal in the 8
+ lines high slave window.
+
+
+* Display updating messages:
+ (echo Header; while true; do echo test$((i++)); sleep 1; done) | dzen2 -l 12
+
+ The slave window will update contents if new input has arrived.
+
+
+* Display log files:
+ (su -c "echo LOGFILENAME; tail -f /var/log/messages") | dzen2 -l 20 -x 100 -y 300 -w 500
+
+
+* Monthly schedule with remind:
+ (echo Monthly Schedule; remind -c1 -m) | dzen2 -l 52 -w 410 -p -fn lime -bg '#e0e8ea' -fg black -x 635
+
+
+* Simple menu:
+ echo "Applications" | dzen2 -l 4 -p -m < menufile
+
+
+* Horizontal menu without any files:
+ {echo Menu; echo -e "xterm\nxclock\nxeyes\nxfontsel"} | dzen2 -l 4 -m h -p
+
+
+* Extract PIDs from the process table:
+
+ {echo Procs; ps -a} | dzen2 -m -l 12 -p \
+ -e 'button1=menuprint;button3=exit;button4=scrollup:3;button5=scrolldown:3;entertitle=uncollapse;leaveslave=collapse' \
+ | awk '{print $1}'
+
+
+* Dzen as xmonad (see http://xmonad.org) statusbar:
+
+ status.sh | dzen2 -ta r -fn '-*-profont-*-*-*-*-11-*-*-*-*-*-iso8859' -bg '#aecf96' -fg black \
+ -p -e 'sigusr1=raise;sigusr2=lower;onquit=exec:rm /tmp/dzen2-pid;button3=exit' & echo $! > /tmp/dzen2-pid
+
+
+
+
+Have fun.
591 README.dzen
@@ -0,0 +1,591 @@
+^fg(lightgreen)^r(190x4)^fg(#6fbf47)^r(38x4)^fg(darkgreen)^r(9x4)
+^fg(#6fbf47) dzen, (c) 2007 by Robert Manea
+^fg(darkgreen)^r(9x4)^fg(#6fbf47)^r(38x4)^fg(lightgreen)^r(190x4)
+
+A general purpose messaging, notification and menu program
+
+
+The "gadgets" subdirectory contains some tools that you can
+use in combination with dzen.
+
+Script archive with a collection of interesting ideas:
+^fg(lightblue) http://gotmor.googlepages.com/dzenscriptarchive
+
+
+
+^fg(#6fbf47)Features
+^fg(#6fbf47)--------
+
+ ^co(4x4) scriptable in any language
+
+ ^co(4x4) dynamic colorizer
+
+ ^co(4x4) icons support
+
+ ^co(4x4) keyboard support
+
+ ^co(4x4) single line and/or windows holding multiple lines
+
+ ^co(4x4) menu functionality
+
+ ^co(4x4) in-text formating language
+
+ ^co(4x4) flexible event/action mechanism
+
+ ^co(4x4) hideable, collapsable
+
+ ^co(4x4) Xinerama support
+
+
+^fg(#6fbf47)Requirements
+^fg(#6fbf47)------------
+In order to build dzen you need the Xlib header files.
+
+
+^fg(#6fbf47)Installation
+^fg(#6fbf47)------------
+Edit config.mk to match your local setup (dzen is installed into
+the /usr/local namespace by default).
+
+Afterwards enter the following command to build and install dzen (if
+necessary as root):
+
+ ^fg(grey85)make clean install
+
+
+Optionally if you want to use dzen's gadgets:
+
+ ^fg(grey85)cd gadgets
+ ^fg(grey85)make clean install
+
+
+^fg(Khaki)Note: By default dzen will ^fg(red)not^fg(Khaki) be compiled with Xinerama and XPM support.
+ ^fg(Khaki)Uncomment the respective lines in config.mk to change this.
+
+
+^fg(#6fbf47)Contact:
+^fg(#6fbf47)--------
+Feature requests, patches or anything else related to dzen can be send
+to: ^fg(Khaki)rob dot manea at gmail dot com
+
+
+^fg(#6fbf47)Running dzen
+^fg(#6fbf47)------------
+dzen accepts a couple of options:
+
+ -fg foreground color
+ -bg background color
+ -fn font
+ -ta alignement of title window content
+ l(eft), c(center), r(ight)
+ -tw title window width
+ -sa alignment of slave window, see "-ta"
+ -l lines, ^fg(#6fbf47)see (1)
+ -e events and actions, ^fg(#6fbf47)see (2)
+ -m menu mode, ^fg(#6fbf47)see (3)
+ -u update contents of title and
+ slave window simultaneously, ^fg(#6fbf47)see (4)
+ -p persist EOF (optional timeout in seconds)
+ -x x position
+ -y y position
+ -h line height (default: fontheight + 2 pixels)
+ -w width
+ -xs number of Xinerama screen
+ -v version information
+
+ ^fg(#6fbf47)see (5)^fg(), for the in-text formating language.
+
+
+
+^fg(#6fbf47)X resources
+^fg(#6fbf47)-----------
+
+Dzen is able to read font and color setting from X resources.
+As an example you can add following lines to ~/.Xresources
+
+^fg(Khaki)dzen2.font: -*-fixed-*-*-*-*-*-*-*-*-*-*-*-*
+^fg(Khaki)dzen2.foreground: #22EE11
+^fg(Khaki)dzen2.background: black
+
+
+
+^fg(#6fbf47)Window layout
+^fg(#6fbf47)-------------
+
+Dzen's window layout is as follows:
+
+^fg(red) ------------------------------------------
+^fg(red) | Title window, single line |
+^fg(red) `------------------------------------------´
+^fg(#6fbf47) | |
+^fg(#6fbf47) | scrollable |
+^fg(#6fbf47) | Slave window |
+^fg(#6fbf47) | multiple lines |
+^fg(#6fbf47) | lines to display simultaneously |
+^fg(#6fbf47) | controlled with the |
+^fg(#6fbf47) | '-l' option |
+^fg(#6fbf47) | |
+^fg(#6fbf47) | |
+^fg(#6fbf47) `------------------------------------------´
+
+The first line you provide to dzen always goes to the title window,
+all other consecutive lines will be drawn to the slave window unless
+you explicitly overide this with the ^fg(#6fbf47)(5) In-text formating language
+^fg()command ^^tw().
+
+
+^fg(#6fbf47)QA:
+^fg(#6fbf47)---
+
+Q1: I don't want a slave window, what to do?
+
+A1: Do not provide the '-l' option, all lines will be displayed
+ in the title window, this is the default behaviour.
+
+
+Q2: I used the '-l' option but no slave window appears.
+
+A2: With the default event/action handling the slave window will
+ only be displayed if you hoover with the mouse over the title
+ window. See ^fg(#6fbf47)(2) Events and actions ^fg()if you'd like to change
+ this.
+
+
+Q3: If I echo some text or cat a file dzen closes itself imediatelly.
+
+A3: There are 2 different approaches dzen uses to terminate itself,
+ see next section ^fg(#6fbf47)Termination^fg().
+
+
+Q4: Ok, the title and slave thing works, can I update the
+ contents of both windows at the same time?
+
+A4: Sure, see ^fg(#6fbf47)(4) Simultaneous updates ^fg()or use the in-text
+ command ^^tw() to explicitly draw to the title windwow.
+ See ^fg(#6fbf47)(5) In-Text formating language ^fg()for further details
+
+Q5: Can i chnage color of my input at runtime?
+
+A5: Yes, you can change both background and foreground colors and
+ much more See ^fg(#6fbf47)(5) In-Text formating language^fg().
+
+
+Q6: Can I use dzen as a menu?
+
+A6: Yes, both vertical and horizontal menus are supported.
+ See ^fg(#6fbf47)(3) Menu ^fg()for further details.
+
+
+
+
+^fg(#6fbf47)Termination:
+^fg(#6fbf47)------------
+dzen uses two different approaches to terminate itself:
+
+ ^co(4x4) Timed termination: if EOF is received -> terminate
+ - unless the '-p' option is set
+ · '-p' without argument persist forever
+ · '-p' with argument n persist for n seconds
+
+ ^co(4x4) Interactive termination: if mouse button3 is clicked -> terminate
+ - this is the default behaviour, ^fg(#6fbf47)see (2)
+ - in some modes the Escape key terminates too, ^fg(#6fbf47)see (2)
+
+
+
+^fg(#6fbf47)Return values:
+^fg(#6fbf47)--------------
+0 - dzen received EOF
+1 - some error occured, inspect the error message
+user defined - set with 'exit:retval' action, ^fg(#6fbf47)see (2)
+
+
+
+^fg(#6fbf47)(1) Option "-l": Slave window
+^fg(#6fbf47)--------------------------------
+
+Enables support for displaying multiple lines. The parameter to "-l"
+specifies the number of lines to be displayed.
+
+These lines of input are held in the slave window which becomes active as soon
+as the pointer enters the title (default action) window.
+
+If the mouse leaves the slave window it will be hidden unless it is set
+sticky by clicking with Button2 into it (default action).
+
+Button4 and Button5 (mouse wheel) will scroll the slave window up
+and down if the content exceeds the window height (default action).
+
+
+
+^fg(#6fbf47)(2) Option '-e': Events and actions
+^fg(#6fbf47)-----------------------------------
+
+dzen allows the user to associate actions to events.
+
+The command line syntax is as follows:
+-e 'event1=action1:option1:...option<n>,...,action<m>;...;event<l>'
+
+Every event can take any number of actions and every action can take any number
+of options. (By default limited to 64 each, easily changable in action.h)
+
+An example:
+^fg(grey70) -e 'button1=exec:xterm:firefox;entertitle=uncollapse,unhide;button3=exit'
+
+ Meaning:
+
+ ^fg(grey70)button1=exec:xterm:firefox;
+ on Button1 event (Button1 press on the mouse) execute xterm and
+ firefox.
+ ^fg(Khaki)Note: xterm and firefox are options to the exec action
+
+ ^fg(grey70)entertitle=uncollapse,unhide;
+ on entertitle (mouse pointer enters the title window) uncollapse
+ slave window and unhide the title window
+
+ ^fg(grey70)button3=exit
+ on button3 event exit dzen
+
+
+^fg(#6fbf47)Supported events:
+^fg(#6fbf47)-----------------
+
+ onstart Perform actions right after startup
+ onexit Perform actions just before exiting
+ onnewinput Perform actions if there is new input for the slave window
+ button1 Mouse button1 released
+ button2 Mouse button2 released
+ button3 Mouse button3 released
+ button4 Mouse button4 released (usually scrollwheel)
+ button5 Mouse button5 released (usually scrollwheel)
+ button6 Mouse button6 released
+ button7 Mouse button7 released
+ entertitle Mouse enters the title window
+ leavetitle Mouse leaves the title window
+ enterslave Mouse enters the slave window
+ leaveslave Mouse leaves the slave window
+ sigusr1 SIGUSR1 received
+ sigusr2 SIGUSR2 received
+ key_KEYNAME Keyboard events (*)
+
+
+ ^fg(#6fbf47)(*) Keyboard events:
+ ^fg(#6fbf47)--------------------
+
+ Every key can be bound to an action (see below). The format is:
+ key_KEYNAME where KEYNAME is the name of the key as defined in
+ keysymdef.h (usually: /usr/include/X11/keysymdef.h). The part
+ after 'XK_' in keysymdef.h must be used for KEYNAME.
+
+
+
+^fg(#6fbf47)Supported actions:
+^fg(#6fbf47)------------------
+
+ exec:command1:..:n execute all given options
+ menuexec executes selected menu entry
+ exit:retval exit dzen and return 'retval'
+ print:str1:...:n write all given options to STDOUT
+ menuprint write selected menu entry to STDOUT
+ collapse collapse (roll-up) slave window
+ uncollapse uncollapse (roll-down) slave window
+ togglecollapse toggle collapsed state
+ stick stick slave window
+ unstick unstick slave window
+ togglestick toggle sticky state
+ hide hide title window
+ unhide unhide title window
+ togglehide toggle hide state
+ raise raise window to view (above all others)
+ lower lower window (behind all others)
+ scrollhome show head of input
+ scrollend show tail of input
+ scrollup:n scroll slave window n lines up (default n=1)
+ scrolldown:n scroll slave window n lines down (default n=1)
+ grabkeys enable keyboard support
+ ungrabkeys disable keyboard support
+ grabmouse enable mouse support
+ only needed with specific windowmanagers, such as fluxbox
+ ungrabmouse release mouse
+ only needed with specific windowmanagers, such as fluxbox
+
+
+^fg(Khaki)Note: If no events/actions are specified dzen defaults to:
+
+ ^fg(#6fbf47)Title only mode:
+ ^fg(#6fbf47)----------------
+
+ -e 'button3=exit:13'
+
+
+ ^fg(#6fbf47)Multiple lines and vertical menu mode:
+ ^fg(#6fbf47)--------------------------------------
+
+ -e 'entertitle=uncollapse,grabkeys;
+ enterslave=grabkeys;leaveslave=collapse,ungrabkeys;
+ button1=menuexec;button2=togglestick;button3=exit:13;
+ button4=scrollup;button5=scrolldown;
+ key_Escape=ungrabkeys,exit'
+
+
+ ^fg(#6fbf47)Horizontal menu mode:
+ ^fg(#6fbf47)---------------------
+
+ -e 'enterslave=grabkeys;leaveslave=ungrabkeys;
+ button4=scrollup;button5=scrolldown;
+ key_Left=scrollup;key_Right=scrolldown;
+ button1=menuexec;button3=exit:13
+ key_Escape=ungrabkeys,exit'
+
+
+ ^fg(Khaki)If you define any events/actions, there is no default behaviour,
+ ^fg(Khaki)i.e. you will have to specify _all_ events/actions you want to
+ ^fg(Khaki)use.
+
+
+
+^fg(#6fbf47)(3) Option '-m', Menu
+^fg(#6fbf47)---------------------
+
+Dzen provides two menu modes, vertical and horizontal menus. You can
+access these modes by adding 'v'(ertical) or 'h'(orizontal) to the
+'-m' option. If nothing is specified dzen defaults to vertical menus.
+
+Vertical menu, both invocations are equivalent:
+ ^fg(grey70)dzen2 -p -l 4 -m < file
+ ^fg(grey70)dzen2 -p -l 4 -m v < file
+
+Horizontal menu:
+ ^fg(grey70)dzen2 -p -l 4 -m h < file
+
+
+All actions beginning with "menu" work on the selected menu entry.
+
+^fg(Khaki)Note: Menu mode only makes sense if '-l <n>' is specified!
+
+ ^fg(Khaki)Horizontal menus have no title window, so all actions
+ ^fg(Khaki)affecting the title window will be silently discarded
+ ^fg(Khaki)in this mode.
+
+
+
+^fg(#6fbf47)(4) Option '-u', Simultaneous updates
+^fg(#6fbf47)-------------------------------------
+
+This option provides facilities to update the title and slave window at
+the same time.
+
+The way it works is best described by an example:
+
+ Motivation:
+
+ We want to display an updating clock in the title and some log
+ output in the slave window.
+
+ Solution:
+
+ ^fg(grey70)while true; do
+ ^fg(grey70)date # output goes to the title window
+ ^fg(grey70)dmesg | tail -n 10 # output goes to the slave window
+ ^fg(grey70)sleep 1
+ ^fg(grey70)done | dzen2 -l 10 -u
+
+For this to work correctly it is essential to provide exactly the number
+of lines to the slave window as defined by the parameter to '-l'.
+
+
+
+^fg(#6fbf47)(5) In-text formating language:
+^fg(#6fbf47)-------------------------------
+
+This feature allows to dynamically (at runtime) format the text dzen
+displays.
+
+Currently the following commands are supported:
+
+
+Colors:
+-------
+
+ ^^fg(color) set foreground color
+ ^^fg() without arguments, sets default fg color
+ ^^bg(color) set background color
+ ^^bg() without arguments, sets default bg color
+
+Graphics:
+---------
+
+ ^^i(path) draw icon specified by path
+ Supported formats: XBM and optionally XPM
+
+ ^^r(WIDTHxHEIGHT) draw a rectangle with the dimensions
+ WIDTH and HEIGHT
+ ^^ro(WIDTHxHEIGHT) rectangle outline
+
+ ^^c(RADIUS) draw a circle with size RADIUS pixels
+ ^^co(RADIUS) circle outline
+
+Positioning:
+------------
+
+ ^^p(PIXEL) position next input amount of PIXELs to the right
+ or left of the current position
+ a.k.a. relative positioning
+
+ ^^pa(PIXEL) position next input at PIXEL
+ a.k.a. absolute positioning
+ For maximum predictability ^^pa() should only be
+ used with '-ta l' or '-sa l'
+Other:
+------
+
+ ^^tw() draw to title window
+ This command has some annoyances, as only
+ the input after the command will be drawn
+ to the title window, so it is best used
+ only once and as first command per line
+ Subject to be improved in the future.
+
+ ^^cs() clear slave window
+ This command must be the first and only command
+ per line.
+
+ ^^ib(VALUE) ignore background setting, VALUE can be either
+ 1 to ignore or 0 to not ignore the bg color set
+ with ^^bg(color)
+ This command is useful in combination with ^^pa()
+ in order to position the input inside other already
+ drawn input.
+
+ Example:
+ ^^ib(1)^^fg(red)^^ro(100x15)^^p(-98)^^fg(blue)^^r(20x10)^^fg(orange)^^p(3)^^r(40x10)^^p(4)^^fg(darkgreen)^^co(12)^^p(2)^^c(10)
+ Giving:
+ ^ib(1)^fg(red)^ro(100x15)^p(-98)^fg(blue)^r(20x10)^fg(orange)^p(3)^r(40x10)^p(4)^fg(darkgreen)^co(12)^p(2)^c(10)
+
+
+
+These commands can appear anywhere and in any combination in dzen's
+input.
+
+The color can be specified either as symbolic name (e.g. red,
+darkgreen, etc.) or as #rrggbb hex-value (e.g. #ffffaa).
+
+Icons must be in the XBM or optionally XPM format, see the "bitmaps"
+directory for some sample icons. With the standard "bitmap" application
+you can easily draw your own icons.
+
+^fg(Khaki)Note: Displaying XPM (pixmap) files imposes a somewhat
+ ^fg(Khaki)higher load than lightweight XBM files, so use
+ ^fg(Khaki)them with care in tight loops.
+
+
+Doubling the '^^' character removes the special meaning from it.
+
+
+Some examples:
+
+ Input:
+ ^^fg(red)I'm red text ^^fg(blue)I am blue
+
+ Resulting in:
+ ^fg(red)I'm red text ^fg(blue)I am blue
+
+
+ Input:
+ ^^bg(#ffaaaa)The ^^fg(yellow)text to ^^bg(blue)^^fg(orange)colorize
+
+ Resulting in:
+ ^bg(#ffaaaa)The ^fg(yellow)text to ^bg(blue)^fg(orange)colorize
+
+
+ Input:
+ ^^fg(white)Some text containing ^^^^ characters
+
+ Resulting in:
+ ^fg(white)Some text containing ^^ characters
+
+
+ Input for icons:
+ ^^i(bitmaps/envelope.xbm) I am an envelope ^^fg(yellow)and ^^i(bitmaps/battery.xbm) I'm a baterry.
+
+ Resulting in:
+ ^i(bitmaps/envelope.xbm) I am an envelope ^fg(yellow)and ^i(bitmaps/battery.xbm) I'm a baterry.
+
+
+ Input for rectangles:
+ 6x4 rectangle ^^r(6x4) ^^fg(red)12x8 ^^r(12x8) ^^fg(yellow)and finally 100x15 ^^r(100x15)
+
+ Resulting in:
+ 6x4 rectangle ^r(6x4) ^fg(red)12x8 ^r(12x8) ^fg(yellow)and finally 100x15 ^r(100x15)
+
+
+ Input for relative positioning:
+ Some text^^p(100)^^fg(yellow)100 pixels to the right^^p(50)^^fg(red)50 more pixels to the right
+
+ Resulting in:
+ Some text^p(100)^fg(yellow)100 pixels to the right^p(50)^fg(red)50 more pixels to the right
+
+
+
+
+
+^fg(#6fbf47)Examples:
+^fg(#6fbf47)---------
+
+^co(4x4) Display message and timeout after 10 seconds:
+^fg(grey85) (echo "This is a message"; sleep 10) | dzen2 -bg darkred -fg grey85 -fn fixed
+
+
+^co(4x4) Display message and never timeout:
+^fg(grey85) echo "This is a message"| dzen2 -p
+
+
+^co(4x4) Display updating single line message:
+^fg(grey85) for i in $(seq 1 20); do A=${A}'='; print $A; sleep 1; done | dzen2
+
+
+^co(4x4) Display header and a message with multiple lines:
+^fg(grey85) (echo Header; cal; sleep 20) | dzen2 -l 8
+
+ Displays "Header" in the title window and the output of cal in the
+ 8 lines high slave window.
+
+
+^co(4x4) Display updating messages:
+^fg(grey85) (echo Header; while true; do echo test$((i++)); sleep 1; done) | dzen2 -l 12
+
+ The slave window will update contents if new input has arrived.
+
+
+^co(4x4) Display log files:
+^fg(grey85) (su -c "echo LOGFILENAME; tail -f /var/log/messages") | dzen2 -l 20 -x 100 -y 300 -w 500
+
+
+^co(4x4) Monthly schedule with remind:
+^fg(grey85) (echo Monthly Schedule; remind -c1 -m) | dzen2 -l 52 -w 410 -p -fn lime -bg '#e0e8ea' -fg black -x 635
+
+
+^co(4x4) Simple menu:
+^fg(grey85) echo "Applications" | dzen2 -l 4 -p -m < menufile
+
+
+^co(4x4) Horizontal menu without any files:
+^fg(grey85) {echo Menu; echo -e "xterm\nxclock\nxeyes\nxfontsel"} | dzen2 -l 4 -m h -p
+
+
+^co(4x4) Extract PIDs from the process table:
+
+^fg(grey85) {echo Procs; ps -a} | dzen2 -m -l 12 -p \
+^fg(grey85) -e 'button1=menuprint;button3=exit;button4=scrollup:3;button5=scrolldown:3;entertitle=uncollapse;leaveslave=collapse' \
+^fg(grey85) | awk '{print $1}'
+
+
+^co(4x4) Dzen as xmonad (see http://xmonad.org) statusbar:
+
+^fg(grey85) status.sh | dzen2 -ta r -fn '-*-profont-*-*-*-*-11-*-*-*-*-*-iso8859' -bg '#aecf96' -fg black \
+^fg(grey85) -p -e 'sigusr1=raise;sigusr2=lower;onquit=exec:rm /tmp/dzen2-pid;button3=exit' & echo $! > /tmp/dzen2-pid
+
+
+
+
+Have fun.
24 TODO
@@ -0,0 +1,24 @@
+# documentation
+
+ o `-dock' and `-geometry' options are undocumented
+
+
+# X related
+
+ o XRandR support (MEDIUM PRIORITY)
+ o cache XPM files in order to improve drawing
+ performace (HIGH PRIORITY, done in svn trunk)
+
+
+# extend available actions
+
+ o set font action (LOW PRIORITY)
+ o any other useful action (LOW PRIORITY)
+
+
+# user interface
+
+ o improve in-text command to draw
+ to the title window (MEDIUM PRIORITY, done in svn trunk)
+ o auto fit window width to
+ text length (MEDIUM PRIORITY, done in svn trunk)
571 action.c
@@ -0,0 +1,571 @@
+/*
+* (C)opyright 2007-2009 Robert Manea <rob dot manea at gmail dot com>
+* See LICENSE file for license details.
+*
+*/
+
+#include "dzen.h"
+#include "action.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+struct event_lookup ev_lookup_table[] = {
+ { "onstart", onstart},
+ { "onexit", onexit},
+ { "onnewinput", onnewinput},
+ { "button1", button1},
+ { "button2", button2},
+ { "button3", button3},
+ { "button4", button4},
+ { "button5", button5},
+ { "button6", button6},
+ { "button7", button7},
+ { "entertitle", entertitle},
+ { "leavetitle", leavetitle},
+ { "enterslave", enterslave},
+ { "leaveslave", leaveslave},
+ { "sigusr1", sigusr1},
+ { "sigusr2", sigusr2},
+ { "keymarker", keymarker},
+ { 0, 0 }
+};
+
+struct action_lookup ac_lookup_table[] = {
+ { "print", a_print },
+ { "exec", a_exec},
+ { "exit", a_exit},
+ { "collapse", a_collapse},
+ { "uncollapse", a_uncollapse},
+ { "togglecollapse", a_togglecollapse},
+ { "stick", a_stick},
+ { "unstick", a_unstick},
+ { "togglestick", a_togglestick},
+ { "hide", a_hide},
+ { "unhide", a_unhide},
+ { "togglehide", a_togglehide},
+ { "scrollup", a_scrollup},
+ { "scrolldown", a_scrolldown},
+ { "menuprint", a_menuprint},
+ { "menuprint_noparse", a_menuprint_noparse},
+ { "menuexec", a_menuexec},
+ { "raise", a_raise},
+ { "lower", a_lower},
+ { "scrollhome", a_scrollhome},
+ { "scrollend", a_scrollend},
+ { "grabkeys", a_grabkeys},
+ { "ungrabkeys", a_ungrabkeys},
+ { "grabmouse", a_grabmouse},
+ { "ungrabmouse", a_ungrabmouse},
+ { 0, 0 }
+};
+
+ev_list *head = NULL;
+
+static int
+new_event(long evid) {
+ ev_list *item, *newitem;
+
+ if(!head) {
+ head = emalloc(sizeof (ev_list));
+ head->id = evid;
+ head->next = NULL;
+ }
+ else {
+ item = head;
+ /* check if we already handle this event */
+ while(item) {
+ if(item->id == evid)
+ return 0;
+ item = item->next;
+ }
+ item = head;
+ while(item->next)
+ item = item->next;
+
+ newitem = emalloc(sizeof (ev_list));
+ newitem->id = evid;
+ item->next = newitem;
+ newitem->next = NULL;
+ }
+ return 0;
+}
+
+static void
+add_handler(long evid, int hpos, handlerf* hcb) {
+ ev_list *item;
+
+ item = head;
+ while(item) {
+ if(item->id == evid) {
+ if(hpos < MAXACTIONS) {
+ item->action[hpos] = emalloc(sizeof(As));
+ item->action[hpos]->handler = hcb;
+ }
+ break;
+ }
+ item = item->next;
+ }
+}
+
+static void
+add_option(long evid, int hpos, int opos, char* opt) {
+ ev_list *item;
+
+ item = head;
+ while(item) {
+ if(item->id == evid) {
+ if(opos < MAXOPTIONS) {
+ item->action[hpos]->options[opos] = estrdup(opt);
+ item->action[hpos]->options[opos+1] = NULL;
+ }
+ break;
+ }
+ item = item->next;
+ }
+}
+
+int
+find_event(long evid) {
+ ev_list *item;
+
+ item = head;
+ while(item) {
+ if(item->id == evid)
+ return item->id;
+ item = item->next;
+ }
+
+ return -1;
+}
+
+void
+do_action(long evid) {
+ int i;
+ ev_list *item;
+
+ item = head;
+ while(item) {
+ if(item->id == evid)
+ break;
+ item = item->next;
+ }
+
+ if(item) {
+ for(i=0; item->action[i]->handler; i++) {
+ item->action[i]->handler(item->action[i]->options);
+ }
+ }
+}
+
+int
+get_ev_id(const char *evname) {
+ int i;
+ KeySym ks;
+
+ /* check for keyboard event */
+ if((!strncmp(evname, "key_", 4))
+ && ((ks = XStringToKeysym(evname+4)) != NoSymbol)) {
+ return ks+keymarker;
+ }
+
+ /* own events */
+ for(i=0; ev_lookup_table[i].name; i++) {
+ if(strncmp(ev_lookup_table[i].name, evname, strlen(ev_lookup_table[i].name)) == 0)
+ return ev_lookup_table[i].id;
+ }
+ return -1;
+}
+
+handlerf *
+get_action_handler(const char *acname) {
+ int i;
+
+ for(i=0; ac_lookup_table[i].name; i++) {
+ if(strcmp(ac_lookup_table[i].name, acname) == 0)
+ return ac_lookup_table[i].handler;
+ }
+ return NULL;
+}
+
+
+void
+free_event_list(void) {
+ int i;
+ ev_list *item;
+
+ item = head;
+ while(item) {
+ for(i=0; item->action[i]->handler; i++)
+ free(item->action[i]);
+ item = item->next;
+ }
+}
+
+void
+fill_ev_table(char *input) {
+ char *str1, *str2, *str3, *str4,
+ *token, *subtoken, *kommatoken, *dptoken;
+ char *saveptr1=NULL,
+ *saveptr2=NULL,
+ *saveptr3=NULL,
+ *saveptr4=NULL;
+ int j, i=0, k=0;
+ long eid=0;
+ handlerf *ah=0;
+
+ for (j = 1, str1 = input; ; j++, str1 = NULL) {
+ token = strtok_r(str1, ";", &saveptr1);
+ if (token == NULL)
+ break;
+
+ for (str2 = token; ; str2 = NULL) {
+ subtoken = strtok_r(str2, "=", &saveptr2);
+ if (subtoken == NULL)
+ break;
+ if( (str2 == token) && ((eid = get_ev_id(subtoken)) != -1))
+ ;
+ else if(eid == -1)
+ break;
+
+ for (str3 = subtoken; ; str3 = NULL) {
+ kommatoken = strtok_r(str3, ",", &saveptr3);
+ if (kommatoken == NULL)
+ break;
+
+ for (str4 = kommatoken; ; str4 = NULL) {
+ dptoken = strtok_r(str4, ":", &saveptr4);
+ if (dptoken == NULL) {
+ break;
+ }
+ if(str4 == kommatoken && str4 != token && eid != -1) {
+ if((ah = get_action_handler(dptoken)) != NULL) {
+ new_event(eid);
+ add_handler(eid, i, ah);
+ i++;
+ }
+ }
+ else if(str4 != token && eid != -1 && ah) {
+ add_option(eid, i-1, k, dptoken);
+ k++;
+ }
+ else if(!ah)
+ break;
+ }
+ k=0;
+ }
+ new_event(eid);
+ add_handler(eid, i, NULL);
+ i=0;
+ }
+ }
+}
+
+
+/* actions */
+int
+a_exit(char * opt[]) {
+ if(opt[0])
+ dzen.ret_val = atoi(opt[0]);
+ dzen.running = False;
+ return 0;
+}
+
+int
+a_collapse(char * opt[]){
+ (void)opt;
+ if(!dzen.slave_win.ishmenu
+ && dzen.slave_win.max_lines
+ && !dzen.slave_win.issticky) {
+ XUnmapWindow(dzen.dpy, dzen.slave_win.win);
+ }
+ return 0;
+}
+
+int
+a_uncollapse(char * opt[]){
+ int i;
+ (void)opt;
+ if(!dzen.slave_win.ishmenu
+ && dzen.slave_win.max_lines
+ && !dzen.slave_win.issticky) {
+ XMapRaised(dzen.dpy, dzen.slave_win.win);
+ for(i=0; i < dzen.slave_win.max_lines; i++)
+ XMapWindow(dzen.dpy, dzen.slave_win.line[i]);
+ }
+ return 0;
+}
+
+int
+a_togglecollapse(char * opt[]){
+ XWindowAttributes wa;
+ (void)opt;
+
+ if(dzen.slave_win.max_lines &&
+ (XGetWindowAttributes(dzen.dpy, dzen.slave_win.win, &wa), wa.map_state == IsUnmapped))
+ a_uncollapse(NULL);
+ else
+ a_collapse(NULL);
+
+ return 0;
+}
+
+int
+a_stick(char * opt[]) {
+ (void)opt;
+ if(!dzen.slave_win.ishmenu
+ && dzen.slave_win.max_lines)
+ dzen.slave_win.issticky = True;
+ return 0;
+}
+
+int
+a_unstick(char * opt[]) {
+ (void)opt;
+ if(!dzen.slave_win.ishmenu
+ && dzen.slave_win.max_lines)
+ dzen.slave_win.issticky = False;
+ return 0;
+}
+
+int
+a_togglestick(char * opt[]) {
+ (void)opt;
+ if(!dzen.slave_win.ishmenu
+ && dzen.slave_win.max_lines)
+ dzen.slave_win.issticky = dzen.slave_win.issticky ? False : True;
+ return 0;
+}
+
+static void
+scroll(int n) {
+ if(dzen.slave_win.tcnt <= dzen.slave_win.max_lines)
+ return;
+ if(dzen.slave_win.first_line_vis + n < 0) {
+ dzen.slave_win.first_line_vis = 0;
+ dzen.slave_win.last_line_vis = dzen.slave_win.max_lines;
+ }
+ else if(dzen.slave_win.last_line_vis + n > dzen.slave_win.tcnt) {
+ dzen.slave_win.first_line_vis = dzen.slave_win.tcnt - dzen.slave_win.max_lines;
+ dzen.slave_win.last_line_vis = dzen.slave_win.tcnt;
+ }
+ else {
+ dzen.slave_win.first_line_vis += n;
+ dzen.slave_win.last_line_vis += n;
+ }
+
+ x_draw_body();
+}
+
+int
+a_scrollup(char * opt[]) {
+ int n=1;
+
+ if(opt[0])
+ n = atoi(opt[0]);
+ if(dzen.slave_win.max_lines)
+ scroll(-1*n);
+
+ return 0;
+}
+
+int
+a_scrolldown(char * opt[]) {
+ int n=1;
+
+ if(opt[0])
+ n = atoi(opt[0]);
+ if(dzen.slave_win.max_lines)
+ scroll(n);
+
+ return 0;
+}
+
+int
+a_hide(char * opt[]) {
+ int n=1;
+
+
+ printf("n:%d\n", n);
+ if(!dzen.title_win.ishidden) {
+ if(!dzen.slave_win.ishmenu)
+ XResizeWindow(dzen.dpy, dzen.title_win.win, dzen.title_win.width, 1);
+ else
+ XResizeWindow(dzen.dpy, dzen.slave_win.win, dzen.title_win.width, 1);
+
+ dzen.title_win.ishidden = True;
+ }
+ return 0;
+}
+
+int
+a_unhide(char * opt[]) {
+ (void)opt;
+ if(dzen.title_win.ishidden) {
+ if(!dzen.slave_win.ishmenu)
+ XResizeWindow(dzen.dpy, dzen.title_win.win, dzen.title_win.width, dzen.line_height);
+ else
+ XResizeWindow(dzen.dpy, dzen.slave_win.win, dzen.title_win.width, dzen.line_height);
+
+ dzen.title_win.ishidden = False;
+ }
+ return 0;
+}
+
+int
+a_togglehide(char * opt[]) {
+
+ dzen.title_win.ishidden ?
+ a_unhide(NULL) :
+ a_hide(opt);
+
+ return 0;
+}
+
+int
+a_exec(char * opt[]) {
+ int i;
+
+ if(opt)
+ for(i=0; opt[i]; i++)
+ if(opt[i]) spawn(opt[i]);
+ return 0;
+}
+
+int
+a_print(char * opt[]) {
+ int i;
+
+ if(opt)
+ for(i=0; opt[i]; i++)
+ puts(opt[i]);
+ return 0;
+}
+
+int
+a_menuprint(char * opt[]) {
+ char *text;
+ int i;
+
+ if(dzen.slave_win.ismenu && dzen.slave_win.sel_line != -1
+ && (dzen.slave_win.sel_line + dzen.slave_win.first_line_vis) < dzen.slave_win.tcnt) {
+ text = parse_line(NULL, dzen.slave_win.sel_line, 0, 0, 1);
+ printf("%s", text);
+ if(opt)
+ for(i=0; opt[i]; ++i)
+ printf("%s", opt[i]);
+ puts("");
+ fflush(stdout);
+ dzen.slave_win.sel_line = -1;
+ free(text);
+ }
+ return 0;
+}
+
+int
+a_menuprint_noparse(char * opt[]) {
+ int i;
+
+ if(dzen.slave_win.ismenu && dzen.slave_win.sel_line != -1
+ && (dzen.slave_win.sel_line + dzen.slave_win.first_line_vis) < dzen.slave_win.tcnt) {
+ printf("%s", dzen.slave_win.tbuf[dzen.slave_win.sel_line]);
+ if(opt)
+ for(i=0; opt[i]; ++i)
+ printf("%s", opt[i]);
+ puts("");
+ fflush(stdout);
+ dzen.slave_win.sel_line = -1;
+ }
+ return 0;
+}
+
+int
+a_menuexec(char * opt[]) {
+ char *text;
+ (void)opt;
+
+ if(dzen.slave_win.ismenu && dzen.slave_win.sel_line != -1
+ && (dzen.slave_win.sel_line + dzen.slave_win.first_line_vis) < dzen.slave_win.tcnt) {
+ text = parse_line(NULL, dzen.slave_win.sel_line, 0, 0, 1);
+ spawn(text);
+ dzen.slave_win.sel_line = -1;
+ free(text);
+ }
+ return 0;
+}
+
+int
+a_raise(char * opt[]) {
+ (void)opt;
+ XRaiseWindow(dzen.dpy, dzen.title_win.win);
+
+ if(dzen.slave_win.max_lines)
+ XRaiseWindow(dzen.dpy, dzen.slave_win.win);
+ return 0;
+}
+
+int
+a_lower(char * opt[]) {
+ (void)opt;
+ XLowerWindow(dzen.dpy, dzen.title_win.win);
+
+ if(dzen.slave_win.max_lines)
+ XLowerWindow(dzen.dpy, dzen.slave_win.win);
+ return 0;
+}
+
+int
+a_scrollhome(char * opt[]) {
+ (void)opt;
+ if(dzen.slave_win.max_lines) {
+ dzen.slave_win.first_line_vis = 0;
+ dzen.slave_win.last_line_vis = dzen.slave_win.max_lines;
+
+ x_draw_body();
+ }
+ return 0;
+}
+
+int
+a_scrollend(char * opt[]) {
+ (void)opt;
+ if(dzen.slave_win.max_lines) {
+ dzen.slave_win.first_line_vis = dzen.slave_win.tcnt - dzen.slave_win.max_lines ;
+ dzen.slave_win.last_line_vis = dzen.slave_win.tcnt;
+
+ x_draw_body();
+ }
+ return 0;
+}
+
+int
+a_grabkeys(char * opt[]) {
+ (void)opt;
+ XGrabKeyboard(dzen.dpy, RootWindow(dzen.dpy, dzen.screen),
+ True, GrabModeAsync, GrabModeAsync, CurrentTime);
+ return 0;
+}
+
+int
+a_ungrabkeys(char * opt[]) {
+ (void)opt;
+ XUngrabKeyboard(dzen.dpy, CurrentTime);
+ return 0;
+}
+
+int
+a_grabmouse(char * opt[]) {
+ (void)opt;
+ XGrabPointer(dzen.dpy, RootWindow(dzen.dpy, dzen.screen),
+ True, ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
+ return 0;
+}
+
+int
+a_ungrabmouse(char * opt[]) {
+ (void)opt;
+ XUngrabPointer(dzen.dpy, CurrentTime);
+ return 0;
+}
+
86 action.h
@@ -0,0 +1,86 @@
+/*
+ * (C)opyright 2007-2009 Robert Manea <rob dot manea at gmail dot com>
+ * See LICENSE file for license details.
+ *
+ */
+
+#define MAXACTIONS 64
+#define MAXOPTIONS 64
+
+/* Event, Action data structures */
+typedef struct AS As;
+typedef struct _ev_list ev_list;
+typedef int handlerf(char **);
+
+enum ev_id {
+ /* startup, exit, input */
+ onstart, onexit, onnewinput,
+ /* mouse buttons */
+ button1, button2, button3, button4, button5, button6, button7,
+ /* entering/leaving windows */
+ entertitle, leavetitle, enterslave, leaveslave,
+ /* external signals */
+ sigusr1, sigusr2,
+ /* key event marker
+ * must always be the last entry
+ */
+ keymarker
+};
+
+struct _ev_list {
+ long id;
+ As *action[MAXACTIONS];
+ ev_list *next;
+};
+
+struct event_lookup {
+ const char *name;
+ long id;
+};
+
+struct action_lookup {
+ const char *name;
+ int (*handler)(char **);
+};
+
+struct AS {
+ char *options[MAXOPTIONS];
+ int (*handler)(char **);
+};
+
+
+/* utility functions */
+void do_action(long);
+int get_ev_id(const char *);
+handlerf *get_action_handler(const char *);
+void fill_ev_table(char *);
+void free_event_list(void);
+int find_event(long);
+
+/* action handlers */
+int a_print(char **);
+int a_exit(char **);
+int a_exec(char **);
+int a_collapse(char **);
+int a_uncollapse(char **);
+int a_togglecollapse(char **);
+int a_stick(char **);
+int a_unstick(char **);
+int a_togglestick(char **);
+int a_scrollup(char **);
+int a_scrolldown(char **);
+int a_hide(char **);
+int a_unhide(char **);
+int a_togglehide(char **);
+int a_menuprint(char **);
+int a_menuprint_noparse(char **);
+int a_menuexec(char **);
+int a_raise(char **);
+int a_lower(char **);
+int a_scrollhome(char **);
+int a_scrollend(char **);
+int a_grabkeys(char **);
+int a_ungrabkeys(char **);
+int a_grabmouse(char **);
+int a_ungrabmouse(char **);
+
6 bitmaps/alert.xbm
@@ -0,0 +1,6 @@
+#define alert_width 16
+#define alert_height 16
+static unsigned char alert_bits[] = {
+ 0xff, 0xff, 0x01, 0xf8, 0xf1, 0xf9, 0xe1, 0xc1, 0xe1, 0xc1, 0xe1, 0xc1,
+ 0xe1, 0xc1, 0xe1, 0xc1, 0xe1, 0xc1, 0xe1, 0xc1, 0x01, 0xc0, 0xe1, 0xc1,
+ 0xe1, 0xc1, 0x01, 0xc0, 0xff, 0xff, 0xff, 0xff};
8 bitmaps/ball.xbm
@@ -0,0 +1,8 @@
+#define ball_width 19
+#define ball_height 19
+static unsigned char ball_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x00, 0xe0, 0x3f, 0x00,
+ 0xf0, 0x7f, 0x00, 0x78, 0xfc, 0x00, 0x38, 0xf8, 0x00, 0x7c, 0xfe, 0x01,
+ 0xfc, 0xff, 0x01, 0xfc, 0xff, 0x01, 0xfc, 0xff, 0x01, 0xfc, 0xff, 0x01,
+ 0xf8, 0xff, 0x00, 0xf8, 0xff, 0x00, 0xf0, 0x7f, 0x00, 0xe0, 0x3f, 0x00,
+ 0x80, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
6 bitmaps/battery.xbm
@@ -0,0 +1,6 @@
+#define battery_width 15
+#define battery_height 15
+static unsigned char battery_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f,
+ 0xfc, 0x08, 0xfc, 0x38, 0xfc, 0x38, 0xfc, 0x08, 0xfc, 0x0f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
6 bitmaps/envelope.xbm
@@ -0,0 +1,6 @@
+#define envelope_width 15
+#define envelope_height 15
+static unsigned char envelope_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x1f, 0x0c, 0x18, 0x1c, 0x1c,
+ 0x34, 0x16, 0xc4, 0x11, 0x84, 0x10, 0x04, 0x10, 0xfc, 0x1f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
7 bitmaps/music.xbm
@@ -0,0 +1,7 @@
+#define music_width 16
+#define music_height 16
+static unsigned char music_bits[] = {
+ 0x00, 0x00, 0xe0, 0x00, 0xe0, 0x03, 0x20, 0x1f, 0x20, 0x1c, 0x20, 0x10,
+ 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x2c, 0x10, 0x3e, 0x10, 0x1e, 0x16,
+ 0x0c, 0x1f, 0x00, 0x0f, 0x00, 0x06, 0x00, 0x00 };
+
7 bitmaps/pause.xbm
@@ -0,0 +1,7 @@
+#define pause_width 16
+#define pause_height 16
+static unsigned char pause_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x1e, 0x78, 0x1e, 0x78, 0x1e,
+ 0x78, 0x1e, 0x78, 0x1e, 0x78, 0x1e, 0x78, 0x1e, 0x78, 0x1e, 0x78, 0x1e,
+ 0x78, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
7 bitmaps/play.xbm
@@ -0,0 +1,7 @@
+#define play_width 16
+#define play_height 16
+static unsigned char play_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x78, 0x00, 0xf8, 0x01,
+ 0xf8, 0x07, 0xf8, 0x1f, 0xf8, 0x1f, 0xf8, 0x07, 0xf8, 0x01, 0x78, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
6 bitmaps/volume.xbm
@@ -0,0 +1,6 @@
+#define volume_width 16
+#define volume_height 16
+static unsigned char volume_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x1b, 0x60, 0x1b, 0x60, 0x1b,
+ 0x6c, 0x1b, 0x6c, 0x1b, 0x6c, 0x1b, 0x60, 0x1b, 0x60, 0x1b, 0x00, 0x1b,
+ 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
73 config.mk
@@ -0,0 +1,73 @@
+# dzen version
+VERSION = 0.9.5-svn
+
+# Customize below to fit your system
+
+# paths
+PREFIX = /usr/local
+MANPREFIX = ${PREFIX}/share/man
+
+X11INC = /usr/X11R6/include
+X11LIB = /usr/X11R6/lib
+INCS = -I. -I/usr/include -I${X11INC}
+
+# Configure the features you want to be supported
+# Only one of the following options has to be uncommented,
+# all others must be commented!
+#
+# Uncomment: Remove # from the beginning of respective lines
+# Comment : Add # to the beginning of the respective lines
+
+## Option 1: No Xinerama no XPM no XFT
+#LIBS = -L/usr/lib -lc -L${X11LIB} -lX11
+#CFLAGS = -Wall -Os ${INCS} -DVERSION=\"${VERSION}\"
+
+
+## Option 2: No Xinerama with XPM
+#LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 -lXpm
+#CFLAGS = -Wall -Os ${INCS} -DVERSION=\"${VERSION}\" -DDZEN_XPM
+
+
+# Option 3: With Xinerama no XPM
+#LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 -lXinerama
+#CFLAGS = -Wall -Os ${INCS} -DVERSION=\"${VERSION}\" -DDZEN_XINERAMA
+
+
+## Option 4: With Xinerama and XPM
+#LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 -lXinerama -lXpm
+#CFLAGS = -Wall -Os ${INCS} -DVERSION=\"${VERSION}\" -DDZEN_XINERAMA -DDZEN_XPM
+
+
+## Option 5: With XFT
+LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 `pkg-config --libs xft`
+CFLAGS = -Wall -Os ${INCS} -DVERSION=\"${VERSION}\" -DDZEN_XFT `pkg-config --cflags xft`
+
+
+## Option 6: With XPM and XFT
+#LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 -lXpm `pkg-config --libs xft`
+#CFLAGS = -Wall -Os ${INCS} -DVERSION=\"${VERSION}\" -DDZEN_XPM -DDZEN_XFT `pkg-config --cflags xft`
+
+
+## Option 7: With Xinerama and XPM and XFT
+#LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 -lXinerama -lXpm `pkg-config --libs xft`
+#CFLAGS = -Wall -Os ${INCS} -DVERSION=\"${VERSION}\" -DDZEN_XINERAMA -DDZEN_XPM -DDZEN_XFT `pkg-config --cflags xft`
+
+
+
+# END of feature configuration
+
+
+LDFLAGS = ${LIBS}
+
+# Solaris, uncomment for Solaris
+#CFLAGS = -fast ${INCS} -DVERSION=\"${VERSION}\"
+#LDFLAGS = ${LIBS}
+#CFLAGS += -xtarget=ultra
+
+# Debugging
+#CFLAGS = ${INCS} -DVERSION=\"${VERSION}\" -std=gnu89 -pedantic -Wall -W -Wundef -Wendif-labels -Wshadow -Wpointer-arith -Wbad-function-cast -Wcast-align -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes -Wnested-externs -Winline -Wdisabled-optimization -O2 -pipe -DDZEN_XFT `pkg-config --cflags xft`
+#LDFLAGS = ${LIBS}
+
+# compiler and linker
+CC = gcc
+LD = ${CC}
1,051 draw.c
@@ -0,0 +1,1051 @@
+
+/*
+* (C)opyright 2007-2009 Robert Manea <rob dot manea at gmail dot com>
+* See LICENSE file for license details.
+*
+*/
+
+#include "dzen.h"
+#include "action.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef DZEN_XPM
+#include <X11/xpm.h>
+#endif
+
+#define ARGLEN 256
+#define MAX_ICON_CACHE 32
+
+#define MAX(a,b) ((a)>(b)?(a):(b))
+
+typedef struct ICON_C {
+ char name[ARGLEN];
+ Pixmap p;
+
+ int w, h;
+} icon_c;
+
+icon_c icons[MAX_ICON_CACHE];
+int icon_cnt;
+int otx;
+int xorig=0;
+
+/* command types for the in-text parser */
+enum ctype {bg, fg, icon, rect, recto, circle, circleo, pos, abspos, titlewin, ibg, fn, fixpos, ca, ba};
+
+struct command_lookup {
+ const char *name;
+ int id;
+ int off;
+};
+
+struct command_lookup cmd_lookup_table[] = {
+ { "fg(", fg, 3},
+ { "bg(", bg, 3},
+ { "i(", icon, 2},
+ { "r(", rect, 2},
+ { "ro(", recto, 3},
+ { "c(", circle, 2},
+ { "co(", circleo, 3},
+ { "p(", pos, 2},
+ { "pa(", abspos, 3},
+ { "tw(", titlewin, 3},
+ { "ib(", ibg, 3},
+ { "fn(", fn, 3},
+ { "ca(", ca, 3},
+ { "ba(", ba, 3},
+ { 0, 0, 0}
+};
+
+
+/* positioning helpers */
+enum sctype {LOCK_X, UNLOCK_X, TOP, BOTTOM, CENTER, LEFT, RIGHT};
+
+int get_tokval(const char* line, char **retdata);
+int get_token(const char* line, int * t, char **tval);
+
+static unsigned int
+textnw(Fnt *font, const char *text, unsigned int len) {
+#ifndef DZEN_XFT
+ XRectangle r;
+
+ if(font->set) {
+ XmbTextExtents(font->set, text, len, NULL, &r);
+ return r.width;
+ }
+ return XTextWidth(font->xfont, text, len);
+#else
+ XftTextExtentsUtf8(dzen.dpy, dzen.font.xftfont, (unsigned const char *) text, strlen(text), dzen.font.extents);
+ if(dzen.font.extents->height > dzen.font.height)
+ dzen.font.height = dzen.font.extents->height;
+ return dzen.font.extents->xOff;
+#endif
+}
+
+
+void
+drawtext(const char *text, int reverse, int line, int align) {
+ if(!reverse) {
+ XSetForeground(dzen.dpy, dzen.gc, dzen.norm[ColBG]);
+ XFillRectangle(dzen.dpy, dzen.slave_win.drawable[line], dzen.gc, 0, 0, dzen.w, dzen.h);
+ XSetForeground(dzen.dpy, dzen.gc, dzen.norm[ColFG]);
+ }
+ else {
+ XSetForeground(dzen.dpy, dzen.rgc, dzen.norm[ColFG]);
+ XFillRectangle(dzen.dpy, dzen.slave_win.drawable[line], dzen.rgc, 0, 0, dzen.w, dzen.h);
+ XSetForeground(dzen.dpy, dzen.rgc, dzen.norm[ColBG]);
+ }
+
+ parse_line(text, line, align, reverse, 0);
+}
+
+long
+getcolor(const char *colstr) {
+ Colormap cmap = DefaultColormap(dzen.dpy, dzen.screen);
+ XColor color;
+
+ if(!XAllocNamedColor(dzen.dpy, cmap, colstr, &color, &color))
+ return -1;
+
+ return color.pixel;
+}
+
+void
+setfont(const char *fontstr) {
+#ifndef DZEN_XFT
+ char *def, **missing;
+ int i, n;
+
+ missing = NULL;
+ if(dzen.font.set)
+ XFreeFontSet(dzen.dpy, dzen.font.set);
+
+ dzen.font.set = XCreateFontSet(dzen.dpy, fontstr, &missing, &n, &def);
+ if(missing)
+ XFreeStringList(missing);
+
+ if(dzen.font.set) {
+ XFontSetExtents *font_extents;
+ XFontStruct **xfonts;
+ char **font_names;
+ dzen.font.ascent = dzen.font.descent = 0;
+ font_extents = XExtentsOfFontSet(dzen.font.set);
+ n = XFontsOfFontSet(dzen.font.set, &xfonts, &font_names);
+ for(i = 0, dzen.font.ascent = 0, dzen.font.descent = 0; i < n; i++) {
+ if(dzen.font.ascent < (*xfonts)->ascent)
+ dzen.font.ascent = (*xfonts)->ascent;
+ if(dzen.font.descent < (*xfonts)->descent)
+ dzen.font.descent = (*xfonts)->descent;
+ xfonts++;
+ }
+ }
+ else {
+ if(dzen.font.xfont)
+ XFreeFont(dzen.dpy, dzen.font.xfont);
+ dzen.font.xfont = NULL;
+ if(!(dzen.font.xfont = XLoadQueryFont(dzen.dpy, fontstr)))
+ eprint("dzen: error, cannot load font: '%s'\n", fontstr);
+ dzen.font.ascent = dzen.font.xfont->ascent;
+ dzen.font.descent = dzen.font.xfont->descent;
+ }
+ dzen.font.height = dzen.font.ascent + dzen.font.descent;
+#else
+ dzen.font.xftfont = XftFontOpenXlfd(dzen.dpy, dzen.screen, fontstr);
+ if(!dzen.font.xftfont)
+ dzen.font.xftfont = XftFontOpenName(dzen.dpy, dzen.screen, fontstr);
+ if(!dzen.font.xftfont)
+ eprint("error, cannot load font: '%s'\n", fontstr);
+ dzen.font.extents = malloc(sizeof(XGlyphInfo));
+ XftTextExtentsUtf8(dzen.dpy, dzen.font.xftfont, (unsigned const char *) fontstr, strlen(fontstr), dzen.font.extents);
+ dzen.font.height = dzen.font.xftfont->ascent + dzen.font.xftfont->descent;
+ dzen.font.width = (dzen.font.extents->width)/strlen(fontstr);
+#endif
+}
+
+
+int
+get_tokval(const char* line, char **retdata) {
+ int i;
+ char tokval[ARGLEN];
+
+ for(i=0; i < ARGLEN && (*(line+i) != ')'); i++)
+ tokval[i] = *(line+i);
+
+ tokval[i] = '\0';
+ *retdata = strdup(tokval);
+
+ return i+1;
+}
+
+int
+get_token(const char *line, int * t, char **tval) {
+ int off=0, next_pos=0, i;
+ char *tokval = NULL;
+
+ if(*(line+1) == ESC_CHAR)
+ return 0;
+ line++;
+
+ for(i=0; cmd_lookup_table[i].name; ++i) {
+ if( off=cmd_lookup_table[i].off,
+ !strncmp(line, cmd_lookup_table[i].name, off) ) {
+ next_pos = get_tokval(line+off, &tokval);
+ *t = cmd_lookup_table[i].id;
+ break;
+ }
+ }
+
+
+ *tval = tokval;
+ return next_pos+off;
+}
+
+static void
+setcolor(Drawable *pm, int x, int width, long tfg, long tbg, int reverse, int nobg) {
+
+ if(nobg)
+ return;
+
+ XSetForeground(dzen.dpy, dzen.tgc, reverse ? tfg : tbg);
+ XFillRectangle(dzen.dpy, *pm, dzen.tgc, x, 0, width, dzen.line_height);
+
+ XSetForeground(dzen.dpy, dzen.tgc, reverse ? tbg : tfg);
+ XSetBackground(dzen.dpy, dzen.tgc, reverse ? tfg : tbg);
+}
+
+int
+get_sens_area(char *s, int *b, char *cmd) {
+ memset(cmd, 0, 1024);
+ sscanf(s, "%5d", b);
+ char *comma = strchr(s, ',');
+ if (comma != NULL)
+ strncpy(cmd, comma+1, 1024);
+
+ return 0;
+}
+
+static int
+get_rect_vals(char *s, int *w, int *h, int *x, int *y) {
+ *w=*h=*x=*y=0;
+
+ return sscanf(s, "%5dx%5d%5d%5d", w, h, x, y);
+}
+
+static int
+get_circle_vals(char *s, int *d, int *a) {
+ int ret;
+ *d=*a=ret=0;
+
+ return sscanf(s, "%5d%5d", d, a);
+}
+
+static int
+get_pos_vals(char *s, int *d, int *a) {
+ int i=0, ret=3, onlyx=1;
+ char buf[128];
+ *d=*a=0;
+
+ if(s[0] == '_') {
+ if(!strncmp(s, "_LOCK_X", 7)) {
+ *d = LOCK_X;
+ }
+ if(!strncmp(s, "_UNLOCK_X", 8)) {
+ *d = UNLOCK_X;
+ }
+ if(!strncmp(s, "_LEFT", 5)) {
+ *d = LEFT;
+ }
+ if(!strncmp(s, "_RIGHT", 6)) {
+ *d = RIGHT;
+ }
+ if(!strncmp(s, "_CENTER", 7)) {
+ *d = CENTER;
+ }
+ if(!strncmp(s, "_BOTTOM", 7)) {
+ *d = BOTTOM;
+ }
+ if(!strncmp(s, "_TOP", 4)) {
+ *d = TOP;
+ }
+
+ return 5;
+ } else {
+ for(i=0; s[i] && i<128; i++) {
+ if(s[i] == ';') {
+ onlyx=0;
+ break;
+ } else
+ buf[i]=s[i];
+ }
+
+ if(i) {
+ buf[i]='\0';
+ *d=atoi(buf);
+ } else
+ ret=2;
+
+ if(s[++i]) {
+ *a=atoi(s+i);
+ } else
+ ret = 1;
+
+ if(onlyx) ret=1;
+
+ return ret;
+ }
+}
+
+static int
+get_block_align_vals(char *s, int *a, int *w)
+{
+ char buf[32];
+ int r;
+ *w = -1;
+ r = sscanf(s, "%d,%31s", w, buf);
+ if(!strcmp(buf, "_LEFT"))
+ *a = ALIGNLEFT;
+ else if(!strcmp(buf, "_RIGHT"))
+ *a = ALIGNRIGHT;
+ else if(!strcmp(buf, "_CENTER"))
+ *a = ALIGNCENTER;
+ else
+ *a = -1;
+
+ return r;
+}
+
+
+static int
+search_icon_cache(const char* name) {
+ int i;
+
+ for(i=0; i < MAX_ICON_CACHE; i++)
+ if(!strncmp(icons[i].name, name, ARGLEN))
+ return i;
+
+ return -1;
+}
+
+#ifdef DZEN_XPM
+static void
+cache_icon(const char* name, Pixmap pm, int w, int h) {
+ if(icon_cnt >= MAX_ICON_CACHE)
+ icon_cnt = 0;
+
+ if(icons[icon_cnt].p)
+ XFreePixmap(dzen.dpy, icons[icon_cnt].p);
+
+ strncpy(icons[icon_cnt].name, name, ARGLEN);
+ icons[icon_cnt].w = w;
+ icons[icon_cnt].h = h;
+ icons[icon_cnt].p = pm;
+ icon_cnt++;
+}
+#endif
+
+
+char *
+parse_line(const char *line, int lnr, int align, int reverse, int nodraw) {
+ /* bitmaps */
+ unsigned int bm_w, bm_h;
+ int bm_xh, bm_yh;
+ /* rectangles, cirlcles*/
+ int rectw, recth, rectx, recty;
+ /* positioning */
+ int n_posx, n_posy, set_posy=0;
+ int px=0, py=0, opx=0;
+ int i, next_pos=0, j=0, h=0, tw=0;
+ /* buffer pos */
+ const char *linep=NULL;
+ /* fonts */
+ int font_was_set=0;
+ /* position */
+ int pos_is_fixed = 0;
+ /* block alignment */
+ int block_align = -1;
+ int block_width = -1;
+ /* clickable area y tracking */
+ int max_y=-1;
+
+ /* temp buffers */
+ char lbuf[MAX_LINE_LEN], *rbuf = NULL;
+
+ /* parser state */
+ int t=-1, nobg=0;
+ char *tval=NULL;
+
+ /* X stuff */
+ long lastfg = dzen.norm[ColFG], lastbg = dzen.norm[ColBG];
+ Fnt *cur_fnt = NULL;
+#ifndef DZEN_XFT
+ XGCValues gcv;
+#endif
+ Drawable pm=0, bm;
+#ifdef DZEN_XPM
+ int free_xpm_attrib = 0;
+ Pixmap xpm_pm;
+ XpmAttributes xpma;
+ XpmColorSymbol xpms;
+#endif
+
+#ifdef DZEN_XFT
+ XftDraw *xftd=NULL;
+ XftColor xftc;
+ char *xftcs;
+ int xftcs_f=0;
+ char *xftcs_bg;
+ int xftcs_bgf=0;
+
+ xftcs = (char *)dzen.fg;
+ xftcs_bg = (char *)dzen.bg;
+#endif
+
+ /* icon cache */
+ int ip;
+
+ /* parse line and return the text without control commands */
+ if(nodraw) {
+ rbuf = emalloc(MAX_LINE_LEN);
+ rbuf[0] = '\0';
+ if( (lnr + dzen.slave_win.first_line_vis) >= dzen.slave_win.tcnt)
+ line = NULL;
+ else
+ line = dzen.slave_win.tbuf[dzen.slave_win.first_line_vis+lnr];
+
+ }
+ /* parse line and render text */
+ else {
+ h = dzen.font.height;
+ py = (dzen.line_height - h) / 2;
+ xorig = 0;
+
+
+ if(lnr != -1) {
+ pm = XCreatePixmap(dzen.dpy, RootWindow(dzen.dpy, DefaultScreen(dzen.dpy)), dzen.slave_win.width,
+ dzen.line_height, DefaultDepth(dzen.dpy, dzen.screen));
+ }
+ else {
+ pm = XCreatePixmap(dzen.dpy, RootWindow(dzen.dpy, DefaultScreen(dzen.dpy)), dzen.title_win.width,
+ dzen.line_height, DefaultDepth(dzen.dpy, dzen.screen));
+ sens_areas_cnt = 0;
+ }
+
+#ifdef DZEN_XFT
+ xftd = XftDrawCreate(dzen.dpy, pm, DefaultVisual(dzen.dpy, dzen.screen),
+ DefaultColormap(dzen.dpy, dzen.screen));
+#endif
+
+ if(!reverse) {
+ XSetForeground(dzen.dpy, dzen.tgc, dzen.norm[ColBG]);
+#ifdef DZEN_XPM
+ xpms.pixel = dzen.norm[ColBG];
+#endif
+#ifdef DZEN_XFT
+ xftcs_bg = (char *)dzen.bg;
+ xftcs_bgf = 0;
+#endif
+ }
+ else {
+ XSetForeground(dzen.dpy, dzen.tgc, dzen.norm[ColFG]);
+#ifdef DZEN_XPM
+ xpms.pixel = dzen.norm[ColFG];
+#endif
+ }
+ XFillRectangle(dzen.dpy, pm, dzen.tgc, 0, 0, dzen.w, dzen.h);
+
+ if(!reverse) {
+ XSetForeground(dzen.dpy, dzen.tgc, dzen.norm[ColFG]);
+ }
+ else {
+ XSetForeground(dzen.dpy, dzen.tgc, dzen.norm[ColBG]);
+ }
+
+#ifdef DZEN_XPM
+ xpms.name = NULL;
+ xpms.value = (char *)"none";
+
+ xpma.colormap = DefaultColormap(dzen.dpy, dzen.screen);
+ xpma.depth = DefaultDepth(dzen.dpy, dzen.screen);
+ xpma.visual = DefaultVisual(dzen.dpy, dzen.screen);
+ xpma.colorsymbols = &xpms;
+ xpma.numsymbols = 1;
+ xpma.valuemask = XpmColormap|XpmDepth|XpmVisual|XpmColorSymbols;
+#endif
+
+#ifndef DZEN_XFT
+ if(!dzen.font.set){
+ gcv.font = dzen.font.xfont->fid;
+ XChangeGC(dzen.dpy, dzen.tgc, GCFont, &gcv);
+ }
+#endif
+ cur_fnt = &dzen.font;
+
+ if( lnr != -1 && (lnr + dzen.slave_win.first_line_vis >= dzen.slave_win.tcnt)) {
+ XCopyArea(dzen.dpy, pm, dzen.slave_win.drawable[lnr], dzen.gc,
+ 0, 0, px, dzen.line_height, xorig, 0);
+ XFreePixmap(dzen.dpy, pm);
+ return NULL;
+ }
+ }
+
+ linep = line;
+ while(1) {
+ if(*linep == ESC_CHAR || *linep == '\0') {
+ lbuf[j] = '\0';
+
+ /* clear _lock_x at EOL so final width is correct */
+ if(*linep=='\0')
+ pos_is_fixed=0;
+
+ if(nodraw) {
+ strcat(rbuf, lbuf);
+ }
+ else {
+ if(t != -1 && tval) {
+ switch(t) {
+ case icon:
+ if(MAX_ICON_CACHE && (ip=search_icon_cache(tval)) != -1) {
+ int y;
+ XCopyArea(dzen.dpy, icons[ip].p, pm, dzen.tgc,
+ 0, 0, icons[ip].w, icons[ip].h, px, y=(set_posy ? py :
+ (dzen.line_height >= (signed)icons[ip].h ?
+ (dzen.line_height - icons[ip].h)/2 : 0)));
+ px += !pos_is_fixed ? icons[ip].w : 0;
+ max_y = MAX(max_y, y+icons[ip].h);
+ } else {
+ int y;
+ if(XReadBitmapFile(dzen.dpy, pm, tval, &bm_w,
+ &bm_h, &bm, &bm_xh, &bm_yh) == BitmapSuccess
+ && (h/2 + px + (signed)bm_w < dzen.w)) {
+ setcolor(&pm, px, bm_w, lastfg, lastbg, reverse, nobg);
+
+ XCopyPlane(dzen.dpy, bm, pm, dzen.tgc,
+ 0, 0, bm_w, bm_h, px, y=(set_posy ? py :
+ (dzen.line_height >= (int)bm_h ?
+ (dzen.line_height - (int)bm_h)/2 : 0)), 1);
+ XFreePixmap(dzen.dpy, bm);
+ px += !pos_is_fixed ? bm_w : 0;
+ max_y = MAX(max_y, y+bm_h);
+ }
+#ifdef DZEN_XPM
+ else if(XpmReadFileToPixmap(dzen.dpy, dzen.title_win.win, tval, &xpm_pm, NULL, &xpma) == XpmSuccess) {
+ setcolor(&pm, px, xpma.width, lastfg, lastbg, reverse, nobg);
+
+ if(MAX_ICON_CACHE)
+ cache_icon(tval, xpm_pm, xpma.width, xpma.height);
+
+ XCopyArea(dzen.dpy, xpm_pm, pm, dzen.tgc,
+ 0, 0, xpma.width, xpma.height, px, y=(set_posy ? py :
+ (dzen.line_height >= (int)xpma.height ?
+ (dzen.line_height - (int)xpma.height)/2 : 0)));
+ px += !pos_is_fixed ? xpma.width : 0;
+ max_y = MAX(max_y, y+xpma.height);
+
+ /* freed by cache_icon() */
+ //XFreePixmap(dzen.dpy, xpm_pm);
+ free_xpm_attrib = 1;
+ }
+#endif
+ }
+ break;
+
+
+ case rect:
+ get_rect_vals(tval, &rectw, &recth, &rectx, &recty);
+ recth = recth > dzen.line_height ? dzen.line_height : recth;
+ if(set_posy)
+ py += recty;
+ recty = recty == 0 ? (dzen.line_height - recth)/2 :
+ (dzen.line_height - recth)/2 + recty;
+ px += !pos_is_fixed ? rectx : 0;
+ setcolor(&pm, px, rectw, lastfg, lastbg, reverse, nobg);
+
+ XFillRectangle(dzen.dpy, pm, dzen.tgc, px,
+ set_posy ? py :
+ ((int)recty < 0 ? dzen.line_height + recty : recty),
+ rectw, recth);
+
+ px += !pos_is_fixed ? rectw : 0;
+ break;
+
+ case recto:
+ get_rect_vals(tval, &rectw, &recth, &rectx, &recty);
+ if (!rectw) break;
+
+ recth = recth > dzen.line_height ? dzen.line_height-2 : recth-1;
+ if(set_posy)
+ py += recty;
+ recty = recty == 0 ? (dzen.line_height - recth)/2 :
+ (dzen.line_height - recth)/2 + recty;
+ px = (rectx == 0) ? px : rectx+px;
+ /* prevent from stairs effect when rounding recty */
+ if (!((dzen.line_height - recth) % 2)) recty--;
+ setcolor(&pm, px, rectw, lastfg, lastbg, reverse, nobg);
+ XDrawRectangle(dzen.dpy, pm, dzen.tgc, px,
+ set_posy ? py :
+ ((int)recty<0 ? dzen.line_height + recty : recty), rectw-1, recth);
+ px += !pos_is_fixed ? rectw : 0;
+ break;
+
+ case circle:
+ rectx = get_circle_vals(tval, &rectw, &recth);
+ setcolor(&pm, px, rectw, lastfg, lastbg, reverse, nobg);
+ XFillArc(dzen.dpy, pm, dzen.tgc, px, set_posy ? py :(dzen.line_height - rectw)/2,
+ rectw, rectw, 90*64, rectx>1?recth*64:64*360);
+ px += !pos_is_fixed ? rectw : 0;
+ break;
+
+ case circleo:
+ rectx = get_circle_vals(tval, &rectw, &recth);
+ setcolor(&pm, px, rectw, lastfg, lastbg, reverse, nobg);
+ XDrawArc(dzen.dpy, pm, dzen.tgc, px, set_posy ? py : (dzen.line_height - rectw)/2,
+ rectw, rectw, 90*64, rectx>1?recth*64:64*360);
+ px += !pos_is_fixed ? rectw : 0;
+ break;
+
+ case pos:
+ if(tval[0]) {
+ int r=0;
+ r = get_pos_vals(tval, &n_posx, &n_posy);
+ if( (r == 1 && !set_posy))
+ set_posy=0;
+ else if (r == 5) {
+ switch(n_posx) {
+ case LOCK_X:
+ pos_is_fixed = 1;
+ break;
+ case UNLOCK_X:
+ pos_is_fixed = 0;
+ break;
+ case LEFT:
+ px = 0;
+ break;
+ case RIGHT:
+ px = dzen.w;
+ break;
+ case CENTER:
+ px = dzen.w/2;
+ break;
+ case BOTTOM:
+ set_posy = 1;
+ py = dzen.line_height;
+ break;
+ case TOP:
+ set_posy = 1;
+ py = 0;
+ break;
+ }
+ } else
+ set_posy=1;