151 Commits

Author SHA1 Message Date
601779351c Version 5.1 2012-05-02 14:26:57 +02:00
5f79bace21 Add release target to Makefile 2012-05-02 14:26:36 +02:00
de5efc6a54 Define compatibility macros only if they are needed 2012-05-02 14:26:14 +02:00
1603d18560 cvsimport 2011-12-29 20:48:38 +00:00
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
96ebac8b04 fix pkg-config packages 2011-12-12 16:17:39 +01: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
cbe46b651f cvsimport 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
901a75d3c6 cvsimport 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
58077c157b cvsimport 2011-10-12 15:43:50 +00:00
ce34d0066e Add README 2011-10-05 17:48:47 +02:00
7c7a5bdcdc rewrite Makefile 2011-10-05 17:48:33 +02: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
54c1b90725 cvsimport 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
3c67ec8ccc cvsimport 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
b1d81b7eb6 cvsimport 2011-09-08 12:35:33 +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
513c35dca9 cvsimport 2011-08-04 20:53:37 +02: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
f067809af4 cvsimport 2011-05-15 17:58:47 +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
a90a0b5705 cvsimport 2011-05-07 17:15:37 +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
2bac9a6be9 cvsimport 2011-05-03 19:28:18 +02: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
9eaece0541 cvsimport 2011-02-18 11:50:01 +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
5bc15cdb58 cvsimport 2010-12-24 23:42:39 +01: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
10622cf40d Add protoypes, fixes segfaults on x86 2010-09-26 14:51:23 +02:00
a64855f9cc Improve CFLAGS 2010-09-26 14:51:02 +02:00
e6d9effa8d Use yacc instead of byacc 2010-09-26 01:46:05 +02:00
b11c12e99b Merge branch 'origin' into linux 2010-09-26 01:43:12 +02: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
c9a14a8f40 cvsimport 2010-07-30 12:28:19 +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
e0c9657773 cvsimport 2010-05-22 22:32:08 +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
f769df540d cvsimport 2010-04-12 16:17:46 +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
d90ab51111 Add missing functions 2010-02-21 19:18:12 +01:00
50aff37f50 Import linux.patch
Patch largely based on cwmbuild.sh from http://tamentis.com/hacks/cwm/
written by Bertrand Janin, updated by Christian Neukirchen.
2010-02-21 19:15:27 +01: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
27 changed files with 2387 additions and 1498 deletions

View File

@ -1,26 +1,47 @@
# $OpenBSD$ # cwm makefile for BSD make and GNU make
# uses pkg-config, DESTDIR and PREFIX
.include <bsd.xconf.mk>
PROG= cwm PROG= cwm
PREFIX= /usr/local
SRCS= calmwm.c screen.c xmalloc.c client.c menu.c \ SRCS= calmwm.c screen.c xmalloc.c client.c menu.c \
search.c util.c xutil.c conf.c input.c xevents.c group.c \ search.c util.c xutil.c conf.c xevents.c group.c \
kbfunc.c mousefunc.c font.c parse.y kbfunc.c mousefunc.c font.c parse.y
CPPFLAGS+= -I${X11BASE}/include -I${X11BASE}/include/freetype2 -I${.CURDIR} OBJS= calmwm.o screen.o xmalloc.o client.o menu.o \
search.o util.o xutil.o conf.o xevents.o group.o \
kbfunc.o mousefunc.o font.o strlcpy.o strlcat.o y.tab.o \
strtonum.o fgetln.o
CFLAGS+= -Wall CPPFLAGS+= `pkg-config --cflags fontconfig x11 xft xinerama xrandr`
LDADD+= -L${X11BASE}/lib -lXft -lXrender -lX11 -lXau -lXdmcp \ CFLAGS= -Wall -O2 -g
-lfontconfig -lexpat -lfreetype -lz -lXinerama -lXrandr -lXext
MANDIR= ${X11BASE}/man/cat LDFLAGS+= `pkg-config --libs fontconfig x11 xft xinerama xrandr`
MAN= cwm.1 cwmrc.5
CLEANFILES= cwm.cat1 cwmrc.cat5 MANPREFIX= ${PREFIX}/share/man
obj: _xenocara_obj all: ${PROG}
.include <bsd.prog.mk> clean:
.include <bsd.xorg.mk> rm -rf ${OBJS} ${PROG} y.tab.c
y.tab.c: parse.y
yacc parse.y
${PROG}: ${OBJS} y.tab.o
${CC} ${OBJS} ${LDFLAGS} -o ${PROG}
.c.o:
${CC} -c ${CFLAGS} ${CPPFLAGS} $<
install: ${PROG}
install -d ${DESTDIR}${PREFIX}/bin ${DESTDIR}${MANPREFIX}/man1 ${DESTDIR}${MANPREFIX}/man5
install -m 755 cwm ${DESTDIR}${PREFIX}/bin
install -m 644 cwm.1 ${DESTDIR}${MANPREFIX}/man1
install -m 644 cwmrc.5 ${DESTDIR}${MANPREFIX}/man5
release:
VERSION=$$(git describe --tags | sed 's/^v//;s/-[^.]*$$//') && \
git archive --prefix=cwm-$$VERSION/ -o cwm-$$VERSION.tar.gz HEAD

66
README
View File

@ -1,58 +1,24 @@
-------------------------------------------------------------------------------- This is a port of OpenBSD's excellent cwm[0] to Linux and other
cwm release three Unices.
--------------------------------------------------------------------------------
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 cwm is a window manager for X11 which contains many features that
concentrate on the efficiency and transparency of window
management. cwm also aims to maintain the simplest and most
pleasant aesthetic.
DESCRIPTION This port requires pkg-config, Xft, Xinerama and Xrandr. The included
Makefile should work with both GNU make and BSD make.
cwm is a window manager initially inspired by evilwm[1]. It This version actively tracks changes in the OpenBSD CVS repository.
developed out of modifications to evilwm, but eventually the code Releases are roughly coordinated.
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 The revision controlled version is at https://github.com/chneukirchen/cwm
a very clean, simple & attractive aesthetic. Releases can be found at http://chneukirchen.org/releases
cwm has several novel features, including the ability to search ChangeLog:
for windows.
HIGHLIGHTS IN RELEASE TWO 2012-05-02: First public release 5.1 of portable cwm.
* Improved alt-tabbing, including the ability to reverse cycle. --Christian Neukirchen <chneukirchen@gmail.com>
* 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 [0]: http://www.openbsd.org/cgi-bin/cvsweb/xenocara/app/cwm/
* 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. Please see the LICENSE
file or the top of any source file for more information.
[1] http://evilwm.sourceforge.net/

26
TODO
View File

@ -1,26 +0,0 @@
- 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...
- search window should try to stay inside of the screen boundaries.
- geographical keyboard navigation (window switching)
- 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.

120
calmwm.c
View File

@ -15,32 +15,42 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
* *
* $Id$ * $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" #include "calmwm.h"
Display *X_Dpy; Display *X_Dpy;
Cursor Cursor_move;
Cursor Cursor_resize;
Cursor Cursor_select;
Cursor Cursor_default; Cursor Cursor_default;
Cursor Cursor_move;
Cursor Cursor_normal;
Cursor Cursor_question; Cursor Cursor_question;
Cursor Cursor_resize;
struct screen_ctx_q Screenq; struct screen_ctx_q Screenq = TAILQ_HEAD_INITIALIZER(Screenq);
struct screen_ctx *Curscreen; struct client_ctx_q Clientq = TAILQ_HEAD_INITIALIZER(Clientq);
struct client_ctx_q Clientq;
int HasXinerama, HasRandr, Randr_ev; int HasXinerama, HasRandr, Randr_ev;
int Starting;
struct conf Conf; struct conf Conf;
static void sigchld_cb(int); static void sigchld_cb(int);
static void dpy_init(const char *); static void dpy_init(const char *);
static int x_errorhandler(Display *, XErrorEvent *); static int x_errorhandler(Display *, XErrorEvent *);
static int x_wmerrorhandler(Display *, XErrorEvent *);
static void x_setup(void); static void x_setup(void);
static void x_setupscreen(struct screen_ctx *, u_int); static void x_setupscreen(struct screen_ctx *, u_int);
static void x_teardown(void); static void x_teardown(void);
@ -70,18 +80,12 @@ main(int argc, char **argv)
if (signal(SIGCHLD, sigchld_cb) == SIG_ERR) if (signal(SIGCHLD, sigchld_cb) == SIG_ERR)
err(1, "signal"); err(1, "signal");
Starting = 1;
dpy_init(display_name); dpy_init(display_name);
screen_init();
group_init();
client_init();
bzero(&Conf, sizeof(Conf)); bzero(&Conf, sizeof(Conf));
conf_setup(&Conf, conf_file); conf_setup(&Conf, conf_file);
xu_getatoms(); xu_getatoms();
x_setup(); x_setup();
Starting = 0;
xev_loop(); xev_loop();
@ -95,10 +99,15 @@ dpy_init(const char *dpyname)
{ {
int i; int i;
XSetErrorHandler(x_errorhandler);
if ((X_Dpy = XOpenDisplay(dpyname)) == NULL) if ((X_Dpy = XOpenDisplay(dpyname)) == NULL)
errx(1, "unable to open display \"%s\"", errx(1, "unable to open display \"%s\"",
XDisplayName(dpyname)); XDisplayName(dpyname));
XSetErrorHandler(x_wmerrorhandler);
XSelectInput(X_Dpy, DefaultRootWindow(X_Dpy), SubstructureRedirectMask);
XSync(X_Dpy, False);
XSetErrorHandler(x_errorhandler); XSetErrorHandler(x_errorhandler);
HasRandr = XRRQueryExtension(X_Dpy, &Randr_ev, &i); HasRandr = XRRQueryExtension(X_Dpy, &Randr_ev, &i);
@ -111,6 +120,12 @@ x_setup(void)
struct keybinding *kb; struct keybinding *kb;
int i; 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++) { for (i = 0; i < ScreenCount(X_Dpy); i++) {
sc = xcalloc(1, sizeof(*sc)); sc = xcalloc(1, sizeof(*sc));
x_setupscreen(sc, i); x_setupscreen(sc, i);
@ -123,12 +138,6 @@ x_setup(void)
*/ */
TAILQ_FOREACH(kb, &Conf.keybindingq, entry) TAILQ_FOREACH(kb, &Conf.keybindingq, entry)
conf_grab(&Conf, kb); conf_grab(&Conf, kb);
Cursor_move = XCreateFontCursor(X_Dpy, XC_fleur);
Cursor_resize = XCreateFontCursor(X_Dpy, XC_bottom_right_corner);
Cursor_select = XCreateFontCursor(X_Dpy, XC_hand1);
Cursor_default = XCreateFontCursor(X_Dpy, XC_X_cursor);
Cursor_question = XCreateFontCursor(X_Dpy, XC_question_arrow);
} }
static void static void
@ -150,24 +159,32 @@ x_setupscreen(struct screen_ctx *sc, u_int which)
XSetWindowAttributes rootattr; XSetWindowAttributes rootattr;
int fake; int fake;
u_int nwins, i; u_int nwins, i;
Curscreen = sc;
sc->which = which; sc->which = which;
sc->rootwin = RootWindow(X_Dpy, sc->which); sc->rootwin = RootWindow(X_Dpy, sc->which);
sc->xmax = DisplayWidth(X_Dpy, sc->which);
sc->ymax = DisplayHeight(X_Dpy, sc->which);
conf_color(&Conf); conf_gap(&Conf, sc);
screen_update_geometry(sc, DisplayWidth(X_Dpy, sc->which),
DisplayHeight(X_Dpy, sc->which));
font_init(sc); conf_color(&Conf, sc);
conf_font(&Conf);
group_init(sc);
conf_font(&Conf, sc);
TAILQ_INIT(&sc->mruq); TAILQ_INIT(&sc->mruq);
/* Initialize menu window. */ /* Initialize menu window. */
menu_init(sc); 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. */ /* Deal with existing clients. */
XQueryTree(X_Dpy, sc->rootwin, &w0, &w1, &wins, &nwins); XQueryTree(X_Dpy, sc->rootwin, &w0, &w1, &wins, &nwins);
@ -176,17 +193,11 @@ x_setupscreen(struct screen_ctx *sc, u_int which)
if (winattr.override_redirect || if (winattr.override_redirect ||
winattr.map_state != IsViewable) winattr.map_state != IsViewable)
continue; continue;
client_new(wins[i], sc, winattr.map_state != IsUnmapped); (void)client_new(wins[i], sc, winattr.map_state != IsUnmapped);
} }
XFree(wins); XFree(wins);
screen_updatestackingorder(); screen_updatestackingorder(sc);
rootattr.event_mask = ChildMask|PropertyChangeMask|EnterWindowMask|
LeaveWindowMask|ColormapChangeMask|ButtonMask;
XChangeWindowAttributes(X_Dpy, sc->rootwin,
CWEventMask, &rootattr);
if (XineramaQueryExtension(X_Dpy, &fake, &fake) == 1 && if (XineramaQueryExtension(X_Dpy, &fake, &fake) == 1 &&
((HasXinerama = XineramaIsActive(X_Dpy)) == 1)) ((HasXinerama = XineramaIsActive(X_Dpy)) == 1))
@ -203,28 +214,26 @@ x_setupscreen(struct screen_ctx *sc, u_int which)
XSync(X_Dpy, False); 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 static int
x_errorhandler(Display *dpy, XErrorEvent *e) x_errorhandler(Display *dpy, XErrorEvent *e)
{ {
#ifdef DEBUG #if DEBUG
{ char msg[80], number[80], req[80];
char msg[80], number[80], req[80];
XGetErrorText(X_Dpy, e->error_code, msg, sizeof(msg)); XGetErrorText(X_Dpy, e->error_code, msg, sizeof(msg));
snprintf(number, sizeof(number), "%d", e->request_code); (void)snprintf(number, sizeof(number), "%d", e->request_code);
XGetErrorDatabaseText(X_Dpy, "XRequest", number, XGetErrorDatabaseText(X_Dpy, "XRequest", number,
"<unknown>", req, sizeof(req)); "<unknown>", req, sizeof(req));
warnx("%s(0x%x): %s", req, (u_int)e->resourceid, msg); warnx("%s(0x%x): %s", req, (u_int)e->resourceid, msg);
}
#endif #endif
if (Starting &&
e->error_code == BadAccess &&
e->request_code == X_GrabKey)
errx(1, "root window unavailable - perhaps another "
"wm is running?");
return (0); return (0);
} }
@ -248,6 +257,7 @@ usage(void)
{ {
extern char *__progname; extern char *__progname;
fprintf(stderr, "usage: %s [-c file] [-d display]\n", __progname); (void)fprintf(stderr, "usage: %s [-c file] [-d display]\n",
__progname);
exit(1); exit(1);
} }

791
calmwm.h
View File

