359 Commits

Author SHA1 Message Date
fd9b83a232 check if we're in the group already, else multiple calls to
group_movetogroup() on one client will still increment nhidden if the
group is hidden.

found the hard way by Thomas Jeunet and fix from Alexander Polakov -
thanks to both!

ok oga@
2011-12-29 20:48:38 +00:00
22c2bc618b put snapdist in the correct location; as an option, not a bind; Tiago Cunha.
ok oga@
2011-11-06 02:03:47 +00:00
fded46ba9f rename variable to reduce potential for name-space collision.
bikesheding and ok oga@.
2011-10-17 18:18:38 +00:00
f60f630b81 use xfree instead of free since strings is allocated with xmalloc; from
dhill

ok oga@
2011-10-12 15:43:50 +00:00
ba3dfcf7bd move client to group (movetogroup) and hide client only if group is
already hidden (suggested behavior from Alexander Polakov).

ok sthen oga
2011-09-19 07:23:03 +00:00
22f366830e fix spelling I keep getting wrong for some unknown reason; found by and
diff from Alexander Polakov.
2011-09-13 09:17:30 +00:00
796b32123d add WM_TRANSIENT_FOR event support: moves dialogs, toolbars and such to
the group of the main application window; based on a diff from Alexander
Polakov with CLIENT_IGNORE flag suggestion from oga@.

ok oga@
2011-09-13 08:41:57 +00:00
b96caa16e6 repair groupcycle (broke after cycle-in-group support added more flags);
found by and fix from Thomas Pfaff.

ok oga@
2011-09-13 08:37:49 +00:00
82d31aec1d allow configurable menu font color; from Alexander Polakov with a tweak
from me.

ok oga@
2011-09-08 12:35:33 +00:00
a262f8e80c allow menufg/menubg to be configurable; from Alexander Polakov.
ok oga@
2011-09-08 12:07:03 +00:00
840323558d reinit menu on reload; from Alexander Polakov. needed for catching
upcoming menu config changes.

ok oga@
2011-09-08 12:00:49 +00:00
d85b3adc0c restore a comment and add another for clarity. 2011-09-05 07:37:55 +00:00
oga
44d8b1d3ac Make flavours of maximisation additive.
i.e. horiz-max + vertmax = full maximisation.  full - horiz = vertmax.
etc.

Martynas wrote something like this once, so I did okan, this version
seems to finally deal with the corner cases.

ok okan@.
2011-09-04 16:59:31 +00:00
b852a73a60 split off window hints from geometry so we don't need to carry them all
around when dealing with {,h,v}max.  same idea from oga.
2011-09-03 09:42:33 +00:00
325129c6ba simplify color initialization.
ok oga@
2011-09-03 09:25:39 +00:00
142a36a0c0 Add {r,}cycleingroup to cycle through clients belonging to the same
group as the active client (as opposed to all unhidden clients); from
Alexander Polakov, with a tiny tweak requested by oga.

ok oga@
2011-09-03 09:20:58 +00:00
b51f8e6a99 "defaultfont" is unclear (and confusing while reading code) when it also
applies to the user supplied font, so rename.

ok oga@
2011-09-03 09:17:16 +00:00
a4683b55f8 zap unused macro. ok oga@ 2011-08-29 09:10:49 +00:00
0dcf7efb8e restore mouse move via the keyboard, noticed by todd@. while the check
for cc was wrong due to the fact that cc->sc is always filled in during
the event, we don't even need it - just operate on the focused screen's
root window regardless.

ok todd@ oga@
2011-08-29 09:09:45 +00:00
oga
be3b8a0748 A while ago I wrote some code to not warp to ignored windows on map (rev
1.52), not realising that the previous (less efficient) fix had already
been commited (rev 1.50).

Had this in my tree for ages to remove the previous code. Effectively
reverts rev 1.50.

ok okan@
2011-08-22 16:34:34 +00:00
2dc8df110c revert r1.11 of parse.y and create logic in conf_setup instead to deal
with the various scenarios of when to attempt a parse of the config,
load defaults, and when to warn and/or exit.  triggered by bogus warning
first noticed by sobrado@.

ok oga@
2011-08-22 16:18:05 +00:00
912dd46a7e Re-draw borders after reloading, not before; from Alexander Polakov.
ok oga@
2011-07-26 08:51:24 +00:00
30dbdf4178 use the menu border; from Alexander Polakov, but with the existing define.
ok oga@
2011-07-25 15:41:05 +00:00
f51f3cb9c2 We are inconsistent when it comes to function returns, so just go all
the way with the cwm specific parts.

ok oga@
2011-07-25 15:10:24 +00:00
69ac0624cc Clarify defines and make them not look like non-local ones; started by a
small diff from Thomas Pfaff.

ok oga@
2011-07-23 13:09:11 +00:00
c585dfbf32 correct spelling; from Alexander Polakov. 2011-07-14 11:39:53 +00:00
3db2d84fa8 UTF8-ify, from Alexander Polakov, but without setlocale(), after
feedback from stsp@ - thanks!

'go for it' oga@
2011-06-27 12:46:54 +00:00
bcf90f5f34 warn if we can't parse the config file on start, just like we do on reload.
part of a larger diff that was ok oga@
2011-06-25 13:37:05 +00:00
0573d184f7 Since cwm(1) uses the same parser as others in src, document how
comments and line extensions work.  Taken from sthen@'s recent
commit in src.

ok sthen@
2011-06-25 13:12:56 +00:00
d8747ae702 add 'normal' cursor and shuffle the others we use to make a bit more
sense and to be slightly less un-expected.  from Alexander Polakov.
re-use 'normal' cursor now instead XC_hand1 for menu selection.  i
really wish X had real docs and made sense.

ok on earlier diff with '?' removed (but it's back now) oga@
2011-06-24 06:52:23 +00:00
8f1c583361 New option to raise a client via the mouse (unbound by default);
opposing action, lower, already exists and bound.  Both keyboard
mappings already exist.

'no opinion either way' oga@
2011-06-24 06:09:26 +00:00
34ba6cdbcc introduce a new config option to snap to the screen edge. 'snapdist'
keyword taken from a diff from Sviatoslav Chagaev to do the same thing,
but implemented in a completely way (based on some very old code from
mk@).  default set to 0, so no behavior change.

ok oga@ (who would also like to take it further...)
2011-06-24 06:06:24 +00:00
b230e611be re-do various bits of {,h,v}max for simplicity and less flag handling.
as a bonus, flipping between various combinations of vmax+hmax provides
a more predictable behavior.

commitski oga@
2011-06-24 06:01:47 +00:00
c566b31bd0 replace the non-working check to see if another wm is running with a
method that actually works.  checking for icccm compliant wm's should
also be done first, but that's another diff (noted by oga).

ok oga@
2011-06-24 05:58:51 +00:00
d39f5b9183 more nitems usage.
ok oga@
2011-06-24 05:54:30 +00:00
c8ea76a965 re-order sweep draw so that we map into the client window after
re-parenting; from Sviatoslav Chagaev.

ok oga@
2011-06-24 05:51:25 +00:00
c2a8363dd9 struct XftFont already has height which we can use directly instead of
calculating ourselves, so do so.

ok oga@
2011-06-24 05:45:57 +00:00
f6fcd0eb5d alter a few function returns and prototypes; found by lint.
ok oga@
2011-06-24 05:40:09 +00:00
69cc58555d Correct extern declaration and while here, rename a variable to be
pedantic.

from Thomas Pfaff.

ok oga@
2011-06-24 05:33:41 +00:00
89d8a14b6d collapse client and group {r,}cycle defines since they are really
the same thing.

ok oga@
2011-06-24 05:30:42 +00:00
9a6a2d3cf3 switch to installing source manuals:
* cope with new bsd.man.mk
* update imake configuration

ports use of imake remains unchanged
2011-06-23 22:48:59 +00:00
64d8bb630a fix botched client and group cycle defines; noticed by Thomas Pfaff.
"no cookie! fix it" - oga@
2011-05-15 17:58:47 +00:00
fa64bc2f32 remove left over XSync; ok oga@ 2011-05-13 12:53:19 +00:00
c8cd94882d tag and comment cleanup; ok oga@ 2011-05-11 13:53:51 +00:00
43450c8fd7 introduce a new 'freeze' flag (CMS-f by default) which may be applied to
any window, after which all move/resize requests will be ignored,
essentially freezing the window in place.

there's a possibility to merge this with the 'ignore' concept, pending
on how ignore+freeze should behave (really more ewmh stuff), but punting
for now since ponies are on the line.

requested and tested by thib at k2k11 with ponies, unicorns and rainbows.

'save the unicorns' todd@, ok oga@
2011-05-07 17:15:37 +00:00
oga
760c6b5522 On map, don't warp to windows that are marked as ignored.
Requested by Christian Neukirchen last august. He provided a patch but the one I
wrote was significantly simpler (1 - 2 + in the whole diff).

makes sense to okan@.
2011-05-06 19:39:44 +00:00
604a5d07a4 bump window resize back to 60hz. instead, we should not need to sync
every time we move/resize a window, so remove XSync in both mouse move
and resize events.  tested by Brynet as well.

ok oga@
2011-05-05 19:52:52 +00:00
8ed968601e re-org. ok oga@ 2011-05-05 16:40:37 +00:00
c62c0ee9db make the menu window aware of xinerama info; this makes the menu stay
within the current screen, like other cwm window placements and
mutations (vmax/hmax/max) - from Sviatoslav Chagaev.

ok oga@
2011-05-05 15:32:24 +00:00
349b3295b8 revert the XSync timing change for client move only; first noticed by
brynet.

sure oga@
2011-03-23 07:27:32 +00:00
5972c7a507 warp the pointer back, iff we don't move the mouse, once we are done
with the menu; idea and initial from Sviatoslav Chagaev.

discussion with and ok oga@
2011-03-22 13:50:40 +00:00
e28a7f832e we should re-focus the client and ungrab the ptr even if we don't have a
mouse based match (i.e. in the kbd no match case).  update the comment
as well.

ok oga@
2011-03-22 11:09:52 +00:00
9c587d9725 fix nousance of always highlighting the first entry even when there is
no match (seen in the ctrl-a case)

ok oga@
2011-03-22 11:05:13 +00:00
765479fc86 move the default case to the end.
ok oga@
2011-03-22 11:03:05 +00:00
a50bfb613d reduce the number of times we sync during a window resize.
ok oga@
2011-03-22 10:59:08 +00:00
2c706e60c7 introduce nitems macro, with the appropriate ifndef.
ok oga@
2011-03-22 10:57:31 +00:00
8f88cd474a if virt/horz un-maximizing, restore only the un-maximized axis
coordinates; allows moving a client and not restoring the maximized axis
coordinates.

picked from a larger martynas diff from ages ago.

ok oga@
2011-03-22 10:56:08 +00:00
9b4985439e (0,0) is also inside in the screen; from Sviatoslav Chagaev.
ok oga@
2011-03-22 10:54:42 +00:00
3ff303658c while this piece deals with client argv's in a seemingly inefficient way
(noticed by Tim Peniket), since we don't ever do anything with cliarg,
remove the hunk and cliarg completely.

ok oga@
2011-03-22 10:52:37 +00:00
a12fb346a2 remove XXX and move a configure event out of the event handler functions.
reminded by a similiar diff from Thomas Pfaff.

ok oga@
2011-03-22 10:49:46 +00:00
00b502b1da move the single keycode function directly into the menu code.
ok oga@
2011-03-22 10:47:59 +00:00
e03323d22e xcb is no longer optional. 2011-03-08 20:48:59 +00:00
64e62989d0 if we are saving the pointer location for a specific client, make sure
that if it is not already inbounds, put it in the default location,
which happens to be inbounds.

behavior noticed by Thomas Pfaff while maximizing and un-maximizing a
window, leaving the pointer behind and causing client_cycle() to be a
bit lost.

ok oga@
2011-02-13 20:09:57 +00:00
0884d38e3b we lose track of highstack somewhere, so recompute it before we need it.
fixes a crash reported by christian neukirchen.  ok okan
2011-02-13 17:25:20 +00:00
cd23316a72 in MotionNotify geom.x, geom.y calculations take into account bwidth.
fixes the annoying bug where windows would go +bwidth pixels right,
+bwidth pixels down.  ok okan@
2010-12-14 11:08:47 +00:00
111a88129d Explicitely link libxcb when needed for static arches. 2010-11-27 14:25:47 +00:00
1f310d57e2 s/-offset -indent/-offset indent/ for correct indentation,
and properly encode \(:a
found by mandoc -Tlint
2010-09-25 21:58:18 +00:00
ff3df256a1 s/\.Pb/.Pp/ for correct vertical spacing; found by mandoc -Tlint 2010-09-25 21:48:08 +00:00
dee6ac5b7d do not warp to clients marked 'ignore'; from chneukirchen at gmail - thanks.
(with the manpage bit from me).

ok oga@
2010-09-25 20:04:55 +00:00
2d66003e4b picked a henning diff from src - original log:
fix linecount bug with comments spanning multiple lines
problem reported with the obvious fix for bgpd by Sebastian Benoit
<benoit-lists at fb12.de>, also PR 6432

ok oga@
2010-09-25 20:02:58 +00:00
917bce4b8d spacing nits 2010-09-25 20:01:27 +00:00
2440efad06 revert -r1.45 of group.c (log was: fix window name and class to match
cwmrc(5)).  instead, fix cwmrc(5) to match the old behavior which also
happens to match the example config, of which many have based their
configs; this also nicely matches the output of xprop(1).

clean-up of variable names as a separate commit.

suggested by sthen (and something we should have done initially).

discussed with and ok oga@
2010-07-30 12:28:19 +00:00
aaca5b7e45 fix backwards example (after r1.45 of group.c); noticed by phessler@
ok oga@ phessler@
2010-07-23 15:13:00 +00:00
2a5e1791d4 fix window name and class to match cwmrc(5); from Holger Mikolon - thanks!
ok oga@
2010-06-28 12:29:04 +00:00
85a53083cb initialize nitems
ok oga@
2010-05-22 22:32:08 +00:00
72e6d2d0a9 replace XFetchName() with something more intelligent which attempts to
use the appropriate netwm Atom first, as well as deal with utf8.

slightly different incarnation tested by sthen@ and ajacoutot@ - thanks!

ok oga@
2010-05-22 22:10:31 +00:00
oga
a292c96977 grab events on the root window *before* we look for existing windows.
This closes a race we were hitting often where stuff started right
before cwm may not get noticed and not have borders.

ok okan@. Prompted by something todd noticed.
2010-04-12 16:17:46 +00:00
b12e6fc5cd clean up a few xu_* functions to just accept what they need (Window).
ok oga@
2010-04-11 16:51:26 +00:00
46c9b5cbae Fix formatting errors breaking the xenocara mandoc(1) build:
* .Bl may only have .It children
* .SH requires an argument
* blank lines are illegal outside literal context

Now "cd /usr/xenocara && make man" succeeds,
but unfortunately, that covers a minority of X11 manuals only.

ok matthieu@
2010-03-20 20:13:27 +00:00
507480a695 preserve labels after an edit action is aborted; extending the menu
struct just for this is the least intrusive approach until the menu code
is reviewed.

inspired by Thomas Pfaff's report on tech@

ok oga@
2010-02-10 01:23:05 +00:00
c4a97053cd Honour program-specified window position in size hints when placing windows.
Makes XMMS windows appear as expected.

ok okan, oga
2010-02-02 19:28:46 +00:00
e88bda0df5 - allow per-screen gap; not (yet) user configurable.
- teach _NET_WORKAREA about gap.

ok oga@
2010-01-27 03:04:50 +00:00
ccb207a8a8 pull all non-X11 headers from calmwm.h and place them only where they
are required.

encourged to go all the way by oga@
2009-12-15 04:10:42 +00:00
09a2d7fb98 spacing 2009-12-15 03:38:11 +00:00
b27c3c22b5 pull these headers only into files that need them.
ok oga@
2009-12-15 03:34:34 +00:00
2ad2b5f31d rid ourselves of these functional macros; convert to real functions.
ok oga@
2009-12-15 03:26:22 +00:00
597cb25820 mostly irrelevant now, so remove.
ok oga@
2009-12-15 03:25:22 +00:00
b6b7d273d4 merge the 2 common header files; specific includes to be pulled out as
separate commits.

ok oga@
2009-12-15 03:24:36 +00:00
oga
49661d405b kill _CWM_GRP atom setting. The netwm stuff does us well enough now that
it's superfluous.

ok okan@
2009-12-14 16:39:01 +00:00
oga
3b87bdb047 add _NET_WORKAREA. for now we ignore the gap, this'll change soonish.
ok okan@
2009-12-11 18:09:16 +00:00
oga
28e94b2fbc another int/long fixup that was giving dodgy property values on amd64, shame on
me for not reading xlibs (appauling) documentation more closely.

ok okan@
2009-12-11 17:57:38 +00:00
oga
a0ec2515e9 implement support for _NET_WM_DESKTOP properties on windows.
it works kinda like _CWM_GRP, which we added to aid restarts a while
ago, but it's standardised and clients are specifically allowed to set
it to request a desktop.

for noe we leave _CWM_GRP support in, but its days are now numbered.

while i'm here fixup an int/long mixup with an earlier diff.

ok okan@
2009-12-11 17:55:42 +00:00
oga
b35cbf81d8 Implement _NET_DESKTOP_NAMES, this one was a bit tricky since thespec
says that a pager can change the property at any time (most need a
clientmessage). So deal with property updates.

Needed to shuffle some of the other code around since we can't just use
shortcut_to_name[] everywhere now.

ok okan@
2009-12-11 17:51:42 +00:00
oga
9b04930f24 Implement _NET_VIRTUAL_ROOTS (just clear it, we don't use that technique)
and _NET_SHOWING_DESKTOP (we're never doing so right now).

only three informational root-window hints to go.

ok okan@
2009-12-10 23:21:26 +00:00
oga
a7c3a7cac3 Implement _NET_CURRENT_DESKTOP, _NET_DESKTOP_VIEWPORT and
_NET_DESKTOP_GEOMETRY.

ok okan@
2009-12-10 23:14:58 +00:00
oga
134e777cf0 finish unfucking the screen_ctx handling.
remove screen_current() it was utterly bogus when nscreens > 1.

pass a fake client_ctx in the case where there's no client and the
kbfunc or mousefunc doesn't need a real one, it just contains the
current screen, modify these functions so that they pass down the screen
context to their callees.

make groups per screen, it's the only way it makes sense in this regard.

ok okan@.
2009-12-10 17:16:51 +00:00
ee7df6a95f start fixing screen_ctx usage, for it is utterly broken. bring font
into screen_ctx and start passing screen_ctx around to in order get rid
of Curscreen; fixup per-screen config colors the same way.

diff mostly from oga@, with a bit harsher reaction to the state of screen_ctx.

"please commit" oga@
2009-12-08 16:52:17 +00:00
oga
aa88d5848e Implement _NET_NUMBER_OF_DESKTOPS, currently this is statically 9 and
unchangable. the group code needs some cleaning up before this will be a
bit less hackish.

ok okan@
2009-12-07 23:19:51 +00:00
oga
728d2a40dd support _NET_CLIENT_LIST.
the x property api doesn't let you remove one entry from an X property
array, so client_remove is kinda expensive, but there's no real way
around that..

ok okan@
2009-12-07 22:46:15 +00:00
oga
3c60d854db Implement _NET_ACTIVE_WINDOW. for now just the informational hint is
supported, the client message to change this will be supported when all
informational hints are working.

ok okan@
2009-12-07 22:21:59 +00:00
3e309894c1 introduce the beginnings of netwm support, minimally and correctly;
allows java to be happy, but additionally stops others from whinning
about a non-netwm complaint wm.  more to come.

written a few times; this one includes a clever hack from oga@ to
populate _NET_SUPPORTED.

ok oga@
2009-12-07 21:20:52 +00:00
46630531f8 fix off-by-one where a mere click would select the first item inside a menu
from Thomas Pfaff

ok oga@
2009-12-07 19:48:08 +00:00
ab4d36531c we already have sc from the passed cc, so just used that instead.
ok oga@
2009-12-07 19:45:36 +00:00
892e1e1c0d be consistent
ok oga@
2009-12-07 19:44:31 +00:00
4e2014863b remove unused extern
ok oga@
2009-12-07 19:42:59 +00:00
42bf29fb20 style (whitespaces)
ok oga, okan
2009-11-28 17:52:12 +00:00
afaf69cefc Corrected grammar in comment.
ok (and better style suggestion by) oga, okan
2009-11-22 21:38:50 +00:00
oga
85d8697676 With Xinerama enabled, the borders of a maximized window will show up on
all adjacent screens. This patch hides the borders while the window is
maximized.

From Bertrand Janin; thanks!

ok okan@
2009-09-25 15:57:49 +00:00
4af6a60d84 re-introduce the intention of the change from rev 1.4 in menu.c here
instead, by moving the check for '\0' to only the places that it
matters.  hint and 50% of the diff from oga@, prodded by todd@

ok oga@
2009-09-05 16:06:15 +00:00
38ad2e1d9c style
ok oga
2009-09-05 14:10:11 +00:00
7295c51155 unroll the CCTOSC macro; from Thomas Pfaff
ok oga@
2009-08-27 01:38:08 +00:00
b9f8367089 static; ok oga@ 2009-08-25 12:05:11 +00:00
0a44f2e5c4 we are not doing access control here, so replace the "check if file is
executable" goo with access(2).

originally from jacekm@ long time ago.

"i can live with that" oga@
2009-08-25 02:02:59 +00:00
oga
1968561fcc Reduce duplciation of code for checking modifiers in key/mouse bindings.
shaves a bunch of bytes.

ok okan@
2009-08-25 01:44:39 +00:00
oga
95f65b8be6 Instead of calling conf_bind*() 50 gazillion times in a row, store an
array with all the parameters in and just loop over that to setup the
default keybindings - it's so much easier to read.

okan@ "love love love"ed this
2009-08-25 01:42:05 +00:00
oga
8fd4ff1c7c Instead of messing around everytime we do a resize, just clamp the
resize increments to a minimum of one, and use it unconditionally.

"you've convinced me, do it!" okan@
2009-08-25 01:32:40 +00:00
fcb2684db1 unroll macro; ok oga@ 2009-08-25 01:26:09 +00:00
oga
e2b1cb98c1 Add a keybinding to allow horizontal maximisation of a window (CMS-enter).
based on a diff by Thomas Pfaff; thanks!

ok okan@
2009-08-24 23:54:41 +00:00
028a1778db bring together gathering, calculating and applying of size hints;
additionally, respect aspect ratio hints.

ok oga@
2009-08-24 23:49:04 +00:00
oga
09d88f4a18 Instead of having a function that just calls TAILQ_INIT on a global, use
TAILQ_HEAD_INITIALIZER() and drop the function.

ok okan@
2009-08-24 21:22:48 +00:00
oga
e7f0d63413 instead of checking for flags in the client context, then removing them.
e.g.:

if (flags & flags_we_care_about)
	flags &= ~(flags_we_care_about);

just whack the flags unconditionally, it's simpler.

okan@ agrees.
2009-08-24 17:04:39 +00:00
82911249e2 remove unnecessary Ar macros
ok jmc@
2009-08-08 17:27:51 +00:00
e095e955a8 remove unnecessary Dq macro; based on a diff from Martin Toft
feedback and ok jmc@, martynas@
2009-08-08 00:25:52 +00:00
oga
590eb4f37b use fnmatch to glob the entries in the exec menu.
allows shell globbing constructs such as *ctl, etc in the exec menu (m-?
by default).

Adapted from a diff from Thomas Pfaff, okan@ got almost the same diff as
me when reworking it, and oked this one.
2009-06-26 12:45:12 +00:00
f44862be9c static local functions and data; almost identical diff from Thomas Pfaff
ok oga@
2009-06-26 12:21:58 +00:00
b13d592c57 tidy up startup/init routines
ok oga@
2009-06-23 21:52:38 +00:00
bcc0f73bb6 compact a bit by condensing a few if-else's; from Thomas Pfaff
"go on then" oga@
2009-06-20 00:55:41 +00:00
58d12134b1 unroll XCALLOC/XMALLOC macros; since we use xcalloc/xmalloc all over the
place anyway, this makes things a bit more consistent; from Thomas Pfaff

ok oga@
2009-06-20 00:22:39 +00:00
18c7d89c98 spacing 2009-06-20 00:19:56 +00:00
ee59e4a5a1 `exec'' and `ssh'' are lowercase.
ok martynas@
2009-06-19 10:43:49 +00:00
055b244bb4 items on the first list should have full stops too.
ok martynas@
2009-06-18 20:44:40 +00:00
71ad069846 the on-line manual should use the same notation for key bindings
as the configuration file, this way writing configuration files is easier;
add a few missing interactive command (.Ic) macros to key bindings;
slightly improve spacing in the lists; other tweaks.

ok martynas@
2009-06-18 20:24:54 +00:00
11b4b7fec6 remove unnecessary casts; from Thomas Pfaff
ok oga@
2009-06-17 13:08:37 +00:00
61f841ea58 re-factor parts of mouse move/resize bit to shrink and make more
readable; no behavior change

ok oga@
2009-06-17 12:45:01 +00:00
d7589ca80b move like defines to a central, logical location; no binary change.
aok oga@
2009-06-17 12:30:17 +00:00
3eec3b3802 'no' is the answer to the comment question: cc->name can't be NULL at
this point due to client_setname()'s work; remove this check.

ok oga@
2009-05-30 00:30:27 +00:00
d1b84c5415 re-order a bit for readability.
"if it makes you happy" oga@
2009-05-30 00:30:17 +00:00
6e9fa7548b revert the 1.4 change - causes a double free noticed by grange@ a while
ago while using kazehakase (or clients that don't set a name).

ok oga@
2009-05-30 00:29:08 +00:00
8bbc376fd9 In movetogroup, check the window's current group and skip client_hide()
if it's the same as the active group. Was in my original movetogroup diff,
but it got simplified a little too far.  ok oga@
2009-05-19 12:49:37 +00:00
2c29a1de65 nuke the leading underscore notation for local static functions - there
are far better ways to know.

"go for it" oga@
2009-05-18 00:23:35 +00:00
oga
d2cfeb40b4 oops, we appear to have grown an extra prototype for group_only(), get
the secateurs out.
2009-05-18 00:17:46 +00:00
oga
382662d003 Rip out the event layer and just use a static array of callbacks like
every other window manager since twm.

The event layer is very nice, very shiny, very flexible, and very much
underutilised. We don't need any of those shiny features so it's
probably better to earn ourselves 1k smaller text size instead.

ok todd@, okan@
2009-05-18 00:14:19 +00:00
9be7726606 redraw all borders at once on reload
"sure" oga@
2009-05-17 23:54:17 +00:00
4d5dc5d9ea a long time coming - re-work the way we deal with colors: since we're
using Xft(3), use it to select the font color as well instead of trying
to build one; properly allocate and free colors at-will, e.g. we now
have configurable colors.

feedback and ok's todd@ and oga@
2009-05-17 23:40:57 +00:00
5d51c8e0e5 minor bit of knf, just to be consistent; oga@ doesn't mind that much 2009-05-17 23:37:52 +00:00
4c10afe2cc unbreak 2009-05-17 22:48:47 +00:00
eb7803269e add a "movetogroup" function, which hides the current window from
display and moves it to another group. useful with the recently added
"grouponly" function, giving the ability to use groups as simple
virtual desktops (similar to e.g. xmonad, dwm and scrotwm).

this doesn't have default keyboard bindings; cwmrc(5) now shows how
you could use these functions (use M-1...9 for grouponly1...9 and
MS-1...9 for movetogroup1...9 to emulate the default dwm bindings).

ok oga@
2009-05-17 17:04:59 +00:00
6df7cba24e redraw the border when unhiding a client window. fixes the situation where
you change to a different group and the mouse isn't over a window; previously
the border of the previously active window was highlighted but it didn't
actually have focus.

reads ok to oga@.
2009-05-17 16:51:43 +00:00
oga
29cdc29c6e add missing prototype. 2009-05-14 16:29:58 +00:00
oga
3de90d44fc Add a new command (currently no default keybindings for it), grouponly[1-9].
This works like the group select binding, but hides all other groups.

So, the people who've been complaining that they don't get "virtual
desktops" in cwm may want to try this out in cwmrc (from memory, untested):

---

#cwmrc

# add new windows to the current group
set sticky

# automatically sticky windows. xclock for now.
# to make more windows sticky use group_toggle to unset their group
autogroup 0 xclock

# make the group selection keys hide other groups, emulate virtual desktops
bind CM-1 grouponly1
bind CM-2 grouponly2
bind CM-3 grouponly3
bind CM-4 grouponly4
bind CM-5 grouponly5
bind CM-6 grouponly6
bind CM-7 grouponly7
bind CM-8 grouponly8
bind CM-9 grouponly9

---

mostly by sthen, tweaks from me.

ok todd@, "if it works i'm ok with it" okan@, ok sthen@
2009-05-14 16:24:04 +00:00
fbb1edf2b3 right and middle mouse buttons swapped; from rgouveia@cosmico.net 2009-05-04 22:01:35 +00:00
64f0038db7 no need to use the global here.
ok todd@ oga@
2009-05-04 19:13:33 +00:00
4f34392258 properly document menu_unhide; tweak a patch from rgouveia@cosmico.net - thanks.
ok oga@
2009-05-04 18:05:21 +00:00
655c33c489 fix the other 50% of xrandr cases; reported by sthen@
"commit that" oga@, ok sthen@
2009-05-01 17:50:20 +00:00
cc68490fe1 don't sync more than 60 times per sec on resize and move; idea from scrotwm.
ok oga@ sometime ago
2009-04-15 14:10:07 +00:00
ea96e92ac8 properly teardown X connection upon quit; static a few while here,
requested by oga@

ok oga@ sometime ago
2009-04-15 14:01:45 +00:00
8a490fc270 we include sys/param.h, so remove sys/types.h; sort while here.
ok oga@
2009-04-12 23:51:10 +00:00
8346de997f - avoid shadowed Mask declaration in menu_filter
- make _xev_reincorporate static
evmask naming oga@, input okan@.  ok okan@, oga@
2009-03-28 16:38:54 +00:00
17ae65adc5 add 'moveamount' to cwmrc; it sets keyboard movement amount, making
it more useful on large screens
manpage tweak & ok jmc@
ok okan@, oga@
2009-02-07 21:07:00 +00:00
507b65a27f remove leftover from mdoc.samples; ok jmc@ 2009-02-07 16:59:11 +00:00
4fe12f528c fix off-by-one in geom.[xy], after pwin changes. keyboard movement
to the rightmost or bottommost corners would confuse cwm:
- there's no way to get the window back
- tab cycling breaks
ok okan@, oga@
2009-02-03 22:20:31 +00:00
6ad198022b remove Nscreens and x_screenname() - we really don't need them.
ok oga@
2009-01-27 02:16:20 +00:00
oga
c750462d13 One of the most annoying things to do was restart cwm and lose all of
your group state. Fix this up by using an X Atom (_CWM_GRP) to store the
name of the group that we're using (the name, not the number is because
at one point we may make the group numbers dynamic). I've been talking
about this since c2k8. so CM-w means you keep all of your windows grouped
properly.

ok okan@, todd@
2009-01-27 00:42:53 +00:00
9203c7e8ca passing a null pointer to free() is valid; sprinkle a few free->xfree.
ok oga@
2009-01-23 20:47:45 +00:00
oga
b23cef2e4a Whitespace nit.
pointed out by okan.
2009-01-23 20:07:20 +00:00
oga
01af04a342 Switch to using XInternAtoms for caching the atom numbers. Saves a pile
of function calls and server roundtrips.

ok okan@
2009-01-23 20:04:30 +00:00
7660bf0db0 move conf_clear() and add proto.
ok todd@ oga@
2009-01-23 19:00:59 +00:00
oga
779177a53d Move the keybinding argument to a union to prevent warnings where
sizeof(int) != sizeof(void *). This has been annoying me for ages.

ok okan@, todd@
2009-01-23 18:58:40 +00:00
87964e5c7e now that pwin is gone gone gone, we no longer have to do the bwidth
dance; xevents now able to deal with a border being set (which fixes
those annoying movie-watching apps).

ok todd@, oga@
2009-01-22 19:01:56 +00:00
oga
e239976078 The default font name is strduped, so don't test for default font name
(therefore leaking it) when cleaning up a conf struct.

ok okan@
2009-01-22 18:16:38 +00:00
oga
712f3f62c7 Oops, missed an atom.
ok okan@.
2009-01-22 18:06:16 +00:00
oga
e2f3810fe8 Cache all of the X atoms we use at startup.
Do this instead of querying for them every time we use them. This
removes an XXX that has been in there since time began. This will become
more important as we move towards supporting netwm.

ok todd@, okan@.
2009-01-22 15:26:33 +00:00
1b269199c1 borderwidth as a cwmrc(5) keyword, really helps debugging
from okan@
ok oga@
2009-01-21 15:04:38 +00:00
0548673f2f library dependency ordering matters for static archs, -lXext last in this case
from matthieu@, verified on vax
2009-01-19 20:23:19 +00:00
bd4c4d7734 remove unused
ok oga@
2009-01-17 20:39:24 +00:00
oga
fa87ef4a9e Finally fix the really annoying race where if you rapidly switch groups several
times you'd end up losing clients (thinking they had gone away).

From the ICCCM (which should not be read without a stiff drink in hand,
I made this mistake so you don't have to): to request a window to be
withdrawn one should send a synthetic UnmapRequest event when iconified.
To request iconification one should just unmap the window. The ICCM
further recommends that the synthetic event should just be taken as a
cue to withdraw, to deal with legacy clients. Taking a hint from this,
rework xev_handle_unmaprequest to correctly detect these situations.  A
Withdrawn window may come back anywhere, even as a subwindow of
something else, so the correct way to handle this state is to forget it
ever existed.

While i'm here, kill a dumb attempt to notice this in client_delete, and
nuke the very unnecessary arguments.

Todd confirmed this fixes the `race'.

ok todd@, ok ok okan@
2009-01-17 18:41:50 +00:00
399253a4ff revert just the 'race fix'; more works needs to be ironed out with
events and state.

agreed by oga
2009-01-16 16:49:17 +00:00
ec8e6052ba remove pwin, bringing us to one client, one window. we no longer have
to push attributes around, so things get a lot simplier, while fixing a
few issues in the meantime; original suggestion by Edd Barrett many many
moons ago.

annoying window placement and race, found in c2k8 by todd, fix by oga!

lots of feedback from todd and oga - thanks!

"commit that bad boy" oga@
2009-01-16 15:24:14 +00:00
oga
5c757cc7f4 On startup, don't leak memory when we enumerate existing windows.
The behaviour until now was to ask X for the windows name (which is
malloced) then drop that on the floor and do nothing with it. Skip this
foolery and just skip the window. I don't believe I never noticed this before!

"you can has ok" okan@
2009-01-15 17:23:12 +00:00
49e218cf53 - add missing prototypes.
- properly name, place and static private functions.
- move function which finds the xinerama screen for a coordinate to
a more appropriate place while altering its semantics to match others.
- tiny bit of style.

ok oga@
2009-01-15 00:32:35 +00:00
7e110f379b better cast; noticed by ray@
ok ray@ oga@
2009-01-13 15:25:43 +00:00
oga
c07123ec78 Add -Wall to CFLAGS, it's helped find a few dodgy constructs.
ok okan@.
2009-01-11 21:48:27 +00:00
oga
d1050afb60 shortcut_to_name should not be defined as static in a header file. Put
it in group.c where it it used most, and add an extern definition for
the other users of it.

Found by gcc -Wall. ok okan@
2009-01-11 21:46:48 +00:00
dcfae161a2 add missing prototypes
ok oga@
2009-01-11 21:34:22 +00:00
0aca400461 better comparison idiom; found with -Wall
ok oga@
2009-01-11 21:33:45 +00:00
590169ce24 - merge grab_sweep() into mousefunc_window_resize().
- merge grab_drag() into mousefunc_window_move().
- properly name, proto and static private functions.
- since we already do XMoveResizeWindow() and XMoveWindow() in (now)
mousefunc_window_resize() and mousefunc_window_move() respectively,
client_resize() and client_move() calls are unnecessary.

ok oga@
2009-01-11 18:34:46 +00:00
99afa5091f FcNameParse() manpage lies, cast here.
found with pcc.

ok oga@
2009-01-11 18:32:08 +00:00
b47283ab41 remove unused variables
ok oga@
2009-01-11 18:25:49 +00:00
oga
b523788c0e If the mousebutton is unknown when we go to grab, don't just print a
warning, but also skip the XGrabButton call. Noticed by code inspection
by okan@, but we agreed my fix was cleaner.

ok okan.
2009-01-08 21:35:19 +00:00
ee0ec9a453 remove "search should ignore the current window" from list, for the
current behavior is better...

ok oga@
2009-01-06 00:41:09 +00:00
d2a54bc115 HasXinerama is an int
ok oga@
2009-01-06 00:19:55 +00:00
841c646a2b remove unused code
ok oga@
2009-01-06 00:18:07 +00:00
oga
25af744559 Kill obviously dead variable. 2008-12-04 23:55:04 +00:00
oga
be5dfb4ea4 Don't ignore sigpipe. Everytime cwm forks it execs anyway (so it
shouldn't get that signal), and this causes problems for our children
since they inherit the ignore.

Pointed out by Jacek Masiulani in pr 6010; thanks!
2008-12-03 23:55:46 +00:00
oga
a0739c6cd4 Xinerama and XRandR dual head support for cwm(1). Now we detect the xrandr
reconfiguration events and change our sizes depending on that. We also detect
the xinerama screens for maximize, vertmaximize and initial window placement.

This could be improved by automatically resizing maximized windows when
the screen resolution changes and by moving windows that would be hidden
into visible space. Said changes will come shortly.

Tested by many. matthieu@ didn't oppose.
2008-09-29 23:16:46 +00:00
oga
e2610449d1 .Bl needs a matching .El. From Martin Toft a while ago, thanks! 2008-09-22 14:37:12 +00:00
oga
2bd5e53c2e Improve wording of the ``ignore'' directive. From Martin Toft a while
ago, ok okan@ from similar amount of time ago.
2008-09-22 14:35:16 +00:00
oga
60a88f54cc *sigh* Revert the diff that wasn't meant to go in yet.
note to self: When you mean to type cvs commit search.c, don't forget
the filename.
2008-09-22 14:28:04 +00:00
oga
61601991b5 Display the current window title not a previous one in the case of
``show all'' in the window search dialogue. Noticed and diff from Tim
van der Molen, thanks!
2008-09-22 14:15:03 +00:00
a0082c58a4 Keep the exec menu entries sorted.
Go for it okan@
2008-09-03 04:39:12 +00:00
oga
04441482d4 fix the froggy problem.
Implement a handler for the MappingEvent, meaning that the keymap has changed.
When this happens, ungrab all bindings, update the map, and regrab.

Fixes the problem where some keybindings wouldn't work under non us or
uk keymaps (especially the .fr map, it seems). Issue noticed by
ajacoutot@, ratchov@, and a few people on misc. Based on an initial diff
from ratchov@.

ok okan.
2008-07-22 21:01:54 +00:00
oga
0df9e0673c We've been handling grabbing wrong all this time (noticed at c2k8).
add conf_grab() and conf_ungrab, and use them in the keybinding manipulation
functions to {,un}grab the binding for all screens we have defined.

the lovely little ordering problem comes in here, since when we parse
the config initially Screenq is empty, so regrab after we fill the
queue, hopefully later reordering will remove this little need and there
will be much rejoicing.

ok okan.
2008-07-22 20:51:54 +00:00
oga
436a9e5c54 split x_setup() into two. dpy_init() for setting up the display and
checking the X config, and x_setup to set up the screens.

There's an ordering problem that means that some of this init needs to
come after the config is parsed, the rest should ideally happen before
though. This is a rough split, it will be refined later. Again, needed
for an upcoming change.

ok okan.
2008-07-22 20:42:24 +00:00
oga
20052e0248 Add xu_key_ungrab() and a mirror to xu_key_ungrab(). a couple of changes
that are coming up depend on it.

ok okan.
2008-07-22 20:26:12 +00:00
oga
13b640ea29 Kill screen_init(). it's been stubbed out for a while now. I don't envision it
coming back in it's current form.

ok okan@.
2008-07-22 19:54:57 +00:00
oga
2f8639d37b kill another leftover prototype.
ok okan@
2008-07-22 19:52:54 +00:00
oga
556f7a0871 Put back the initialisation of gc in group_cycle. No cookie for okan.
Reported by Dan Harnett, thanks!
2008-07-18 15:40:52 +00:00
2798cdc9a7 move client_vertmaximize to a more sensible location, purely for readability.
"don't mind at all" oga@
2008-07-15 22:12:09 +00:00
8afabd6c55 save an X call and use what we already have stored.
ok oga@
2008-07-15 22:06:48 +00:00
96f03c8cbc don't compensate for bwidth twice.
ok oga@
2008-07-15 13:52:02 +00:00
6d268bfa4a Nm makes more sense than Xr, from Pierre Riteau - thanks! 2008-07-11 22:43:44 +00:00
oga
b6dab5ccf3 Change "a window" to "current window" in documentation. it's more correct.
While i'm here: Capital letter and full stop in descriptions in cwmrc.5

"looks good - do it" okan@.
2008-07-11 15:42:29 +00:00
a556d3fa1f add Xr for cwm(1) 2008-07-11 15:20:04 +00:00
6ea4b1bd3b no more hidden (and mysterious) config reloads and allow binding a key
to a config reload; CMS-r by default.

ok oga@
2008-07-11 15:18:29 +00:00
8be175b175 replace snprintf with strlcpy
ok oga@
2008-07-11 14:24:34 +00:00
85e6c61360 we already have ymax, so use it instead of asking X for it again.
ok oga@
2008-07-11 14:23:30 +00:00
b23fad3987 spacing, declaration lineup to be consistent throughout cwm,
readability, and a bit of knf.

ok oga@
2008-07-11 14:21:28 +00:00
734f45ab4b only cycle through visible *and* non-ignored windows.
ok oga@
2008-06-30 17:52:37 +00:00
oga
993fd4311f Allow a mouse binding to hide a window, and add a default keybinding for CMS-M3,
so it's hard to press by accident, but there if you need it.

requested (in a way) and tested by johan and todd.
2008-06-25 22:44:42 +00:00
oga
a6ec6cd9e9 Support mod4 (windows key) in mouse bindings too. 2008-06-25 22:40:27 +00:00
oga
05b17bf803 Support shift in mouse bindings. There's really no reason not to.
tested by johan@ and todd@.
2008-06-25 22:38:36 +00:00
oga
2dfd021f8b Actually grab the correct mouse buttons for a window, instead of doing the
old hardcoded ones (which now can be wrong).

tested by todd@ and johan@.
2008-06-25 22:37:29 +00:00
oga
77058c59e2 Sort flags.
From Pierre Riteau, thanks!

ok okan@.
2008-06-25 01:09:09 +00:00
oga
187e7dfad2 Stop keyboard move moving the window utterly off the screen. If that
happens there's no way to get it back.  Also, stop resize making a
windows size negative or zero. X does not like that one bit.

Diff from Martynas. Ok okan@.
2008-06-25 00:52:47 +00:00
oga
6f1ed5bfe3 Don't link "-lX11 -lXau -lXdmcp" twice.
From Martin Toft, thanks!
2008-06-19 02:21:30 +00:00
oga
e21e7680e4 No need to map/unmap the window on hide/show since we already do the
same to its parent.

"makes sense" okan@.
2008-06-18 20:42:29 +00:00
oga
2bddbe12f4 Revert previous "fix" it introduces new issues of its own.
The problem that's causing us to lose windows is that rapid hiding and
unhiding causes a backlog of X events, so we lose track of client state,
and delete cc->pwin when we should not. A proper fix will arrive when it's been
worked out.
2008-06-18 19:09:12 +00:00
0ba60f0b94 missed one mouse function
noticed by oga
2008-06-17 23:46:49 +00:00
oga
4f2d4724c9 Ignore caps lock and numlock for keyboard bindings. The way Xlib makes
you do this is ugly. Also remove mod2 (numlock) and mod3 (odd) from the
list of keybinding modifiers. They don't make much sense here.

based on a heavily modified diff from Martynas.

ok okan.
2008-06-17 23:40:33 +00:00
oga
19ba704ee3 Just rework the mouse binding calculation on event to look like the
kbfunc one.  Makes the code a lot easier to read.

Fixes a bug i introduced in the last commit here.

ok okan.
2008-06-17 20:55:48 +00:00
oga
9657664c7b The mousebinding code missing a break once it had found the correct
binding, this expose another issue that's still being debugged.
Issue pointed out by Dan Harnett, thanks!

While i'm here KNF and rework the logic to not be ass-backwards.

ok okan.
2008-06-17 20:21:17 +00:00
mk
867652c484 Make this not crash when compiled with -g.
Found by myself, analysis by kurt@, fix by me with input from otto.

``Just get some fix in...'' deraadt
2008-06-16 19:09:48 +00:00
oga
07cd0b1ac5 Rip out and burn the HASH_* stuff. We don't need a SPLAY tree for one font.
makes the code a lot simpler. While here rearrange the font handling functions
to be less shit.

ok and help okan@.
2008-06-15 02:47:46 +00:00
96d7310b4a (mostly) proper xshape event support
ok oga@
2008-06-14 22:04:11 +00:00
160228210b unbreak 2008-06-14 21:59:09 +00:00
9d9c61b8f6 slightly alter the semantics of config files:
- if no config file, continue silently and apply defaults
 - if config file, parse and move on
 - if config file specified but not found, error out

ok oga@
2008-06-14 21:51:00 +00:00
bdcbbe7f53 confable menu and window mouse bindings from rivo nurges (thanks!) with
some minor fixups, man page bits and knf.

ok oga@
2008-06-14 21:48:54 +00:00
b4ae492b7b finally document functions that can be bound, removing the need to have
name_to_kbfunc[] around.

feedback jmc@, ok oga@
2008-06-13 21:22:34 +00:00
oga
01eecac5d4 Don't client_delete() on an Unmap event, only do that on a client delete event.
found by (among others) todd@ when you have a lot of clients and do something
that maps and umaps a lot of windows fast.

Debugged with aid of gdb, todd, okan and NULL pointers in a pizza place in
edmonton while waiting an inordinately long time for food.

ok okan@, todd@
2008-06-13 03:41:58 +00:00
077173527b kill another long gone proto 2008-06-12 19:10:56 +00:00
ff9e573e1d remove old (moved) code
ok oga@
2008-06-12 18:55:35 +00:00
198bb381a9 instead of forcing the ptr in the middle everytime, be more 'calm'; keep
the ptr still unless it moves out-of-bounds, then just follow the edge.

brought up by todd@

ok oga@
2008-06-12 18:32:06 +00:00
6f1f3592d4 place the pointer in the middle of the window after resizing with grab,
just like keyboard resize.

from Edd Barrett

ok oga@
2008-06-12 05:10:24 +00:00
78c8bf08cb ignore if non-zero expose events, for we could be covered by multiple
windows; merely an optimization.

ok oga@
2008-06-12 05:01:13 +00:00
4377b5ac3f re-work client_placecalc()
- make sure new clients sit inside the current screen
- respect 'gap' placement on new clients

ok oga@
2008-06-12 04:59:51 +00:00
9037043088 Enter -> Return, to be consistant and correct.
found the hard way by johan and discovered by oga.

"do it" oga@
2008-06-05 14:29:01 +00:00
610e8e83ac prevent trying to exec a null char; could potentially happen with a
canceled or empty searchstr.

ok oga@
2008-06-05 04:01:37 +00:00
efbfc5fa42 actually honor termpath and lockpath if specified in cwmrc.
"now" oga@
2008-06-05 00:07:05 +00:00
b86d3cfae9 "Meta is a perfectly well defined concept in X (The keys bound to the
Meta_L or Meta_R keysysm).  no need to redefine it roughly there" - matthieu@
2008-06-03 21:27:47 +00:00
72bc2a295b make sure to take bwdith into account when placing a new window.
ok oga@
2008-05-23 18:57:35 +00:00
oga
48528d9ba1 Grab the keyboard when we initialise the menu. This stops the keyboard
shortcut code stealing our events in some cases.

"put 'er in" okan@.
2008-05-23 18:48:57 +00:00
oga
779cf04f05 Make menu_filter handle mouse movement too. This enables the keyboard
search dialogues to be manipulated with the mouse, too. It also allows
me to shrink the codebase further by killing grab_menu().

One known issue with highlighting the first entry in a search dialogue,
that'll be fixed soonish.

ok okan@, tested by Edd Barrett and todd@.
2008-05-21 14:11:19 +00:00
oga
1e46ba72f7 Pull out the behaviour in grab_label and search_start into one utility
function menu_filter(). The plan is to eventually merge in grab_menu too.
Shrinks the code a fair bit.

Also, change XMaskEvent for XWindowEvent to prevent getting exposes for other
windows. This is particuarly noticable on slow machines with a LOT of xterms
(todd, you're an odd man).

ok okan@, todd@.
2008-05-20 14:50:51 +00:00
oga
3bb0b451f7 General cleanup.
ok okan@.
2008-05-19 18:53:09 +00:00
53116c4ec3 stop normalizing search input; searching and matching are still
case-insensitive.  since this was the only use of normalizing input,
simplify as well.

allows one to exec with mixed case unmatched commands.

"works for me" oga@
2008-05-19 18:07:53 +00:00
oga
981c2480db Function prototypes should not have parameter names in them. These must
have been missed last time i knfed this.

ok okan.
2008-05-19 17:32:22 +00:00
6733ac217f client_cyclenext() -> client_cycle() since we now pass an arg.
removes a stray proto as well.

discussed with and ok oga@
2008-05-19 17:24:19 +00:00
oga
71f99ab78f allow an autogroup value of 0 to mean no group. This means you can set
automatically "sticky" (in the traditional sense of the word) windows in
autogroup mode.

Based on an initial diff from Andrew Fresh, thanks!

ok okan@.
2008-05-19 17:13:55 +00:00
d347aa3d9a as done with cycle/rcycle, make prev/next group switching one kbfuncs
and use a flag; adjusted to match and rename to {r,}cycle.

"ok, since i came up with the same thing" oga@
2008-05-19 17:11:19 +00:00
oga
43d6e147c2 Use the XGrabKeyboard hack in for alt-tabbing as well. This stops the
mru getting the order messed up when gvim/xpdf et all steal key events.

While i'm here, change the logic in client_cyclenext() to use break instead
of goto, it's nicer that way.

Thirdly, instead of two different kbfuncs, just use the one and a flag.

"put your cycle diff in so I can pkg_delete gvim" okan@
2008-05-19 15:17:50 +00:00
7957a470fd finally implement keyboard binding for group toggling
idea for the
    "slightly-less-abhorrent-hack-but-a-hack-nonetheless-TM" from oga@

grab and ungrab the keyboard to get around some silly X apps that like
stealing events

ok oga@
2008-05-19 12:56:58 +00:00
a94f4bbb7a send the correct x/y coordinates to XConfigureWindow()
fixes some windows that seem as if they don't fit; noticed by Edd Barrett.

ok oga@
2008-05-18 20:06:36 +00:00
5a0128bdc7 remove extra calls to client_draw_border()
ok oga@
2008-05-18 20:00:16 +00:00
5fee379cb5 fix backwards logic in example; found by oga@ 2008-05-18 19:57:43 +00:00
oga
b700be764a Fix two problems with conf_unbind():
1) it used TAILQ_FOREACH() when it's removing entrys from the list, this
   is bad.
2) We didn't free key, so there was a small memleak too.

also rework conf_bindname's logic slightly to be more simple.

ok okan@
2008-05-18 19:47:19 +00:00
oga
27b023ebcb Kill conf_get_int(), it was a silly function anyway.
Since it's only used once just put the (simplified) logic into
conf_client() instead. This  means we can kill an enum and
CONF_IGNORECASE, too.

ok okan@
2008-05-18 19:43:50 +00:00
oga
5c402536fa group_ctx->name is only used in this one function, and for now it
corresponds directly to the static list of group names. Just use the
static list and stop strdup()ing a new version for the context struct.
Since that never got freed this also fixes a small memleak.

Kill some unused variables while i'm here.

ok okan@
2008-05-18 19:38:18 +00:00
oga
a21a064a9b When we're cleaning out the lists in parse_config and conf_clear it's a
lot simpler just to do while (entry = TAILQ_FIRST(head)) than to do a
for () over the whole lot. Simpler, shorter and probably faster.

ok okan@
2008-05-18 19:34:09 +00:00
0f50af616e - re-order and mostly re-write cwmrc(5)
- merge example config file into cwmrc(5) and remove (little good in here)

feedback from jmc@ - thanks!

ok simon@
2008-05-18 19:33:36 +00:00
9a58e74401 fix cwm's current XShape support from Edd Barrett -thanks.
XShape events should be handled at some point.

ok oga@
2008-05-17 03:59:54 +00:00
oga
5034a77849 KNF, no binary change.
From Pierre Riteau. Thanks!
2008-05-15 22:18:00 +00:00
ec77265b87 tiny bit of knf
ok oga@
2008-05-15 21:56:21 +00:00
458f96936d Signal handler of SIGCHLD calls waitpid() which sets errno on error. To
avoid clubbering of errno in normal context, save_errno got introduced.

ok oga
2008-05-06 15:12:04 +00:00
oga
cd0ce46817 Rework the alt-tabbing code to be a lot simpler.
Diff mostly from Edd Barrett, with some minor changes from me.
Unfortunately the issue where apps like gvim and xpdf are stealing
keyrelease events causing the ordering to be messed up, but this is a
lot better. A fix for the aforementioned issue shall be forthcoming,
once a good one's been found.

ok okan@, also tested by todd@
2008-05-01 18:01:13 +00:00
79569a4d59 Allow slashes in unquoted strings.
From Pierre Riteau
Makes sense to oga@
2008-04-29 20:17:28 +00:00
e3971fc758 nits from Pierre Riteau - thanks!
ok oga@
2008-04-28 01:27:46 +00:00
oga
898bfff36a merge kbfunc_{ptrmove,client_{move,resize}} into one function that takes a flag,
this code was almost identical...

ok okan.
2008-04-16 13:47:29 +00:00
oga
cd5c340e01 remove infowin. It slipped out of the last commit, for some reason. 2008-04-16 13:40:34 +00:00
oga
f473dc3d12 Replace a few leftover calls to strdup and calloc with xstrdup and xcalloc
respectively.

ok okan.
2008-04-16 13:38:09 +00:00
oga
f67772be65 Remove screen_infomsg(), nothing uses it.
ok okan.
2008-04-16 13:35:37 +00:00
oga
642afbdf8c kill an unused struct member.
ok okan
2008-04-16 13:33:26 +00:00
oga
d5794a6b02 make the argument parser for commands accept quoted strings, while i'm
there make u_spawn use exec_wm (renamed to u_exec) for it's execution to
remove duplicated code.

This means constructs like this work in .cwmrc:

bind CM-t "ssh -Y 192.168.1.2 \"xterm -e top\""

or alternatively:

bind CM-t "ssh -Y 192.168.1.2 'xterm -e top'"

"in it goes" okan@.
2008-04-15 21:20:56 +00:00
oga
887a5aa65f Kill dirent_isdir() and dirent_islink() nothing used them since the new
parser went in.

ok okan.
2008-04-15 20:26:50 +00:00
oga
75182c6d9c hit it with the knf stick. 2008-04-15 20:24:41 +00:00
oga
3a94c57afc Add "gap" support to .cwmrc. The options put in here make gaps on the edge
of the screen where an application won't be {,vert}maximized over. used for
placing a statusbar or something like xclock.

Patch from Edd Barrett, with input from myself and okan. Thanks!

ok okan@.
2008-04-15 18:46:58 +00:00
4bbb472a25 - add vi keybindings to search
- allow for ctrl-h as well

discussion with and ok oga@
2008-04-15 18:33:13 +00:00
fe80d40063 malloc -> calloc
suggested by and ok oga@
2008-04-15 18:22:08 +00:00
343ec1bb4f remove alt-tab menu
discussed with a few

ok oga@
2008-04-09 18:10:47 +00:00
oga
eb77aabea1 No cookie for okan.
fix use-after-free that broke exec's path getting stuff.

``paths'' isn't used anymore, but pointers to within that array are still
used in the next loop. delay freeing it until after then.
2008-04-08 17:38:27 +00:00
9702d4cfd7 better 'quit' keybinding default (CMS-q)
feedback from oga@ and simon@

ok oga@ simon@
2008-04-08 14:12:28 +00:00
539b5c6534 Make _xev_quit "volatile sig_atomic_t" for proper correctness.
Noticed by oga@, thanks!
2008-04-08 00:09:50 +00:00
0f18223042 Add quit function, bind it per default to CM-q and change exec_wm
binding to CM-w.

Inital diff from Gleydson Soares
Feedback from oga@ and okan@

ok oga@
2008-04-07 23:47:09 +00:00
cb2cc70c3f - use $PATH before _PATH_DEFPATH, from Tim van der Molen
- plug leak, noticed by oga

feedback and ok oga@
2008-04-05 21:09:19 +00:00
ef0859de20 Sync usage() with reality and manpage.
"ok, but no cookie" oga@
2008-04-03 13:58:57 +00:00
oga
34c0a0635f Fix a couple of issues with the maximization code.
If a window is vertically maximized, then resized, before the MAXIMIZED
flag wasn't removed, now it is. so doing a resize then does the right
thing.

Also, separate flags are needed for vertical and normal maximziation,
else when you do vertical-maximize, followed by maximize, the window
returns to it's original size.

ok simon@, okan@
2008-03-26 15:45:42 +00:00
e704b57d33 Introduce bsd.xconf.mk to set default config variables used
at several places in the Xenocara build in a central place instead
of duplicating the checks all over the place. ok oga@.
2008-03-25 23:41:50 +00:00
c3aa344e78 Replace the symlink configuration scheme with a simple yacc parser as
found in other places of the tree.  Remove sticky and font commandline
options and add another one for alternative config locations.
Split off cwmrc(5) from cwm(1), nuke #ifdef __OpenBSD__ while there.

tested by various kind people, feedback from oga@ and okan@ - thanks!
ok oga@, jasper@, okan@
2008-03-23 15:09:21 +00:00
38ff7a904e allow autogrouping and sticky mode to work together
ok oga@
2008-03-22 21:34:07 +00:00
oga
36c1aac90f Rip out, burn, and dance around the grave of group-edit mode.
I've yet to speak to anyone who uses it, so just kill it.

You can still add/remove from groups using the mouse binding.  Groups
may get a re-work sometime soon if i have a stroke of genius.

knocks about 4k off the i386 binary for me.

ok okan@, todd@.
2008-03-22 15:09:45 +00:00
oga
cd46788d85 Remove a bunch of unused variables and incorrect comments.
"ok with me" okan@.
2008-03-22 14:09:02 +00:00
oga
fead0d511f As mentioned in my last commit, there was an issue where the switching
code would always assume that the number of windows to switch to was
three if there were more windows hidden. Check for CLIENT_HIDDEN when we
count. Now it counts correctly.

ok simon@.
2008-03-19 00:18:28 +00:00
oga
f85ba10437 client_{,r}cycle() doens't need a client. so get rid of KBFUNC_NEEDSCLIENT.
this prevents the issue where you close or hide a window, and end up
with no client selected (you're on the root window). When that happened
alt-tab failed.  This, however, exposed to me a few more issues in the
alt-tabbing code:

-the code to detect how many lines we need looks bogus (you always get
three)

-alt-tabbing when everything is hidden always reawakes the most recent
window.

Fixes for these will be forthcoming.

ok simon@.
2008-03-18 00:48:56 +00:00
a466ddaa2d typo fix. ok oga 2008-03-14 14:38:10 +00:00
d816834954 Change the default for XSRCDIR to /usr/xenocara. ok deraadt@ 2008-03-03 07:01:44 +00:00
oga
de36e6ec2f add exec_wm to calmwm.h, it was missing (bad ian@!)
Also, exec_wm() currenty err()s out if something failed with the exec,
killing the currently running wm. This is bad. Replace the err() with
warn() instead.


from Gleydson Soares, thanks!
2008-02-20 13:00:18 +00:00
oga
7ef6f63557 Typo: s/supression/suppression
from Pierre Riteau, thanks!
2008-02-20 12:56:10 +00:00
oga
3f63e529bf usage never returns, and thus should be __dead.
ok jasper@.
2008-02-13 21:48:03 +00:00
oga
9cb4f8884e add usage() for when an unknown option is given.
from Gleydson Soares <gsoares@gmail.com>, thanks!

ok jasper@
2008-02-13 21:04:19 +00:00
oga
09dbddac87 Make cwm print the XDisplayName() if it fails to open the display,
instead of an error message that'll be gibberish to most people.

from Gleydson Soares. Thanks!

ok simon@.
2008-02-13 12:09:47 +00:00
ian
a936ffc470 Trivial typo in recent "exec windowmanager" addition 2008-01-22 17:35:23 +00:00
oga
de72f62924 All of the 9wm code in cwm has been removed or re-written. Edit LICENSE
and the manpage to reflect this. While i'm here remove the note in todo
about cleaning up the menu code; it's been done.

ok ian@, okan@ (he also provided most of the manpage rework)
2008-01-16 16:14:55 +00:00
oga
7fb2664f92 huge amount of cleanup and dead code removal.
full description of changes:
-remove fontlist, and all associated structures/calls, it's not needed.
 this also removes any doubt about leftover 9wm code (the list was
 borrowed from it). Since cwm now uses Xft for everything, the legacy
 font handling is just not needed.
-add /* FALLTHROUGH */ comments into grab_{label,menu}. I actually
 didn't intend grab_menu to be a fallthrough, but it actually works quite
 well there, so remove the extra rectangle drawing. I love it when that
 happens.
-remove a couple of unused prototypes that were obviously missed
 before.
-remove a bunch of commented out or if 0ed out code. It doesn't look to
 be coming back anytime soon.
-several functions returned an int, but this was never checked. most of
 them only failed if they failed to grab the pointer (thus the internal
 state didn't change), so just make them void and return early if this is
 the case.
-remove several unused functions and some useless variables.

knocks something like 200bytes off the stripped binary size for me.

ok marc@, tested by several others.
2008-01-16 11:39:20 +00:00
oga
1eed217b1c Rewrite most of grab_menu in grab.c (it was partly 9wm code).
This should work functionally the same, with a few simplifications.

Changes:
- we don't care if you're holding another button when you release the
  menu key if you don't want to select anything, move off the menu.
- remove the hysteresis from the menu selection (before you had to move
  more than three pixels onto a new menu entry before it selected it)
- simplify a lot of the selection code
- kill dead code.
- do what the XXX comment said and cache the screensize (i may tweak
  this later).

As far as I can tell, the only code remaining from 9wm is the list of
fonts in calmwm.c. Others appear to concur.

ok marc@, looked over and tested by a few others. Reminders from okan@.
2008-01-14 15:21:10 +00:00
oga
e5cabb0f43 - Remove the "all rights reserved" tag at the top of most of the source
files, and replace them with the actual ISC license.

- add license to the manpage (it was lacking before)

- correct license statement in the README

Permission given by Marius (copyright holder):
"1. please replace with the standard ISC license
2. you may add the ISC license to the man page
3. feel free to replace the information in the README as well"

and Dros (copyright holder for group.c):
"Please switch group.c to the ISC License."

ok ian@
2008-01-11 16:06:44 +00:00
oga
3de5c68888 Kill some more dead code, cursor.c goes away.
ok marc@
2008-01-08 20:21:43 +00:00
160d6aa910 Adjust initial window placement with any geometry that would place
the window at or over the right or bottom edge.
OK oda@
2008-01-03 20:20:20 +00:00
oga
847191cff3 Kill draw.c, nothing uses the code in it.
More dead code removals to come.

ok marc@
2008-01-03 01:58:16 +00:00
oga
f82afee4e2 Kill some warnings intoduced with the execwm feature.
ok marc@
2008-01-03 01:56:25 +00:00
381ba77e03 remove declaration of removed function
Reminded by matthieu@  (thanks!)
2008-01-02 20:54:32 +00:00
01a3f493d6 remove unused code
OK oga@
2008-01-02 20:47:11 +00:00
219f297493 Only use the x,y values from the XSizeHints structure when they are greater
than zero.   The fields are obsolete and not always used.
OK jasper@
2008-01-01 22:28:59 +00:00
2e72df662d allow the search feature to work in the root window, like other similar ones.
ok todd@
2007-12-31 02:49:45 +00:00
ian
8b3cd2243a Add a "restart wm" function. ok oga@ 2007-11-28 16:35:52 +00:00
oga
f14a3eeebf Another messed up keybinding.
I blame todd...

ok okan@
2007-11-28 16:02:37 +00:00
19ae2f65de re-add a lost group keybinding
ok oga@ todd@
2007-11-27 17:17:08 +00:00
oga
3341229c74 Make cwm default keybindings always exist. Additional keybindings now
overlap with the new ones, overriding them. Also a new "unmap" keyword
in binding definitions now unmaps a binding without adding a new one.

This seriously shrinks the ~/.calmwm/.keys directory of anyone who defines
their own bindings whilst wanting some of the defaults.

Looked over, liked and ok todd@
2007-11-19 22:18:16 +00:00
jmc
ebebed71bd fix a pasto: documentation/5639 from viq
while i'm at it:
- fix an .El botch up
- kill trailing whitespace
- new sentence, new line
2007-11-16 23:04:56 +00:00
4b85adbe60 introduce conf_bindname() to drastically simplify conf.c
really liked by oga@
2007-11-13 23:26:04 +00:00
576d299095 enable pointer movement in cwm via C-<arrowkeys>
looked over by oga@
2007-11-13 23:08:49 +00:00
oga
dc39e11ff9 Small manpage nit.
From Okan Demirmen, thanks!
2007-11-08 13:03:22 +00:00
oga
6b00b86622 Change MOVE_AMOUNT in kbfunc.c to 1 from 10. This allows more fine tuning when
moving and resizing windows using the keyboard.

Future diffs might make this value configurable.

ok jasper@, todd@.
2007-11-07 22:02:04 +00:00
oga
e64e1709ba Document cwm's keybinding support. It was already there, but not in the manpage.
While I'm here add support for extra modifier keys.

"commit commit!" jasper@, ok todd@.
2007-11-07 22:00:26 +00:00
oga
699b048959 Add support to cwm for resizing the windows using Control-Meta-[hjkl].
Please note that this remaps Control-Meta-L (label) to Control-Meta-N (name).

ok jasper@, todd@.
2007-11-07 21:58:03 +00:00
ian
af71fc930a wording 2007-10-07 16:56:21 +00:00
56994282f0 When cycling, only the end of the window names will be printed if the
name is too long. so show the beginning instead.

from Pierre Riteau <pierre.riteau at free.fr>

"looks correct" matthieu@
2007-10-02 18:01:45 +00:00
0584867396 fix buffer overflow, as sizeof(paths) won't fit inside the array.
from Stefan Kempf

"looks right to me" matthieu@
2007-09-06 06:01:14 +00:00
jmc
964a1e73a7 Okan Demirmen sent me a diff to kill some silly Fa macros, then persuaded
me to clean this page up;

jasper and bernd gave oks for the Fa removal;
2007-06-29 21:10:37 +00:00
365aecd25e implement keyboard initiated movement of windows
enhanced version of diff originally from niallo@
man bits from niallo@
ok niallo@ japser@
2007-06-27 13:28:22 +00:00
a1d4169eb3 modify "exec" dialog so that it auto-completes based on executables in
_PATH_DEFPATH

add an "ssh-to" dialog which auto-completes based on contents of
 ~/.ssh/known_hosts (M-.)

testing and eyeballing by Simon Kuhnle <simonkuhnle at web.de>, todd@, pedro@
mk@ and David Cathcart <david at cathcart.cx>

ok todd@
2007-06-26 19:34:26 +00:00
80d08270b8 don't map hidden windows on re-start.
from aon@iki.fi
2007-06-08 16:29:19 +00:00
35887fbdf6 document the autogroup functionality.
with aon@iki.fi
2007-06-06 22:08:02 +00:00
c025dc9089 make it possible to cycle through the windows when non are selected.
(eg. when they're hidden, now you can cycle through them)

from aon@iki.fi
2007-06-05 19:03:20 +00:00
15fdb76df9 draw window borders when redrawing a window
from aon@iki.fi
2007-06-05 18:57:03 +00:00
9b04f2582b show hidden windows when they should (eg. when the pointer is warped to them)
from aon@iki.fi via bernd@
2007-05-29 22:38:44 +00:00
5a0f777c6f don't give borderless windows a border, when they're inactive
from aon@iki.fi via bernd@
2007-05-29 22:35:04 +00:00
04248d0ed3 add two missing closedir()'s
from Antti Nyknen <aon at iki.fi> via bernd@

ok pedro@
2007-05-28 21:11:39 +00:00
9006bbf20b convert globals from G_foo to Foo, as per TODO.
"looks good" pedro@, ok matthieu@
2007-05-28 18:34:27 +00:00
4a498a4c60 full screen sized windows
ok matthieu@
2007-05-27 09:23:12 +00:00
31356d9833 autoconf junk was zapped, so no need for HAVE_CONFIG_H 2007-05-22 22:14:42 +00:00
2742ebe21c remove useless #ifdef
ok pedro@
2007-05-22 17:59:17 +00:00
2b75f1ef96 remove bogus entry (shortcut for xlock) which has been taken care of (C-M-DEL)
ok pedro@
2007-05-22 17:38:51 +00:00
57da7d7cd8 we don't use this file on openbsd, so zap it.
ok matthieu@ pedro@
2007-05-21 19:24:46 +00:00
c3a569adfb fix optind
ok ray@
2007-05-21 07:53:11 +00:00
22329fd6f6 - new sentence, new line.
- use .Pp instead of just a newline
- no empty lines between sections.

ok jmc@ matthieu@
2007-05-10 21:28:23 +00:00
9d51a8cf84 - add a "-d" option, to specify the display cwm should be started on
- adjust argc/argv by optind
- add an ENVIRONMENT section to the manpage

ok matthieu@ ray@
2007-05-10 17:23:49 +00:00
8d60503290 Apply cwm-3-input_shift.diff from http://aon.iki.fi/cwm/. 2007-04-27 18:10:39 +00:00
890a32aa33 Apply cwm-3-exec.diff from http://aon.iki.fi/cwm/. Document the new
key binding.
2007-04-27 18:08:14 +00:00
fa515a82d0 Remove autoconf crap and other stuff we don't need. 2007-04-27 18:04:40 +00:00
d957b53c6f Simple Makefile to build cwm. 2007-04-27 18:01:38 +00:00
47 changed files with 5381 additions and 19174 deletions

18
LICENSE
View File

@ -12,21 +12,3 @@
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Parts derived from 9wm:
9wm is free software, and is Copyright (c) 1994 by David Hogan.
Permission is granted to all sentient beings to use this software,
to make copies of it, and to distribute those copies, provided
that:
(1) the copyright and licence notices are left intact
(2) the recipients are aware that it is free software
(3) any unapproved changes in functionality are either
(i) only distributed as patches
or (ii) distributed as a new program which is not called 9wm
and whose documentation gives credit where it is due
(4) the author is not held responsible for any defects
or shortcomings in the software, or damages caused by it.
There is no warranty for this software. Have a nice day.

24
Makefile Normal file
View File

@ -0,0 +1,24 @@
# $OpenBSD$
.include <bsd.xconf.mk>
PROG= cwm
SRCS= calmwm.c screen.c xmalloc.c client.c menu.c \
search.c util.c xutil.c conf.c xevents.c group.c \
kbfunc.c mousefunc.c font.c parse.y
CPPFLAGS+= -I${X11BASE}/include -I${X11BASE}/include/freetype2 -I${.CURDIR}
CFLAGS+= -Wall
LDADD+= -L${X11BASE}/lib -lXft -lXrender -lX11 -lxcb -lXau -lXdmcp \
-lfontconfig -lexpat -lfreetype -lz -lXinerama -lXrandr -lXext
MANDIR= ${X11BASE}/man/man
MAN= cwm.1 cwmrc.5
obj: _xenocara_obj
.include <bsd.prog.mk>
.include <bsd.xorg.mk>

View File

@ -1,19 +0,0 @@
include $(top_srcdir)/Makefile.am.inc
CC = gcc
man_MANS = cwm.1
bin_PROGRAMS = cwm
cwm_DEPENDENCIES = @ERRO@ @LIBOBJS@
cwm_SOURCES = calmwm.c draw.c screen.c xmalloc.c client.c grab.c \
search.c util.c xutil.c conf.c input.c xevents.c \
group.c geographic.c kbfunc.c cursor.c font.c
cwm_LDADD = @ERRO@ @LIBOBJS@ $(XFT_LIBS)
AM_CFLAGS = -Wall -Icompat $(XFT_CFLAGS)
EXTRA_DIST = LICENSE README cwm.1 strlcpy.c err.c Makefile.am.inc \
compat/sys/queue.h compat/sys/tree.h hash.h calmwm.h \
headers.h strlcat.c

View File

@ -1,3 +0,0 @@
AUTOMAKE_OPTIONS = foreign no-dependencies
DISTCLEANFILES = *~

View File

@ -1,617 +0,0 @@
# Makefile.in generated by automake 1.9.6 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
# 2003, 2004, 2005 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
pkgdatadir = $(datadir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
top_builddir = .
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
INSTALL = @INSTALL@
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
target_triplet = @target@
DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \
$(srcdir)/Makefile.in $(srcdir)/config.h.in \
$(top_srcdir)/Makefile.am.inc $(top_srcdir)/configure TODO \
acconfig.h config.guess config.sub install-sh missing \
strlcat.c strlcpy.c strsep.c
bin_PROGRAMS = cwm$(EXEEXT)
subdir = .
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/configure.in
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
configure.lineno configure.status.lineno
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = config.h
CONFIG_CLEAN_FILES =
am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)"
binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
PROGRAMS = $(bin_PROGRAMS)
am_cwm_OBJECTS = calmwm.$(OBJEXT) draw.$(OBJEXT) screen.$(OBJEXT) \
xmalloc.$(OBJEXT) client.$(OBJEXT) grab.$(OBJEXT) \
search.$(OBJEXT) util.$(OBJEXT) xutil.$(OBJEXT) conf.$(OBJEXT) \
input.$(OBJEXT) xevents.$(OBJEXT) group.$(OBJEXT) \
geographic.$(OBJEXT) kbfunc.$(OBJEXT) cursor.$(OBJEXT) \
font.$(OBJEXT)
cwm_OBJECTS = $(am_cwm_OBJECTS)
am__DEPENDENCIES_1 =
DEFAULT_INCLUDES = -I. -I$(srcdir) -I.
depcomp =
am__depfiles_maybe =
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
CCLD = $(CC)
LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
SOURCES = $(cwm_SOURCES)
DIST_SOURCES = $(cwm_SOURCES)
man1dir = $(mandir)/man1
NROFF = nroff
MANS = $(man_MANS)
ETAGS = etags
CTAGS = ctags
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
distdir = $(PACKAGE)-$(VERSION)
top_distdir = $(distdir)
am__remove_distdir = \
{ test ! -d $(distdir) \
|| { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \
&& rm -fr $(distdir); }; }
DIST_ARCHIVES = $(distdir).tar.gz
GZIP_ENV = --best
distuninstallcheck_listfiles = find . -type f -print
distcleancheck_listfiles = find . -type f -print
ACLOCAL = @ACLOCAL@
AMDEP_FALSE = @AMDEP_FALSE@
AMDEP_TRUE = @AMDEP_TRUE@
AMTAR = @AMTAR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
CC = gcc
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
ERRO = @ERRO@
EXEEXT = @EXEEXT@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
LDFLAGS = @LDFLAGS@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LTLIBOBJS = @LTLIBOBJS@
MAINT = @MAINT@
MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
MAKEINFO = @MAKEINFO@
OBJEXT = @OBJEXT@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
PKG_CONFIG = @PKG_CONFIG@
RANLIB = @RANLIB@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@
VERSION = @VERSION@
XFT_CFLAGS = @XFT_CFLAGS@
XFT_LIBS = @XFT_LIBS@
X_CFLAGS = @X_CFLAGS@
X_EXTRA_LIBS = @X_EXTRA_LIBS@
X_LIBS = @X_LIBS@
X_PRE_LIBS = @X_PRE_LIBS@
ac_ct_CC = @ac_ct_CC@
ac_ct_RANLIB = @ac_ct_RANLIB@
ac_ct_STRIP = @ac_ct_STRIP@
am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
datadir = @datadir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
prefix = @prefix@
program_transform_name = @program_transform_name@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
sysconfdir = @sysconfdir@
target = @target@
target_alias = @target_alias@
target_cpu = @target_cpu@
target_os = @target_os@
target_vendor = @target_vendor@
AUTOMAKE_OPTIONS = foreign no-dependencies
DISTCLEANFILES = *~
man_MANS = cwm.1
cwm_DEPENDENCIES = @ERRO@ @LIBOBJS@
cwm_SOURCES = calmwm.c draw.c screen.c xmalloc.c client.c grab.c \
search.c util.c xutil.c conf.c input.c xevents.c \
group.c geographic.c kbfunc.c cursor.c font.c
cwm_LDADD = @ERRO@ @LIBOBJS@ $(XFT_LIBS)
AM_CFLAGS = -Wall -Icompat $(XFT_CFLAGS)
EXTRA_DIST = LICENSE README cwm.1 strlcpy.c err.c Makefile.am.inc \
compat/sys/queue.h compat/sys/tree.h hash.h calmwm.h \
headers.h strlcat.c
all: config.h
$(MAKE) $(AM_MAKEFLAGS) all-am
.SUFFIXES:
.SUFFIXES: .c .o .obj
am--refresh:
@:
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/Makefile.am.inc $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
echo ' cd $(srcdir) && $(AUTOMAKE) --foreign '; \
cd $(srcdir) && $(AUTOMAKE) --foreign \
&& exit 0; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \
cd $(top_srcdir) && \
$(AUTOMAKE) --foreign Makefile
.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
echo ' $(SHELL) ./config.status'; \
$(SHELL) ./config.status;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
$(SHELL) ./config.status --recheck
$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
cd $(srcdir) && $(AUTOCONF)
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
config.h: stamp-h1
@if test ! -f $@; then \
rm -f stamp-h1; \
$(MAKE) stamp-h1; \
else :; fi
stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
@rm -f stamp-h1
cd $(top_builddir) && $(SHELL) ./config.status config.h
$(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) $(top_srcdir)/acconfig.h
cd $(top_srcdir) && $(AUTOHEADER)
rm -f stamp-h1
touch $@
distclean-hdr:
-rm -f config.h stamp-h1
install-binPROGRAMS: $(bin_PROGRAMS)
@$(NORMAL_INSTALL)
test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)"
@list='$(bin_PROGRAMS)'; for p in $$list; do \
p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
if test -f $$p \
; then \
f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \
$(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \
else :; fi; \
done
uninstall-binPROGRAMS:
@$(NORMAL_UNINSTALL)
@list='$(bin_PROGRAMS)'; for p in $$list; do \
f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \
rm -f "$(DESTDIR)$(bindir)/$$f"; \
done
clean-binPROGRAMS:
-test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
cwm$(EXEEXT): $(cwm_OBJECTS) $(cwm_DEPENDENCIES)
@rm -f cwm$(EXEEXT)
$(LINK) $(cwm_LDFLAGS) $(cwm_OBJECTS) $(cwm_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
.c.o:
$(COMPILE) -c $<
.c.obj:
$(COMPILE) -c `$(CYGPATH_W) '$<'`
uninstall-info-am:
install-man1: $(man1_MANS) $(man_MANS)
@$(NORMAL_INSTALL)
test -z "$(man1dir)" || $(mkdir_p) "$(DESTDIR)$(man1dir)"
@list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \
l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
for i in $$l2; do \
case "$$i" in \
*.1*) list="$$list $$i" ;; \
esac; \
done; \
for i in $$list; do \
if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
else file=$$i; fi; \
ext=`echo $$i | sed -e 's/^.*\\.//'`; \
case "$$ext" in \
1*) ;; \
*) ext='1' ;; \
esac; \
inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
inst=`echo $$inst | sed -e 's/^.*\///'`; \
inst=`echo $$inst | sed '$(transform)'`.$$ext; \
echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \
$(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst"; \
done
uninstall-man1:
@$(NORMAL_UNINSTALL)
@list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \
l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
for i in $$l2; do \
case "$$i" in \
*.1*) list="$$list $$i" ;; \
esac; \
done; \
for i in $$list; do \
ext=`echo $$i | sed -e 's/^.*\\.//'`; \
case "$$ext" in \
1*) ;; \
*) ext='1' ;; \
esac; \
inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
inst=`echo $$inst | sed -e 's/^.*\///'`; \
inst=`echo $$inst | sed '$(transform)'`.$$ext; \
echo " rm -f '$(DESTDIR)$(man1dir)/$$inst'"; \
rm -f "$(DESTDIR)$(man1dir)/$$inst"; \
done
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) ' { files[$$0] = 1; } \
END { for (i in files) print i; }'`; \
mkid -fID $$unique
tags: TAGS
TAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
$(TAGS_FILES) $(LISP)
tags=; \
here=`pwd`; \
list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) ' { files[$$0] = 1; } \
END { for (i in files) print i; }'`; \
if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$tags $$unique; \
fi
ctags: CTAGS
CTAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
$(TAGS_FILES) $(LISP)
tags=; \
here=`pwd`; \
list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) ' { files[$$0] = 1; } \
END { for (i in files) print i; }'`; \
test -z "$(CTAGS_ARGS)$$tags$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$tags $$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& cd $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) $$here
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
distdir: $(DISTFILES)
$(am__remove_distdir)
mkdir $(distdir)
$(mkdir_p) $(distdir)/compat/sys
@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
list='$(DISTFILES)'; for file in $$list; do \
case $$file in \
$(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
$(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
esac; \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
if test "$$dir" != "$$file" && test "$$dir" != "."; then \
dir="/$$dir"; \
$(mkdir_p) "$(distdir)$$dir"; \
else \
dir=''; \
fi; \
if test -d $$d/$$file; then \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
fi; \
cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
else \
test -f $(distdir)/$$file \
|| cp -p $$d/$$file $(distdir)/$$file \
|| exit 1; \
fi; \
done
-find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \
! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
! -type d ! -perm -400 -exec chmod a+r {} \; -o \
! -type d ! -perm -444 -exec $(SHELL) $(install_sh) -c -m a+r {} {} \; \
|| chmod -R a+r $(distdir)
dist-gzip: distdir
tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
$(am__remove_distdir)
dist-bzip2: distdir
tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2
$(am__remove_distdir)
dist-tarZ: distdir
tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
$(am__remove_distdir)
dist-shar: distdir
shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
$(am__remove_distdir)
dist-zip: distdir
-rm -f $(distdir).zip
zip -rq $(distdir).zip $(distdir)
$(am__remove_distdir)
dist dist-all: distdir
tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
$(am__remove_distdir)
# This target untars the dist file and tries a VPATH configuration. Then
# it guarantees that the distribution is self-contained by making another
# tarfile.
distcheck: dist
case '$(DIST_ARCHIVES)' in \
*.tar.gz*) \
GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\
*.tar.bz2*) \
bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\
*.tar.Z*) \
uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
*.shar.gz*) \
GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\
*.zip*) \
unzip $(distdir).zip ;;\
esac
chmod -R a-w $(distdir); chmod a+w $(distdir)
mkdir $(distdir)/_build
mkdir $(distdir)/_inst
chmod a-w $(distdir)
dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
&& dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
&& cd $(distdir)/_build \
&& ../configure --srcdir=.. --prefix="$$dc_install_base" \
$(DISTCHECK_CONFIGURE_FLAGS) \
&& $(MAKE) $(AM_MAKEFLAGS) \
&& $(MAKE) $(AM_MAKEFLAGS) dvi \
&& $(MAKE) $(AM_MAKEFLAGS) check \
&& $(MAKE) $(AM_MAKEFLAGS) install \
&& $(MAKE) $(AM_MAKEFLAGS) installcheck \
&& $(MAKE) $(AM_MAKEFLAGS) uninstall \
&& $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
distuninstallcheck \
&& chmod -R a-w "$$dc_install_base" \
&& ({ \
(cd ../.. && umask 077 && mkdir "$$dc_destdir") \
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
} || { rm -rf "$$dc_destdir"; exit 1; }) \
&& rm -rf "$$dc_destdir" \
&& $(MAKE) $(AM_MAKEFLAGS) dist \
&& rm -rf $(DIST_ARCHIVES) \
&& $(MAKE) $(AM_MAKEFLAGS) distcleancheck
$(am__remove_distdir)
@(echo "$(distdir) archives ready for distribution: "; \
list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
sed -e '1{h;s/./=/g;p;x;}' -e '$${p;x;}'
distuninstallcheck:
@cd $(distuninstallcheck_dir) \
&& test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \
|| { echo "ERROR: files left after uninstall:" ; \
if test -n "$(DESTDIR)"; then \
echo " (check DESTDIR support)"; \
fi ; \
$(distuninstallcheck_listfiles) ; \
exit 1; } >&2
distcleancheck: distclean
@if test '$(srcdir)' = . ; then \
echo "ERROR: distcleancheck can only run from a VPATH build" ; \
exit 1 ; \
fi
@test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
|| { echo "ERROR: files left in build directory after distclean:" ; \
$(distcleancheck_listfiles) ; \
exit 1; } >&2
check-am: all-am
check: check-am
all-am: Makefile $(PROGRAMS) $(MANS) config.h
installdirs:
for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)"; do \
test -z "$$dir" || $(mkdir_p) "$$dir"; \
done
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
`test -z '$(STRIP)' || \
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
mostlyclean-generic:
clean-generic:
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
clean: clean-am
clean-am: clean-binPROGRAMS clean-generic mostlyclean-am
distclean: distclean-am
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-hdr distclean-tags
dvi: dvi-am
dvi-am:
html: html-am
info: info-am
info-am:
install-data-am: install-man
install-exec-am: install-binPROGRAMS
install-info: install-info-am
install-man: install-man1
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
-rm -rf $(top_srcdir)/autom4te.cache
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-compile mostlyclean-generic
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am: uninstall-binPROGRAMS uninstall-info-am uninstall-man
uninstall-man: uninstall-man1
.PHONY: CTAGS GTAGS all all-am am--refresh check check-am clean \
clean-binPROGRAMS clean-generic ctags dist dist-all dist-bzip2 \
dist-gzip dist-shar dist-tarZ dist-zip distcheck distclean \
distclean-compile distclean-generic distclean-hdr \
distclean-tags distcleancheck distdir distuninstallcheck dvi \
dvi-am html html-am info info-am install install-am \
install-binPROGRAMS install-data install-data-am install-exec \
install-exec-am install-info install-info-am install-man \
install-man1 install-strip installcheck installcheck-am \
installdirs maintainer-clean maintainer-clean-generic \
mostlyclean mostlyclean-compile mostlyclean-generic pdf pdf-am \
ps ps-am tags uninstall uninstall-am uninstall-binPROGRAMS \
uninstall-info-am uninstall-man uninstall-man1
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:

59
README
View File

@ -1,59 +0,0 @@
--------------------------------------------------------------------------------
cwm release three
--------------------------------------------------------------------------------
by Marius Aamodt Eriksen <marius@monkey.org>
contributions by Andy Adamson <dros@monkey.org>,
Niels Provos <provos@monkey.org>,
Martin Murray <mmurray@monkey.org>,
Dimitris Economou <dimeco@stanford.edu> &
Antti Nyk<79>nen <aon@iki.fi>.
http://monkey.org/~marius/cwm
DESCRIPTION
cwm is a window manager initially inspired by evilwm[1]. It
developed out of modifications to evilwm, but eventually the code
base of evilwm did not accomodate well for the new features added.
So calmwm was written from scratch.
Its main goal is to be as efficient as possible, while providing
a very clean, simple & attractive aesthetic.
cwm has several novel features, including the ability to search
for windows.
HIGHLIGHTS IN RELEASE TWO
* Improved alt-tabbing, including the ability to reverse cycle.
* Display of a context menu when alt-tabbing, showing the previous,
current and next window in the cycle order.
* Much improved ranking in search.
* In search-menus, the ability to list every item.
HIGHLIGHTS IN RELEASE THREE
* More search ranking improvements
* Many contributions by Antti Nyk<79>nen: keyboard binding "i18n",
show window labels in minimized window menu, automatic window
grouping, MWM hints support & some bug fixes.
* Xft support & the addition of the -f flag (see manpage).
INSTALL
./configure
make
su
make install
DOCUMENTATION
See the manpage cwm(1).
LICENSE
cwm is distributed under a BSD like license. Feel free to use,
modify and distribute in any form. See the LICENSE file for more
information.
[1] http://evilwm.sourceforge.net/

34
TODO
View File

@ -1,34 +0,0 @@
- clean up menu code from 9wm
- window initial position
- don't map windows if it's within [some time increment] of active typing,
this is part of the "calm" goal. also, it helps if you're mindlessly
typing in a password and the keyboard input ends up in some other window,
bad...
- integrate everything into /ONE/ event loop.
register handlers, with the ability to select, for example,
a window, or an event, etc. (no, maybe not...)
- ignoreq, always lower them. perhaps implement by lowering the entire
queue on each XLower...
- kbd shortcut for xlock
- search window should try to stay inside of the screen boundaries.
- geographical keyboard navigation (window switching)
- search should ignore the current window. (not add to match list).
- make kbd shortcuts/events more general. the ability to associate an
event with a mode (i.e. prioritize). gets rid of hacky-ness in
groups, etc.
- figure out what's up when alt-tab goes back to the current window
once before moving on.
- cache all the atoms somewhere.
- convert globals from G_foo to Foo;

View File

@ -1,27 +0,0 @@
#undef u_int16_t
#undef u_int32_t
#undef u_int64_t
#undef u_int8_t
@BOTTOM@
/* Prototypes for missing functions */
#ifndef HAVE_STRLCPY
size_t strlcpy(char *, const char *, size_t);
#endif
#ifndef HAVE_STRLCAT
size_t strlcat(char *, const char *, size_t);
#endif
#ifndef HAVE_STRSEP
char *strsep(char **, const char *);
#endif /* HAVE_STRSEP */
#ifndef HAVE_ERR
void err(int, const char *, ...);
void warn(const char *, ...);
void errx(int , const char *, ...);
void warnx(const char *, ...);
#endif

949
aclocal.m4 vendored
View File

@ -1,949 +0,0 @@
# generated automatically by aclocal 1.9.6 -*- Autoconf -*-
# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
# 2005 Free Software Foundation, Inc.
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
dnl PKG_CHECK_MODULES(GSTUFF, gtk+-2.0 >= 1.3 glib = 1.3.4, action-if, action-not)
dnl defines GSTUFF_LIBS, GSTUFF_CFLAGS, see pkg-config man page
dnl also defines GSTUFF_PKG_ERRORS on error
AC_DEFUN(PKG_CHECK_MODULES, [
succeeded=no
if test -z "$PKG_CONFIG"; then
AC_PATH_PROG(PKG_CONFIG, pkg-config, no)
fi
if test "$PKG_CONFIG" = "no" ; then
echo "*** The pkg-config script could not be found. Make sure it is"
echo "*** in your path, or set the PKG_CONFIG environment variable"
echo "*** to the full path to pkg-config."
echo "*** Or see http://www.freedesktop.org/software/pkgconfig to get pkg-config."
else
PKG_CONFIG_MIN_VERSION=0.9.0
if $PKG_CONFIG --atleast-pkgconfig-version $PKG_CONFIG_MIN_VERSION; then
AC_MSG_CHECKING(for $2)
if $PKG_CONFIG --exists "$2" ; then
AC_MSG_RESULT(yes)
succeeded=yes
AC_MSG_CHECKING($1_CFLAGS)
$1_CFLAGS=`$PKG_CONFIG --cflags "$2"`
AC_MSG_RESULT($$1_CFLAGS)
AC_MSG_CHECKING($1_LIBS)
$1_LIBS=`$PKG_CONFIG --libs "$2"`
AC_MSG_RESULT($$1_LIBS)
else
$1_CFLAGS=""
$1_LIBS=""
## If we have a custom action on failure, don't print errors, but
## do set a variable so people can do so.
$1_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"`
ifelse([$4], ,echo $$1_PKG_ERRORS,)
fi
AC_SUBST($1_CFLAGS)
AC_SUBST($1_LIBS)
else
echo "*** Your version of pkg-config is too old. You need version $PKG_CONFIG_MIN_VERSION or newer."
echo "*** See http://www.freedesktop.org/software/pkgconfig"
fi
fi
if test $succeeded = yes; then
ifelse([$3], , :, [$3])
else
ifelse([$4], , AC_MSG_ERROR([Library requirements ($2) not met; consider adjusting the PKG_CONFIG_PATH environment variable if your libraries are in a nonstandard prefix so pkg-config can find them.]), [$4])
fi
])
# Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# AM_AUTOMAKE_VERSION(VERSION)
# ----------------------------
# Automake X.Y traces this macro to ensure aclocal.m4 has been
# generated from the m4 files accompanying Automake X.Y.
AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version="1.9"])
# AM_SET_CURRENT_AUTOMAKE_VERSION
# -------------------------------
# Call AM_AUTOMAKE_VERSION so it can be traced.
# This function is AC_REQUIREd by AC_INIT_AUTOMAKE.
AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
[AM_AUTOMAKE_VERSION([1.9.6])])
# AM_AUX_DIR_EXPAND -*- Autoconf -*-
# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to
# `$srcdir', `$srcdir/..', or `$srcdir/../..'.
#
# Of course, Automake must honor this variable whenever it calls a
# tool from the auxiliary directory. The problem is that $srcdir (and
# therefore $ac_aux_dir as well) can be either absolute or relative,
# depending on how configure is run. This is pretty annoying, since
# it makes $ac_aux_dir quite unusable in subdirectories: in the top
# source directory, any form will work fine, but in subdirectories a
# relative path needs to be adjusted first.
#
# $ac_aux_dir/missing
# fails when called from a subdirectory if $ac_aux_dir is relative
# $top_srcdir/$ac_aux_dir/missing
# fails if $ac_aux_dir is absolute,
# fails when called from a subdirectory in a VPATH build with
# a relative $ac_aux_dir
#
# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
# are both prefixed by $srcdir. In an in-source build this is usually
# harmless because $srcdir is `.', but things will broke when you
# start a VPATH build or use an absolute $srcdir.
#
# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
# iff we strip the leading $srcdir from $ac_aux_dir. That would be:
# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
# and then we would define $MISSING as
# MISSING="\${SHELL} $am_aux_dir/missing"
# This will work as long as MISSING is not called from configure, because
# unfortunately $(top_srcdir) has no meaning in configure.
# However there are other variables, like CC, which are often used in
# configure, and could therefore not use this "fixed" $ac_aux_dir.
#
# Another solution, used here, is to always expand $ac_aux_dir to an
# absolute PATH. The drawback is that using absolute paths prevent a
# configured tree to be moved without reconfiguration.
AC_DEFUN([AM_AUX_DIR_EXPAND],
[dnl Rely on autoconf to set up CDPATH properly.
AC_PREREQ([2.50])dnl
# expand $ac_aux_dir to an absolute path
am_aux_dir=`cd $ac_aux_dir && pwd`
])
# AM_CONDITIONAL -*- Autoconf -*-
# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005
# Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 7
# AM_CONDITIONAL(NAME, SHELL-CONDITION)
# -------------------------------------
# Define a conditional.
AC_DEFUN([AM_CONDITIONAL],
[AC_PREREQ(2.52)dnl
ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])],
[$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
AC_SUBST([$1_TRUE])
AC_SUBST([$1_FALSE])
if $2; then
$1_TRUE=
$1_FALSE='#'
else
$1_TRUE='#'
$1_FALSE=
fi
AC_CONFIG_COMMANDS_PRE(
[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
AC_MSG_ERROR([[conditional "$1" was never defined.
Usually this means the macro was only invoked conditionally.]])
fi])])
# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
# Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 8
# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be
# written in clear, in which case automake, when reading aclocal.m4,
# will think it sees a *use*, and therefore will trigger all it's
# C support machinery. Also note that it means that autoscan, seeing
# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
# _AM_DEPENDENCIES(NAME)
# ----------------------
# See how the compiler implements dependency checking.
# NAME is "CC", "CXX", "GCJ", or "OBJC".
# We try a few techniques and use that to set a single cache variable.
#
# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
# dependency, and given that the user is not expected to run this macro,
# just rely on AC_PROG_CC.
AC_DEFUN([_AM_DEPENDENCIES],
[AC_REQUIRE([AM_SET_DEPDIR])dnl
AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
AC_REQUIRE([AM_MAKE_INCLUDE])dnl
AC_REQUIRE([AM_DEP_TRACK])dnl
ifelse([$1], CC, [depcc="$CC" am_compiler_list=],
[$1], CXX, [depcc="$CXX" am_compiler_list=],
[$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
[$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'],
[depcc="$$1" am_compiler_list=])
AC_CACHE_CHECK([dependency style of $depcc],
[am_cv_$1_dependencies_compiler_type],
[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
# We make a subdir and do the tests there. Otherwise we can end up
# making bogus files that we don't know about and never remove. For
# instance it was reported that on HP-UX the gcc test will end up
# making a dummy file named `D' -- because `-MD' means `put the output
# in D'.
mkdir conftest.dir
# Copy depcomp to subdir because otherwise we won't find it if we're
# using a relative directory.
cp "$am_depcomp" conftest.dir
cd conftest.dir
# We will build objects and dependencies in a subdirectory because
# it helps to detect inapplicable dependency modes. For instance
# both Tru64's cc and ICC support -MD to output dependencies as a
# side effect of compilation, but ICC will put the dependencies in
# the current directory while Tru64 will put them in the object
# directory.
mkdir sub
am_cv_$1_dependencies_compiler_type=none
if test "$am_compiler_list" = ""; then
am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
fi
for depmode in $am_compiler_list; do
# Setup a source with many dependencies, because some compilers
# like to wrap large dependency lists on column 80 (with \), and
# we should not choose a depcomp mode which is confused by this.
#
# We need to recreate these files for each test, as the compiler may
# overwrite some of them when testing with obscure command lines.
# This happens at least with the AIX C compiler.
: > sub/conftest.c
for i in 1 2 3 4 5 6; do
echo '#include "conftst'$i'.h"' >> sub/conftest.c
# Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
# Solaris 8's {/usr,}/bin/sh.
touch sub/conftst$i.h
done
echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
case $depmode in
nosideeffect)
# after this tag, mechanisms are not by side-effect, so they'll
# only be used when explicitly requested
if test "x$enable_dependency_tracking" = xyes; then
continue
else
break
fi
;;
none) break ;;
esac
# We check with `-c' and `-o' for the sake of the "dashmstdout"
# mode. It turns out that the SunPro C++ compiler does not properly
# handle `-M -o', and we need to detect this.
if depmode=$depmode \
source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \
depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
$SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \
>/dev/null 2>conftest.err &&
grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 &&
${MAKE-make} -s -f confmf > /dev/null 2>&1; then
# icc doesn't choke on unknown options, it will just issue warnings
# or remarks (even with -Werror). So we grep stderr for any message
# that says an option was ignored or not supported.
# When given -MP, icc 7.0 and 7.1 complain thusly:
# icc: Command line warning: ignoring option '-M'; no argument required
# The diagnosis changed in icc 8.0:
# icc: Command line remark: option '-MP' not supported
if (grep 'ignoring option' conftest.err ||
grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
am_cv_$1_dependencies_compiler_type=$depmode
break
fi
fi
done
cd ..
rm -rf conftest.dir
else
am_cv_$1_dependencies_compiler_type=none
fi
])
AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
AM_CONDITIONAL([am__fastdep$1], [
test "x$enable_dependency_tracking" != xno \
&& test "$am_cv_$1_dependencies_compiler_type" = gcc3])
])
# AM_SET_DEPDIR
# -------------
# Choose a directory name for dependency files.
# This macro is AC_REQUIREd in _AM_DEPENDENCIES
AC_DEFUN([AM_SET_DEPDIR],
[AC_REQUIRE([AM_SET_LEADING_DOT])dnl
AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
])
# AM_DEP_TRACK
# ------------
AC_DEFUN([AM_DEP_TRACK],
[AC_ARG_ENABLE(dependency-tracking,
[ --disable-dependency-tracking speeds up one-time build
--enable-dependency-tracking do not reject slow dependency extractors])
if test "x$enable_dependency_tracking" != xno; then
am_depcomp="$ac_aux_dir/depcomp"
AMDEPBACKSLASH='\'
fi
AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
AC_SUBST([AMDEPBACKSLASH])
])
# Generate code to set up dependency tracking. -*- Autoconf -*-
# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
# Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
#serial 3
# _AM_OUTPUT_DEPENDENCY_COMMANDS
# ------------------------------
AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
[for mf in $CONFIG_FILES; do
# Strip MF so we end up with the name of the file.
mf=`echo "$mf" | sed -e 's/:.*$//'`
# Check whether this is an Automake generated Makefile or not.
# We used to match only the files named `Makefile.in', but
# some people rename them; so instead we look at the file content.
# Grep'ing the first line is not enough: some people post-process
# each Makefile.in and add a new line on top of each file to say so.
# So let's grep whole file.
if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then
dirpart=`AS_DIRNAME("$mf")`
else
continue
fi
# Extract the definition of DEPDIR, am__include, and am__quote
# from the Makefile without running `make'.
DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
test -z "$DEPDIR" && continue
am__include=`sed -n 's/^am__include = //p' < "$mf"`
test -z "am__include" && continue
am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
# When using ansi2knr, U may be empty or an underscore; expand it
U=`sed -n 's/^U = //p' < "$mf"`
# Find all dependency output files, they are included files with
# $(DEPDIR) in their names. We invoke sed twice because it is the
# simplest approach to changing $(DEPDIR) to its actual value in the
# expansion.
for file in `sed -n "
s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
# Make sure the directory exists.
test -f "$dirpart/$file" && continue
fdir=`AS_DIRNAME(["$file"])`
AS_MKDIR_P([$dirpart/$fdir])
# echo "creating $dirpart/$file"
echo '# dummy' > "$dirpart/$file"
done
done
])# _AM_OUTPUT_DEPENDENCY_COMMANDS
# AM_OUTPUT_DEPENDENCY_COMMANDS
# -----------------------------
# This macro should only be invoked once -- use via AC_REQUIRE.
#
# This code is only required when automatic dependency tracking
# is enabled. FIXME. This creates each `.P' file that we will
# need in order to bootstrap the dependency handling code.
AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
[AC_CONFIG_COMMANDS([depfiles],
[test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
[AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"])
])
# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005
# Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 8
# AM_CONFIG_HEADER is obsolete. It has been replaced by AC_CONFIG_HEADERS.
AU_DEFUN([AM_CONFIG_HEADER], [AC_CONFIG_HEADERS($@)])
# Do all the work for Automake. -*- Autoconf -*-
# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
# Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 12
# This macro actually does too much. Some checks are only needed if
# your package does certain things. But this isn't really a big deal.
# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
# AM_INIT_AUTOMAKE([OPTIONS])
# -----------------------------------------------
# The call with PACKAGE and VERSION arguments is the old style
# call (pre autoconf-2.50), which is being phased out. PACKAGE
# and VERSION should now be passed to AC_INIT and removed from
# the call to AM_INIT_AUTOMAKE.
# We support both call styles for the transition. After
# the next Automake release, Autoconf can make the AC_INIT
# arguments mandatory, and then we can depend on a new Autoconf
# release and drop the old call support.
AC_DEFUN([AM_INIT_AUTOMAKE],
[AC_PREREQ([2.58])dnl
dnl Autoconf wants to disallow AM_ names. We explicitly allow
dnl the ones we care about.
m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
AC_REQUIRE([AC_PROG_INSTALL])dnl
# test to see if srcdir already configured
if test "`cd $srcdir && pwd`" != "`pwd`" &&
test -f $srcdir/config.status; then
AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
fi
# test whether we have cygpath
if test -z "$CYGPATH_W"; then
if (cygpath --version) >/dev/null 2>/dev/null; then
CYGPATH_W='cygpath -w'
else
CYGPATH_W=echo
fi
fi
AC_SUBST([CYGPATH_W])
# Define the identity of the package.
dnl Distinguish between old-style and new-style calls.
m4_ifval([$2],
[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
AC_SUBST([PACKAGE], [$1])dnl
AC_SUBST([VERSION], [$2])],
[_AM_SET_OPTIONS([$1])dnl
AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
_AM_IF_OPTION([no-define],,
[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl
# Some tools Automake needs.
AC_REQUIRE([AM_SANITY_CHECK])dnl
AC_REQUIRE([AC_ARG_PROGRAM])dnl
AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version})
AM_MISSING_PROG(AUTOCONF, autoconf)
AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version})
AM_MISSING_PROG(AUTOHEADER, autoheader)
AM_MISSING_PROG(MAKEINFO, makeinfo)
AM_PROG_INSTALL_SH
AM_PROG_INSTALL_STRIP
AC_REQUIRE([AM_PROG_MKDIR_P])dnl
# We need awk for the "check" target. The system "awk" is bad on
# some platforms.
AC_REQUIRE([AC_PROG_AWK])dnl
AC_REQUIRE([AC_PROG_MAKE_SET])dnl
AC_REQUIRE([AM_SET_LEADING_DOT])dnl
_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
[_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
[_AM_PROG_TAR([v7])])])
_AM_IF_OPTION([no-dependencies],,
[AC_PROVIDE_IFELSE([AC_PROG_CC],
[_AM_DEPENDENCIES(CC)],
[define([AC_PROG_CC],
defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl
AC_PROVIDE_IFELSE([AC_PROG_CXX],
[_AM_DEPENDENCIES(CXX)],
[define([AC_PROG_CXX],
defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl
])
])
# When config.status generates a header, we must update the stamp-h file.
# This file resides in the same directory as the config header
# that is generated. The stamp files are numbered to have different names.
# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
# loop where config.status creates the headers, so we can generate
# our stamp files there.
AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
[# Compute $1's index in $config_headers.
_am_stamp_count=1
for _am_header in $config_headers :; do
case $_am_header in
$1 | $1:* )
break ;;
* )
_am_stamp_count=`expr $_am_stamp_count + 1` ;;
esac
done
echo "timestamp for $1" >`AS_DIRNAME([$1])`/stamp-h[]$_am_stamp_count])
# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# AM_PROG_INSTALL_SH
# ------------------
# Define $install_sh.
AC_DEFUN([AM_PROG_INSTALL_SH],
[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
install_sh=${install_sh-"$am_aux_dir/install-sh"}
AC_SUBST(install_sh)])
# Copyright (C) 2003, 2005 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 2
# Check whether the underlying file-system supports filenames
# with a leading dot. For instance MS-DOS doesn't.
AC_DEFUN([AM_SET_LEADING_DOT],
[rm -rf .tst 2>/dev/null
mkdir .tst 2>/dev/null
if test -d .tst; then
am__leading_dot=.
else
am__leading_dot=_
fi
rmdir .tst 2>/dev/null
AC_SUBST([am__leading_dot])])
# Add --enable-maintainer-mode option to configure. -*- Autoconf -*-
# From Jim Meyering
# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005
# Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 4
AC_DEFUN([AM_MAINTAINER_MODE],
[AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
dnl maintainer-mode is disabled by default
AC_ARG_ENABLE(maintainer-mode,
[ --enable-maintainer-mode enable make rules and dependencies not useful
(and sometimes confusing) to the casual installer],
USE_MAINTAINER_MODE=$enableval,
USE_MAINTAINER_MODE=no)
AC_MSG_RESULT([$USE_MAINTAINER_MODE])
AM_CONDITIONAL(MAINTAINER_MODE, [test $USE_MAINTAINER_MODE = yes])
MAINT=$MAINTAINER_MODE_TRUE
AC_SUBST(MAINT)dnl
]
)
AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE])
# Check to see how 'make' treats includes. -*- Autoconf -*-
# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 3
# AM_MAKE_INCLUDE()
# -----------------
# Check to see how make treats includes.
AC_DEFUN([AM_MAKE_INCLUDE],
[am_make=${MAKE-make}
cat > confinc << 'END'
am__doit:
@echo done
.PHONY: am__doit
END
# If we don't find an include directive, just comment out the code.
AC_MSG_CHECKING([for style of include used by $am_make])
am__include="#"
am__quote=
_am_result=none
# First try GNU make style include.
echo "include confinc" > confmf
# We grep out `Entering directory' and `Leaving directory'
# messages which can occur if `w' ends up in MAKEFLAGS.
# In particular we don't look at `^make:' because GNU make might
# be invoked under some other name (usually "gmake"), in which
# case it prints its new name instead of `make'.
if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then
am__include=include
am__quote=
_am_result=GNU
fi
# Now try BSD make style include.
if test "$am__include" = "#"; then
echo '.include "confinc"' > confmf
if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then
am__include=.include
am__quote="\""
_am_result=BSD
fi
fi
AC_SUBST([am__include])
AC_SUBST([am__quote])
AC_MSG_RESULT([$_am_result])
rm -f confinc confmf
])
# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*-
# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2005
# Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 4
# AM_MISSING_PROG(NAME, PROGRAM)
# ------------------------------
AC_DEFUN([AM_MISSING_PROG],
[AC_REQUIRE([AM_MISSING_HAS_RUN])
$1=${$1-"${am_missing_run}$2"}
AC_SUBST($1)])
# AM_MISSING_HAS_RUN
# ------------------
# Define MISSING if not defined so far and test if it supports --run.
# If it does, set am_missing_run to use it, otherwise, to nothing.
AC_DEFUN([AM_MISSING_HAS_RUN],
[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing"
# Use eval to expand $SHELL
if eval "$MISSING --run true"; then
am_missing_run="$MISSING --run "
else
am_missing_run=
AC_MSG_WARN([`missing' script is too old or missing])
fi
])
# Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# AM_PROG_MKDIR_P
# ---------------
# Check whether `mkdir -p' is supported, fallback to mkinstalldirs otherwise.
#
# Automake 1.8 used `mkdir -m 0755 -p --' to ensure that directories
# created by `make install' are always world readable, even if the
# installer happens to have an overly restrictive umask (e.g. 077).
# This was a mistake. There are at least two reasons why we must not
# use `-m 0755':
# - it causes special bits like SGID to be ignored,
# - it may be too restrictive (some setups expect 775 directories).
#
# Do not use -m 0755 and let people choose whatever they expect by
# setting umask.
#
# We cannot accept any implementation of `mkdir' that recognizes `-p'.
# Some implementations (such as Solaris 8's) are not thread-safe: if a
# parallel make tries to run `mkdir -p a/b' and `mkdir -p a/c'
# concurrently, both version can detect that a/ is missing, but only
# one can create it and the other will error out. Consequently we
# restrict ourselves to GNU make (using the --version option ensures
# this.)
AC_DEFUN([AM_PROG_MKDIR_P],
[if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then
# We used to keeping the `.' as first argument, in order to
# allow $(mkdir_p) to be used without argument. As in
# $(mkdir_p) $(somedir)
# where $(somedir) is conditionally defined. However this is wrong
# for two reasons:
# 1. if the package is installed by a user who cannot write `.'
# make install will fail,
# 2. the above comment should most certainly read
# $(mkdir_p) $(DESTDIR)$(somedir)
# so it does not work when $(somedir) is undefined and
# $(DESTDIR) is not.
# To support the latter case, we have to write
# test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir),
# so the `.' trick is pointless.
mkdir_p='mkdir -p --'
else
# On NextStep and OpenStep, the `mkdir' command does not
# recognize any option. It will interpret all options as
# directories to create, and then abort because `.' already
# exists.
for d in ./-p ./--version;
do
test -d $d && rmdir $d
done
# $(mkinstalldirs) is defined by Automake if mkinstalldirs exists.
if test -f "$ac_aux_dir/mkinstalldirs"; then
mkdir_p='$(mkinstalldirs)'
else
mkdir_p='$(install_sh) -d'
fi
fi
AC_SUBST([mkdir_p])])
# Helper functions for option handling. -*- Autoconf -*-
# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 3
# _AM_MANGLE_OPTION(NAME)
# -----------------------
AC_DEFUN([_AM_MANGLE_OPTION],
[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
# _AM_SET_OPTION(NAME)
# ------------------------------
# Set option NAME. Presently that only means defining a flag for this option.
AC_DEFUN([_AM_SET_OPTION],
[m4_define(_AM_MANGLE_OPTION([$1]), 1)])
# _AM_SET_OPTIONS(OPTIONS)
# ----------------------------------
# OPTIONS is a space-separated list of Automake options.
AC_DEFUN([_AM_SET_OPTIONS],
[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
# -------------------------------------------
# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
AC_DEFUN([_AM_IF_OPTION],
[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
# Check to make sure that the build environment is sane. -*- Autoconf -*-
# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005
# Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 4
# AM_SANITY_CHECK
# ---------------
AC_DEFUN([AM_SANITY_CHECK],
[AC_MSG_CHECKING([whether build environment is sane])
# Just in case
sleep 1
echo timestamp > conftest.file
# Do `set' in a subshell so we don't clobber the current shell's
# arguments. Must try -L first in case configure is actually a
# symlink; some systems play weird games with the mod time of symlinks
# (eg FreeBSD returns the mod time of the symlink's containing
# directory).
if (
set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null`
if test "$[*]" = "X"; then
# -L didn't work.
set X `ls -t $srcdir/configure conftest.file`
fi
rm -f conftest.file
if test "$[*]" != "X $srcdir/configure conftest.file" \
&& test "$[*]" != "X conftest.file $srcdir/configure"; then
# If neither matched, then we have a broken ls. This can happen
# if, for instance, CONFIG_SHELL is bash and it inherits a
# broken ls alias from the environment. This has actually
# happened. Such a system could not be considered "sane".
AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken
alias in your environment])
fi
test "$[2]" = conftest.file
)
then
# Ok.
:
else
AC_MSG_ERROR([newly created file is older than distributed files!
Check your system clock])
fi
AC_MSG_RESULT(yes)])
# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# AM_PROG_INSTALL_STRIP
# ---------------------
# One issue with vendor `install' (even GNU) is that you can't
# specify the program used to strip binaries. This is especially
# annoying in cross-compiling environments, where the build's strip
# is unlikely to handle the host's binaries.
# Fortunately install-sh will honor a STRIPPROG variable, so we
# always use install-sh in `make install-strip', and initialize
# STRIPPROG with the value of the STRIP variable (set by the user).
AC_DEFUN([AM_PROG_INSTALL_STRIP],
[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
# Installed binaries are usually stripped using `strip' when the user
# run `make install-strip'. However `strip' might not be the right
# tool to use in cross-compilation environments, therefore Automake
# will honor the `STRIP' environment variable to overrule this program.
dnl Don't test for $cross_compiling = yes, because it might be `maybe'.
if test "$cross_compiling" != no; then
AC_CHECK_TOOL([STRIP], [strip], :)
fi
INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s"
AC_SUBST([INSTALL_STRIP_PROGRAM])])
# Check how to create a tarball. -*- Autoconf -*-
# Copyright (C) 2004, 2005 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 2
# _AM_PROG_TAR(FORMAT)
# --------------------
# Check how to create a tarball in format FORMAT.
# FORMAT should be one of `v7', `ustar', or `pax'.
#
# Substitute a variable $(am__tar) that is a command
# writing to stdout a FORMAT-tarball containing the directory
# $tardir.
# tardir=directory && $(am__tar) > result.tar
#
# Substitute a variable $(am__untar) that extract such
# a tarball read from stdin.
# $(am__untar) < result.tar
AC_DEFUN([_AM_PROG_TAR],
[# Always define AMTAR for backward compatibility.
AM_MISSING_PROG([AMTAR], [tar])
m4_if([$1], [v7],
[am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'],
[m4_case([$1], [ustar],, [pax],,
[m4_fatal([Unknown tar format])])
AC_MSG_CHECKING([how to create a $1 tar archive])
# Loop over all known methods to create a tar archive until one works.
_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
_am_tools=${am_cv_prog_tar_$1-$_am_tools}
# Do not fold the above two line into one, because Tru64 sh and
# Solaris sh will not grok spaces in the rhs of `-'.
for _am_tool in $_am_tools
do
case $_am_tool in
gnutar)
for _am_tar in tar gnutar gtar;
do
AM_RUN_LOG([$_am_tar --version]) && break
done
am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
am__untar="$_am_tar -xf -"
;;
plaintar)
# Must skip GNU tar: if it does not support --format= it doesn't create
# ustar tarball either.
(tar --version) >/dev/null 2>&1 && continue
am__tar='tar chf - "$$tardir"'
am__tar_='tar chf - "$tardir"'
am__untar='tar xf -'
;;
pax)
am__tar='pax -L -x $1 -w "$$tardir"'
am__tar_='pax -L -x $1 -w "$tardir"'
am__untar='pax -r'
;;
cpio)
am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
am__untar='cpio -i -H $1 -d'
;;
none)
am__tar=false
am__tar_=false
am__untar=false
;;
esac
# If the value was cached, stop now. We just wanted to have am__tar
# and am__untar set.
test -n "${am_cv_prog_tar_$1}" && break
# tar/untar a dummy directory, and stop if the command works
rm -rf conftest.dir
mkdir conftest.dir
echo GrepMe > conftest.dir/file
AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
rm -rf conftest.dir
if test -s conftest.tar; then
AM_RUN_LOG([$am__untar <conftest.tar])
grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
fi
done
rm -rf conftest.dir
AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
AC_MSG_RESULT([$am_cv_prog_tar_$1])])
AC_SUBST([am__tar])
AC_SUBST([am__untar])
]) # _AM_PROG_TAR

530
calmwm.c
View File

@ -2,344 +2,262 @@
* calmwm - the calm window manager
*
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
* All rights reserved.
*
* $Id$
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $OpenBSD$
*/
#include "headers.h"
#include <sys/param.h>
#include <sys/queue.h>
#include <sys/wait.h>
#include <err.h>
#include <errno.h>
#include <getopt.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "calmwm.h"
Display *G_dpy;
XFontStruct *G_font;
Display *X_Dpy;
Cursor G_cursor_move;
Cursor G_cursor_resize;
Cursor G_cursor_select;
Cursor G_cursor_default;
Cursor G_cursor_question;
Cursor Cursor_default;
Cursor Cursor_move;
Cursor Cursor_normal;
Cursor Cursor_question;
Cursor Cursor_resize;
struct screen_ctx_q G_screenq;
struct screen_ctx *G_curscreen;
u_int G_nscreens;
struct screen_ctx_q Screenq = TAILQ_HEAD_INITIALIZER(Screenq);
struct client_ctx_q Clientq = TAILQ_HEAD_INITIALIZER(Clientq);
struct client_ctx_q G_clientq;
int HasXinerama, HasRandr, Randr_ev;
struct conf Conf;
int G_doshape, G_shape_ev;
int G_starting;
struct conf G_conf;
struct fontdesc *DefaultFont;
char *DefaultFontName;
/* From TWM */
#define gray_width 2
#define gray_height 2
static char gray_bits[] = {0x02, 0x01};
/* List borrowed from 9wm/rio */
char *tryfonts[] = {
"9x15bold",
"blit",
"*-lucidatypewriter-bold-*-14-*-75-*",
"*-lucidatypewriter-medium-*-12-*-75-*",
"fixed",
"*",
NULL,
};
static void _sigchld_cb(int);
static void sigchld_cb(int);
static void dpy_init(const char *);
static int x_errorhandler(Display *, XErrorEvent *);
static int x_wmerrorhandler(Display *, XErrorEvent *);
static void x_setup(void);
static void x_setupscreen(struct screen_ctx *, u_int);
static void x_teardown(void);
int
main(int argc, char **argv)
{
int ch;
int conf_flags = 0;
const char *conf_file = NULL;
char *display_name = NULL;
int ch;
DefaultFontName = "sans-serif:pixelsize=14:bold";
while ((ch = getopt(argc, argv, "sf:")) != -1) {
while ((ch = getopt(argc, argv, "c:d:")) != -1) {
switch (ch) {
case 's':
conf_flags |= CONF_STICKY_GROUPS;
case 'c':
conf_file = optarg;
break;
case 'f':
DefaultFontName = xstrdup(optarg);
case 'd':
display_name = optarg;
break;
default:
errx(1, "Unknown option '%c'", ch);
usage();
}
}
argc -= optind;
argv += optind;
/* Ignore a few signals. */
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
err(1, "signal");
if (signal(SIGCHLD, sigchld_cb) == SIG_ERR)
err(1, "signal");
if (signal(SIGCHLD, _sigchld_cb) == SIG_ERR)
err(1, "signal");
dpy_init(display_name);
group_init();
G_starting = 1;
conf_setup(&G_conf);
G_conf.flags |= conf_flags;
client_setup();
bzero(&Conf, sizeof(Conf));
conf_setup(&Conf, conf_file);
xu_getatoms();
x_setup();
G_starting = 0;
xev_init();
XEV_QUICK(NULL, NULL, MapRequest, xev_handle_maprequest, NULL);
XEV_QUICK(NULL, NULL, UnmapNotify, xev_handle_unmapnotify, NULL);
XEV_QUICK(NULL, NULL, ConfigureRequest,
xev_handle_configurerequest, NULL);
XEV_QUICK(NULL, NULL, PropertyNotify, xev_handle_propertynotify, NULL);
XEV_QUICK(NULL, NULL, EnterNotify, xev_handle_enternotify, NULL);
XEV_QUICK(NULL, NULL, LeaveNotify, xev_handle_leavenotify, NULL);
XEV_QUICK(NULL, NULL, ButtonPress, xev_handle_buttonpress, NULL);
XEV_QUICK(NULL, NULL, ButtonRelease, xev_handle_buttonrelease, NULL);
XEV_QUICK(NULL, NULL, KeyPress, xev_handle_keypress, NULL);
XEV_QUICK(NULL, NULL, KeyRelease, xev_handle_keyrelease, NULL);
XEV_QUICK(NULL, NULL, Expose, xev_handle_expose, NULL);
XEV_QUICK(NULL, NULL, DestroyNotify, xev_handle_destroynotify, NULL);
XEV_QUICK(NULL, NULL, ClientMessage, xev_handle_clientmessage, NULL);
xev_loop();
return (0);
}
void
x_setup(void)
{
int i;
struct screen_ctx *sc;
char *fontname;
TAILQ_INIT(&G_screenq);
if ((G_dpy = XOpenDisplay("")) == NULL)
errx(1, "%s:%d XOpenDisplay()", __FILE__, __LINE__);
XSetErrorHandler(x_errorhandler);
G_doshape = XShapeQueryExtension(G_dpy, &G_shape_ev, &i);
i = 0;
while ((fontname = tryfonts[i++]) != NULL) {
if ((G_font = XLoadQueryFont(G_dpy, fontname)) != NULL)
break;
}
if (fontname == NULL)
errx(1, "Couldn't load any fonts.");
G_nscreens = ScreenCount(G_dpy);
for (i = 0; i < (int)G_nscreens; i++) {
XMALLOC(sc, struct screen_ctx);
x_setupscreen(sc, i);
TAILQ_INSERT_TAIL(&G_screenq, sc, entry);
}
G_cursor_move = XCreateFontCursor(G_dpy, XC_fleur);
G_cursor_resize = XCreateFontCursor(G_dpy, XC_bottom_right_corner);
/* (used to be) XCreateFontCursor(G_dpy, XC_hand1); */
G_cursor_select = XCreateFontCursor(G_dpy, XC_hand1);
/* G_cursor_select = cursor_bigarrow(G_curscreen); */
G_cursor_default = XCreateFontCursor(G_dpy, XC_X_cursor);
/* G_cursor_default = cursor_bigarrow(G_curscreen); */
G_cursor_question = XCreateFontCursor(G_dpy, XC_question_arrow);
}
int
x_setupscreen(struct screen_ctx *sc, u_int which)
{
XColor tmp;
XGCValues gv, gv1/* , gv2 */;
Window *wins, w0, w1;
u_int nwins, i = 0;
XWindowAttributes winattr;
XSetWindowAttributes rootattr;
struct keybinding *kb;
sc->display = x_screenname(which);
sc->which = which;
sc->rootwin = RootWindow(G_dpy, which);
XAllocNamedColor(G_dpy, DefaultColormap(G_dpy, which),
"black", &sc->fgcolor, &tmp);
XAllocNamedColor(G_dpy, DefaultColormap(G_dpy, which),
"#00cc00", &sc->bgcolor, &tmp);
XAllocNamedColor(G_dpy,DefaultColormap(G_dpy, which),
"blue", &sc->fccolor, &tmp);
XAllocNamedColor(G_dpy, DefaultColormap(G_dpy, which),
"red", &sc->redcolor, &tmp);
XAllocNamedColor(G_dpy, DefaultColormap(G_dpy, which),
"#00ccc8", &sc->cyancolor, &tmp);
XAllocNamedColor(G_dpy, DefaultColormap(G_dpy, which),
"white", &sc->whitecolor, &tmp);
XAllocNamedColor(G_dpy, DefaultColormap(G_dpy, which),
"black", &sc->blackcolor, &tmp);
TAILQ_FOREACH(kb, &G_conf.keybindingq, entry)
xu_key_grab(sc->rootwin, kb->modmask, kb->keysym);
/* Special -- for alt state. */
/* xu_key_grab(sc->rootwin, 0, XK_Alt_L); */
/* xu_key_grab(sc->rootwin, 0, XK_Alt_R); */
sc->blackpixl = BlackPixel(G_dpy, sc->which);
sc->whitepixl = WhitePixel(G_dpy, sc->which);
sc->bluepixl = sc->fccolor.pixel;
sc->redpixl = sc->redcolor.pixel;
sc->cyanpixl = sc->cyancolor.pixel;
sc->gray = XCreatePixmapFromBitmapData(G_dpy, sc->rootwin,
gray_bits, gray_width, gray_height,
sc->blackpixl, sc->whitepixl, DefaultDepth(G_dpy, sc->which));
sc->blue = XCreatePixmapFromBitmapData(G_dpy, sc->rootwin,
gray_bits, gray_width, gray_height,
sc->bluepixl, sc->whitepixl, DefaultDepth(G_dpy, sc->which));
sc->red = XCreatePixmapFromBitmapData(G_dpy, sc->rootwin,
gray_bits, gray_width, gray_height,
sc->redpixl, sc->whitepixl, DefaultDepth(G_dpy, sc->which));
gv.foreground = sc->blackpixl^sc->whitepixl;
gv.background = sc->whitepixl;
gv.function = GXxor;
gv.line_width = 1;
gv.subwindow_mode = IncludeInferiors;
gv.font = G_font->fid;
sc->gc = XCreateGC(G_dpy, sc->rootwin,
GCForeground|GCBackground|GCFunction|
GCLineWidth|GCSubwindowMode|GCFont, &gv);
#ifdef notyet
gv2.foreground = sc->blackpixl^sc->cyanpixl;
gv2.background = sc->cyanpixl;
gv2.function = GXxor;
gv2.line_width = 1;
gv2.subwindow_mode = IncludeInferiors;
gv2.font = G_font->fid;
#endif
sc->hlgc = XCreateGC(G_dpy, sc->rootwin,
GCForeground|GCBackground|GCFunction|
GCLineWidth|GCSubwindowMode|GCFont, &gv);
gv1.function = GXinvert;
gv1.subwindow_mode = IncludeInferiors;
gv1.line_width = 1;
gv1.font = G_font->fid;
sc->invgc = XCreateGC(G_dpy, sc->rootwin,
GCFunction|GCSubwindowMode|GCLineWidth|GCFont, &gv1);
font_init(sc);
DefaultFont = font_getx(sc, DefaultFontName);
/*
* XXX - this should *really* be in screen_init(). ordering
* problem.
*/
TAILQ_INIT(&sc->mruq);
/* Initialize menu window. */
grab_menuinit(sc);
search_init(sc);
/* Deal with existing clients. */
XQueryTree(G_dpy, sc->rootwin, &w0, &w1, &wins, &nwins);
for (i = 0; i < nwins; i++) {
XGetWindowAttributes(G_dpy, wins[i], &winattr);
if (winattr.override_redirect ||
winattr.map_state != IsViewable) {
char *name;
XFetchName(G_dpy, wins[i], &name);
continue;
}
client_new(wins[i], sc, winattr.map_state != IsUnmapped);
}
XFree(wins);
G_curscreen = sc; /* XXX */
screen_init();
screen_updatestackingorder();
rootattr.event_mask = ChildMask|PropertyChangeMask|EnterWindowMask|
LeaveWindowMask|ColormapChangeMask|ButtonMask;
/* Set the root cursor to a nice obnoxious arrow :-) */
/* rootattr.cursor = cursor_bigarrow(sc); */
XChangeWindowAttributes(G_dpy, sc->rootwin,
/* CWCursor| */CWEventMask, &rootattr);
XSync(G_dpy, False);
return (0);
}
char *
x_screenname(int which)
{
char *cp, *dstr, *sn;
size_t snlen;
if (which > 9)
errx(1, "Can't handle more than 9 screens. If you need it, "
"tell <marius@monkey.org>. It's a trivial fix.");
dstr = xstrdup(DisplayString(G_dpy));
if ((cp = rindex(dstr, ':')) == NULL)
return (NULL);
if ((cp = index(cp, '.')) != NULL)
*cp = '\0';
snlen = strlen(dstr) + 3; /* string, dot, number, null */
sn = (char *)xmalloc(snlen);
snprintf(sn, snlen, "%s.%d", dstr, which);
free(dstr);
return (sn);
}
int
x_errorhandler(Display *dpy, XErrorEvent *e)
{
#ifdef DEBUG
{
char msg[80], number[80], req[80];
XGetErrorText(G_dpy, e->error_code, msg, sizeof(msg));
snprintf(number, sizeof(number), "%d", e->request_code);
XGetErrorDatabaseText(G_dpy, "XRequest", number,
"<unknown>", req, sizeof(req));
warnx("%s(0x%x): %s", req, (u_int)e->resourceid, msg);
}
#endif
if (G_starting &&
e->error_code == BadAccess &&
e->request_code == X_GrabKey)
errx(1, "root window unavailable - perhaps another "
"wm is running?");
x_teardown();
return (0);
}
static void
_sigchld_cb(int which)
dpy_init(const char *dpyname)
{
pid_t pid;
int status;
int i;
/* Collect dead children. */
while ((pid = waitpid(-1, &status, WNOHANG)) > 0 ||
(pid < 0 && errno == EINTR))
;
XSetErrorHandler(x_errorhandler);
if ((X_Dpy = XOpenDisplay(dpyname)) == NULL)
errx(1, "unable to open display \"%s\"",
XDisplayName(dpyname));
XSetErrorHandler(x_wmerrorhandler);
XSelectInput(X_Dpy, DefaultRootWindow(X_Dpy), SubstructureRedirectMask);
XSync(X_Dpy, False);
XSetErrorHandler(x_errorhandler);
HasRandr = XRRQueryExtension(X_Dpy, &Randr_ev, &i);
}
static void
x_setup(void)
{
struct screen_ctx *sc;
struct keybinding *kb;
int i;
Cursor_default = XCreateFontCursor(X_Dpy, XC_X_cursor);
Cursor_move = XCreateFontCursor(X_Dpy, XC_fleur);
Cursor_normal = XCreateFontCursor(X_Dpy, XC_left_ptr);
Cursor_question = XCreateFontCursor(X_Dpy, XC_question_arrow);
Cursor_resize = XCreateFontCursor(X_Dpy, XC_bottom_right_corner);
for (i = 0; i < ScreenCount(X_Dpy); i++) {
sc = xcalloc(1, sizeof(*sc));
x_setupscreen(sc, i);
TAILQ_INSERT_TAIL(&Screenq, sc, entry);
}
/*
* XXX key grabs weren't done before, since Screenq was empty,
* do them here for now (this needs changing).
*/
TAILQ_FOREACH(kb, &Conf.keybindingq, entry)
conf_grab(&Conf, kb);
}
static void
x_teardown(void)
{
struct screen_ctx *sc;
TAILQ_FOREACH(sc, &Screenq, entry)
XFreeGC(X_Dpy, sc->gc);
XCloseDisplay(X_Dpy);
}
static void
x_setupscreen(struct screen_ctx *sc, u_int which)
{
Window *wins, w0, w1;
XWindowAttributes winattr;
XSetWindowAttributes rootattr;
int fake;
u_int nwins, i;
sc->which = which;
sc->rootwin = RootWindow(X_Dpy, sc->which);
conf_gap(&Conf, sc);
screen_update_geometry(sc, DisplayWidth(X_Dpy, sc->which),
DisplayHeight(X_Dpy, sc->which));
conf_color(&Conf, sc);
group_init(sc);
conf_font(&Conf, sc);
TAILQ_INIT(&sc->mruq);
/* Initialize menu window. */
menu_init(sc);
xu_setwmname(sc);
rootattr.cursor = Cursor_normal;
rootattr.event_mask = CHILDMASK|PropertyChangeMask|EnterWindowMask|
LeaveWindowMask|ColormapChangeMask|BUTTONMASK;
XChangeWindowAttributes(X_Dpy, sc->rootwin,
CWEventMask|CWCursor, &rootattr);
/* Deal with existing clients. */
XQueryTree(X_Dpy, sc->rootwin, &w0, &w1, &wins, &nwins);
for (i = 0; i < nwins; i++) {
XGetWindowAttributes(X_Dpy, wins[i], &winattr);
if (winattr.override_redirect ||
winattr.map_state != IsViewable)
continue;
(void)client_new(wins[i], sc, winattr.map_state != IsUnmapped);
}
XFree(wins);
screen_updatestackingorder(sc);
if (XineramaQueryExtension(X_Dpy, &fake, &fake) == 1 &&
((HasXinerama = XineramaIsActive(X_Dpy)) == 1))
HasXinerama = 1;
if (HasRandr)
XRRSelectInput(X_Dpy, sc->rootwin, RRScreenChangeNotifyMask);
/*
* initial setup of xinerama screens, if we're using RandR then we'll
* redo this whenever the screen changes since a CTRC may have been
* added or removed
*/
screen_init_xinerama(sc);
XSync(X_Dpy, False);
}
static int
x_wmerrorhandler(Display *dpy, XErrorEvent *e)
{
errx(1, "root window unavailable - perhaps another wm is running?");
return (0);
}
static int
x_errorhandler(Display *dpy, XErrorEvent *e)
{
#if DEBUG
char msg[80], number[80], req[80];
XGetErrorText(X_Dpy, e->error_code, msg, sizeof(msg));
(void)snprintf(number, sizeof(number), "%d", e->request_code);
XGetErrorDatabaseText(X_Dpy, "XRequest", number,
"<unknown>", req, sizeof(req));
warnx("%s(0x%x): %s", req, (u_int)e->resourceid, msg);
#endif
return (0);
}
static void
sigchld_cb(int which)
{
pid_t pid;
int save_errno = errno;
int status;
/* Collect dead children. */
while ((pid = waitpid(-1, &status, WNOHANG)) > 0 ||
(pid < 0 && errno == EINTR))
;
errno = save_errno;
}
__dead void
usage(void)
{
extern char *__progname;
(void)fprintf(stderr, "usage: %s [-c file] [-d display]\n",
__progname);
exit(1);
}

832
calmwm.h
View File

@ -2,506 +2,518 @@
* calmwm - the calm window manager
*
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
* All rights reserved.
*
* $Id$
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $OpenBSD$
*/
#ifndef _CALMWM_H_
#define _CALMWM_H_
#define CALMWM_MAXNAMELEN 256
#include "hash.h"
#include <X11/Xatom.h>
#include <X11/Xft/Xft.h>
#include <X11/Xlib.h>
#include <X11/Xproto.h>
#include <X11/Xutil.h>
#include <X11/cursorfont.h>
#include <X11/extensions/Xinerama.h>
#include <X11/extensions/Xrandr.h>
#include <X11/keysym.h>
#undef MIN
#undef MAX
#define MIN(x, y) ((x) < (y) ? (x) : (y))
#define MAX(x, y) ((x) > (y) ? (x) : (y))
enum conftype {
CONF_BWIDTH, CONF_IGNORE, CONF_NOTIFIER,
#ifndef nitems
#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
#endif
#define CONFFILE ".cwmrc"
#define WMNAME "CWM"
#define CHILDMASK (SubstructureRedirectMask|SubstructureNotifyMask)
#define BUTTONMASK (ButtonPressMask|ButtonReleaseMask)
#define MOUSEMASK (BUTTONMASK|PointerMotionMask)
#define KEYMASK (KeyPressMask|ExposureMask)
#define MENUMASK (BUTTONMASK|ButtonMotionMask|ExposureMask| \
PointerMotionMask)
#define MENUGRABMASK (BUTTONMASK|ButtonMotionMask|StructureNotifyMask|\
PointerMotionMask)
#define SEARCHMASK (KeyPressMask|ExposureMask)
/* kb movement */
#define CWM_MOVE 0x0001
#define CWM_RESIZE 0x0002
#define CWM_PTRMOVE 0x0004
#define CWM_BIGMOVE 0x0008
#define CWM_UP 0x0010
#define CWM_DOWN 0x0020
#define CWM_LEFT 0x0040
#define CWM_RIGHT 0x0080
/* exec */
#define CWM_EXEC_PROGRAM 0x0001
#define CWM_EXEC_WM 0x0002
/* cycle */
#define CWM_CYCLE 0x0001
#define CWM_RCYCLE 0x0002
#define CWM_INGROUP 0x0004
#define KBTOGROUP(X) ((X) - 1)
union arg {
char *c;
int i;
};
#define ChildMask (SubstructureRedirectMask|SubstructureNotifyMask)
#define ButtonMask (ButtonPressMask|ButtonReleaseMask)
#define MouseMask (ButtonMask|PointerMotionMask)
struct client_ctx;
TAILQ_HEAD(cycle_entry_q, client_ctx);
/* #define CYCLE_FOREACH_MRU(cy, ctx) TAILQ_FOREACH((ctx), */
struct screen_ctx;
struct fontdesc {
const char *name;
XftFont *fn;
struct screen_ctx *sc;
HASH_ENTRY(fontdesc) node;
enum cwmcolor {
CWM_COLOR_BORDER_ACTIVE,
CWM_COLOR_BORDER_INACTIVE,
CWM_COLOR_BORDER_GROUP,
CWM_COLOR_BORDER_UNGROUP,
CWM_COLOR_FG_MENU,
CWM_COLOR_BG_MENU,
CWM_COLOR_FONT,
CWM_COLOR_MAX
};
int fontdesc_cmp(struct fontdesc *a, struct fontdesc *b);
HASH_HEAD(fonthash, fontdesc, 16);
HASH_PROTOTYPE(fonthash, fontdesc, node, fontdesc_cmp);
struct screen_ctx {
TAILQ_ENTRY(screen_ctx) entry;
u_int which;
Window rootwin;
Window menuwin;
Window searchwin;
Window groupwin;
Window infowin;
Colormap colormap;
GC invcg;
XColor bgcolor, fgcolor, fccolor, redcolor, cyancolor,
whitecolor, blackcolor;
char *display;
unsigned long blackpixl, whitepixl, redpixl, bluepixl, cyanpixl;
GC gc, invgc, hlgc;
Pixmap gray, blue, red;
int altpersist;
FILE *notifier;
struct cycle_entry_q mruq;
struct client_ctx* cycle_client;
struct fonthash fonthash;
XftDraw *xftdraw;
XftColor xftcolor;
struct color {
char *name;
unsigned long pixel;
};
TAILQ_HEAD(screen_ctx_q, screen_ctx);
#define CLIENT_PROTO_DELETE 0x01
#define CLIENT_PROTO_TAKEFOCUS 0x02
#define CLIENT_MAXNAMEQLEN 5
#define CLIENT_HIDDEN 0x01
#define CLIENT_IGNORE 0x02
#define CLIENT_INQUEUE 0x04 /* tmp used by search code */
#define CLIENT_MAXIMIZED 0x08
#define CLIENT_HIGHLIGHT_BLUE 1
#define CLIENT_HIGHLIGHT_RED 2
struct gap {
int top;
int bottom;
int left;
int right;
};
struct winname {
TAILQ_ENTRY(winname) entry;
char *name;
TAILQ_ENTRY(winname) entry;
char *name;
};
TAILQ_HEAD(winname_q, winname);
struct client_ctx {
TAILQ_ENTRY(client_ctx) entry;
TAILQ_ENTRY(client_ctx) searchentry;
TAILQ_ENTRY(client_ctx) group_entry;
TAILQ_ENTRY(client_ctx) mru_entry;
struct screen_ctx *sc;
Window win;
XSizeHints *size;
Colormap cmap;
Window pwin;
u_int bwidth;
Colormap cmap;
u_int bwidth; /* border width */
struct {
int x, y, width, height;
int min_dx, min_dy;
int x; /* x position */
int y; /* y position */
int width; /* width */
int height;/* height */
} geom, savegeom;
struct {
int x,y;
int basew; /* desired width */
int baseh; /* desired height */
int minw; /* minimum width */
int minh; /* minimum height */
int maxw; /* maximum width */
int maxh; /* maximum height */
int incw; /* width increment progression */
int inch; /* height increment progression */
float mina; /* minimum aspect ratio */
float maxa; /* maximum aspect ratio */
} hint;
struct {
int x; /* x position */
int y; /* y position */
} ptr;
int beepbeep;
#define CLIENT_PROTO_DELETE 0x0001
#define CLIENT_PROTO_TAKEFOCUS 0x0002
int xproto;
#define CLIENT_HIDDEN 0x0001
#define CLIENT_IGNORE 0x0002
#define CLIENT_VMAXIMIZED 0x0004
#define CLIENT_HMAXIMIZED 0x0008
#define CLIENT_FREEZE 0x0010
#define CLIENT_MAXFLAGS (CLIENT_VMAXIMIZED | CLIENT_HMAXIMIZED)
#define CLIENT_MAXIMIZED (CLIENT_VMAXIMIZED | CLIENT_HMAXIMIZED)
int flags;
int state;
char *name;
struct winname_q nameq;
size_t nameqlen;
char *label;
int active;
int stackingorder;
#define CLIENT_HIGHLIGHT_GROUP 0x0001
#define CLIENT_HIGHLIGHT_UNGROUP 0x0002
int highlight;
struct winname_q nameq;
#define CLIENT_MAXNAMEQLEN 5
int nameqlen;
char *name;
char *label;
char *matchname;
struct group_ctx *group;
int groupcommit;
int stackingorder;
char *app_class;
char *app_name;
char *app_cliarg;
struct group_ctx *group;
char *app_class;
char *app_name;
};
TAILQ_HEAD(client_ctx_q, client_ctx);
TAILQ_HEAD(cycle_entry_q, client_ctx);
struct winmatch {
TAILQ_ENTRY(winmatch) entry;
#define WIN_MAXTITLELEN 256
char title[WIN_MAXTITLELEN];
};
TAILQ_HEAD(winmatch_q, winmatch);
struct group_ctx {
TAILQ_ENTRY(group_ctx) entry;
struct client_ctx_q clients;
char *name;
int shortcut;
int hidden;
int nhidden;
int highstack;
};
TAILQ_ENTRY(group_ctx) entry;
struct client_ctx_q clients;
int shortcut;
int hidden;
int nhidden;
int highstack;
};
TAILQ_HEAD(group_ctx_q, group_ctx);
/* Autogroups */
struct autogroupwin {
TAILQ_ENTRY(autogroupwin) entry;
char *class;
char *name;
char *group;
TAILQ_ENTRY(autogroupwin) entry;
char *class;
char *name;
int num;
};
TAILQ_HEAD(autogroupwin_q, autogroupwin);
/* NULL/0 values indicate match any. */
struct xevent {
TAILQ_ENTRY(xevent) entry;
Window *xev_win;
Window *xev_root;
int xev_type;
void (*xev_cb)(struct xevent *, XEvent *);
void *xev_arg;
struct screen_ctx {
TAILQ_ENTRY(screen_ctx) entry;
u_int which;
Window rootwin;
Window menuwin;
struct color color[CWM_COLOR_MAX];
GC gc;
int altpersist;
int xmax;
int ymax;
struct gap gap;
struct cycle_entry_q mruq;
XftColor xftcolor;
XftDraw *xftdraw;
XftFont *font;
int xinerama_no;
XineramaScreenInfo *xinerama;
#define CALMWM_NGROUPS 9
struct group_ctx groups[CALMWM_NGROUPS];
struct group_ctx_q groupq;
int group_hideall;
int group_nonames;
struct group_ctx *group_active;
char **group_names;
};
TAILQ_HEAD(xevent_q, xevent);
/* Keybindings */
enum kbtype {
KB_DELETE, KB_NEWTERM0, KB_NEWTERM1, KB_HIDE,
KB_LOWER, KB_RAISE, KB_SEARCH, KB_CYCLE, KB_LABEL,
KB_GROUPSELECT, KB_VERTMAXIMIZE,
/* Group numbers need to be in order. */
KB_GROUP_1, KB_GROUP_2, KB_GROUP_3, KB_GROUP_4, KB_GROUP_5,
KB_GROUP_6, KB_GROUP_7, KB_GROUP_8, KB_GROUP_9, KB_NOGROUP,
KB_NEXTGROUP, KB_PREVGROUP,
KB_MOVE_WEST, KB_MOVE_EAST, KB_MOVE_NORTH, KB_MOVE_SOUTH,
KB__LAST
};
#define KBFLAG_NEEDCLIENT 0x01
#define KBFLAG_FINDCLIENT 0x02
#define KBTOGROUP(X) ((X) - 1)
TAILQ_HEAD(screen_ctx_q, screen_ctx);
struct keybinding {
int modmask;
int keysym;
int keycode;
int flags;
void (*callback)(struct client_ctx *, void *);
void *argument;
TAILQ_ENTRY(keybinding) entry;
TAILQ_ENTRY(keybinding) entry;
void (*callback)(struct client_ctx *, union arg *);
union arg argument;
int modmask;
int keysym;
int keycode;
#define KBFLAG_NEEDCLIENT 0x0001
int flags;
};
TAILQ_HEAD(keybinding_q, keybinding);
struct mousebinding {
TAILQ_ENTRY(mousebinding) entry;
void (*callback)(struct client_ctx *, void *);
int modmask;
int button;
#define MOUSEBIND_CTX_ROOT 0x0001
#define MOUSEBIND_CTX_WIN 0x0002
int context;
};
TAILQ_HEAD(mousebinding_q, mousebinding);
struct cmd {
TAILQ_ENTRY(cmd) entry;
int flags;
#define CMD_STATIC 0x01 /* static configuration in conf.c */
char image[MAXPATHLEN];
char label[256];
/* (argv) */
TAILQ_ENTRY(cmd) entry;
int flags;
char image[MAXPATHLEN];
#define CMD_MAXLABELLEN 256
char label[CMD_MAXLABELLEN];
};
TAILQ_HEAD(keybinding_q, keybinding);
TAILQ_HEAD(cmd_q, cmd);
/* Global configuration */
struct conf {
struct keybinding_q keybindingq;
struct autogroupwin_q autogroupq;
char menu_path[MAXPATHLEN];
struct cmd_q cmdq;
int flags;
#define CONF_STICKY_GROUPS 0x0001
char termpath[MAXPATHLEN];
char lockpath[MAXPATHLEN];
};
/* Menu stuff */
#define MENU_MAXENTRY 50
struct menu {
TAILQ_ENTRY(menu) entry;
TAILQ_ENTRY(menu) resultentry;
char text[MENU_MAXENTRY + 1];
char print[MENU_MAXENTRY + 1];
void *ctx;
short lasthit;
TAILQ_ENTRY(menu) entry;
TAILQ_ENTRY(menu) resultentry;
#define MENU_MAXENTRY 50
char text[MENU_MAXENTRY + 1];
char print[MENU_MAXENTRY + 1];
void *ctx;
short dummy;
short abort;
};
TAILQ_HEAD(menu_q, menu);
enum ctltype {
CTL_NONE = -1,
CTL_ERASEONE = 0, CTL_WIPE, CTL_UP, CTL_DOWN, CTL_RETURN,
CTL_ABORT, CTL_ALL
struct conf {
struct keybinding_q keybindingq;
struct autogroupwin_q autogroupq;
struct winmatch_q ignoreq;
char conf_path[MAXPATHLEN];
struct cmd_q cmdq;
struct mousebinding_q mousebindingq;
#define CONF_STICKY_GROUPS 0x0001
int flags;
#define CONF_BWIDTH 1
int bwidth;
#define CONF_MAMOUNT 1
int mamount;
#define CONF_SNAPDIST 0
int snapdist;
struct gap gap;
struct color color[CWM_COLOR_MAX];
char termpath[MAXPATHLEN];
char lockpath[MAXPATHLEN];
#define CONF_FONT "sans-serif:pixelsize=14:bold"
char *font;
};
/* MWM hints */
struct mwm_hints {
u_long flags;
u_long functions;
u_long decorations;
u_long flags;
u_long functions;
u_long decorations;
};
#define MWM_NUMHINTS 3
#define PROP_MWM_HINTS_ELEMENTS 3
#define MWM_HINTS_DECORATIONS (1<<1)
#define MWM_DECOR_ALL (1<<0)
#define MWM_DECOR_BORDER (1<<1)
#define MWM_NUMHINTS 3
__dead void usage(void);
#define PROP_MWM_HINTS_ELEMENTS 3
#define MWM_HINTS_DECORATIONS (1 << 1)
#define MWM_DECOR_ALL (1 << 0)
#define MWM_DECOR_BORDER (1 << 1)
void client_applysizehints(struct client_ctx *);
struct client_ctx *client_current(void);
void client_cycle(struct screen_ctx *, int);
void client_delete(struct client_ctx *);
void client_draw_border(struct client_ctx *);
struct client_ctx *client_find(Window);
void client_freeze(struct client_ctx *);
void client_getsizehints(struct client_ctx *);
void client_hide(struct client_ctx *);
void client_horizmaximize(struct client_ctx *);
void client_leave(struct client_ctx *);
void client_lower(struct client_ctx *);
void client_map(struct client_ctx *);
void client_maximize(struct client_ctx *);
void client_move(struct client_ctx *);
void client_mtf(struct client_ctx *);
struct client_ctx *client_new(Window, struct screen_ctx *, int);
void client_ptrsave(struct client_ctx *);
void client_ptrwarp(struct client_ctx *);
void client_raise(struct client_ctx *);
void client_resize(struct client_ctx *);
void client_send_delete(struct client_ctx *);
void client_setactive(struct client_ctx *, int);
void client_setname(struct client_ctx *);
int client_snapcalc(int, int, int, int, int);
void client_transient(struct client_ctx *);
void client_unhide(struct client_ctx *);
void client_vertmaximize(struct client_ctx *);
void client_warp(struct client_ctx *);
int input_keycodetrans(KeyCode, u_int, enum ctltype *, char *, int);
void group_alltoggle(struct screen_ctx *);
void group_autogroup(struct client_ctx *);
void group_client_delete(struct client_ctx *);
void group_cycle(struct screen_ctx *, int);
void group_hidetoggle(struct screen_ctx *, int);
void group_init(struct screen_ctx *);
void group_make_autogroup(struct conf *, char *, int);
void group_menu(XButtonEvent *);
void group_movetogroup(struct client_ctx *, int);
void group_only(struct screen_ctx *, int);
void group_sticky(struct client_ctx *);
void group_sticky_toggle_enter(struct client_ctx *);
void group_sticky_toggle_exit(struct client_ctx *);
void group_update_names(struct screen_ctx *);
int x_errorhandler(Display *, XErrorEvent *);
void x_setup(void);
char *x_screenname(int);
void x_loop(void);
int x_setupscreen(struct screen_ctx *, u_int);
void search_match_client(struct menu_q *, struct menu_q *,
char *);
void search_match_exec(struct menu_q *, struct menu_q *,
char *);
void search_match_text(struct menu_q *, struct menu_q *,
char *);
void search_print_client(struct menu *, int);
struct client_ctx *client_find(Window);
void client_setup(void);
struct client_ctx *client_new(Window, struct screen_ctx *, int);
int client_delete(struct client_ctx *, int, int);
void client_setactive(struct client_ctx *, int);
void client_gravitate(struct client_ctx *, int);
void client_resize(struct client_ctx *);
void client_lower(struct client_ctx *);
void client_raise(struct client_ctx *);
void client_move(struct client_ctx *);
void client_leave(struct client_ctx *);
void client_send_delete(struct client_ctx *);
struct client_ctx *client_current(void);
void client_hide(struct client_ctx *);
void client_unhide(struct client_ctx *);
void client_nocurrent(void);
void client_setname(struct client_ctx *);
void client_warp(struct client_ctx *);
void client_ptrwarp(struct client_ctx *);
void client_ptrsave(struct client_ctx *);
void client_draw_border(struct client_ctx *);
void client_update(struct client_ctx *);
void client_cycle(struct client_ctx *);
void client_placecalc(struct client_ctx *);
void client_maximize(struct client_ctx *);
void client_vertmaximize(struct client_ctx *);
u_long client_bg_pixel(struct client_ctx *);
Pixmap client_bg_pixmap(struct client_ctx *);
void client_map(struct client_ctx *cc);
void client_mtf(struct client_ctx *cc);
struct client_ctx *client_cyclenext(struct client_ctx *cc, int reverse);
void client_cycleinfo(struct client_ctx *cc);
void client_altrelease();
struct client_ctx *client_mrunext(struct client_ctx *cc);
struct client_ctx *client_mruprev(struct client_ctx *cc);
void client_gethints(struct client_ctx *cc);
void client_freehints(struct client_ctx *cc);
XineramaScreenInfo *screen_find_xinerama(struct screen_ctx *, int, int);
struct screen_ctx *screen_fromroot(Window);
void screen_init_xinerama(struct screen_ctx *);
void screen_update_geometry(struct screen_ctx *, int, int);
void screen_updatestackingorder(struct screen_ctx *);
void xev_handle_maprequest(struct xevent *, XEvent *);
void xev_handle_unmapnotify(struct xevent *, XEvent *);
void xev_handle_destroynotify(struct xevent *, XEvent *);
void xev_handle_configurerequest(struct xevent *, XEvent *);
void xev_handle_propertynotify(struct xevent *, XEvent *);
void xev_handle_enternotify(struct xevent *, XEvent *);
void xev_handle_leavenotify(struct xevent *, XEvent *);
void xev_handle_buttonpress(struct xevent *, XEvent *);
void xev_handle_buttonrelease(struct xevent *, XEvent *);
void xev_handle_keypress(struct xevent *, XEvent *);
void xev_handle_keyrelease(struct xevent *, XEvent *);
void xev_handle_expose(struct xevent *, XEvent *);
void xev_handle_clientmessage(struct xevent *, XEvent *);
void kbfunc_client_cycle(struct client_ctx *, union arg *);
void kbfunc_client_cyclegroup(struct client_ctx *,
union arg *);
void kbfunc_client_delete(struct client_ctx *, union arg *);
void kbfunc_client_freeze(struct client_ctx *, union arg *);
void kbfunc_client_group(struct client_ctx *, union arg *);
void kbfunc_client_grouponly(struct client_ctx *,
union arg *);
void kbfunc_client_grouptoggle(struct client_ctx *,
union arg *);
void kbfunc_client_hide(struct client_ctx *, union arg *);
void kbfunc_client_hmaximize(struct client_ctx *,
union arg *);
void kbfunc_client_label(struct client_ctx *, union arg *);
void kbfunc_client_lower(struct client_ctx *, union arg *);
void kbfunc_client_maximize(struct client_ctx *,
union arg *);
void kbfunc_client_movetogroup(struct client_ctx *,
union arg *);
void kbfunc_client_nogroup(struct client_ctx *,
union arg *);
void kbfunc_client_raise(struct client_ctx *, union arg *);
void kbfunc_client_rcycle(struct client_ctx *, union arg *);
void kbfunc_client_search(struct client_ctx *, union arg *);
void kbfunc_client_vmaximize(struct client_ctx *,
union arg *);
void kbfunc_cmdexec(struct client_ctx *, union arg *);
void kbfunc_exec(struct client_ctx *, union arg *);
void kbfunc_lock(struct client_ctx *, union arg *);
void kbfunc_menu_search(struct client_ctx *, union arg *);
void kbfunc_moveresize(struct client_ctx *, union arg *);
void kbfunc_quit_wm(struct client_ctx *, union arg *);
void kbfunc_reload(struct client_ctx *, union arg *);
void kbfunc_ssh(struct client_ctx *, union arg *);
void kbfunc_term(struct client_ctx *, union arg *);
#define XEV_QUICK(a, b, c, d, e) do { \
xev_register(xev_new(a, b, c, d, e)); \
} while (0)
void mousefunc_menu_cmd(struct client_ctx *, void *);
void mousefunc_menu_group(struct client_ctx *, void *);
void mousefunc_menu_unhide(struct client_ctx *, void *);
void mousefunc_window_grouptoggle(struct client_ctx *,
void *);
void mousefunc_window_hide(struct client_ctx *, void *);
void mousefunc_window_lower(struct client_ctx *, void *);
void mousefunc_window_move(struct client_ctx *, void *);
void mousefunc_window_raise(struct client_ctx *, void *);
void mousefunc_window_resize(struct client_ctx *, void *);
void xev_reconfig(struct client_ctx *); /* XXX should be xu_ */
struct menu *menu_filter(struct screen_ctx *, struct menu_q *,
char *, char *, int,
void (*)(struct menu_q *, struct menu_q *, char *),
void (*)(struct menu *, int));
void menu_init(struct screen_ctx *);
void xev_init(void);
struct xevent *xev_new(Window *, Window *, int, void (*)(struct xevent *, XEvent *), void *);
void xev_register(struct xevent *);
void xev_loop(void);
int parse_config(const char *, struct conf *);
int xu_ptr_grab(Window, int, Cursor);
int xu_btn_grab(Window, int, u_int);
int xu_ptr_regrab(int, Cursor);
void xu_btn_ungrab(Window, int, u_int);
void xu_ptr_ungrab(void);
void xu_ptr_setpos(Window, int, int);
void xu_ptr_getpos(Window, int *, int *);
void xu_key_grab(Window, int, int);
void xu_sendmsg(struct client_ctx *, Atom, long);
int xu_getprop(struct client_ctx *, Atom, Atom, long, u_char **);
char *xu_getstrprop(struct client_ctx *, Atom atm);
void xu_setstate(struct client_ctx *, int);
int xu_getstate(struct client_ctx *, int *);
void xu_key_grab_keycode(Window, int, int);
void conf_bindname(struct conf *, char *, char *);
void conf_clear(struct conf *);
void conf_client(struct client_ctx *);
void conf_cmd_add(struct conf *, char *, char *, int);
void conf_color(struct conf *, struct screen_ctx *);
void conf_font(struct conf *, struct screen_ctx *);
void conf_gap(struct conf *, struct screen_ctx *);
void conf_grab(struct conf *, struct keybinding *);
void conf_grab_mouse(struct client_ctx *);
void conf_init(struct conf *);
void conf_mousebind(struct conf *, char *, char *);
void conf_reload(struct conf *);
void conf_setup(struct conf *, const char *);
void conf_ungrab(struct conf *, struct keybinding *);
int dirent_exists(char *);
int dirent_isdir(char *);
int dirent_islink(char *);
int u_spawn(char *);
int font_ascent(struct screen_ctx *);
int font_descent(struct screen_ctx *);
void font_draw(struct screen_ctx *, const char *, int,
Drawable, int, int);
u_int font_height(struct screen_ctx *);
void font_init(struct screen_ctx *, const char *);
int font_width(struct screen_ctx *, const char *, int);
XftFont *font_make(struct screen_ctx *, const char *);
int grab_sweep(struct client_ctx *);
int grab_drag(struct client_ctx *);
void grab_menuinit(struct screen_ctx *);
void *grab_menu(XButtonEvent *, struct menu_q *);
void grab_label(struct client_ctx *);
void xev_loop(void);
void xfree(void *);
void *xmalloc(size_t);
void *xcalloc(size_t);
char *xstrdup(const char *);
void xu_btn_grab(Window, int, u_int);
void xu_btn_ungrab(Window, int, u_int);
void xu_configure(struct client_ctx *);
void xu_freecolor(struct screen_ctx *, unsigned long);
void xu_getatoms(void);
unsigned long xu_getcolor(struct screen_ctx *, char *);
int xu_getprop(Window, Atom, Atom, long, u_char **);
int xu_getstate(struct client_ctx *, int *);
int xu_getstrprop(Window, Atom, char **);
void xu_key_grab(Window, int, int);
void xu_key_ungrab(Window, int, int);
void xu_ptr_getpos(Window, int *, int *);
int xu_ptr_grab(Window, int, Cursor);
int xu_ptr_regrab(int, Cursor);
void xu_ptr_setpos(Window, int, int);
void xu_ptr_ungrab(void);
void xu_sendmsg(Window, Atom, long);
void xu_setstate(struct client_ctx *, int);
void xu_setwmname(struct screen_ctx *);
#define XMALLOC(p, t) ((p) = (t *)xmalloc(sizeof * (p)))
#define XCALLOC(p, t) ((p) = (t *)xcalloc(sizeof * (p)))
void u_exec(char *);
void u_spawn(char *);
void screen_init(void);
struct screen_ctx *screen_fromroot(Window);
struct screen_ctx *screen_current(void);
void screen_updatestackingorder(void);
void screen_infomsg(char *);
void conf_setup(struct conf *);
int conf_get_int(struct client_ctx *, enum conftype);
void conf_client(struct client_ctx *);
void conf_bindkey(struct conf *, void (*)(struct client_ctx *, void *),
int, int, int, void *);
void conf_parsekeys(struct conf *, char *);
void conf_parsesettings(struct conf *, char *);
void conf_parseignores(struct conf *, char *);
void conf_parseautogroups(struct conf *, char *);
void conf_cmd_clear(struct conf *);
int conf_cmd_changed(char *);
void conf_cmd_populate(struct conf *, char *);
void conf_cmd_refresh(struct conf *c);
char *conf_get_str(struct client_ctx *, enum conftype);
void kbfunc_client_lower(struct client_ctx *, void *);
void kbfunc_client_raise(struct client_ctx *, void *);
void kbfunc_client_search(struct client_ctx *, void *);
void kbfunc_client_hide(struct client_ctx *, void *);
void kbfunc_client_cycle(struct client_ctx *, void *);
void kbfunc_client_rcycle(struct client_ctx *cc, void *arg);
void kbfunc_cmdexec(struct client_ctx *, void *);
void kbfunc_client_label(struct client_ctx *, void *);
void kbfunc_client_delete(struct client_ctx *, void *);
void kbfunc_client_groupselect(struct client_ctx *, void *);
void kbfunc_client_group(struct client_ctx *, void *);
void kbfunc_client_nextgroup(struct client_ctx *, void *);
void kbfunc_client_prevgroup(struct client_ctx *, void *);
void kbfunc_client_nogroup(struct client_ctx *, void *);
void kbfunc_client_maximize(struct client_ctx *, void *);
void kbfunc_client_vmaximize(struct client_ctx *, void *);
void kbfunc_menu_search(struct client_ctx *, void *);
void kbfunc_term(struct client_ctx *cc, void *arg);
void kbfunc_lock(struct client_ctx *cc, void *arg);
void draw_outline(struct client_ctx *);
void search_init(struct screen_ctx *);
struct menu *search_start(struct menu_q *menuq,
void (*match)(struct menu_q *, struct menu_q *, char *),
void (*rank)(struct menu_q *, char *),
void (*print)(struct menu *mi, int),
char *);
void search_match_client(struct menu_q *, struct menu_q *, char *);
void search_print_client(struct menu *mi, int list);
void search_match_text(struct menu_q *, struct menu_q *, char *);
void search_rank_text(struct menu_q *, char *);
void group_init(void);
int group_new(void);
int group_select(int);
void group_enter(void);
void group_exit(int);
void group_click(struct client_ctx *);
void group_display_init(struct screen_ctx *);
void group_display_draw(struct screen_ctx *);
void group_display_keypress(KeyCode);
void group_hidetoggle(int);
void group_slide(int);
void group_sticky(struct client_ctx *);
void group_client_delete(struct client_ctx *);
void group_menu(XButtonEvent *);
void group_namemode(void);
void group_alltoggle(void);
void group_deletecurrent(void);
void group_done(void);
void group_sticky_toggle_enter(struct client_ctx *);
void group_sticky_toggle_exit(struct client_ctx *);
void group_autogroup(struct client_ctx *);
void notification_init(struct screen_ctx *);
struct client_ctx *geographic_west(struct client_ctx *);
Cursor cursor_bigarrow();
void font_init(struct screen_ctx *sc);
struct fontdesc *font_get(struct screen_ctx *sc, const char *name);
int font_width(struct fontdesc *fdp, const char *text, int len);
void font_draw(struct fontdesc *fdp, const char *text, int len,
Drawable d, int x, int y);
int font_ascent(struct fontdesc *fdp);
int font_descent(struct fontdesc *fdp);
struct fontdesc *font_getx(struct screen_ctx *sc, const char *name);
#define CCTOSC(cc) (cc->sc)
void *xcalloc(size_t, size_t);
void xfree(void *);
void *xmalloc(size_t);
char *xstrdup(const char *);
/* Externs */
extern Display *X_Dpy;
extern Display *G_dpy;
extern XFontStruct *G_font;
extern Cursor Cursor_default;
extern Cursor Cursor_move;
extern Cursor Cursor_normal;
extern Cursor Cursor_question;
extern Cursor Cursor_resize;
extern Cursor G_cursor_move;
extern Cursor G_cursor_resize;
extern Cursor G_cursor_select;
extern Cursor G_cursor_default;
extern Cursor G_cursor_question;
extern struct screen_ctx_q Screenq;
extern struct client_ctx_q Clientq;
extern struct conf Conf;
extern struct screen_ctx_q G_screenq;
extern struct screen_ctx *G_curscreen;
extern u_int G_nscreens;
extern int HasXinerama, HasRandr, Randr_ev;
extern struct client_ctx_q G_clientq;
extern int G_doshape, G_shape_ev;
extern struct conf G_conf;
extern int G_groupmode;
extern struct fontdesc *DefaultFont;
#define WM_STATE cwm_atoms[0]
#define WM_DELETE_WINDOW cwm_atoms[1]
#define WM_TAKE_FOCUS cwm_atoms[2]
#define WM_PROTOCOLS cwm_atoms[3]
#define _MOTIF_WM_HINTS cwm_atoms[4]
#define UTF8_STRING cwm_atoms[5]
/*
* please make all hints below this point netwm hints, starting with
* _NET_SUPPORTED. If you change other hints make sure you update
* CWM_NETWM_START
*/
#define _NET_SUPPORTED cwm_atoms[6]
#define _NET_SUPPORTING_WM_CHECK cwm_atoms[7]
#define _NET_WM_NAME cwm_atoms[8]
#define _NET_ACTIVE_WINDOW cwm_atoms[9]
#define _NET_CLIENT_LIST cwm_atoms[10]
#define _NET_NUMBER_OF_DESKTOPS cwm_atoms[11]
#define _NET_CURRENT_DESKTOP cwm_atoms[12]
#define _NET_DESKTOP_VIEWPORT cwm_atoms[13]
#define _NET_DESKTOP_GEOMETRY cwm_atoms[14]
#define _NET_VIRTUAL_ROOTS cwm_atoms[15]
#define _NET_SHOWING_DESKTOP cwm_atoms[16]
#define _NET_DESKTOP_NAMES cwm_atoms[17]
#define _NET_WM_DESKTOP cwm_atoms[18]
#define _NET_WORKAREA cwm_atoms[19]
#define CWM_NO_ATOMS 20
#define CWM_NETWM_START 6
extern Atom cwm_atoms[CWM_NO_ATOMS];
#endif /* _CALMWM_H_ */

1126
client.c

File diff suppressed because it is too large Load Diff

View File

@ -1,508 +0,0 @@
/* $OpenBSD$ */
/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */
/*
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)queue.h 8.5 (Berkeley) 8/20/94
*/
#ifndef _SYS_QUEUE_H_
#define _SYS_QUEUE_H_
/*
* This file defines five types of data structures: singly-linked lists,
* lists, simple queues, tail queues, and circular queues.
*
*
* A singly-linked list is headed by a single forward pointer. The elements
* are singly linked for minimum space and pointer manipulation overhead at
* the expense of O(n) removal for arbitrary elements. New elements can be
* added to the list after an existing element or at the head of the list.
* Elements being removed from the head of the list should use the explicit
* macro for this purpose for optimum efficiency. A singly-linked list may
* only be traversed in the forward direction. Singly-linked lists are ideal
* for applications with large datasets and few or no removals or for
* implementing a LIFO queue.
*
* A list is headed by a single forward pointer (or an array of forward
* pointers for a hash table header). The elements are doubly linked
* so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before
* or after an existing element or at the head of the list. A list
* may only be traversed in the forward direction.
*
* A simple queue is headed by a pair of pointers, one the head of the
* list and the other to the tail of the list. The elements are singly
* linked to save space, so elements can only be removed from the
* head of the list. New elements can be added to the list before or after
* an existing element, at the head of the list, or at the end of the
* list. A simple queue may only be traversed in the forward direction.
*
* A tail queue is headed by a pair of pointers, one to the head of the
* list and the other to the tail of the list. The elements are doubly
* linked so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before or
* after an existing element, at the head of the list, or at the end of
* the list. A tail queue may be traversed in either direction.
*
* A circle queue is headed by a pair of pointers, one to the head of the
* list and the other to the tail of the list. The elements are doubly
* linked so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before or after
* an existing element, at the head of the list, or at the end of the list.
* A circle queue may be traversed in either direction, but has a more
* complex end of list detection.
*
* For details on the use of these macros, see the queue(3) manual page.
*/
/*
* Singly-linked List definitions.
*/
#define SLIST_HEAD(name, type) \
struct name { \
struct type *slh_first; /* first element */ \
}
#define SLIST_HEAD_INITIALIZER(head) \
{ NULL }
#define SLIST_ENTRY(type) \
struct { \
struct type *sle_next; /* next element */ \
}
/*
* Singly-linked List access methods.
*/
#define SLIST_FIRST(head) ((head)->slh_first)
#define SLIST_END(head) NULL
#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head))
#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
#define SLIST_FOREACH(var, head, field) \
for((var) = SLIST_FIRST(head); \
(var) != SLIST_END(head); \
(var) = SLIST_NEXT(var, field))
#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \
for ((varp) = &SLIST_FIRST((head)); \
((var) = *(varp)) != SLIST_END(head); \
(varp) = &SLIST_NEXT((var), field))
/*
* Singly-linked List functions.
*/
#define SLIST_INIT(head) { \
SLIST_FIRST(head) = SLIST_END(head); \
}
#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
(elm)->field.sle_next = (slistelm)->field.sle_next; \
(slistelm)->field.sle_next = (elm); \
} while (0)
#define SLIST_INSERT_HEAD(head, elm, field) do { \
(elm)->field.sle_next = (head)->slh_first; \
(head)->slh_first = (elm); \
} while (0)
#define SLIST_REMOVE_NEXT(head, elm, field) do { \
(elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \
} while (0)
#define SLIST_REMOVE_HEAD(head, field) do { \
(head)->slh_first = (head)->slh_first->field.sle_next; \
} while (0)
#define SLIST_REMOVE(head, elm, type, field) do { \
if ((head)->slh_first == (elm)) { \
SLIST_REMOVE_HEAD((head), field); \
} \
else { \
struct type *curelm = (head)->slh_first; \
while( curelm->field.sle_next != (elm) ) \
curelm = curelm->field.sle_next; \
curelm->field.sle_next = \
curelm->field.sle_next->field.sle_next; \
} \
} while (0)
/*
* List definitions.
*/
#define LIST_HEAD(name, type) \
struct name { \
struct type *lh_first; /* first element */ \
}
#define LIST_HEAD_INITIALIZER(head) \
{ NULL }
#define LIST_ENTRY(type) \
struct { \
struct type *le_next; /* next element */ \
struct type **le_prev; /* address of previous next element */ \
}
/*
* List access methods
*/
#define LIST_FIRST(head) ((head)->lh_first)
#define LIST_END(head) NULL
#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head))
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
#define LIST_FOREACH(var, head, field) \
for((var) = LIST_FIRST(head); \
(var)!= LIST_END(head); \
(var) = LIST_NEXT(var, field))
/*
* List functions.
*/
#define LIST_INIT(head) do { \
LIST_FIRST(head) = LIST_END(head); \
} while (0)
#define LIST_INSERT_AFTER(listelm, elm, field) do { \
if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
(listelm)->field.le_next->field.le_prev = \
&(elm)->field.le_next; \
(listelm)->field.le_next = (elm); \
(elm)->field.le_prev = &(listelm)->field.le_next; \
} while (0)
#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
(elm)->field.le_prev = (listelm)->field.le_prev; \
(elm)->field.le_next = (listelm); \
*(listelm)->field.le_prev = (elm); \
(listelm)->field.le_prev = &(elm)->field.le_next; \
} while (0)
#define LIST_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.le_next = (head)->lh_first) != NULL) \
(head)->lh_first->field.le_prev = &(elm)->field.le_next;\
(head)->lh_first = (elm); \
(elm)->field.le_prev = &(head)->lh_first; \
} while (0)
#define LIST_REMOVE(elm, field) do { \
if ((elm)->field.le_next != NULL) \
(elm)->field.le_next->field.le_prev = \
(elm)->field.le_prev; \
*(elm)->field.le_prev = (elm)->field.le_next; \
} while (0)
#define LIST_REPLACE(elm, elm2, field) do { \
if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \
(elm2)->field.le_next->field.le_prev = \
&(elm2)->field.le_next; \
(elm2)->field.le_prev = (elm)->field.le_prev; \
*(elm2)->field.le_prev = (elm2); \
} while (0)
/*
* Simple queue definitions.
*/
#define SIMPLEQ_HEAD(name, type) \
struct name { \
struct type *sqh_first; /* first element */ \
struct type **sqh_last; /* addr of last next element */ \
}
#define SIMPLEQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).sqh_first }
#define SIMPLEQ_ENTRY(type) \
struct { \
struct type *sqe_next; /* next element */ \
}
/*
* Simple queue access methods.
*/
#define SIMPLEQ_FIRST(head) ((head)->sqh_first)
#define SIMPLEQ_END(head) NULL
#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
#define SIMPLEQ_FOREACH(var, head, field) \
for((var) = SIMPLEQ_FIRST(head); \
(var) != SIMPLEQ_END(head); \
(var) = SIMPLEQ_NEXT(var, field))
/*
* Simple queue functions.
*/
#define SIMPLEQ_INIT(head) do { \
(head)->sqh_first = NULL; \
(head)->sqh_last = &(head)->sqh_first; \
} while (0)
#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
(head)->sqh_last = &(elm)->field.sqe_next; \
(head)->sqh_first = (elm); \
} while (0)
#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.sqe_next = NULL; \
*(head)->sqh_last = (elm); \
(head)->sqh_last = &(elm)->field.sqe_next; \
} while (0)
#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
(head)->sqh_last = &(elm)->field.sqe_next; \
(listelm)->field.sqe_next = (elm); \
} while (0)
#define SIMPLEQ_REMOVE_HEAD(head, field) do { \
if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
(head)->sqh_last = &(head)->sqh_first; \
} while (0)
/*
* Tail queue definitions.
*/
#define TAILQ_HEAD(name, type) \
struct name { \
struct type *tqh_first; /* first element */ \
struct type **tqh_last; /* addr of last next element */ \
}
#define TAILQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).tqh_first }
#define TAILQ_ENTRY(type) \
struct { \
struct type *tqe_next; /* next element */ \
struct type **tqe_prev; /* address of previous next element */ \
}
/*
* tail queue access methods
*/
#define TAILQ_FIRST(head) ((head)->tqh_first)
#define TAILQ_END(head) NULL
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
#define TAILQ_LAST(head, headname) \
(*(((struct headname *)((head)->tqh_last))->tqh_last))
/* XXX */
#define TAILQ_PREV(elm, headname, field) \
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
#define TAILQ_EMPTY(head) \
(TAILQ_FIRST(head) == TAILQ_END(head))
#define TAILQ_FOREACH(var, head, field) \
for((var) = TAILQ_FIRST(head); \
(var) != TAILQ_END(head); \
(var) = TAILQ_NEXT(var, field))
#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
for((var) = TAILQ_LAST(head, headname); \
(var) != TAILQ_END(head); \
(var) = TAILQ_PREV(var, headname, field))
/*
* Tail queue functions.
*/
#define TAILQ_INIT(head) do { \
(head)->tqh_first = NULL; \
(head)->tqh_last = &(head)->tqh_first; \
} while (0)
#define TAILQ_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
(head)->tqh_first->field.tqe_prev = \
&(elm)->field.tqe_next; \
else \
(head)->tqh_last = &(elm)->field.tqe_next; \
(head)->tqh_first = (elm); \
(elm)->field.tqe_prev = &(head)->tqh_first; \
} while (0)
#define TAILQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.tqe_next = NULL; \
(elm)->field.tqe_prev = (head)->tqh_last; \
*(head)->tqh_last = (elm); \
(head)->tqh_last = &(elm)->field.tqe_next; \
} while (0)
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
(elm)->field.tqe_next->field.tqe_prev = \
&(elm)->field.tqe_next; \
else \
(head)->tqh_last = &(elm)->field.tqe_next; \
(listelm)->field.tqe_next = (elm); \
(elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
} while (0)
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
(elm)->field.tqe_next = (listelm); \
*(listelm)->field.tqe_prev = (elm); \
(listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
} while (0)
#define TAILQ_REMOVE(head, elm, field) do { \
if (((elm)->field.tqe_next) != NULL) \
(elm)->field.tqe_next->field.tqe_prev = \
(elm)->field.tqe_prev; \
else \
(head)->tqh_last = (elm)->field.tqe_prev; \
*(elm)->field.tqe_prev = (elm)->field.tqe_next; \
} while (0)
#define TAILQ_REPLACE(head, elm, elm2, field) do { \
if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \
(elm2)->field.tqe_next->field.tqe_prev = \
&(elm2)->field.tqe_next; \
else \
(head)->tqh_last = &(elm2)->field.tqe_next; \
(elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
*(elm2)->field.tqe_prev = (elm2); \
} while (0)
/*
* Circular queue definitions.
*/
#define CIRCLEQ_HEAD(name, type) \
struct name { \
struct type *cqh_first; /* first element */ \
struct type *cqh_last; /* last element */ \
}
#define CIRCLEQ_HEAD_INITIALIZER(head) \
{ CIRCLEQ_END(&head), CIRCLEQ_END(&head) }
#define CIRCLEQ_ENTRY(type) \
struct { \
struct type *cqe_next; /* next element */ \
struct type *cqe_prev; /* previous element */ \
}
/*
* Circular queue access methods
*/
#define CIRCLEQ_FIRST(head) ((head)->cqh_first)
#define CIRCLEQ_LAST(head) ((head)->cqh_last)
#define CIRCLEQ_END(head) ((void *)(head))
#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
#define CIRCLEQ_EMPTY(head) \
(CIRCLEQ_FIRST(head) == CIRCLEQ_END(head))
#define CIRCLEQ_FOREACH(var, head, field) \
for((var) = CIRCLEQ_FIRST(head); \
(var) != CIRCLEQ_END(head); \
(var) = CIRCLEQ_NEXT(var, field))
#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \
for((var) = CIRCLEQ_LAST(head); \
(var) != CIRCLEQ_END(head); \
(var) = CIRCLEQ_PREV(var, field))
/*
* Circular queue functions.
*/
#define CIRCLEQ_INIT(head) do { \
(head)->cqh_first = CIRCLEQ_END(head); \
(head)->cqh_last = CIRCLEQ_END(head); \
} while (0)
#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
(elm)->field.cqe_next = (listelm)->field.cqe_next; \
(elm)->field.cqe_prev = (listelm); \
if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \
(head)->cqh_last = (elm); \
else \
(listelm)->field.cqe_next->field.cqe_prev = (elm); \
(listelm)->field.cqe_next = (elm); \
} while (0)
#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
(elm)->field.cqe_next = (listelm); \
(elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \
(head)->cqh_first = (elm); \
else \
(listelm)->field.cqe_prev->field.cqe_next = (elm); \
(listelm)->field.cqe_prev = (elm); \
} while (0)
#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
(elm)->field.cqe_next = (head)->cqh_first; \
(elm)->field.cqe_prev = CIRCLEQ_END(head); \
if ((head)->cqh_last == CIRCLEQ_END(head)) \
(head)->cqh_last = (elm); \
else \
(head)->cqh_first->field.cqe_prev = (elm); \
(head)->cqh_first = (elm); \
} while (0)
#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.cqe_next = CIRCLEQ_END(head); \
(elm)->field.cqe_prev = (head)->cqh_last; \
if ((head)->cqh_first == CIRCLEQ_END(head)) \
(head)->cqh_first = (elm); \
else \
(head)->cqh_last->field.cqe_next = (elm); \
(head)->cqh_last = (elm); \
} while (0)
#define CIRCLEQ_REMOVE(head, elm, field) do { \
if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \
(head)->cqh_last = (elm)->field.cqe_prev; \
else \
(elm)->field.cqe_next->field.cqe_prev = \
(elm)->field.cqe_prev; \
if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \
(head)->cqh_first = (elm)->field.cqe_next; \
else \
(elm)->field.cqe_prev->field.cqe_next = \
(elm)->field.cqe_next; \
} while (0)
#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \
if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \
CIRCLEQ_END(head)) \
(head).cqh_last = (elm2); \
else \
(elm2)->field.cqe_next->field.cqe_prev = (elm2); \
if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \
CIRCLEQ_END(head)) \
(head).cqh_first = (elm2); \
else \
(elm2)->field.cqe_prev->field.cqe_next = (elm2); \
} while (0)
#endif /* !_SYS_QUEUE_H_ */

View File

@ -1,677 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _SYS_TREE_H_
#define _SYS_TREE_H_
/*
* This file defines data structures for different types of trees:
* splay trees and red-black trees.
*
* A splay tree is a self-organizing data structure. Every operation
* on the tree causes a splay to happen. The splay moves the requested
* node to the root of the tree and partly rebalances it.
*
* This has the benefit that request locality causes faster lookups as
* the requested nodes move to the top of the tree. On the other hand,
* every lookup causes memory writes.
*
* The Balance Theorem bounds the total access time for m operations
* and n inserts on an initially empty tree as O((m + n)lg n). The
* amortized cost for a sequence of m accesses to a splay tree is O(lg n);
*
* A red-black tree is a binary search tree with the node color as an
* extra attribute. It fulfills a set of conditions:
* - every search path from the root to a leaf consists of the
* same number of black nodes,
* - each red node (except for the root) has a black parent,
* - each leaf node is black.
*
* Every operation on a red-black tree is bounded as O(lg n).
* The maximum height of a red-black tree is 2lg (n+1).
*/
#define SPLAY_HEAD(name, type) \
struct name { \
struct type *sph_root; /* root of the tree */ \
}
#define SPLAY_INITIALIZER(root) \
{ NULL }
#define SPLAY_INIT(root) do { \
(root)->sph_root = NULL; \
} while (0)
#define SPLAY_ENTRY(type) \
struct { \
struct type *spe_left; /* left element */ \
struct type *spe_right; /* right element */ \
}
#define SPLAY_LEFT(elm, field) (elm)->field.spe_left
#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right
#define SPLAY_ROOT(head) (head)->sph_root
#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL)
/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */
#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \
SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \
SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
(head)->sph_root = tmp; \
} while (0)
#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \
SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \
SPLAY_LEFT(tmp, field) = (head)->sph_root; \
(head)->sph_root = tmp; \
} while (0)
#define SPLAY_LINKLEFT(head, tmp, field) do { \
SPLAY_LEFT(tmp, field) = (head)->sph_root; \
tmp = (head)->sph_root; \
(head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
} while (0)
#define SPLAY_LINKRIGHT(head, tmp, field) do { \
SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
tmp = (head)->sph_root; \
(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \
} while (0)
#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \
SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \
SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\
SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \
SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \
} while (0)
/* Generates prototypes and inline functions */
#define SPLAY_PROTOTYPE(name, type, field, cmp) \
void name##_SPLAY(struct name *, struct type *); \
void name##_SPLAY_MINMAX(struct name *, int); \
struct type *name##_SPLAY_INSERT(struct name *, struct type *); \
struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \
\
/* Finds the node with the same key as elm */ \
static __inline struct type * \
name##_SPLAY_FIND(struct name *head, struct type *elm) \
{ \
if (SPLAY_EMPTY(head)) \
return(NULL); \
name##_SPLAY(head, elm); \
if ((cmp)(elm, (head)->sph_root) == 0) \
return (head->sph_root); \
return (NULL); \
} \
\
static __inline struct type * \
name##_SPLAY_NEXT(struct name *head, struct type *elm) \
{ \
name##_SPLAY(head, elm); \
if (SPLAY_RIGHT(elm, field) != NULL) { \
elm = SPLAY_RIGHT(elm, field); \
while (SPLAY_LEFT(elm, field) != NULL) { \
elm = SPLAY_LEFT(elm, field); \
} \
} else \
elm = NULL; \
return (elm); \
} \
\
static __inline struct type * \
name##_SPLAY_MIN_MAX(struct name *head, int val) \
{ \
name##_SPLAY_MINMAX(head, val); \
return (SPLAY_ROOT(head)); \
}
/* Main splay operation.
* Moves node close to the key of elm to top
*/
#define SPLAY_GENERATE(name, type, field, cmp) \
struct type * \
name##_SPLAY_INSERT(struct name *head, struct type *elm) \
{ \
if (SPLAY_EMPTY(head)) { \
SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \
} else { \
int __comp; \
name##_SPLAY(head, elm); \
__comp = (cmp)(elm, (head)->sph_root); \
if(__comp < 0) { \
SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\
SPLAY_RIGHT(elm, field) = (head)->sph_root; \
SPLAY_LEFT((head)->sph_root, field) = NULL; \
} else if (__comp > 0) { \
SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\
SPLAY_LEFT(elm, field) = (head)->sph_root; \
SPLAY_RIGHT((head)->sph_root, field) = NULL; \
} else \
return ((head)->sph_root); \
} \
(head)->sph_root = (elm); \
return (NULL); \
} \
\
struct type * \
name##_SPLAY_REMOVE(struct name *head, struct type *elm) \
{ \
struct type *__tmp; \
if (SPLAY_EMPTY(head)) \
return (NULL); \
name##_SPLAY(head, elm); \
if ((cmp)(elm, (head)->sph_root) == 0) { \
if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \
(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\
} else { \
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
(head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\
name##_SPLAY(head, elm); \
SPLAY_RIGHT((head)->sph_root, field) = __tmp; \
} \
return (elm); \
} \
return (NULL); \
} \
\
void \
name##_SPLAY(struct name *head, struct type *elm) \
{ \
struct type __node, *__left, *__right, *__tmp; \
int __comp; \
\
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
__left = __right = &__node; \
\
while ((__comp = (cmp)(elm, (head)->sph_root))) { \
if (__comp < 0) { \
__tmp = SPLAY_LEFT((head)->sph_root, field); \
if (__tmp == NULL) \
break; \
if ((cmp)(elm, __tmp) < 0){ \
SPLAY_ROTATE_RIGHT(head, __tmp, field); \
if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
break; \
} \
SPLAY_LINKLEFT(head, __right, field); \
} else if (__comp > 0) { \
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
if (__tmp == NULL) \
break; \
if ((cmp)(elm, __tmp) > 0){ \
SPLAY_ROTATE_LEFT(head, __tmp, field); \
if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
break; \
} \
SPLAY_LINKRIGHT(head, __left, field); \
} \
} \
SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
} \
\
/* Splay with either the minimum or the maximum element \
* Used to find minimum or maximum element in tree. \
*/ \
void name##_SPLAY_MINMAX(struct name *head, int __comp) \
{ \
struct type __node, *__left, *__right, *__tmp; \
\
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
__left = __right = &__node; \
\
while (1) { \
if (__comp < 0) { \
__tmp = SPLAY_LEFT((head)->sph_root, field); \
if (__tmp == NULL) \
break; \
if (__comp < 0){ \
SPLAY_ROTATE_RIGHT(head, __tmp, field); \
if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
break; \
} \
SPLAY_LINKLEFT(head, __right, field); \
} else if (__comp > 0) { \
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
if (__tmp == NULL) \
break; \
if (__comp > 0) { \
SPLAY_ROTATE_LEFT(head, __tmp, field); \
if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
break; \
} \
SPLAY_LINKRIGHT(head, __left, field); \
} \
} \
SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
}
#define SPLAY_NEGINF -1
#define SPLAY_INF 1
#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y)
#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y)
#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y)
#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y)
#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \
: name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF))
#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \
: name##_SPLAY_MIN_MAX(x, SPLAY_INF))
#define SPLAY_FOREACH(x, name, head) \
for ((x) = SPLAY_MIN(name, head); \
(x) != NULL; \
(x) = SPLAY_NEXT(name, head, x))
/* Macros that define a red-black tree */
#define RB_HEAD(name, type) \
struct name { \
struct type *rbh_root; /* root of the tree */ \
}
#define RB_INITIALIZER(root) \
{ NULL }
#define RB_INIT(root) do { \
(root)->rbh_root = NULL; \
} while (0)
#define RB_BLACK 0
#define RB_RED 1
#define RB_ENTRY(type) \
struct { \
struct type *rbe_left; /* left element */ \
struct type *rbe_right; /* right element */ \
struct type *rbe_parent; /* parent element */ \
int rbe_color; /* node color */ \
}
#define RB_LEFT(elm, field) (elm)->field.rbe_left
#define RB_RIGHT(elm, field) (elm)->field.rbe_right
#define RB_PARENT(elm, field) (elm)->field.rbe_parent
#define RB_COLOR(elm, field) (elm)->field.rbe_color
#define RB_ROOT(head) (head)->rbh_root
#define RB_EMPTY(head) (RB_ROOT(head) == NULL)
#define RB_SET(elm, parent, field) do { \
RB_PARENT(elm, field) = parent; \
RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \
RB_COLOR(elm, field) = RB_RED; \
} while (0)
#define RB_SET_BLACKRED(black, red, field) do { \
RB_COLOR(black, field) = RB_BLACK; \
RB_COLOR(red, field) = RB_RED; \
} while (0)
#ifndef RB_AUGMENT
#define RB_AUGMENT(x)
#endif
#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \
(tmp) = RB_RIGHT(elm, field); \
if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field))) { \
RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \
} \
RB_AUGMENT(elm); \
if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \
if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
else \
RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
} else \
(head)->rbh_root = (tmp); \
RB_LEFT(tmp, field) = (elm); \
RB_PARENT(elm, field) = (tmp); \
RB_AUGMENT(tmp); \
if ((RB_PARENT(tmp, field))) \
RB_AUGMENT(RB_PARENT(tmp, field)); \
} while (0)
#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \
(tmp) = RB_LEFT(elm, field); \
if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field))) { \
RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \
} \
RB_AUGMENT(elm); \
if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \
if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
else \
RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
} else \
(head)->rbh_root = (tmp); \
RB_RIGHT(tmp, field) = (elm); \
RB_PARENT(elm, field) = (tmp); \
RB_AUGMENT(tmp); \
if ((RB_PARENT(tmp, field))) \
RB_AUGMENT(RB_PARENT(tmp, field)); \
} while (0)
/* Generates prototypes and inline functions */
#define RB_PROTOTYPE(name, type, field, cmp) \
void name##_RB_INSERT_COLOR(struct name *, struct type *); \
void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\
struct type *name##_RB_REMOVE(struct name *, struct type *); \
struct type *name##_RB_INSERT(struct name *, struct type *); \
struct type *name##_RB_FIND(struct name *, struct type *); \
struct type *name##_RB_NEXT(struct type *); \
struct type *name##_RB_MINMAX(struct name *, int); \
\
/* Main rb operation.
* Moves node close to the key of elm to top
*/
#define RB_GENERATE(name, type, field, cmp) \
void \
name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \
{ \
struct type *parent, *gparent, *tmp; \
while ((parent = RB_PARENT(elm, field)) && \
RB_COLOR(parent, field) == RB_RED) { \
gparent = RB_PARENT(parent, field); \
if (parent == RB_LEFT(gparent, field)) { \
tmp = RB_RIGHT(gparent, field); \
if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
RB_COLOR(tmp, field) = RB_BLACK; \
RB_SET_BLACKRED(parent, gparent, field);\
elm = gparent; \
continue; \
} \
if (RB_RIGHT(parent, field) == elm) { \
RB_ROTATE_LEFT(head, parent, tmp, field);\
tmp = parent; \
parent = elm; \
elm = tmp; \
} \
RB_SET_BLACKRED(parent, gparent, field); \
RB_ROTATE_RIGHT(head, gparent, tmp, field); \
} else { \
tmp = RB_LEFT(gparent, field); \
if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
RB_COLOR(tmp, field) = RB_BLACK; \
RB_SET_BLACKRED(parent, gparent, field);\
elm = gparent; \
continue; \
} \
if (RB_LEFT(parent, field) == elm) { \
RB_ROTATE_RIGHT(head, parent, tmp, field);\
tmp = parent; \
parent = elm; \
elm = tmp; \
} \
RB_SET_BLACKRED(parent, gparent, field); \
RB_ROTATE_LEFT(head, gparent, tmp, field); \
} \
} \
RB_COLOR(head->rbh_root, field) = RB_BLACK; \
} \
\
void \
name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \
{ \
struct type *tmp; \
while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \
elm != RB_ROOT(head)) { \
if (RB_LEFT(parent, field) == elm) { \
tmp = RB_RIGHT(parent, field); \
if (RB_COLOR(tmp, field) == RB_RED) { \
RB_SET_BLACKRED(tmp, parent, field); \
RB_ROTATE_LEFT(head, parent, tmp, field);\
tmp = RB_RIGHT(parent, field); \
} \
if ((RB_LEFT(tmp, field) == NULL || \
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\
(RB_RIGHT(tmp, field) == NULL || \
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\
RB_COLOR(tmp, field) = RB_RED; \
elm = parent; \
parent = RB_PARENT(elm, field); \
} else { \
if (RB_RIGHT(tmp, field) == NULL || \
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\
struct type *oleft; \
if ((oleft = RB_LEFT(tmp, field)))\
RB_COLOR(oleft, field) = RB_BLACK;\
RB_COLOR(tmp, field) = RB_RED; \
RB_ROTATE_RIGHT(head, tmp, oleft, field);\
tmp = RB_RIGHT(parent, field); \
} \
RB_COLOR(tmp, field) = RB_COLOR(parent, field);\
RB_COLOR(parent, field) = RB_BLACK; \
if (RB_RIGHT(tmp, field)) \
RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\
RB_ROTATE_LEFT(head, parent, tmp, field);\
elm = RB_ROOT(head); \
break; \
} \
} else { \
tmp = RB_LEFT(parent, field); \
if (RB_COLOR(tmp, field) == RB_RED) { \
RB_SET_BLACKRED(tmp, parent, field); \
RB_ROTATE_RIGHT(head, parent, tmp, field);\
tmp = RB_LEFT(parent, field); \
} \
if ((RB_LEFT(tmp, field) == NULL || \
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\
(RB_RIGHT(tmp, field) == NULL || \
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\
RB_COLOR(tmp, field) = RB_RED; \
elm = parent; \
parent = RB_PARENT(elm, field); \
} else { \
if (RB_LEFT(tmp, field) == NULL || \
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\
struct type *oright; \
if ((oright = RB_RIGHT(tmp, field)))\
RB_COLOR(oright, field) = RB_BLACK;\
RB_COLOR(tmp, field) = RB_RED; \
RB_ROTATE_LEFT(head, tmp, oright, field);\
tmp = RB_LEFT(parent, field); \
} \
RB_COLOR(tmp, field) = RB_COLOR(parent, field);\
RB_COLOR(parent, field) = RB_BLACK; \
if (RB_LEFT(tmp, field)) \
RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\
RB_ROTATE_RIGHT(head, parent, tmp, field);\
elm = RB_ROOT(head); \
break; \
} \
} \
} \
if (elm) \
RB_COLOR(elm, field) = RB_BLACK; \
} \
\
struct type * \
name##_RB_REMOVE(struct name *head, struct type *elm) \
{ \
struct type *child, *parent, *old = elm; \
int color; \
if (RB_LEFT(elm, field) == NULL) \
child = RB_RIGHT(elm, field); \
else if (RB_RIGHT(elm, field) == NULL) \
child = RB_LEFT(elm, field); \
else { \
struct type *left; \
elm = RB_RIGHT(elm, field); \
while ((left = RB_LEFT(elm, field))) \
elm = left; \
child = RB_RIGHT(elm, field); \
parent = RB_PARENT(elm, field); \
color = RB_COLOR(elm, field); \
if (child) \
RB_PARENT(child, field) = parent; \
if (parent) { \
if (RB_LEFT(parent, field) == elm) \
RB_LEFT(parent, field) = child; \
else \
RB_RIGHT(parent, field) = child; \
RB_AUGMENT(parent); \
} else \
RB_ROOT(head) = child; \
if (RB_PARENT(elm, field) == old) \
parent = elm; \
(elm)->field = (old)->field; \
if (RB_PARENT(old, field)) { \
if (RB_LEFT(RB_PARENT(old, field), field) == old)\
RB_LEFT(RB_PARENT(old, field), field) = elm;\
else \
RB_RIGHT(RB_PARENT(old, field), field) = elm;\
RB_AUGMENT(RB_PARENT(old, field)); \
} else \
RB_ROOT(head) = elm; \
RB_PARENT(RB_LEFT(old, field), field) = elm; \
if (RB_RIGHT(old, field)) \
RB_PARENT(RB_RIGHT(old, field), field) = elm; \
if (parent) { \
left = parent; \
do { \
RB_AUGMENT(left); \
} while ((left = RB_PARENT(left, field))); \
} \
goto color; \
} \
parent = RB_PARENT(elm, field); \
color = RB_COLOR(elm, field); \
if (child) \
RB_PARENT(child, field) = parent; \
if (parent) { \
if (RB_LEFT(parent, field) == elm) \
RB_LEFT(parent, field) = child; \
else \
RB_RIGHT(parent, field) = child; \
RB_AUGMENT(parent); \
} else \
RB_ROOT(head) = child; \
color: \
if (color == RB_BLACK) \
name##_RB_REMOVE_COLOR(head, parent, child); \
return (old); \
} \
\
/* Inserts a node into the RB tree */ \
struct type * \
name##_RB_INSERT(struct name *head, struct type *elm) \
{ \
struct type *tmp; \
struct type *parent = NULL; \
int comp = 0; \
tmp = RB_ROOT(head); \
while (tmp) { \
parent = tmp; \
comp = (cmp)(elm, parent); \
if (comp < 0) \
tmp = RB_LEFT(tmp, field); \
else if (comp > 0) \
tmp = RB_RIGHT(tmp, field); \
else \
return (tmp); \
} \
RB_SET(elm, parent, field); \
if (parent != NULL) { \
if (comp < 0) \
RB_LEFT(parent, field) = elm; \
else \
RB_RIGHT(parent, field) = elm; \
RB_AUGMENT(parent); \
} else \
RB_ROOT(head) = elm; \
name##_RB_INSERT_COLOR(head, elm); \
return (NULL); \
} \
\
/* Finds the node with the same key as elm */ \
struct type * \
name##_RB_FIND(struct name *head, struct type *elm) \
{ \
struct type *tmp = RB_ROOT(head); \
int comp; \
while (tmp) { \
comp = cmp(elm, tmp); \
if (comp < 0) \
tmp = RB_LEFT(tmp, field); \
else if (comp > 0) \
tmp = RB_RIGHT(tmp, field); \
else \
return (tmp); \
} \
return (NULL); \
} \
\
struct type * \
name##_RB_NEXT(struct type *elm) \
{ \
if (RB_RIGHT(elm, field)) { \
elm = RB_RIGHT(elm, field); \
while (RB_LEFT(elm, field)) \
elm = RB_LEFT(elm, field); \
} else { \
if (RB_PARENT(elm, field) && \
(elm == RB_LEFT(RB_PARENT(elm, field), field))) \
elm = RB_PARENT(elm, field); \
else { \
while (RB_PARENT(elm, field) && \
(elm == RB_RIGHT(RB_PARENT(elm, field), field)))\
elm = RB_PARENT(elm, field); \
elm = RB_PARENT(elm, field); \
} \
} \
return (elm); \
} \
\
struct type * \
name##_RB_MINMAX(struct name *head, int val) \
{ \
struct type *tmp = RB_ROOT(head); \
struct type *parent = NULL; \
while (tmp) { \
parent = tmp; \
if (val < 0) \
tmp = RB_LEFT(tmp, field); \
else \
tmp = RB_RIGHT(tmp, field); \
} \
return (parent); \
}
#define RB_NEGINF -1
#define RB_INF 1
#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y)
#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y)
#define RB_FIND(name, x, y) name##_RB_FIND(x, y)
#define RB_NEXT(name, x, y) name##_RB_NEXT(y)
#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF)
#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF)
#define RB_FOREACH(x, name, head) \
for ((x) = RB_MIN(name, head); \
(x) != NULL; \
(x) = name##_RB_NEXT(x))
#endif /* _SYS_TREE_H_ */

1020
conf.c

File diff suppressed because it is too large Load Diff

1463
config.guess vendored

File diff suppressed because it is too large Load Diff

View File

@ -1,129 +0,0 @@
/* config.h.in. Generated from configure.in by autoheader. */
#undef u_int16_t
#undef u_int32_t
#undef u_int64_t
#undef u_int8_t
/* Define to 1 if you have the <err.h> header file. */
#undef HAVE_ERR_H
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define to 1 if you have the `socket' function. */
#undef HAVE_SOCKET
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define to 1 if you have the `strlcat' function. */
#undef HAVE_STRLCAT
/* Define to 1 if you have the `strlcpy' function. */
#undef HAVE_STRLCPY
/* Define to 1 if you have the `strsep' function. */
#undef HAVE_STRSEP
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/time.h> header file. */
#undef HAVE_SYS_TIME_H
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
#undef HAVE_SYS_WAIT_H
/* Define to 1 if you have the <time.h> header file. */
#undef HAVE_TIME_H
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Name of package */
#undef PACKAGE
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* Define as the return type of signal handlers (`int' or `void'). */
#undef RETSIGTYPE
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
#undef TIME_WITH_SYS_TIME
/* Version number of package */
#undef VERSION
/* Define to empty if `const' does not conform to ANSI C. */
#undef const
/* Define to `int' if <sys/types.h> does not define. */
#undef pid_t
/* Define to `unsigned' if <sys/types.h> does not define. */
#undef size_t
/* Define to `unsigned short' if <sys/types.h> does not define. */
#undef u_int16_t
/* Define to `unsigned int' if <sys/types.h> does not define. */
#undef u_int32_t
/* Define to `unsigned long long' if <sys/types.h> does not define. */
#undef u_int64_t
/* Define to `unsigned char' if <sys/types.h> does not define. */
#undef u_int8_t
/* Prototypes for missing functions */
#ifndef HAVE_STRLCPY
size_t strlcpy(char *, const char *, size_t);
#endif
#ifndef HAVE_STRLCAT
size_t strlcat(char *, const char *, size_t);
#endif
#ifndef HAVE_STRSEP
char *strsep(char **, const char *);
#endif /* HAVE_STRSEP */
#ifndef HAVE_ERR
void err(int, const char *, ...);
void warn(const char *, ...);
void errx(int , const char *, ...);
void warnx(const char *, ...);
#endif

1579
config.sub vendored

File diff suppressed because it is too large Load Diff

7775
configure vendored

File diff suppressed because it is too large Load Diff

View File

@ -1,74 +0,0 @@
dnl $Id$
AC_INIT(calmwm.c)
AC_CANONICAL_SYSTEM
dnl AC_LIBTOOL_DLOPEN
AM_INIT_AUTOMAKE(cwm, 3)
AM_CONFIG_HEADER(config.h)
AM_MAINTAINER_MODE
AC_PROG_CC
AC_PROG_MAKE_SET
dnl intitialization
if test "x$prefix" = "xNONE"; then
prefix="/usr/local"
fi
dnl Checks for programs.
AC_PROG_RANLIB
AC_PROG_INSTALL
dnl ugly ugly hack
AC_CHECK_LIB(c, err, [ ERRO="" ], [ ERRO="err.o" ],)
AC_SUBST(ERRO)
dnl Checks for header files.
AC_HEADER_STDC
AC_HEADER_SYS_WAIT
dnl X stuff
AC_PATH_X
AC_PATH_XTRA
LIBS="$X_LIBS -lX11 -lXext"
CFLAGS="$CFLAGS $X_CFLAGS"
dnl dnl Check for __progname; from OpenSSHp
dnl AC_CACHE_CHECK([if libc defines __progname], ac_cv_libc_defines___progname, [
dnl AC_TRY_LINK([],
dnl [ extern char *__progname; printf("%s", __progname); ],
dnl [ ac_cv_libc_defines___progname="yes" ],
dnl [ ac_cv_libc_defines___progname="no" ]
dnl )
dnl ])
dnl if test "x$ac_cv_libc_defines___progname" = "xyes" ; then
dnl AC_DEFINE(HAVE___PROGNAME)
dnl fi
AC_CHECK_HEADERS(sys/time.h err.h time.h unistd.h stdint.h)
dnl Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
AC_TYPE_PID_T
AC_TYPE_SIZE_T
AC_HEADER_TIME
AC_CHECK_TYPE(u_int64_t, unsigned long long)
AC_CHECK_TYPE(u_int32_t, unsigned int)
AC_CHECK_TYPE(u_int16_t, unsigned short)
AC_CHECK_TYPE(u_int8_t, unsigned char)
dnl Checks for library functions.
AC_PROG_GCC_TRADITIONAL
AC_TYPE_SIGNAL
AC_CHECK_FUNCS(socket)
AC_REPLACE_FUNCS(strlcpy strsep strlcat)
PKG_CHECK_MODULES(XFT, [xft], , )
AC_SUBST(XFT_CFLAGS)
AC_SUBST(XFT_LIBS)
AC_SUBST(LTLIBOBJS)
AC_OUTPUT(Makefile)

View File

@ -1,65 +0,0 @@
/*
* cursor.c
*
* Copyright (c) 2005 Marius Eriksen <marius@monkey.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "headers.h"
#include "calmwm.h"
/* Pretty much straight out of 9wm... */
struct cursor_data {
int width;
int hot[2];
u_char mask[64];
u_char fore[64];
};
static struct cursor_data Bigarrow = {
16,
{0, 0},
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0x3F,
0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x1F, 0xFF, 0x3F,
0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0x3F,
0xCF, 0x1F, 0x8F, 0x0F, 0x07, 0x07, 0x03, 0x02,
},
{ 0x00, 0x00, 0xFE, 0x7F, 0xFE, 0x3F, 0xFE, 0x0F,
0xFE, 0x07, 0xFE, 0x07, 0xFE, 0x0F, 0xFE, 0x1F,
0xFE, 0x3F, 0xFE, 0x7F, 0xFE, 0x3F, 0xCE, 0x1F,
0x86, 0x0F, 0x06, 0x07, 0x02, 0x02, 0x00, 0x00,
},
};
static Cursor
_mkcursor(struct cursor_data *c, struct screen_ctx *sc)
{
Pixmap f, m;
f = XCreatePixmapFromBitmapData(G_dpy, sc->rootwin, (char *)c->fore,
c->width, c->width, 1, 0, 1);
m = XCreatePixmapFromBitmapData(G_dpy, sc->rootwin, (char *)c->mask,
c->width, c->width, 1, 0, 1);
return (XCreatePixmapCursor(G_dpy, f, m,
&sc->blackcolor, &sc->whitecolor, c->hot[0], c->hot[1]));
}
Cursor
cursor_bigarrow(struct screen_ctx *sc)
{
return _mkcursor(&Bigarrow, sc);
}

379
cwm.1
View File

@ -1,7 +1,20 @@
.\" $OpenBSD$
.\"
.\" The following requests are required for all man pages.
.Dd July 10, 2004
.\" Copyright (c) 2004,2005 Marius Aamodt Eriksen <marius@monkey.org>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
.\" copyright notice and this permission notice appear in all copies.
.\"
.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: September 25 2010 $
.Dt CWM 1
.Os
.Sh NAME
@ -10,214 +23,260 @@
.Sh SYNOPSIS
.\" For a program: program [-abc] file ...
.Nm cwm
.Op Fl s
.Op Fl f Ar fontname
.Op Fl c Ar file
.Op Fl d Ar display
.Sh DESCRIPTION
.Nm
is a window manager for X11. It was originally inspired by evilwm,
but was rewritten from scratch due to limitations in the evilwm
codebase. The from-scratch rewrite borrowed some code from 9wm.
is a window manager for X11 which contains many features that
concentrate on the efficiency and transparency of window management.
.Nm
contains many new features which all concentrate on the efficiency and
transparency of window management.
.Nm
also aims to maintain the most simplest and pleasant aesthetic.
.Sh BASIC OPERATION
We will adopt the following notation:
.Bl -tag -width 10n -offset -indent -compact
.It Fa C
Control
.It Fa M
Meta (Alt on PCs)
.It Fa S
Shift
.It Fa M1
Left mouse button
.It Fa M2
Middle mouse button
.It Fa M3
Right mouse button
also aims to maintain the simplest and most pleasant aesthetic.
.Pp
The following notation is used throughout this page:
.Pp
.Bl -tag -width Ds -offset indent -compact
.It Ic C
Control.
.It Ic M
Meta.
.It Ic S
Shift.
.It Ic M1
Left mouse button.
.It Ic M2
Middle mouse button.
.It Ic M3
Right mouse button.
.El
.Pp
.Nm
is very simple in its use. Most of the actions are initiated via
keybindings. The current keybindings are described below, their
functionality is described in more detail later.
.Bl -tag -width 10n -offset -indent -compact
.It Fa C-M-Enter
is very simple in its use.
Most of the actions are initiated via key bindings.
The current key bindings are described below;
their functionality is described in more detail later.
.Pp
.Bl -tag -width "CM-EscapeXXXXX" -offset indent -compact
.It Ic CM-Return
Spawn a new terminal.
.It Fa C-M-Delete
.It Ic CM-Delete
Lock the screen.
.It Fa M-Enter
.It Ic M-Return
Hide current window.
.It Fa M-Down
.It Ic M-Down
Lower current window.
.It Fa M-Up
.It Ic M-Up
Raise current window.
.It Fa M-/
.It Ic M-/
Search for windows.
.It Fa C-/
.It Ic C-/
Search for applications.
.It Fa C-M-l
.It Ic CM-n
Label current window.
.It Fa M-Tab
.It Ic M-Tab
Cycle through currently visible windows.
.It Fa M-S-Tab
.It Ic MS-Tab
Reverse cycle through currently visible windows.
.It Fa C-M-x
.It Ic CM-x
Delete current window.
.It Fa C-M-Escape
Enter group edit mode.
.It Fa C-M-[n]
.It Ic CM-[n]
Select group n, where n is 1-9.
.It Fa C-M-0
.It Ic CM-0
Select all groups.
.It Fa M-Right
Switch to next group.
.It Fa M-Left
Switch to previous group.
.It Fa C-M-=
Toggle vertical maximization of window.
.It Ic CM-g
Toggle group membership of current window.
.It Ic M-Right
Cycle through active groups.
.It Ic M-Left
Reverse cycle through active groups.
.It Ic CMS-f
Toggle freezing geometry of current window.
.It Ic CM-f
Toggle full-screen size of current window.
.It Ic CM-=
Toggle vertical maximization of current window.
.It Ic CMS-=
Toggle horizontal maximization of current window.
.It Ic M-?
Spawn
.Dq exec program
dialog.
.It Ic M-.
Spawn
.Dq ssh to
dialog.
This parses
.Pa $HOME/.ssh/known_hosts
to provide host auto-completion.
.Xr ssh 1
will be executed via the configured terminal emulator.
.It Ic CM-w
Spawn
.Dq exec WindowManager
dialog; allows you to switch from
.Nm
to another window manager without restarting the X server.
.It Ic CMS-r
Reload configuration.
.It Ic CMS-q
Quit
.Nm .
.El
.Pp
The mouse bindings are also important, they are:
.Bl -tag -width 10n -offset -indent -compact
.It Fa M-M1
Move a window.
.It Fa C-M-M1
Toggle a window's membership in the current group. A blue highlight
indicates the window has been added to the group, a red highlight
indicates it has been removed.
.It Fa M-M2
Resize a window/Select a window.
.It Fa M-M3
Lower a window.
.Pp
.Bl -tag -width Ds -offset indent -compact
.It Ic M-M1
Move current window.
.It Ic CM-M1
Toggle group membership of current window.
.It Ic M-M2
Resize current window
.It Ic M-M3
Lower current window.
.It Ic CMS-M3
Hide current window.
.El
.Pp
The options for
.Nm
are as follows:
.Bl -tag -width Ds
.It Fl s
Set sticky group mode on.
The default behavior for new windows is to not assign any group.
This changes the default behavior to assigning the currrently selected
group to any newly created windows.
.It Fl f Ar fontname
Makes the
.Xr Xft 3
font string
.Ar fontname
the default font.
.It Fl c Ar file
Specify the config file to use. Defaults to
.Pa ~/.cwmrc .
.It Fl d Ar display
Specify the display to use.
.El
.Sh POINTER MOVEMENT
The pointer can be moved with the use of the keyboard through bindings.
.Ic C-[Up|Down|Left|Right]
moves the pointer a small amount, while
.Ic CS-[Up|Down|Left|Right]
moves the pointer a larger amount.
For example, to move the pointer to the left by a small amount,
press
.Ic C-Left .
To move the pointer down by a larger amount, press
.Ic CS-Down .
.Sh WINDOW MOVEMENT AND RESIZING
.Nm
windows can be moved with the use of the keyboard through
.Cm vi Ns -like
bindings.
.Ic M-[hjkl]
moves the current window a small amount, while
.Ic MS-[hjkl]
moves the current window a larger amount.
For example, to move the current window to the left a small amount, press
.Ic M-h .
To move the current window down by a larger amount, press
.Ic MS-j .
.Pp
Similarly, windows may be resized with the same key bindings with the addition
of the Control key.
.Ic CM-[hjkl]
resizes the window a small amount and
.Ic CMS-[hjkl]
resizes by a larger increment.
.Sh SEARCH
.Nm
features the ability to search for windows by their current title, old
titles and by their label. The priority for the search results are:
Label, current title, old titles in reverse order and finally window
class name.
.Nm
features the ability to search for windows by their current title,
old titles, and by their label.
The priority for the search results are: label, current title,
old titles in reverse order, and finally window class name.
.Nm
keeps a history of the 5 previous titles of a window.
.Pp
When searching, the leftmost character of the result list may show a
flag:
.Bl -tag -width 10n -offset -indent -compact
.It Fa !
.Pp
.Bl -tag -width 10n -offset indent -compact
.It !
The window is the currently focused window.
.It Fa &
.It &
The window is hidden.
.El
The following keybindings may be used to navigate the result list:
.Bl -tag -width 10n -offset -indent -compact
.It [Down] or C-s
.Pp
The following key bindings may be used to navigate the result list:
.Pp
.Bl -tag -width "[Down] or C-s or M-j" -offset indent -compact
.It Ic [Down], C-s No or Ic M-j
Select the next window in the list.
.It [Up] or C-r
.It Ic [Up], C-r No or Ic M-k
Select the previous window in the list.
.It C-u
.It Ic [Backspace] No or Ic C-h
Backspace.
.It Ic C-u
Clear the input.
.It [Enter]
.It Ic [Return]
Focus the selected window.
.It [Esc]
Quit.
.It C-a
.It Ic [Esc]
Cancel.
.It Ic C-a
Whenever there are no matching windows, list every window.
.El
.Sh GROUPS
.Nm
has the ability to group windows together, and use the groups to
perform operations on the entire group instead of just one window.
Currently, the only operation that is supported is to hide and unhide
the grouped windows. Together with the
.Fl s
the grouped windows.
Together with the
.Pa sticky
option, this can be used to emulate virtual desktops.
To edit groups, enter the group edit mode, and select/unselect the
groups with the group selection mouse click. A blue border will be
shown on the currently selected windows. The group selection keyboard
shortcuts can also be used to change which group to edit.
.Pp
To edit groups, use the group selection commands to toggle membership
of a group.
A blue border will be shown briefly on windows added to the current group,
and a red border will be shown on those just removed.
.Sh MENUS
Menus are recalled by clicking the mouse on the root window:
.Bl -tag -width 10n -offset -indent -compact
.It Fa M1
Show list of currently hidden windows. Clicking on an item will
unhide that window.
.It Fa M2
Show list of currently defined groups. Clicking on an item will
hide/unhide that group.
.It Fa M3
Show list of applications as defined in
.Fa ~/.calmwm .
Clicking on an item will spawn that application.
.Pp
.Bl -tag -width 10n -offset indent -compact
.It Ic M1
Show list of currently hidden windows.
Clicking on an item will unhide that window.
.It Ic M2
Show list of currently defined groups.
Clicking on an item will hide/unhide that group.
.It Ic M3
Show list of applications as defined in
.Pa ~/.cwmrc .
Clicking on an item will spawn that application.
.El
.Sh ~/.calmwm
Any directory entries here are shown in the application menu. When it
is selected, the image is executed with
.Xr execve 2 .
One use of this is to create symbolic links for your favorite
applications in this directory using
.Xr ln 1 .
The entries
.Nm term
and
.Nm lock
have special meaning. When they exist they point to the terminal
program and screen locking programs used by the keybindings specified
above. The defaults for these are
.Xr xterm 1
and
.Xr xlock 1 ,
respectively.
.Sh ACKNOWLEDGEMENTS
.Sh ENVIRONMENT
.Bl -tag -width "DISPLAYXXX"
.It DISPLAY
.Nm
contains some code from 9wm.
starts on this display unless the
.Fl d
option is given.
.El
.Sh FILES
.Bl -tag -width Ds
.It Pa ~/.cwmrc
.El
.Sh SEE ALSO
.Xr cwmrc 5
.Sh AUTHORS
The
.An -nosplit
.Pp
.Nm
software has been developed by Marius Aamodt Eriksen
.Aq marius@monkey.org
with contributions from Andy Adamson
.Aq dros@monkey.org ,
Niels Provos
.Aq provos@monkey.org
and Antti Nyk<79>nen
.Aq aon@iki.fi .
was developed by
.An Marius Aamodt Eriksen Aq marius@monkey.org
with contributions from
.An Andy Adamson Aq dros@monkey.org ,
.An Niels Provos Aq provos@monkey.org ,
and
.An Antti Nyk\(:anen Aq aon@iki.fi .
Ideas, discussion with many others.
.\" .Sh HISTORY
.\".Aq marius@monkey.org .
.\" .Sh CAVEATS
.Sh HISTORY
.Nm
was originally inspired by evilwm, but was rewritten from scratch
due to limitations in the evilwm codebase.
The from-scratch rewrite borrowed some code from 9wm, however that code
has since been removed or rewritten.
.Pp
.Nm
first appeared in
.Ox 4.2 .

458
cwmrc.5 Normal file
View File

@ -0,0 +1,458 @@
.\" $OpenBSD$
.\"
.\" Copyright (c) 2004,2005 Marius Aamodt Eriksen <marius@monkey.org>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
.\" copyright notice and this permission notice appear in all copies.
.\"
.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: September 8 2011 $
.Dt CWMRC 5
.Os
.Sh NAME
.Nm cwmrc
.Nd calm window manager configuration file
.Sh DESCRIPTION
This manual page describes the
.Xr cwm 1
configuration file.
.Pp
The current line can be extended over multiple lines using a backslash
.Pq Sq \e .
Comments can be put anywhere in the file using a hash mark
.Pq Sq # ,
and extend to the end of the current line.
Care should be taken when commenting out multi-line text:
the comment is effective until the end of the entire block.
.Pp
Arguments containing whitespace should be surrounded by double quotes
.Pq \&" .
.Pp
The following options are accepted:
.Pp
.Bl -tag -width Ds -compact
.It Ic autogroup Ar group windowname
.It Ic autogroup Ar group windowname,windowclass
Control automatic window grouping, based on the name and/or class
properties, where
.Ar group
is a number between 0 and 9.
If the group number is 0, then the window will not be grouped; this to
allow for
.Dq sticky
windows in sticky group mode.
.Pp
The name and class of a window may be obtained using
.Xr xprop 1 .
.Pp
.It Ic bind Ar keys command
Cause the creation of a keybinding, or replacement of a default
keybinding.
The modifier keys come first, followed by a
.Sq - .
.Pp
The following modifiers are recognised:
.Pp
.Bl -tag -width Ds -offset indent -compact
.It C
The Control key.
.It M
The Meta key.
.It S
The Shift key.
.It 4
The Mod4 key (normally the windows key).
.El
.Pp
The
.Sq -
should be followed by either a keysym name, taken from
.Pa /usr/X11R6/include/X11/keysymdef.h ,
or a numerical keycode value enclosed in
.Dq [] .
The
.Ar command
may either be one from the
.Sx BIND COMMAND LIST
(see below) or the command line that is to be executed.
.Pp
A special
.Ar command
keyword
.Dq unmap
can be used to remove the named keybinding.
This can be used to remove a binding which conflicts with an
application.
.Pp
.It Ic borderwidth Ar pixels
Set the window border width to
.Ar pixels .
.Pp
.It Ic color activeborder Ar color
Set the color of the active border.
.Pp
.It Ic color font Ar color
Set menu font color.
.Pp
.It Ic color groupborder Ar color
Set the color of the border while grouping a window.
.Pp
.It Ic color inactiveborder Ar color
Set the color of the inactive border.
.Pp
.It Ic color menubg Ar color
Set menu background color.
.Pp
.It Ic color menufg Ar color
Set menu foreground color.
.Pp
.It Ic color ungroupborder Ar color
Set the color of the border while ungrouping a window.
.Pp
.It Ic command Ar name path
Every
.Ar name
entry is shown in the application menu.
When selected, the defined
.Ar path
is executed with
.Xr execve 2 .
.Pp
The
.Ar name
entries
.Nm term
and
.Nm lock
have a special meaning.
They point to the terminal and screen locking programs specified by
keybindings.
The defaults are
.Xr xterm 1
and
.Xr xlock 1 ,
respectively.
.Pp
.It Ic fontname Ar font
Change the default
.Ar font
for
.Xr Xft 3 .
.Pp
.It Ic gap Ar top bottom left right
Define a
.Dq gap
in pixels at the edge of the screen, so that when a
window is maximized it will not overlap this area.
This
.Dq gap
can be used for applications such as
.Xr xclock 1 ,
where the user may wish to remain visible.
.Pp
.It Ic ignore Ar windowname
Ignore, and do not warp to, windows with the name
.Ar windowname
when drawing borders and cycling through windows.
.Pp
.It Ic mousebind Ar buttons command
Cause the creation of a mouse binding, or replacement of a default
mouse binding.
The modifier keys come first, followed by a
.Sq - .
.Pp
The following modifiers are recognised:
.Pp
.Bl -tag -width Ds -offset indent -compact
.It C
The Control key.
.It M
The Meta key.
.It S
The Shift key.
.It 4
The Mod4 key (normally the windows key).
.El
.Pp
The
.Sq -
should be followed by number:
.Pp
.Bl -tag -width Ds -offset indent -compact
.It 1
Left mouse button.
.It 2
Middle mouse button.
.It 3
Right mouse button.
.El
.Pp
The
.Ar command
may be taken from the
.Sx MOUSEBIND COMMAND LIST
(see below).
.Pp
.It Ic moveamount Ar pixels
Set a default size for the keyboard movement bindings,
in pixels.
The default is 1.
.Pp
.It Ic snapdist Ar pixels
Minimum distance to snap-to adjacent edge, in pixels.
The default is 0.
.Pp
.It Ic sticky Ic yes Ns \&| Ns Ic no
Toggle sticky group mode.
The default behavior for new windows is to not assign any group.
By enabling sticky group mode,
.Xr cwm 1
will assign new windows to the currently selected group.
.El
.Sh EXAMPLE CONFIGURATION
.Bd -literal
# Set default Xft(3) font
fontname "sans-serif:pixelsize=14:bold"
# Turn on sticky-group mode
sticky yes
# Any entry here is shown in the application menu
command firefox firefox
command xmms xmms
command top "xterm -e top"
# Autogroup definitions
autogroup 3 "aterm,XTerm"
autogroup 3 "xterm,XTerm"
# Ignore programs by that name by not drawing borders around them.
ignore XMMS
ignore xwi
ignore xapm
ignore xclock
# Keybindings
bind CM-r label
bind CS-Return "xterm -e top"
bind 4-o unmap
bind M-1 grouponly1
bind M-2 grouponly2
bind M-3 grouponly3
bind MS-1 movetogroup1
bind MS-2 movetogroup2
bind MS-3 movetogroup3
# Mousebindings
mousebind M-2 window_lower
mousebind M-3 window_resize
.Ed
.Sh BIND COMMAND LIST
.Bl -tag -width 18n -compact
.It reload
Reload configuration.
.It quit
Quit
.Xr cwm 1 .
.It terminal
Spawn a new terminal.
.It lock
Lock the screen.
.It search
Launch window search menu.
.It menusearch
Launch application search menu.
.It exec
Launch
.Dq exec program
menu.
.It exec_wm
Launch
.Dq exec WindowManager
menu.
.It ssh
Launch
.Dq ssh
menu.
.It group[n]
Select group n, where n is 1-9.
.It grouponly[n]
Like
.Ar group[n]
but also hides the other groups.
.It nogroup
Select all groups.
.It grouptoggle
Toggle group membership of current window.
.It movetogroup[n]
Hide current window from display and move to group n, where n is 1-9.
.It cyclegroup
Forward cycle through groups.
.It rcyclegroup
Reverse cycle through groups.
.It cycle
Forward cycle through windows.
.It rcycle
Reverse cycle through windows.
.It cycleingroup
Forward cycle through windows in current group.
.It rcycleingroup
Reverse cycle through windows in current group.
.It delete
Delete current window.
.It hide
Hide current window.
.It lower
Lower current window.
.It raise
Raise current window.
.It label
Label current window.
.It freeze
Freeze current window geometry.
.It maximize
Maximize current window full-screen.
.It vmaximize
Maximize current window vertically.
.It hmaximize
Maximize current window horizontally.
.It moveup
Move window
.Ar moveamount
pixels up.
.It movedown
Move window
.Ar moveamount
pixels down.
.It moveright
Move window
.Ar moveamount
pixels right.
.It moveleft
Move window
.Ar moveamount
pixels left.
.It bigmoveup
Move window 10 times
.Ar moveamount
pixels up.
.It bigmovedown
Move window 10 times
.Ar moveamount
pixels down.
.It bigmoveright
Move window 10 times
.Ar moveamount
pixels right.
.It bigmoveleft
Move window 10 times
.Ar moveamount
pixels left.
.It resizeup
Resize window
.Ar moveamount
pixels up.
.It resizedown
Resize window
.Ar moveamount
pixels down.
.It resizeright
Resize window
.Ar moveamount
pixels right.
.It resizeleft
Resize window
.Ar moveamount
pixels left.
.It bigresizeup
Resize window 10 times
.Ar moveamount
pixels up.
.It bigresizedown
Resize window 10 times
.Ar moveamount
pixels down.
.It bigresizeright
Resize window 10 times
.Ar moveamount
pixels right.
.It bigresizeleft
Resize window 10 times
.Ar moveamount
pixels left.
.It ptrmoveup
Move pointer
.Ar moveamount
pixels up.
.It ptrmovedown
Move pointer
.Ar moveamount
pixels down.
.It ptrmoveright
Move pointer
.Ar moveamount
pixels right.
.It ptrmoveleft
Move pointer
.Ar moveamount
pixels left.
.It bigptrmoveup
Move pointer 10 times
.Ar moveamount
pixels up.
.It bigptrmovedown
Move pointer 10 times
.Ar moveamount
pixels down.
.It bigptrmoveright
Move pointer 10 times
.Ar moveamount
pixels right.
.It bigptrmoveleft
Move pointer 10 times
.Ar moveamount
pixels left.
.El
.Sh MOUSEBIND COMMAND LIST
.Bl -tag -width 18n -compact
.It window_move
Move current window.
.It window_resize
Resize current window.
.It window_lower
Lower current window.
.It window_raise
Raise current window.
.It window_hide
Hide current window.
.It window_grouptoggle
Toggle group membership of current window.
.It menu_group
Launch group list.
.It menu_unhide
Launch hidden window list.
.It menu_cmd
Launch command list.
.El
.Sh FILES
.Bl -tag -width "~/.cwmrcXXX" -compact
.It Pa ~/.cwmrc
default
.Xr cwm 1
configuration file
.El
.Sh SEE ALSO
.Xr cwm 1
.Sh HISTORY
The
.Nm
file format first appeared in
.Ox 4.4 .

21
draw.c
View File

@ -1,21 +0,0 @@
/*
* calmwm - the calm window manager
*
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
* All rights reserved.
*
* $Id$
*/
#include "headers.h"
#include "calmwm.h"
void
draw_outline(struct client_ctx *cc)
{
struct screen_ctx *sc = CCTOSC(cc);
XDrawRectangle(G_dpy, sc->rootwin, sc->invgc,
cc->geom.x - cc->bwidth, cc->geom.y - cc->bwidth,
cc->geom.width + cc->bwidth, cc->geom.height + cc->bwidth);
}

105
err.c
View File

@ -1,105 +0,0 @@
/*
* err.c
*
* Adapted from OpenBSD libc *err* *warn* code.
*
* Copyright (c) 2000 Dug Song <dugsong@monkey.org>
*
* Copyright (c) 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/types.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
void
err(int eval, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
if (fmt != NULL) {
(void)vfprintf(stderr, fmt, ap);
(void)fprintf(stderr, ": ");
}
va_end(ap);
(void)fprintf(stderr, "%s\n", strerror(errno));
exit(eval);
}
void
warn(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
if (fmt != NULL) {
(void)vfprintf(stderr, fmt, ap);
(void)fprintf(stderr, ": ");
}
va_end(ap);
(void)fprintf(stderr, "%s\n", strerror(errno));
}
void
errx(int eval, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
if (fmt != NULL)
(void)vfprintf(stderr, fmt, ap);
(void)fprintf(stderr, "\n");
va_end(ap);
exit(eval);
}
void
warnx(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
if (fmt != NULL)
(void)vfprintf(stderr, fmt, ap);
(void)fprintf(stderr, "\n");
va_end(ap);
}

156
font.c
View File

@ -1,5 +1,5 @@
/*
* font.c - cwm font abstraction
* calmwm - the calm window manager
*
* Copyright (c) 2005 Marius Eriksen <marius@monkey.org>
*
@ -14,146 +14,92 @@
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $OpenBSD$
*/
#include "hash.h"
#include "headers.h"
#include <sys/param.h>
#include <sys/queue.h>
#include <err.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "calmwm.h"
static XftFont *_make_font(struct screen_ctx *sc, struct fontdesc *fdp);
HASH_GENERATE(fonthash, fontdesc, node, fontdesc_cmp);
int
fontdesc_cmp(struct fontdesc *a, struct fontdesc *b)
font_ascent(struct screen_ctx *sc)
{
return strcmp(a->name, b->name);
return (sc->font->ascent);
}
/*
* Fowler/Noll/Vo hash
* http://www.isthe.com/chongo/tech/comp/fnv/
*/
#define FNV_P_32 ((unsigned int)0x01000193) /* 16777619 */
#define FNV_1_32 ((unsigned int)0x811c9dc5) /* 2166136261 */
unsigned int
fontdesc_hash(struct fontdesc *fdp)
int
font_descent(struct screen_ctx *sc)
{
const unsigned char *p, *end, *start;
unsigned int hash = FNV_1_32;
return (sc->font->descent);
}
start = fdp->name;
end = (const unsigned char *)fdp->name + strlen(fdp->name);
for (p = start; p < end; p++) {
hash *= FNV_P_32;
hash ^= (unsigned int)*p;
}
return (hash);
u_int
font_height(struct screen_ctx *sc)
{
return (sc->font->height + 1);
}
void
font_init(struct screen_ctx *sc)
font_init(struct screen_ctx *sc, const char *color)
{
XColor xcolor, tmp;
HASH_INIT(&sc->fonthash, fontdesc_hash);
sc->xftdraw = XftDrawCreate(G_dpy, sc->rootwin,
DefaultVisual(G_dpy, sc->which), DefaultColormap(G_dpy, sc->which));
if (sc->xftdraw)
XftDrawDestroy(sc->xftdraw);
sc->xftdraw = XftDrawCreate(X_Dpy, sc->rootwin,
DefaultVisual(X_Dpy, sc->which), DefaultColormap(X_Dpy, sc->which));
if (sc->xftdraw == NULL)
errx(1, "XftDrawCreate");
if (!XAllocNamedColor(G_dpy, DefaultColormap(G_dpy, sc->which),
"black", &xcolor, &tmp))
errx(1, "XAllocNamedColor");
sc->xftcolor.color.red = xcolor.red;
sc->xftcolor.color.green = xcolor.green;
sc->xftcolor.color.blue = xcolor.blue;
sc->xftcolor.color.alpha = 0x00ff00;
sc->xftcolor.pixel = xcolor.pixel;
}
struct fontdesc *
font_getx(struct screen_ctx *sc, const char *name)
{
struct fontdesc *fdp;
if ((fdp = font_get(sc, name)) == NULL)
errx(1, "font_get()");
return (fdp);
}
struct fontdesc *
font_get(struct screen_ctx *sc, const char *name)
{
struct fontdesc fd, *fdp;
XftFont *fn;
fd.name = name;
if ((fdp = HASH_FIND(fonthash, &sc->fonthash, &fd)) == NULL
&& (fn = _make_font(sc, &fd)) != NULL) {
fdp = xmalloc(sizeof(*fdp));
fdp->name = xstrdup(fd.name);
fdp->fn = fn;
fdp->sc = sc;
HASH_INSERT(fonthash, &sc->fonthash, fdp);
}
return (fdp);
if (sc->xftcolor.pixel)
XftColorFree(X_Dpy, DefaultVisual(X_Dpy, sc->which),
DefaultColormap(X_Dpy, sc->which), &sc->xftcolor);
if (!XftColorAllocName(X_Dpy, DefaultVisual(X_Dpy, sc->which),
DefaultColormap(X_Dpy, sc->which), color, &sc->xftcolor))
errx(1, "XftColorAllocName");
}
int
font_width(struct fontdesc *fdp, const char *text, int len)
font_width(struct screen_ctx *sc, const char *text, int len)
{
XGlyphInfo extents;
XftTextExtents8(G_dpy, fdp->fn, (const XftChar8*)text, len, &extents);
XGlyphInfo extents;
return (extents.xOff);
XftTextExtentsUtf8(X_Dpy, sc->font, (const FcChar8*)text,
len, &extents);
return (extents.xOff);
}
void
font_draw(struct fontdesc *fdp, const char *text, int len,
font_draw(struct screen_ctx *sc, const char *text, int len,
Drawable d, int x, int y)
{
XftDrawChange(fdp->sc->xftdraw, d);
/* Really needs to be UTF8'd. */
XftDrawString8(fdp->sc->xftdraw, &fdp->sc->xftcolor, fdp->fn, x, y,
XftDrawChange(sc->xftdraw, d);
XftDrawStringUtf8(sc->xftdraw, &sc->xftcolor, sc->font, x, y,
(const FcChar8*)text, len);
}
int
font_ascent(struct fontdesc *fdp)
XftFont *
font_make(struct screen_ctx *sc, const char *name)
{
return fdp->fn->ascent;
}
XftFont *fn = NULL;
FcPattern *pat, *patx;
XftResult res;
int
font_descent(struct fontdesc *fdp)
{
return fdp->fn->descent;
}
static XftFont *
_make_font(struct screen_ctx *sc, struct fontdesc *fdp)
{
XftFont *fn = NULL;
FcPattern *pat, *patx;
XftResult res;
if ((pat = FcNameParse(fdp->name)) == NULL)
if ((pat = FcNameParse((const FcChar8*)name)) == NULL)
return (NULL);
if ((patx = XftFontMatch(G_dpy, sc->which, pat, &res)) != NULL)
fn = XftFontOpenPattern(G_dpy, patx);
if ((patx = XftFontMatch(X_Dpy, sc->which, pat, &res)) != NULL)
fn = XftFontOpenPattern(X_Dpy, patx);
FcPatternDestroy(pat);
return (fn);
}

View File

@ -1,53 +0,0 @@
/*
* calmwm - the calm window manager
*
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
* All rights reserved.
*
* $Id$
*/
#include "headers.h"
#include "calmwm.h"
struct client_ctx *
geographic_west(struct client_ctx *from_cc)
{
/* Window *wins, w0, w1; */
/* struct screen_ctx *sc = screen_current(); */
/* u_int nwins, i; */
/* struct client_ctx *cc; */
screen_updatestackingorder();
return (NULL);
}
#if 0
int
_visible(struct client_ctx *this_cc)
{
int stacking = cc->stackingorder;
struct client_ctx *cc;
if (cc->flags & CLIENT_HIDDEN)
return (0);
TAILQ_FOREACH(cc, &G_clientq, entry) {
if (cc->flags & CLIENT_HIDDEN)
continue;
if (cc->stackingorder > stacking &&
cc->geom.x <= this_cc->geom.x &&
cc->geom.y <= this_cc->geom.y &&
cc->geom.width > (this_cc->geom.width +
(this_cc->geom.x - cc->geom.x) &&
cc->geom.height > (this_cc->geom.height - cc->geom.height))
return (0);
}
return (1);
}
#endif

475
grab.c
View File

@ -1,475 +0,0 @@
/*
* calmwm - the calm window manager
*
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
* All rights reserved.
*
* $Id$
*/
#include "headers.h"
#include "calmwm.h"
int _sweepcalc(struct client_ctx *, int, int, int, int);
int _nobuttons(XButtonEvent *);
#define ADJUST_HEIGHT(cc, dy) ((cc->geom.height - cc->geom.min_dy)/ dy)
#define ADJUST_WIDTH(cc, dx) ((cc->geom.width - cc->geom.min_dx)/ dx)
void
grab_sweep_draw(struct client_ctx *cc, int dx, int dy)
{
struct screen_ctx *sc = CCTOSC(cc);
int x0 = cc->geom.x, y0 = cc->geom.y;
char asize[10]; /* fits "nnnnxnnnn\0" */
int wide, height, wide_size, wide_name;
struct fontdesc *font = DefaultFont;
snprintf(asize, sizeof(asize), "%dx%d",
ADJUST_WIDTH(cc, dx), ADJUST_HEIGHT(cc, dy));
wide_size = font_width(font, asize, strlen(asize)) + 4;
wide_name = font_width(font, cc->name, strlen(cc->name)) + 4;
wide = MAX(wide_size, wide_name);
height = font_ascent(font) + font_descent(font) + 1;
XMoveResizeWindow(G_dpy, sc->menuwin, x0, y0, wide, height * 2);
XMapWindow(G_dpy, sc->menuwin);
XReparentWindow(G_dpy, sc->menuwin, cc->win, 0, 0);
XClearWindow(G_dpy, sc->menuwin);
font_draw(font, cc->name, strlen(cc->name), sc->menuwin,
2, font_ascent(font) + 1);
font_draw(font, asize, strlen(asize), sc->menuwin,
wide/2 - wide_size/2, height + font_ascent(font) + 1);
}
int
grab_sweep(struct client_ctx *cc)
{
XEvent ev;
struct screen_ctx *sc = CCTOSC(cc);
int x0 = cc->geom.x, y0 = cc->geom.y;
int dx, dy;
dx = MAX(1, cc->size->width_inc);
dy = MAX(1, cc->size->height_inc);
client_raise(cc);
client_ptrsave(cc);
if (xu_ptr_grab(sc->rootwin, MouseMask, G_cursor_resize) < 0)
return (-1);
xu_ptr_setpos(cc->win, cc->geom.width, cc->geom.height);
grab_sweep_draw(cc, dx, dy);
for (;;) {
/* Look for changes in ptr position. */
XMaskEvent(G_dpy, MouseMask, &ev);
switch (ev.type) {
case MotionNotify:
if (_sweepcalc(cc, x0, y0, ev.xmotion.x, ev.xmotion.y))
/* Recompute window output */
grab_sweep_draw(cc, dx, dy);
XMoveResizeWindow(G_dpy, cc->pwin,
cc->geom.x - cc->bwidth,
cc->geom.y - cc->bwidth,
cc->geom.width + cc->bwidth*2,
cc->geom.height + cc->bwidth*2);
XMoveResizeWindow(G_dpy, cc->win,
cc->bwidth, cc->bwidth,
cc->geom.width, cc->geom.height);
break;
case ButtonRelease:
XUnmapWindow(G_dpy, sc->menuwin);
XReparentWindow(G_dpy, sc->menuwin, sc->rootwin, 0, 0);
xu_ptr_ungrab();
client_ptrwarp(cc);
return (0);
}
}
/* NOTREACHED */
}
int
grab_drag(struct client_ctx *cc)
{
int x0 = cc->geom.x, y0 = cc->geom.y, xm, ym;
struct screen_ctx *sc = CCTOSC(cc);
XEvent ev;
client_raise(cc);
if (xu_ptr_grab(sc->rootwin, MouseMask, G_cursor_move) < 0)
return (-1);
xu_ptr_getpos(sc->rootwin, &xm, &ym);
for (;;) {
XMaskEvent(G_dpy, MouseMask, &ev);
switch (ev.type) {
case MotionNotify:
cc->geom.x = x0 + (ev.xmotion.x - xm);
cc->geom.y = y0 + (ev.xmotion.y - ym);
XMoveWindow(G_dpy, cc->pwin,
cc->geom.x - cc->bwidth, cc->geom.y - cc->bwidth);
break;
case ButtonRelease:
xu_ptr_ungrab();
return (0);
}
}
/* NOTREACHED */
}
/*
* Adapted from 9wm.
*/
/* XXX - this REALLY needs to be cleaned up. */
#define MenuMask (ButtonMask|ButtonMotionMask|ExposureMask)
#define MenuGrabMask (ButtonMask|ButtonMotionMask|StructureNotifyMask)
#define AllButtonMask (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask)
#ifdef notyet
struct client_ctx *
grab_menu_getcc(struct menu_q *menuq, int off)
{
int where = 0;
struct menu *mi;
TAILQ_FOREACH(mi, menuq, entry)
if (off == where++)
return mi->ctx;
return (NULL);
}
#endif
void *
grab_menu(XButtonEvent *e, struct menu_q *menuq)
{
struct screen_ctx *sc;
struct menu *mi;
XEvent ev;
int i, n, cur = 0, old, wide, high, status, drawn, warp;
int x, y, dx, dy, xmax, ymax;
int tx, ty;
struct fontdesc *font = DefaultFont;
if ((sc = screen_fromroot(e->root)) == NULL || e->window == sc->menuwin)
return (NULL);
dx = 0;
i = 0;
TAILQ_FOREACH(mi, menuq, entry) {
wide = font_width(font, mi->text, strlen(mi->text)) + 4;
if (wide > dx)
dx = wide;
if (mi->lasthit)
cur = i;
i++;
}
n = i;
wide = dx;
high = font_ascent(font) + font_descent(font) + 1;
dy = n*high;
x = e->x - wide/2;
y = e->y - cur*high - high/2;
warp = 0;
/* XXX - cache these in sc. */
xmax = DisplayWidth(G_dpy, sc->which);
ymax = DisplayHeight(G_dpy, sc->which);
if (x < 0) {
e->x -= x;
x = 0;
warp++;
}
if (x+wide >= xmax) {
e->x -= x+wide-xmax;
x = xmax-wide;
warp++;
}
if (y < 0) {
e->y -= y;
y = 0;
warp++;
}
if (y+dy >= ymax) {
e->y -= y+dy-ymax;
y = ymax-dy;
warp++;
}
if (warp)
xu_ptr_setpos(e->root, e->x, e->y);
XMoveResizeWindow(G_dpy, sc->menuwin, x, y, dx, dy);
XSelectInput(G_dpy, sc->menuwin, MenuMask);
XMapRaised(G_dpy, sc->menuwin);
status = xu_ptr_grab(sc->menuwin, MenuGrabMask, G_cursor_select);
if (status < 0) {
XUnmapWindow(G_dpy, sc->menuwin);
return (NULL);
}
drawn = 0;
#ifdef notyet
if (e->button == Button1) {
struct client_ctx *cc;
cc = grab_menu_getcc(menuq, cur);
if (cc != NULL) {
client_unhide(cc);
XRaiseWindow(G_dpy, sc->menuwin);
}
}
#endif
for (;;) {
XMaskEvent(G_dpy, MenuMask, &ev);
switch (ev.type) {
default:
warnx("menuhit: unknown ev.type %d\n", ev.type);
break;
case ButtonPress:
break;
case ButtonRelease:
if (ev.xbutton.button != e->button)
break;
x = ev.xbutton.x;
y = ev.xbutton.y;
i = y/high;
if (cur >= 0 && y >= cur*high-3 && y < (cur+1)*high+3)
i = cur;
if (x < 0 || x > wide || y < -3)
i = -1;
else if (i < 0 || i >= n)
i = -1;
/* else */
/* m->lasthit = i; */
if (!_nobuttons(&ev.xbutton))
i = -1;
/* XXX */
/* ungrab(&ev.xbutton); */
xu_ptr_ungrab();
XUnmapWindow(G_dpy, sc->menuwin);
n = 0;
TAILQ_FOREACH(mi, menuq, entry)
if (i == n++)
break;
return (mi);
case MotionNotify:
if (!drawn)
break;
x = ev.xbutton.x;
y = ev.xbutton.y;
old = cur;
cur = y/high;
if (old >= 0 && y >= old*high-3 && y < (old+1)*high+3)
cur = old;
if (x < 0 || x > wide || y < -3)
cur = -1;
else if (cur < 0 || cur >= n)
cur = -1;
if (cur == old)
break;
if (old >= 0 && old < n) {
#ifdef notyet
if (e->button == Button1) {
struct client_ctx *cc;
cc = grab_menu_getcc(menuq, old);
if (cc != NULL)
client_hide(cc);
}
#endif
XFillRectangle(G_dpy, sc->menuwin,
sc->hlgc, 0, old*high, wide, high);
}
if (cur >= 0 && cur < n) {
#ifdef notyet
if (e->button == Button1) {
struct client_ctx *cc;
cc = grab_menu_getcc(menuq, cur);
if (cc != NULL) {
client_unhide(cc);
XRaiseWindow(G_dpy,
sc->menuwin);
}
}
#endif
xu_ptr_regrab(MenuGrabMask, G_cursor_select);
XFillRectangle(G_dpy, sc->menuwin,
sc->hlgc, 0, cur*high, wide, high);
} else
xu_ptr_regrab(MenuGrabMask, G_cursor_default);
break;
case Expose:
XClearWindow(G_dpy, sc->menuwin);
i = 0;
TAILQ_FOREACH(mi, menuq, entry) {
tx = (wide - font_width(font, mi->text,
strlen(mi->text)))/2;
ty = i*high + font_ascent(font) + 1;
font_draw(font, mi->text, strlen(mi->text),
sc->menuwin, tx, ty);
i++;
}
if (cur >= 0 && cur < n)
XFillRectangle(G_dpy, sc->menuwin,
sc->hlgc, 0, cur*high, wide, high);
drawn = 1;
}
}
}
void
grab_menuinit(struct screen_ctx *sc)
{
sc->menuwin = XCreateSimpleWindow(G_dpy, sc->rootwin, 0, 0,
1, 1, 1, sc->blackpixl, sc->whitepixl);
}
#define LABEL_MAXLEN 256
#define LabelMask (KeyPressMask|ExposureMask)
void
grab_label(struct client_ctx *cc)
{
struct screen_ctx *sc = screen_current();
int x, y, dx, dy, fontheight, focusrevert;
XEvent e;
char labelstr[LABEL_MAXLEN];
char dispstr[LABEL_MAXLEN + sizeof("label>") - 1];
Window focuswin;
char chr;
enum ctltype ctl;
size_t len;
struct fontdesc *font = DefaultFont;
if (cc->label != NULL)
strlcpy(labelstr, cc->label, sizeof(labelstr));
else
labelstr[0] = '\0';
xu_ptr_getpos(sc->rootwin, &x, &y);
dy = fontheight = font_ascent(font) + font_descent(font) + 1;
dx = font_width(font, "label>", 6);
XMoveResizeWindow(G_dpy, sc->searchwin, x, y, dx, dy);
XSelectInput(G_dpy, sc->searchwin, LabelMask);
XMapRaised(G_dpy, sc->searchwin);
XGetInputFocus(G_dpy, &focuswin, &focusrevert);
XSetInputFocus(G_dpy, sc->searchwin,
RevertToPointerRoot, CurrentTime);
for (;;) {
XMaskEvent(G_dpy, LabelMask, &e);
switch (e.type) {
case KeyPress:
if (input_keycodetrans(e.xkey.keycode, e.xkey.state,
&ctl, &chr, 1) < 0)
continue;
switch (ctl) {
case CTL_ERASEONE:
if ((len = strlen(labelstr)) > 0)
labelstr[len - 1] = '\0';
break;
case CTL_RETURN:
/* Done */
if (strlen(labelstr) == 0)
goto out;
if (cc->label != NULL)
xfree(cc->label);
cc->label = xstrdup(labelstr);
case CTL_ABORT:
goto out;
default:
break;
}
if (chr != '\0') {
char str[2];
str[0] = chr;
str[1] = '\0';
strlcat(labelstr, str, sizeof(labelstr));
}
case Expose:
snprintf(dispstr, sizeof(dispstr), "label>%s", labelstr);
dx = font_width(font, dispstr, strlen(dispstr));
dy = fontheight;
XClearWindow(G_dpy, sc->searchwin);
XResizeWindow(G_dpy, sc->searchwin, dx, dy);
font_draw(font, dispstr, strlen(dispstr),
sc->searchwin, 0, font_ascent(font) + 1);
break;
}
}
out:
XSetInputFocus(G_dpy, focuswin,
focusrevert, CurrentTime);
XUnmapWindow(G_dpy, sc->searchwin);
}
int
_sweepcalc(struct client_ctx *cc, int x0, int y0, int motionx, int motiony)
{
int width, height;
width = cc->geom.width;
height = cc->geom.height;
cc->geom.width = abs(x0 - motionx);
cc->geom.height = abs(y0 - motiony);
if (cc->size->flags & PResizeInc) {
cc->geom.width -=
(cc->geom.width - cc->geom.min_dx) % cc->size->width_inc;
cc->geom.height -=
(cc->geom.height - cc->geom.min_dy) % cc->size->height_inc;
}
if (cc->size->flags & PMinSize) {
cc->geom.width = MAX(cc->geom.width, cc->size->min_width);
cc->geom.height = MAX(cc->geom.height, cc->size->min_height);
}
if (cc->size->flags & PMaxSize) {
cc->geom.width = MIN(cc->geom.width, cc->size->max_width);
cc->geom.height = MIN(cc->geom.height, cc->size->max_height);
}
cc->geom.x = x0 <= motionx ? x0 : x0 - cc->geom.width;
cc->geom.y = y0 <= motiony ? y0 : y0 - cc->geom.height;
return (width != cc->geom.width || height != cc->geom.height);
}
/* XXX */
int
_nobuttons(XButtonEvent *e) /* Einstuerzende */
{
int state;
state = (e->state & AllButtonMask);
return (e->type == ButtonRelease) && (state & (state - 1)) == 0;
}

717
group.c
View File

@ -3,41 +3,56 @@
*
* Copyright (c) 2004 Andy Adamson <dros@monkey.org>
* Copyright (c) 2004,2005 Marius Aamodt Eriksen <marius@monkey.org>
* All rights reserved.
*
* $Id$
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $OpenBSD$
*/
#include "headers.h"
#include <sys/param.h>
#include <sys/queue.h>
#include <assert.h>
#include <err.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "calmwm.h"
#define CALMWM_NGROUPS 9
static void group_add(struct group_ctx *, struct client_ctx *);
static void group_remove(struct client_ctx *);
static void group_hide(struct screen_ctx *, struct group_ctx *);
static void group_show(struct screen_ctx *, struct group_ctx *);
static void group_fix_hidden_state(struct group_ctx *);
static void group_setactive(struct screen_ctx *, long);
static void group_set_names(struct screen_ctx *);
int G_groupmode = 0;
int G_groupnamemode = 0;
struct group_ctx *G_group_active = NULL;
struct group_ctx *G_group_current = NULL;
struct group_ctx G_groups[CALMWM_NGROUPS];
char G_group_name[256];
int G_groupfocusset = 0;
Window G_groupfocuswin;
int G_groupfocusrevert;
int G_grouphideall = 0;
struct group_ctx_q G_groupq;
#define GroupMask (KeyPressMask|ExposureMask)
static char *shortcut_to_name[] = {
"XXX", "one", "two", "three",
"four", "five", "six", "seven",
"eight", "nine",
const char *shortcut_to_name[] = {
"nogroup", "one", "two", "three", "four", "five", "six",
"seven", "eight", "nine"
};
static void
_group_add(struct group_ctx *gc, struct client_ctx *cc)
group_add(struct group_ctx *gc, struct client_ctx *cc)
{
long no;
if (cc == NULL || gc == NULL)
errx(1, "_group_add: a ctx is NULL");
errx(1, "group_add: a ctx is NULL");
no = gc->shortcut - 1;
if (cc->group == gc)
return;
@ -45,56 +60,34 @@ _group_add(struct group_ctx *gc, struct client_ctx *cc)
if (cc->group != NULL)
TAILQ_REMOVE(&cc->group->clients, cc, group_entry);
XChangeProperty(X_Dpy, cc->win, _NET_WM_DESKTOP, XA_CARDINAL,
32, PropModeReplace, (unsigned char *)&no, 1);
TAILQ_INSERT_TAIL(&gc->clients, cc, group_entry);
cc->group = gc;
cc->groupcommit = 0;
}
static void
_group_remove(struct client_ctx *cc)
group_remove(struct client_ctx *cc)
{
long no = 0xffffffff;
if (cc == NULL || cc->group == NULL)
errx(1, "_group_remove: a ctx is NULL");
errx(1, "group_remove: a ctx is NULL");
XChangeProperty(X_Dpy, cc->win, _NET_WM_DESKTOP, XA_CARDINAL,
32, PropModeReplace, (unsigned char *)&no, 1);
TAILQ_REMOVE(&cc->group->clients, cc, group_entry);
cc->group = NULL;
cc->groupcommit = 0;
cc->highlight = 0;
client_draw_border(cc);
}
static void
_group_commit(struct group_ctx *gc)
group_hide(struct screen_ctx *sc, struct group_ctx *gc)
{
struct client_ctx *cc;
struct client_ctx *cc;
if (gc == NULL)
errx(1, "_group_commit: ctx is null");
TAILQ_FOREACH(cc, &gc->clients, group_entry)
cc->groupcommit = 1;
}
static void
_group_purge(struct group_ctx *gc)
{
struct client_ctx *cc;
if (gc == NULL)
errx(1, "_group_commit: ctx is null");
TAILQ_FOREACH(cc, &gc->clients, group_entry)
if (cc->groupcommit == 0)
_group_remove(cc);
}
static void
_group_hide(struct group_ctx *gc)
{
struct client_ctx *cc;
screen_updatestackingorder();
screen_updatestackingorder(sc);
gc->nhidden = 0;
gc->highstack = 0;
@ -108,21 +101,26 @@ _group_hide(struct group_ctx *gc)
}
static void
_group_show(struct group_ctx *gc)
group_show(struct screen_ctx *sc, struct group_ctx *gc)
{
struct client_ctx *cc;
Window *winlist;
u_int i;
int lastempty = -1;
struct client_ctx *cc;
Window *winlist;
u_int i;
int lastempty = -1;
winlist = (Window *) xcalloc(sizeof(*winlist) * (gc->highstack + 1));
gc->highstack = 0;
TAILQ_FOREACH(cc, &gc->clients, group_entry) {
if (cc->stackingorder > gc->highstack)
gc->highstack = cc->stackingorder;
}
winlist = (Window *) xcalloc(sizeof(*winlist), (gc->highstack + 1));
/*
* Invert the stacking order as XRestackWindows() expects them
* top-to-bottom.
*/
TAILQ_FOREACH(cc, &gc->clients, group_entry) {
winlist[gc->highstack - cc->stackingorder] = cc->pwin;
winlist[gc->highstack - cc->stackingorder] = cc->win;
client_unhide(cc);
}
@ -137,184 +135,119 @@ _group_show(struct group_ctx *gc)
}
}
XRestackWindows(G_dpy, winlist, gc->nhidden);
XRestackWindows(X_Dpy, winlist, gc->nhidden);
xfree(winlist);
gc->hidden = 0;
G_group_active = gc;
}
static void
_group_destroy(struct group_ctx *gc)
{
struct client_ctx *cc;
if (gc->name != NULL) {
xfree(gc->name);
gc->name = NULL;
}
while ((cc = TAILQ_FIRST(&gc->clients)) != NULL) {
TAILQ_REMOVE(&gc->clients, cc, group_entry);
cc->group = NULL;
cc->groupcommit = 0;
cc->highlight = 0;
client_draw_border(cc);
}
group_setactive(sc, gc->shortcut - 1);
}
void
group_init(void)
group_init(struct screen_ctx *sc)
{
int i;
int i;
long viewports[2] = {0, 0};
long ndesks = CALMWM_NGROUPS, zero = 0;
TAILQ_INIT(&G_groupq);
TAILQ_INIT(&sc->groupq);
sc->group_hideall = 0;
/* see if any group names have already been set and update the property
* with ours if they'll have changed.
*/
group_update_names(sc);
for (i = 0; i < CALMWM_NGROUPS; i++) {
TAILQ_INIT(&G_groups[i].clients);
G_groups[i].hidden = 0;
G_groups[i].shortcut = i + 1;
TAILQ_INSERT_TAIL(&G_groupq, &G_groups[i], entry);
TAILQ_INIT(&sc->groups[i].clients);
sc->groups[i].hidden = 0;
sc->groups[i].shortcut = i + 1;
TAILQ_INSERT_TAIL(&sc->groupq, &sc->groups[i], entry);
}
G_group_current = G_group_active = &G_groups[0];
/* we don't support large desktops, so this is always (0, 0) */
XChangeProperty(X_Dpy, sc->rootwin, _NET_DESKTOP_VIEWPORT,
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)viewports, 2);
XChangeProperty(X_Dpy, sc->rootwin, _NET_NUMBER_OF_DESKTOPS,
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&ndesks, 1);
/*
* we don't use virtual roots, so make sure it's not there from a
* previous wm.
*/
XDeleteProperty(X_Dpy, sc->rootwin, _NET_VIRTUAL_ROOTS);
/*
* We don't really have a ``showing desktop'' mode, so this is zero
* always. XXX Note that when we hide all groups, or when all groups
* are hidden we could technically set this later on.
*/
XChangeProperty(X_Dpy, sc->rootwin, _NET_SHOWING_DESKTOP,
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&zero, 1);
group_setactive(sc, 0);
}
/*
* manipulate the 'current group'
*/
#if 0
/* set current group to the first empty group
* returns 0 on success, -1 if there are no empty groups
*/
int
group_new(void)
void
group_make_autogroup(struct conf *conf, char *val, int no)
{
int i;
struct autogroupwin *aw;
char *p;
for (i=0; i < CALMWM_NGROUPS; i++) {
if (TAILQ_EMPTY(&G_groups[i].clients)) {
G_group_current = &G_groups[i];
aw = xcalloc(1, sizeof(*aw));
return (0);
}
if ((p = strchr(val, ',')) == NULL) {
aw->name = NULL;
aw->class = xstrdup(val);
} else {
*(p++) = '\0';
aw->name = xstrdup(val);
aw->class = xstrdup(p);
}
aw->num = no;
return (-1);
TAILQ_INSERT_TAIL(&conf->autogroupq, aw, entry);
}
#endif
/* change the current group */
int
group_select(int idx)
static void
group_setactive(struct screen_ctx *sc, long idx)
{
struct group_ctx *gc = G_group_current;
struct client_ctx *cc;
sc->group_active = &sc->groups[idx];
XChangeProperty(X_Dpy, sc->rootwin, _NET_CURRENT_DESKTOP,
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&idx, 1);
}
void
group_movetogroup(struct client_ctx *cc, int idx)
{
struct screen_ctx *sc = cc->sc;
struct group_ctx *gc;
if (idx < 0 || idx >= CALMWM_NGROUPS)
return (-1);
err(1, "group_movetogroup: index out of range (%d)", idx);
TAILQ_FOREACH(cc, &gc->clients, group_entry) {
cc->highlight = 0;
client_draw_border(cc);
gc = &sc->groups[idx];
if (cc->group == gc)
return;
if (gc->hidden) {
client_hide(cc);
gc->nhidden++;
}
_group_commit(gc);
G_group_current = &G_groups[idx];
group_display_draw(screen_current());
return (0);
}
/* enter group mode */
void
group_enter(void)
{
if (G_groupmode != 0)
errx(1, "group_enter called twice");
if (G_group_current == NULL)
G_group_current = &G_groups[0];
/* setup input buffer */
G_group_name[0] = '\0';
G_groupmode = 1;
group_display_init(screen_current());
group_display_draw(screen_current());
}
/* exit group mode */
void
group_exit(int commit)
{
struct group_ctx *gc = G_group_current;
struct client_ctx *cc;
if (G_groupmode != 1)
errx(1, "group_exit called twice");
TAILQ_FOREACH(cc, &gc->clients, group_entry) {
cc->highlight = 0;
client_draw_border(cc);
}
if (commit) {
_group_commit(gc);
} else {
/* abort */
_group_purge(gc);
if (!TAILQ_EMPTY(&gc->clients))
_group_destroy(gc);
}
XUnmapWindow(G_dpy, screen_current()->groupwin);
if (G_groupnamemode) {
XSetInputFocus(G_dpy, G_groupfocuswin, G_groupfocusrevert,
CurrentTime);
G_groupfocusset = 0;
}
G_groupmode = G_groupnamemode = 0;
}
void
group_click(struct client_ctx *cc)
{
struct group_ctx *gc = G_group_current;
if (gc == cc->group)
_group_remove(cc);
else
_group_add(gc, cc);
group_display_draw(screen_current());
}
/* Used to add a newly mapped window to the active group */
void
group_sticky(struct client_ctx *cc)
{
_group_add(G_group_active, cc);
group_add(gc, cc);
}
/*
* Colouring for groups upon add/remove.
*/
void
group_sticky_toggle_enter(struct client_ctx *cc)
{
struct group_ctx *gc = G_group_active;
struct screen_ctx *sc = cc->sc;
struct group_ctx *gc;
gc = sc->group_active;
if (gc == cc->group) {
_group_remove(cc);
cc->highlight = CLIENT_HIGHLIGHT_RED;
group_remove(cc);
cc->highlight = CLIENT_HIGHLIGHT_UNGROUP;
} else {
_group_add(gc, cc);
cc->highlight = CLIENT_HIGHLIGHT_BLUE;
group_add(gc, cc);
cc->highlight = CLIENT_HIGHLIGHT_GROUP;
}
client_draw_border(cc);
@ -328,95 +261,13 @@ group_sticky_toggle_exit(struct client_ctx *cc)
}
/*
* selection list display
* if group_hidetoggle would produce no effect, toggle the group's hidden state
*/
void
group_display_init(struct screen_ctx *sc)
static void
group_fix_hidden_state(struct group_ctx *gc)
{
sc->groupwin = XCreateSimpleWindow(G_dpy, sc->rootwin, 0, 0,
1, 1, 1, sc->blackpixl, sc->whitepixl);
}
void
group_display_draw(struct screen_ctx *sc)
{
struct group_ctx *gc = G_group_current;
int x, y, dx, dy, fontheight, titlelen;
struct client_ctx *cc;
char titlebuf[1024];
struct fontdesc *font = DefaultFont;
snprintf(titlebuf, sizeof(titlebuf), "Editing group %d", gc->shortcut);
x = y = 0;
fontheight = font_ascent(font) + font_descent(font) + 1;
dx = titlelen = font_width(font, titlebuf, strlen(titlebuf));
dy = fontheight;
TAILQ_FOREACH(cc, &gc->clients, group_entry) {
cc->highlight = CLIENT_HIGHLIGHT_BLUE;
client_draw_border(cc);
}
XMoveResizeWindow(G_dpy, sc->groupwin, x, y, dx, dy);
/* XXX */
XSelectInput(G_dpy, sc->groupwin, GroupMask);
XMapRaised(G_dpy, sc->groupwin);
XClearWindow(G_dpy, sc->groupwin);
font_draw(font, titlebuf, strlen(titlebuf), sc->groupwin,
0, font_ascent(font) + 1);
}
void
group_display_keypress(KeyCode k)
{
struct group_ctx * gc = G_group_current;
char chr;
enum ctltype ctl;
int len;
if (!G_groupnamemode)
return;
if (input_keycodetrans(k, 0, &ctl, &chr, 1) < 0)
goto out;
switch (ctl) {
case CTL_ERASEONE:
if ((len = strlen(G_group_name)) > 0)
G_group_name[len - 1] = '\0';
break;
case CTL_RETURN:
if (gc->name != NULL)
xfree(gc->name);
gc->name = xstrdup(G_group_name);
group_exit(1);
return;
default:
break;
}
if (chr != '\0')
snprintf(G_group_name, sizeof(G_group_name), "%s%c",
G_group_name, chr);
out:
group_display_draw(screen_current());
}
/* if group_hidetoggle would produce no effect, toggle the group's hidden state
*/
void
_group_fix_hidden_state(struct group_ctx *gc)
{
struct client_ctx *cc;
int same = 0;
struct client_ctx *cc;
int same = 0;
TAILQ_FOREACH(cc, &gc->clients, group_entry) {
if (gc->hidden == ((cc->flags & CLIENT_HIDDEN) ? 1 : 0))
@ -428,72 +279,77 @@ _group_fix_hidden_state(struct group_ctx *gc)
}
void
group_hidetoggle(int idx)
group_hidetoggle(struct screen_ctx *sc, int idx)
{
struct group_ctx *gc;
#ifdef notyet
char buf[128];
#endif
struct group_ctx *gc;
if (idx < 0 || idx >= CALMWM_NGROUPS)
err(1, "group_hidetoggle: index out of range (%d)", idx);
gc = &G_groups[idx];
_group_fix_hidden_state(gc);
gc = &sc->groups[idx];
group_fix_hidden_state(gc);
if (gc->hidden)
_group_show(gc);
group_show(sc, gc);
else {
_group_hide(gc);
group_hide(sc, gc);
/* XXX wtf? */
if (TAILQ_EMPTY(&gc->clients))
G_group_active = gc;
group_setactive(sc, idx);
}
#ifdef notyet
snprintf(buf, sizeof(buf), "Group %d", idx + 1);
screen_infomsg(buf);
#endif
}
#define GROUP_NEXT(gc, fwd) (fwd) ? \
TAILQ_NEXT(gc, entry) : TAILQ_PREV(gc, group_ctx_q, entry)
void
group_only(struct screen_ctx *sc, int idx)
{
int i;
if (idx < 0 || idx >= CALMWM_NGROUPS)
err(1, "group_only: index out of range (%d)", idx);
for (i = 0; i < CALMWM_NGROUPS; i++) {
if (i == idx)
group_show(sc, &sc->groups[i]);
else
group_hide(sc, &sc->groups[i]);
}
}
/*
* Jump to the next/previous active group. If none exist, then just
* stay put.
* Cycle through active groups. If none exist, then just stay put.
*/
void
group_slide(int fwd)
group_cycle(struct screen_ctx *sc, int flags)
{
struct group_ctx *gc, *showgroup = NULL;
struct group_ctx *gc, *showgroup = NULL;
assert(G_group_active != NULL);
assert(sc->group_active != NULL);
gc = G_group_active;
gc = sc->group_active;
for (;;) {
gc = GROUP_NEXT(gc, fwd);
gc = (flags & CWM_RCYCLE) ? TAILQ_PREV(gc, group_ctx_q,
entry) : TAILQ_NEXT(gc, entry);
if (gc == NULL)
gc = fwd ? TAILQ_FIRST(&G_groupq) :
TAILQ_LAST(&G_groupq, group_ctx_q);
if (gc == G_group_active)
gc = (flags & CWM_RCYCLE) ? TAILQ_LAST(&sc->groupq,
group_ctx_q) : TAILQ_FIRST(&sc->groupq);
if (gc == sc->group_active)
break;
if (!TAILQ_EMPTY(&gc->clients) && showgroup == NULL)
showgroup = gc;
else if (!gc->hidden)
_group_hide(gc);
group_hide(sc, gc);
}
if (showgroup == NULL)
return;
_group_hide(G_group_active);
group_hide(sc, sc->group_active);
if (showgroup->hidden)
_group_show(showgroup);
group_show(sc, showgroup);
else
G_group_active = showgroup;
group_setactive(sc, showgroup->shortcut - 1);
}
/* called when a client is deleted */
@ -501,39 +357,37 @@ void
group_client_delete(struct client_ctx *cc)
{
if (cc->group == NULL)
return;
return;
TAILQ_REMOVE(&cc->group->clients, cc, group_entry);
cc->group = NULL; /* he he */
cc->groupcommit = 0;
}
void
group_menu(XButtonEvent *e)
{
struct menu_q menuq;
struct menu *mi;
int i;
struct group_ctx *gc;
struct screen_ctx *sc;
struct group_ctx *gc;
struct menu *mi;
struct menu_q menuq;
int i;
sc = screen_fromroot(e->root);
TAILQ_INIT(&menuq);
for (i = 0; i < CALMWM_NGROUPS; i++) {
gc = &G_groups[i];
gc = &sc->groups[i];
if (TAILQ_EMPTY(&gc->clients))
continue;
if (gc->name == NULL)
gc->name = xstrdup(shortcut_to_name[gc->shortcut]);
XCALLOC(mi, struct menu);
mi = xcalloc(1, sizeof(*mi));
if (gc->hidden)
snprintf(mi->text, sizeof(mi->text), "%d: [%s]",
gc->shortcut, gc->name);
(void)snprintf(mi->text, sizeof(mi->text), "%d: [%s]",
gc->shortcut, sc->group_names[i]);
else
snprintf(mi->text, sizeof(mi->text), "%d: %s",
gc->shortcut, gc->name);
(void)snprintf(mi->text, sizeof(mi->text), "%d: %s",
gc->shortcut, sc->group_names[i]);
mi->ctx = gc;
TAILQ_INSERT_TAIL(&menuq, mi, entry);
}
@ -541,19 +395,16 @@ group_menu(XButtonEvent *e)
if (TAILQ_EMPTY(&menuq))
return;
mi = (struct menu *)grab_menu(e, &menuq);
mi = menu_filter(sc, &menuq, NULL, NULL, 0, NULL, NULL);
if (mi == NULL || mi->ctx == NULL)
goto cleanup;
gc = (struct group_ctx *)mi->ctx;
if (gc->hidden)
_group_show(gc);
else
_group_hide(gc);
(gc->hidden) ? group_show(sc, gc) : group_hide(sc, gc);
cleanup:
cleanup:
while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
TAILQ_REMOVE(&menuq, mi, entry);
xfree(mi);
@ -561,74 +412,138 @@ group_menu(XButtonEvent *e)
}
void
group_namemode(void)
group_alltoggle(struct screen_ctx *sc)
{
G_groupnamemode = 1;
int i;
group_display_draw(screen_current());
}
void
group_alltoggle(void)
{
int i;
for (i=0; i < CALMWM_NGROUPS; i++) {
if (G_grouphideall)
_group_show(&G_groups[i]);
for (i = 0; i < CALMWM_NGROUPS; i++) {
if (sc->group_hideall)
group_show(sc, &sc->groups[i]);
else
_group_hide(&G_groups[i]);
group_hide(sc, &sc->groups[i]);
}
if (G_grouphideall)
G_grouphideall = 0;
else
G_grouphideall = 1;
}
void
group_deletecurrent(void)
{
_group_destroy(G_group_current);
XUnmapWindow(G_dpy, screen_current()->groupwin);
G_groupmode = G_groupnamemode = 0;
}
void
group_done(void)
{
struct group_ctx *gc = G_group_current;
if (gc->name != NULL)
xfree(gc->name);
gc->name = xstrdup(shortcut_to_name[gc->shortcut]);
group_exit(1);
sc->group_hideall = (!sc->group_hideall);
}
void
group_autogroup(struct client_ctx *cc)
{
struct autogroupwin *aw;
struct group_ctx *gc;
char group[CALMWM_MAXNAMELEN];
struct screen_ctx *sc = cc->sc;
struct autogroupwin *aw;
struct group_ctx *gc;
int no = -1;
long *grpno;
if (cc->app_class == NULL || cc->app_name == NULL)
return;
TAILQ_FOREACH(aw, &G_conf.autogroupq, entry) {
if (strcmp(aw->class, cc->app_class) == 0 &&
(aw->name == NULL || strcmp(aw->name, cc->app_name) == 0)) {
strlcpy(group, aw->group, sizeof(group));
break;
if (xu_getprop(cc->win, _NET_WM_DESKTOP, XA_CARDINAL,
1, (unsigned char **)&grpno) > 0) {
if (*grpno == 0xffffffff)
no = 0;
else if (*grpno > CALMWM_NGROUPS || *grpno < 0)
no = CALMWM_NGROUPS - 1;
else
no = *grpno + 1;
XFree(grpno);
} else {
TAILQ_FOREACH(aw, &Conf.autogroupq, entry) {
if (strcmp(aw->class, cc->app_class) == 0 &&
(aw->name == NULL ||
strcmp(aw->name, cc->app_name) == 0)) {
no = aw->num;
break;
}
}
}
TAILQ_FOREACH(gc, &G_groupq, entry) {
if (strcmp(shortcut_to_name[gc->shortcut], group) == 0)
_group_add(gc, cc);
/* no group please */
if (no == 0)
return;
TAILQ_FOREACH(gc, &sc->groupq, entry) {
if (gc->shortcut == no) {
group_add(gc, cc);
return;
}
}
if (Conf.flags & CONF_STICKY_GROUPS)
group_add(sc->group_active, cc);
}
void
group_update_names(struct screen_ctx *sc)
{
char **strings, *p;
unsigned char *prop_ret;
Atom type_ret;
int format_ret, i = 0, nstrings = 0, n, setnames = 0;
unsigned long bytes_after, num_ret;
if (XGetWindowProperty(X_Dpy, sc->rootwin, _NET_DESKTOP_NAMES, 0,
0xffffff, False, UTF8_STRING, &type_ret, &format_ret,
&num_ret, &bytes_after, &prop_ret) == Success &&
prop_ret != NULL && format_ret == 8) {
/* failure, just set defaults */
prop_ret[num_ret - 1] = '\0'; /* paranoia */
while (i < num_ret) {
if (prop_ret[i++] == '\0')
nstrings++;
}
}
strings = xmalloc((nstrings < CALMWM_NGROUPS ? CALMWM_NGROUPS :
nstrings) * sizeof(*strings));
i = n = 0;
p = prop_ret;
while (n < nstrings) {
strings[n++] = xstrdup(p);
p += strlen(p) + 1;
}
/*
* make sure we always set our defaults if nothing is there to
* replace them.
*/
if (n < CALMWM_NGROUPS) {
setnames = 1;
i = 1;
while (n < CALMWM_NGROUPS)
strings[n++] = xstrdup(shortcut_to_name[i++]);
}
if (prop_ret != NULL)
XFree(prop_ret);
if (sc->group_nonames != 0)
xfree(sc->group_names);
sc->group_names = strings;
sc->group_nonames = n;
if (setnames)
group_set_names(sc);
}
static void
group_set_names(struct screen_ctx *sc)
{
unsigned char *p, *q;
size_t len = 0, tlen, slen;
int i;
for (i = 0; i < sc->group_nonames; i++)
len += strlen(sc->group_names[i]) + 1;
q = p = xcalloc(len, sizeof(*p));
tlen = len;
for (i = 0; i < sc->group_nonames; i++) {
slen = strlen(sc->group_names[i]) + 1;
(void)strlcpy(q, sc->group_names[i], tlen);
tlen -= slen;
q += slen;
}
XChangeProperty(X_Dpy, sc->rootwin, _NET_DESKTOP_NAMES,
UTF8_STRING, 8, PropModeReplace, p, len);
}

68
hash.h
View File

@ -1,68 +0,0 @@
/*
* hash.h - generic hash template, akin to queue.h & tree.h
*
* Copyright (c) 2005 Marius Eriksen <marius@monkey.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _HASH_H_ /* Possibly this is too generic. */
#define _HASH_H_
#include <sys/tree.h>
#define HASH_ENTRY SPLAY_ENTRY
#define HASH_HEAD(name, type, nbuckets) \
SPLAY_HEAD(name##_HASH_TREE, type); \
struct name { \
struct name##_HASH_TREE buckets[nbuckets]; \
unsigned int (*hashfn)(struct type *elm); \
};
#define HASH_NBUCKETS(head) \
(sizeof((head)->buckets)/sizeof((head)->buckets[0]))
#define HASH_INIT(head, fn) do { \
int i; \
for (i = 0; i < HASH_NBUCKETS(head); i++) { \
SPLAY_INIT(&(head)->buckets[i]); \
} \
(head)->hashfn = fn; \
} while (0)
#define HASH_PROTOTYPE(name, type, field, cmp) \
SPLAY_PROTOTYPE(name##_HASH_TREE, type, field, cmp) \
struct type *name##_HASH_TREE_FIND(struct name *head, struct type *find); \
void name##_HASH_TREE_INSERT(struct name *head, struct type *insert);
#define HASH_GENERATE(name, type, field, cmp) \
SPLAY_GENERATE(name##_HASH_TREE, type, field, cmp) \
struct type *name##_HASH_TREE_FIND(struct name *head, struct type *find) \
{ \
struct name##_HASH_TREE *bucket = \
&head->buckets[(*head->hashfn)(find) % HASH_NBUCKETS(head)]; \
return SPLAY_FIND(name##_HASH_TREE, bucket, find); \
} \
void name##_HASH_TREE_INSERT(struct name *head, struct type *insert) \
{ \
struct name##_HASH_TREE *bucket = \
&head->buckets[(*head->hashfn)(insert) % HASH_NBUCKETS(head)]; \
\
SPLAY_INSERT(name##_HASH_TREE, bucket, insert); \
}
#define HASH_FIND(name, head, find) name##_HASH_TREE_FIND((head), (find))
#define HASH_INSERT(name, head, insert) name##_HASH_TREE_INSERT((head), (insert))
#endif /* _HASH_H_ */

View File

@ -1,52 +0,0 @@
/*
* calmwm - the calm window manager
*
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
* All rights reserved.
*
* $Id$
*/
#ifndef _CALMWM_HEADERS_H_
#define _CALMWM_HEADERS_H_
#include <sys/types.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
#include <sys/queue.h>
#include <sys/wait.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <dirent.h>
#include <getopt.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <ctype.h>
#include <X11/cursorfont.h>
#include <X11/extensions/shape.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include <X11/Xatom.h>
#include <X11/Xproto.h>
#include <X11/Intrinsic.h>
#include <X11/Xos.h>
#include <X11/Xft/Xft.h>
#ifdef USE_XOSD
#include <xosd.h>
#endif /* USE_XOSD */
#include <err.h>
#endif /* _CALMWM_HEADERS_H_ */

81
input.c
View File

@ -1,81 +0,0 @@
/*
* calmwm - the calm window manager
*
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
* All rights reserved.
*
* $Id$
*/
#include "headers.h"
#include "calmwm.h"
int
input_keycodetrans(KeyCode kc, u_int state,
enum ctltype *ctl, char *chr, int normalize)
{
int ks;
*ctl = CTL_NONE;
*chr = '\0';
ks = XKeycodeToKeysym(G_dpy, kc, 0);
/* Look for control characters. */
switch (ks) {
case XK_BackSpace:
*ctl = CTL_ERASEONE;
break;
case XK_Return:
*ctl = CTL_RETURN;
break;
case XK_Up:
*ctl = CTL_UP;
break;
case XK_Down:
*ctl = CTL_DOWN;
break;
case XK_Escape:
*ctl = CTL_ABORT;
break;
}
if (*ctl == CTL_NONE && (state & ControlMask)) {
switch (ks) {
case XK_s:
case XK_S:
/* Emacs "next" */
*ctl = CTL_DOWN;
break;
case XK_r:
case XK_R:
/* Emacs "previous" */
*ctl = CTL_UP;
break;
case XK_u:
case XK_U:
*ctl = CTL_WIPE;
break;
case XK_a:
case XK_A:
*ctl = CTL_ALL;
break;
}
}
if (*ctl != CTL_NONE)
return (0);
/*
* For regular characters, only (part of, actually) Latin 1
* for now.
*/
if (ks < 0x20 || ks > 0x07e)
return (-1);
*chr = (char)ks;
if (normalize)
*chr = tolower(*chr);
return (0);
}

View File

@ -1,323 +0,0 @@
#!/bin/sh
# install - install a program, script, or datafile
scriptversion=2005-05-14.22
# This originates from X11R5 (mit/util/scripts/install.sh), which was
# later released in X11R6 (xc/config/util/install.sh) with the
# following copyright and license.
#
# Copyright (C) 1994 X Consortium
#
# 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
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Except as contained in this notice, the name of the X Consortium shall not
# be used in advertising or otherwise to promote the sale, use or other deal-
# ings in this Software without prior written authorization from the X Consor-
# tium.
#
#
# FSF changes to this file are in the public domain.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# `make' implicit rules from creating a file called install from it
# when there is no Makefile.
#
# This script is compatible with the BSD install script, but was written
# from scratch. It can only install one file at a time, a restriction
# shared with many OS's install programs.
# set DOITPROG to echo to test this script
# Don't use :- since 4.3BSD and earlier shells don't like it.
doit="${DOITPROG-}"
# put in absolute paths if you don't have them in your path; or use env. vars.
mvprog="${MVPROG-mv}"
cpprog="${CPPROG-cp}"
chmodprog="${CHMODPROG-chmod}"
chownprog="${CHOWNPROG-chown}"
chgrpprog="${CHGRPPROG-chgrp}"
stripprog="${STRIPPROG-strip}"
rmprog="${RMPROG-rm}"
mkdirprog="${MKDIRPROG-mkdir}"
chmodcmd="$chmodprog 0755"
chowncmd=
chgrpcmd=
stripcmd=
rmcmd="$rmprog -f"
mvcmd="$mvprog"
src=
dst=
dir_arg=
dstarg=
no_target_directory=
usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
or: $0 [OPTION]... SRCFILES... DIRECTORY
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
or: $0 [OPTION]... -d DIRECTORIES...
In the 1st form, copy SRCFILE to DSTFILE.
In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
In the 4th, create DIRECTORIES.
Options:
-c (ignored)
-d create directories instead of installing files.
-g GROUP $chgrpprog installed files to GROUP.
-m MODE $chmodprog installed files to MODE.
-o USER $chownprog installed files to USER.
-s $stripprog installed files.
-t DIRECTORY install into DIRECTORY.
-T report an error if DSTFILE is a directory.
--help display this help and exit.
--version display version info and exit.
Environment variables override the default commands:
CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG
"
while test -n "$1"; do
case $1 in
-c) shift
continue;;
-d) dir_arg=true
shift
continue;;
-g) chgrpcmd="$chgrpprog $2"
shift
shift
continue;;
--help) echo "$usage"; exit $?;;
-m) chmodcmd="$chmodprog $2"
shift
shift
continue;;
-o) chowncmd="$chownprog $2"
shift
shift
continue;;
-s) stripcmd=$stripprog
shift
continue;;
-t) dstarg=$2
shift
shift
continue;;
-T) no_target_directory=true
shift
continue;;
--version) echo "$0 $scriptversion"; exit $?;;
*) # When -d is used, all remaining arguments are directories to create.
# When -t is used, the destination is already specified.
test -n "$dir_arg$dstarg" && break
# Otherwise, the last argument is the destination. Remove it from $@.
for arg
do
if test -n "$dstarg"; then
# $@ is not empty: it contains at least $arg.
set fnord "$@" "$dstarg"
shift # fnord
fi
shift # arg
dstarg=$arg
done
break;;
esac
done
if test -z "$1"; then
if test -z "$dir_arg"; then
echo "$0: no input file specified." >&2
exit 1
fi
# It's OK to call `install-sh -d' without argument.
# This can happen when creating conditional directories.
exit 0
fi
for src
do
# Protect names starting with `-'.
case $src in
-*) src=./$src ;;
esac
if test -n "$dir_arg"; then
dst=$src
src=
if test -d "$dst"; then
mkdircmd=:
chmodcmd=
else
mkdircmd=$mkdirprog
fi
else
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if test ! -f "$src" && test ! -d "$src"; then
echo "$0: $src does not exist." >&2
exit 1
fi
if test -z "$dstarg"; then
echo "$0: no destination specified." >&2
exit 1
fi
dst=$dstarg
# Protect names starting with `-'.
case $dst in
-*) dst=./$dst ;;
esac
# If destination is a directory, append the input filename; won't work
# if double slashes aren't ignored.
if test -d "$dst"; then
if test -n "$no_target_directory"; then
echo "$0: $dstarg: Is a directory" >&2
exit 1
fi
dst=$dst/`basename "$src"`
fi
fi
# This sed command emulates the dirname command.
dstdir=`echo "$dst" | sed -e 's,/*$,,;s,[^/]*$,,;s,/*$,,;s,^$,.,'`
# Make sure that the destination directory exists.
# Skip lots of stat calls in the usual case.
if test ! -d "$dstdir"; then
defaultIFS='
'
IFS="${IFS-$defaultIFS}"
oIFS=$IFS
# Some sh's can't handle IFS=/ for some reason.
IFS='%'
set x `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'`
shift
IFS=$oIFS
pathcomp=
while test $# -ne 0 ; do
pathcomp=$pathcomp$1
shift
if test ! -d "$pathcomp"; then
$mkdirprog "$pathcomp"
# mkdir can fail with a `File exist' error in case several
# install-sh are creating the directory concurrently. This
# is OK.
test -d "$pathcomp" || exit
fi
pathcomp=$pathcomp/
done
fi
if test -n "$dir_arg"; then
$doit $mkdircmd "$dst" \
&& { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \
&& { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \
&& { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \
&& { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; }
else
dstfile=`basename "$dst"`
# Make a couple of temp file names in the proper directory.
dsttmp=$dstdir/_inst.$$_
rmtmp=$dstdir/_rm.$$_
# Trap to clean up those temp files at exit.
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
trap '(exit $?); exit' 1 2 13 15
# Copy the file name to the temp name.
$doit $cpprog "$src" "$dsttmp" &&
# and set any options; do chmod last to preserve setuid bits.
#
# If any of these fail, we abort the whole thing. If we want to
# ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $cpprog $src $dsttmp" command.
#
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \
&& { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \
&& { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \
&& { test -z "$chmodcmd" || $doit $chmodcmd "$dsttmp"; } &&
# Now rename the file to the real destination.
{ $doit $mvcmd -f "$dsttmp" "$dstdir/$dstfile" 2>/dev/null \
|| {
# The rename failed, perhaps because mv can't rename something else
# to itself, or perhaps because mv is so ancient that it does not
# support -f.
# Now remove or move aside any old file at destination location.
# We try this two ways since rm can't unlink itself on some
# systems and the destination file might be busy for other
# reasons. In this case, the final cleanup might fail but the new
# file should still install successfully.
{
if test -f "$dstdir/$dstfile"; then
$doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \
|| $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \
|| {
echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2
(exit 1); exit 1
}
else
:
fi
} &&
# Now rename the file to the real destination.
$doit $mvcmd "$dsttmp" "$dstdir/$dstfile"
}
}
fi || { (exit 1); exit 1; }
done
# The final little trick to "correctly" pass the exit status to the exit trap.
{
(exit 0); exit 0
}
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-end: "$"
# End:

462
kbfunc.c
View File

@ -1,47 +1,164 @@
/*
* calmwm - the calm window manager
*
* Copyright (c) 2004 Martin Murray <mmurray@monkey.org>
* All rights reserved.
* calmwm - the calm window manager
*
* $Id$
* Copyright (c) 2004 Martin Murray <mmurray@monkey.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $OpenBSD$
*/
#include "headers.h"
#include <sys/param.h>
#include <sys/queue.h>
#include <dirent.h>
#include <err.h>
#include <errno.h>
#include <paths.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "calmwm.h"
#define KNOWN_HOSTS ".ssh/known_hosts"
#define HASH_MARKER "|1|"
extern sig_atomic_t xev_quit;
void
kbfunc_client_lower(struct client_ctx *cc, void *arg)
kbfunc_client_lower(struct client_ctx *cc, union arg *arg)
{
client_lower(cc);
}
void
kbfunc_client_raise(struct client_ctx *cc, void *arg)
kbfunc_client_raise(struct client_ctx *cc, union arg *arg)
{
client_raise(cc);
}
#define TYPEMASK (CWM_MOVE | CWM_RESIZE | CWM_PTRMOVE)
#define MOVEMASK (CWM_UP | CWM_DOWN | CWM_LEFT | CWM_RIGHT)
void
kbfunc_client_search(struct client_ctx *scratch, void *arg)
kbfunc_moveresize(struct client_ctx *cc, union arg *arg)
{
struct menu_q menuq;
struct client_ctx *cc, *old_cc = client_current();
struct menu *mi;
struct screen_ctx *sc;
int x, y, flags, amt;
u_int mx, my;
if (cc->flags & CLIENT_FREEZE)
return;
sc = cc->sc;
mx = my = 0;
flags = arg->i;
amt = Conf.mamount;
if (flags & CWM_BIGMOVE) {
flags -= CWM_BIGMOVE;
amt = amt * 10;
}
switch (flags & MOVEMASK) {
case CWM_UP:
my -= amt;
break;
case CWM_DOWN:
my += amt;
break;
case CWM_RIGHT:
mx += amt;
break;
case CWM_LEFT:
mx -= amt;
break;
}
switch (flags & TYPEMASK) {
case CWM_MOVE:
cc->geom.y += my;
if (cc->geom.y + cc->geom.height < 0)
cc->geom.y = -cc->geom.height;
if (cc->geom.y > cc->sc->ymax - 1)
cc->geom.y = cc->sc->ymax - 1;
cc->geom.x += mx;
if (cc->geom.x + cc->geom.width < 0)
cc->geom.x = -cc->geom.width;
if (cc->geom.x > cc->sc->xmax - 1)
cc->geom.x = cc->sc->xmax - 1;
cc->geom.x += client_snapcalc(cc->geom.x,
cc->geom.width, cc->sc->xmax,
cc->bwidth, Conf.snapdist);
cc->geom.y += client_snapcalc(cc->geom.y,
cc->geom.height, cc->sc->ymax,
cc->bwidth, Conf.snapdist);
client_move(cc);
xu_ptr_getpos(cc->win, &x, &y);
cc->ptr.y = y + my;
cc->ptr.x = x + mx;
client_ptrwarp(cc);
break;
case CWM_RESIZE:
if ((cc->geom.height += my) < 1)
cc->geom.height = 1;
if ((cc->geom.width += mx) < 1)
cc->geom.width = 1;
client_resize(cc);
/* Make sure the pointer stays within the window. */
xu_ptr_getpos(cc->win, &cc->ptr.x, &cc->ptr.y);
if (cc->ptr.x > cc->geom.width)
cc->ptr.x = cc->geom.width - cc->bwidth;
if (cc->ptr.y > cc->geom.height)
cc->ptr.y = cc->geom.height - cc->bwidth;
client_ptrwarp(cc);
break;
case CWM_PTRMOVE:
xu_ptr_getpos(sc->rootwin, &x, &y);
xu_ptr_setpos(sc->rootwin, x + mx, y + my);
break;
default:
warnx("invalid flags passed to kbfunc_client_moveresize");
}
}
void
kbfunc_client_search(struct client_ctx *cc, union arg *arg)
{
struct screen_ctx *sc;
struct client_ctx *old_cc;
struct menu *mi;
struct menu_q menuq;
sc = cc->sc;
old_cc = client_current();
TAILQ_INIT(&menuq);
TAILQ_FOREACH(cc, &G_clientq, entry) {
struct menu *mi;
XCALLOC(mi, struct menu);
strlcpy(mi->text, cc->name, sizeof(mi->text));
TAILQ_FOREACH(cc, &Clientq, entry) {
mi = xcalloc(1, sizeof(*mi));
(void)strlcpy(mi->text, cc->name, sizeof(mi->text));
mi->ctx = cc;
TAILQ_INSERT_TAIL(&menuq, mi, entry);
}
if ((mi = search_start(&menuq,
search_match_client, NULL,
search_print_client, "window")) != NULL) {
if ((mi = menu_filter(sc, &menuq, "window", NULL, 0,
search_match_client, search_print_client)) != NULL) {
cc = (struct client_ctx *)mi->ctx;
if (cc->flags & CLIENT_HIDDEN)
client_unhide(cc);
@ -58,24 +175,25 @@ kbfunc_client_search(struct client_ctx *scratch, void *arg)
}
void
kbfunc_menu_search(struct client_ctx *scratch, void *arg)
kbfunc_menu_search(struct client_ctx *cc, union arg *arg)
{
struct menu_q menuq;
struct menu *mi;
struct cmd *cmd;
struct screen_ctx *sc;
struct cmd *cmd;
struct menu *mi;
struct menu_q menuq;
sc = cc->sc;
TAILQ_INIT(&menuq);
conf_cmd_refresh(&G_conf);
TAILQ_FOREACH(cmd, &G_conf.cmdq, entry) {
XCALLOC(mi, struct menu);
strlcpy(mi->text, cmd->label, sizeof(mi->text));
TAILQ_FOREACH(cmd, &Conf.cmdq, entry) {
mi = xcalloc(1, sizeof(*mi));
(void)strlcpy(mi->text, cmd->label, sizeof(mi->text));
mi->ctx = cmd;
TAILQ_INSERT_TAIL(&menuq, mi, entry);
}
if ((mi = search_start(&menuq,
search_match_text, NULL, NULL, "application")) != NULL)
if ((mi = menu_filter(sc, &menuq, "application", NULL, 0,
search_match_text, NULL)) != NULL)
u_spawn(((struct cmd *)mi->ctx)->image);
while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
@ -85,102 +203,302 @@ kbfunc_menu_search(struct client_ctx *scratch, void *arg)
}
void
kbfunc_client_cycle(struct client_ctx *cc, void *arg)
kbfunc_client_cycle(struct client_ctx *cc, union arg *arg)
{
client_cyclenext(cc, 0);
struct screen_ctx *sc;
sc = cc->sc;
/* XXX for X apps that ignore events */
XGrabKeyboard(X_Dpy, sc->rootwin, True,
GrabModeAsync, GrabModeAsync, CurrentTime);
client_cycle(sc, arg->i);
}
void
kbfunc_client_rcycle(struct client_ctx *cc, void *arg)
{
client_cyclenext(cc, 1);
}
void
kbfunc_client_hide(struct client_ctx *cc, void *arg)
kbfunc_client_hide(struct client_ctx *cc, union arg *arg)
{
client_hide(cc);
}
void
kbfunc_cmdexec(struct client_ctx *cc, void *arg)
kbfunc_cmdexec(struct client_ctx *cc, union arg *arg)
{
u_spawn((char *)arg);
u_spawn(arg->c);
}
void
kbfunc_term(struct client_ctx *cc, void *arg)
kbfunc_term(struct client_ctx *cc, union arg *arg)
{
conf_cmd_refresh(&G_conf);
u_spawn(G_conf.termpath);
u_spawn(Conf.termpath);
}
void
kbfunc_lock(struct client_ctx *cc, void *arg)
kbfunc_lock(struct client_ctx *cc, union arg *arg)
{
conf_cmd_refresh(&G_conf);
u_spawn(G_conf.lockpath);
u_spawn(Conf.lockpath);
}
void
kbfunc_client_label(struct client_ctx *cc, void *arg)
kbfunc_exec(struct client_ctx *cc, union arg *arg)
{
grab_label(cc);
#define NPATHS 256
struct screen_ctx *sc;
char **ap, *paths[NPATHS], *path, *pathcpy, *label;
char tpath[MAXPATHLEN];
DIR *dirp;
struct dirent *dp;
struct menu *mi;
struct menu_q menuq;
int l, i, cmd = arg->i;
sc = cc->sc;
switch (cmd) {
case CWM_EXEC_PROGRAM:
label = "exec";
break;
case CWM_EXEC_WM:
label = "wm";
break;
default:
err(1, "kbfunc_exec: invalid cmd %d", cmd);
/*NOTREACHED*/
}
TAILQ_INIT(&menuq);
if ((path = getenv("PATH")) == NULL)
path = _PATH_DEFPATH;
pathcpy = path = xstrdup(path);
for (ap = paths; ap < &paths[NPATHS - 1] &&
(*ap = strsep(&pathcpy, ":")) != NULL;) {
if (**ap != '\0')
ap++;
}
*ap = NULL;
for (i = 0; i < NPATHS && paths[i] != NULL; i++) {
if ((dirp = opendir(paths[i])) == NULL)
continue;
while ((dp = readdir(dirp)) != NULL) {
/* skip everything but regular files and symlinks */
if (dp->d_type != DT_REG && dp->d_type != DT_LNK)
continue;
(void)memset(tpath, '\0', sizeof(tpath));
l = snprintf(tpath, sizeof(tpath), "%s/%s", paths[i],
dp->d_name);
/* check for truncation etc */
if (l == -1 || l >= (int)sizeof(tpath))
continue;
if (access(tpath, X_OK) == 0) {
mi = xcalloc(1, sizeof(*mi));
(void)strlcpy(mi->text,
dp->d_name, sizeof(mi->text));
TAILQ_INSERT_TAIL(&menuq, mi, entry);
}
}
(void)closedir(dirp);
}
xfree(path);
if ((mi = menu_filter(sc, &menuq, label, NULL, 1,
search_match_exec, NULL)) != NULL) {
if (mi->text[0] == '\0')
goto out;
switch (cmd) {
case CWM_EXEC_PROGRAM:
u_spawn(mi->text);
break;
case CWM_EXEC_WM:
u_exec(mi->text);
warn("%s", mi->text);
break;
default:
err(1, "kb_func: egad, cmd changed value!");
break;
}
}
out:
if (mi != NULL && mi->dummy)
xfree(mi);
while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
TAILQ_REMOVE(&menuq, mi, entry);
xfree(mi);
}
}
void
kbfunc_client_delete(struct client_ctx *cc, void *arg)
kbfunc_ssh(struct client_ctx *cc, union arg *arg)
{
struct screen_ctx *sc;
struct menu *mi;
struct menu_q menuq;
FILE *fp;
char *buf, *lbuf, *p, *home;
char hostbuf[MAXHOSTNAMELEN], filename[MAXPATHLEN];
char cmd[256];
int l;
size_t len;
sc = cc->sc;
if ((home = getenv("HOME")) == NULL)
return;
l = snprintf(filename, sizeof(filename), "%s/%s", home, KNOWN_HOSTS);
if (l == -1 || l >= sizeof(filename))
return;
if ((fp = fopen(filename, "r")) == NULL)
return;
TAILQ_INIT(&menuq);
lbuf = NULL;
while ((buf = fgetln(fp, &len))) {
if (buf[len - 1] == '\n')
buf[len - 1] = '\0';
else {
/* EOF without EOL, copy and add the NUL */
lbuf = xmalloc(len + 1);
(void)memcpy(lbuf, buf, len);
lbuf[len] = '\0';
buf = lbuf;
}
/* skip hashed hosts */
if (strncmp(buf, HASH_MARKER, strlen(HASH_MARKER)) == 0)
continue;
for (p = buf; *p != ',' && *p != ' ' && p != buf + len; p++) {
/* do nothing */
}
/* ignore badness */
if (p - buf + 1 > sizeof(hostbuf))
continue;
(void)strlcpy(hostbuf, buf, p - buf + 1);
mi = xcalloc(1, sizeof(*mi));
(void)strlcpy(mi->text, hostbuf, sizeof(mi->text));
TAILQ_INSERT_TAIL(&menuq, mi, entry);
}
xfree(lbuf);
(void)fclose(fp);
if ((mi = menu_filter(sc, &menuq, "ssh", NULL, 1,
search_match_exec, NULL)) != NULL) {
if (mi->text[0] == '\0')
goto out;
l = snprintf(cmd, sizeof(cmd), "%s -e ssh %s", Conf.termpath,
mi->text);
if (l != -1 && l < sizeof(cmd))
u_spawn(cmd);
}
out:
if (mi != NULL && mi->dummy)
xfree(mi);
while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
TAILQ_REMOVE(&menuq, mi, entry);
xfree(mi);
}
}
void
kbfunc_client_label(struct client_ctx *cc, union arg *arg)
{
struct menu *mi;
struct menu_q menuq;
TAILQ_INIT(&menuq);
/* dummy is set, so this will always return */
mi = menu_filter(cc->sc, &menuq, "label", cc->label, 1,
search_match_text, NULL);
if (!mi->abort) {
if (cc->label != NULL)
xfree(cc->label);
cc->label = xstrdup(mi->text);
}
xfree(mi);
}
void
kbfunc_client_delete(struct client_ctx *cc, union arg *arg)
{
client_send_delete(cc);
}
void
kbfunc_client_groupselect(struct client_ctx *cc, void *arg)
kbfunc_client_group(struct client_ctx *cc, union arg *arg)
{
if (G_groupmode)
group_done();
else
group_enter();
group_hidetoggle(cc->sc, KBTOGROUP(arg->i));
}
void
kbfunc_client_group(struct client_ctx *cc, void *arg)
kbfunc_client_grouponly(struct client_ctx *cc, union arg *arg)
{
if (G_groupmode)
group_select(KBTOGROUP((int)arg));
else
group_hidetoggle(KBTOGROUP((int)arg));
group_only(cc->sc, KBTOGROUP(arg->i));
}
void
kbfunc_client_nextgroup(struct client_ctx *cc, void *arg)
kbfunc_client_cyclegroup(struct client_ctx *cc, union arg *arg)
{
group_slide(1);
group_cycle(cc->sc, arg->i);
}
void
kbfunc_client_prevgroup(struct client_ctx *cc, void *arg)
kbfunc_client_nogroup(struct client_ctx *cc, union arg *arg)
{
group_slide(0);
group_alltoggle(cc->sc);
}
void
kbfunc_client_nogroup(struct client_ctx *cc, void *arg)
kbfunc_client_grouptoggle(struct client_ctx *cc, union arg *arg)
{
if (G_groupmode)
group_deletecurrent();
else
group_alltoggle();
/* XXX for stupid X apps like xpdf and gvim */
XGrabKeyboard(X_Dpy, cc->win, True,
GrabModeAsync, GrabModeAsync, CurrentTime);
group_sticky_toggle_enter(cc);
}
void
kbfunc_client_maximize(struct client_ctx *cc, void *arg)
kbfunc_client_movetogroup(struct client_ctx *cc, union arg *arg)
{
group_movetogroup(cc, KBTOGROUP(arg->i));
}
void
kbfunc_client_maximize(struct client_ctx *cc, union arg *arg)
{
client_maximize(cc);
}
void
kbfunc_client_vmaximize(struct client_ctx *cc, void *arg)
kbfunc_client_vmaximize(struct client_ctx *cc, union arg *arg)
{
client_vertmaximize(cc);
}
void
kbfunc_client_hmaximize(struct client_ctx *cc, union arg *arg)
{
client_horizmaximize(cc);
}
void
kbfunc_client_freeze(struct client_ctx *cc, union arg *arg)
{
client_freeze(cc);
}
void
kbfunc_quit_wm(struct client_ctx *cc, union arg *arg)
{
xev_quit = 1;
}
void
kbfunc_reload(struct client_ctx *cc, union arg *arg)
{
conf_reload(&Conf);
}

545
menu.c Normal file
View File

@ -0,0 +1,545 @@
/*
* calmwm - the calm window manager
*
* Copyright (c) 2008 Owain G. Ainsworth <oga@openbsd.org>
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $OpenBSD$
*/
#include <sys/param.h>
#include <sys/queue.h>
#include <err.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "calmwm.h"
#define PROMPT_SCHAR "\xc2\xbb"
#define PROMPT_ECHAR "\xc2\xab"
enum ctltype {
CTL_NONE = -1,
CTL_ERASEONE = 0, CTL_WIPE, CTL_UP, CTL_DOWN, CTL_RETURN,
CTL_ABORT, CTL_ALL
};
struct menu_ctx {
char searchstr[MENU_MAXENTRY + 1];
char dispstr[MENU_MAXENTRY*2 + 1];
char promptstr[MENU_MAXENTRY + 1];
int hasprompt;
int list;
int listing;
int changed;
int noresult;
int prev;
int entry;
int width;
int num;
int x;
int y;
void (*match)(struct menu_q *, struct menu_q *, char *);
void (*print)(struct menu *, int);
};
static struct menu *menu_handle_key(XEvent *, struct menu_ctx *,
struct menu_q *, struct menu_q *);
static void menu_handle_move(XEvent *, struct menu_ctx *,
struct screen_ctx *);
static struct menu *menu_handle_release(XEvent *, struct menu_ctx *,
struct screen_ctx *, struct menu_q *);
static void menu_draw(struct screen_ctx *, struct menu_ctx *,
struct menu_q *, struct menu_q *);
static int menu_calc_entry(struct screen_ctx *, struct menu_ctx *,
int, int);
static int menu_keycode(KeyCode, u_int, enum ctltype *,
char *);
void
menu_init(struct screen_ctx *sc)
{
XGCValues gv;
if (sc->menuwin)
XDestroyWindow(X_Dpy, sc->menuwin);
sc->menuwin = XCreateSimpleWindow(X_Dpy, sc->rootwin, 0, 0, 1, 1,
Conf.bwidth,
sc->color[CWM_COLOR_FG_MENU].pixel,
sc->color[CWM_COLOR_BG_MENU].pixel);
gv.foreground =
sc->color[CWM_COLOR_FG_MENU].pixel^sc->color[CWM_COLOR_BG_MENU].pixel;
gv.background = sc->color[CWM_COLOR_BG_MENU].pixel;
gv.function = GXxor;
if (sc->gc)
XFreeGC(X_Dpy, sc->gc);
sc->gc = XCreateGC(X_Dpy, sc->menuwin,
GCForeground|GCBackground|GCFunction, &gv);
}
struct menu *
menu_filter(struct screen_ctx *sc, struct menu_q *menuq, char *prompt,
char *initial, int dummy,
void (*match)(struct menu_q *, struct menu_q *, char *),
void (*print)(struct menu *, int))
{
struct menu_ctx mc;
struct menu_q resultq;
struct menu *mi = NULL;
XEvent e;
Window focuswin;
int evmask, focusrevert;
int xsave, ysave, xcur, ycur;
TAILQ_INIT(&resultq);
bzero(&mc, sizeof(mc));
xu_ptr_getpos(sc->rootwin, &mc.x, &mc.y);
xsave = mc.x;
ysave = mc.y;
if (prompt == NULL) {
evmask = MENUMASK;
mc.promptstr[0] = '\0';
mc.list = 1;
} else {
evmask = MENUMASK | KEYMASK; /* only accept keys if prompt */
(void)snprintf(mc.promptstr, sizeof(mc.promptstr), "%s%s",
prompt, PROMPT_SCHAR);
(void)snprintf(mc.dispstr, sizeof(mc.dispstr), "%s%s%s",
mc.promptstr, mc.searchstr, PROMPT_ECHAR);
mc.width = font_width(sc, mc.dispstr, strlen(mc.dispstr));
mc.hasprompt = 1;
}
if (initial != NULL)
(void)strlcpy(mc.searchstr, initial, sizeof(mc.searchstr));
else
mc.searchstr[0] = '\0';
mc.match = match;
mc.print = print;
mc.entry = mc.prev = -1;
XMoveResizeWindow(X_Dpy, sc->menuwin, mc.x, mc.y, mc.width,
font_height(sc));
XSelectInput(X_Dpy, sc->menuwin, evmask);
XMapRaised(X_Dpy, sc->menuwin);
if (xu_ptr_grab(sc->menuwin, MENUGRABMASK, Cursor_question) < 0) {
XUnmapWindow(X_Dpy, sc->menuwin);
return (NULL);
}
XGetInputFocus(X_Dpy, &focuswin, &focusrevert);
XSetInputFocus(X_Dpy, sc->menuwin, RevertToPointerRoot, CurrentTime);
/* make sure keybindings don't remove keys from the menu stream */
XGrabKeyboard(X_Dpy, sc->menuwin, True,
GrabModeAsync, GrabModeAsync, CurrentTime);
for (;;) {
mc.changed = 0;
XWindowEvent(X_Dpy, sc->menuwin, evmask, &e);
switch (e.type) {
case KeyPress:
if ((mi = menu_handle_key(&e, &mc, menuq, &resultq))
!= NULL)
goto out;
/* FALLTHROUGH */
case Expose:
menu_draw(sc, &mc, menuq, &resultq);
break;
case MotionNotify:
menu_handle_move(&e, &mc, sc);
break;
case ButtonRelease:
if ((mi = menu_handle_release(&e, &mc, sc, &resultq))
!= NULL)
goto out;
break;
default:
break;
}
}
out:
if (dummy == 0 && mi->dummy) { /* no mouse based match */
xfree(mi);
mi = NULL;
}
XSetInputFocus(X_Dpy, focuswin, focusrevert, CurrentTime);
/* restore if user didn't move */
xu_ptr_getpos(sc->rootwin, &xcur, &ycur);
if (xcur == mc.x && ycur == mc.y)
xu_ptr_setpos(sc->rootwin, xsave, ysave);
xu_ptr_ungrab();
XUnmapWindow(X_Dpy, sc->menuwin);
XUngrabKeyboard(X_Dpy, CurrentTime);
return (mi);
}
static struct menu *
menu_handle_key(XEvent *e, struct menu_ctx *mc, struct menu_q *menuq,
struct menu_q *resultq)
{
struct menu *mi;
enum ctltype ctl;
char chr;
size_t len;
if (menu_keycode(e->xkey.keycode, e->xkey.state, &ctl, &chr) < 0)
return (NULL);
switch (ctl) {
case CTL_ERASEONE:
if ((len = strlen(mc->searchstr)) > 0) {
mc->searchstr[len - 1] = '\0';
mc->changed = 1;
}
break;
case CTL_UP:
mi = TAILQ_LAST(resultq, menu_q);
if (mi == NULL)
break;
TAILQ_REMOVE(resultq, mi, resultentry);
TAILQ_INSERT_HEAD(resultq, mi, resultentry);
break;
case CTL_DOWN:
mi = TAILQ_FIRST(resultq);
if (mi == NULL)
break;
TAILQ_REMOVE(resultq, mi, resultentry);
TAILQ_INSERT_TAIL(resultq, mi, resultentry);
break;
case CTL_RETURN:
/*
* Return whatever the cursor is currently on. Else
* even if dummy is zero, we need to return something.
*/
if ((mi = TAILQ_FIRST(resultq)) == NULL) {
mi = xmalloc(sizeof *mi);
(void)strlcpy(mi->text,
mc->searchstr, sizeof(mi->text));
mi->dummy = 1;
}
mi->abort = 0;
return (mi);
case CTL_WIPE:
mc->searchstr[0] = '\0';
mc->changed = 1;
break;
case CTL_ALL:
mc->list = !mc->list;
break;
case CTL_ABORT:
mi = xmalloc(sizeof *mi);
mi->text[0] = '\0';
mi->dummy = 1;
mi->abort = 1;
return (mi);
default:
break;
}
if (chr != '\0') {
char str[2];
str[0] = chr;
str[1] = '\0';
mc->changed = 1;
(void)strlcat(mc->searchstr, str, sizeof(mc->searchstr));
}
mc->noresult = 0;
if (mc->changed && mc->searchstr[0] != '\0') {
(*mc->match)(menuq, resultq, mc->searchstr);
/* If menuq is empty, never show we've failed */
mc->noresult = TAILQ_EMPTY(resultq) && !TAILQ_EMPTY(menuq);
} else if (mc->changed)
TAILQ_INIT(resultq);
if (!mc->list && mc->listing && !mc->changed) {
TAILQ_INIT(resultq);
mc->listing = 0;
}
return (NULL);
}
static void
menu_draw(struct screen_ctx *sc, struct menu_ctx *mc, struct menu_q *menuq,
struct menu_q *resultq)
{
struct menu *mi;
XineramaScreenInfo *xine;
int xmin, xmax, ymin, ymax;
int n, dy, xsave, ysave;
if (mc->list) {
if (TAILQ_EMPTY(resultq) && mc->list) {
/* Copy them all over. */
TAILQ_FOREACH(mi, menuq, entry)
TAILQ_INSERT_TAIL(resultq, mi,
resultentry);
mc->listing = 1;
} else if (mc->changed)
mc->listing = 0;
}
mc->num = 0;
mc->width = 0;
dy = 0;
if (mc->hasprompt) {
(void)snprintf(mc->dispstr, sizeof(mc->dispstr), "%s%s%s",
mc->promptstr, mc->searchstr, PROMPT_ECHAR);
mc->width = font_width(sc, mc->dispstr, strlen(mc->dispstr));
dy = font_height(sc);
mc->num = 1;
}
TAILQ_FOREACH(mi, resultq, resultentry) {
char *text;
if (mc->print != NULL) {
(*mc->print)(mi, mc->listing);
text = mi->print;
} else {
mi->print[0] = '\0';
text = mi->text;
}
mc->width = MAX(mc->width, font_width(sc, text,
MIN(strlen(text), MENU_MAXENTRY)));
dy += font_height(sc);
mc->num++;
}
xine = screen_find_xinerama(sc, mc->x, mc->y);
if (xine) {
xmin = xine->x_org;
xmax = xine->x_org + xine->width;
ymin = xine->y_org;
ymax = xine->y_org + xine->height;
} else {
xmin = ymin = 0;
xmax = sc->xmax;
ymax = sc->ymax;
}
xsave = mc->x;
ysave = mc->y;
if (mc->x < xmin)
mc->x = xmin;
else if (mc->x + mc->width >= xmax)
mc->x = xmax - mc->width;
if (mc->y + dy >= ymax)
mc->y = ymax - dy;
/* never hide the top of the menu */
if (mc->y < ymin) {
mc->y = ymin;
dy = ymax - ymin;
}
if (mc->x != xsave || mc->y != ysave)
xu_ptr_setpos(sc->rootwin, mc->x, mc->y);
XClearWindow(X_Dpy, sc->menuwin);
XMoveResizeWindow(X_Dpy, sc->menuwin, mc->x, mc->y, mc->width, dy);
if (mc->hasprompt) {
font_draw(sc, mc->dispstr, strlen(mc->dispstr), sc->menuwin,
0, font_ascent(sc) + 1);
n = 1;
} else
n = 0;
TAILQ_FOREACH(mi, resultq, resultentry) {
char *text = mi->print[0] != '\0' ?
mi->print : mi->text;
font_draw(sc, text, MIN(strlen(text), MENU_MAXENTRY),
sc->menuwin, 0, n * font_height(sc) + font_ascent(sc) + 1);
n++;
}
if (mc->hasprompt && n > 1 && (mc->searchstr[0] != '\0'))
XFillRectangle(X_Dpy, sc->menuwin, sc->gc,
0, font_height(sc), mc->width, font_height(sc));
if (mc->noresult)
XFillRectangle(X_Dpy, sc->menuwin, sc->gc,
0, 0, mc->width, font_height(sc));
}
static void
menu_handle_move(XEvent *e, struct menu_ctx *mc, struct screen_ctx *sc)
{
mc->prev = mc->entry;
mc->entry = menu_calc_entry(sc, mc, e->xbutton.x, e->xbutton.y);
if (mc->prev != -1)
XFillRectangle(X_Dpy, sc->menuwin, sc->gc, 0,
font_height(sc) * mc->prev, mc->width, font_height(sc));
if (mc->entry != -1) {
(void)xu_ptr_regrab(MENUGRABMASK, Cursor_normal);
XFillRectangle(X_Dpy, sc->menuwin, sc->gc, 0,
font_height(sc) * mc->entry, mc->width, font_height(sc));
} else
(void)xu_ptr_regrab(MENUGRABMASK, Cursor_default);
}
static struct menu *
menu_handle_release(XEvent *e, struct menu_ctx *mc, struct screen_ctx *sc,
struct menu_q *resultq)
{
struct menu *mi;
int entry, i = 0;
entry = menu_calc_entry(sc, mc, e->xbutton.x, e->xbutton.y);
if (mc->hasprompt)
i = 1;
TAILQ_FOREACH(mi, resultq, resultentry)
if (entry == i++)
break;
if (mi == NULL) {
mi = xmalloc(sizeof(*mi));
mi->text[0] = '\0';
mi->dummy = 1;
}
return (mi);
}
static int
menu_calc_entry(struct screen_ctx *sc, struct menu_ctx *mc, int x, int y)
{
int entry;
entry = y / font_height(sc);
/* in bounds? */
if (x <= 0 || x > mc->width || y <= 0 ||
y > font_height(sc) * mc->num || entry < 0 || entry >= mc->num)
entry = -1;
if (mc->hasprompt && entry == 0)
entry = -1;
return (entry);
}
static int
menu_keycode(KeyCode kc, u_int state, enum ctltype *ctl, char *chr)
{
int ks;
*ctl = CTL_NONE;
*chr = '\0';
ks = XKeycodeToKeysym(X_Dpy, kc, (state & ShiftMask) ? 1 : 0);
/* Look for control characters. */
switch (ks) {
case XK_BackSpace:
*ctl = CTL_ERASEONE;
break;
case XK_Return:
*ctl = CTL_RETURN;
break;
case XK_Up:
*ctl = CTL_UP;
break;
case XK_Down:
*ctl = CTL_DOWN;
break;
case XK_Escape:
*ctl = CTL_ABORT;
break;
}
if (*ctl == CTL_NONE && (state & ControlMask)) {
switch (ks) {
case XK_s:
case XK_S:
/* Emacs "next" */
*ctl = CTL_DOWN;
break;
case XK_r:
case XK_R:
/* Emacs "previous" */
*ctl = CTL_UP;
break;
case XK_u:
case XK_U:
*ctl = CTL_WIPE;
break;
case XK_h:
case XK_H:
*ctl = CTL_ERASEONE;
break;
case XK_a:
case XK_A:
*ctl = CTL_ALL;
break;
}
}
if (*ctl == CTL_NONE && (state & Mod1Mask)) {
switch (ks) {
case XK_j:
case XK_J:
/* Vi "down" */
*ctl = CTL_DOWN;
break;
case XK_k:
case XK_K:
/* Vi "up" */
*ctl = CTL_UP;
break;
}
}
if (*ctl != CTL_NONE)
return (0);
/*
* For regular characters, only (part of, actually) Latin 1
* for now.
*/
if (ks < 0x20 || ks > 0x07e)
return (-1);
*chr = (char)ks;
return (0);
}

360
missing
View File

@ -1,360 +0,0 @@
#! /bin/sh
# Common stub for a few missing GNU programs while installing.
scriptversion=2005-06-08.21
# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005
# Free Software Foundation, Inc.
# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
# 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, 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.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
if test $# -eq 0; then
echo 1>&2 "Try \`$0 --help' for more information"
exit 1
fi
run=:
# In the cases where this matters, `missing' is being run in the
# srcdir already.
if test -f configure.ac; then
configure_ac=configure.ac
else
configure_ac=configure.in
fi
msg="missing on your system"
case "$1" in
--run)
# Try to run requested program, and just exit if it succeeds.
run=
shift
"$@" && exit 0
# Exit code 63 means version mismatch. This often happens
# when the user try to use an ancient version of a tool on
# a file that requires a minimum version. In this case we
# we should proceed has if the program had been absent, or
# if --run hadn't been passed.
if test $? = 63; then
run=:
msg="probably too old"
fi
;;
-h|--h|--he|--hel|--help)
echo "\
$0 [OPTION]... PROGRAM [ARGUMENT]...
Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
error status if there is no known handling for PROGRAM.
Options:
-h, --help display this help and exit
-v, --version output version information and exit
--run try to run the given command, and emulate it if it fails
Supported PROGRAM values:
aclocal touch file \`aclocal.m4'
autoconf touch file \`configure'
autoheader touch file \`config.h.in'
automake touch all \`Makefile.in' files
bison create \`y.tab.[ch]', if possible, from existing .[ch]
flex create \`lex.yy.c', if possible, from existing .c
help2man touch the output file
lex create \`lex.yy.c', if possible, from existing .c
makeinfo touch the output file
tar try tar, gnutar, gtar, then tar without non-portable flags
yacc create \`y.tab.[ch]', if possible, from existing .[ch]
Send bug reports to <bug-automake@gnu.org>."
exit $?
;;
-v|--v|--ve|--ver|--vers|--versi|--versio|--version)
echo "missing $scriptversion (GNU Automake)"
exit $?
;;
-*)
echo 1>&2 "$0: Unknown \`$1' option"
echo 1>&2 "Try \`$0 --help' for more information"
exit 1
;;
esac
# Now exit if we have it, but it failed. Also exit now if we
# don't have it and --version was passed (most likely to detect
# the program).
case "$1" in
lex|yacc)
# Not GNU programs, they don't have --version.
;;
tar)
if test -n "$run"; then
echo 1>&2 "ERROR: \`tar' requires --run"
exit 1
elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
exit 1
fi
;;
*)
if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
# We have it, but it failed.
exit 1
elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
# Could not run --version or --help. This is probably someone
# running `$TOOL --version' or `$TOOL --help' to check whether
# $TOOL exists and not knowing $TOOL uses missing.
exit 1
fi
;;
esac
# If it does not exist, or fails to run (possibly an outdated version),
# try to emulate it.
case "$1" in
aclocal*)
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified \`acinclude.m4' or \`${configure_ac}'. You might want
to install the \`Automake' and \`Perl' packages. Grab them from
any GNU archive site."
touch aclocal.m4
;;
autoconf)
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified \`${configure_ac}'. You might want to install the
\`Autoconf' and \`GNU m4' packages. Grab them from any GNU
archive site."
touch configure
;;
autoheader)
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified \`acconfig.h' or \`${configure_ac}'. You might want
to install the \`Autoconf' and \`GNU m4' packages. Grab them
from any GNU archive site."
files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}`
test -z "$files" && files="config.h"
touch_files=
for f in $files; do
case "$f" in
*:*) touch_files="$touch_files "`echo "$f" |
sed -e 's/^[^:]*://' -e 's/:.*//'`;;
*) touch_files="$touch_files $f.in";;
esac
done
touch $touch_files
;;
automake*)
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'.
You might want to install the \`Automake' and \`Perl' packages.
Grab them from any GNU archive site."
find . -type f -name Makefile.am -print |
sed 's/\.am$/.in/' |
while read f; do touch "$f"; done
;;
autom4te)
echo 1>&2 "\
WARNING: \`$1' is needed, but is $msg.
You might have modified some files without having the
proper tools for further handling them.
You can get \`$1' as part of \`Autoconf' from any GNU
archive site."
file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'`
test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'`
if test -f "$file"; then
touch $file
else
test -z "$file" || exec >$file
echo "#! /bin/sh"
echo "# Created by GNU Automake missing as a replacement of"
echo "# $ $@"
echo "exit 0"
chmod +x $file
exit 1
fi
;;
bison|yacc)
echo 1>&2 "\
WARNING: \`$1' $msg. You should only need it if
you modified a \`.y' file. You may need the \`Bison' package
in order for those modifications to take effect. You can get
\`Bison' from any GNU archive site."
rm -f y.tab.c y.tab.h
if [ $# -ne 1 ]; then
eval LASTARG="\${$#}"
case "$LASTARG" in
*.y)
SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
if [ -f "$SRCFILE" ]; then
cp "$SRCFILE" y.tab.c
fi
SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
if [ -f "$SRCFILE" ]; then
cp "$SRCFILE" y.tab.h
fi
;;
esac
fi
if [ ! -f y.tab.h ]; then
echo >y.tab.h
fi
if [ ! -f y.tab.c ]; then
echo 'main() { return 0; }' >y.tab.c
fi
;;
lex|flex)
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified a \`.l' file. You may need the \`Flex' package
in order for those modifications to take effect. You can get
\`Flex' from any GNU archive site."
rm -f lex.yy.c
if [ $# -ne 1 ]; then
eval LASTARG="\${$#}"
case "$LASTARG" in
*.l)
SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
if [ -f "$SRCFILE" ]; then
cp "$SRCFILE" lex.yy.c
fi
;;
esac
fi
if [ ! -f lex.yy.c ]; then
echo 'main() { return 0; }' >lex.yy.c
fi
;;
help2man)
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified a dependency of a manual page. You may need the
\`Help2man' package in order for those modifications to take
effect. You can get \`Help2man' from any GNU archive site."
file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
if test -z "$file"; then
file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'`
fi
if [ -f "$file" ]; then
touch $file
else
test -z "$file" || exec >$file
echo ".ab help2man is required to generate this page"
exit 1
fi
;;
makeinfo)
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified a \`.texi' or \`.texinfo' file, or any other file
indirectly affecting the aspect of the manual. The spurious
call might also be the consequence of using a buggy \`make' (AIX,
DU, IRIX). You might want to install the \`Texinfo' package or
the \`GNU make' package. Grab either from any GNU archive site."
# The file to touch is that specified with -o ...
file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
if test -z "$file"; then
# ... or it is the one specified with @setfilename ...
infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $infile`
# ... or it is derived from the source name (dir/f.texi becomes f.info)
test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info
fi
# If the file does not exist, the user really needs makeinfo;
# let's fail without touching anything.
test -f $file || exit 1
touch $file
;;
tar)
shift
# We have already tried tar in the generic part.
# Look for gnutar/gtar before invocation to avoid ugly error
# messages.
if (gnutar --version > /dev/null 2>&1); then
gnutar "$@" && exit 0
fi
if (gtar --version > /dev/null 2>&1); then
gtar "$@" && exit 0
fi
firstarg="$1"
if shift; then
case "$firstarg" in
*o*)
firstarg=`echo "$firstarg" | sed s/o//`
tar "$firstarg" "$@" && exit 0
;;
esac
case "$firstarg" in
*h*)
firstarg=`echo "$firstarg" | sed s/h//`
tar "$firstarg" "$@" && exit 0
;;
esac
fi
echo 1>&2 "\
WARNING: I can't seem to be able to run \`tar' with the given arguments.
You may want to install GNU tar or Free paxutils, or check the
command line arguments."
exit 1
;;
*)
echo 1>&2 "\
WARNING: \`$1' is needed, and is $msg.
You might have modified some files without having the
proper tools for further handling them. Check the \`README' file,
it often tells you about the needed prerequisites for installing
this package. You may also peek at any GNU archive site, in case
some other package would contain this missing \`$1' program."
exit 1
;;
esac
exit 0
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-end: "$"
# End:

289
mousefunc.c Normal file
View File

@ -0,0 +1,289 @@
/*
* calmwm - the calm window manager
*
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
* Copyright (c) 2008 rivo nurges <rix@estpak.ee>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $OpenBSD$
*/
#include <sys/param.h>
#include <sys/queue.h>
#include <err.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "calmwm.h"
static int mousefunc_sweep_calc(struct client_ctx *, int, int, int, int);
static void mousefunc_sweep_draw(struct client_ctx *);
static int
mousefunc_sweep_calc(struct client_ctx *cc, int x, int y, int mx, int my)
{
int width = cc->geom.width, height = cc->geom.height;
cc->geom.width = abs(x - mx) - cc->bwidth;
cc->geom.height = abs(y - my) - cc->bwidth;
client_applysizehints(cc);
cc->geom.x = x <= mx ? x : x - cc->geom.width;
cc->geom.y = y <= my ? y : y - cc->geom.height;
return (width != cc->geom.width || height != cc->geom.height);
}
static void
mousefunc_sweep_draw(struct client_ctx *cc)
{
struct screen_ctx *sc = cc->sc;
char asize[10]; /* fits "nnnnxnnnn\0" */
int width, width_size, width_name;
(void)snprintf(asize, sizeof(asize), "%dx%d",
(cc->geom.width - cc->hint.basew) / cc->hint.incw,
(cc->geom.height - cc->hint.baseh) / cc->hint.inch);
width_size = font_width(sc, asize, strlen(asize)) + 4;
width_name = font_width(sc, cc->name, strlen(cc->name)) + 4;
width = MAX(width_size, width_name);
XReparentWindow(X_Dpy, sc->menuwin, cc->win, 0, 0);
XMoveResizeWindow(X_Dpy, sc->menuwin, 0, 0, width, font_height(sc) * 2);
XMapWindow(X_Dpy, sc->menuwin);
XClearWindow(X_Dpy, sc->menuwin);
font_draw(sc, cc->name, strlen(cc->name), sc->menuwin,
2, font_ascent(sc) + 1);
font_draw(sc, asize, strlen(asize), sc->menuwin,
width / 2 - width_size / 2, font_height(sc) + font_ascent(sc) + 1);
}
void
mousefunc_window_resize(struct client_ctx *cc, void *arg)
{
XEvent ev;
Time ltime = 0;
struct screen_ctx *sc = cc->sc;
int x = cc->geom.x, y = cc->geom.y;
if (cc->flags & CLIENT_FREEZE)
return;
client_raise(cc);
client_ptrsave(cc);
if (xu_ptr_grab(cc->win, MOUSEMASK, Cursor_resize) < 0)
return;
xu_ptr_setpos(cc->win, cc->geom.width, cc->geom.height);
mousefunc_sweep_draw(cc);
for (;;) {
XMaskEvent(X_Dpy, MOUSEMASK|ExposureMask, &ev);
switch (ev.type) {
case Expose:
client_draw_border(cc);
break;
case MotionNotify:
if (mousefunc_sweep_calc(cc, x, y,
ev.xmotion.x_root, ev.xmotion.y_root))
/* Recompute window output */
mousefunc_sweep_draw(cc);
/* don't resize more than 60 times / second */
if ((ev.xmotion.time - ltime) > (1000 / 60)) {
ltime = ev.xmotion.time;
client_resize(cc);
}
break;
case ButtonRelease:
if (ltime)
client_resize(cc);
XUnmapWindow(X_Dpy, sc->menuwin);
XReparentWindow(X_Dpy, sc->menuwin, sc->rootwin, 0, 0);
xu_ptr_ungrab();
/* Make sure the pointer stays within the window. */
if (cc->ptr.x > cc->geom.width)
cc->ptr.x = cc->geom.width - cc->bwidth;
if (cc->ptr.y > cc->geom.height)
cc->ptr.y = cc->geom.height - cc->bwidth;
client_ptrwarp(cc);
return;
}
}
/* NOTREACHED */
}
void
mousefunc_window_move(struct client_ctx *cc, void *arg)
{
XEvent ev;
Time ltime = 0;
int px, py;
client_raise(cc);
if (cc->flags & CLIENT_FREEZE)
return;
if (xu_ptr_grab(cc->win, MOUSEMASK, Cursor_move) < 0)
return;
xu_ptr_getpos(cc->win, &px, &py);
for (;;) {
XMaskEvent(X_Dpy, MOUSEMASK|ExposureMask, &ev);
switch (ev.type) {
case Expose:
client_draw_border(cc);
break;
case MotionNotify:
cc->geom.x = ev.xmotion.x_root - px - cc->bwidth;
cc->geom.y = ev.xmotion.y_root - py - cc->bwidth;
cc->geom.x += client_snapcalc(cc->geom.x,
cc->geom.width, cc->sc->xmax,
cc->bwidth, Conf.snapdist);
cc->geom.y += client_snapcalc(cc->geom.y,
cc->geom.height, cc->sc->ymax,
cc->bwidth, Conf.snapdist);
/* don't move more than 60 times / second */
if ((ev.xmotion.time - ltime) > (1000 / 60)) {
ltime = ev.xmotion.time;
client_move(cc);
}
break;
case ButtonRelease:
if (ltime)
client_move(cc);
xu_ptr_ungrab();
return;
}
}
/* NOTREACHED */
}
void
mousefunc_window_grouptoggle(struct client_ctx *cc, void *arg)
{
group_sticky_toggle_enter(cc);
}
void
mousefunc_window_lower(struct client_ctx *cc, void *arg)
{
client_ptrsave(cc);
client_lower(cc);
}
void
mousefunc_window_raise(struct client_ctx *cc, void *arg)
{
client_raise(cc);
}
void
mousefunc_window_hide(struct client_ctx *cc, void *arg)
{
client_hide(cc);
}
void
mousefunc_menu_group(struct client_ctx *cc, void *arg)
{
group_menu(arg);
}
void
mousefunc_menu_unhide(struct client_ctx *cc, void *arg)
{
struct screen_ctx *sc;
struct client_ctx *old_cc;
struct menu *mi;
struct menu_q menuq;
char *wname;
sc = cc->sc;
old_cc = client_current();
TAILQ_INIT(&menuq);
TAILQ_FOREACH(cc, &Clientq, entry)
if (cc->flags & CLIENT_HIDDEN) {
wname = (cc->label) ? cc->label : cc->name;
if (wname == NULL)
continue;
mi = xcalloc(1, sizeof(*mi));
(void)strlcpy(mi->text, wname, sizeof(mi->text));
mi->ctx = cc;
TAILQ_INSERT_TAIL(&menuq, mi, entry);
}
if (TAILQ_EMPTY(&menuq))
return;
mi = menu_filter(sc, &menuq, NULL, NULL, 0, NULL, NULL);
if (mi != NULL) {
cc = (struct client_ctx *)mi->ctx;
client_unhide(cc);
if (old_cc != NULL)
client_ptrsave(old_cc);
client_ptrwarp(cc);
} else {
while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
TAILQ_REMOVE(&menuq, mi, entry);
xfree(mi);
}
}
}
void
mousefunc_menu_cmd(struct client_ctx *cc, void *arg)
{
struct screen_ctx *sc;
struct menu *mi;
struct menu_q menuq;
struct cmd *cmd;
sc = cc->sc;
TAILQ_INIT(&menuq);
TAILQ_FOREACH(cmd, &Conf.cmdq, entry) {
mi = xcalloc(1, sizeof(*mi));
(void)strlcpy(mi->text, cmd->label, sizeof(mi->text));
mi->ctx = cmd;
TAILQ_INSERT_TAIL(&menuq, mi, entry);
}
if (TAILQ_EMPTY(&menuq))
return;
mi = menu_filter(sc, &menuq, NULL, NULL, 0, NULL, NULL);
if (mi != NULL)
u_spawn(((struct cmd *)mi->ctx)->image);
else
while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
TAILQ_REMOVE(&menuq, mi, entry);
xfree(mi);
}
}

586
parse.y Normal file
View File

@ -0,0 +1,586 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
* Copyright (c) 2001 Markus Friedl. All rights reserved.
* Copyright (c) 2001 Daniel Hartmeier. All rights reserved.
* Copyright (c) 2001 Theo de Raadt. All rights reserved.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
%{
#include <sys/param.h>
#include <sys/queue.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "calmwm.h"
TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files);
static struct file {
TAILQ_ENTRY(file) entry;
FILE *stream;
char *name;
int lineno;
int errors;
} *file;
struct file *pushfile(const char *);
int popfile(void);
int yyparse(void);
int yylex(void);
int yyerror(const char *, ...);
int kw_cmp(const void *, const void *);
int lookup(char *);
int lgetc(int);
int lungetc(int);
int findeol(void);
static struct conf *conf;
typedef struct {
union {
int64_t number;
char *string;
} v;
int lineno;
} YYSTYPE;
%}
%token FONTNAME STICKY GAP MOUSEBIND
%token AUTOGROUP BIND COMMAND IGNORE
%token YES NO BORDERWIDTH MOVEAMOUNT
%token COLOR SNAPDIST
%token ACTIVEBORDER INACTIVEBORDER
%token GROUPBORDER UNGROUPBORDER
%token MENUBG MENUFG FONTCOLOR
%token ERROR
%token <v.string> STRING
%token <v.number> NUMBER
%type <v.number> yesno
%type <v.string> string
%%
grammar : /* empty */
| grammar '\n'
| grammar main '\n'
| grammar color '\n'
| grammar error '\n' { file->errors++; }
;
string : string STRING {
if (asprintf(&$$, "%s %s", $1, $2) == -1) {
free($1);
free($2);
yyerror("string: asprintf");
YYERROR;
}
free($1);
free($2);
}
| STRING
;
yesno : YES { $$ = 1; }
| NO { $$ = 0; }
;
main : FONTNAME STRING {
free(conf->font);
conf->font = $2;
}
| STICKY yesno {
if ($2 == 0)
conf->flags &= ~CONF_STICKY_GROUPS;
else
conf->flags |= CONF_STICKY_GROUPS;
}
| BORDERWIDTH NUMBER {
conf->bwidth = $2;
}
| MOVEAMOUNT NUMBER {
conf->mamount = $2;
}
| SNAPDIST NUMBER {
conf->snapdist = $2;
}
| COMMAND STRING string {
conf_cmd_add(conf, $3, $2, 0);
free($2);
free($3);
}
| AUTOGROUP NUMBER STRING {
if ($2 < 0 || $2 > 9) {
free($3);
yyerror("autogroup number out of range: %d", $2);
YYERROR;
}
group_make_autogroup(conf, $3, $2);
free($3);
}
| IGNORE STRING {
struct winmatch *wm;
wm = xcalloc(1, sizeof(*wm));
(void)strlcpy(wm->title, $2, sizeof(wm->title));
TAILQ_INSERT_TAIL(&conf->ignoreq, wm, entry);
free($2);
}
| BIND STRING string {
conf_bindname(conf, $2, $3);
free($2);
free($3);
}
| GAP NUMBER NUMBER NUMBER NUMBER {
conf->gap.top = $2;
conf->gap.bottom = $3;
conf->gap.left = $4;
conf->gap.right = $5;
}
| MOUSEBIND STRING string {
conf_mousebind(conf, $2, $3);
free($2);
free($3);
}
;
color : COLOR colors
;
colors : ACTIVEBORDER STRING {
free(conf->color[CWM_COLOR_BORDER_ACTIVE].name);
conf->color[CWM_COLOR_BORDER_ACTIVE].name = $2;
}
| INACTIVEBORDER STRING {
free(conf->color[CWM_COLOR_BORDER_INACTIVE].name);
conf->color[CWM_COLOR_BORDER_INACTIVE].name = $2;
}
| GROUPBORDER STRING {
free(conf->color[CWM_COLOR_BORDER_GROUP].name);
conf->color[CWM_COLOR_BORDER_GROUP].name = $2;
}
| UNGROUPBORDER STRING {
free(conf->color[CWM_COLOR_BORDER_UNGROUP].name);
conf->color[CWM_COLOR_BORDER_UNGROUP].name = $2;
}
| MENUBG STRING {
free(conf->color[CWM_COLOR_BG_MENU].name);
conf->color[CWM_COLOR_BG_MENU].name = $2;
}
| MENUFG STRING {
free(conf->color[CWM_COLOR_FG_MENU].name);
conf->color[CWM_COLOR_FG_MENU].name = $2;
}
| FONTCOLOR STRING {
free(conf->color[CWM_COLOR_FONT].name);
conf->color[CWM_COLOR_FONT].name = $2;
}
;
%%
struct keywords {
const char *k_name;
int k_val;
};
int
yyerror(const char *fmt, ...)
{
va_list ap;
file->errors++;
va_start(ap, fmt);
fprintf(stderr, "%s:%d: ", file->name, yylval.lineno);
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
va_end(ap);
return (0);
}
int
kw_cmp(const void *k, const void *e)
{
return (strcmp(k, ((const struct keywords *)e)->k_name));
}
int
lookup(char *s)
{
/* this has to be sorted always */
static const struct keywords keywords[] = {
{ "activeborder", ACTIVEBORDER},
{ "autogroup", AUTOGROUP},
{ "bind", BIND},
{ "borderwidth", BORDERWIDTH},
{ "color", COLOR},
{ "command", COMMAND},
{ "font", FONTCOLOR},
{ "fontname", FONTNAME},
{ "gap", GAP},
{ "groupborder", GROUPBORDER},
{ "ignore", IGNORE},
{ "inactiveborder", INACTIVEBORDER},
{ "menubg", MENUBG},
{ "menufg", MENUFG},
{ "mousebind", MOUSEBIND},
{ "moveamount", MOVEAMOUNT},
{ "no", NO},
{ "snapdist", SNAPDIST},
{ "sticky", STICKY},
{ "ungroupborder", UNGROUPBORDER},
{ "yes", YES}
};
const struct keywords *p;
p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
sizeof(keywords[0]), kw_cmp);
if (p)
return (p->k_val);
else
return (STRING);
}
#define MAXPUSHBACK 128
char *parsebuf;
int parseindex;
char pushback_buffer[MAXPUSHBACK];
int pushback_index = 0;
int
lgetc(int quotec)
{
int c, next;
if (parsebuf) {
/* Read character from the parsebuffer instead of input. */
if (parseindex >= 0) {
c = parsebuf[parseindex++];
if (c != '\0')
return (c);
parsebuf = NULL;
} else
parseindex++;
}
if (pushback_index)
return (pushback_buffer[--pushback_index]);
if (quotec) {
if ((c = getc(file->stream)) == EOF) {
yyerror("reached end of file while parsing quoted string");
if (popfile() == EOF)
return (EOF);
return (quotec);
}
return (c);
}
while ((c = getc(file->stream)) == '\\') {
next = getc(file->stream);
if (next != '\n') {
c = next;
break;
}
yylval.lineno = file->lineno;
file->lineno++;
}
while (c == EOF) {
if (popfile() == EOF)
return (EOF);
c = getc(file->stream);
}
return (c);
}
int
lungetc(int c)
{
if (c == EOF)
return (EOF);
if (parsebuf) {
parseindex--;
if (parseindex >= 0)
return (c);
}
if (pushback_index < MAXPUSHBACK-1)
return (pushback_buffer[pushback_index++] = c);
else
return (EOF);
}
int
findeol(void)
{
int c;
parsebuf = NULL;
pushback_index = 0;
/* skip to either EOF or the first real EOL */
while (1) {
c = lgetc(0);
if (c == '\n') {
file->lineno++;
break;
}
if (c == EOF)
break;
}
return (ERROR);
}
int
yylex(void)
{
char buf[8096];
char *p;
int quotec, next, c;
int token;
p = buf;
while ((c = lgetc(0)) == ' ' || c == '\t')
; /* nothing */
yylval.lineno = file->lineno;
if (c == '#')
while ((c = lgetc(0)) != '\n' && c != EOF)
; /* nothing */
switch (c) {
case '\'':
case '"':
quotec = c;
while (1) {
if ((c = lgetc(quotec)) == EOF)
return (0);
if (c == '\n') {
file->lineno++;
continue;
} else if (c == '\\') {
if ((next = lgetc(quotec)) == EOF)
return (0);
if (next == quotec || c == ' ' || c == '\t')
c = next;
else if (next == '\n') {
file->lineno++;
continue;
} else
lungetc(next);
} else if (c == quotec) {
*p = '\0';
break;
}
if (p + 1 >= buf + sizeof(buf) - 1) {
yyerror("string too long");
return (findeol());
}
*p++ = (char)c;
}
yylval.v.string = xstrdup(buf);
return (STRING);
}
#define allowed_to_end_number(x) \
(isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
if (c == '-' || isdigit(c)) {
do {
*p++ = c;
if ((unsigned)(p-buf) >= sizeof(buf)) {
yyerror("string too long");
return (findeol());
}
} while ((c = lgetc(0)) != EOF && isdigit(c));
lungetc(c);
if (p == buf + 1 && buf[0] == '-')
goto nodigits;
if (c == EOF || allowed_to_end_number(c)) {
const char *errstr = NULL;
*p = '\0';
yylval.v.number = strtonum(buf, LLONG_MIN,
LLONG_MAX, &errstr);
if (errstr) {
yyerror("\"%s\" invalid number: %s",
buf, errstr);
return (findeol());
}
return (NUMBER);
} else {
nodigits:
while (p > buf + 1)
lungetc(*--p);
c = *--p;
if (c == '-')
return (c);
}
}
#define allowed_in_string(x) \
(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
x != '{' && x != '}' && x != '<' && x != '>' && \
x != '!' && x != '=' && x != '#' && x != ','))
if (isalnum(c) || c == ':' || c == '_' || c == '*' || c == '/') {
do {
*p++ = c;
if ((unsigned)(p-buf) >= sizeof(buf)) {
yyerror("string too long");
return (findeol());
}
} while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
lungetc(c);
*p = '\0';
if ((token = lookup(buf)) == STRING)
yylval.v.string = xstrdup(buf);
return (token);
}
if (c == '\n') {
yylval.lineno = file->lineno;
file->lineno++;
}
if (c == EOF)
return (0);
return (c);
}
struct file *
pushfile(const char *name)
{
struct file *nfile;
nfile = xcalloc(1, sizeof(struct file));
nfile->name = xstrdup(name);
if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
free(nfile->name);
free(nfile);
return (NULL);
}
nfile->lineno = 1;
TAILQ_INSERT_TAIL(&files, nfile, entry);
return (nfile);
}
int
popfile(void)
{
struct file *prev;
if ((prev = TAILQ_PREV(file, files, entry)) != NULL) {
prev->errors += file->errors;
TAILQ_REMOVE(&files, file, entry);
fclose(file->stream);
free(file->name);
free(file);
file = prev;
return (0);
}
return (EOF);
}
int
parse_config(const char *filename, struct conf *xconf)
{
int errors = 0;
conf = xcalloc(1, sizeof(*conf));
if ((file = pushfile(filename)) == NULL) {
free(conf);
return (-1);
}
(void)strlcpy(conf->conf_path, filename, sizeof(conf->conf_path));
conf_init(conf);
yyparse();
errors = file->errors;
file->errors = 0;
popfile();
if (errors) {
conf_clear(conf);
}
else {
struct autogroupwin *ag;
struct keybinding *kb;
struct winmatch *wm;
struct cmd *cmd;
struct mousebinding *mb;
int i;
conf_clear(xconf);
xconf->flags = conf->flags;
xconf->bwidth = conf->bwidth;
xconf->mamount = conf->mamount;
xconf->snapdist = conf->snapdist;
xconf->gap = conf->gap;
while ((cmd = TAILQ_FIRST(&conf->cmdq)) != NULL) {
TAILQ_REMOVE(&conf->cmdq, cmd, entry);
TAILQ_INSERT_TAIL(&xconf->cmdq, cmd, entry);
}
while ((kb = TAILQ_FIRST(&conf->keybindingq)) != NULL) {
TAILQ_REMOVE(&conf->keybindingq, kb, entry);
TAILQ_INSERT_TAIL(&xconf->keybindingq, kb, entry);
}
while ((ag = TAILQ_FIRST(&conf->autogroupq)) != NULL) {
TAILQ_REMOVE(&conf->autogroupq, ag, entry);
TAILQ_INSERT_TAIL(&xconf->autogroupq, ag, entry);
}
while ((wm = TAILQ_FIRST(&conf->ignoreq)) != NULL) {
TAILQ_REMOVE(&conf->ignoreq, wm, entry);
TAILQ_INSERT_TAIL(&xconf->ignoreq, wm, entry);
}
while ((mb = TAILQ_FIRST(&conf->mousebindingq)) != NULL) {
TAILQ_REMOVE(&conf->mousebindingq, mb, entry);
TAILQ_INSERT_TAIL(&xconf->mousebindingq, mb, entry);
}
(void)strlcpy(xconf->termpath, conf->termpath,
sizeof(xconf->termpath));
(void)strlcpy(xconf->lockpath, conf->lockpath,
sizeof(xconf->lockpath));
for (i = 0; i < CWM_COLOR_MAX; i++)
xconf->color[i].name = conf->color[i].name;
xconf->font = conf->font;
}
free(conf);
return (errors ? -1 : 0);
}

136
screen.c
View File

@ -2,52 +2,55 @@
* calmwm - the calm window manager
*
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
* All rights reserved.
*
* $Id$
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $OpenBSD$
*/
#include "headers.h"
#include <sys/param.h>
#include <sys/queue.h>
#include <err.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "calmwm.h"
extern struct screen_ctx_q G_screenq;
extern struct screen_ctx *G_curscreen;
static void
_clearwindow_cb(int sig)
{
struct screen_ctx *sc = screen_current();
XUnmapWindow(G_dpy, sc->infowin);
}
struct screen_ctx *
screen_fromroot(Window rootwin)
{
struct screen_ctx *sc;
struct screen_ctx *sc;
TAILQ_FOREACH(sc, &G_screenq, entry)
TAILQ_FOREACH(sc, &Screenq, entry)
if (sc->rootwin == rootwin)
return (sc);
/* XXX FAIL HERE */
return (TAILQ_FIRST(&G_screenq));
}
struct screen_ctx *
screen_current(void)
{
return (G_curscreen);
return (TAILQ_FIRST(&Screenq));
}
void
screen_updatestackingorder(void)
screen_updatestackingorder(struct screen_ctx *sc)
{
Window *wins, w0, w1;
struct screen_ctx *sc = screen_current();
u_int nwins, i, s;
struct client_ctx *cc;
Window *wins, w0, w1;
struct client_ctx *cc;
u_int nwins, i, s;
if (!XQueryTree(G_dpy, sc->rootwin, &w0, &w1, &wins, &nwins))
if (!XQueryTree(X_Dpy, sc->rootwin, &w0, &w1, &wins, &nwins))
return;
for (s = 0, i = 0; i < nwins; i++) {
@ -63,41 +66,68 @@ screen_updatestackingorder(void)
}
void
screen_init(void)
screen_init_xinerama(struct screen_ctx *sc)
{
XineramaScreenInfo *info;
int no;
struct screen_ctx *sc = screen_current();
if (HasXinerama == 0 || XineramaIsActive(X_Dpy) == 0) {
HasXinerama = 0;
sc->xinerama_no = 0;
}
sc->cycle_client = NULL;
info = XineramaQueryScreens(X_Dpy, &no);
if (info == NULL) {
/* Is xinerama actually off, instead of a malloc failure? */
if (sc->xinerama == NULL)
HasXinerama = 0;
return;
}
sc->infowin = XCreateSimpleWindow(G_dpy, sc->rootwin, 0, 0,
1, 1, 1, sc->blackpixl, sc->whitepixl);
if (sc->xinerama != NULL)
XFree(sc->xinerama);
sc->xinerama = info;
sc->xinerama_no = no;
}
/* XXX - marius. */
if (signal(SIGALRM, _clearwindow_cb) == SIG_ERR)
err(1, "signal");
/*
* Find which xinerama screen the coordinates (x,y) is on.
*/
XineramaScreenInfo *
screen_find_xinerama(struct screen_ctx *sc, int x, int y)
{
XineramaScreenInfo *info;
int i;
for (i = 0; i < sc->xinerama_no; i++) {
info = &sc->xinerama[i];
if (x >= info->x_org && x < info->x_org + info->width &&
y >= info->y_org && y < info->y_org + info->height)
return (info);
}
return (NULL);
}
void
screen_infomsg(char *msg)
screen_update_geometry(struct screen_ctx *sc, int width, int height)
{
struct screen_ctx *sc = screen_current();
char buf[1024];
int dy, dx;
struct fontdesc *font = DefaultFont;
long geom[2], workareas[CALMWM_NGROUPS][4];
int i;
XUnmapWindow(G_dpy, sc->infowin);
alarm(0);
sc->xmax = geom[0] = width;
sc->ymax = geom[1] = height;
XChangeProperty(X_Dpy, sc->rootwin, _NET_DESKTOP_GEOMETRY,
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)geom , 2);
snprintf(buf, sizeof(buf), ">%s", msg);
dy = font_ascent(font) + font_descent(font) + 1;
dx = font_width(font, buf, strlen(buf));
/* x, y, width, height. */
for (i = 0; i < CALMWM_NGROUPS; i++) {
workareas[i][0] = sc->gap.left;
workareas[i][1] = sc->gap.top;
workareas[i][2] = width - (sc->gap.left + sc->gap.right);
workareas[i][3] = height - (sc->gap.top + sc->gap.bottom);
}
XMoveResizeWindow(G_dpy, sc->infowin, 0, 0, dx, dy);
XMapRaised(G_dpy, sc->infowin);
font_draw(font, buf, strlen(buf), sc->infowin,
0, font_ascent(font) + 1);
alarm(1);
XChangeProperty(X_Dpy, sc->rootwin, _NET_WORKAREA,
XA_CARDINAL, 32, PropModeReplace,
(unsigned char *)workareas, CALMWM_NGROUPS * 4);
}

396
search.c
View File

@ -2,282 +2,37 @@
* calmwm - the calm window manager
*
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
* All rights reserved.
*
* $Id$
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $OpenBSD$
*/
#include "headers.h"
#include <sys/param.h>
#include <sys/queue.h>
#include <assert.h>
#include <err.h>
#include <errno.h>
#include <fnmatch.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "calmwm.h"
#define SearchMask (KeyPressMask|ExposureMask)
static int _strsubmatch(char *, char *);
void
search_init(struct screen_ctx *sc)
{
sc->searchwin = XCreateSimpleWindow(G_dpy, sc->rootwin, 0, 0,
1, 1, 1, sc->blackpixl, sc->whitepixl);
}
/*
* ranking. each rank type is assigned a weight. multiply this by
* the rank given. add them up. simple linear combination.
*/
/*
* Input: list of items,
* Output: choose one
* so, exactly like menus
*/
struct menu *
search_start(struct menu_q *menuq,
void (*match)(struct menu_q *, struct menu_q *, char *),
void (*rank)(struct menu_q *resultq, char *search),
void (*print)(struct menu *mi, int print),
char *prompt)
{
struct screen_ctx *sc = screen_current();
int x, y, dx, dy, fontheight,
focusrevert, mutated, xmax, ymax, warp, added, beobnoxious = 0;
XEvent e;
char searchstr[MENU_MAXENTRY + 1];
char dispstr[MENU_MAXENTRY*2 + 1];
char promptstr[MENU_MAXENTRY + 1];
Window focuswin;
struct menu *mi = NULL;
struct menu_q resultq;
char chr;
enum ctltype ctl;
size_t len;
u_int n;
static int list = 0;
int listing = 0;
char endchar = '<EFBFBD>';
struct fontdesc *font = DefaultFont;
if (prompt == NULL)
prompt = "search";
TAILQ_INIT(&resultq);
xmax = DisplayWidth(G_dpy, sc->which);
ymax = DisplayHeight(G_dpy, sc->which);
xu_ptr_getpos(sc->rootwin, &x, &y);
searchstr[0] = '\0';
snprintf(promptstr, sizeof(promptstr), "%s <20>", prompt);
dy = fontheight = font_ascent(font) + font_descent(font) + 1;
snprintf(dispstr, sizeof(dispstr), "%s%c", promptstr, endchar);
dx = font_width(font, dispstr, strlen(dispstr));
XMoveResizeWindow(G_dpy, sc->searchwin, x, y, dx, dy);
XSelectInput(G_dpy, sc->searchwin, SearchMask);
XMapRaised(G_dpy, sc->searchwin);
/*
* TODO: eventually, the mouse should be able to select
* results as well. Right now we grab it only to set a fancy
* cursor.
*/
if (xu_ptr_grab(sc->searchwin, 0, G_cursor_question) < 0) {
XUnmapWindow(G_dpy, sc->searchwin);
return (NULL);
}
XGetInputFocus(G_dpy, &focuswin, &focusrevert);
XSetInputFocus(G_dpy, sc->searchwin, RevertToPointerRoot, CurrentTime);
for (;;) {
added = mutated = 0;
XMaskEvent(G_dpy, SearchMask, &e);
switch (e.type) {
case KeyPress:
/*
* XXX - C-s & C-r for next and prev.
*/
if (input_keycodetrans(e.xkey.keycode, e.xkey.state,
&ctl, &chr, 1) < 0)
continue;
switch (ctl) {
case CTL_ERASEONE:
if ((len = strlen(searchstr)) > 0) {
searchstr[len - 1] = '\0';
mutated = 1;
}
break;
case CTL_UP:
mi = TAILQ_LAST(&resultq, menu_q);
if (mi == NULL)
break;
TAILQ_REMOVE(&resultq, mi, resultentry);
TAILQ_INSERT_HEAD(&resultq, mi, resultentry);
break;
case CTL_DOWN:
mi = TAILQ_FIRST(&resultq);
if (mi == NULL)
break;
TAILQ_REMOVE(&resultq, mi, resultentry);
TAILQ_INSERT_TAIL(&resultq, mi, resultentry);
break;
case CTL_RETURN:
/* This is just picking the match the
* cursor is over. */
if ((mi = TAILQ_FIRST(&resultq)) != NULL)
goto found;
else
goto out;
case CTL_WIPE:
searchstr[0] = '\0';
mutated = 1;
break;
case CTL_ALL:
list = !list;
break;
case CTL_ABORT:
goto out;
default:
break;
}
if (chr != '\0') {
char str[2];
str[0] = chr;
str[1] = '\0';
mutated = 1;
added =
strlcat(searchstr, str, sizeof(searchstr));
}
beobnoxious = 0;
if (mutated && strlen(searchstr) > 0) {
(*match)(menuq, &resultq, searchstr);
beobnoxious = TAILQ_EMPTY(&resultq);
if (!beobnoxious && rank != NULL)
(*rank)(&resultq, searchstr);
} else if (mutated)
TAILQ_INIT(&resultq);
if (!list && listing && !mutated) {
TAILQ_INIT(&resultq);
listing = 0;
}
case Expose:
if (list) {
if (TAILQ_EMPTY(&resultq) && list) {
/* Copy them over and rank them. */
TAILQ_FOREACH(mi, menuq, entry)
TAILQ_INSERT_TAIL(&resultq, mi,
resultentry);
if (rank != NULL)
(*rank)(&resultq, searchstr);
listing = 1;
} else if (mutated)
listing = 0;
}
snprintf(dispstr, sizeof(dispstr), "%s%s%c",
promptstr, searchstr, endchar);
dx = font_width(font, dispstr, strlen(dispstr));
dy = fontheight;
TAILQ_FOREACH(mi, &resultq, resultentry) {
char *text;
if (print != NULL) {
(*print)(mi, listing);
text = mi->print;
} else {
mi->print[0] = '\0';
text = mi->text;
}
dx = MAX(dx, font_width(font, text,
MIN(strlen(text), MENU_MAXENTRY)));
dy += fontheight;
}
/*
* Calculate new geometry.
*
* XXX - put this into a util function -- it's
* used elsewhere, too.
*/
warp = 0;
if (x < 0) {
x = 0;
warp = 1;
}
if (x + dx >= xmax) {
x = xmax - dx;
warp = 1;
}
if (y < 0) {
y = 0;
warp = 1;
}
if (y + dy >= ymax) {
y = ymax - dy;
warp = 1;
}
if (warp)
xu_ptr_setpos(sc->rootwin, x, y);
XClearWindow(G_dpy, sc->searchwin);
XMoveResizeWindow(G_dpy, sc->searchwin, x, y, dx, dy);
font_draw(font, dispstr, strlen(dispstr), sc->searchwin,
0, font_ascent(font) + 1);
n = 1;
TAILQ_FOREACH(mi, &resultq, resultentry) {
char *text = mi->print[0] != '\0' ?
mi->print : mi->text;
font_draw(font, text,
MIN(strlen(text), MENU_MAXENTRY),
sc->searchwin,
0, n*fontheight + font_ascent(font) + 1);
n++;
}
if (n > 1)
XFillRectangle(G_dpy, sc->searchwin, sc->gc,
0, fontheight, dx, fontheight);
if (beobnoxious)
XFillRectangle(G_dpy, sc->searchwin, sc->gc,
0, 0, dx, fontheight);
break;
}
}
out:
/* (if no match) */
xu_ptr_ungrab();
XSetInputFocus(G_dpy, focuswin, focusrevert, CurrentTime);
found:
XUnmapWindow(G_dpy, sc->searchwin);
return (mi);
}
static int strsubmatch(char *, char *, int);
/*
* Match: label, title, class.
@ -286,13 +41,12 @@ found:
void
search_match_client(struct menu_q *menuq, struct menu_q *resultq, char *search)
{
struct winname *wn;
struct menu *mi, *tierp[4], *before = NULL;
int ntiers = sizeof(tierp)/sizeof(tierp[0]);
struct winname *wn;
struct menu *mi, *tierp[4], *before = NULL;
TAILQ_INIT(resultq);
memset(tierp, 0, sizeof(tierp));
(void)memset(tierp, 0, sizeof(tierp));
/*
* In order of rank:
@ -307,27 +61,23 @@ search_match_client(struct menu_q *menuq, struct menu_q *resultq, char *search)
struct client_ctx *cc = mi->ctx;
/* First, try to match on labels. */
if (cc->label != NULL && _strsubmatch(search, cc->label)) {
if (cc->label != NULL && strsubmatch(search, cc->label, 0)) {
cc->matchname = cc->label;
tier = 0;
}
}
/* Then, on window names. */
if (tier < 0) {
TAILQ_FOREACH_REVERSE(wn, &cc->nameq, winname_q, entry)
if (_strsubmatch(search, wn->name)) {
cc->matchname = wn->name;
tier = 2;
break;
}
if (strsubmatch(search, wn->name, 0)) {
cc->matchname = wn->name;
tier = 2;
break;
}
}
/*
* See if there is a match on the window class
* name.
*/
if (tier < 0 && _strsubmatch(search, cc->app_class)) {
/* Then if there is a match on the window class name. */
if (tier < 0 && strsubmatch(search, cc->app_class, 0)) {
cc->matchname = cc->app_class;
tier = 3;
}
@ -340,16 +90,14 @@ search_match_client(struct menu_q *menuq, struct menu_q *resultq, char *search)
* window. Furthermore, this is denoted by a "!" when
* printing the window name in the search menu.
*/
if (cc == client_current() && tier < ntiers - 1)
if (cc == client_current() && tier < nitems(tierp) - 1)
tier++;
/*
* Clients that are hidden get ranked one up.
*/
/* Clients that are hidden get ranked one up. */
if (cc->flags & CLIENT_HIDDEN && tier > 0)
tier--;
assert(tier < ntiers);
assert(tier < nitems(tierp));
/*
* If you have a tierp, insert after it, and make it
@ -358,7 +106,6 @@ search_match_client(struct menu_q *menuq, struct menu_q *resultq, char *search)
* Always make your current tierp the newly inserted
* entry.
*/
for (t = tier; t >= 0 && ((before = tierp[t]) == NULL); t--)
;
@ -374,8 +121,10 @@ search_match_client(struct menu_q *menuq, struct menu_q *resultq, char *search)
void
search_print_client(struct menu *mi, int list)
{
struct client_ctx *cc = mi->ctx;
char flag = ' ';
struct client_ctx *cc;
char flag = ' ';
cc = mi->ctx;
if (cc == client_current())
flag = '!';
@ -383,15 +132,18 @@ search_print_client(struct menu *mi, int list)
flag = '&';
if (list)
cc->matchname = TAILQ_FIRST(&cc->nameq)->name;
cc->matchname = cc->name;
snprintf(mi->print, sizeof(mi->print), "%c%s", flag, cc->matchname);
(void)snprintf(mi->print, sizeof(mi->print), "%c%s", flag,
cc->matchname);
if (!list && cc->matchname != cc->name &&
strlen(mi->print) < sizeof(mi->print) - 1) {
int diff = sizeof(mi->print) - 1 - strlen(mi->print);
const char *marker = "";
char buf[MENU_MAXENTRY + 1];
const char *marker = "";
char buf[MENU_MAXENTRY + 1];
int diff;
diff = sizeof(mi->print) - 1 - strlen(mi->print);
/* One for the ':' */
diff -= 1;
@ -403,8 +155,8 @@ search_print_client(struct menu *mi, int list)
diff = strlen(cc->name);
}
strlcpy(buf, mi->print, sizeof(buf));
snprintf(mi->print, sizeof(mi->print),
(void)strlcpy(buf, mi->print, sizeof(buf));
(void)snprintf(mi->print, sizeof(mi->print),
"%s:%.*s%s", buf, diff, cc->name, marker);
}
}
@ -412,26 +164,43 @@ search_print_client(struct menu *mi, int list)
void
search_match_text(struct menu_q *menuq, struct menu_q *resultq, char *search)
{
struct menu *mi;
struct menu *mi;
TAILQ_INIT(resultq);
TAILQ_FOREACH(mi, menuq, entry)
if (_strsubmatch(search, mi->text))
if (strsubmatch(search, mi->text, 0))
TAILQ_INSERT_TAIL(resultq, mi, resultentry);
}
void
search_rank_text(struct menu_q *resultq, char *search)
search_match_exec(struct menu_q *menuq, struct menu_q *resultq, char *search)
{
return;
struct menu *mi, *mj;
TAILQ_INIT(resultq);
TAILQ_FOREACH(mi, menuq, entry) {
if (strsubmatch(search, mi->text, 1) == 0 &&
fnmatch(search, mi->text, 0) == FNM_NOMATCH)
continue;
for (mj = TAILQ_FIRST(resultq); mj != NULL;
mj = TAILQ_NEXT(mj, resultentry)) {
if (strcasecmp(mi->text, mj->text) < 0) {
TAILQ_INSERT_BEFORE(mj, mi, resultentry);
break;
}
}
if (mj == NULL)
TAILQ_INSERT_TAIL(resultq, mi, resultentry);
}
}
static int
_strsubmatch(char *sub, char *str)
strsubmatch(char *sub, char *str, int zeroidx)
{
size_t len, sublen;
u_int n;
size_t len, sublen;
u_int n, flen;
if (sub == NULL || str == NULL)
return (0);
@ -442,7 +211,12 @@ _strsubmatch(char *sub, char *str)
if (sublen > len)
return (0);
for (n = 0; n <= len - sublen; n++)
if (!zeroidx)
flen = len - sublen;
else
flen = 0;
for (n = 0; n <= flen; n++)
if (strncasecmp(sub, str + n, sublen) == 0)
return (1);

View File

@ -1,79 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *rcsid = "$OpenBSD$";
#endif /* LIBC_SCCS and not lint */
#if defined(__sun__)
#include <sys/socket.h>
#endif /* __sun__ */
#include <sys/types.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
#include <string.h>
/*
* Appends src to string dst of size siz (unlike strncat, siz is the
* full size of dst, not space left). At most siz-1 characters
* will be copied. Always NUL terminates (unless siz <= strlen(dst)).
* Returns strlen(src) + MIN(siz, strlen(initial dst)).
* If retval >= siz, truncation occurred.
*/
size_t
strlcat(char *dst,const char *src, size_t siz)
{
register char *d = dst;
register const char *s = src;
register size_t n = siz;
size_t dlen;
/* Find the end of dst and adjust bytes left but don't go past end */
while (n-- != 0 && *d != '\0')
d++;
dlen = d - dst;
n = siz - dlen;
if (n == 0)
return(dlen + strlen(s));
while (*s != '\0') {
if (n != 1) {
*d++ = *s;
n--;
}
s++;
}
*d = '\0';
return(dlen + (s - src)); /* count does not include NUL */
}

View File

@ -1,71 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *rcsid = "$OpenBSD$";
#endif /* LIBC_SCCS and not lint */
#include <sys/types.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
#include <string.h>
/*
* Copy src to string dst of size siz. At most siz-1 characters
* will be copied. Always NUL terminates (unless siz == 0).
* Returns strlen(src); if retval >= siz, truncation occurred.
*/
size_t
strlcpy(char *dst, const char *src, size_t siz)
{
register char *d = dst;
register const char *s = src;
register size_t n = siz;
/* Copy as many bytes as will fit */
if (n != 0 && --n != 0) {
do {
if ((*d++ = *s++) == 0)
break;
} while (--n != 0);
}
/* Not enough room in dst, add NUL and traverse rest of src */
if (n == 0) {
if (siz != 0)
*d = '\0'; /* NUL-terminate dst */
while (*s++)
;
}
return(s - src - 1); /* count does not include NUL */
}

View File

@ -1,95 +0,0 @@
/* $OpenBSD$ */
/*-
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if !defined(HAVE_STRSEP)
#include <sys/types.h>
#include <string.h>
#include <stdio.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
#if defined(LIBC_SCCS) && !defined(lint)
#if 0
static char sccsid[] = "@(#)strsep.c 8.1 (Berkeley) 6/4/93";
#else
static char *rcsid = "$OpenBSD$";
#endif
#endif /* LIBC_SCCS and not lint */
/*
* Get next token from string *stringp, where tokens are possibly-empty
* strings separated by characters from delim.
*
* Writes NULs into the string at *stringp to end tokens.
* delim need not remain constant from call to call.
* On return, *stringp points past the last NUL written (if there might
* be further tokens), or is NULL (if there are definitely no more tokens).
*
* If *stringp is NULL, strsep returns NULL.
*/
char *
strsep(char **stringp, const char *delim)
{
register char *s;
register const char *spanp;
register int c, sc;
char *tok;
if ((s = *stringp) == NULL)
return (NULL);
for (tok = s;;) {
c = *s++;
spanp = delim;
do {
if ((sc = *spanp++) == c) {
if (c == 0)
s = NULL;
else
s[-1] = 0;
*stringp = s;
return (tok);
}
} while (sc != 0);
}
/* NOTREACHED */
}
#endif /* !defined(HAVE_STRSEP) */

103
util.c
View File

@ -2,71 +2,80 @@
* calmwm - the calm window manager
*
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
* All rights reserved.
*
* $Id$
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $OpenBSD$
*/
#include "headers.h"
#include <sys/param.h>
#include <sys/queue.h>
#include <err.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "calmwm.h"
#define MAXARGLEN 20
int
void
u_spawn(char *argstr)
{
char *args[MAXARGLEN], **ap;
char **end = &args[MAXARGLEN - 1];
switch (fork()) {
case 0:
ap = args;
while (ap < end && (*ap = strsep(&argstr, " \t")) != NULL)
ap++;
*ap = NULL;
setsid();
execvp(args[0], args);
err(1, args[0]);
u_exec(argstr);
err(1, "%s", argstr);
break;
case -1:
warn("fork");
return (-1);
default:
break;
}
return (0);
}
int dirent_exists(char *filename) {
struct stat buffer;
void
u_exec(char *argstr)
{
char *args[MAXARGLEN], **ap = args;
char **end = &args[MAXARGLEN - 1], *tmp;
return stat(filename, &buffer);
while (ap < end && (*ap = strsep(&argstr, " \t")) != NULL) {
if (**ap == '\0')
continue;
ap++;
if (argstr != NULL) {
/* deal with quoted strings */
switch(argstr[0]) {
case '"':
case '\'':
if ((tmp = strchr(argstr + 1, argstr[0]))
!= NULL) {
*(tmp++) = '\0';
*(ap++) = ++argstr;
argstr = tmp;
}
break;
default:
break;
}
}
}
*ap = NULL;
(void)setsid();
(void)execvp(args[0], args);
}
int dirent_isdir(char *filename) {
struct stat buffer;
int return_value;
return_value = stat(filename, &buffer);
if(return_value == -1)
return 0;
else
return S_ISDIR(buffer.st_mode);
}
int dirent_islink(char *filename) {
struct stat buffer;
int return_value;
return_value = lstat(filename, &buffer);
if(return_value == -1)
return 0;
else
return S_ISLNK(buffer.st_mode);
}

710
xevents.c
View File

@ -2,9 +2,20 @@
* calmwm - the calm window manager
*
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
* All rights reserved.
*
* $Id$
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $OpenBSD$
*/
/*
@ -13,96 +24,119 @@
* management of the xevent's.
*/
#include "headers.h"
#include <sys/param.h>
#include <sys/queue.h>
#include <err.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "calmwm.h"
void _sendxmsg(Window, Atom, long);
static void xev_handle_maprequest(XEvent *);
static void xev_handle_unmapnotify(XEvent *);
static void xev_handle_destroynotify(XEvent *);
static void xev_handle_configurerequest(XEvent *);
static void xev_handle_propertynotify(XEvent *);
static void xev_handle_enternotify(XEvent *);
static void xev_handle_leavenotify(XEvent *);
static void xev_handle_buttonpress(XEvent *);
static void xev_handle_buttonrelease(XEvent *);
static void xev_handle_keypress(XEvent *);
static void xev_handle_keyrelease(XEvent *);
static void xev_handle_expose(XEvent *);
static void xev_handle_clientmessage(XEvent *);
static void xev_handle_randr(XEvent *);
static void xev_handle_mappingnotify(XEvent *);
/*
* NOTE: in reality, many of these should move to client.c now that
* we've got this nice event layer.
*/
void
xev_handle_maprequest(struct xevent *xev, XEvent *ee)
void (*xev_handlers[LASTEvent])(XEvent *) = {
[MapRequest] = xev_handle_maprequest,
[UnmapNotify] = xev_handle_unmapnotify,
[ConfigureRequest] = xev_handle_configurerequest,
[PropertyNotify] = xev_handle_propertynotify,
[EnterNotify] = xev_handle_enternotify,
[LeaveNotify] = xev_handle_leavenotify,
[ButtonPress] = xev_handle_buttonpress,
[ButtonRelease] = xev_handle_buttonrelease,
[KeyPress] = xev_handle_keypress,
[KeyRelease] = xev_handle_keyrelease,
[Expose] = xev_handle_expose,
[DestroyNotify] = xev_handle_destroynotify,
[ClientMessage] = xev_handle_clientmessage,
[MappingNotify] = xev_handle_mappingnotify,
};
static void
xev_handle_maprequest(XEvent *ee)
{
XMapRequestEvent *e = &ee->xmaprequest;
struct client_ctx *cc = NULL, *old_cc = client_current();
XWindowAttributes xattr;
struct screen_ctx *sc;
#ifdef notyet
int state;
#endif
XMapRequestEvent *e = &ee->xmaprequest;
struct client_ctx *cc = NULL, *old_cc;
XWindowAttributes xattr;
if (old_cc != NULL)
if ((old_cc = client_current()) != NULL)
client_ptrsave(old_cc);
if ((cc = client_find(e->window)) == NULL) {
XGetWindowAttributes(G_dpy, e->window, &xattr);
if ((cc = client_find(e->window)) == NULL) {
XGetWindowAttributes(X_Dpy, e->window, &xattr);
cc = client_new(e->window, screen_fromroot(xattr.root), 1);
sc = CCTOSC(cc);
} else {
cc->beepbeep = 1;
}
#ifdef notyet /* XXX - possibly, we shouldn't map if
* the window is withdrawn. */
if (xu_getstate(cc, &state) == 0 && state == WithdrawnState)
warnx("WITHDRAWNSTATE for %s", cc->name);
#endif
client_ptrwarp(cc);
xev_register(xev);
if ((cc->flags & CLIENT_IGNORE) == 0)
client_ptrwarp(cc);
}
void
xev_handle_unmapnotify(struct xevent *xev, XEvent *ee)
static void
xev_handle_unmapnotify(XEvent *ee)
{
XUnmapEvent *e = &ee->xunmap;
struct client_ctx *cc;
struct screen_ctx *sc;
int wascurrent;
XUnmapEvent *e = &ee->xunmap;
XEvent ev;
struct client_ctx *cc;
/* XXX, we need a recursive locking wrapper around grab server */
XGrabServer(X_Dpy);
if ((cc = client_find(e->window)) != NULL) {
sc = CCTOSC(cc);
wascurrent = cc == client_current();
client_delete(cc, e->send_event, 0);
#ifdef notyet
/* XXX disable the ptrwarp until we handle it
* better. */
if (!client_delete(cc, e->send_event, 0) && wascurrent)
;/* client_ptrwarp(new_cc); */
#endif
/*
* If it's going to die anyway, nuke it.
*
* Else, if it's a synthetic event delete state, since they
* want it to be withdrawn. ICCM recommends you withdraw on
* this even if we haven't alredy been told to iconify, to
* deal with legacy clients.
*/
if (XCheckTypedWindowEvent(X_Dpy, cc->win,
DestroyNotify, &ev) || e->send_event != 0) {
client_delete(cc);
} else
client_hide(cc);
}
xev_register(xev);
XUngrabServer(X_Dpy);
}
void
xev_handle_destroynotify(struct xevent *xev, XEvent *ee)
static void
xev_handle_destroynotify(XEvent *ee)
{
XDestroyWindowEvent *e = &ee->xdestroywindow;
struct client_ctx *cc;
XDestroyWindowEvent *e = &ee->xdestroywindow;
struct client_ctx *cc;
if ((cc = client_find(e->window)) != NULL)
client_delete(cc, 1, 1);
xev_register(xev);
client_delete(cc);
}
void
xev_handle_configurerequest(struct xevent *xev, XEvent *ee)
static void
xev_handle_configurerequest(XEvent *ee)
{
XConfigureRequestEvent *e = &ee->xconfigurerequest;
struct client_ctx *cc;
struct screen_ctx *sc;
XWindowChanges wc;
XConfigureRequestEvent *e = &ee->xconfigurerequest;
struct client_ctx *cc;
struct screen_ctx *sc;
XWindowChanges wc;
if ((cc = client_find(e->window)) != NULL) {
sc = CCTOSC(cc);
sc = cc->sc;
client_gravitate(cc, 0);
if (e->value_mask & CWWidth)
cc->geom.width = e->width;
if (e->value_mask & CWHeight)
@ -111,266 +145,146 @@ xev_handle_configurerequest(struct xevent *xev, XEvent *ee)
cc->geom.x = e->x;
if (e->value_mask & CWY)
cc->geom.y = e->y;
if (e->value_mask & CWBorderWidth)
wc.border_width = e->border_width;
if (cc->geom.x == 0 &&
cc->geom.width >= DisplayWidth(G_dpy, sc->which))
if (cc->geom.x == 0 && cc->geom.width >= sc->xmax)
cc->geom.x -= cc->bwidth;
if (cc->geom.y == 0 &&
cc->geom.height >= DisplayHeight(G_dpy, sc->which))
cc->geom.y -= cc->bwidth;
if (cc->geom.y == 0 && cc->geom.height >= sc->ymax)
cc->geom.y -= cc->bwidth;
client_gravitate(cc, 1);
wc.x = cc->geom.x;
wc.y = cc->geom.y;
wc.width = cc->geom.width;
wc.height = cc->geom.height;
wc.border_width = cc->bwidth;
wc.x = cc->geom.x - cc->bwidth;
wc.y = cc->geom.y - cc->bwidth;
wc.width = cc->geom.width + cc->bwidth*2;
wc.height = cc->geom.height + cc->bwidth*2;
wc.border_width = 0;
XConfigureWindow(X_Dpy, cc->win, e->value_mask, &wc);
xu_configure(cc);
} else {
/* let it do what it wants, it'll be ours when we map it. */
wc.x = e->x;
wc.y = e->y;
wc.width = e->width;
wc.height = e->height;
wc.border_width = e->border_width;
wc.stack_mode = Above;
e->value_mask &= ~CWStackMode;
/* We need to move the parent window, too. */
XConfigureWindow(G_dpy, cc->pwin, e->value_mask, &wc);
xev_reconfig(cc);
XConfigureWindow(X_Dpy, e->window, e->value_mask, &wc);
}
wc.x = cc != NULL ? 0 : e->x;
wc.y = cc != NULL ? 0 : e->y;
wc.width = e->width;
wc.height = e->height;
wc.stack_mode = Above;
wc.border_width = 0;
e->value_mask &= ~CWStackMode;
e->value_mask |= CWBorderWidth;
XConfigureWindow(G_dpy, e->window, e->value_mask, &wc);
xev_register(xev);
}
void
xev_handle_propertynotify(struct xevent *xev, XEvent *ee)
static void
xev_handle_propertynotify(XEvent *ee)
{
XPropertyEvent *e = &ee->xproperty;
struct client_ctx *cc;
long tmp;
XPropertyEvent *e = &ee->xproperty;
struct screen_ctx *sc;
struct client_ctx *cc;
if ((cc = client_find(e->window)) != NULL) {
switch(e->atom) {
switch (e->atom) {
case XA_WM_NORMAL_HINTS:
XGetWMNormalHints(G_dpy, cc->win, cc->size, &tmp);
client_getsizehints(cc);
break;
case XA_WM_NAME:
client_setname(cc);
break;
case XA_WM_TRANSIENT_FOR:
client_transient(cc);
break;
default:
/* do nothing */
break;
}
} else {
TAILQ_FOREACH(sc, &Screenq, entry)
if (sc->rootwin == e->window)
goto test;
return;
test:
if (e->atom == _NET_DESKTOP_NAMES)
group_update_names(sc);
}
xev_register(xev);
}
void
xev_reconfig(struct client_ctx *cc)
static void
xev_handle_enternotify(XEvent *ee)
{
XConfigureEvent ce;
XCrossingEvent *e = &ee->xcrossing;
struct client_ctx *cc;
ce.type = ConfigureNotify;
ce.event = cc->win;
ce.window = cc->win;
ce.x = cc->geom.x;
ce.y = cc->geom.y;
ce.width = cc->geom.width;
ce.height = cc->geom.height;
ce.border_width = 0;
ce.above = None;
ce.override_redirect = 0;
XSendEvent(G_dpy, cc->win, False, StructureNotifyMask, (XEvent *)&ce);
}
void
xev_handle_enternotify(struct xevent *xev, XEvent *ee)
{
XCrossingEvent *e = &ee->xcrossing;
struct client_ctx *cc;
if ((cc = client_find(e->window)) == NULL) {
/*
* XXX - later. messes up unclutter. but may be
* needed when we introduce menu windows and such into
* the main event loop.
*/
#ifdef notyet
if (e->window != e->root)
client_nocurrent();
#endif
} else
if ((cc = client_find(e->window)) != NULL)
client_setactive(cc, 1);
xev_register(xev);
}
void
xev_handle_leavenotify(struct xevent *xev, XEvent *ee)
static void
xev_handle_leavenotify(XEvent *ee)
{
client_leave(NULL);
xev_register(xev);
}
/* We can split this into two event handlers. */
void
xev_handle_buttonpress(struct xevent *xev, XEvent *ee)
static void
xev_handle_buttonpress(XEvent *ee)
{
XButtonEvent *e = &ee->xbutton;
struct client_ctx *cc, *old_cc = client_current();
struct screen_ctx *sc = screen_fromroot(e->root);
char *wname;
int altcontrol = e->state == (ControlMask|Mod1Mask);
XButtonEvent *e = &ee->xbutton;
struct client_ctx *cc, fakecc;
struct screen_ctx *sc;
struct mousebinding *mb;
sc = screen_fromroot(e->root);
cc = client_find(e->window);
if (sc->rootwin == e->window && !altcontrol) {
struct menu_q menuq;
struct menu *mi;
/* Ignore caps lock and numlock */
e->state &= ~(Mod2Mask | LockMask);
/* XXXSIGH!!!! */
if (e->button == Button2) {
group_menu(e);
goto out;
}
TAILQ_INIT(&menuq);
switch (e->button) {
case Button1:
TAILQ_FOREACH(cc, &G_clientq, entry) {
if (cc->flags & CLIENT_HIDDEN) {
if (cc->label != NULL)
wname = cc->label;
else
wname = cc->name;
if (wname == NULL)
continue;
XCALLOC(mi, struct menu);
strlcpy(mi->text,
wname, sizeof(mi->text));
mi->ctx = cc;
TAILQ_INSERT_TAIL(&menuq, mi, entry);
}
}
TAILQ_FOREACH(mb, &Conf.mousebindingq, entry) {
if (e->button == mb->button && e->state == mb->modmask)
break;
case Button3: {
struct cmd *cmd;
if (conf_cmd_changed(G_conf.menu_path)) {
conf_cmd_clear(&G_conf);
conf_cmd_populate(&G_conf, G_conf.menu_path);
}
TAILQ_FOREACH(cmd, &G_conf.cmdq, entry) {
XCALLOC(mi, struct menu);
strlcpy(mi->text, cmd->label, sizeof(mi->text));
mi->ctx = cmd;
TAILQ_INSERT_TAIL(&menuq, mi, entry);
}
break;
}
default:
break;
}
if (TAILQ_EMPTY(&menuq))
goto out;
mi = (struct menu *)grab_menu(e, &menuq);
if (mi == NULL)
goto cleanup;
switch (e->button) {
case Button1:
cc = (struct client_ctx *)mi->ctx;
client_unhide(cc);
if (old_cc != NULL)
client_ptrsave(old_cc);
client_ptrwarp(cc);
break;
case Button3:
u_spawn(((struct cmd *)mi->ctx)->image);
break;
default:
break;
}
cleanup:
while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
TAILQ_REMOVE(&menuq, mi, entry);
xfree(mi);
}
goto out;
}
if (cc == NULL || e->state == 0)
goto out;
if (mb == NULL)
return;
if (mb->context == MOUSEBIND_CTX_ROOT) {
if (e->window != sc->rootwin)
return;
cc = &fakecc;
cc->sc = screen_fromroot(e->window);
} else if (cc == NULL) /* (mb->context == MOUSEBIND_CTX_WIN */
return;
sc = CCTOSC(cc);
switch (e->button) {
case Button1:
if (altcontrol && !G_groupmode)
group_sticky_toggle_enter(cc);
else {
grab_drag(cc);
client_move(cc);
}
break;
case Button2:
/* XXXSIGH!!! */
if (G_groupmode)
group_click(cc);
else {
grab_sweep(cc);
client_resize(cc);
}
break;
case Button3:
client_ptrsave(cc);
client_lower(cc);
break;
}
out:
xev_register(xev);
(*mb->callback)(cc, e);
}
void
xev_handle_buttonrelease(struct xevent *xev, XEvent *ee)
static void
xev_handle_buttonrelease(XEvent *ee)
{
struct client_ctx *cc = client_current();
struct client_ctx *cc;
if (cc != NULL && !G_groupmode)
if ((cc = client_current()) != NULL)
group_sticky_toggle_exit(cc);
xev_register(xev);
}
void
xev_handle_keypress(struct xevent *xev, XEvent *ee)
static void
xev_handle_keypress(XEvent *ee)
{
XKeyEvent *e = &ee->xkey;
struct client_ctx *cc = NULL; /* Make gcc happy. */
struct keybinding *kb;
KeySym keysym, skeysym;
int modshift;
XKeyEvent *e = &ee->xkey;
struct client_ctx *cc = NULL, fakecc;
struct keybinding *kb;
KeySym keysym, skeysym;
int modshift;
keysym = XKeycodeToKeysym(G_dpy, e->keycode, 0);
skeysym = XKeycodeToKeysym(G_dpy, e->keycode, 1);
TAILQ_FOREACH(kb, &G_conf.keybindingq, entry) {
keysym = XKeycodeToKeysym(X_Dpy, e->keycode, 0);
skeysym = XKeycodeToKeysym(X_Dpy, e->keycode, 1);
/* we don't care about caps lock and numlock here */
e->state &= ~(LockMask | Mod2Mask);
TAILQ_FOREACH(kb, &Conf.keybindingq, entry) {
if (keysym != kb->keysym && skeysym == kb->keysym)
modshift = ShiftMask;
else
@ -380,224 +294,132 @@ xev_handle_keypress(struct xevent *xev, XEvent *ee)
continue;
if ((kb->keycode != 0 && kb->keysym == NoSymbol &&
kb->keycode == e->keycode) || kb->keysym ==
(modshift == 0 ? keysym : skeysym))
kb->keycode == e->keycode) || kb->keysym ==
(modshift == 0 ? keysym : skeysym))
break;
}
if (kb == NULL && e->window == screen_current()->groupwin)
group_display_keypress(e->keycode);
}
if (kb == NULL)
goto out;
return;
if (kb->flags & KBFLAG_NEEDCLIENT) {
if (((cc = client_find(e->window)) == NULL) &&
(cc = client_current()) == NULL)
return;
} else {
cc = &fakecc;
cc->sc = screen_fromroot(e->window);
}
if ((kb->flags & (KBFLAG_NEEDCLIENT|KBFLAG_FINDCLIENT)) &&
(cc = client_find(e->window)) == NULL &&
(cc = client_current()) == NULL)
if (kb->flags & KBFLAG_NEEDCLIENT)
goto out;
(*kb->callback)(cc, kb->argument);
out:
xev_register(xev);
(*kb->callback)(cc, &kb->argument);
}
/*
* This is only used for the alt supression detection.
* This is only used for the alt suppression detection.
*/
void
xev_handle_keyrelease(struct xevent *xev, XEvent *ee)
static void
xev_handle_keyrelease(XEvent *ee)
{
XKeyEvent *e = &ee->xkey;
struct screen_ctx *sc = screen_fromroot(e->root);
int keysym;
XKeyEvent *e = &ee->xkey;
struct screen_ctx *sc;
struct client_ctx *cc;
int keysym;
keysym = XKeycodeToKeysym(G_dpy, e->keycode, 0);
sc = screen_fromroot(e->root);
cc = client_current();
keysym = XKeycodeToKeysym(X_Dpy, e->keycode, 0);
if (keysym != XK_Alt_L && keysym != XK_Alt_R)
goto out;
return;
sc->altpersist = 0;
/*
* XXX - better interface... xevents should not know about
* how/when to mtf.
*/
client_mtf(NULL);
client_altrelease();
out:
xev_register(xev);
if (cc != NULL) {
group_sticky_toggle_exit(cc);
XUngrabKeyboard(X_Dpy, CurrentTime);
}
}
void
xev_handle_clientmessage(struct xevent *xev, XEvent *ee)
static void
xev_handle_clientmessage(XEvent *ee)
{
XClientMessageEvent *e = &ee->xclient;
struct client_ctx *cc = client_find(e->window);
Atom xa_wm_change_state = XInternAtom(G_dpy, "WM_CHANGE_STATE", False);
XClientMessageEvent *e = &ee->xclient;
Atom xa_wm_change_state;
struct client_ctx *cc;
if (cc == NULL)
goto out;
xa_wm_change_state = XInternAtom(X_Dpy, "WM_CHANGE_STATE", False);
if ((cc = client_find(e->window)) == NULL)
return;
if (e->message_type == xa_wm_change_state && e->format == 32 &&
e->data.l[0] == IconicState)
client_hide(cc);
out:
xev_register(xev);
}
/*
* X Event handling
*/
static struct xevent_q _xevq, _xevq_putaway;
static short _xev_q_lock = 0;
void
xev_init(void)
static void
xev_handle_randr(XEvent *ee)
{
TAILQ_INIT(&_xevq);
TAILQ_INIT(&_xevq_putaway);
}
XRRScreenChangeNotifyEvent *rev = (XRRScreenChangeNotifyEvent *)ee;
struct screen_ctx *sc;
int i;
struct xevent *
xev_new(Window *win, Window *root,
int type, void (*cb)(struct xevent *, XEvent *), void *arg)
{
struct xevent *xev;
XMALLOC(xev, struct xevent);
xev->xev_win = win;
xev->xev_root = root;
xev->xev_type = type;
xev->xev_cb = cb;
xev->xev_arg = arg;
return (xev);
}
void
xev_register(struct xevent *xev)
{
struct xevent_q *xq;
xq = _xev_q_lock ? &_xevq_putaway : &_xevq;
TAILQ_INSERT_TAIL(xq, xev, entry);
}
void
_xev_reincorporate(void)
{
struct xevent *xev;
while ((xev = TAILQ_FIRST(&_xevq_putaway)) != NULL) {
TAILQ_REMOVE(&_xevq_putaway, xev, entry);
TAILQ_INSERT_TAIL(&_xevq, xev, entry);
i = XRRRootToScreen(X_Dpy, rev->root);
TAILQ_FOREACH(sc, &Screenq, entry) {
if (sc->which == (u_int)i) {
XRRUpdateConfiguration(ee);
screen_update_geometry(sc, rev->width, rev->height);
screen_init_xinerama(sc);
}
}
}
void
xev_handle_expose(struct xevent *xev, XEvent *ee)
/*
* Called when the keymap has changed.
* Ungrab all keys, reload keymap and then regrab
*/
static void
xev_handle_mappingnotify(XEvent *ee)
{
XExposeEvent *e = &ee->xexpose;
struct screen_ctx *sc = screen_current();
struct client_ctx *cc;
XMappingEvent *e = &ee->xmapping;
struct keybinding *kb;
if ((cc = client_find(e->window)) != NULL)
client_draw_border(cc);
TAILQ_FOREACH(kb, &Conf.keybindingq, entry)
conf_ungrab(&Conf, kb);
if (sc->groupwin == e->window)
group_display_draw(sc);
XRefreshKeyboardMapping(e);
xev_register(xev);
TAILQ_FOREACH(kb, &Conf.keybindingq, entry)
conf_grab(&Conf, kb);
}
#define ASSIGN(xtype) do { \
root = e. xtype .root; \
win = e. xtype .window; \
} while (0)
static void
xev_handle_expose(XEvent *ee)
{
XExposeEvent *e = &ee->xexpose;
struct client_ctx *cc;
#define ASSIGN1(xtype) do { \
win = e. xtype .window; \
} while (0)
if ((cc = client_find(e->window)) != NULL && e->count == 0)
client_draw_border(cc);
}
volatile sig_atomic_t xev_quit = 0;
void
xev_loop(void)
{
Window win, root;
int type;
XEvent e;
struct xevent *xev, *nextxev;
XEvent e;
for (;;) {
#ifdef DIAGNOSTIC
if (TAILQ_EMPTY(&_xevq))
errx(1, "X event queue empty");
#endif
XNextEvent(G_dpy, &e);
type = e.type;
win = root = 0;
switch (type) {
case MapRequest:
ASSIGN1(xmaprequest);
break;
case UnmapNotify:
ASSIGN1(xunmap);
break;
case ConfigureRequest:
ASSIGN1(xconfigurerequest);
break;
case PropertyNotify:
ASSIGN1(xproperty);
break;
case EnterNotify:
case LeaveNotify:
ASSIGN(xcrossing);
break;
case ButtonPress:
ASSIGN(xbutton);
break;
case ButtonRelease:
ASSIGN(xbutton);
break;
case KeyPress:
case KeyRelease:
ASSIGN(xkey);
break;
case DestroyNotify:
ASSIGN1(xdestroywindow);
break;
case ClientMessage:
ASSIGN1(xclient);
break;
default: /* XXX - still need shape event support. */
break;
}
/*
* Now, search for matches, and call each of them.
*/
_xev_q_lock = 1;
for (xev = TAILQ_FIRST(&_xevq); xev != NULL; xev = nextxev) {
nextxev = TAILQ_NEXT(xev, entry);
if ((type != xev->xev_type && xev->xev_type != 0) ||
(xev->xev_win != NULL && win != *xev->xev_win) ||
(xev->xev_root != NULL && root != *xev->xev_root))
continue;
TAILQ_REMOVE(&_xevq, xev, entry);
(*xev->xev_cb)(xev, &e);
}
_xev_q_lock = 0;
_xev_reincorporate();
while (xev_quit == 0) {
XNextEvent(X_Dpy, &e);
if (e.type - Randr_ev == RRScreenChangeNotify)
xev_handle_randr(&e);
else if (e.type < LASTEvent && xev_handlers[e.type] != NULL)
(*xev_handlers[e.type])(&e);
}
}
#undef ASSIGN
#undef ASSIGN1

View File

@ -2,18 +2,38 @@
* calmwm - the calm window manager
*
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
* All rights reserved.
*
* $Id$
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $OpenBSD$
*/
#include "headers.h"
#include <sys/param.h>
#include <sys/queue.h>
#include <err.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "calmwm.h"
void *
xmalloc(size_t siz)
{
void *p;
void *p;
if ((p = malloc(siz)) == NULL)
err(1, "malloc");
@ -22,11 +42,11 @@ xmalloc(size_t siz)
}
void *
xcalloc(size_t siz)
xcalloc(size_t no, size_t siz)
{
void *p;
void *p;
if ((p = calloc(1, siz)) == NULL)
if ((p = calloc(no, siz)) == NULL)
err(1, "calloc");
return (p);
@ -41,7 +61,7 @@ xfree(void *p)
char *
xstrdup(const char *str)
{
char *p;
char *p;
if ((p = strdup(str)) == NULL)
err(1, "strdup");

271
xutil.c
View File

@ -2,114 +2,166 @@
* calmwm - the calm window manager
*
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
* All rights reserved.
*
* $Id$
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $OpenBSD$
*/
#include "headers.h"
#include <sys/param.h>
#include <sys/queue.h>
#include <err.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "calmwm.h"
static unsigned int ign_mods[] = { 0, LockMask, Mod2Mask, Mod2Mask | LockMask };
int
xu_ptr_grab(Window win, int mask, Cursor curs)
{
return (XGrabPointer(G_dpy, win, False, mask,
GrabModeAsync, GrabModeAsync,
None, curs, CurrentTime) == GrabSuccess ? 0 : -1);
return (XGrabPointer(X_Dpy, win, False, mask,
GrabModeAsync, GrabModeAsync,
None, curs, CurrentTime) == GrabSuccess ? 0 : -1);
}
int
xu_ptr_regrab(int mask, Cursor curs)
{
return (XChangeActivePointerGrab(G_dpy, mask,
curs, CurrentTime) == GrabSuccess ? 0 : -1);
return (XChangeActivePointerGrab(X_Dpy, mask,
curs, CurrentTime) == GrabSuccess ? 0 : -1);
}
void
xu_ptr_ungrab(void)
{
XUngrabPointer(G_dpy, CurrentTime);
XUngrabPointer(X_Dpy, CurrentTime);
}
int
void
xu_btn_grab(Window win, int mask, u_int btn)
{
return (XGrabButton(G_dpy, btn, mask, win,
False, ButtonMask, GrabModeAsync,
GrabModeSync, None, None) == GrabSuccess ? 0 : -1);
int i;
for (i = 0; i < nitems(ign_mods); i++)
XGrabButton(X_Dpy, btn, (mask | ign_mods[i]), win,
False, BUTTONMASK, GrabModeAsync,
GrabModeSync, None, None);
}
void
xu_btn_ungrab(Window win, int mask, u_int btn)
{
XUngrabButton(G_dpy, btn, mask, win);
int i;
for (i = 0; i < nitems(ign_mods); i++)
XUngrabButton(X_Dpy, btn, (mask | ign_mods[i]), win);
}
void
xu_ptr_getpos(Window rootwin, int *x, int *y)
{
int tmp0, tmp1;
u_int tmp2;
Window w0, w1;
Window w0, w1;
int tmp0, tmp1;
u_int tmp2;
XQueryPointer(G_dpy, rootwin, &w0, &w1, &tmp0, &tmp1, x, y, &tmp2);
XQueryPointer(X_Dpy, rootwin, &w0, &w1, &tmp0, &tmp1, x, y, &tmp2);
}
void
xu_ptr_setpos(Window win, int x, int y)
{
XWarpPointer(G_dpy, None, win, 0, 0, 0, 0, x, y);
XWarpPointer(X_Dpy, None, win, 0, 0, 0, 0, x, y);
}
void
xu_key_grab(Window win, int mask, int keysym)
{
KeyCode code;
KeyCode code;
int i;
code = XKeysymToKeycode(G_dpy, keysym);
if ((XKeycodeToKeysym(G_dpy, code, 0) != keysym) &&
(XKeycodeToKeysym(G_dpy, code, 1) == keysym))
code = XKeysymToKeycode(X_Dpy, keysym);
if ((XKeycodeToKeysym(X_Dpy, code, 0) != keysym) &&
(XKeycodeToKeysym(X_Dpy, code, 1) == keysym))
mask |= ShiftMask;
XGrabKey(G_dpy, XKeysymToKeycode(G_dpy, keysym), mask, win, True,
GrabModeAsync, GrabModeAsync);
#if 0
XGrabKey(G_dpy, XKeysymToKeycode(G_dpy, keysym), LockMask|mask,
win, True, GrabModeAsync, GrabModeAsync);
#endif
for (i = 0; i < nitems(ign_mods); i++)
XGrabKey(X_Dpy, code, (mask | ign_mods[i]), win,
True, GrabModeAsync, GrabModeAsync);
}
void
xu_key_grab_keycode(Window win, int mask, int keycode)
xu_key_ungrab(Window win, int mask, int keysym)
{
XGrabKey(G_dpy, keycode, mask, win, True, GrabModeAsync, GrabModeAsync);
KeyCode code;
int i;
code = XKeysymToKeycode(X_Dpy, keysym);
if ((XKeycodeToKeysym(X_Dpy, code, 0) != keysym) &&
(XKeycodeToKeysym(X_Dpy, code, 1) == keysym))
mask |= ShiftMask;
for (i = 0; i < nitems(ign_mods); i++)
XUngrabKey(X_Dpy, code, (mask | ign_mods[i]), win);
}
void
xu_sendmsg(struct client_ctx *cc, Atom atm, long val)
xu_configure(struct client_ctx *cc)
{
XEvent e;
XConfigureEvent ce;
memset(&e, 0, sizeof(e));
ce.type = ConfigureNotify;
ce.event = cc->win;
ce.window = cc->win;
ce.x = cc->geom.x;
ce.y = cc->geom.y;
ce.width = cc->geom.width;
ce.height = cc->geom.height;
ce.border_width = cc->bwidth;
ce.above = None;
ce.override_redirect = 0;
XSendEvent(X_Dpy, cc->win, False, StructureNotifyMask, (XEvent *)&ce);
}
void
xu_sendmsg(Window win, Atom atm, long val)
{
XEvent e;
(void)memset(&e, 0, sizeof(e));
e.xclient.type = ClientMessage;
e.xclient.window = cc->win;
e.xclient.window = win;
e.xclient.message_type = atm;
e.xclient.format = 32;
e.xclient.data.l[0] = val;
e.xclient.data.l[1] = CurrentTime;
XSendEvent(G_dpy, cc->win, False, 0, &e);
XSendEvent(X_Dpy, win, False, 0, &e);
}
int
xu_getprop(struct client_ctx *cc, Atom atm, Atom type, long len, u_char **p)
xu_getprop(Window win, Atom atm, Atom type, long len, u_char **p)
{
Atom realtype;
u_long n, extra;
int format;
Atom realtype;
u_long n, extra;
int format;
if (XGetWindowProperty(G_dpy, cc->win, atm, 0L, len, False, type,
&realtype, &format, &n, &extra, p) != Success || *p == NULL)
if (XGetWindowProperty(X_Dpy, win, atm, 0L, len, False, type,
&realtype, &format, &n, &extra, p) != Success || *p == NULL)
return (-1);
if (n == 0)
@ -118,13 +170,44 @@ xu_getprop(struct client_ctx *cc, Atom atm, Atom type, long len, u_char **p)
return (n);
}
int
xu_getstrprop(Window win, Atom atm, char **text) {
XTextProperty prop;
char **list;
int nitems = 0;
*text = NULL;
XGetTextProperty(X_Dpy, win, &prop, atm);
if (!prop.nitems)
return (0);
if (Xutf8TextPropertyToTextList(X_Dpy, &prop, &list,
&nitems) == Success && nitems > 0 && *list) {
if (nitems > 1) {
XTextProperty prop2;
if (Xutf8TextListToTextProperty(X_Dpy, list, nitems,
XUTF8StringStyle, &prop2) == Success) {
*text = xstrdup(prop2.value);
XFree(prop2.value);
}
} else {
*text = xstrdup(*list);
}
XFreeStringList(list);
}
XFree(prop.value);
return (nitems);
}
int
xu_getstate(struct client_ctx *cc, int *state)
{
Atom wm_state = XInternAtom(G_dpy, "WM_STATE", False);
long *p = NULL;
long *p = NULL;
if (xu_getprop(cc, wm_state, wm_state, 2L, (u_char **)&p) <= 0)
if (xu_getprop(cc->win, WM_STATE, WM_STATE, 2L, (u_char **)&p) <= 0)
return (-1);
*state = (int)*p;
@ -133,30 +216,90 @@ xu_getstate(struct client_ctx *cc, int *state)
return (0);
}
char *
xu_getstrprop(struct client_ctx *cc, Atom atm)
{
u_char *cp;
if (xu_getprop(cc, atm, XA_STRING, 100L, &cp) <= 0)
return (NULL);
return ((char *)cp);
}
void
xu_setstate(struct client_ctx *cc, int state)
{
long dat[2];
Atom wm_state;
long dat[2];
/* XXX cache */
wm_state = XInternAtom(G_dpy, "WM_STATE", False);
dat[0] = (long)state;
dat[1] = (long)None;
dat[0] = state;
dat[1] = None;
cc->state = state;
XChangeProperty(G_dpy, cc->win, wm_state, wm_state, 32,
XChangeProperty(X_Dpy, cc->win, WM_STATE, WM_STATE, 32,
PropModeReplace, (unsigned char *)dat, 2);
}
Atom cwm_atoms[CWM_NO_ATOMS];
char *atoms[CWM_NO_ATOMS] = {
"WM_STATE",
"WM_DELETE_WINDOW",
"WM_TAKE_FOCUS",
"WM_PROTOCOLS",
"_MOTIF_WM_HINTS",
"UTF8_STRING",
"_NET_SUPPORTED",
"_NET_SUPPORTING_WM_CHECK",
"_NET_WM_NAME",
"_NET_ACTIVE_WINDOW",
"_NET_CLIENT_LIST",
"_NET_NUMBER_OF_DESKTOPS",
"_NET_CURRENT_DESKTOP",
"_NET_DESKTOP_VIEWPORT",
"_NET_DESKTOP_GEOMETRY",
"_NET_VIRTUAL_ROOTS",
"_NET_SHOWING_DESKTOP",
"_NET_DESKTOP_NAMES",
"_NET_WM_DESKTOP",
"_NET_WORKAREA",
};
void
xu_getatoms(void)
{
XInternAtoms(X_Dpy, atoms, CWM_NO_ATOMS, False, cwm_atoms);
}
void
xu_setwmname(struct screen_ctx *sc)
{
/*
* set up the _NET_SUPPORTED hint with all netwm atoms that we
* know about.
*/
XChangeProperty(X_Dpy, sc->rootwin, _NET_SUPPORTED, XA_ATOM, 32,
PropModeReplace, (unsigned char *)&_NET_SUPPORTED,
CWM_NO_ATOMS - CWM_NETWM_START);
/*
* netwm spec says that to prove that the hint is not stale you must
* provide _NET_SUPPORTING_WM_CHECK containing a window (we use the
* menu window). The property must be set on the root window and the
* window itself, the window also must have _NET_WM_NAME set with the
* window manager name.
*/
XChangeProperty(X_Dpy, sc->rootwin, _NET_SUPPORTING_WM_CHECK,
XA_WINDOW, 32, PropModeReplace, (unsigned char *)&sc->menuwin, 1);
XChangeProperty(X_Dpy, sc->menuwin, _NET_SUPPORTING_WM_CHECK,
XA_WINDOW, 32, PropModeReplace, (unsigned char *)&sc->menuwin, 1);
XChangeProperty(X_Dpy, sc->menuwin, _NET_WM_NAME, UTF8_STRING,
8, PropModeReplace, WMNAME, strlen(WMNAME));
}
unsigned long
xu_getcolor(struct screen_ctx *sc, char *name)
{
XColor color, tmp;
if (!XAllocNamedColor(X_Dpy, DefaultColormap(X_Dpy, sc->which),
name, &color, &tmp)) {
warnx("XAllocNamedColor error: '%s'", name);
return 0;
}
return color.pixel;
}
void
xu_freecolor(struct screen_ctx *sc, unsigned long pixel)
{
XFreeColors(X_Dpy, DefaultColormap(X_Dpy, sc->which), &pixel, 1, 0L);
}