@ -15,200 +15,74 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
* *
* $Id$ * $OpenBSD$
*/ */
#ifndef _CALMWM_H_ #ifndef _CALMWM_H_
#define _CALMWM_H_ #define _CALMWM_H_
#define CALMWM_MAXNAMELEN 256 /* ugly stuff */
#ifndef TAILQ_END
#define TAILQ_END(head) NULL
#endif
#ifndef __dead
#define __dead
#endif
char *fgetln(FILE *, size_t *);
long long strtonum(const char *, long long, long long, const char **);
size_t strlcpy(char *, const char *, size_t);
size_t strlcat(char *, const char *, size_t);
#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 MIN
#undef MAX #undef MAX
#define MIN(x, y) ((x) < (y) ? (x) : (y)) #define MIN(x, y) ((x) < (y) ? (x) : (y))
#define MAX(x, y) ((x) > (y) ? (x) : (y)) #define MAX(x, y) ((x) > (y) ? (x) : (y))
#ifndef nitems
#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
#endif
#define CONFFILE ".cwmrc" #define CONFFILE ".cwmrc"
#define WMNAME "CWM"
#define ChildMask (SubstructureRedirectMask|SubstructureNotifyMask) #define CHILDMASK (SubstructureRedirectMask|SubstructureNotifyMask)
#define ButtonMask (ButtonPressMask|ButtonReleaseMask) #define BUTTONMASK (ButtonPressMask|ButtonReleaseMask)
#define MouseMask (ButtonMask|PointerMotionMask) #define MOUSEMASK (BUTTONMASK|PointerMotionMask)
#define KeyMask (KeyPressMask|ExposureMask) #define KEYMASK (KeyPressMask|ExposureMask)
#define MenuMask (ButtonMask|ButtonMotionMask|ExposureMask| \ #define MENUMASK (BUTTONMASK|ButtonMotionMask|ExposureMask| \
PointerMotionMask) PointerMotionMask)
#define MenuGrabMask (ButtonMask|ButtonMotionMask|StructureNotifyMask|\ #define MENUGRABMASK (BUTTONMASK|ButtonMotionMask|StructureNotifyMask|\
PointerMotionMask) PointerMotionMask)
#define SearchMask (KeyPressMask|ExposureMask) #define SEARCHMASK (KeyPressMask|ExposureMask)
enum cwmcolor { /* kb movement */
CWM_COLOR_BORDOR_ACTIVE, #define CWM_MOVE 0x0001
CWM_COLOR_BORDER_INACTIVE, #define CWM_RESIZE 0x0002
CWM_COLOR_BORDER_GROUP, #define CWM_PTRMOVE 0x0004
CWM_COLOR_BORDER_UNGROUP, #define CWM_BIGMOVE 0x0008
CWM_COLOR_FG_MENU, #define CWM_UP 0x0010
CWM_COLOR_BG_MENU, #define CWM_DOWN 0x0020
CWM_COLOR_MAX #define CWM_LEFT 0x0040
}; #define CWM_RIGHT 0x0080
struct color { /* exec */
unsigned long pixel; #define CWM_EXEC_PROGRAM 0x0001
char *name; #define CWM_EXEC_WM 0x0002
};
struct client_ctx; /* cycle */
#define CWM_CYCLE 0x0001
TAILQ_HEAD(cycle_entry_q, client_ctx); #define CWM_RCYCLE 0x0002
#define CWM_INGROUP 0x0004
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 cycle_entry_q mruq;
XftDraw *xftdraw;
XftColor xftcolor;
int xinerama_no;
XineramaScreenInfo *xinerama;
};
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_DOMAXIMIZE 0x04
#define CLIENT_MAXIMIZED 0x08
#define CLIENT_DOVMAXIMIZE 0x10
#define CLIENT_VMAXIMIZED 0x20
#define CLIENT_HIGHLIGHT_GROUP 1
#define CLIENT_HIGHLIGHT_UNGROUP 2
struct winname {
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;
u_int bwidth;
struct {
int x, y, width, height;
int min_dx, min_dy;
} geom, savegeom;
struct {
int x,y;
} ptr;
int xproto;
int flags;
int state;
char *name;
struct winname_q nameq;
size_t nameqlen;
char *label;
int active;
int highlight;
char *matchname;
struct group_ctx *group;
int stackingorder;
char *app_class;
char *app_name;
char *app_cliarg;
};
TAILQ_HEAD(client_ctx_q, client_ctx);
extern const char *shortcut_to_name[];
struct group_ctx {
TAILQ_ENTRY(group_ctx) entry;
struct client_ctx_q clients;
const char *name;
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_HEAD(autogroupwin_q, autogroupwin);
#define CWM_MOVE 0x01
#define CWM_RESIZE 0x02
#define CWM_PTRMOVE 0x04
#define CWM_BIGMOVE 0x08
#define CWM_UP 0x10
#define CWM_DOWN 0x20
#define CWM_LEFT 0x40
#define CWM_RIGHT 0x80
/*
* Match a window.
*/
#define CONF_MAX_WINTITLE 256
struct winmatch {
TAILQ_ENTRY(winmatch) entry;
char title[CONF_MAX_WINTITLE];
};
TAILQ_HEAD(winmatch_q, winmatch);
/* for cwm_exec */
#define CWM_EXEC_PROGRAM 0x1
#define CWM_EXEC_WM 0x2
/* for alt-tab */
#define CWM_CYCLE 0x0
#define CWM_RCYCLE 0x1
/* for group cycle */
#define CWM_CYCLEGROUP 0x0
#define CWM_RCYCLEGROUP 0x1
#define KBFLAG_NEEDCLIENT 0x01
#define KBTOGROUP(X) ((X) - 1) #define KBTOGROUP(X) ((X) - 1)
@ -217,6 +91,149 @@ union arg {
int i; int i;
}; };
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
};
struct color {
char *name;
unsigned long pixel;
};
struct gap {
int top;
int bottom;
int left;
int right;
};
struct winname {
TAILQ_ENTRY(winname) entry;
char *name;
};
TAILQ_HEAD(winname_q, winname);
struct client_ctx {
TAILQ_ENTRY(client_ctx) entry;
TAILQ_ENTRY(client_ctx) group_entry;
TAILQ_ENTRY(client_ctx) mru_entry;
struct screen_ctx *sc;
Window win;
XSizeHints *size;
Colormap cmap;
u_int bwidth; /* border width */
struct {
int x; /* x position */
int y; /* y position */
int width; /* width */
int height;/* height */
} geom, savegeom;
struct {
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;
#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;
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;
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;
int shortcut;
int hidden;
int nhidden;
int highstack;
};
TAILQ_HEAD(group_ctx_q, group_ctx);
struct autogroupwin {
TAILQ_ENTRY(autogroupwin) entry;
char *class;
char *name;
int num;
};
TAILQ_HEAD(autogroupwin_q, autogroupwin);
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(screen_ctx_q, screen_ctx);
struct keybinding { struct keybinding {
TAILQ_ENTRY(keybinding) entry; TAILQ_ENTRY(keybinding) entry;
void (*callback)(struct client_ctx *, union arg *); void (*callback)(struct client_ctx *, union arg *);
@ -224,33 +241,43 @@ struct keybinding {
int modmask; int modmask;
int keysym; int keysym;
int keycode; int keycode;
#define KBFLAG_NEEDCLIENT 0x0001
int flags; 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 { struct cmd {
TAILQ_ENTRY(cmd) entry; TAILQ_ENTRY(cmd) entry;
int flags; int flags;
char image[MAXPATHLEN]; char image[MAXPATHLEN];
char label[256]; #define CMD_MAXLABELLEN 256
/* (argv) */ char label[CMD_MAXLABELLEN];
}; };
struct mousebinding {
int modmask;
int button;
int context;
void (*callback)(struct client_ctx *, void *);
TAILQ_ENTRY(mousebinding) entry;
};
#define MOUSEBIND_CTX_ROOT 1
#define MOUSEBIND_CTX_WIN 2
TAILQ_HEAD(keybinding_q, keybinding);
TAILQ_HEAD(cmd_q, cmd); TAILQ_HEAD(cmd_q, cmd);
TAILQ_HEAD(mousebinding_q, mousebinding);
/* Global configuration */ struct menu {
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);
struct conf { struct conf {
struct keybinding_q keybindingq; struct keybinding_q keybindingq;
struct autogroupwin_q autogroupq; struct autogroupwin_q autogroupq;
@ -258,260 +285,246 @@ struct conf {
char conf_path[MAXPATHLEN]; char conf_path[MAXPATHLEN];
struct cmd_q cmdq; struct cmd_q cmdq;
struct mousebinding_q mousebindingq; struct mousebinding_q mousebindingq;
#define CONF_STICKY_GROUPS 0x0001
#define CONF_STICKY_GROUPS 0x0001
int flags; int flags;
#define CONF_BWIDTH 1 #define CONF_BWIDTH 1
int bwidth; int bwidth;
#define CONF_MAMOUNT 1 #define CONF_MAMOUNT 1
int mamount; int mamount;
#define CONF_SNAPDIST 0
#define CONF_COLOR_ACTIVEBORDER "#CCCCCC" int snapdist;
#define CONF_COLOR_INACTIVEBORDER "#666666" struct gap gap;
#define CONF_COLOR_GROUPBORDER "blue"
#define CONF_COLOR_UNGROUPBORDER "red"
#define CONF_COLOR_MENUFG "black"
#define CONF_COLOR_MENUBG "white"
struct color color[CWM_COLOR_MAX]; struct color color[CWM_COLOR_MAX];
char termpath[MAXPATHLEN]; char termpath[MAXPATHLEN];
char lockpath[MAXPATHLEN]; char lockpath[MAXPATHLEN];
#define CONF_FONT "sans-serif:pixelsize=14:bold"
#define DEFAULTFONTNAME "sans-serif:pixelsize=14:bold" char *font;
char *DefaultFontName;
XftFont *DefaultFont;
u_int FontHeight;
int gap_top, gap_bottom, gap_left, gap_right;
};
/* 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 dummy;
};
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
}; };
/* MWM hints */ /* MWM hints */
struct mwm_hints { struct mwm_hints {
u_long flags; u_long flags;
u_long functions; u_long functions;
u_long decorations; u_long decorations;
}; };
#define MWM_NUMHINTS 3
#define MWM_NUMHINTS 3
#define PROP_MWM_HINTS_ELEMENTS 3 #define PROP_MWM_HINTS_ELEMENTS 3
#define MWM_HINTS_DECORATIONS (1 << 1) #define MWM_HINTS_DECORATIONS (1<<1)
#define MWM_DECOR_ALL (1 << 0) #define MWM_DECOR_ALL (1<<0)
#define MWM_DECOR_BORDER (1 << 1) #define MWM_DECOR_BORDER (1<<1)
int input_keycodetrans(KeyCode, u_int, enum ctltype *,
char *);
__dead void usage(void); __dead void usage(void);
struct client_ctx *client_find(Window); void client_applysizehints(struct client_ctx *);
void client_init(void);
struct client_ctx *client_new(Window, struct screen_ctx *, int);
int client_delete(struct client_ctx *);
void client_setactive(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); struct client_ctx *client_current(void);
void client_hide(struct client_ctx *); void client_cycle(struct screen_ctx *, int);
void client_unhide(struct client_ctx *); void client_delete(struct client_ctx *);
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_draw_border(struct client_ctx *);
void client_maximize(struct client_ctx *); struct client_ctx *client_find(Window);
void client_vertmaximize(struct client_ctx *); 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_map(struct client_ctx *);
void client_maximize(struct client_ctx *);
void client_move(struct client_ctx *);
void client_mtf(struct client_ctx *); void client_mtf(struct client_ctx *);
struct client_ctx *client_cycle(int); 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 *);
struct menu *menu_filter(struct menu_q *, char *, 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 *);
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);
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 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 *);
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 *);
struct menu *menu_filter(struct screen_ctx *, struct menu_q *,
char *, char *, int,
void (*)(struct menu_q *, struct menu_q *, char *), void (*)(struct menu_q *, struct menu_q *, char *),
void (*)(struct menu *, int)); void (*)(struct menu *, int));
void menu_init(struct screen_ctx *); void menu_init(struct screen_ctx *);
/* XXX should be xu_ */ int parse_config(const char *, struct conf *);
void xev_reconfig(struct client_ctx *);
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 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 *);
void xev_loop(void); void xev_loop(void);
void xu_getatoms(void);
int xu_ptr_grab(Window, int, Cursor);
void xu_btn_grab(Window, int, u_int); void xu_btn_grab(Window, int, u_int);
int xu_ptr_regrab(int, Cursor);
void xu_btn_ungrab(Window, int, u_int); void xu_btn_ungrab(Window, int, u_int);
void xu_ptr_ungrab(void); void xu_configure(struct client_ctx *);
void xu_ptr_setpos(Window, int, int); void xu_freecolor(struct screen_ctx *, unsigned long);
void xu_ptr_getpos(Window, int *, int *); 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_grab(Window, int, int);
void xu_key_ungrab(Window, int, int); void xu_key_ungrab(Window, int, int);
void xu_sendmsg(struct client_ctx *, Atom, long); void xu_ptr_getpos(Window, int *, int *);
int xu_getprop(struct client_ctx *, Atom, Atom, long, int xu_ptr_grab(Window, int, Cursor);
u_char **); int xu_ptr_regrab(int, Cursor);
char *xu_getstrprop(struct client_ctx *, Atom atm); 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_setstate(struct client_ctx *, int);
int xu_getstate(struct client_ctx *, int *); void xu_setwmname(struct screen_ctx *);
unsigned long xu_getcolor(struct screen_ctx *, char *);
void xu_freecolor(struct screen_ctx *, unsigned long);
int u_spawn(char *);
void u_exec(char *); void u_exec(char *);
void u_spawn(char *);
void *xcalloc(size_t, size_t);
void xfree(void *); void xfree(void *);
void *xmalloc(size_t); void *xmalloc(size_t);
void *xcalloc(size_t, size_t);
char *xstrdup(const char *); char *xstrdup(const char *);
void screen_init(void);
struct screen_ctx *screen_fromroot(Window);
struct screen_ctx *screen_current(void);
void screen_updatestackingorder(void);
void screen_init_xinerama(struct screen_ctx *);
XineramaScreenInfo *screen_find_xinerama(struct screen_ctx *, int, int);
void conf_setup(struct conf *, const char *);
void conf_client(struct client_ctx *);
void conf_grab(struct conf *, struct keybinding *);
void conf_ungrab(struct conf *, struct keybinding *);
void conf_bindname(struct conf *, char *, char *);
void conf_mousebind(struct conf *, char *, char *);
void conf_grab_mouse(struct client_ctx *);
void conf_reload(struct conf *);
void conf_font(struct conf *);
void conf_color(struct conf *);
void conf_init(struct conf *);
void conf_clear(struct conf *);
void conf_cmd_add(struct conf *, char *, char *, int);
int parse_config(const char *, struct conf *);
void kbfunc_client_lower(struct client_ctx *, union arg *);
void kbfunc_client_raise(struct client_ctx *, union arg *);
void kbfunc_client_search(struct client_ctx *, union arg *);
void kbfunc_client_hide(struct client_ctx *, union arg *);
void kbfunc_client_cycle(struct client_ctx *, union arg *);
void kbfunc_client_rcycle(struct client_ctx *, union arg *);
void kbfunc_cmdexec(struct client_ctx *, union arg *);
void kbfunc_client_label(struct client_ctx *, union arg *);
void kbfunc_client_delete(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_cyclegroup(struct client_ctx *,
union arg *);
void kbfunc_client_nogroup(struct client_ctx *,
union arg *);
void kbfunc_client_grouptoggle(struct client_ctx *,
union arg *);
void kbfunc_client_movetogroup(struct client_ctx *,
union arg *);
void kbfunc_client_maximize(struct client_ctx *,
union arg *);
void kbfunc_client_vmaximize(struct client_ctx *,
union arg *);
void kbfunc_reload(struct client_ctx *, union arg *);
void kbfunc_quit_wm(struct client_ctx *, union arg *);
void kbfunc_moveresize(struct client_ctx *, union arg *);
void kbfunc_menu_search(struct client_ctx *, union arg *);
void kbfunc_exec(struct client_ctx *, union arg *);
void kbfunc_ssh(struct client_ctx *, union arg *);
void kbfunc_term(struct client_ctx *, union arg *);
void kbfunc_lock(struct client_ctx *, union arg *);
void mousefunc_window_resize(struct client_ctx *, void *);
void mousefunc_window_move(struct client_ctx *, void *);
void mousefunc_window_grouptoggle(struct client_ctx *,
void *);
void mousefunc_window_lower(struct client_ctx *, void *);
void mousefunc_window_hide(struct client_ctx *, void *);
void mousefunc_menu_group(struct client_ctx *, void *);
void mousefunc_menu_unhide(struct client_ctx *, void *);
void mousefunc_menu_cmd(struct client_ctx *, void *);
void search_match_client(struct menu_q *, struct menu_q *,
char *);
void search_print_client(struct menu *, int);
void search_match_text(struct menu_q *, struct menu_q *,
char *);
void search_match_exec(struct menu_q *, struct menu_q *,
char *);
void group_init(void);
void group_hidetoggle(int);
void group_only(int);
void group_cycle(int);
void group_sticky(struct client_ctx *);
void group_client_delete(struct client_ctx *);
void group_menu(XButtonEvent *);
void group_alltoggle(void);
void group_sticky_toggle_enter(struct client_ctx *);
void group_sticky_toggle_exit(struct client_ctx *);
void group_autogroup(struct client_ctx *);
void group_movetogroup(struct client_ctx *, int);
void font_init(struct screen_ctx *);
int font_width(const char *, int);
void font_draw(struct screen_ctx *, const char *, int,
Drawable, int, int);
XftFont *font_make(struct screen_ctx *, const char *);
#define font_ascent() Conf.DefaultFont->ascent
#define font_descent() Conf.DefaultFont->descent
#define font_height() Conf.FontHeight
#define CCTOSC(cc) (cc->sc)
/* Externs */ /* Externs */
extern Display *X_Dpy; extern Display *X_Dpy;
extern Cursor Cursor_move;
extern Cursor Cursor_resize;
extern Cursor Cursor_select;
extern Cursor Cursor_default; extern Cursor Cursor_default;
extern Cursor Cursor_move;
extern Cursor Cursor_normal;
extern Cursor Cursor_question; extern Cursor Cursor_question;
extern Cursor Cursor_resize;
extern struct screen_ctx_q Screenq; extern struct screen_ctx_q Screenq;
extern struct screen_ctx *curscreen;
extern struct client_ctx_q Clientq; extern struct client_ctx_q Clientq;
extern struct conf Conf;
extern int HasXinerama, HasRandr, Randr_ev; extern int HasXinerama, HasRandr, Randr_ev;
extern struct conf Conf;
#define WM_STATE cwm_atoms[0] #define WM_STATE cwm_atoms[0]
#define WM_DELETE_WINDOW cwm_atoms[1] #define WM_DELETE_WINDOW cwm_atoms[1]
#define WM_TAKE_FOCUS cwm_atoms[2] #define WM_TAKE_FOCUS cwm_atoms[2]
#define WM_PROTOCOLS cwm_atoms[3] #define WM_PROTOCOLS cwm_atoms[3]
#define _MOTIF_WM_HINTS cwm_atoms[4] #define _MOTIF_WM_HINTS cwm_atoms[4]
#define _CWM_GRP cwm_atoms[5] #define UTF8_STRING cwm_atoms[5]
#define CWM_NO_ATOMS 6 /*
* 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]; extern Atom cwm_atoms[CWM_NO_ATOMS];

526
client.c
View File

@ -15,14 +15,25 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
* *
* $Id$ * $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" #include "calmwm.h"
static struct client_ctx *client_mrunext(struct client_ctx *); static struct client_ctx *client_mrunext(struct client_ctx *);
static struct client_ctx *client_mruprev(struct client_ctx *); static struct client_ctx *client_mruprev(struct client_ctx *);
static void client_none(struct screen_ctx *);
static void client_placecalc(struct client_ctx *); static void client_placecalc(struct client_ctx *);
static void client_update(struct client_ctx *); static void client_update(struct client_ctx *);
static void client_gethints(struct client_ctx *); static void client_gethints(struct client_ctx *);
@ -32,12 +43,6 @@ static int client_inbound(struct client_ctx *, int, int);
static char emptystring[] = ""; static char emptystring[] = "";
struct client_ctx *_curcc = NULL; struct client_ctx *_curcc = NULL;
void
client_init(void)
{
TAILQ_INIT(&Clientq);
}
struct client_ctx * struct client_ctx *
client_find(Window win) client_find(Window win)
{ {
@ -56,7 +61,6 @@ client_new(Window win, struct screen_ctx *sc, int mapped)
struct client_ctx *cc; struct client_ctx *cc;
XWindowAttributes wattr; XWindowAttributes wattr;
XWMHints *wmhints; XWMHints *wmhints;
long tmp;
int state; int state;
if (win == None) if (win == None)
@ -71,14 +75,7 @@ client_new(Window win, struct screen_ctx *sc, int mapped)
cc->win = win; cc->win = win;
cc->size = XAllocSizeHints(); cc->size = XAllocSizeHints();
XGetWMNormalHints(X_Dpy, cc->win, cc->size, &tmp); client_getsizehints(cc);
if (cc->size->flags & PBaseSize) {
cc->geom.min_dx = cc->size->base_width;
cc->geom.min_dy = cc->size->base_height;
} else if (cc->size->flags & PMinSize) {
cc->geom.min_dx = cc->size->min_width;
cc->geom.min_dy = cc->size->min_height;
}
TAILQ_INIT(&cc->nameq); TAILQ_INIT(&cc->nameq);
client_setname(cc); client_setname(cc);
@ -116,8 +113,10 @@ client_new(Window win, struct screen_ctx *sc, int mapped)
XAddToSaveSet(X_Dpy, cc->win); XAddToSaveSet(X_Dpy, cc->win);
client_transient(cc);
/* Notify client of its configuration. */ /* Notify client of its configuration. */
xev_reconfig(cc); xu_configure(cc);
(state == IconicState) ? client_hide(cc) : client_unhide(cc); (state == IconicState) ? client_hide(cc) : client_unhide(cc);
xu_setstate(cc, cc->state); xu_setstate(cc, cc->state);
@ -127,6 +126,9 @@ client_new(Window win, struct screen_ctx *sc, int mapped)
TAILQ_INSERT_TAIL(&sc->mruq, cc, mru_entry); TAILQ_INSERT_TAIL(&sc->mruq, cc, mru_entry);
TAILQ_INSERT_TAIL(&Clientq, cc, entry); TAILQ_INSERT_TAIL(&Clientq, cc, entry);
/* append to the client list */
XChangeProperty(X_Dpy, sc->rootwin, _NET_CLIENT_LIST, XA_WINDOW, 32,
PropModeAppend, (unsigned char *)&cc->win, 1);
client_gethints(cc); client_gethints(cc);
client_update(cc); client_update(cc);
@ -137,11 +139,14 @@ client_new(Window win, struct screen_ctx *sc, int mapped)
return (cc); return (cc);
} }
int void
client_delete(struct client_ctx *cc) client_delete(struct client_ctx *cc)
{ {
struct screen_ctx *sc = CCTOSC(cc); struct screen_ctx *sc = cc->sc;
struct client_ctx *tcc;
struct winname *wn; struct winname *wn;
Window *winlist;
int i, j;
group_client_delete(cc); group_client_delete(cc);
@ -154,23 +159,38 @@ client_delete(struct client_ctx *cc)
TAILQ_REMOVE(&sc->mruq, cc, mru_entry); TAILQ_REMOVE(&sc->mruq, cc, mru_entry);
TAILQ_REMOVE(&Clientq, cc, entry); TAILQ_REMOVE(&Clientq, cc, entry);
/*
* Sadly we can't remove just one entry from a property, so we must
* redo the whole thing from scratch. this is the stupid way, the other
* way incurs many roundtrips to the server.
*/
i = j = 0;
TAILQ_FOREACH(tcc, &Clientq, entry)
i++;
if (i > 0) {
winlist = xmalloc(i * sizeof(*winlist));
TAILQ_FOREACH(tcc, &Clientq, entry)
winlist[j++] = tcc->win;
XChangeProperty(X_Dpy, sc->rootwin, _NET_CLIENT_LIST,
XA_WINDOW, 32, PropModeReplace,
(unsigned char *)winlist, i);
xfree(winlist);
}
if (_curcc == cc) if (_curcc == cc)
_curcc = NULL; client_none(sc);
XFree(cc->size); XFree(cc->size);
while ((wn = TAILQ_FIRST(&cc->nameq)) != NULL) { while ((wn = TAILQ_FIRST(&cc->nameq)) != NULL) {
TAILQ_REMOVE(&cc->nameq, wn, entry); TAILQ_REMOVE(&cc->nameq, wn, entry);
if (wn->name != emptystring) if (wn->name != emptystring)
XFree(wn->name); xfree(wn->name);
xfree(wn); xfree(wn);
} }
client_freehints(cc); client_freehints(cc);
xfree(cc); xfree(cc);
return (0);
} }
void void
@ -183,7 +203,7 @@ client_leave(struct client_ctx *cc)
if (cc == NULL) if (cc == NULL)
return; return;
sc = CCTOSC(cc); sc = cc->sc;
xu_btn_ungrab(sc->rootwin, AnyModifier, Button1); xu_btn_ungrab(sc->rootwin, AnyModifier, Button1);
} }
@ -197,7 +217,7 @@ client_setactive(struct client_ctx *cc, int fg)
if (cc == NULL) if (cc == NULL)
return; return;
sc = CCTOSC(cc); sc = cc->sc;
if (fg) { if (fg) {
XInstallColormap(X_Dpy, cc->cmap); XInstallColormap(X_Dpy, cc->cmap);
@ -216,113 +236,210 @@ client_setactive(struct client_ctx *cc, int fg)
if (fg && _curcc != cc) { if (fg && _curcc != cc) {
client_setactive(NULL, 0); client_setactive(NULL, 0);
_curcc = cc; _curcc = cc;
XChangeProperty(X_Dpy, sc->rootwin, _NET_ACTIVE_WINDOW,
XA_WINDOW, 32, PropModeReplace,
(unsigned char *)&cc->win, 1);
} }
cc->active = fg; cc->active = fg;
client_draw_border(cc); client_draw_border(cc);
} }
/*
* set when there is no active client
*/
static void
client_none(struct screen_ctx *sc)
{
Window none = None;
XChangeProperty(X_Dpy, sc->rootwin, _NET_ACTIVE_WINDOW,
XA_WINDOW, 32, PropModeReplace, (unsigned char *)&none, 1);
_curcc = NULL;
}
struct client_ctx * struct client_ctx *
client_current(void) client_current(void)
{ {
return (_curcc); return (_curcc);
} }
void
client_freeze(struct client_ctx *cc)
{
if (cc->flags & CLIENT_FREEZE)
cc->flags &= ~CLIENT_FREEZE;
else
cc->flags |= CLIENT_FREEZE;
}
void void
client_maximize(struct client_ctx *cc) client_maximize(struct client_ctx *cc)
{ {
struct screen_ctx *sc = CCTOSC(cc); struct screen_ctx *sc = cc->sc;
int xmax = sc->xmax, ymax = sc->ymax; int xmax = sc->xmax, ymax = sc->ymax;
int x_org = 0, y_org = 0; int x_org = 0, y_org = 0;
if (cc->flags & CLIENT_MAXIMIZED) { if (cc->flags & CLIENT_FREEZE)
return;
if ((cc->flags & CLIENT_MAXFLAGS) == CLIENT_MAXIMIZED) {
cc->flags &= ~CLIENT_MAXIMIZED;
cc->geom = cc->savegeom; cc->geom = cc->savegeom;
} else { cc->bwidth = Conf.bwidth;
if (!(cc->flags & CLIENT_VMAXIMIZED)) goto resize;
cc->savegeom = cc->geom;
if (HasXinerama) {
XineramaScreenInfo *xine;
/*
* pick screen that the middle of the window is on.
* that's probably more fair than if just the origin of
* a window is poking over a boundary
*/
xine = screen_find_xinerama(CCTOSC(cc),
cc->geom.x + cc->geom.width / 2,
cc->geom.y + cc->geom.height / 2);
if (xine == NULL)
goto calc;
x_org = xine->x_org;
y_org = xine->y_org;
xmax = xine->width;
ymax = xine->height;
}
calc:
cc->geom.x = x_org - cc->bwidth + Conf.gap_left;
cc->geom.y = y_org - cc->bwidth + Conf.gap_top;
cc->geom.height = ymax - (Conf.gap_top + Conf.gap_bottom);
cc->geom.width = xmax - (Conf.gap_left + Conf.gap_right);
cc->flags |= CLIENT_DOMAXIMIZE;
} }
if ((cc->flags & CLIENT_VMAXIMIZED) == 0) {
cc->savegeom.height = cc->geom.height;
cc->savegeom.y = cc->geom.y;
}
if ((cc->flags & CLIENT_HMAXIMIZED) == 0) {
cc->savegeom.width = cc->geom.width;
cc->savegeom.x = cc->geom.x;
}
if (HasXinerama) {
XineramaScreenInfo *xine;
/*
* pick screen that the middle of the window is on.
* that's probably more fair than if just the origin of
* a window is poking over a boundary
*/
xine = screen_find_xinerama(sc,
cc->geom.x + cc->geom.width / 2,
cc->geom.y + cc->geom.height / 2);
if (xine == NULL)
goto calc;
x_org = xine->x_org;
y_org = xine->y_org;
xmax = xine->width;
ymax = xine->height;
}
calc:
cc->geom.x = x_org + sc->gap.left;
cc->geom.y = y_org + sc->gap.top;
cc->geom.height = ymax - (sc->gap.top + sc->gap.bottom);
cc->geom.width = xmax - (sc->gap.left + sc->gap.right);
cc->bwidth = 0;
cc->flags |= CLIENT_MAXIMIZED;
resize:
client_resize(cc); client_resize(cc);
} }
void void
client_vertmaximize(struct client_ctx *cc) client_vertmaximize(struct client_ctx *cc)
{ {
struct screen_ctx *sc = CCTOSC(cc); struct screen_ctx *sc = cc->sc;
int y_org = 0, ymax = sc->ymax; int y_org = 0, ymax = sc->ymax;
if (cc->flags & CLIENT_FREEZE)
return;
if (cc->flags & CLIENT_VMAXIMIZED) { if (cc->flags & CLIENT_VMAXIMIZED) {
cc->geom = cc->savegeom; cc->geom.y = cc->savegeom.y;
} else { cc->geom.height = cc->savegeom.height;
if (!(cc->flags & CLIENT_MAXIMIZED)) cc->bwidth = Conf.bwidth;
cc->savegeom = cc->geom; if (cc->flags & CLIENT_HMAXIMIZED)
if (HasXinerama) { cc->geom.width -= cc->bwidth * 2;
XineramaScreenInfo *xine; cc->flags &= ~CLIENT_VMAXIMIZED;
xine = screen_find_xinerama(CCTOSC(cc), goto resize;
cc->geom.x + cc->geom.width / 2,
cc->geom.y + cc->geom.height / 2);
if (xine == NULL)
goto calc;
y_org = xine->y_org;
ymax = xine->height;
}
calc:
cc->geom.y = y_org + Conf.gap_top;
cc->geom.height = ymax - (cc->bwidth * 2) - (Conf.gap_top +
Conf.gap_bottom);
cc->flags |= CLIENT_DOVMAXIMIZE;
} }
cc->savegeom.y = cc->geom.y;
cc->savegeom.height = cc->geom.height;
/* if this will make us fully maximized then remove boundary */
if ((cc->flags & CLIENT_MAXFLAGS) == CLIENT_HMAXIMIZED) {
cc->geom.width += Conf.bwidth * 2;
cc->bwidth = 0;
}
if (HasXinerama) {
XineramaScreenInfo *xine;
xine = screen_find_xinerama(sc,
cc->geom.x + cc->geom.width / 2,
cc->geom.y + cc->geom.height / 2);
if (xine == NULL)
goto calc;
y_org = xine->y_org;
ymax = xine->height;
}
calc:
cc->geom.y = y_org + sc->gap.top;
cc->geom.height = ymax - (cc->bwidth * 2) - (sc->gap.top +
sc->gap.bottom);
cc->flags |= CLIENT_VMAXIMIZED;
resize:
client_resize(cc);
}
void
client_horizmaximize(struct client_ctx *cc)
{
struct screen_ctx *sc = cc->sc;
int x_org = 0, xmax = sc->xmax;
if (cc->flags & CLIENT_FREEZE)
return;
if (cc->flags & CLIENT_HMAXIMIZED) {
cc->geom.x = cc->savegeom.x;
cc->geom.width = cc->savegeom.width;
cc->bwidth = Conf.bwidth;
if (cc->flags & CLIENT_VMAXIMIZED)
cc->geom.height -= cc->bwidth * 2;
cc->flags &= ~CLIENT_HMAXIMIZED;
goto resize;
}
cc->savegeom.x = cc->geom.x;
cc->savegeom.width = cc->geom.width;
/* if this will make us fully maximized then remove boundary */
if ((cc->flags & CLIENT_MAXFLAGS) == CLIENT_VMAXIMIZED) {
cc->geom.height += cc->bwidth * 2;
cc->bwidth = 0;
}
if (HasXinerama) {
XineramaScreenInfo *xine;
xine = screen_find_xinerama(sc,
cc->geom.x + cc->geom.width / 2,
cc->geom.y + cc->geom.height / 2);
if (xine == NULL)
goto calc;
x_org = xine->x_org;
xmax = xine->width;
}
calc:
cc->geom.x = x_org + sc->gap.left;
cc->geom.width = xmax - (cc->bwidth * 2) - (sc->gap.left +
sc->gap.right);
cc->flags |= CLIENT_HMAXIMIZED;
resize:
client_resize(cc); client_resize(cc);
} }
void void
client_resize(struct client_ctx *cc) client_resize(struct client_ctx *cc)
{ {
if (cc->flags & (CLIENT_MAXIMIZED | CLIENT_VMAXIMIZED)) client_draw_border(cc);
cc->flags &= ~(CLIENT_MAXIMIZED | CLIENT_VMAXIMIZED);
if (cc->flags & CLIENT_DOMAXIMIZE) {
cc->flags &= ~CLIENT_DOMAXIMIZE;
cc->flags |= CLIENT_MAXIMIZED;
} else if (cc->flags & CLIENT_DOVMAXIMIZE) {
cc->flags &= ~CLIENT_DOVMAXIMIZE;
cc->flags |= CLIENT_VMAXIMIZED;
}
XMoveResizeWindow(X_Dpy, cc->win, cc->geom.x, XMoveResizeWindow(X_Dpy, cc->win, cc->geom.x,
cc->geom.y, cc->geom.width, cc->geom.height); cc->geom.y, cc->geom.width, cc->geom.height);
xev_reconfig(cc); xu_configure(cc);
} }
void void
client_move(struct client_ctx *cc) client_move(struct client_ctx *cc)
{ {
XMoveWindow(X_Dpy, cc->win, cc->geom.x, cc->geom.y); XMoveWindow(X_Dpy, cc->win, cc->geom.x, cc->geom.y);
xev_reconfig(cc); xu_configure(cc);
} }
void void
@ -360,6 +477,9 @@ client_ptrsave(struct client_ctx *cc)
if (client_inbound(cc, x, y)) { if (client_inbound(cc, x, y)) {
cc->ptr.x = x; cc->ptr.x = x;
cc->ptr.y = y; cc->ptr.y = y;
} else {
cc->ptr.x = -1;
cc->ptr.y = -1;
} }
} }
@ -374,7 +494,7 @@ client_hide(struct client_ctx *cc)
xu_setstate(cc, IconicState); xu_setstate(cc, IconicState);
if (cc == _curcc) if (cc == _curcc)
_curcc = NULL; client_none(cc->sc);
} }
void void
@ -391,7 +511,7 @@ client_unhide(struct client_ctx *cc)
void void
client_draw_border(struct client_ctx *cc) client_draw_border(struct client_ctx *cc)
{ {
struct screen_ctx *sc = CCTOSC(cc); struct screen_ctx *sc = cc->sc;
unsigned long pixel; unsigned long pixel;
if (cc->active) if (cc->active)
@ -403,7 +523,7 @@ client_draw_border(struct client_ctx *cc)
pixel = sc->color[CWM_COLOR_BORDER_UNGROUP].pixel; pixel = sc->color[CWM_COLOR_BORDER_UNGROUP].pixel;
break; break;
default: default:
pixel = sc->color[CWM_COLOR_BORDOR_ACTIVE].pixel; pixel = sc->color[CWM_COLOR_BORDER_ACTIVE].pixel;
break; break;
} }
else else
@ -416,11 +536,11 @@ client_draw_border(struct client_ctx *cc)
static void static void
client_update(struct client_ctx *cc) client_update(struct client_ctx *cc)
{ {
Atom *p; Atom *p;
int i; int i;
long n; long n;
if ((n = xu_getprop(cc, WM_PROTOCOLS, if ((n = xu_getprop(cc->win, WM_PROTOCOLS,
XA_ATOM, 20L, (u_char **)&p)) <= 0) XA_ATOM, 20L, (u_char **)&p)) <= 0)
return; return;
@ -437,7 +557,7 @@ void
client_send_delete(struct client_ctx *cc) client_send_delete(struct client_ctx *cc)
{ {
if (cc->xproto & CLIENT_PROTO_DELETE) if (cc->xproto & CLIENT_PROTO_DELETE)
xu_sendmsg(cc, WM_PROTOCOLS, WM_DELETE_WINDOW); xu_sendmsg(cc->win, WM_PROTOCOLS, WM_DELETE_WINDOW);
else else
XKillClient(X_Dpy, cc->win); XKillClient(X_Dpy, cc->win);
} }
@ -448,9 +568,9 @@ client_setname(struct client_ctx *cc)
struct winname *wn; struct winname *wn;
char *newname; char *newname;
XFetchName(X_Dpy, cc->win, &newname); if (!xu_getstrprop(cc->win, _NET_WM_NAME, &newname))
if (newname == NULL) if (!xu_getstrprop(cc->win, XA_WM_NAME, &newname))
newname = emptystring; newname = emptystring;
TAILQ_FOREACH(wn, &cc->nameq, entry) TAILQ_FOREACH(wn, &cc->nameq, entry)
if (strcmp(wn->name, newname) == 0) { if (strcmp(wn->name, newname) == 0) {
@ -474,47 +594,44 @@ match:
assert(wn != NULL); assert(wn != NULL);
TAILQ_REMOVE(&cc->nameq, wn, entry); TAILQ_REMOVE(&cc->nameq, wn, entry);
if (wn->name != emptystring) if (wn->name != emptystring)
XFree(wn->name); xfree(wn->name);
xfree(wn); xfree(wn);
cc->nameqlen--; cc->nameqlen--;
} }
return;
} }
struct client_ctx * void
client_cycle(int reverse) client_cycle(struct screen_ctx *sc, int flags)
{ {
struct client_ctx *oldcc, *newcc; struct client_ctx *oldcc, *newcc;
struct screen_ctx *sc;
int again = 1; int again = 1;
oldcc = client_current(); oldcc = client_current();
sc = screen_current();
/* If no windows then you cant cycle */ /* If no windows then you cant cycle */
if (TAILQ_EMPTY(&sc->mruq)) if (TAILQ_EMPTY(&sc->mruq))
return (NULL); return;
if (oldcc == NULL) if (oldcc == NULL)
oldcc = (reverse ? TAILQ_LAST(&sc->mruq, cycle_entry_q) : oldcc = (flags & CWM_RCYCLE ? TAILQ_LAST(&sc->mruq, cycle_entry_q) :
TAILQ_FIRST(&sc->mruq)); TAILQ_FIRST(&sc->mruq));
newcc = oldcc; newcc = oldcc;
while (again) { while (again) {
again = 0; again = 0;
newcc = (reverse ? client_mruprev(newcc) : newcc = (flags & CWM_RCYCLE ? client_mruprev(newcc) :
client_mrunext(newcc)); client_mrunext(newcc));
/* Only cycle visible and non-ignored windows. */ /* Only cycle visible and non-ignored windows. */
if (newcc->flags & (CLIENT_HIDDEN|CLIENT_IGNORE)) if ((newcc->flags & (CLIENT_HIDDEN|CLIENT_IGNORE))
|| ((flags & CWM_INGROUP) && (newcc->group != oldcc->group)))
again = 1; again = 1;
/* Is oldcc the only non-hidden window? */ /* Is oldcc the only non-hidden window? */
if (newcc == oldcc) { if (newcc == oldcc) {
if (again) if (again)
return (NULL); /* No windows visible. */ return; /* No windows visible. */
break; break;
} }
@ -524,14 +641,12 @@ client_cycle(int reverse)
sc->altpersist = 1; sc->altpersist = 1;
client_ptrsave(oldcc); client_ptrsave(oldcc);
client_ptrwarp(newcc); client_ptrwarp(newcc);
return (newcc);
} }
static struct client_ctx * static struct client_ctx *
client_mrunext(struct client_ctx *cc) client_mrunext(struct client_ctx *cc)
{ {
struct screen_ctx *sc = CCTOSC(cc); struct screen_ctx *sc = cc->sc;
struct client_ctx *ccc; struct client_ctx *ccc;
return ((ccc = TAILQ_NEXT(cc, mru_entry)) != NULL ? return ((ccc = TAILQ_NEXT(cc, mru_entry)) != NULL ?
@ -541,7 +656,7 @@ client_mrunext(struct client_ctx *cc)
static struct client_ctx * static struct client_ctx *
client_mruprev(struct client_ctx *cc) client_mruprev(struct client_ctx *cc)
{ {
struct screen_ctx *sc = CCTOSC(cc); struct screen_ctx *sc = cc->sc;
struct client_ctx *ccc; struct client_ctx *ccc;
return ((ccc = TAILQ_PREV(cc, cycle_entry_q, mru_entry)) != NULL ? return ((ccc = TAILQ_PREV(cc, cycle_entry_q, mru_entry)) != NULL ?
@ -551,10 +666,10 @@ client_mruprev(struct client_ctx *cc)
static void static void
client_placecalc(struct client_ctx *cc) client_placecalc(struct client_ctx *cc)
{ {
struct screen_ctx *sc = CCTOSC(cc); struct screen_ctx *sc = cc->sc;
int xslack, yslack; int xslack, yslack;
if (cc->size->flags & USPosition) { if (cc->size->flags & (USPosition|PPosition)) {
/* /*
* Ignore XINERAMA screens, just make sure it's somewhere * Ignore XINERAMA screens, just make sure it's somewhere
* in the virtual desktop. else it stops people putting xterms * in the virtual desktop. else it stops people putting xterms
@ -599,21 +714,21 @@ noxine:
if (xslack >= xorig) { if (xslack >= xorig) {
cc->geom.x = MAX(MIN(xmouse, xslack), cc->geom.x = MAX(MIN(xmouse, xslack),
xorig + Conf.gap_left); xorig + sc->gap.left);
if (cc->geom.x > (xslack - Conf.gap_right)) if (cc->geom.x > (xslack - sc->gap.right))
cc->geom.x -= Conf.gap_right; cc->geom.x -= sc->gap.right;
} else { } else {
cc->geom.x = xorig + Conf.gap_left; cc->geom.x = xorig + sc->gap.left;
cc->geom.width = xmax - Conf.gap_left; cc->geom.width = xmax - sc->gap.left;
} }
if (yslack >= yorig) { if (yslack >= yorig) {
cc->geom.y = MAX(MIN(ymouse, yslack), cc->geom.y = MAX(MIN(ymouse, yslack),
yorig + Conf.gap_top); yorig + sc->gap.top);
if (cc->geom.y > (yslack - Conf.gap_bottom)) if (cc->geom.y > (yslack - sc->gap.bottom))
cc->geom.y -= Conf.gap_bottom; cc->geom.y -= sc->gap.bottom;
} else { } else {
cc->geom.y = yorig + Conf.gap_top; cc->geom.y = yorig + sc->gap.top;
cc->geom.height = ymax - Conf.gap_top; cc->geom.height = ymax - sc->gap.top;
} }
} }
} }
@ -628,19 +743,108 @@ client_mtf(struct client_ctx *cc)
if (cc == NULL) if (cc == NULL)
return; return;
sc = CCTOSC(cc); sc = cc->sc;
/* Move to front. */ /* Move to front. */
TAILQ_REMOVE(&sc->mruq, cc, mru_entry); TAILQ_REMOVE(&sc->mruq, cc, mru_entry);
TAILQ_INSERT_HEAD(&sc->mruq, cc, mru_entry); TAILQ_INSERT_HEAD(&sc->mruq, cc, mru_entry);
} }
void
client_getsizehints(struct client_ctx *cc)
{
long tmp;
if (!XGetWMNormalHints(X_Dpy, cc->win, cc->size, &tmp))
cc->size->flags = PSize;
if (cc->size->flags & PBaseSize) {
cc->hint.basew = cc->size->base_width;
cc->hint.baseh = cc->size->base_height;
} else if (cc->size->flags & PMinSize) {
cc->hint.basew = cc->size->min_width;
cc->hint.baseh = cc->size->min_height;
}
if (cc->size->flags & PMinSize) {
cc->hint.minw = cc->size->min_width;
cc->hint.minh = cc->size->min_height;
} else if (cc->size->flags & PBaseSize) {
cc->hint.minw = cc->size->base_width;
cc->hint.minh = cc->size->base_height;
}
if (cc->size->flags & PMaxSize) {
cc->hint.maxw = cc->size->max_width;
cc->hint.maxh = cc->size->max_height;
}
if (cc->size->flags & PResizeInc) {
cc->hint.incw = cc->size->width_inc;
cc->hint.inch = cc->size->height_inc;
}
cc->hint.incw = MAX(1, cc->hint.incw);
cc->hint.inch = MAX(1, cc->hint.inch);
if (cc->size->flags & PAspect) {
if (cc->size->min_aspect.x > 0)
cc->hint.mina = (float)cc->size->min_aspect.y /
cc->size->min_aspect.x;
if (cc->size->max_aspect.y > 0)
cc->hint.maxa = (float)cc->size->max_aspect.x /
cc->size->max_aspect.y;
}
}
void
client_applysizehints(struct client_ctx *cc)
{
Bool baseismin;
baseismin = (cc->hint.basew == cc->hint.minw) &&
(cc->hint.baseh == cc->hint.minh);
/* temporarily remove base dimensions, ICCCM 4.1.2.3 */
if (!baseismin) {
cc->geom.width -= cc->hint.basew;
cc->geom.height -= cc->hint.baseh;
}
/* adjust for aspect limits */
if (cc->hint.mina > 0 && cc->hint.maxa > 0) {
if (cc->hint.maxa <
(float)cc->geom.width / cc->geom.height)
cc->geom.width = cc->geom.height * cc->hint.maxa;
else if (cc->hint.mina <
(float)cc->geom.height / cc->geom.width)
cc->geom.height = cc->geom.width * cc->hint.mina;
}
/* remove base dimensions for increment */
if (baseismin) {
cc->geom.width -= cc->hint.basew;
cc->geom.height -= cc->hint.baseh;
}
/* adjust for increment value */
cc->geom.width -= cc->geom.width % cc->hint.incw;
cc->geom.height -= cc->geom.height % cc->hint.inch;
/* restore base dimensions */
cc->geom.width += cc->hint.basew;
cc->geom.height += cc->hint.baseh;
/* adjust for min width/height */
cc->geom.width = MAX(cc->geom.width, cc->hint.minw);
cc->geom.height = MAX(cc->geom.height, cc->hint.minh);
/* adjust for max width/height */
if (cc->hint.maxw)
cc->geom.width = MIN(cc->geom.width, cc->hint.maxw);
if (cc->hint.maxh)
cc->geom.height = MIN(cc->geom.height, cc->hint.maxh);
}
static void static void
client_gethints(struct client_ctx *cc) client_gethints(struct client_ctx *cc)
{ {
XClassHint xch; XClassHint xch;
int argc;
char **argv;
struct mwm_hints *mwmh; struct mwm_hints *mwmh;
if (XGetClassHint(X_Dpy, cc->win, &xch)) { if (XGetClassHint(X_Dpy, cc->win, &xch)) {
@ -650,35 +854,12 @@ client_gethints(struct client_ctx *cc)
cc->app_class = xch.res_class; cc->app_class = xch.res_class;
} }
if (xu_getprop(cc, _MOTIF_WM_HINTS, _MOTIF_WM_HINTS, if (xu_getprop(cc->win, _MOTIF_WM_HINTS, _MOTIF_WM_HINTS,
PROP_MWM_HINTS_ELEMENTS, (u_char **)&mwmh) == MWM_NUMHINTS) PROP_MWM_HINTS_ELEMENTS, (u_char **)&mwmh) == MWM_NUMHINTS)
if (mwmh->flags & MWM_HINTS_DECORATIONS && if (mwmh->flags & MWM_HINTS_DECORATIONS &&
!(mwmh->decorations & MWM_DECOR_ALL) && !(mwmh->decorations & MWM_DECOR_ALL) &&
!(mwmh->decorations & MWM_DECOR_BORDER)) !(mwmh->decorations & MWM_DECOR_BORDER))
cc->bwidth = 0; cc->bwidth = 0;
if (XGetCommand(X_Dpy, cc->win, &argv, &argc)) {
#define MAX_ARGLEN 512
#define ARG_SEP_ " "
int i, o, len = MAX_ARGLEN;
char *buf;
buf = xmalloc(len);
buf[0] = '\0';
for (o = 0, i = 0; o < len && i < argc; i++) {
if (argv[i] == NULL)
break;
strlcat(buf, argv[i], len);
o += strlen(buf);
strlcat(buf, ARG_SEP_, len);
o += strlen(ARG_SEP_);
}
if (strlen(buf) > 0)
cc->app_cliarg = buf;
XFreeStringList(argv);
}
} }
static void static void
@ -688,7 +869,21 @@ client_freehints(struct client_ctx *cc)
XFree(cc->app_name); XFree(cc->app_name);
if (cc->app_class != NULL) if (cc->app_class != NULL)
XFree(cc->app_class); XFree(cc->app_class);
xfree(cc->app_cliarg); }
void
client_transient(struct client_ctx *cc)
{
struct client_ctx *tc;
Window trans;
if (XGetTransientForHint(X_Dpy, cc->win, &trans)) {
if ((tc = client_find(trans)) && tc->group) {
group_movetogroup(cc, tc->group->shortcut - 1);
if (tc->flags & CLIENT_IGNORE)
cc->flags |= CLIENT_IGNORE;
}
}
} }
static int static int
@ -697,3 +892,32 @@ client_inbound(struct client_ctx *cc, int x, int y)
return (x < cc->geom.width && x >= 0 && return (x < cc->geom.width && x >= 0 &&
y < cc->geom.height && y >= 0); y < cc->geom.height && y >= 0);
} }
int
client_snapcalc(int n, int dn, int nmax, int bwidth, int snapdist)
{
int n0, n1, s0, s1;
s0 = s1 = 0;
n0 = n;
n1 = n + dn + (bwidth * 2);
if (abs(n0) <= snapdist)
s0 = -n0;
if (nmax - snapdist <= n1 && n1 <= nmax + snapdist)
s1 = nmax - n1;
/* possible to snap in both directions */
if (s0 != 0 && s1 != 0)
if (abs(s0) < abs(s1))
return s0;
else
return s1;
else if (s0 != 0)
return s0;
else if (s1 != 0)
return s1;
else
return 0;
}

368
conf.c
View File

@ -15,24 +15,25 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
* *
* $Id$ * $OpenBSD$
*/ */
#include "headers.h" #include <sys/param.h>
#include "calmwm.h" #include <sys/queue.h>
#include <sys/stat.h>
#ifndef timespeccmp #include <err.h>
#define timespeccmp(tsp, usp, cmp) \ #include <errno.h>
(((tsp)->tv_sec == (usp)->tv_sec) ? \ #include <stdlib.h>
((tsp)->tv_nsec cmp (usp)->tv_nsec) : \ #include <string.h>
((tsp)->tv_sec cmp (usp)->tv_sec)) #include <stdio.h>
#endif #include <unistd.h>
#include "calmwm.h"
static void conf_mouseunbind(struct conf *, struct mousebinding *); static void conf_mouseunbind(struct conf *, struct mousebinding *);
static void conf_unbind(struct conf *, struct keybinding *); static void conf_unbind(struct conf *, struct keybinding *);
extern struct screen_ctx *Curscreen;
/* Add an command menu entry to the end of the menu */ /* Add an command menu entry to the end of the menu */
void void
conf_cmd_add(struct conf *c, char *image, char *label, int flags) conf_cmd_add(struct conf *c, char *image, char *label, int flags)
@ -40,36 +41,45 @@ conf_cmd_add(struct conf *c, char *image, char *label, int flags)
/* "term" and "lock" have special meanings. */ /* "term" and "lock" have special meanings. */
if (strcmp(label, "term") == 0) if (strcmp(label, "term") == 0)
strlcpy(c->termpath, image, sizeof(c->termpath)); (void)strlcpy(c->termpath, image, sizeof(c->termpath));
else if (strcmp(label, "lock") == 0) else if (strcmp(label, "lock") == 0)
strlcpy(c->lockpath, image, sizeof(c->lockpath)); (void)strlcpy(c->lockpath, image, sizeof(c->lockpath));
else { else {
struct cmd *cmd = xmalloc(sizeof(*cmd)); struct cmd *cmd = xmalloc(sizeof(*cmd));
cmd->flags = flags; cmd->flags = flags;
strlcpy(cmd->image, image, sizeof(cmd->image)); (void)strlcpy(cmd->image, image, sizeof(cmd->image));
strlcpy(cmd->label, label, sizeof(cmd->label)); (void)strlcpy(cmd->label, label, sizeof(cmd->label));
TAILQ_INSERT_TAIL(&c->cmdq, cmd, entry); TAILQ_INSERT_TAIL(&c->cmdq, cmd, entry);
} }
} }
void void
conf_font(struct conf *c) conf_gap(struct conf *c, struct screen_ctx *sc)
{ {
struct screen_ctx *sc; sc->gap = c->gap;
sc = screen_current();
c->DefaultFont = font_make(sc, c->DefaultFontName);
c->FontHeight = font_ascent() + font_descent() + 1;
} }
void void
conf_color(struct conf *c) conf_font(struct conf *c, struct screen_ctx *sc)
{ {
struct screen_ctx *sc; font_init(sc, c->color[CWM_COLOR_FONT].name);
int i; sc->font = font_make(sc, c->font);
}
sc = screen_current(); static struct color color_binds[] = {
{ "#CCCCCC", 0 }, /* CWM_COLOR_BORDER_ACTIVE */
{ "#666666", 0 }, /* CWM_COLOR_BORDER_INACTIVE */
{ "blue", 0 }, /* CWM_COLOR_BORDER_GROUP */
{ "red", 0 }, /* CWM_COLOR_BORDER_UNGROUP */
{ "black", 0 }, /* CWM_COLOR_FG_MENU */
{ "white", 0 }, /* CWM_COLOR_BG_MENU */
{ "black", 0 }, /* CWM_COLOR_FONT */
};
void
conf_color(struct conf *c, struct screen_ctx *sc)
{
int i;
for (i = 0; i < CWM_COLOR_MAX; i++) { for (i = 0; i < CWM_COLOR_MAX; i++) {
xu_freecolor(sc, sc->color[i].pixel); xu_freecolor(sc, sc->color[i].pixel);
@ -80,6 +90,7 @@ conf_color(struct conf *c)
void void
conf_reload(struct conf *c) conf_reload(struct conf *c)
{ {
struct screen_ctx *sc;
struct client_ctx *cc; struct client_ctx *cc;
if (parse_config(c->conf_path, c) == -1) { if (parse_config(c->conf_path, c) == -1) {
@ -87,18 +98,98 @@ conf_reload(struct conf *c)
return; return;
} }
conf_color(c); TAILQ_FOREACH(sc, &Screenq, entry) {
conf_gap(c, sc);
conf_color(c, sc);
conf_font(c, sc);
menu_init(sc);
}
TAILQ_FOREACH(cc, &Clientq, entry) TAILQ_FOREACH(cc, &Clientq, entry)
client_draw_border(cc); client_draw_border(cc);
conf_font(c);
} }
static struct {
char *key;
char *func;
} kb_binds[] = {
{ "CM-Return", "terminal" },
{ "CM-Delete", "lock" },
{ "M-question", "exec" },
{ "CM-w", "exec_wm" },
{ "M-period", "ssh" },
{ "M-Return", "hide" },
{ "M-Down", "lower" },
{ "M-Up", "raise" },
{ "M-slash", "search" },
{ "C-slash", "menusearch" },
{ "M-Tab", "cycle" },
{ "MS-Tab", "rcycle" },
{ "CM-n", "label" },
{ "CM-x", "delete" },
{ "CM-0", "nogroup" },
{ "CM-1", "group1" },
{ "CM-2", "group2" },
{ "CM-3", "group3" },
{ "CM-4", "group4" },
{ "CM-5", "group5" },
{ "CM-6", "group6" },
{ "CM-7", "group7" },
{ "CM-8", "group8" },
{ "CM-9", "group9" },
{ "M-Right", "cyclegroup" },
{ "M-Left", "rcyclegroup" },
{ "CM-g", "grouptoggle" },
{ "CM-f", "maximize" },
{ "CM-equal", "vmaximize" },
{ "CMS-equal", "hmaximize" },
{ "CMS-f", "freeze" },
{ "CMS-r", "reload" },
{ "CMS-q", "quit" },
{ "M-h", "moveleft" },
{ "M-j", "movedown" },
{ "M-k", "moveup" },
{ "M-l", "moveright" },
{ "M-H", "bigmoveleft" },
{ "M-J", "bigmovedown" },
{ "M-K", "bigmoveup" },
{ "M-L", "bigmoveright" },
{ "CM-h", "resizeleft" },
{ "CM-j", "resizedown" },
{ "CM-k", "resizeup" },
{ "CM-l", "resizeright" },
{ "CM-H", "bigresizeleft" },
{ "CM-J", "bigresizedown" },
{ "CM-K", "bigresizeup" },
{ "CM-L", "bigresizeright" },
{ "C-Left", "ptrmoveleft" },
{ "C-Down", "ptrmovedown" },
{ "C-Up", "ptrmoveup" },
{ "C-Right", "ptrmoveright" },
{ "CS-Left", "bigptrmoveleft" },
{ "CS-Down", "bigptrmovedown" },
{ "CS-Up", "bigptrmoveup" },
{ "CS-Right", "bigptrmoveright" },
},
m_binds[] = {
{ "1", "menu_unhide" },
{ "2", "menu_group" },
{ "3", "menu_cmd" },
{ "M-1", "window_move" },
{ "CM-1", "window_grouptoggle" },
{ "M-2", "window_resize" },
{ "M-3", "window_lower" },
{ "CMS-3", "window_hide" },
};
void void
conf_init(struct conf *c) conf_init(struct conf *c)
{ {
int i;
c->flags = 0; c->flags = 0;
c->bwidth = CONF_BWIDTH; c->bwidth = CONF_BWIDTH;
c->mamount = CONF_MAMOUNT; c->mamount = CONF_MAMOUNT;
c->snapdist = CONF_SNAPDIST;
TAILQ_INIT(&c->ignoreq); TAILQ_INIT(&c->ignoreq);
TAILQ_INIT(&c->cmdq); TAILQ_INIT(&c->cmdq);
@ -106,92 +197,20 @@ conf_init(struct conf *c)
TAILQ_INIT(&c->autogroupq); TAILQ_INIT(&c->autogroupq);
TAILQ_INIT(&c->mousebindingq); TAILQ_INIT(&c->mousebindingq);
conf_bindname(c, "CM-Return", "terminal"); for (i = 0; i < nitems(kb_binds); i++)
conf_bindname(c, "CM-Delete", "lock"); conf_bindname(c, kb_binds[i].key, kb_binds[i].func);
conf_bindname(c, "M-question", "exec");
conf_bindname(c, "CM-w", "exec_wm");
conf_bindname(c, "M-period", "ssh");
conf_bindname(c, "M-Return", "hide");
conf_bindname(c, "M-Down", "lower");
conf_bindname(c, "M-Up", "raise");
conf_bindname(c, "M-slash", "search");
conf_bindname(c, "C-slash", "menusearch");
conf_bindname(c, "M-Tab", "cycle");
conf_bindname(c, "MS-Tab", "rcycle");
conf_bindname(c, "CM-n", "label");
conf_bindname(c, "CM-x", "delete");
conf_bindname(c, "CM-0", "nogroup");
conf_bindname(c, "CM-1", "group1");
conf_bindname(c, "CM-2", "group2");
conf_bindname(c, "CM-3", "group3");
conf_bindname(c, "CM-4", "group4");
conf_bindname(c, "CM-5", "group5");
conf_bindname(c, "CM-6", "group6");
conf_bindname(c, "CM-7", "group7");
conf_bindname(c, "CM-8", "group8");
conf_bindname(c, "CM-9", "group9");
conf_bindname(c, "M-Right", "cyclegroup");
conf_bindname(c, "M-Left", "rcyclegroup");
conf_bindname(c, "CM-g", "grouptoggle");
conf_bindname(c, "CM-f", "maximize");
conf_bindname(c, "CM-equal", "vmaximize");
conf_bindname(c, "CMS-r", "reload");
conf_bindname(c, "CMS-q", "quit");
conf_bindname(c, "M-h", "moveleft"); for (i = 0; i < nitems(m_binds); i++)
conf_bindname(c, "M-j", "movedown"); conf_mousebind(c, m_binds[i].key, m_binds[i].func);
conf_bindname(c, "M-k", "moveup");
conf_bindname(c, "M-l", "moveright");
conf_bindname(c, "M-H", "bigmoveleft");
conf_bindname(c, "M-J", "bigmovedown");
conf_bindname(c, "M-K", "bigmoveup");
conf_bindname(c, "M-L", "bigmoveright");
conf_bindname(c, "CM-h", "resizeleft"); for (i = 0; i < nitems(color_binds); i++)
conf_bindname(c, "CM-j", "resizedown"); c->color[i].name = xstrdup(color_binds[i].name);
conf_bindname(c, "CM-k", "resizeup");
conf_bindname(c, "CM-l", "resizeright");
conf_bindname(c, "CM-H", "bigresizeleft");
conf_bindname(c, "CM-J", "bigresizedown");
conf_bindname(c, "CM-K", "bigresizeup");
conf_bindname(c, "CM-L", "bigresizeright");
conf_bindname(c, "C-Left", "ptrmoveleft");
conf_bindname(c, "C-Down", "ptrmovedown");
conf_bindname(c, "C-Up", "ptrmoveup");
conf_bindname(c, "C-Right", "ptrmoveright");
conf_bindname(c, "CS-Left", "bigptrmoveleft");
conf_bindname(c, "CS-Down", "bigptrmovedown");
conf_bindname(c, "CS-Up", "bigptrmoveup");
conf_bindname(c, "CS-Right", "bigptrmoveright");
conf_mousebind(c, "1", "menu_unhide");
conf_mousebind(c, "2", "menu_group");
conf_mousebind(c, "3", "menu_cmd");
conf_mousebind(c, "M-1", "window_move");
conf_mousebind(c, "CM-1", "window_grouptoggle");
conf_mousebind(c, "M-2", "window_resize");
conf_mousebind(c, "M-3", "window_lower");
conf_mousebind(c, "CMS-3", "window_hide");
/* Default term/lock */ /* Default term/lock */
strlcpy(c->termpath, "xterm", sizeof(c->termpath)); (void)strlcpy(c->termpath, "xterm", sizeof(c->termpath));
strlcpy(c->lockpath, "xlock", sizeof(c->lockpath)); (void)strlcpy(c->lockpath, "xlock", sizeof(c->lockpath));
c->color[CWM_COLOR_BORDOR_ACTIVE].name = c->font = xstrdup(CONF_FONT);
xstrdup(CONF_COLOR_ACTIVEBORDER);
c->color[CWM_COLOR_BORDER_INACTIVE].name =
xstrdup(CONF_COLOR_INACTIVEBORDER);
c->color[CWM_COLOR_BORDER_GROUP].name =
xstrdup(CONF_COLOR_GROUPBORDER);
c->color[CWM_COLOR_BORDER_UNGROUP].name =
xstrdup(CONF_COLOR_UNGROUPBORDER);
c->color[CWM_COLOR_FG_MENU].name =
xstrdup(CONF_COLOR_MENUFG);
c->color[CWM_COLOR_BG_MENU].name =
xstrdup(CONF_COLOR_MENUBG);
c->DefaultFontName = xstrdup(DEFAULTFONTNAME);
} }
void void
@ -219,7 +238,6 @@ conf_clear(struct conf *c)
xfree(ag->class); xfree(ag->class);
if (ag->name) if (ag->name)
xfree(ag->name); xfree(ag->name);
xfree(ag->group);
xfree(ag); xfree(ag);
} }
@ -236,31 +254,39 @@ conf_clear(struct conf *c)
for (i = 0; i < CWM_COLOR_MAX; i++) for (i = 0; i < CWM_COLOR_MAX; i++)
xfree(c->color[i].name); xfree(c->color[i].name);
xfree(c->DefaultFontName); xfree(c->font);
} }
void void
conf_setup(struct conf *c, const char *conf_file) conf_setup(struct conf *c, const char *conf_file)
{ {
char *home;
struct stat sb; struct stat sb;
int parse = 0;
if (conf_file == NULL) {
char *home = getenv("HOME");
if (home == NULL)
errx(1, "No HOME directory.");
snprintf(c->conf_path, sizeof(c->conf_path), "%s/%s", home,
CONFFILE);
} else
if (stat(conf_file, &sb) == -1 || !(sb.st_mode & S_IFREG))
errx(1, "%s: %s", conf_file, strerror(errno));
else
strlcpy(c->conf_path, conf_file, sizeof(c->conf_path));
conf_init(c); conf_init(c);
(void)parse_config(c->conf_path, c); if (conf_file == NULL) {
if ((home = getenv("HOME")) == NULL)
errx(1, "No HOME directory.");
(void)snprintf(c->conf_path, sizeof(c->conf_path), "%s/%s",
home, CONFFILE);
if (stat(c->conf_path, &sb) == 0 && (sb.st_mode & S_IFREG))
parse = 1;
} else {
if (stat(conf_file, &sb) == -1 || !(sb.st_mode & S_IFREG))
errx(1, "%s: %s", conf_file, strerror(errno));
else {
(void)strlcpy(c->conf_path, conf_file,
sizeof(c->conf_path));
parse = 1;
}
}
if (parse && (parse_config(c->conf_path, c) == -1))
warnx("config file %s has errors, not loading", c->conf_path);
} }
void void
@ -333,11 +359,15 @@ static struct {
{ "movetogroup9", kbfunc_client_movetogroup, KBFLAG_NEEDCLIENT, { "movetogroup9", kbfunc_client_movetogroup, KBFLAG_NEEDCLIENT,
{.i = 9} }, {.i = 9} },
{ "nogroup", kbfunc_client_nogroup, 0, {0} }, { "nogroup", kbfunc_client_nogroup, 0, {0} },
{ "cyclegroup", kbfunc_client_cyclegroup, 0, {.i = CWM_CYCLEGROUP} }, { "cyclegroup", kbfunc_client_cyclegroup, 0, {.i = CWM_CYCLE} },
{ "rcyclegroup", kbfunc_client_cyclegroup, 0, {.i = CWM_RCYCLEGROUP} }, { "rcyclegroup", kbfunc_client_cyclegroup, 0, {.i = CWM_RCYCLE} },
{ "cycleingroup", kbfunc_client_cycle, KBFLAG_NEEDCLIENT, {.i = CWM_CYCLE|CWM_INGROUP} },
{ "rcycleingroup", kbfunc_client_cycle, KBFLAG_NEEDCLIENT, {.i = CWM_RCYCLE|CWM_INGROUP} },
{ "grouptoggle", kbfunc_client_grouptoggle, KBFLAG_NEEDCLIENT, {0}}, { "grouptoggle", kbfunc_client_grouptoggle, KBFLAG_NEEDCLIENT, {0}},
{ "maximize", kbfunc_client_maximize, KBFLAG_NEEDCLIENT, {0} }, { "maximize", kbfunc_client_maximize, KBFLAG_NEEDCLIENT, {0} },
{ "vmaximize", kbfunc_client_vmaximize, KBFLAG_NEEDCLIENT, {0} }, { "vmaximize", kbfunc_client_vmaximize, KBFLAG_NEEDCLIENT, {0} },
{ "hmaximize", kbfunc_client_hmaximize, KBFLAG_NEEDCLIENT, {0} },
{ "freeze", kbfunc_client_freeze, KBFLAG_NEEDCLIENT, {0} },
{ "reload", kbfunc_reload, 0, {0} }, { "reload", kbfunc_reload, 0, {0} },
{ "quit", kbfunc_quit_wm, 0, {0} }, { "quit", kbfunc_quit_wm, 0, {0} },
{ "exec", kbfunc_exec, 0, {.i = CWM_EXEC_PROGRAM} }, { "exec", kbfunc_exec, 0, {.i = CWM_EXEC_PROGRAM} },
@ -390,7 +420,6 @@ static struct {
{.i = (CWM_LEFT|CWM_PTRMOVE|CWM_BIGMOVE)} }, {.i = (CWM_LEFT|CWM_PTRMOVE|CWM_BIGMOVE)} },
{ "bigptrmoveright", kbfunc_moveresize, 0, { "bigptrmoveright", kbfunc_moveresize, 0,
{.i = (CWM_RIGHT|CWM_PTRMOVE|CWM_BIGMOVE)} }, {.i = (CWM_RIGHT|CWM_PTRMOVE|CWM_BIGMOVE)} },
{ NULL, NULL, 0, {0}},
}; };
/* /*
@ -424,36 +453,39 @@ conf_ungrab(struct conf *c, struct keybinding *kb)
xu_key_ungrab(sc->rootwin, kb->modmask, kb->keysym); xu_key_ungrab(sc->rootwin, kb->modmask, kb->keysym);
} }
static struct {
char chr;
int mask;
} bind_mods[] = {
{ 'C', ControlMask },
{ 'M', Mod1Mask },
{ '4', Mod4Mask },
{ 'S', ShiftMask },
};
void void
conf_bindname(struct conf *c, char *name, char *binding) conf_bindname(struct conf *c, char *name, char *binding)
{ {
struct keybinding *current_binding; struct keybinding *current_binding;
char *substring; char *substring, *tmp;
int iter; int iter;
current_binding = xcalloc(1, sizeof(*current_binding)); current_binding = xcalloc(1, sizeof(*current_binding));
if (strchr(name, 'C') != NULL && if ((substring = strchr(name, '-')) != NULL) {
strchr(name, 'C') < strchr(name, '-')) for (iter = 0; iter < nitems(bind_mods); iter++) {
current_binding->modmask |= ControlMask; if ((tmp = strchr(name, bind_mods[iter].chr)) !=
NULL && tmp < substring) {
current_binding->modmask |=
bind_mods[iter].mask;
}
}
if (strchr(name, 'M') != NULL && /* skip past the modifiers */
strchr(name, 'M') < strchr(name, '-')) substring++;
current_binding->modmask |= Mod1Mask; } else {
if (strchr(name, '4') != NULL &&
strchr(name, '4') < strchr(name, '-'))
current_binding->modmask |= Mod4Mask;
if (strchr(name, 'S') != NULL &&
strchr(name, 'S') < strchr(name, '-'))
current_binding->modmask |= ShiftMask;
substring = strchr(name, '-') + 1;
/* If there is no '-' in name, continue as is */
if (strchr(name, '-') == NULL)
substring = name; substring = name;
}
if (substring[0] == '[' && if (substring[0] == '[' &&
substring[strlen(substring)-1] == ']') { substring[strlen(substring)-1] == ']') {
@ -476,7 +508,7 @@ conf_bindname(struct conf *c, char *name, char *binding)
if (strcmp("unmap", binding) == 0) if (strcmp("unmap", binding) == 0)
return; return;
for (iter = 0; name_to_kbfunc[iter].tag != NULL; iter++) { for (iter = 0; iter < nitems(name_to_kbfunc); iter++) {
if (strcmp(name_to_kbfunc[iter].tag, binding) != 0) if (strcmp(name_to_kbfunc[iter].tag, binding) != 0)
continue; continue;
@ -493,7 +525,6 @@ conf_bindname(struct conf *c, char *name, char *binding)
current_binding->flags = 0; current_binding->flags = 0;
conf_grab(c, current_binding); conf_grab(c, current_binding);
TAILQ_INSERT_TAIL(&c->keybindingq, current_binding, entry); TAILQ_INSERT_TAIL(&c->keybindingq, current_binding, entry);
return;
} }
static void static void
@ -528,42 +559,35 @@ static struct {
{ "window_grouptoggle", mousefunc_window_grouptoggle, { "window_grouptoggle", mousefunc_window_grouptoggle,
MOUSEBIND_CTX_WIN }, MOUSEBIND_CTX_WIN },
{ "window_lower", mousefunc_window_lower, MOUSEBIND_CTX_WIN }, { "window_lower", mousefunc_window_lower, MOUSEBIND_CTX_WIN },
{ "window_raise", mousefunc_window_raise, MOUSEBIND_CTX_WIN },
{ "window_hide", mousefunc_window_hide, MOUSEBIND_CTX_WIN }, { "window_hide", mousefunc_window_hide, MOUSEBIND_CTX_WIN },
{ "menu_group", mousefunc_menu_group, MOUSEBIND_CTX_ROOT }, { "menu_group", mousefunc_menu_group, MOUSEBIND_CTX_ROOT },
{ "menu_unhide", mousefunc_menu_unhide, MOUSEBIND_CTX_ROOT }, { "menu_unhide", mousefunc_menu_unhide, MOUSEBIND_CTX_ROOT },
{ "menu_cmd", mousefunc_menu_cmd, MOUSEBIND_CTX_ROOT }, { "menu_cmd", mousefunc_menu_cmd, MOUSEBIND_CTX_ROOT },
{ NULL, NULL, 0 },
}; };
void void
conf_mousebind(struct conf *c, char *name, char *binding) conf_mousebind(struct conf *c, char *name, char *binding)
{ {
struct mousebinding *current_binding; struct mousebinding *current_binding;
char *substring; char *substring, *tmp;
const char *errstr; const char *errstr;
int iter; int iter;
current_binding = xcalloc(1, sizeof(*current_binding)); current_binding = xcalloc(1, sizeof(*current_binding));
if (strchr(name, 'C') != NULL && if ((substring = strchr(name, '-')) != NULL) {
strchr(name, 'C') < strchr(name, '-')) for (iter = 0; iter < nitems(bind_mods); iter++) {
current_binding->modmask |= ControlMask; if ((tmp = strchr(name, bind_mods[iter].chr)) !=
NULL && tmp < substring) {
current_binding->modmask |=
bind_mods[iter].mask;
}
}
if (strchr(name, 'M') != NULL && /* skip past the modifiers */
strchr(name, 'M') < strchr(name, '-')) substring++;
current_binding->modmask |= Mod1Mask; } else
if (strchr(name, 'S') != NULL &&
strchr(name, 'S') < strchr(name, '-'))
current_binding->modmask |= ShiftMask;
if (strchr(name, '4') != NULL &&
strchr(name, '4') < strchr(name, '-'))
current_binding->modmask |= Mod4Mask;
substring = strchr(name, '-') + 1;
if (strchr(name, '-') == NULL)
substring = name; substring = name;
current_binding->button = strtonum(substring, 1, 3, &errstr); current_binding->button = strtonum(substring, 1, 3, &errstr);
@ -575,7 +599,7 @@ conf_mousebind(struct conf *c, char *name, char *binding)
if (strcmp("unmap", binding) == 0) if (strcmp("unmap", binding) == 0)
return; return;
for (iter = 0; name_to_mousefunc[iter].tag != NULL; iter++) { for (iter = 0; iter < nitems(name_to_mousefunc); iter++) {
if (strcmp(name_to_mousefunc[iter].tag, binding) != 0) if (strcmp(name_to_mousefunc[iter].tag, binding) != 0)
continue; continue;

12
cwm.1
View File

@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" .\"
.Dd $Mdocdate: June 18 2009 $ .Dd $Mdocdate: September 25 2010 $
.Dt CWM 1 .Dt CWM 1
.Os .Os
.Sh NAME .Sh NAME
@ -88,10 +88,14 @@ Toggle group membership of current window.
Cycle through active groups. Cycle through active groups.
.It Ic M-Left .It Ic M-Left
Reverse cycle through active groups. Reverse cycle through active groups.
.It Ic CMS-f
Toggle freezing geometry of current window.
.It Ic CM-f .It Ic CM-f
Toggle full-screen size of current window. Toggle full-screen size of current window.
.It Ic CM-= .It Ic CM-=
Toggle vertical maximization of current window. Toggle vertical maximization of current window.
.It Ic CMS-=
Toggle horizontal maximization of current window.
.It Ic M-? .It Ic M-?
Spawn Spawn
.Dq exec program .Dq exec program
@ -186,7 +190,7 @@ keeps a history of the 5 previous titles of a window.
When searching, the leftmost character of the result list may show a When searching, the leftmost character of the result list may show a
flag: flag:
.Pp .Pp
.Bl -tag -width 10n -offset -indent -compact .Bl -tag -width 10n -offset indent -compact
.It ! .It !
The window is the currently focused window. The window is the currently focused window.
.It & .It &
@ -228,7 +232,7 @@ and a red border will be shown on those just removed.
.Sh MENUS .Sh MENUS
Menus are recalled by clicking the mouse on the root window: Menus are recalled by clicking the mouse on the root window:
.Pp .Pp
.Bl -tag -width 10n -offset -indent -compact .Bl -tag -width 10n -offset indent -compact
.It Ic M1 .It Ic M1
Show list of currently hidden windows. Show list of currently hidden windows.
Clicking on an item will unhide that window. Clicking on an item will unhide that window.
@ -264,7 +268,7 @@ with contributions from
.An Andy Adamson Aq dros@monkey.org , .An Andy Adamson Aq dros@monkey.org ,
.An Niels Provos Aq provos@monkey.org , .An Niels Provos Aq provos@monkey.org ,
and and
.An Antti Nyk<EFBFBD>nen Aq aon@iki.fi . .An Antti Nyk\(:anen Aq aon@iki.fi .
Ideas, discussion with many others. Ideas, discussion with many others.
.Sh HISTORY .Sh HISTORY
.Nm .Nm

60
cwmrc.5
View File

@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" .\"
.Dd $Mdocdate: May 17 2009 $ .Dd $Mdocdate: September 8 2011 $
.Dt CWMRC 5 .Dt CWMRC 5
.Os .Os
.Sh NAME .Sh NAME
@ -24,12 +24,24 @@
This manual page describes the This manual page describes the
.Xr cwm 1 .Xr cwm 1
configuration file. configuration file.
The following options are accepted in the 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 .Pp
.Bl -tag -width Ds -compact .Bl -tag -width Ds -compact
.It Ic autogroup Ar group Dq windowclass .It Ic autogroup Ar group windowname
.It Ic autogroup Ar group Dq windowclass,windowname .It Ic autogroup Ar group windowname,windowclass
Control automatic window grouping, based on the class and/or name Control automatic window grouping, based on the name and/or class
properties, where properties, where
.Ar group .Ar group
is a number between 0 and 9. is a number between 0 and 9.
@ -38,10 +50,10 @@ allow for
.Dq sticky .Dq sticky
windows in sticky group mode. windows in sticky group mode.
.Pp .Pp
The class and name of a window may be obtained using The name and class of a window may be obtained using
.Xr xprop 1 . .Xr xprop 1 .
.Pp .Pp
.It Ic bind Ar keys Ar command .It Ic bind Ar keys command
Cause the creation of a keybinding, or replacement of a default Cause the creation of a keybinding, or replacement of a default
keybinding. keybinding.
The modifier keys come first, followed by a The modifier keys come first, followed by a
@ -87,16 +99,25 @@ Set the window border width to
.It Ic color activeborder Ar color .It Ic color activeborder Ar color
Set the color of the active border. Set the color of the active border.
.Pp .Pp
.It Ic color font Ar color
Set menu font color.
.Pp
.It Ic color groupborder Ar color .It Ic color groupborder Ar color
Set the color of the border while grouping a window. Set the color of the border while grouping a window.
.Pp .Pp
.It Ic color inactiveborder Ar color .It Ic color inactiveborder Ar color
Set the color of the inactive border. Set the color of the inactive border.
.Pp .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 .It Ic color ungroupborder Ar color
Set the color of the border while ungrouping a window. Set the color of the border while ungrouping a window.
.Pp .Pp
.It Ic command Ar name Ar path .It Ic command Ar name path
Every Every
.Ar name .Ar name
entry is shown in the application menu. entry is shown in the application menu.
@ -138,16 +159,16 @@ can be used for applications such as
where the user may wish to remain visible. where the user may wish to remain visible.
.Pp .Pp
.It Ic ignore Ar windowname .It Ic ignore Ar windowname
Ignore windows with the name Ignore, and do not warp to, windows with the name
.Ar windowname .Ar windowname
when drawing borders and cycling through windows. when drawing borders and cycling through windows.
.Pp .Pp
.It Ic mousebind Ar buttons Ar command .It Ic mousebind Ar buttons command
Cause the creation of a mouse binding, or replacement of a default Cause the creation of a mouse binding, or replacement of a default
mouse binding. mouse binding.
The modifier keys come first, followed by a The modifier keys come first, followed by a
.Sq - . .Sq - .
.Pb .Pp
The following modifiers are recognised: The following modifiers are recognised:
.Pp .Pp
.Bl -tag -width Ds -offset indent -compact .Bl -tag -width Ds -offset indent -compact
@ -164,9 +185,8 @@ The Mod4 key (normally the windows key).
The The
.Sq - .Sq -
should be followed by number: should be followed by number:
.Pb
.Bl -tag -width Ds -offset indent -compact
.Pp .Pp
.Bl -tag -width Ds -offset indent -compact
.It 1 .It 1
Left mouse button. Left mouse button.
.It 2 .It 2
@ -186,6 +206,10 @@ Set a default size for the keyboard movement bindings,
in pixels. in pixels.
The default is 1. The default is 1.
.Pp .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 .It Ic sticky Ic yes Ns \&| Ns Ic no
Toggle sticky group mode. Toggle sticky group mode.
The default behavior for new windows is to not assign any group. The default behavior for new windows is to not assign any group.
@ -278,6 +302,10 @@ Reverse cycle through groups.
Forward cycle through windows. Forward cycle through windows.
.It rcycle .It rcycle
Reverse cycle through windows. Reverse cycle through windows.
.It cycleingroup
Forward cycle through windows in current group.
.It rcycleingroup
Reverse cycle through windows in current group.
.It delete .It delete
Delete current window. Delete current window.
.It hide .It hide
@ -288,10 +316,14 @@ Lower current window.
Raise current window. Raise current window.
.It label .It label
Label current window. Label current window.
.It freeze
Freeze current window geometry.
.It maximize .It maximize
Maximize current window full-screen. Maximize current window full-screen.
.It vmaximize .It vmaximize
Maximize current window vertically. Maximize current window vertically.
.It hmaximize
Maximize current window horizontally.
.It moveup .It moveup
Move window Move window
.Ar moveamount .Ar moveamount
@ -397,6 +429,8 @@ Move current window.
Resize current window. Resize current window.
.It window_lower .It window_lower
Lower current window. Lower current window.
.It window_raise
Raise current window.
.It window_hide .It window_hide
Hide current window. Hide current window.
.It window_grouptoggle .It window_grouptoggle

106
fgetln.c Normal file
View File

@ -0,0 +1,106 @@
/* $NetBSD: fgetln.c,v 1.9 2008/04/29 06:53:03 martin Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Christos Zoulas.
*
* 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
*/
#ifdef HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#if !HAVE_FGETLN
#include <stdlib.h>
#ifndef HAVE_NBTOOL_CONFIG_H
/* These headers are required, but included from nbtool_config.h */
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#endif
char *
fgetln(FILE *fp, size_t *len)
{
static char *buf = NULL;
static size_t bufsiz = 0;
char *ptr;
if (buf == NULL) {
bufsiz = BUFSIZ;
if ((buf = malloc(bufsiz)) == NULL)
return NULL;
}
if (fgets(buf, bufsiz, fp) == NULL)
return NULL;
*len = 0;
while ((ptr = strchr(&buf[*len], '\n')) == NULL) {
size_t nbufsiz = bufsiz + BUFSIZ;
char *nbuf = realloc(buf, nbufsiz);
if (nbuf == NULL) {
int oerrno = errno;
free(buf);
errno = oerrno;
buf = NULL;
return NULL;
} else
buf = nbuf;
if (fgets(&buf[bufsiz], BUFSIZ, fp) == NULL) {
buf[bufsiz] = '\0';
*len = strlen(buf);
return buf;
}
*len = bufsiz;
bufsiz = nbufsiz;
}
*len = (ptr - buf) + 1;
return buf;
}
#endif
#ifdef TEST
int
main(int argc, char *argv[])
{
char *p;
size_t len;
while ((p = fgetln(stdin, &len)) != NULL) {
(void)printf("%zu %s", len, p);
free(p);
}
return 0;
}
#endif

51
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> * Copyright (c) 2005 Marius Eriksen <marius@monkey.org>
* *
@ -14,30 +14,64 @@
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * 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" #include "calmwm.h"
void int
font_init(struct screen_ctx *sc) font_ascent(struct screen_ctx *sc)
{ {
return (sc->font->ascent);
}
int
font_descent(struct screen_ctx *sc)
{
return (sc->font->descent);
}
u_int
font_height(struct screen_ctx *sc)
{
return (sc->font->height + 1);
}
void
font_init(struct screen_ctx *sc, const char *color)
{
if (sc->xftdraw)
XftDrawDestroy(sc->xftdraw);
sc->xftdraw = XftDrawCreate(X_Dpy, sc->rootwin, sc->xftdraw = XftDrawCreate(X_Dpy, sc->rootwin,
DefaultVisual(X_Dpy, sc->which), DefaultColormap(X_Dpy, sc->which)); DefaultVisual(X_Dpy, sc->which), DefaultColormap(X_Dpy, sc->which));
if (sc->xftdraw == NULL) if (sc->xftdraw == NULL)
errx(1, "XftDrawCreate"); errx(1, "XftDrawCreate");
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), if (!XftColorAllocName(X_Dpy, DefaultVisual(X_Dpy, sc->which),
DefaultColormap(X_Dpy, sc->which), "black", &sc->xftcolor)) DefaultColormap(X_Dpy, sc->which), color, &sc->xftcolor))
errx(1, "XftColorAllocName"); errx(1, "XftColorAllocName");
} }
int int
font_width(const char *text, int len) font_width(struct screen_ctx *sc, const char *text, int len)
{ {
XGlyphInfo extents; XGlyphInfo extents;
XftTextExtents8(X_Dpy, Conf.DefaultFont, (const XftChar8*)text, XftTextExtentsUtf8(X_Dpy, sc->font, (const FcChar8*)text,
len, &extents); len, &extents);
return (extents.xOff); return (extents.xOff);
@ -48,8 +82,7 @@ font_draw(struct screen_ctx *sc, const char *text, int len,
Drawable d, int x, int y) Drawable d, int x, int y)
{ {
XftDrawChange(sc->xftdraw, d); XftDrawChange(sc->xftdraw, d);
/* Really needs to be UTF8'd. */ XftDrawStringUtf8(sc->xftdraw, &sc->xftcolor, sc->font, x, y,
XftDrawString8(sc->xftdraw, &sc->xftcolor, Conf.DefaultFont, x, y,
(const FcChar8*)text, len); (const FcChar8*)text, len);
} }

311
group.c
View File

@ -16,24 +16,29 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
* *
* $Id$ * $OpenBSD$
*/ */
#include "headers.h" #include <sys/param.h>
#include "calmwm.h" #include <sys/queue.h>
#define CALMWM_NGROUPS 9 #include <assert.h>
#include <err.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "calmwm.h"
static void group_add(struct group_ctx *, struct client_ctx *); static void group_add(struct group_ctx *, struct client_ctx *);
static void group_remove(struct client_ctx *); static void group_remove(struct client_ctx *);
static void group_hide(struct group_ctx *); static void group_hide(struct screen_ctx *, struct group_ctx *);
static void group_show(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_fix_hidden_state(struct group_ctx *);
static void group_setactive(struct screen_ctx *, long);
struct group_ctx *Group_active = NULL; static void group_set_names(struct screen_ctx *);
struct group_ctx Groups[CALMWM_NGROUPS];
int Grouphideall = 0;
struct group_ctx_q Groupq;
const char *shortcut_to_name[] = { const char *shortcut_to_name[] = {
"nogroup", "one", "two", "three", "four", "five", "six", "nogroup", "one", "two", "three", "four", "five", "six",
@ -43,17 +48,20 @@ const char *shortcut_to_name[] = {
static void 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) 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) if (cc->group == gc)
return; return;
if (cc->group != NULL) if (cc->group != NULL)
TAILQ_REMOVE(&cc->group->clients, cc, group_entry); TAILQ_REMOVE(&cc->group->clients, cc, group_entry);
XChangeProperty(X_Dpy, cc->win, _CWM_GRP, XA_STRING, XChangeProperty(X_Dpy, cc->win, _NET_WM_DESKTOP, XA_CARDINAL,
8, PropModeReplace, gc->name, strlen(gc->name)); 32, PropModeReplace, (unsigned char *)&no, 1);
TAILQ_INSERT_TAIL(&gc->clients, cc, group_entry); TAILQ_INSERT_TAIL(&gc->clients, cc, group_entry);
cc->group = gc; cc->group = gc;
@ -62,23 +70,24 @@ group_add(struct group_ctx *gc, struct client_ctx *cc)
static void static void
group_remove(struct client_ctx *cc) group_remove(struct client_ctx *cc)
{ {
long no = 0xffffffff;
if (cc == NULL || cc->group == NULL) 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, _CWM_GRP, XA_STRING, 8, XChangeProperty(X_Dpy, cc->win, _NET_WM_DESKTOP, XA_CARDINAL,
PropModeReplace, shortcut_to_name[0], 32, PropModeReplace, (unsigned char *)&no, 1);
strlen(shortcut_to_name[0]));
TAILQ_REMOVE(&cc->group->clients, cc, group_entry); TAILQ_REMOVE(&cc->group->clients, cc, group_entry);
cc->group = NULL; cc->group = NULL;
} }
static void static void
group_hide(struct group_ctx *gc) group_hide(struct screen_ctx *sc, struct group_ctx *gc)
{ {
struct client_ctx *cc; struct client_ctx *cc;
screen_updatestackingorder(); screen_updatestackingorder(sc);
gc->nhidden = 0; gc->nhidden = 0;
gc->highstack = 0; gc->highstack = 0;
@ -92,13 +101,18 @@ group_hide(struct group_ctx *gc)
} }
static void static void
group_show(struct group_ctx *gc) group_show(struct screen_ctx *sc, struct group_ctx *gc)
{ {
struct client_ctx *cc; struct client_ctx *cc;
Window *winlist; Window *winlist;
u_int i; u_int i;
int lastempty = -1; int lastempty = -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)); winlist = (Window *) xcalloc(sizeof(*winlist), (gc->highstack + 1));
/* /*
@ -125,36 +139,96 @@ group_show(struct group_ctx *gc)
xfree(winlist); xfree(winlist);
gc->hidden = 0; gc->hidden = 0;
Group_active = gc; group_setactive(sc, gc->shortcut - 1);
} }
void 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(&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++) { for (i = 0; i < CALMWM_NGROUPS; i++) {
TAILQ_INIT(&Groups[i].clients); TAILQ_INIT(&sc->groups[i].clients);
Groups[i].hidden = 0; sc->groups[i].hidden = 0;
Groups[i].shortcut = i + 1; sc->groups[i].shortcut = i + 1;
Groups[i].name = shortcut_to_name[Groups[i].shortcut]; TAILQ_INSERT_TAIL(&sc->groupq, &sc->groups[i], entry);
TAILQ_INSERT_TAIL(&Groupq, &Groups[i], entry);
} }
Group_active = &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);
}
void
group_make_autogroup(struct conf *conf, char *val, int no)
{
struct autogroupwin *aw;
char *p;
aw = xcalloc(1, sizeof(*aw));
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;
TAILQ_INSERT_TAIL(&conf->autogroupq, aw, entry);
}
static void
group_setactive(struct screen_ctx *sc, long idx)
{
sc->group_active = &sc->groups[idx];
XChangeProperty(X_Dpy, sc->rootwin, _NET_CURRENT_DESKTOP,
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&idx, 1);
} }
void void
group_movetogroup(struct client_ctx *cc, int idx) group_movetogroup(struct client_ctx *cc, int idx)
{ {
struct screen_ctx *sc = cc->sc;
struct group_ctx *gc;
if (idx < 0 || idx >= CALMWM_NGROUPS) if (idx < 0 || idx >= CALMWM_NGROUPS)
err(1, "group_movetogroup: index out of range (%d)", idx); err(1, "group_movetogroup: index out of range (%d)", idx);
if(Group_active != &Groups[idx]) gc = &sc->groups[idx];
if (cc->group == gc)
return;
if (gc->hidden) {
client_hide(cc); client_hide(cc);
group_add(&Groups[idx], cc); gc->nhidden++;
}
group_add(gc, cc);
} }
/* /*
@ -163,9 +237,10 @@ group_movetogroup(struct client_ctx *cc, int idx)
void void
group_sticky_toggle_enter(struct client_ctx *cc) group_sticky_toggle_enter(struct client_ctx *cc)
{ {
struct screen_ctx *sc = cc->sc;
struct group_ctx *gc; struct group_ctx *gc;
gc = Group_active; gc = sc->group_active;
if (gc == cc->group) { if (gc == cc->group) {
group_remove(cc); group_remove(cc);
@ -204,28 +279,28 @@ group_fix_hidden_state(struct group_ctx *gc)
} }
void void
group_hidetoggle(int idx) group_hidetoggle(struct screen_ctx *sc, int idx)
{ {
struct group_ctx *gc; struct group_ctx *gc;
if (idx < 0 || idx >= CALMWM_NGROUPS) if (idx < 0 || idx >= CALMWM_NGROUPS)
err(1, "group_hidetoggle: index out of range (%d)", idx); err(1, "group_hidetoggle: index out of range (%d)", idx);
gc = &Groups[idx]; gc = &sc->groups[idx];
group_fix_hidden_state(gc); group_fix_hidden_state(gc);
if (gc->hidden) if (gc->hidden)
group_show(gc); group_show(sc, gc);
else { else {
group_hide(gc); group_hide(sc, gc);
/* XXX wtf? */
if (TAILQ_EMPTY(&gc->clients)) if (TAILQ_EMPTY(&gc->clients))
Group_active = gc; group_setactive(sc, idx);
} }
} }
void void
group_only(int idx) group_only(struct screen_ctx *sc, int idx)
{ {
int i; int i;
@ -234,9 +309,9 @@ group_only(int idx)
for (i = 0; i < CALMWM_NGROUPS; i++) { for (i = 0; i < CALMWM_NGROUPS; i++) {
if (i == idx) if (i == idx)
group_show(&Groups[i]); group_show(sc, &sc->groups[i]);
else else
group_hide(&Groups[i]); group_hide(sc, &sc->groups[i]);
} }
} }
@ -244,37 +319,37 @@ group_only(int idx)
* Cycle through active groups. If none exist, then just stay put. * Cycle through active groups. If none exist, then just stay put.
*/ */
void void
group_cycle(int reverse) group_cycle(struct screen_ctx *sc, int flags)
{ {
struct group_ctx *gc, *showgroup = NULL; struct group_ctx *gc, *showgroup = NULL;
assert(Group_active != NULL); assert(sc->group_active != NULL);
gc = Group_active; gc = sc->group_active;
for (;;) { for (;;) {
gc = reverse ? TAILQ_PREV(gc, group_ctx_q, entry) : gc = (flags & CWM_RCYCLE) ? TAILQ_PREV(gc, group_ctx_q,
TAILQ_NEXT(gc, entry); entry) : TAILQ_NEXT(gc, entry);
if (gc == NULL) if (gc == NULL)
gc = reverse ? TAILQ_LAST(&Groupq, group_ctx_q) : gc = (flags & CWM_RCYCLE) ? TAILQ_LAST(&sc->groupq,
TAILQ_FIRST(&Groupq); group_ctx_q) : TAILQ_FIRST(&sc->groupq);
if (gc == Group_active) if (gc == sc->group_active)
break; break;
if (!TAILQ_EMPTY(&gc->clients) && showgroup == NULL) if (!TAILQ_EMPTY(&gc->clients) && showgroup == NULL)
showgroup = gc; showgroup = gc;
else if (!gc->hidden) else if (!gc->hidden)
group_hide(gc); group_hide(sc, gc);
} }
if (showgroup == NULL) if (showgroup == NULL)
return; return;
group_hide(Group_active); group_hide(sc, sc->group_active);
if (showgroup->hidden) if (showgroup->hidden)
group_show(showgroup); group_show(sc, showgroup);
else else
Group_active = showgroup; group_setactive(sc, showgroup->shortcut - 1);
} }
/* called when a client is deleted */ /* called when a client is deleted */
@ -291,26 +366,28 @@ group_client_delete(struct client_ctx *cc)
void void
group_menu(XButtonEvent *e) group_menu(XButtonEvent *e)
{ {
struct screen_ctx *sc;
struct group_ctx *gc; struct group_ctx *gc;
struct menu *mi; struct menu *mi;
struct menu_q menuq; struct menu_q menuq;
int i; int i;
sc = screen_fromroot(e->root);
TAILQ_INIT(&menuq); TAILQ_INIT(&menuq);
for (i = 0; i < CALMWM_NGROUPS; i++) { for (i = 0; i < CALMWM_NGROUPS; i++) {
gc = &Groups[i]; gc = &sc->groups[i];
if (TAILQ_EMPTY(&gc->clients)) if (TAILQ_EMPTY(&gc->clients))
continue; continue;
mi = xcalloc(1, sizeof(*mi)); mi = xcalloc(1, sizeof(*mi));
if (gc->hidden) if (gc->hidden)
snprintf(mi->text, sizeof(mi->text), "%d: [%s]", (void)snprintf(mi->text, sizeof(mi->text), "%d: [%s]",
gc->shortcut, shortcut_to_name[gc->shortcut]); gc->shortcut, sc->group_names[i]);
else else
snprintf(mi->text, sizeof(mi->text), "%d: %s", (void)snprintf(mi->text, sizeof(mi->text), "%d: %s",
gc->shortcut, shortcut_to_name[gc->shortcut]); gc->shortcut, sc->group_names[i]);
mi->ctx = gc; mi->ctx = gc;
TAILQ_INSERT_TAIL(&menuq, mi, entry); TAILQ_INSERT_TAIL(&menuq, mi, entry);
} }
@ -318,14 +395,14 @@ group_menu(XButtonEvent *e)
if (TAILQ_EMPTY(&menuq)) if (TAILQ_EMPTY(&menuq))
return; return;
mi = menu_filter(&menuq, NULL, NULL, 0, NULL, NULL); mi = menu_filter(sc, &menuq, NULL, NULL, 0, NULL, NULL);
if (mi == NULL || mi->ctx == NULL) if (mi == NULL || mi->ctx == NULL)
goto cleanup; goto cleanup;
gc = (struct group_ctx *)mi->ctx; gc = (struct group_ctx *)mi->ctx;
(gc->hidden) ? group_show(gc) : group_hide(gc); (gc->hidden) ? group_show(sc, gc) : group_hide(sc, gc);
cleanup: cleanup:
while ((mi = TAILQ_FIRST(&menuq)) != NULL) { while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
@ -335,56 +412,138 @@ cleanup:
} }
void void
group_alltoggle(void) group_alltoggle(struct screen_ctx *sc)
{ {
int i; int i;
for (i = 0; i < CALMWM_NGROUPS; i++) { for (i = 0; i < CALMWM_NGROUPS; i++) {
if (Grouphideall) if (sc->group_hideall)
group_show(&Groups[i]); group_show(sc, &sc->groups[i]);
else else
group_hide(&Groups[i]); group_hide(sc, &sc->groups[i]);
} }
Grouphideall = (Grouphideall) ? 0 : 1; sc->group_hideall = (!sc->group_hideall);
} }
void void
group_autogroup(struct client_ctx *cc) group_autogroup(struct client_ctx *cc)
{ {
struct screen_ctx *sc = cc->sc;
struct autogroupwin *aw; struct autogroupwin *aw;
struct group_ctx *gc; struct group_ctx *gc;
unsigned char *grpstr = NULL; int no = -1;
char group[CALMWM_MAXNAMELEN]; long *grpno;
if (cc->app_class == NULL || cc->app_name == NULL) if (cc->app_class == NULL || cc->app_name == NULL)
return; return;
if (xu_getprop(cc, _CWM_GRP, XA_STRING,
(CALMWM_MAXNAMELEN - 1)/sizeof(long), &grpstr) > 0) { if (xu_getprop(cc->win, _NET_WM_DESKTOP, XA_CARDINAL,
strlcpy(group, grpstr, sizeof(group)); 1, (unsigned char **)&grpno) > 0) {
XFree(grpstr); if (*grpno == 0xffffffff)
no = 0;
else if (*grpno > CALMWM_NGROUPS || *grpno < 0)
no = CALMWM_NGROUPS - 1;
else
no = *grpno + 1;
XFree(grpno);
} else { } else {
TAILQ_FOREACH(aw, &Conf.autogroupq, entry) { TAILQ_FOREACH(aw, &Conf.autogroupq, entry) {
if (strcmp(aw->class, cc->app_class) == 0 && if (strcmp(aw->class, cc->app_class) == 0 &&
(aw->name == NULL || (aw->name == NULL ||
strcmp(aw->name, cc->app_name) == 0)) { strcmp(aw->name, cc->app_name) == 0)) {
strlcpy(group, aw->group, sizeof(group)); no = aw->num;
break; break;
} }
} }
} }
if (strncmp("nogroup", group, 7) == 0) /* no group please */
if (no == 0)
return; return;
TAILQ_FOREACH(gc, &Groupq, entry) { TAILQ_FOREACH(gc, &sc->groupq, entry) {
if (strcmp(shortcut_to_name[gc->shortcut], group) == 0) { if (gc->shortcut == no) {
group_add(gc, cc); group_add(gc, cc);
return; return;
} }
} }
if (Conf.flags & CONF_STICKY_GROUPS) if (Conf.flags & CONF_STICKY_GROUPS)
group_add(Group_active, cc); 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);
} }

View File

@ -1,53 +0,0 @@
/*
* calmwm - the calm window manager
*
* 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.
*
* $Id$
*/
#ifndef _CALMWM_HEADERS_H_
#define _CALMWM_HEADERS_H_
#include <sys/param.h>
#include <sys/queue.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <assert.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <dirent.h>
#include <getopt.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <X11/Intrinsic.h>
#include <X11/Xatom.h>
#include <X11/Xft/Xft.h>
#include <X11/Xlib.h>
#include <X11/Xos.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>
#endif /* _CALMWM_HEADERS_H_ */

108
input.c
View File

@ -1,108 +0,0 @@
/*
* calmwm - the calm window manager
*
* 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.
*
* $Id$
*/
#include "headers.h"
#include "calmwm.h"
int
input_keycodetrans(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);
}

215
kbfunc.c
View File

@ -1,7 +1,7 @@
/* /*
* calmwm - the calm window manager * calmwm - the calm window manager
* *
* Copyright (c) 2004 Martin Murray <mmurray@monkey.org> * Copyright (c) 2004 Martin Murray <mmurray@monkey.org>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -15,18 +15,28 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
* *
* $Id$ * $OpenBSD$
*/ */
#include <paths.h> #include <sys/param.h>
#include <sys/queue.h>
#include <dirent.h>
#include <err.h>
#include <errno.h>
#include <paths.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "headers.h"
#include "calmwm.h" #include "calmwm.h"
#define KNOWN_HOSTS ".ssh/known_hosts" #define KNOWN_HOSTS ".ssh/known_hosts"
#define HASH_MARKER "|1|" #define HASH_MARKER "|1|"
extern int _xev_quit; extern sig_atomic_t xev_quit;
void void
kbfunc_client_lower(struct client_ctx *cc, union arg *arg) kbfunc_client_lower(struct client_ctx *cc, union arg *arg)
@ -40,8 +50,8 @@ kbfunc_client_raise(struct client_ctx *cc, union arg *arg)
client_raise(cc); client_raise(cc);
} }
#define typemask (CWM_MOVE | CWM_RESIZE | CWM_PTRMOVE) #define TYPEMASK (CWM_MOVE | CWM_RESIZE | CWM_PTRMOVE)
#define movemask (CWM_UP | CWM_DOWN | CWM_LEFT | CWM_RIGHT) #define MOVEMASK (CWM_UP | CWM_DOWN | CWM_LEFT | CWM_RIGHT)
void void
kbfunc_moveresize(struct client_ctx *cc, union arg *arg) kbfunc_moveresize(struct client_ctx *cc, union arg *arg)
{ {
@ -49,7 +59,10 @@ kbfunc_moveresize(struct client_ctx *cc, union arg *arg)
int x, y, flags, amt; int x, y, flags, amt;
u_int mx, my; u_int mx, my;
sc = screen_current(); if (cc->flags & CLIENT_FREEZE)
return;
sc = cc->sc;
mx = my = 0; mx = my = 0;
flags = arg->i; flags = arg->i;
@ -60,7 +73,7 @@ kbfunc_moveresize(struct client_ctx *cc, union arg *arg)
amt = amt * 10; amt = amt * 10;
} }
switch (flags & movemask) { switch (flags & MOVEMASK) {
case CWM_UP: case CWM_UP:
my -= amt; my -= amt;
break; break;
@ -74,7 +87,7 @@ kbfunc_moveresize(struct client_ctx *cc, union arg *arg)
mx -= amt; mx -= amt;
break; break;
} }
switch (flags & typemask) { switch (flags & TYPEMASK) {
case CWM_MOVE: case CWM_MOVE:
cc->geom.y += my; cc->geom.y += my;
if (cc->geom.y + cc->geom.height < 0) if (cc->geom.y + cc->geom.height < 0)
@ -88,6 +101,13 @@ kbfunc_moveresize(struct client_ctx *cc, union arg *arg)
if (cc->geom.x > cc->sc->xmax - 1) if (cc->geom.x > cc->sc->xmax - 1)
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); client_move(cc);
xu_ptr_getpos(cc->win, &x, &y); xu_ptr_getpos(cc->win, &x, &y);
cc->ptr.y = y + my; cc->ptr.y = y + my;
@ -110,13 +130,8 @@ kbfunc_moveresize(struct client_ctx *cc, union arg *arg)
client_ptrwarp(cc); client_ptrwarp(cc);
break; break;
case CWM_PTRMOVE: case CWM_PTRMOVE:
if (cc) { xu_ptr_getpos(sc->rootwin, &x, &y);
xu_ptr_getpos(cc->win, &x, &y); xu_ptr_setpos(sc->rootwin, x + mx, y + my);
xu_ptr_setpos(cc->win, x + mx, y + my);
} else {
xu_ptr_getpos(sc->rootwin, &x, &y);
xu_ptr_setpos(sc->rootwin, x + mx, y + my);
}
break; break;
default: default:
warnx("invalid flags passed to kbfunc_client_moveresize"); warnx("invalid flags passed to kbfunc_client_moveresize");
@ -124,24 +139,26 @@ kbfunc_moveresize(struct client_ctx *cc, union arg *arg)
} }
void void
kbfunc_client_search(struct client_ctx *scratch, union arg *arg) kbfunc_client_search(struct client_ctx *cc, union arg *arg)
{ {
struct client_ctx *cc, *old_cc; struct screen_ctx *sc;
struct client_ctx *old_cc;
struct menu *mi; struct menu *mi;
struct menu_q menuq; struct menu_q menuq;
sc = cc->sc;
old_cc = client_current(); old_cc = client_current();
TAILQ_INIT(&menuq); TAILQ_INIT(&menuq);
TAILQ_FOREACH(cc, &Clientq, entry) { TAILQ_FOREACH(cc, &Clientq, entry) {
mi = xcalloc(1, sizeof(*mi)); mi = xcalloc(1, sizeof(*mi));
strlcpy(mi->text, cc->name, sizeof(mi->text)); (void)strlcpy(mi->text, cc->name, sizeof(mi->text));
mi->ctx = cc; mi->ctx = cc;
TAILQ_INSERT_TAIL(&menuq, mi, entry); TAILQ_INSERT_TAIL(&menuq, mi, entry);
} }
if ((mi = menu_filter(&menuq, "window", NULL, 0, if ((mi = menu_filter(sc, &menuq, "window", NULL, 0,
search_match_client, search_print_client)) != NULL) { search_match_client, search_print_client)) != NULL) {
cc = (struct client_ctx *)mi->ctx; cc = (struct client_ctx *)mi->ctx;
if (cc->flags & CLIENT_HIDDEN) if (cc->flags & CLIENT_HIDDEN)
@ -159,22 +176,24 @@ kbfunc_client_search(struct client_ctx *scratch, union arg *arg)
} }
void void
kbfunc_menu_search(struct client_ctx *scratch, union arg *arg) kbfunc_menu_search(struct client_ctx *cc, union arg *arg)
{ {
struct cmd *cmd; struct screen_ctx *sc;
struct menu *mi; struct cmd *cmd;
struct menu_q menuq; struct menu *mi;
struct menu_q menuq;
sc = cc->sc;
TAILQ_INIT(&menuq); TAILQ_INIT(&menuq);
TAILQ_FOREACH(cmd, &Conf.cmdq, entry) { TAILQ_FOREACH(cmd, &Conf.cmdq, entry) {
mi = xcalloc(1, sizeof(*mi)); mi = xcalloc(1, sizeof(*mi));
strlcpy(mi->text, cmd->label, sizeof(mi->text)); (void)strlcpy(mi->text, cmd->label, sizeof(mi->text));
mi->ctx = cmd; mi->ctx = cmd;
TAILQ_INSERT_TAIL(&menuq, mi, entry); TAILQ_INSERT_TAIL(&menuq, mi, entry);
} }
if ((mi = menu_filter(&menuq, "application", NULL, 0, if ((mi = menu_filter(sc, &menuq, "application", NULL, 0,
search_match_text, NULL)) != NULL) search_match_text, NULL)) != NULL)
u_spawn(((struct cmd *)mi->ctx)->image); u_spawn(((struct cmd *)mi->ctx)->image);
@ -185,17 +204,17 @@ kbfunc_menu_search(struct client_ctx *scratch, union arg *arg)
} }
void void
kbfunc_client_cycle(struct client_ctx *scratch, union arg *arg) kbfunc_client_cycle(struct client_ctx *cc, union arg *arg)
{ {
struct screen_ctx *sc; struct screen_ctx *sc;
sc = screen_current(); sc = cc->sc;
/* XXX for X apps that ignore events */ /* XXX for X apps that ignore events */
XGrabKeyboard(X_Dpy, sc->rootwin, True, XGrabKeyboard(X_Dpy, sc->rootwin, True,
GrabModeAsync, GrabModeAsync, CurrentTime); GrabModeAsync, GrabModeAsync, CurrentTime);
client_cycle(arg->i); client_cycle(sc, arg->i);
} }
void void
@ -223,21 +242,19 @@ kbfunc_lock(struct client_ctx *cc, union arg *arg)
} }
void void
kbfunc_exec(struct client_ctx *scratch, union arg *arg) kbfunc_exec(struct client_ctx *cc, union arg *arg)
{ {
#define NPATHS 256 #define NPATHS 256
char **ap, *paths[NPATHS], *path, *pathcpy, *label; struct screen_ctx *sc;
char tpath[MAXPATHLEN]; char **ap, *paths[NPATHS], *path, *pathcpy, *label;
int l, i, j, ngroups; char tpath[MAXPATHLEN];
gid_t mygroups[NGROUPS_MAX]; DIR *dirp;
uid_t ruid, euid, suid; struct dirent *dp;
DIR *dirp; struct menu *mi;
struct dirent *dp; struct menu_q menuq;
struct menu *mi; int l, i, cmd = arg->i;
struct menu_q menuq;
struct stat sb;
int cmd = arg->i; sc = cc->sc;
switch (cmd) { switch (cmd) {
case CWM_EXEC_PROGRAM: case CWM_EXEC_PROGRAM:
label = "exec"; label = "exec";
@ -250,11 +267,6 @@ kbfunc_exec(struct client_ctx *scratch, union arg *arg)
/*NOTREACHED*/ /*NOTREACHED*/
} }
if (getgroups(0, mygroups) == -1)
err(1, "getgroups failure");
if ((ngroups = getresuid(&ruid, &euid, &suid)) == -1)
err(1, "getresuid failure");
TAILQ_INIT(&menuq); TAILQ_INIT(&menuq);
if ((path = getenv("PATH")) == NULL) if ((path = getenv("PATH")) == NULL)
@ -275,45 +287,27 @@ kbfunc_exec(struct client_ctx *scratch, union arg *arg)
/* skip everything but regular files and symlinks */ /* skip everything but regular files and symlinks */
if (dp->d_type != DT_REG && dp->d_type != DT_LNK) if (dp->d_type != DT_REG && dp->d_type != DT_LNK)
continue; continue;
memset(tpath, '\0', sizeof(tpath)); (void)memset(tpath, '\0', sizeof(tpath));
l = snprintf(tpath, sizeof(tpath), "%s/%s", paths[i], l = snprintf(tpath, sizeof(tpath), "%s/%s", paths[i],
dp->d_name); dp->d_name);
/* check for truncation etc */ /* check for truncation etc */
if (l == -1 || l >= (int)sizeof(tpath)) if (l == -1 || l >= (int)sizeof(tpath))
continue; continue;
/* just ignore on stat failure */ if (access(tpath, X_OK) == 0) {
if (stat(tpath, &sb) == -1) mi = xcalloc(1, sizeof(*mi));
continue; (void)strlcpy(mi->text,
/* may we execute this file? */ dp->d_name, sizeof(mi->text));
if (euid == sb.st_uid) { TAILQ_INSERT_TAIL(&menuq, mi, entry);
if (sb.st_mode & S_IXUSR)
goto executable;
else
continue;
} }
for (j = 0; j < ngroups; j++) {
if (mygroups[j] == sb.st_gid) {
if (sb.st_mode & S_IXGRP)
goto executable;
else
continue;
}
}
if (sb.st_mode & S_IXOTH)
goto executable;
continue;
executable:
/* the thing in tpath, we may execute */
mi = xcalloc(1, sizeof(*mi));
strlcpy(mi->text, dp->d_name, sizeof(mi->text));
TAILQ_INSERT_TAIL(&menuq, mi, entry);
} }
(void)closedir(dirp); (void)closedir(dirp);
} }
xfree(path); xfree(path);
if ((mi = menu_filter(&menuq, label, NULL, 1, if ((mi = menu_filter(sc, &menuq, label, NULL, 1,
search_match_exec, NULL)) != NULL) { search_match_exec, NULL)) != NULL) {
if (mi->text[0] == '\0')
goto out;
switch (cmd) { switch (cmd) {
case CWM_EXEC_PROGRAM: case CWM_EXEC_PROGRAM:
u_spawn(mi->text); u_spawn(mi->text);
@ -327,7 +321,7 @@ kbfunc_exec(struct client_ctx *scratch, union arg *arg)
break; break;
} }
} }
out:
if (mi != NULL && mi->dummy) if (mi != NULL && mi->dummy)
xfree(mi); xfree(mi);
while ((mi = TAILQ_FIRST(&menuq)) != NULL) { while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
@ -337,16 +331,19 @@ kbfunc_exec(struct client_ctx *scratch, union arg *arg)
} }
void void
kbfunc_ssh(struct client_ctx *scratch, union arg *arg) kbfunc_ssh(struct client_ctx *cc, union arg *arg)
{ {
struct menu *mi; struct screen_ctx *sc;
struct menu_q menuq; struct menu *mi;
FILE *fp; struct menu_q menuq;
char *buf, *lbuf, *p, *home; FILE *fp;
char hostbuf[MAXHOSTNAMELEN], filename[MAXPATHLEN]; char *buf, *lbuf, *p, *home;
char cmd[256]; char hostbuf[MAXHOSTNAMELEN], filename[MAXPATHLEN];
int l; char cmd[256];
size_t len; int l;
size_t len;
sc = cc->sc;
if ((home = getenv("HOME")) == NULL) if ((home = getenv("HOME")) == NULL)
return; return;
@ -366,7 +363,7 @@ kbfunc_ssh(struct client_ctx *scratch, union arg *arg)
else { else {
/* EOF without EOL, copy and add the NUL */ /* EOF without EOL, copy and add the NUL */
lbuf = xmalloc(len + 1); lbuf = xmalloc(len + 1);
memcpy(lbuf, buf, len); (void)memcpy(lbuf, buf, len);
lbuf[len] = '\0'; lbuf[len] = '\0';
buf = lbuf; buf = lbuf;
} }
@ -379,22 +376,24 @@ kbfunc_ssh(struct client_ctx *scratch, union arg *arg)
/* ignore badness */ /* ignore badness */
if (p - buf + 1 > sizeof(hostbuf)) if (p - buf + 1 > sizeof(hostbuf))
continue; continue;
(void) strlcpy(hostbuf, buf, p - buf + 1); (void)strlcpy(hostbuf, buf, p - buf + 1);
mi = xcalloc(1, sizeof(*mi)); mi = xcalloc(1, sizeof(*mi));
(void) strlcpy(mi->text, hostbuf, sizeof(mi->text)); (void)strlcpy(mi->text, hostbuf, sizeof(mi->text));
TAILQ_INSERT_TAIL(&menuq, mi, entry); TAILQ_INSERT_TAIL(&menuq, mi, entry);
} }
xfree(lbuf); xfree(lbuf);
fclose(fp); (void)fclose(fp);
if ((mi = menu_filter(&menuq, "ssh", NULL, 1, if ((mi = menu_filter(sc, &menuq, "ssh", NULL, 1,
search_match_exec, NULL)) != NULL) { search_match_exec, NULL)) != NULL) {
if (mi->text[0] == '\0')
goto out;
l = snprintf(cmd, sizeof(cmd), "%s -e ssh %s", Conf.termpath, l = snprintf(cmd, sizeof(cmd), "%s -e ssh %s", Conf.termpath,
mi->text); mi->text);
if (l != -1 && l < sizeof(cmd)) if (l != -1 && l < sizeof(cmd))
u_spawn(cmd); u_spawn(cmd);
} }
out:
if (mi != NULL && mi->dummy) if (mi != NULL && mi->dummy)
xfree(mi); xfree(mi);
while ((mi = TAILQ_FIRST(&menuq)) != NULL) { while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
@ -408,19 +407,19 @@ kbfunc_client_label(struct client_ctx *cc, union arg *arg)
{ {
struct menu *mi; struct menu *mi;
struct menu_q menuq; struct menu_q menuq;
char *current;
TAILQ_INIT(&menuq); TAILQ_INIT(&menuq);
current = cc->label;
if ((mi = menu_filter(&menuq, "label", current, 1, /* dummy is set, so this will always return */
search_match_text, NULL)) != NULL) { mi = menu_filter(cc->sc, &menuq, "label", cc->label, 1,
search_match_text, NULL);
if (!mi->abort) {
if (cc->label != NULL) if (cc->label != NULL)
xfree(cc->label); xfree(cc->label);
cc->label = xstrdup(mi->text); cc->label = xstrdup(mi->text);
xfree(mi);
} }
xfree(mi);
} }
void void
@ -432,25 +431,25 @@ kbfunc_client_delete(struct client_ctx *cc, union arg *arg)
void void
kbfunc_client_group(struct client_ctx *cc, union arg *arg) kbfunc_client_group(struct client_ctx *cc, union arg *arg)
{ {
group_hidetoggle(KBTOGROUP(arg->i)); group_hidetoggle(cc->sc, KBTOGROUP(arg->i));
} }
void void
kbfunc_client_grouponly(struct client_ctx *cc, union arg *arg) kbfunc_client_grouponly(struct client_ctx *cc, union arg *arg)
{ {
group_only(KBTOGROUP(arg->i)); group_only(cc->sc, KBTOGROUP(arg->i));
} }
void void
kbfunc_client_cyclegroup(struct client_ctx *cc, union arg *arg) kbfunc_client_cyclegroup(struct client_ctx *cc, union arg *arg)
{ {
group_cycle(arg->i); group_cycle(cc->sc, arg->i);
} }
void void
kbfunc_client_nogroup(struct client_ctx *cc, union arg *arg) kbfunc_client_nogroup(struct client_ctx *cc, union arg *arg)
{ {
group_alltoggle(); group_alltoggle(cc->sc);
} }
void void
@ -481,10 +480,22 @@ kbfunc_client_vmaximize(struct client_ctx *cc, union arg *arg)
client_vertmaximize(cc); 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 void
kbfunc_quit_wm(struct client_ctx *cc, union arg *arg) kbfunc_quit_wm(struct client_ctx *cc, union arg *arg)
{ {
_xev_quit = 1; xev_quit = 1;
} }
void void

252
menu.c
View File

@ -1,4 +1,6 @@
/* /*
* calmwm - the calm window manager
*
* Copyright (c) 2008 Owain G. Ainsworth <oga@openbsd.org> * Copyright (c) 2008 Owain G. Ainsworth <oga@openbsd.org>
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org> * Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
* *
@ -13,13 +15,30 @@
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * 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" #include "calmwm.h"
#define PROMPT_SCHAR '<27>' #define PROMPT_SCHAR "\xc2\xbb"
#define PROMPT_ECHAR '<27>' #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 { struct menu_ctx {
char searchstr[MENU_MAXENTRY + 1]; char searchstr[MENU_MAXENTRY + 1];
@ -49,14 +68,19 @@ static void menu_draw(struct screen_ctx *, struct menu_ctx *,
struct menu_q *, struct menu_q *); struct menu_q *, struct menu_q *);
static int menu_calc_entry(struct screen_ctx *, struct menu_ctx *, static int menu_calc_entry(struct screen_ctx *, struct menu_ctx *,
int, int); int, int);
static int menu_keycode(KeyCode, u_int, enum ctltype *,
char *);
void void
menu_init(struct screen_ctx *sc) menu_init(struct screen_ctx *sc)
{ {
XGCValues gv; XGCValues gv;
sc->menuwin = XCreateSimpleWindow(X_Dpy, sc->rootwin, 0, 0, 1, 1, 0, if (sc->menuwin)
sc->color[CWM_COLOR_BG_MENU].pixel, 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); sc->color[CWM_COLOR_BG_MENU].pixel);
gv.foreground = gv.foreground =
@ -64,24 +88,25 @@ menu_init(struct screen_ctx *sc)
gv.background = sc->color[CWM_COLOR_BG_MENU].pixel; gv.background = sc->color[CWM_COLOR_BG_MENU].pixel;
gv.function = GXxor; gv.function = GXxor;
if (sc->gc)
XFreeGC(X_Dpy, sc->gc);
sc->gc = XCreateGC(X_Dpy, sc->menuwin, sc->gc = XCreateGC(X_Dpy, sc->menuwin,
GCForeground|GCBackground|GCFunction, &gv); GCForeground|GCBackground|GCFunction, &gv);
} }
struct menu * struct menu *
menu_filter(struct menu_q *menuq, char *prompt, char *initial, int dummy, 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 (*match)(struct menu_q *, struct menu_q *, char *),
void (*print)(struct menu *, int)) void (*print)(struct menu *, int))
{ {
struct screen_ctx *sc;
struct menu_ctx mc; struct menu_ctx mc;
struct menu_q resultq; struct menu_q resultq;
struct menu *mi = NULL; struct menu *mi = NULL;
XEvent e; XEvent e;
Window focuswin; Window focuswin;
int evmask, focusrevert; int evmask, focusrevert;
int xsave, ysave, xcur, ycur;
sc = screen_current();
TAILQ_INIT(&resultq); TAILQ_INIT(&resultq);
@ -89,22 +114,25 @@ menu_filter(struct menu_q *menuq, char *prompt, char *initial, int dummy,
xu_ptr_getpos(sc->rootwin, &mc.x, &mc.y); xu_ptr_getpos(sc->rootwin, &mc.x, &mc.y);
xsave = mc.x;
ysave = mc.y;
if (prompt == NULL) { if (prompt == NULL) {
evmask = MenuMask; evmask = MENUMASK;
mc.promptstr[0] = '\0'; mc.promptstr[0] = '\0';
mc.list = 1; mc.list = 1;
} else { } else {
evmask = MenuMask | KeyMask; /* only accept keys if prompt */ evmask = MENUMASK | KEYMASK; /* only accept keys if prompt */
snprintf(mc.promptstr, sizeof(mc.promptstr), "%s%c", prompt, (void)snprintf(mc.promptstr, sizeof(mc.promptstr), "%s%s",
PROMPT_SCHAR); prompt, PROMPT_SCHAR);
snprintf(mc.dispstr, sizeof(mc.dispstr), "%s%s%c", mc.promptstr, (void)snprintf(mc.dispstr, sizeof(mc.dispstr), "%s%s%s",
mc.searchstr, PROMPT_ECHAR); mc.promptstr, mc.searchstr, PROMPT_ECHAR);
mc.width = font_width(mc.dispstr, strlen(mc.dispstr)); mc.width = font_width(sc, mc.dispstr, strlen(mc.dispstr));
mc.hasprompt = 1; mc.hasprompt = 1;
} }
if (initial != NULL) if (initial != NULL)
strlcpy(mc.searchstr, initial, sizeof(mc.searchstr)); (void)strlcpy(mc.searchstr, initial, sizeof(mc.searchstr));
else else
mc.searchstr[0] = '\0'; mc.searchstr[0] = '\0';
@ -113,11 +141,11 @@ menu_filter(struct menu_q *menuq, char *prompt, char *initial, int dummy,
mc.entry = mc.prev = -1; mc.entry = mc.prev = -1;
XMoveResizeWindow(X_Dpy, sc->menuwin, mc.x, mc.y, mc.width, XMoveResizeWindow(X_Dpy, sc->menuwin, mc.x, mc.y, mc.width,
font_height()); font_height(sc));
XSelectInput(X_Dpy, sc->menuwin, evmask); XSelectInput(X_Dpy, sc->menuwin, evmask);
XMapRaised(X_Dpy, sc->menuwin); XMapRaised(X_Dpy, sc->menuwin);
if (xu_ptr_grab(sc->menuwin, MenuGrabMask, Cursor_question) < 0) { if (xu_ptr_grab(sc->menuwin, MENUGRABMASK, Cursor_question) < 0) {
XUnmapWindow(X_Dpy, sc->menuwin); XUnmapWindow(X_Dpy, sc->menuwin);
return (NULL); return (NULL);
} }
@ -135,8 +163,6 @@ menu_filter(struct menu_q *menuq, char *prompt, char *initial, int dummy,
XWindowEvent(X_Dpy, sc->menuwin, evmask, &e); XWindowEvent(X_Dpy, sc->menuwin, evmask, &e);
switch (e.type) { switch (e.type) {
default:
break;
case KeyPress: case KeyPress:
if ((mi = menu_handle_key(&e, &mc, menuq, &resultq)) if ((mi = menu_handle_key(&e, &mc, menuq, &resultq))
!= NULL) != NULL)
@ -153,16 +179,23 @@ menu_filter(struct menu_q *menuq, char *prompt, char *initial, int dummy,
!= NULL) != NULL)
goto out; goto out;
break; break;
default:
break;
} }
} }
out: out:
if (dummy == 0 && mi->dummy) { /* no match */ if (dummy == 0 && mi->dummy) { /* no mouse based match */
xfree (mi); xfree(mi);
mi = NULL; mi = NULL;
xu_ptr_ungrab();
XSetInputFocus(X_Dpy, focuswin, focusrevert, CurrentTime);
} }
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); XUnmapWindow(X_Dpy, sc->menuwin);
XUngrabKeyboard(X_Dpy, CurrentTime); XUngrabKeyboard(X_Dpy, CurrentTime);
@ -178,8 +211,7 @@ menu_handle_key(XEvent *e, struct menu_ctx *mc, struct menu_q *menuq,
char chr; char chr;
size_t len; size_t len;
if (input_keycodetrans(e->xkey.keycode, e->xkey.state, if (menu_keycode(e->xkey.keycode, e->xkey.state, &ctl, &chr) < 0)
&ctl, &chr) < 0)
return (NULL); return (NULL);
switch (ctl) { switch (ctl) {
@ -216,6 +248,7 @@ menu_handle_key(XEvent *e, struct menu_ctx *mc, struct menu_q *menuq,
mc->searchstr, sizeof(mi->text)); mc->searchstr, sizeof(mi->text));
mi->dummy = 1; mi->dummy = 1;
} }
mi->abort = 0;
return (mi); return (mi);
case CTL_WIPE: case CTL_WIPE:
mc->searchstr[0] = '\0'; mc->searchstr[0] = '\0';
@ -228,6 +261,7 @@ menu_handle_key(XEvent *e, struct menu_ctx *mc, struct menu_q *menuq,
mi = xmalloc(sizeof *mi); mi = xmalloc(sizeof *mi);
mi->text[0] = '\0'; mi->text[0] = '\0';
mi->dummy = 1; mi->dummy = 1;
mi->abort = 1;
return (mi); return (mi);
default: default:
break; break;
@ -239,18 +273,18 @@ menu_handle_key(XEvent *e, struct menu_ctx *mc, struct menu_q *menuq,
str[0] = chr; str[0] = chr;
str[1] = '\0'; str[1] = '\0';
mc->changed = 1; mc->changed = 1;
strlcat(mc->searchstr, str, sizeof(mc->searchstr)); (void)strlcat(mc->searchstr, str, sizeof(mc->searchstr));
} }
mc->noresult = 0; mc->noresult = 0;
if (mc->changed && strlen(mc->searchstr) > 0) { if (mc->changed && mc->searchstr[0] != '\0') {
(*mc->match)(menuq, resultq, mc->searchstr); (*mc->match)(menuq, resultq, mc->searchstr);
/* If menuq is empty, never show we've failed */ /* If menuq is empty, never show we've failed */
mc->noresult = TAILQ_EMPTY(resultq) && !TAILQ_EMPTY(menuq); mc->noresult = TAILQ_EMPTY(resultq) && !TAILQ_EMPTY(menuq);
} else if (mc->changed) } else if (mc->changed)
TAILQ_INIT(resultq); TAILQ_INIT(resultq);
if (!mc->list && mc->listing && !mc->changed) { if (!mc->list && mc->listing && !mc->changed) {
TAILQ_INIT(resultq); TAILQ_INIT(resultq);
mc->listing = 0; mc->listing = 0;
} }
@ -262,8 +296,10 @@ static void
menu_draw(struct screen_ctx *sc, struct menu_ctx *mc, struct menu_q *menuq, menu_draw(struct screen_ctx *sc, struct menu_ctx *mc, struct menu_q *menuq,
struct menu_q *resultq) struct menu_q *resultq)
{ {
struct menu *mi; struct menu *mi;
int n, dy, xsave, ysave; XineramaScreenInfo *xine;
int xmin, xmax, ymin, ymax;
int n, dy, xsave, ysave;
if (mc->list) { if (mc->list) {
if (TAILQ_EMPTY(resultq) && mc->list) { if (TAILQ_EMPTY(resultq) && mc->list) {
@ -281,10 +317,10 @@ menu_draw(struct screen_ctx *sc, struct menu_ctx *mc, struct menu_q *menuq,
mc->width = 0; mc->width = 0;
dy = 0; dy = 0;
if (mc->hasprompt) { if (mc->hasprompt) {
snprintf(mc->dispstr, sizeof(mc->dispstr), "%s%s%c", (void)snprintf(mc->dispstr, sizeof(mc->dispstr), "%s%s%s",
mc->promptstr, mc->searchstr, PROMPT_ECHAR); mc->promptstr, mc->searchstr, PROMPT_ECHAR);
mc->width = font_width(mc->dispstr, strlen(mc->dispstr)); mc->width = font_width(sc, mc->dispstr, strlen(mc->dispstr));
dy = font_height(); dy = font_height(sc);
mc->num = 1; mc->num = 1;
} }
@ -299,24 +335,39 @@ menu_draw(struct screen_ctx *sc, struct menu_ctx *mc, struct menu_q *menuq,
text = mi->text; text = mi->text;
} }
mc->width = MAX(mc->width, font_width(text, mc->width = MAX(mc->width, font_width(sc, text,
MIN(strlen(text), MENU_MAXENTRY))); MIN(strlen(text), MENU_MAXENTRY)));
dy += font_height(); dy += font_height(sc);
mc->num++; 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; xsave = mc->x;
ysave = mc->y; ysave = mc->y;
if (mc->x < 0)
mc->x = 0;
else if (mc->x + mc->width >= sc->xmax)
mc->x = sc->xmax - mc->width;
if (mc->y + dy >= sc->ymax) if (mc->x < xmin)
mc->y = sc->ymax - dy; 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 */ /* never hide the top of the menu */
if (mc->y < 0) if (mc->y < ymin) {
mc->y = 0; mc->y = ymin;
dy = ymax - ymin;
}
if (mc->x != xsave || mc->y != ysave) if (mc->x != xsave || mc->y != ysave)
xu_ptr_setpos(sc->rootwin, mc->x, mc->y); xu_ptr_setpos(sc->rootwin, mc->x, mc->y);
@ -326,7 +377,7 @@ menu_draw(struct screen_ctx *sc, struct menu_ctx *mc, struct menu_q *menuq,
if (mc->hasprompt) { if (mc->hasprompt) {
font_draw(sc, mc->dispstr, strlen(mc->dispstr), sc->menuwin, font_draw(sc, mc->dispstr, strlen(mc->dispstr), sc->menuwin,
0, font_ascent() + 1); 0, font_ascent(sc) + 1);
n = 1; n = 1;
} else } else
n = 0; n = 0;
@ -336,17 +387,17 @@ menu_draw(struct screen_ctx *sc, struct menu_ctx *mc, struct menu_q *menuq,
mi->print : mi->text; mi->print : mi->text;
font_draw(sc, text, MIN(strlen(text), MENU_MAXENTRY), font_draw(sc, text, MIN(strlen(text), MENU_MAXENTRY),
sc->menuwin, 0, n*font_height() + font_ascent() + 1); sc->menuwin, 0, n * font_height(sc) + font_ascent(sc) + 1);
n++; n++;
} }
if (mc->hasprompt && n > 1) if (mc->hasprompt && n > 1 && (mc->searchstr[0] != '\0'))
XFillRectangle(X_Dpy, sc->menuwin, sc->gc, XFillRectangle(X_Dpy, sc->menuwin, sc->gc,
0, font_height(), mc->width, font_height()); 0, font_height(sc), mc->width, font_height(sc));
if (mc->noresult) if (mc->noresult)
XFillRectangle(X_Dpy, sc->menuwin, sc->gc, XFillRectangle(X_Dpy, sc->menuwin, sc->gc,
0, 0, mc->width, font_height()); 0, 0, mc->width, font_height(sc));
} }
static void static void
@ -357,13 +408,13 @@ menu_handle_move(XEvent *e, struct menu_ctx *mc, struct screen_ctx *sc)
if (mc->prev != -1) if (mc->prev != -1)
XFillRectangle(X_Dpy, sc->menuwin, sc->gc, 0, XFillRectangle(X_Dpy, sc->menuwin, sc->gc, 0,
font_height() * mc->prev, mc->width, font_height()); font_height(sc) * mc->prev, mc->width, font_height(sc));
if (mc->entry != -1) { if (mc->entry != -1) {
xu_ptr_regrab(MenuGrabMask, Cursor_select); (void)xu_ptr_regrab(MENUGRABMASK, Cursor_normal);
XFillRectangle(X_Dpy, sc->menuwin, sc->gc, 0, XFillRectangle(X_Dpy, sc->menuwin, sc->gc, 0,
font_height() * mc->entry, mc->width, font_height()); font_height(sc) * mc->entry, mc->width, font_height(sc));
} else } else
xu_ptr_regrab(MenuGrabMask, Cursor_default); (void)xu_ptr_regrab(MENUGRABMASK, Cursor_default);
} }
static struct menu * static struct menu *
@ -374,7 +425,6 @@ menu_handle_release(XEvent *e, struct menu_ctx *mc, struct screen_ctx *sc,
int entry, i = 0; int entry, i = 0;
entry = menu_calc_entry(sc, mc, e->xbutton.x, e->xbutton.y); entry = menu_calc_entry(sc, mc, e->xbutton.x, e->xbutton.y);
xu_ptr_ungrab();
if (mc->hasprompt) if (mc->hasprompt)
i = 1; i = 1;
@ -395,11 +445,11 @@ menu_calc_entry(struct screen_ctx *sc, struct menu_ctx *mc, int x, int y)
{ {
int entry; int entry;
entry = y / font_height(); entry = y / font_height(sc);
/* in bounds? */ /* in bounds? */
if (x < 0 || x > mc->width || y < 0 || y > font_height() * mc->num || if (x <= 0 || x > mc->width || y <= 0 ||
entry < 0 || entry >= mc->num) y > font_height(sc) * mc->num || entry < 0 || entry >= mc->num)
entry = -1; entry = -1;
if (mc->hasprompt && entry == 0) if (mc->hasprompt && entry == 0)
@ -407,3 +457,89 @@ menu_calc_entry(struct screen_ctx *sc, struct menu_ctx *mc, int x, int y)
return (entry); 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);
}

View File

@ -1,8 +1,8 @@
/* /*
* calmwm - the calm window manager * calmwm - the calm window manager
* *
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org> * Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
* Copyright (c) 2008 rivo nurges <rix@estpak.ee> * Copyright (c) 2008 rivo nurges <rix@estpak.ee>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -16,10 +16,19 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
* *
* $Id$ * $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" #include "calmwm.h"
static int mousefunc_sweep_calc(struct client_ctx *, int, int, int, int); static int mousefunc_sweep_calc(struct client_ctx *, int, int, int, int);
@ -33,22 +42,7 @@ mousefunc_sweep_calc(struct client_ctx *cc, int x, int y, int mx, int my)
cc->geom.width = abs(x - mx) - cc->bwidth; cc->geom.width = abs(x - mx) - cc->bwidth;
cc->geom.height = abs(y - my) - cc->bwidth; cc->geom.height = abs(y - my) - cc->bwidth;
if (cc->size->flags & PResizeInc) { client_applysizehints(cc);
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 = x <= mx ? x : x - cc->geom.width; cc->geom.x = x <= mx ? x : x - cc->geom.width;
cc->geom.y = y <= my ? y : y - cc->geom.height; cc->geom.y = y <= my ? y : y - cc->geom.height;
@ -59,51 +53,49 @@ mousefunc_sweep_calc(struct client_ctx *cc, int x, int y, int mx, int my)
static void static void
mousefunc_sweep_draw(struct client_ctx *cc) mousefunc_sweep_draw(struct client_ctx *cc)
{ {
struct screen_ctx *sc = CCTOSC(cc); struct screen_ctx *sc = cc->sc;
char asize[10]; /* fits "nnnnxnnnn\0" */ char asize[10]; /* fits "nnnnxnnnn\0" */
int width, height, width_size, width_name; int width, width_size, width_name;
snprintf(asize, sizeof(asize), "%dx%d", (void)snprintf(asize, sizeof(asize), "%dx%d",
(cc->geom.width - cc->geom.min_dx) / cc->size->width_inc, (cc->geom.width - cc->hint.basew) / cc->hint.incw,
(cc->geom.height - cc->geom.min_dy) / cc->size->height_inc); (cc->geom.height - cc->hint.baseh) / cc->hint.inch);
width_size = font_width(asize, strlen(asize)) + 4; width_size = font_width(sc, asize, strlen(asize)) + 4;
width_name = font_width(cc->name, strlen(cc->name)) + 4; width_name = font_width(sc, cc->name, strlen(cc->name)) + 4;
width = MAX(width_size, width_name); width = MAX(width_size, width_name);
height = font_ascent() + font_descent() + 1;
XMoveResizeWindow(X_Dpy, sc->menuwin, cc->geom.x, cc->geom.y,
width, height * 2);
XMapWindow(X_Dpy, sc->menuwin);
XReparentWindow(X_Dpy, sc->menuwin, cc->win, 0, 0); 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); XClearWindow(X_Dpy, sc->menuwin);
font_draw(sc, cc->name, strlen(cc->name), sc->menuwin, font_draw(sc, cc->name, strlen(cc->name), sc->menuwin,
2, font_ascent() + 1); 2, font_ascent(sc) + 1);
font_draw(sc, asize, strlen(asize), sc->menuwin, font_draw(sc, asize, strlen(asize), sc->menuwin,
width / 2 - width_size / 2, height + font_ascent() + 1); width / 2 - width_size / 2, font_height(sc) + font_ascent(sc) + 1);
} }
void void
mousefunc_window_resize(struct client_ctx *cc, void *arg) mousefunc_window_resize(struct client_ctx *cc, void *arg)
{ {
XEvent ev; XEvent ev;
Time time = 0; Time ltime = 0;
struct screen_ctx *sc = CCTOSC(cc); struct screen_ctx *sc = cc->sc;
int x = cc->geom.x, y = cc->geom.y; int x = cc->geom.x, y = cc->geom.y;
cc->size->width_inc = MAX(1, cc->size->width_inc); if (cc->flags & CLIENT_FREEZE)
cc->size->height_inc = MAX(1, cc->size->height_inc); return;
client_raise(cc); client_raise(cc);
client_ptrsave(cc); client_ptrsave(cc);
if (xu_ptr_grab(cc->win, MouseMask, Cursor_resize) < 0) if (xu_ptr_grab(cc->win, MOUSEMASK, Cursor_resize) < 0)
return; return;
xu_ptr_setpos(cc->win, cc->geom.width, cc->geom.height); xu_ptr_setpos(cc->win, cc->geom.width, cc->geom.height);
mousefunc_sweep_draw(cc); mousefunc_sweep_draw(cc);
for (;;) { for (;;) {
XMaskEvent(X_Dpy, MouseMask|ExposureMask, &ev); XMaskEvent(X_Dpy, MOUSEMASK|ExposureMask, &ev);
switch (ev.type) { switch (ev.type) {
case Expose: case Expose:
@ -115,18 +107,15 @@ mousefunc_window_resize(struct client_ctx *cc, void *arg)
/* Recompute window output */ /* Recompute window output */
mousefunc_sweep_draw(cc); mousefunc_sweep_draw(cc);
/* don't sync more than 60 times / second */ /* don't resize more than 60 times / second */
if ((ev.xmotion.time - time) > (1000 / 60)) { if ((ev.xmotion.time - ltime) > (1000 / 60)) {
time = ev.xmotion.time; ltime = ev.xmotion.time;
XSync(X_Dpy, False);
client_resize(cc); client_resize(cc);
} }
break; break;
case ButtonRelease: case ButtonRelease:
if (time) { if (ltime)
XSync(X_Dpy, False);
client_resize(cc); client_resize(cc);
}
XUnmapWindow(X_Dpy, sc->menuwin); XUnmapWindow(X_Dpy, sc->menuwin);
XReparentWindow(X_Dpy, sc->menuwin, sc->rootwin, 0, 0); XReparentWindow(X_Dpy, sc->menuwin, sc->rootwin, 0, 0);
xu_ptr_ungrab(); xu_ptr_ungrab();
@ -137,7 +126,6 @@ mousefunc_window_resize(struct client_ctx *cc, void *arg)
if (cc->ptr.y > cc->geom.height) if (cc->ptr.y > cc->geom.height)
cc->ptr.y = cc->geom.height - cc->bwidth; cc->ptr.y = cc->geom.height - cc->bwidth;
client_ptrwarp(cc); client_ptrwarp(cc);
return; return;
} }
} }
@ -148,39 +136,46 @@ void
mousefunc_window_move(struct client_ctx *cc, void *arg) mousefunc_window_move(struct client_ctx *cc, void *arg)
{ {
XEvent ev; XEvent ev;
Time time = 0; Time ltime = 0;
int px, py; int px, py;
client_raise(cc); client_raise(cc);
if (xu_ptr_grab(cc->win, MouseMask, Cursor_move) < 0) if (cc->flags & CLIENT_FREEZE)
return;
if (xu_ptr_grab(cc->win, MOUSEMASK, Cursor_move) < 0)
return; return;
xu_ptr_getpos(cc->win, &px, &py); xu_ptr_getpos(cc->win, &px, &py);
for (;;) { for (;;) {
XMaskEvent(X_Dpy, MouseMask|ExposureMask, &ev); XMaskEvent(X_Dpy, MOUSEMASK|ExposureMask, &ev);
switch (ev.type) { switch (ev.type) {
case Expose: case Expose:
client_draw_border(cc); client_draw_border(cc);
break; break;
case MotionNotify: case MotionNotify:
cc->geom.x = ev.xmotion.x_root - px; cc->geom.x = ev.xmotion.x_root - px - cc->bwidth;
cc->geom.y = ev.xmotion.y_root - py; cc->geom.y = ev.xmotion.y_root - py - cc->bwidth;
/* don't sync more than 60 times / second */ cc->geom.x += client_snapcalc(cc->geom.x,
if ((ev.xmotion.time - time) > (1000 / 60)) { cc->geom.width, cc->sc->xmax,
time = ev.xmotion.time; cc->bwidth, Conf.snapdist);
XSync(X_Dpy, False); 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); client_move(cc);
} }
break; break;
case ButtonRelease: case ButtonRelease:
if (time) { if (ltime)
XSync(X_Dpy, False);
client_move(cc); client_move(cc);
}
xu_ptr_ungrab(); xu_ptr_ungrab();
return; return;
} }
@ -201,6 +196,12 @@ mousefunc_window_lower(struct client_ctx *cc, void *arg)
client_lower(cc); client_lower(cc);
} }
void
mousefunc_window_raise(struct client_ctx *cc, void *arg)
{
client_raise(cc);
}
void void
mousefunc_window_hide(struct client_ctx *cc, void *arg) mousefunc_window_hide(struct client_ctx *cc, void *arg)
{ {
@ -216,11 +217,13 @@ mousefunc_menu_group(struct client_ctx *cc, void *arg)
void void
mousefunc_menu_unhide(struct client_ctx *cc, void *arg) mousefunc_menu_unhide(struct client_ctx *cc, void *arg)
{ {
struct screen_ctx *sc;
struct client_ctx *old_cc; struct client_ctx *old_cc;
struct menu *mi; struct menu *mi;
struct menu_q menuq; struct menu_q menuq;
char *wname; char *wname;
sc = cc->sc;
old_cc = client_current(); old_cc = client_current();
TAILQ_INIT(&menuq); TAILQ_INIT(&menuq);
@ -231,7 +234,7 @@ mousefunc_menu_unhide(struct client_ctx *cc, void *arg)
continue; continue;
mi = xcalloc(1, sizeof(*mi)); mi = xcalloc(1, sizeof(*mi));
strlcpy(mi->text, wname, sizeof(mi->text)); (void)strlcpy(mi->text, wname, sizeof(mi->text));
mi->ctx = cc; mi->ctx = cc;
TAILQ_INSERT_TAIL(&menuq, mi, entry); TAILQ_INSERT_TAIL(&menuq, mi, entry);
} }
@ -239,7 +242,7 @@ mousefunc_menu_unhide(struct client_ctx *cc, void *arg)
if (TAILQ_EMPTY(&menuq)) if (TAILQ_EMPTY(&menuq))
return; return;
mi = menu_filter(&menuq, NULL, NULL, 0, NULL, NULL); mi = menu_filter(sc, &menuq, NULL, NULL, 0, NULL, NULL);
if (mi != NULL) { if (mi != NULL) {
cc = (struct client_ctx *)mi->ctx; cc = (struct client_ctx *)mi->ctx;
client_unhide(cc); client_unhide(cc);
@ -258,21 +261,24 @@ mousefunc_menu_unhide(struct client_ctx *cc, void *arg)
void void
mousefunc_menu_cmd(struct client_ctx *cc, void *arg) mousefunc_menu_cmd(struct client_ctx *cc, void *arg)
{ {
struct menu *mi; struct screen_ctx *sc;
struct menu_q menuq; struct menu *mi;
struct cmd *cmd; struct menu_q menuq;
struct cmd *cmd;
sc = cc->sc;
TAILQ_INIT(&menuq); TAILQ_INIT(&menuq);
TAILQ_FOREACH(cmd, &Conf.cmdq, entry) { TAILQ_FOREACH(cmd, &Conf.cmdq, entry) {
mi = xcalloc(1, sizeof(*mi)); mi = xcalloc(1, sizeof(*mi));
strlcpy(mi->text, cmd->label, sizeof(mi->text)); (void)strlcpy(mi->text, cmd->label, sizeof(mi->text));
mi->ctx = cmd; mi->ctx = cmd;
TAILQ_INSERT_TAIL(&menuq, mi, entry); TAILQ_INSERT_TAIL(&menuq, mi, entry);
} }
if (TAILQ_EMPTY(&menuq)) if (TAILQ_EMPTY(&menuq))
return; return;
mi = menu_filter(&menuq, NULL, NULL, 0, NULL, NULL); mi = menu_filter(sc, &menuq, NULL, NULL, 0, NULL, NULL);
if (mi != NULL) if (mi != NULL)
u_spawn(((struct cmd *)mi->ctx)->image); u_spawn(((struct cmd *)mi->ctx)->image);
else else

82
parse.y
View File

@ -21,7 +21,11 @@
%{ %{
#include <sys/param.h>
#include <sys/queue.h>
#include <ctype.h> #include <ctype.h>
#include <err.h>
#include <errno.h> #include <errno.h>
#include <limits.h> #include <limits.h>
#include <stdarg.h> #include <stdarg.h>
@ -29,7 +33,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "headers.h"
#include "calmwm.h" #include "calmwm.h"
TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files);
@ -67,9 +70,10 @@ typedef struct {
%token FONTNAME STICKY GAP MOUSEBIND %token FONTNAME STICKY GAP MOUSEBIND
%token AUTOGROUP BIND COMMAND IGNORE %token AUTOGROUP BIND COMMAND IGNORE
%token YES NO BORDERWIDTH MOVEAMOUNT %token YES NO BORDERWIDTH MOVEAMOUNT
%token COLOR %token COLOR SNAPDIST
%token ACTIVEBORDER INACTIVEBORDER %token ACTIVEBORDER INACTIVEBORDER
%token GROUPBORDER UNGROUPBORDER %token GROUPBORDER UNGROUPBORDER
%token MENUBG MENUFG FONTCOLOR
%token ERROR %token ERROR
%token <v.string> STRING %token <v.string> STRING
%token <v.number> NUMBER %token <v.number> NUMBER
@ -102,8 +106,8 @@ yesno : YES { $$ = 1; }
; ;
main : FONTNAME STRING { main : FONTNAME STRING {
free(conf->DefaultFontName); free(conf->font);
conf->DefaultFontName = $2; conf->font = $2;
} }
| STICKY yesno { | STICKY yesno {
if ($2 == 0) if ($2 == 0)
@ -117,42 +121,29 @@ main : FONTNAME STRING {
| MOVEAMOUNT NUMBER { | MOVEAMOUNT NUMBER {
conf->mamount = $2; conf->mamount = $2;
} }
| SNAPDIST NUMBER {
conf->snapdist = $2;
}
| COMMAND STRING string { | COMMAND STRING string {
conf_cmd_add(conf, $3, $2, 0); conf_cmd_add(conf, $3, $2, 0);
free($2); free($2);
free($3); free($3);
} }
| AUTOGROUP NUMBER STRING { | AUTOGROUP NUMBER STRING {
struct autogroupwin *aw;
char *p;
if ($2 < 0 || $2 > 9) { if ($2 < 0 || $2 > 9) {
free($3); free($3);
yyerror("autogroup number out of range: %d", $2); yyerror("autogroup number out of range: %d", $2);
YYERROR; YYERROR;
} }
aw = xcalloc(1, sizeof(*aw)); group_make_autogroup(conf, $3, $2);
if ((p = strchr($3, ',')) == NULL) {
aw->name = NULL;
aw->class = xstrdup($3);
} else {
*(p++) = '\0';
aw->name = xstrdup($3);
aw->class = xstrdup(p);
}
aw->group = xstrdup(shortcut_to_name[$2]);
TAILQ_INSERT_TAIL(&conf->autogroupq, aw, entry);
free($3); free($3);
} }
| IGNORE STRING { | IGNORE STRING {
struct winmatch *wm; struct winmatch *wm;
wm = xcalloc(1, sizeof(*wm)); wm = xcalloc(1, sizeof(*wm));
strlcpy(wm->title, $2, sizeof(wm->title)); (void)strlcpy(wm->title, $2, sizeof(wm->title));
TAILQ_INSERT_TAIL(&conf->ignoreq, wm, entry); TAILQ_INSERT_TAIL(&conf->ignoreq, wm, entry);
free($2); free($2);
@ -163,10 +154,10 @@ main : FONTNAME STRING {
free($3); free($3);
} }
| GAP NUMBER NUMBER NUMBER NUMBER { | GAP NUMBER NUMBER NUMBER NUMBER {
conf->gap_top = $2; conf->gap.top = $2;
conf->gap_bottom = $3; conf->gap.bottom = $3;
conf->gap_left = $4; conf->gap.left = $4;
conf->gap_right = $5; conf->gap.right = $5;
} }
| MOUSEBIND STRING string { | MOUSEBIND STRING string {
conf_mousebind(conf, $2, $3); conf_mousebind(conf, $2, $3);
@ -179,8 +170,8 @@ color : COLOR colors
; ;
colors : ACTIVEBORDER STRING { colors : ACTIVEBORDER STRING {
free(conf->color[CWM_COLOR_BORDOR_ACTIVE].name); free(conf->color[CWM_COLOR_BORDER_ACTIVE].name);
conf->color[CWM_COLOR_BORDOR_ACTIVE].name = $2; conf->color[CWM_COLOR_BORDER_ACTIVE].name = $2;
} }
| INACTIVEBORDER STRING { | INACTIVEBORDER STRING {
free(conf->color[CWM_COLOR_BORDER_INACTIVE].name); free(conf->color[CWM_COLOR_BORDER_INACTIVE].name);
@ -194,6 +185,18 @@ colors : ACTIVEBORDER STRING {
free(conf->color[CWM_COLOR_BORDER_UNGROUP].name); free(conf->color[CWM_COLOR_BORDER_UNGROUP].name);
conf->color[CWM_COLOR_BORDER_UNGROUP].name = $2; 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;
}
; ;
%% %%
@ -233,14 +236,18 @@ lookup(char *s)
{ "borderwidth", BORDERWIDTH}, { "borderwidth", BORDERWIDTH},
{ "color", COLOR}, { "color", COLOR},
{ "command", COMMAND}, { "command", COMMAND},
{ "font", FONTCOLOR},
{ "fontname", FONTNAME}, { "fontname", FONTNAME},
{ "gap", GAP}, { "gap", GAP},
{ "groupborder", GROUPBORDER}, { "groupborder", GROUPBORDER},
{ "ignore", IGNORE}, { "ignore", IGNORE},
{ "inactiveborder", INACTIVEBORDER}, { "inactiveborder", INACTIVEBORDER},
{ "menubg", MENUBG},
{ "menufg", MENUFG},
{ "mousebind", MOUSEBIND}, { "mousebind", MOUSEBIND},
{ "moveamount", MOVEAMOUNT}, { "moveamount", MOVEAMOUNT},
{ "no", NO}, { "no", NO},
{ "snapdist", SNAPDIST},
{ "sticky", STICKY}, { "sticky", STICKY},
{ "ungroupborder", UNGROUPBORDER}, { "ungroupborder", UNGROUPBORDER},
{ "yes", YES} { "yes", YES}
@ -379,9 +386,10 @@ yylex(void)
return (0); return (0);
if (next == quotec || c == ' ' || c == '\t') if (next == quotec || c == ' ' || c == '\t')
c = next; c = next;
else if (next == '\n') else if (next == '\n') {
file->lineno++;
continue; continue;
else } else
lungetc(next); lungetc(next);
} else if (c == quotec) { } else if (c == quotec) {
*p = '\0'; *p = '\0';
@ -470,8 +478,6 @@ pushfile(const char *name)
nfile->name = xstrdup(name); nfile->name = xstrdup(name);
if ((nfile->stream = fopen(nfile->name, "r")) == NULL) { if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
if (errno != ENOENT)
warn("%s", nfile->name);
free(nfile->name); free(nfile->name);
free(nfile); free(nfile);
return (NULL); return (NULL);
@ -510,7 +516,7 @@ parse_config(const char *filename, struct conf *xconf)
return (-1); return (-1);
} }
strlcpy(conf->conf_path, filename, sizeof(conf->conf_path)); (void)strlcpy(conf->conf_path, filename, sizeof(conf->conf_path));
conf_init(conf); conf_init(conf);
@ -535,6 +541,8 @@ parse_config(const char *filename, struct conf *xconf)
xconf->flags = conf->flags; xconf->flags = conf->flags;
xconf->bwidth = conf->bwidth; xconf->bwidth = conf->bwidth;
xconf->mamount = conf->mamount; xconf->mamount = conf->mamount;
xconf->snapdist = conf->snapdist;
xconf->gap = conf->gap;
while ((cmd = TAILQ_FIRST(&conf->cmdq)) != NULL) { while ((cmd = TAILQ_FIRST(&conf->cmdq)) != NULL) {
TAILQ_REMOVE(&conf->cmdq, cmd, entry); TAILQ_REMOVE(&conf->cmdq, cmd, entry);
@ -561,17 +569,15 @@ parse_config(const char *filename, struct conf *xconf)
TAILQ_INSERT_TAIL(&xconf->mousebindingq, mb, entry); TAILQ_INSERT_TAIL(&xconf->mousebindingq, mb, entry);
} }
strlcpy(xconf->termpath, conf->termpath, (void)strlcpy(xconf->termpath, conf->termpath,
sizeof(xconf->termpath)); sizeof(xconf->termpath));
strlcpy(xconf->lockpath, conf->lockpath, (void)strlcpy(xconf->lockpath, conf->lockpath,
sizeof(xconf->lockpath)); sizeof(xconf->lockpath));
for (i = 0; i < CWM_COLOR_MAX; i++) for (i = 0; i < CWM_COLOR_MAX; i++)
xconf->color[i].name = conf->color[i].name; xconf->color[i].name = conf->color[i].name;
xconf->DefaultFontName = conf->DefaultFontName; xconf->font = conf->font;
bcopy(&(conf->gap_top), &(xconf->gap_top), sizeof(int) * 4);
} }
free(conf); free(conf);

View File

@ -15,20 +15,21 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
* *
* $Id$ * $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" #include "calmwm.h"
extern struct screen_ctx *Curscreen;
void
screen_init(void)
{
TAILQ_INIT(&Screenq);
}
struct screen_ctx * struct screen_ctx *
screen_fromroot(Window rootwin) screen_fromroot(Window rootwin)
{ {
@ -42,22 +43,13 @@ screen_fromroot(Window rootwin)
return (TAILQ_FIRST(&Screenq)); return (TAILQ_FIRST(&Screenq));
} }
struct screen_ctx *
screen_current(void)
{
return (Curscreen);
}
void void
screen_updatestackingorder(void) screen_updatestackingorder(struct screen_ctx *sc)
{ {
Window *wins, w0, w1; Window *wins, w0, w1;
struct screen_ctx *sc;
struct client_ctx *cc; struct client_ctx *cc;
u_int nwins, i, s; u_int nwins, i, s;
sc = screen_current();
if (!XQueryTree(X_Dpy, sc->rootwin, &w0, &w1, &wins, &nwins)) if (!XQueryTree(X_Dpy, sc->rootwin, &w0, &w1, &wins, &nwins))
return; return;
@ -83,10 +75,10 @@ screen_init_xinerama(struct screen_ctx *sc)
HasXinerama = 0; HasXinerama = 0;
sc->xinerama_no = 0; sc->xinerama_no = 0;
} }
info = XineramaQueryScreens(X_Dpy, &no); info = XineramaQueryScreens(X_Dpy, &no);
if (info == NULL) { if (info == NULL) {
/*is xinerama is actually off, instead of a malloc failure? */ /* Is xinerama actually off, instead of a malloc failure? */
if (sc->xinerama == NULL) if (sc->xinerama == NULL)
HasXinerama = 0; HasXinerama = 0;
return; return;
@ -109,9 +101,33 @@ screen_find_xinerama(struct screen_ctx *sc, int x, int y)
for (i = 0; i < sc->xinerama_no; i++) { for (i = 0; i < sc->xinerama_no; i++) {
info = &sc->xinerama[i]; info = &sc->xinerama[i];
if (x > info->x_org && x < info->x_org + info->width && if (x >= info->x_org && x < info->x_org + info->width &&
y > info->y_org && y < info->y_org + info->height) y >= info->y_org && y < info->y_org + info->height)
return (info); return (info);
} }
return (NULL); return (NULL);
} }
void
screen_update_geometry(struct screen_ctx *sc, int width, int height)
{
long geom[2], workareas[CALMWM_NGROUPS][4];
int i;
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);
/* 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);
}
XChangeProperty(X_Dpy, sc->rootwin, _NET_WORKAREA,
XA_CARDINAL, 32, PropModeReplace,
(unsigned char *)workareas, CALMWM_NGROUPS * 4);
}

View File

@ -2,6 +2,7 @@
* calmwm - the calm window manager * calmwm - the calm window manager
* *
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org> * Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
*
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies. * copyright notice and this permission notice appear in all copies.
@ -14,11 +15,21 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
* *
* $Id$ * $OpenBSD$
*/ */
#include <sys/param.h>
#include <sys/queue.h>
#include <assert.h>
#include <err.h>
#include <errno.h>
#include <fnmatch.h> #include <fnmatch.h>
#include "headers.h" #include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "calmwm.h" #include "calmwm.h"
static int strsubmatch(char *, char *, int); static int strsubmatch(char *, char *, int);
@ -32,13 +43,10 @@ search_match_client(struct menu_q *menuq, struct menu_q *resultq, char *search)
{ {
struct winname *wn; struct winname *wn;
struct menu *mi, *tierp[4], *before = NULL; struct menu *mi, *tierp[4], *before = NULL;
int ntiers;
ntiers = sizeof(tierp) / sizeof(tierp[0]);
TAILQ_INIT(resultq); TAILQ_INIT(resultq);
memset(tierp, 0, sizeof(tierp)); (void)memset(tierp, 0, sizeof(tierp));
/* /*
* In order of rank: * In order of rank:
@ -68,11 +76,7 @@ search_match_client(struct menu_q *menuq, struct menu_q *resultq, char *search)
} }
} }
/* /* Then if there is a match on the window class name. */
* See if there is a match on the window class
* name.
*/
if (tier < 0 && strsubmatch(search, cc->app_class, 0)) { if (tier < 0 && strsubmatch(search, cc->app_class, 0)) {
cc->matchname = cc->app_class; cc->matchname = cc->app_class;
tier = 3; tier = 3;
@ -86,16 +90,14 @@ search_match_client(struct menu_q *menuq, struct menu_q *resultq, char *search)
* window. Furthermore, this is denoted by a "!" when * window. Furthermore, this is denoted by a "!" when
* printing the window name in the search menu. * printing the window name in the search menu.
*/ */
if (cc == client_current() && tier < ntiers - 1) if (cc == client_current() && tier < nitems(tierp) - 1)
tier++; tier++;
/* /* Clients that are hidden get ranked one up. */
* Clients that are hidden get ranked one up.
*/
if (cc->flags & CLIENT_HIDDEN && tier > 0) if (cc->flags & CLIENT_HIDDEN && tier > 0)
tier--; tier--;
assert(tier < ntiers); assert(tier < nitems(tierp));
/* /*
* If you have a tierp, insert after it, and make it * If you have a tierp, insert after it, and make it
@ -104,7 +106,6 @@ search_match_client(struct menu_q *menuq, struct menu_q *resultq, char *search)
* Always make your current tierp the newly inserted * Always make your current tierp the newly inserted
* entry. * entry.
*/ */
for (t = tier; t >= 0 && ((before = tierp[t]) == NULL); t--) for (t = tier; t >= 0 && ((before = tierp[t]) == NULL); t--)
; ;
@ -133,7 +134,8 @@ search_print_client(struct menu *mi, int list)
if (list) if (list)
cc->matchname = cc->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 && if (!list && cc->matchname != cc->name &&
strlen(mi->print) < sizeof(mi->print) - 1) { strlen(mi->print) < sizeof(mi->print) - 1) {
@ -153,8 +155,8 @@ search_print_client(struct menu *mi, int list)
diff = strlen(cc->name); diff = strlen(cc->name);
} }
strlcpy(buf, mi->print, sizeof(buf)); (void)strlcpy(buf, mi->print, sizeof(buf));
snprintf(mi->print, sizeof(mi->print), (void)snprintf(mi->print, sizeof(mi->print),
"%s:%.*s%s", buf, diff, cc->name, marker); "%s:%.*s%s", buf, diff, cc->name, marker);
} }
} }

61
strlcat.c Normal file
View File

@ -0,0 +1,61 @@
/* $OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */
/*
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
*
* 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 ORIGINAL: lib/libc/string/strlcat.c */
#ifndef HAVE_STRLCAT
#include <sys/types.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)
{
char *d = dst;
const char *s = src;
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 */
}
#endif /* !HAVE_STRLCAT */

57
strlcpy.c Normal file
View File

@ -0,0 +1,57 @@
/* $OpenBSD: strlcpy.c,v 1.10 2005/08/08 08:05:37 espie Exp $ */
/*
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
*
* 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 ORIGINAL: lib/libc/string/strlcpy.c */
#ifndef HAVE_STRLCPY
#include <sys/types.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)
{
char *d = dst;
const char *s = src;
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 */
}
#endif /* !HAVE_STRLCPY */

70
strtonum.c Normal file
View File

@ -0,0 +1,70 @@
/* $OpenBSD: strtonum.c,v 1.6 2004/08/03 19:38:01 millert Exp $ */
/*
* Copyright (c) 2004 Ted Unangst and Todd Miller
* 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.
*/
/* OPENBSD ORIGINAL: lib/libc/stdlib/strtonum.c */
#ifndef HAVE_STRTONUM
#include <stdlib.h>
#include <limits.h>
#include <errno.h>
#define INVALID 1
#define TOOSMALL 2
#define TOOLARGE 3
long long
strtonum(const char *numstr, long long minval, long long maxval,
const char **errstrp)
{
long long ll = 0;
char *ep;
int error = 0;
struct errval {
const char *errstr;
int err;
} ev[4] = {
{ NULL, 0 },
{ "invalid", EINVAL },
{ "too small", ERANGE },
{ "too large", ERANGE },
};
ev[0].err = errno;
errno = 0;
if (minval > maxval)
error = INVALID;
else {
ll = strtoll(numstr, &ep, 10);
if (numstr == ep || *ep != '\0')
error = INVALID;
else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval)
error = TOOSMALL;
else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval)
error = TOOLARGE;
}
if (errstrp != NULL)
*errstrp = ev[error].errstr;
errno = ev[error].err;
if (error)
ll = 0;
return (ll);
}
#endif /* HAVE_STRTONUM */

22
util.c
View File

@ -15,15 +15,24 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
* *
* $Id$ * $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" #include "calmwm.h"
#define MAXARGLEN 20 #define MAXARGLEN 20
int void
u_spawn(char *argstr) u_spawn(char *argstr)
{ {
switch (fork()) { switch (fork()) {
@ -33,12 +42,9 @@ u_spawn(char *argstr)
break; break;
case -1: case -1:
warn("fork"); warn("fork");
return (-1);
default: default:
break; break;
} }
return (0);
} }
void void
@ -70,6 +76,6 @@ u_exec(char *argstr)
} }
*ap = NULL; *ap = NULL;
setsid(); (void)setsid();
execvp(args[0], args); (void)execvp(args[0], args);
} }

View File

@ -15,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
* *
* $Id$ * $OpenBSD$
*/ */
/* /*
@ -24,7 +24,17 @@
* management of the xevent's. * management of the xevent's.
*/ */
#include "headers.h" #include <sys/param.h>
#include <sys/queue.h>
#include <err.h>
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "calmwm.h" #include "calmwm.h"
static void xev_handle_maprequest(XEvent *); static void xev_handle_maprequest(XEvent *);
@ -76,7 +86,8 @@ xev_handle_maprequest(XEvent *ee)
cc = client_new(e->window, screen_fromroot(xattr.root), 1); cc = client_new(e->window, screen_fromroot(xattr.root), 1);
} }
client_ptrwarp(cc); if ((cc->flags & CLIENT_IGNORE) == 0)
client_ptrwarp(cc);
} }
static void static void
@ -125,7 +136,7 @@ xev_handle_configurerequest(XEvent *ee)
XWindowChanges wc; XWindowChanges wc;
if ((cc = client_find(e->window)) != NULL) { if ((cc = client_find(e->window)) != NULL) {
sc = CCTOSC(cc); sc = cc->sc;
if (e->value_mask & CWWidth) if (e->value_mask & CWWidth)
cc->geom.width = e->width; cc->geom.width = e->width;
@ -151,7 +162,7 @@ xev_handle_configurerequest(XEvent *ee)
wc.border_width = cc->bwidth; wc.border_width = cc->bwidth;
XConfigureWindow(X_Dpy, cc->win, e->value_mask, &wc); XConfigureWindow(X_Dpy, cc->win, e->value_mask, &wc);
xev_reconfig(cc); xu_configure(cc);
} else { } else {
/* let it do what it wants, it'll be ours when we map it. */ /* let it do what it wants, it'll be ours when we map it. */
wc.x = e->x; wc.x = e->x;
@ -170,41 +181,35 @@ static void
xev_handle_propertynotify(XEvent *ee) xev_handle_propertynotify(XEvent *ee)
{ {
XPropertyEvent *e = &ee->xproperty; XPropertyEvent *e = &ee->xproperty;
struct screen_ctx *sc;
struct client_ctx *cc; struct client_ctx *cc;
long tmp;
if ((cc = client_find(e->window)) != NULL) { if ((cc = client_find(e->window)) != NULL) {
switch (e->atom) { switch (e->atom) {
case XA_WM_NORMAL_HINTS: case XA_WM_NORMAL_HINTS:
XGetWMNormalHints(X_Dpy, cc->win, cc->size, &tmp); client_getsizehints(cc);
break; break;
case XA_WM_NAME: case XA_WM_NAME:
client_setname(cc); client_setname(cc);
break; break;
case XA_WM_TRANSIENT_FOR:
client_transient(cc);
break;
default: default:
/* do nothing */ /* do nothing */
break; 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);
} }
}
void
xev_reconfig(struct client_ctx *cc)
{
XConfigureEvent ce;
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);
} }
static void static void
@ -228,7 +233,7 @@ static void
xev_handle_buttonpress(XEvent *ee) xev_handle_buttonpress(XEvent *ee)
{ {
XButtonEvent *e = &ee->xbutton; XButtonEvent *e = &ee->xbutton;
struct client_ctx *cc; struct client_ctx *cc, fakecc;
struct screen_ctx *sc; struct screen_ctx *sc;
struct mousebinding *mb; struct mousebinding *mb;
@ -245,15 +250,13 @@ xev_handle_buttonpress(XEvent *ee)
if (mb == NULL) if (mb == NULL)
return; return;
if (mb->context == MOUSEBIND_CTX_ROOT) { if (mb->context == MOUSEBIND_CTX_ROOT) {
if (e->window != sc->rootwin) if (e->window != sc->rootwin)
return; return;
} else if (mb->context == MOUSEBIND_CTX_WIN) { cc = &fakecc;
cc = client_find(e->window); cc->sc = screen_fromroot(e->window);
if (cc == NULL) } else if (cc == NULL) /* (mb->context == MOUSEBIND_CTX_WIN */
return; return;
}
(*mb->callback)(cc, e); (*mb->callback)(cc, e);
} }
@ -271,7 +274,7 @@ static void
xev_handle_keypress(XEvent *ee) xev_handle_keypress(XEvent *ee)
{ {
XKeyEvent *e = &ee->xkey; XKeyEvent *e = &ee->xkey;
struct client_ctx *cc = NULL; struct client_ctx *cc = NULL, fakecc;
struct keybinding *kb; struct keybinding *kb;
KeySym keysym, skeysym; KeySym keysym, skeysym;
int modshift; int modshift;
@ -299,12 +302,14 @@ xev_handle_keypress(XEvent *ee)
if (kb == NULL) if (kb == NULL)
return; return;
if (kb->flags & KBFLAG_NEEDCLIENT) {
if ((kb->flags & (KBFLAG_NEEDCLIENT)) && if (((cc = client_find(e->window)) == NULL) &&
(cc = client_find(e->window)) == NULL && (cc = client_current()) == NULL)
(cc = client_current()) == NULL)
if (kb->flags & KBFLAG_NEEDCLIENT)
return; return;
} else {
cc = &fakecc;
cc->sc = screen_fromroot(e->window);
}
(*kb->callback)(cc, &kb->argument); (*kb->callback)(cc, &kb->argument);
} }
@ -369,14 +374,13 @@ xev_handle_randr(XEvent *ee)
TAILQ_FOREACH(sc, &Screenq, entry) { TAILQ_FOREACH(sc, &Screenq, entry) {
if (sc->which == (u_int)i) { if (sc->which == (u_int)i) {
XRRUpdateConfiguration(ee); XRRUpdateConfiguration(ee);
sc->xmax = rev->width; screen_update_geometry(sc, rev->width, rev->height);
sc->ymax = rev->height;
screen_init_xinerama(sc); screen_init_xinerama(sc);
} }
} }
} }
/* /*
* Called when the keymap has changed. * Called when the keymap has changed.
* Ungrab all keys, reload keymap and then regrab * Ungrab all keys, reload keymap and then regrab
*/ */
@ -405,15 +409,14 @@ xev_handle_expose(XEvent *ee)
client_draw_border(cc); client_draw_border(cc);
} }
volatile sig_atomic_t xev_quit = 0;
volatile sig_atomic_t _xev_quit = 0;
void void
xev_loop(void) xev_loop(void)
{ {
XEvent e; XEvent e;
while (_xev_quit == 0) { while (xev_quit == 0) {
XNextEvent(X_Dpy, &e); XNextEvent(X_Dpy, &e);
if (e.type - Randr_ev == RRScreenChangeNotify) if (e.type - Randr_ev == RRScreenChangeNotify)
xev_handle_randr(&e); xev_handle_randr(&e);

View File

@ -15,10 +15,19 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
* *
* $Id$ * $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" #include "calmwm.h"
void * void *

129
xutil.c
View File

@ -15,10 +15,19 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
* *
* $Id$ * $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" #include "calmwm.h"
static unsigned int ign_mods[] = { 0, LockMask, Mod2Mask, Mod2Mask | LockMask }; static unsigned int ign_mods[] = { 0, LockMask, Mod2Mask, Mod2Mask | LockMask };
@ -48,9 +57,9 @@ void
xu_btn_grab(Window win, int mask, u_int btn) xu_btn_grab(Window win, int mask, u_int btn)
{ {
int i; int i;
for (i = 0; i < sizeof(ign_mods)/sizeof(*ign_mods); i++) for (i = 0; i < nitems(ign_mods); i++)
XGrabButton(X_Dpy, btn, (mask | ign_mods[i]), win, XGrabButton(X_Dpy, btn, (mask | ign_mods[i]), win,
False, ButtonMask, GrabModeAsync, False, BUTTONMASK, GrabModeAsync,
GrabModeSync, None, None); GrabModeSync, None, None);
} }
@ -58,7 +67,7 @@ void
xu_btn_ungrab(Window win, int mask, u_int btn) xu_btn_ungrab(Window win, int mask, u_int btn)
{ {
int i; int i;
for (i = 0; i < sizeof(ign_mods)/sizeof(*ign_mods); i++) for (i = 0; i < nitems(ign_mods); i++)
XUngrabButton(X_Dpy, btn, (mask | ign_mods[i]), win); XUngrabButton(X_Dpy, btn, (mask | ign_mods[i]), win);
} }
@ -89,7 +98,7 @@ xu_key_grab(Window win, int mask, int keysym)
(XKeycodeToKeysym(X_Dpy, code, 1) == keysym)) (XKeycodeToKeysym(X_Dpy, code, 1) == keysym))
mask |= ShiftMask; mask |= ShiftMask;
for (i = 0; i < sizeof(ign_mods)/sizeof(*ign_mods); i++) for (i = 0; i < nitems(ign_mods); i++)
XGrabKey(X_Dpy, code, (mask | ign_mods[i]), win, XGrabKey(X_Dpy, code, (mask | ign_mods[i]), win,
True, GrabModeAsync, GrabModeAsync); True, GrabModeAsync, GrabModeAsync);
} }
@ -105,34 +114,53 @@ xu_key_ungrab(Window win, int mask, int keysym)
(XKeycodeToKeysym(X_Dpy, code, 1) == keysym)) (XKeycodeToKeysym(X_Dpy, code, 1) == keysym))
mask |= ShiftMask; mask |= ShiftMask;
for (i = 0; i < sizeof(ign_mods)/sizeof(*ign_mods); i++) for (i = 0; i < nitems(ign_mods); i++)
XUngrabKey(X_Dpy, code, (mask | ign_mods[i]), win); XUngrabKey(X_Dpy, code, (mask | ign_mods[i]), win);
} }
void void
xu_sendmsg(struct client_ctx *cc, Atom atm, long val) xu_configure(struct client_ctx *cc)
{
XConfigureEvent ce;
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; XEvent e;
memset(&e, 0, sizeof(e)); (void)memset(&e, 0, sizeof(e));
e.xclient.type = ClientMessage; e.xclient.type = ClientMessage;
e.xclient.window = cc->win; e.xclient.window = win;
e.xclient.message_type = atm; e.xclient.message_type = atm;
e.xclient.format = 32; e.xclient.format = 32;
e.xclient.data.l[0] = val; e.xclient.data.l[0] = val;
e.xclient.data.l[1] = CurrentTime; e.xclient.data.l[1] = CurrentTime;
XSendEvent(X_Dpy, cc->win, False, 0, &e); XSendEvent(X_Dpy, win, False, 0, &e);
} }
int 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; Atom realtype;
u_long n, extra; u_long n, extra;
int format; int format;
if (XGetWindowProperty(X_Dpy, cc->win, atm, 0L, len, False, type, if (XGetWindowProperty(X_Dpy, win, atm, 0L, len, False, type,
&realtype, &format, &n, &extra, p) != Success || *p == NULL) &realtype, &format, &n, &extra, p) != Success || *p == NULL)
return (-1); return (-1);
@ -142,12 +170,44 @@ xu_getprop(struct client_ctx *cc, Atom atm, Atom type, long len, u_char **p)
return (n); 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 int
xu_getstate(struct client_ctx *cc, int *state) xu_getstate(struct client_ctx *cc, int *state)
{ {
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); return (-1);
*state = (int)*p; *state = (int)*p;
@ -176,7 +236,21 @@ char *atoms[CWM_NO_ATOMS] = {
"WM_TAKE_FOCUS", "WM_TAKE_FOCUS",
"WM_PROTOCOLS", "WM_PROTOCOLS",
"_MOTIF_WM_HINTS", "_MOTIF_WM_HINTS",
"_CWM_GRP", "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 void
@ -185,6 +259,31 @@ xu_getatoms(void)
XInternAtoms(X_Dpy, atoms, CWM_NO_ATOMS, False, cwm_atoms); 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 unsigned long
xu_getcolor(struct screen_ctx *sc, char *name) xu_getcolor(struct screen_ctx *sc, char *name)
{ {