158 Commits

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

from Thomas Pfaff.

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

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

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

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

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

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

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

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

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

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

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

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

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

picked from a larger martynas diff from ages ago.

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

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

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

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

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

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

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

clean-up of variable names as a separate commit.

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

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

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

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

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

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

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

inspired by Thomas Pfaff's report on tech@

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

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

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

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

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

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

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

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

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

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

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

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

only three informational root-window hints to go.

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

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

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

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

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

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

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

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

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

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

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

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

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

From Bertrand Janin; thanks!

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

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

originally from jacekm@ long time ago.

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

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

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

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

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

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

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

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

just whack the flags unconditionally, it's simpler.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

---

#cwmrc

# add new windows to the current group
set sticky

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

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

---

mostly by sthen, tweaks from me.

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

ok oga@ sometime ago
2009-04-15 14:01:45 +00:00
8a490fc270 we include sys/param.h, so remove sys/types.h; sort while here.
ok oga@
2009-04-12 23:51:10 +00:00
8346de997f - avoid shadowed Mask declaration in menu_filter
- make _xev_reincorporate static
evmask naming oga@, input okan@.  ok okan@, oga@
2009-03-28 16:38:54 +00:00
23 changed files with 2473 additions and 1932 deletions

View File

@ -5,21 +5,19 @@
PROG= cwm
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
CPPFLAGS+= -I${X11BASE}/include -I${X11BASE}/include/freetype2 -I${.CURDIR}
CFLAGS+= -Wall
LDADD+= -L${X11BASE}/lib -lXft -lXrender -lX11 -lXau -lXdmcp \
LDADD+= -L${X11BASE}/lib -lXft -lXrender -lX11 -lxcb -lXau -lXdmcp \
-lfontconfig -lexpat -lfreetype -lz -lXinerama -lXrandr -lXext
MANDIR= ${X11BASE}/man/cat
MANDIR= ${X11BASE}/man/man
MAN= cwm.1 cwmrc.5
CLEANFILES= cwm.cat1 cwmrc.cat5
obj: _xenocara_obj
.include <bsd.prog.mk>

58
README
View File

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

207
calmwm.c
View File

@ -15,31 +15,45 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* 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"
Display *X_Dpy;
Cursor Cursor_move;
Cursor Cursor_resize;
Cursor Cursor_select;
Cursor Cursor_default;
Cursor Cursor_move;
Cursor Cursor_normal;
Cursor Cursor_question;
Cursor Cursor_resize;
struct screen_ctx_q Screenq;
struct screen_ctx *Curscreen;
struct client_ctx_q Clientq;
struct screen_ctx_q Screenq = TAILQ_HEAD_INITIALIZER(Screenq);
struct client_ctx_q Clientq = TAILQ_HEAD_INITIALIZER(Clientq);
int HasXinerama, HasRandr, Randr_ev;
int Starting;
struct conf Conf;
static void _sigchld_cb(int);
static void sigchld_cb(int);
static void dpy_init(const char *);
static int x_errorhandler(Display *, XErrorEvent *);
static int x_wmerrorhandler(Display *, XErrorEvent *);
static void x_setup(void);
static void x_setupscreen(struct screen_ctx *, u_int);
static void x_teardown(void);
int
main(int argc, char **argv)
@ -63,68 +77,57 @@ main(int argc, char **argv)
argc -= optind;
argv += optind;
if (signal(SIGCHLD, _sigchld_cb) == SIG_ERR)
if (signal(SIGCHLD, sigchld_cb) == SIG_ERR)
err(1, "signal");
group_init();
Starting = 1;
dpy_init(display_name);
bzero(&Conf, sizeof(Conf));
conf_setup(&Conf, conf_file);
client_setup();
xu_getatoms();
x_setup();
Starting = 0;
xev_init();
XEV_QUICK(NULL, NULL, MapRequest, xev_handle_maprequest, NULL);
XEV_QUICK(NULL, NULL, UnmapNotify, xev_handle_unmapnotify, NULL);
XEV_QUICK(NULL, NULL, ConfigureRequest,
xev_handle_configurerequest, NULL);
XEV_QUICK(NULL, NULL, PropertyNotify, xev_handle_propertynotify, NULL);
XEV_QUICK(NULL, NULL, EnterNotify, xev_handle_enternotify, NULL);
XEV_QUICK(NULL, NULL, LeaveNotify, xev_handle_leavenotify, NULL);
XEV_QUICK(NULL, NULL, ButtonPress, xev_handle_buttonpress, NULL);
XEV_QUICK(NULL, NULL, ButtonRelease, xev_handle_buttonrelease, NULL);
XEV_QUICK(NULL, NULL, KeyPress, xev_handle_keypress, NULL);
XEV_QUICK(NULL, NULL, KeyRelease, xev_handle_keyrelease, NULL);
XEV_QUICK(NULL, NULL, Expose, xev_handle_expose, NULL);
XEV_QUICK(NULL, NULL, DestroyNotify, xev_handle_destroynotify, NULL);
XEV_QUICK(NULL, NULL, ClientMessage, xev_handle_clientmessage, NULL);
XEV_QUICK(NULL, NULL, MappingNotify, xev_handle_mapping, NULL);
xev_loop();
x_teardown();
return (0);
}
void
static void
dpy_init(const char *dpyname)
{
int i;
XSetErrorHandler(x_errorhandler);
if ((X_Dpy = XOpenDisplay(dpyname)) == NULL)
errx(1, "unable to open display \"%s\"",
XDisplayName(dpyname));
XSetErrorHandler(x_wmerrorhandler);
XSelectInput(X_Dpy, DefaultRootWindow(X_Dpy), SubstructureRedirectMask);
XSync(X_Dpy, False);
XSetErrorHandler(x_errorhandler);
HasRandr = XRRQueryExtension(X_Dpy, &Randr_ev, &i);
TAILQ_INIT(&Screenq);
}
void
static void
x_setup(void)
{
struct screen_ctx *sc;
struct keybinding *kb;
int i;
Cursor_default = XCreateFontCursor(X_Dpy, XC_X_cursor);
Cursor_move = XCreateFontCursor(X_Dpy, XC_fleur);
Cursor_normal = XCreateFontCursor(X_Dpy, XC_left_ptr);
Cursor_question = XCreateFontCursor(X_Dpy, XC_question_arrow);
Cursor_resize = XCreateFontCursor(X_Dpy, XC_bottom_right_corner);
for (i = 0; i < ScreenCount(X_Dpy); i++) {
XCALLOC(sc, struct screen_ctx);
sc = xcalloc(1, sizeof(*sc));
x_setupscreen(sc, i);
TAILQ_INSERT_TAIL(&Screenq, sc, entry);
}
@ -135,72 +138,53 @@ x_setup(void)
*/
TAILQ_FOREACH(kb, &Conf.keybindingq, entry)
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);
}
void
static void
x_teardown(void)
{
struct screen_ctx *sc;
TAILQ_FOREACH(sc, &Screenq, entry)
XFreeGC(X_Dpy, sc->gc);
XCloseDisplay(X_Dpy);
}
static void
x_setupscreen(struct screen_ctx *sc, u_int which)
{
XColor tmp;
XGCValues gv;
Window *wins, w0, w1;
XWindowAttributes winattr;
XSetWindowAttributes rootattr;
int fake;
u_int nwins, i;
Curscreen = sc;
sc->which = which;
sc->rootwin = RootWindow(X_Dpy, which);
sc->rootwin = RootWindow(X_Dpy, sc->which);
sc->xmax = DisplayWidth(X_Dpy, sc->which);
sc->ymax = DisplayHeight(X_Dpy, sc->which);
conf_gap(&Conf, sc);
screen_update_geometry(sc, DisplayWidth(X_Dpy, sc->which),
DisplayHeight(X_Dpy, sc->which));
XAllocNamedColor(X_Dpy, DefaultColormap(X_Dpy, which),
"black", &sc->fgcolor, &tmp);
XAllocNamedColor(X_Dpy, DefaultColormap(X_Dpy, which),
"#00cc00", &sc->bgcolor, &tmp);
XAllocNamedColor(X_Dpy,DefaultColormap(X_Dpy, which),
"blue", &sc->fccolor, &tmp);
XAllocNamedColor(X_Dpy, DefaultColormap(X_Dpy, which),
"red", &sc->redcolor, &tmp);
XAllocNamedColor(X_Dpy, DefaultColormap(X_Dpy, which),
"#666666", &sc->graycolor, &tmp);
XAllocNamedColor(X_Dpy, DefaultColormap(X_Dpy, which),
"white", &sc->whitecolor, &tmp);
XAllocNamedColor(X_Dpy, DefaultColormap(X_Dpy, which),
"black", &sc->blackcolor, &tmp);
conf_color(&Conf, sc);
sc->blackpixl = BlackPixel(X_Dpy, sc->which);
sc->whitepixl = WhitePixel(X_Dpy, sc->which);
sc->bluepixl = sc->fccolor.pixel;
sc->redpixl = sc->redcolor.pixel;
sc->graypixl = sc->graycolor.pixel;
gv.foreground = sc->blackpixl^sc->whitepixl;
gv.background = sc->whitepixl;
gv.function = GXxor;
gv.line_width = 1;
gv.subwindow_mode = IncludeInferiors;
sc->gc = XCreateGC(X_Dpy, sc->rootwin,
GCForeground|GCBackground|GCFunction|
GCLineWidth|GCSubwindowMode, &gv);
font_init(sc);
conf_font(&Conf);
group_init(sc);
conf_font(&Conf, sc);
TAILQ_INIT(&sc->mruq);
/* Initialize menu window. */
menu_init(sc);
xu_setwmname(sc);
rootattr.cursor = Cursor_normal;
rootattr.event_mask = CHILDMASK|PropertyChangeMask|EnterWindowMask|
LeaveWindowMask|ColormapChangeMask|BUTTONMASK;
XChangeWindowAttributes(X_Dpy, sc->rootwin,
CWEventMask|CWCursor, &rootattr);
/* Deal with existing clients. */
XQueryTree(X_Dpy, sc->rootwin, &w0, &w1, &wins, &nwins);
@ -209,17 +193,11 @@ x_setupscreen(struct screen_ctx *sc, u_int which)
if (winattr.override_redirect ||
winattr.map_state != IsViewable)
continue;
client_new(wins[i], sc, winattr.map_state != IsUnmapped);
(void)client_new(wins[i], sc, winattr.map_state != IsUnmapped);
}
XFree(wins);
screen_updatestackingorder();
rootattr.event_mask = ChildMask|PropertyChangeMask|EnterWindowMask|
LeaveWindowMask|ColormapChangeMask|ButtonMask;
XChangeWindowAttributes(X_Dpy, sc->rootwin,
CWEventMask, &rootattr);
screen_updatestackingorder(sc);
if (XineramaQueryExtension(X_Dpy, &fake, &fake) == 1 &&
((HasXinerama = XineramaIsActive(X_Dpy)) == 1))
@ -234,37 +212,33 @@ x_setupscreen(struct screen_ctx *sc, u_int which)
screen_init_xinerama(sc);
XSync(X_Dpy, False);
return;
}
int
static int
x_wmerrorhandler(Display *dpy, XErrorEvent *e)
{
errx(1, "root window unavailable - perhaps another wm is running?");
return (0);
}
static int
x_errorhandler(Display *dpy, XErrorEvent *e)
{
#ifdef DEBUG
{
char msg[80], number[80], req[80];
#if DEBUG
char msg[80], number[80], req[80];
XGetErrorText(X_Dpy, e->error_code, msg, sizeof(msg));
snprintf(number, sizeof(number), "%d", e->request_code);
XGetErrorDatabaseText(X_Dpy, "XRequest", number,
"<unknown>", req, sizeof(req));
XGetErrorText(X_Dpy, e->error_code, msg, sizeof(msg));
(void)snprintf(number, sizeof(number), "%d", e->request_code);
XGetErrorDatabaseText(X_Dpy, "XRequest", number,
"<unknown>", req, sizeof(req));
warnx("%s(0x%x): %s", req, (u_int)e->resourceid, msg);
}
warnx("%s(0x%x): %s", req, (u_int)e->resourceid, msg);
#endif
if (Starting &&
e->error_code == BadAccess &&
e->request_code == X_GrabKey)
errx(1, "root window unavailable - perhaps another "
"wm is running?");
return (0);
}
static void
_sigchld_cb(int which)
sigchld_cb(int which)
{
pid_t pid;
int save_errno = errno;
@ -283,6 +257,7 @@ usage(void)
{
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);
}

810
calmwm.h
View File

@ -15,193 +15,62 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id$
* $OpenBSD$
*/
#ifndef _CALMWM_H_
#define _CALMWM_H_
#define CALMWM_MAXNAMELEN 256
#include <X11/Xatom.h>
#include <X11/Xft/Xft.h>
#include <X11/Xlib.h>
#include <X11/Xproto.h>
#include <X11/Xutil.h>
#include <X11/cursorfont.h>
#include <X11/extensions/Xinerama.h>
#include <X11/extensions/Xrandr.h>
#include <X11/keysym.h>
#undef MIN
#undef MAX
#define MIN(x, y) ((x) < (y) ? (x) : (y))
#define MAX(x, y) ((x) > (y) ? (x) : (y))
#ifndef nitems
#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
#endif
#define CONFFILE ".cwmrc"
#define WMNAME "CWM"
#define ChildMask (SubstructureRedirectMask|SubstructureNotifyMask)
#define ButtonMask (ButtonPressMask|ButtonReleaseMask)
#define MouseMask (ButtonMask|PointerMotionMask)
#define CHILDMASK (SubstructureRedirectMask|SubstructureNotifyMask)
#define BUTTONMASK (ButtonPressMask|ButtonReleaseMask)
#define MOUSEMASK (BUTTONMASK|PointerMotionMask)
#define KEYMASK (KeyPressMask|ExposureMask)
#define MENUMASK (BUTTONMASK|ButtonMotionMask|ExposureMask| \
PointerMotionMask)
#define MENUGRABMASK (BUTTONMASK|ButtonMotionMask|StructureNotifyMask|\
PointerMotionMask)
#define SEARCHMASK (KeyPressMask|ExposureMask)
struct client_ctx;
/* kb movement */
#define CWM_MOVE 0x0001
#define CWM_RESIZE 0x0002
#define CWM_PTRMOVE 0x0004
#define CWM_BIGMOVE 0x0008
#define CWM_UP 0x0010
#define CWM_DOWN 0x0020
#define CWM_LEFT 0x0040
#define CWM_RIGHT 0x0080
TAILQ_HEAD(cycle_entry_q, client_ctx);
/* exec */
#define CWM_EXEC_PROGRAM 0x0001
#define CWM_EXEC_WM 0x0002
struct screen_ctx {
TAILQ_ENTRY(screen_ctx) entry;
u_int which;
Window rootwin;
Window menuwin;
Colormap colormap;
XColor bgcolor, fgcolor, fccolor, redcolor, graycolor,
whitecolor, blackcolor;
unsigned long blackpixl, whitepixl, redpixl, bluepixl, graypixl;
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_BLUE 1
#define CLIENT_HIGHLIGHT_RED 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);
/* NULL/0 values indicate match any. */
struct xevent {
TAILQ_ENTRY(xevent) entry;
Window *xev_win;
Window *xev_root;
int xev_type;
void (*xev_cb)(struct xevent *, XEvent *);
void *xev_arg;
};
TAILQ_HEAD(xevent_q, xevent);
#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
/* cycle */
#define CWM_CYCLE 0x0001
#define CWM_RCYCLE 0x0002
#define CWM_INGROUP 0x0004
#define KBTOGROUP(X) ((X) - 1)
@ -210,6 +79,149 @@ union arg {
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 {
TAILQ_ENTRY(keybinding) entry;
void (*callback)(struct client_ctx *, union arg *);
@ -217,33 +229,43 @@ struct keybinding {
int modmask;
int keysym;
int keycode;
#define KBFLAG_NEEDCLIENT 0x0001
int flags;
};
TAILQ_HEAD(keybinding_q, keybinding);
struct mousebinding {
TAILQ_ENTRY(mousebinding) entry;
void (*callback)(struct client_ctx *, void *);
int modmask;
int button;
#define MOUSEBIND_CTX_ROOT 0x0001
#define MOUSEBIND_CTX_WIN 0x0002
int context;
};
TAILQ_HEAD(mousebinding_q, mousebinding);
struct cmd {
TAILQ_ENTRY(cmd) entry;
int flags;
char image[MAXPATHLEN];
char label[256];
/* (argv) */
#define CMD_MAXLABELLEN 256
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(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 keybinding_q keybindingq;
struct autogroupwin_q autogroupq;
@ -251,280 +273,246 @@ struct conf {
char conf_path[MAXPATHLEN];
struct cmd_q cmdq;
struct mousebinding_q mousebindingq;
#define CONF_STICKY_GROUPS 0x0001
#define CONF_STICKY_GROUPS 0x0001
int flags;
#define CONF_BWIDTH 1
#define CONF_BWIDTH 1
int bwidth;
#define CONF_MAMOUNT 1
#define CONF_MAMOUNT 1
int mamount;
#define CONF_SNAPDIST 0
int snapdist;
struct gap gap;
struct color color[CWM_COLOR_MAX];
char termpath[MAXPATHLEN];
char lockpath[MAXPATHLEN];
#define DEFAULTFONTNAME "sans-serif:pixelsize=14:bold"
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
#define CONF_FONT "sans-serif:pixelsize=14:bold"
char *font;
};
/* MWM hints */
struct mwm_hints {
u_long flags;
u_long functions;
u_long decorations;
};
#define MWM_NUMHINTS 3
#define MWM_NUMHINTS 3
#define PROP_MWM_HINTS_ELEMENTS 3
#define MWM_HINTS_DECORATIONS (1 << 1)
#define MWM_DECOR_ALL (1 << 0)
#define MWM_DECOR_BORDER (1 << 1)
#define MWM_HINTS_DECORATIONS (1<<1)
#define MWM_DECOR_ALL (1<<0)
#define MWM_DECOR_BORDER (1<<1)
int input_keycodetrans(KeyCode, u_int, enum ctltype *,
char *);
int x_errorhandler(Display *, XErrorEvent *);
void x_setup(void);
void x_setupscreen(struct screen_ctx *, u_int);
__dead void usage(void);
struct client_ctx *client_find(Window);
void client_setup(void);
struct client_ctx *client_new(Window, struct screen_ctx *, int);
int client_delete(struct client_ctx *);
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 *);
void client_applysizehints(struct client_ctx *);
struct client_ctx *client_current(void);
void client_hide(struct client_ctx *);
void client_unhide(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_cycle(struct screen_ctx *, int);
void client_delete(struct client_ctx *);
void client_draw_border(struct client_ctx *);
void client_update(struct client_ctx *);
void client_placecalc(struct client_ctx *);
void client_maximize(struct client_ctx *);
void client_vertmaximize(struct client_ctx *);
struct client_ctx *client_find(Window);
void client_freeze(struct client_ctx *);
void client_getsizehints(struct client_ctx *);
void client_hide(struct client_ctx *);
void client_horizmaximize(struct client_ctx *);
void client_leave(struct client_ctx *);
void client_lower(struct client_ctx *);
void client_map(struct client_ctx *);
void client_maximize(struct client_ctx *);
void client_move(struct client_ctx *);
void client_mtf(struct client_ctx *);
struct client_ctx *client_cycle(int);
struct client_ctx *client_mrunext(struct client_ctx *);
struct client_ctx *client_mruprev(struct client_ctx *);
void client_gethints(struct client_ctx *);
void client_freehints(struct client_ctx *);
struct client_ctx *client_new(Window, struct screen_ctx *, int);
void client_ptrsave(struct client_ctx *);
void client_ptrwarp(struct client_ctx *);
void client_raise(struct client_ctx *);
void client_resize(struct client_ctx *);
void client_send_delete(struct client_ctx *);
void client_setactive(struct client_ctx *, int);
void client_setname(struct client_ctx *);
int client_snapcalc(int, int, int, int, int);
void client_transient(struct client_ctx *);
void client_unhide(struct client_ctx *);
void client_vertmaximize(struct client_ctx *);
void client_warp(struct client_ctx *);
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 *, int));
void menu_init(struct screen_ctx *);
void xev_handle_maprequest(struct xevent *, XEvent *);
void xev_handle_unmapnotify(struct xevent *, XEvent *);
void xev_handle_destroynotify(struct xevent *, XEvent *);
void xev_handle_configurerequest(struct xevent *, XEvent *);
void xev_handle_propertynotify(struct xevent *, XEvent *);
void xev_handle_enternotify(struct xevent *, XEvent *);
void xev_handle_leavenotify(struct xevent *, XEvent *);
void xev_handle_buttonpress(struct xevent *, XEvent *);
void xev_handle_buttonrelease(struct xevent *, XEvent *);
void xev_handle_keypress(struct xevent *, XEvent *);
void xev_handle_keyrelease(struct xevent *, XEvent *);
void xev_handle_expose(struct xevent *, XEvent *);
void xev_handle_clientmessage(struct xevent *, XEvent *);
void xev_handle_randr(struct xevent *, XEvent *);
void xev_handle_mapping(struct xevent *, XEvent *);
#define XEV_QUICK(a, b, c, d, e) do { \
xev_register(xev_new(a, b, c, d, e)); \
} while (0)
/* XXX should be xu_ */
void xev_reconfig(struct client_ctx *);
void xev_init(void);
struct xevent *xev_new(Window *, Window *, int,
void (*)(struct xevent *, XEvent *), void *);
void xev_register(struct xevent *);
void xev_loop(void);
void xu_getatoms(void);
int xu_ptr_grab(Window, int, Cursor);
void xu_btn_grab(Window, int, u_int);
int xu_ptr_regrab(int, Cursor);
void xu_btn_ungrab(Window, int, u_int);
void xu_ptr_ungrab(void);
void xu_ptr_setpos(Window, int, int);
void xu_ptr_getpos(Window, int *, int *);
void xu_key_grab(Window, int, int);
void xu_key_ungrab(Window, int, int);
void xu_sendmsg(struct client_ctx *, Atom, long);
int xu_getprop(struct client_ctx *, Atom, Atom, long,
u_char **);
char *xu_getstrprop(struct client_ctx *, Atom atm);
void xu_setstate(struct client_ctx *, int);
int xu_getstate(struct client_ctx *, int *);
int u_spawn(char *);
void u_exec(char *);
void xfree(void *);
void *xmalloc(size_t);
void *xcalloc(size_t, size_t);
char *xstrdup(const char *);
#define XMALLOC(p, t) ((p) = (t *)xmalloc(sizeof * (p)))
#define XCALLOC(p, t) ((p) = (t *)xcalloc(1, sizeof * (p)))
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_unbind(struct conf *, struct keybinding *);
void conf_mousebind(struct conf *, char *, char *);
void conf_mouseunbind(struct conf *, struct mousebinding *);
void conf_grab_mouse(struct client_ctx *);
void conf_reload(struct conf *);
void conf_font(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_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_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 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 *);
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_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 font_init(struct screen_ctx *);
int font_width(const char *, int);
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 *);
#define font_ascent() Conf.DefaultFont->ascent
#define font_descent() Conf.DefaultFont->descent
#define font_height() Conf.FontHeight
void xev_loop(void);
#define CCTOSC(cc) (cc->sc)
void xu_btn_grab(Window, int, u_int);
void xu_btn_ungrab(Window, int, u_int);
void xu_configure(struct client_ctx *);
void xu_freecolor(struct screen_ctx *, unsigned long);
void xu_getatoms(void);
unsigned long xu_getcolor(struct screen_ctx *, char *);
int xu_getprop(Window, Atom, Atom, long, u_char **);
int xu_getstate(struct client_ctx *, int *);
int xu_getstrprop(Window, Atom, char **);
void xu_key_grab(Window, int, int);
void xu_key_ungrab(Window, int, int);
void xu_ptr_getpos(Window, int *, int *);
int xu_ptr_grab(Window, int, Cursor);
int xu_ptr_regrab(int, Cursor);
void xu_ptr_setpos(Window, int, int);
void xu_ptr_ungrab(void);
void xu_sendmsg(Window, Atom, long);
void xu_setstate(struct client_ctx *, int);
void xu_setwmname(struct screen_ctx *);
void u_exec(char *);
void u_spawn(char *);
void *xcalloc(size_t, size_t);
void xfree(void *);
void *xmalloc(size_t);
char *xstrdup(const char *);
/* Externs */
extern Display *X_Dpy;
extern Cursor Cursor_move;
extern Cursor Cursor_resize;
extern Cursor Cursor_select;
extern Cursor Cursor_default;
extern Cursor Cursor_move;
extern Cursor Cursor_normal;
extern Cursor Cursor_question;
extern Cursor Cursor_resize;
extern struct screen_ctx_q Screenq;
extern struct screen_ctx *curscreen;
extern struct client_ctx_q Clientq;
extern struct conf Conf;
extern int HasXinerama, HasRandr, Randr_ev;
extern struct conf Conf;
#define WM_STATE cwm_atoms[0]
#define WM_DELETE_WINDOW cwm_atoms[1]
#define WM_TAKE_FOCUS cwm_atoms[2]
#define WM_PROTOCOLS cwm_atoms[3]
#define _MOTIF_WM_HINTS cwm_atoms[4]
#define _CWM_GRP cwm_atoms[5]
#define CWM_NO_ATOMS 6
#define UTF8_STRING cwm_atoms[5]
/*
* please make all hints below this point netwm hints, starting with
* _NET_SUPPORTED. If you change other hints make sure you update
* CWM_NETWM_START
*/
#define _NET_SUPPORTED cwm_atoms[6]
#define _NET_SUPPORTING_WM_CHECK cwm_atoms[7]
#define _NET_WM_NAME cwm_atoms[8]
#define _NET_ACTIVE_WINDOW cwm_atoms[9]
#define _NET_CLIENT_LIST cwm_atoms[10]
#define _NET_NUMBER_OF_DESKTOPS cwm_atoms[11]
#define _NET_CURRENT_DESKTOP cwm_atoms[12]
#define _NET_DESKTOP_VIEWPORT cwm_atoms[13]
#define _NET_DESKTOP_GEOMETRY cwm_atoms[14]
#define _NET_VIRTUAL_ROOTS cwm_atoms[15]
#define _NET_SHOWING_DESKTOP cwm_atoms[16]
#define _NET_DESKTOP_NAMES cwm_atoms[17]
#define _NET_WM_DESKTOP cwm_atoms[18]
#define _NET_WORKAREA cwm_atoms[19]
#define CWM_NO_ATOMS 20
#define CWM_NETWM_START 6
extern Atom cwm_atoms[CWM_NO_ATOMS];

593
client.c
View File

@ -15,23 +15,34 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* 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"
static int _client_inbound(struct client_ctx *, int, int);
static struct client_ctx *client_mrunext(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_update(struct client_ctx *);
static void client_gethints(struct client_ctx *);
static void client_freehints(struct client_ctx *);
static int client_inbound(struct client_ctx *, int, int);
static char emptystring[] = "";
struct client_ctx *_curcc = NULL;
void
client_setup(void)
{
TAILQ_INIT(&Clientq);
}
struct client_ctx *
client_find(Window win)
{
@ -50,13 +61,12 @@ client_new(Window win, struct screen_ctx *sc, int mapped)
struct client_ctx *cc;
XWindowAttributes wattr;
XWMHints *wmhints;
long tmp;
int state;
if (win == None)
return (NULL);
XCALLOC(cc, struct client_ctx);
cc = xcalloc(1, sizeof(*cc));
XGrabServer(X_Dpy);
@ -64,34 +74,19 @@ client_new(Window win, struct screen_ctx *sc, int mapped)
cc->sc = sc;
cc->win = win;
cc->size = XAllocSizeHints();
XGetWMNormalHints(X_Dpy, cc->win, cc->size, &tmp);
if (cc->size->width_inc == 0)
cc->size->width_inc = 1;
if (cc->size->height_inc == 0)
cc->size->height_inc = 1;
client_getsizehints(cc);
TAILQ_INIT(&cc->nameq);
client_setname(cc);
/*
* conf_client() needs at least cc->win and cc->name
*/
conf_client(cc);
XGetWindowAttributes(X_Dpy, cc->win, &wattr);
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;
}
/* Saved pointer position */
cc->ptr.x = -1;
cc->ptr.y = -1;
XGetWindowAttributes(X_Dpy, cc->win, &wattr);
cc->geom.x = wattr.x;
cc->geom.y = wattr.y;
cc->geom.width = wattr.width;
@ -118,14 +113,12 @@ client_new(Window win, struct screen_ctx *sc, int mapped)
XAddToSaveSet(X_Dpy, cc->win);
client_transient(cc);
/* Notify client of its configuration. */
xev_reconfig(cc);
if (state == IconicState)
client_hide(cc);
else
client_unhide(cc);
xu_configure(cc);
(state == IconicState) ? client_hide(cc) : client_unhide(cc);
xu_setstate(cc, cc->state);
XSync(X_Dpy, False);
@ -133,6 +126,9 @@ client_new(Window win, struct screen_ctx *sc, int mapped)
TAILQ_INSERT_TAIL(&sc->mruq, cc, mru_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_update(cc);
@ -143,11 +139,14 @@ client_new(Window win, struct screen_ctx *sc, int mapped)
return (cc);
}
int
void
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;
Window *winlist;
int i, j;
group_client_delete(cc);
@ -160,24 +159,38 @@ client_delete(struct client_ctx *cc)
TAILQ_REMOVE(&sc->mruq, cc, mru_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)
_curcc = NULL;
client_none(sc);
XFree(cc->size);
while ((wn = TAILQ_FIRST(&cc->nameq)) != NULL) {
TAILQ_REMOVE(&cc->nameq, wn, entry);
if (wn->name != emptystring)
XFree(wn->name);
xfree(wn->name);
xfree(wn);
}
client_freehints(cc);
xfree(cc);
return (0);
}
void
@ -190,7 +203,7 @@ client_leave(struct client_ctx *cc)
if (cc == NULL)
return;
sc = CCTOSC(cc);
sc = cc->sc;
xu_btn_ungrab(sc->rootwin, AnyModifier, Button1);
}
@ -204,7 +217,7 @@ client_setactive(struct client_ctx *cc, int fg)
if (cc == NULL)
return;
sc = CCTOSC(cc);
sc = cc->sc;
if (fg) {
XInstallColormap(X_Dpy, cc->cmap);
@ -223,113 +236,210 @@ client_setactive(struct client_ctx *cc, int fg)
if (fg && _curcc != cc) {
client_setactive(NULL, 0);
_curcc = cc;
XChangeProperty(X_Dpy, sc->rootwin, _NET_ACTIVE_WINDOW,
XA_WINDOW, 32, PropModeReplace,
(unsigned char *)&cc->win, 1);
}
cc->active = fg;
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 *
client_current(void)
{
return (_curcc);
}
void
client_freeze(struct client_ctx *cc)
{
if (cc->flags & CLIENT_FREEZE)
cc->flags &= ~CLIENT_FREEZE;
else
cc->flags |= CLIENT_FREEZE;
}
void
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 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;
} else {
if (!(cc->flags & CLIENT_VMAXIMIZED))
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;
cc->bwidth = Conf.bwidth;
goto resize;
}
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);
}
void
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;
if (cc->flags & CLIENT_FREEZE)
return;
if (cc->flags & CLIENT_VMAXIMIZED) {
cc->geom = cc->savegeom;
} else {
if (!(cc->flags & CLIENT_MAXIMIZED))
cc->savegeom = cc->geom;
if (HasXinerama) {
XineramaScreenInfo *xine;
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;
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->geom.y = cc->savegeom.y;
cc->geom.height = cc->savegeom.height;
cc->bwidth = Conf.bwidth;
if (cc->flags & CLIENT_HMAXIMIZED)
cc->geom.width -= cc->bwidth * 2;
cc->flags &= ~CLIENT_VMAXIMIZED;
goto resize;
}
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);
}
void
client_resize(struct client_ctx *cc)
{
if (cc->flags & (CLIENT_MAXIMIZED | CLIENT_VMAXIMIZED))
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;
}
client_draw_border(cc);
XMoveResizeWindow(X_Dpy, cc->win, cc->geom.x,
cc->geom.y, cc->geom.width, cc->geom.height);
xev_reconfig(cc);
xu_configure(cc);
}
void
client_move(struct client_ctx *cc)
{
XMoveWindow(X_Dpy, cc->win, cc->geom.x, cc->geom.y);
xev_reconfig(cc);
xu_configure(cc);
}
void
@ -354,11 +464,7 @@ client_ptrwarp(struct client_ctx *cc)
y = cc->geom.height / 2;
}
if (cc->state == IconicState)
client_unhide(cc);
else
client_raise(cc);
(cc->state == IconicState) ? client_unhide(cc) : client_raise(cc);
xu_ptr_setpos(cc->win, x, y);
}
@ -368,9 +474,12 @@ client_ptrsave(struct client_ctx *cc)
int x, y;
xu_ptr_getpos(cc->win, &x, &y);
if (_client_inbound(cc, x, y)) {
if (client_inbound(cc, x, y)) {
cc->ptr.x = x;
cc->ptr.y = y;
} else {
cc->ptr.x = -1;
cc->ptr.y = -1;
}
}
@ -385,7 +494,7 @@ client_hide(struct client_ctx *cc)
xu_setstate(cc, IconicState);
if (cc == _curcc)
_curcc = NULL;
client_none(cc->sc);
}
void
@ -396,41 +505,42 @@ client_unhide(struct client_ctx *cc)
cc->highlight = 0;
cc->flags &= ~CLIENT_HIDDEN;
xu_setstate(cc, NormalState);
client_draw_border(cc);
}
void
client_draw_border(struct client_ctx *cc)
{
struct screen_ctx *sc = CCTOSC(cc);
u_long pixl;
struct screen_ctx *sc = cc->sc;
unsigned long pixel;
if (cc->active)
switch (cc->highlight) {
case CLIENT_HIGHLIGHT_BLUE:
pixl = sc->bluepixl;
case CLIENT_HIGHLIGHT_GROUP:
pixel = sc->color[CWM_COLOR_BORDER_GROUP].pixel;
break;
case CLIENT_HIGHLIGHT_RED:
pixl = sc->redpixl;
case CLIENT_HIGHLIGHT_UNGROUP:
pixel = sc->color[CWM_COLOR_BORDER_UNGROUP].pixel;
break;
default:
pixl = sc->whitepixl;
pixel = sc->color[CWM_COLOR_BORDER_ACTIVE].pixel;
break;
}
else
pixl = sc->graypixl;
pixel = sc->color[CWM_COLOR_BORDER_INACTIVE].pixel;
XSetWindowBorderWidth(X_Dpy, cc->win, cc->bwidth);
XSetWindowBorder(X_Dpy, cc->win, pixl);
XSetWindowBorder(X_Dpy, cc->win, pixel);
}
void
static void
client_update(struct client_ctx *cc)
{
Atom *p;
Atom *p;
int i;
long n;
if ((n = xu_getprop(cc, WM_PROTOCOLS,
if ((n = xu_getprop(cc->win, WM_PROTOCOLS,
XA_ATOM, 20L, (u_char **)&p)) <= 0)
return;
@ -446,9 +556,8 @@ client_update(struct client_ctx *cc)
void
client_send_delete(struct client_ctx *cc)
{
if (cc->xproto & CLIENT_PROTO_DELETE)
xu_sendmsg(cc, WM_PROTOCOLS, WM_DELETE_WINDOW);
xu_sendmsg(cc->win, WM_PROTOCOLS, WM_DELETE_WINDOW);
else
XKillClient(X_Dpy, cc->win);
}
@ -459,9 +568,9 @@ client_setname(struct client_ctx *cc)
struct winname *wn;
char *newname;
XFetchName(X_Dpy, cc->win, &newname);
if (newname == NULL)
newname = emptystring;
if (!xu_getstrprop(cc->win, _NET_WM_NAME, &newname))
if (!xu_getstrprop(cc->win, XA_WM_NAME, &newname))
newname = emptystring;
TAILQ_FOREACH(wn, &cc->nameq, entry)
if (strcmp(wn->name, newname) == 0) {
@ -471,7 +580,7 @@ client_setname(struct client_ctx *cc)
goto match;
}
XMALLOC(wn, struct winname);
wn = xmalloc(sizeof(*wn));
wn->name = newname;
TAILQ_INSERT_TAIL(&cc->nameq, wn, entry);
cc->nameqlen++;
@ -485,47 +594,44 @@ match:
assert(wn != NULL);
TAILQ_REMOVE(&cc->nameq, wn, entry);
if (wn->name != emptystring)
XFree(wn->name);
xfree(wn->name);
xfree(wn);
cc->nameqlen--;
}
return;
}
struct client_ctx *
client_cycle(int reverse)
void
client_cycle(struct screen_ctx *sc, int flags)
{
struct client_ctx *oldcc, *newcc;
struct screen_ctx *sc;
int again = 1;
oldcc = client_current();
sc = screen_current();
/* If no windows then you cant cycle */
if (TAILQ_EMPTY(&sc->mruq))
return (NULL);
return;
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));
newcc = oldcc;
while (again) {
again = 0;
newcc = (reverse ? client_mruprev(newcc) :
newcc = (flags & CWM_RCYCLE ? client_mruprev(newcc) :
client_mrunext(newcc));
/* 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;
/* Is oldcc the only non-hidden window? */
if (newcc == oldcc) {
if (again)
return (NULL); /* No windows visible. */
return; /* No windows visible. */
break;
}
@ -535,37 +641,35 @@ client_cycle(int reverse)
sc->altpersist = 1;
client_ptrsave(oldcc);
client_ptrwarp(newcc);
return (newcc);
}
struct client_ctx *
static struct client_ctx *
client_mrunext(struct client_ctx *cc)
{
struct screen_ctx *sc = CCTOSC(cc);
struct screen_ctx *sc = cc->sc;
struct client_ctx *ccc;
return ((ccc = TAILQ_NEXT(cc, mru_entry)) != NULL ?
ccc : TAILQ_FIRST(&sc->mruq));
}
struct client_ctx *
static struct client_ctx *
client_mruprev(struct client_ctx *cc)
{
struct screen_ctx *sc = CCTOSC(cc);
struct screen_ctx *sc = cc->sc;
struct client_ctx *ccc;
return ((ccc = TAILQ_PREV(cc, cycle_entry_q, mru_entry)) != NULL ?
ccc : TAILQ_LAST(&sc->mruq, cycle_entry_q));
}
void
static void
client_placecalc(struct client_ctx *cc)
{
struct screen_ctx *sc = CCTOSC(cc);
struct screen_ctx *sc = cc->sc;
int xslack, yslack;
if (cc->size->flags & USPosition) {
if (cc->size->flags & (USPosition|PPosition)) {
/*
* Ignore XINERAMA screens, just make sure it's somewhere
* in the virtual desktop. else it stops people putting xterms
@ -610,21 +714,21 @@ noxine:
if (xslack >= xorig) {
cc->geom.x = MAX(MIN(xmouse, xslack),
xorig + Conf.gap_left);
if (cc->geom.x > (xslack - Conf.gap_right))
cc->geom.x -= Conf.gap_right;
xorig + sc->gap.left);
if (cc->geom.x > (xslack - sc->gap.right))
cc->geom.x -= sc->gap.right;
} else {
cc->geom.x = xorig + Conf.gap_left;
cc->geom.width = xmax - Conf.gap_left;
cc->geom.x = xorig + sc->gap.left;
cc->geom.width = xmax - sc->gap.left;
}
if (yslack >= yorig) {
cc->geom.y = MAX(MIN(ymouse, yslack),
yorig + Conf.gap_top);
if (cc->geom.y > (yslack - Conf.gap_bottom))
cc->geom.y -= Conf.gap_bottom;
yorig + sc->gap.top);
if (cc->geom.y > (yslack - sc->gap.bottom))
cc->geom.y -= sc->gap.bottom;
} else {
cc->geom.y = yorig + Conf.gap_top;
cc->geom.height = ymax - Conf.gap_top;
cc->geom.y = yorig + sc->gap.top;
cc->geom.height = ymax - sc->gap.top;
}
}
}
@ -639,7 +743,7 @@ client_mtf(struct client_ctx *cc)
if (cc == NULL)
return;
sc = CCTOSC(cc);
sc = cc->sc;
/* Move to front. */
TAILQ_REMOVE(&sc->mruq, cc, mru_entry);
@ -647,11 +751,100 @@ client_mtf(struct client_ctx *cc)
}
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
client_gethints(struct client_ctx *cc)
{
XClassHint xch;
int argc;
char **argv;
struct mwm_hints *mwmh;
if (XGetClassHint(X_Dpy, cc->win, &xch)) {
@ -661,50 +854,70 @@ client_gethints(struct client_ctx *cc)
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)
if (mwmh->flags & MWM_HINTS_DECORATIONS &&
!(mwmh->decorations & MWM_DECOR_ALL) &&
!(mwmh->decorations & MWM_DECOR_BORDER))
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);
}
}
void
static void
client_freehints(struct client_ctx *cc)
{
if (cc->app_name != NULL)
XFree(cc->app_name);
if (cc->app_class != NULL)
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
_client_inbound(struct client_ctx *cc, int x, int y)
client_inbound(struct client_ctx *cc, int x, int y)
{
return (x < cc->geom.width && x >= 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;
}

423
conf.c
View File

@ -15,20 +15,24 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* 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/stat.h>
#include <err.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "calmwm.h"
#ifndef timespeccmp
#define timespeccmp(tsp, usp, cmp) \
(((tsp)->tv_sec == (usp)->tv_sec) ? \
((tsp)->tv_nsec cmp (usp)->tv_nsec) : \
((tsp)->tv_sec cmp (usp)->tv_sec))
#endif
extern struct screen_ctx *Curscreen;
static void conf_mouseunbind(struct conf *, struct mousebinding *);
static void conf_unbind(struct conf *, struct keybinding *);
/* Add an command menu entry to the end of the menu */
void
@ -37,47 +41,155 @@ conf_cmd_add(struct conf *c, char *image, char *label, int flags)
/* "term" and "lock" have special meanings. */
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)
strlcpy(c->lockpath, image, sizeof(c->lockpath));
(void)strlcpy(c->lockpath, image, sizeof(c->lockpath));
else {
struct cmd *cmd;
XMALLOC(cmd, struct cmd);
struct cmd *cmd = xmalloc(sizeof(*cmd));
cmd->flags = flags;
strlcpy(cmd->image, image, sizeof(cmd->image));
strlcpy(cmd->label, label, sizeof(cmd->label));
(void)strlcpy(cmd->image, image, sizeof(cmd->image));
(void)strlcpy(cmd->label, label, sizeof(cmd->label));
TAILQ_INSERT_TAIL(&c->cmdq, cmd, entry);
}
}
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();
void
conf_font(struct conf *c, struct screen_ctx *sc)
{
font_init(sc, c->color[CWM_COLOR_FONT].name);
sc->font = font_make(sc, c->font);
}
c->DefaultFont = font_make(sc, Conf.DefaultFontName);
c->FontHeight = font_ascent() + font_descent() + 1;
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++) {
xu_freecolor(sc, sc->color[i].pixel);
sc->color[i].pixel = xu_getcolor(sc, c->color[i].name);
}
}
void
conf_reload(struct conf *c)
{
struct screen_ctx *sc;
struct client_ctx *cc;
if (parse_config(c->conf_path, c) == -1) {
warnx("config file %s has errors, not reloading", c->conf_path);
return;
}
conf_font(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)
client_draw_border(cc);
}
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
conf_init(struct conf *c)
{
int i;
c->flags = 0;
c->bwidth = CONF_BWIDTH;
c->mamount = CONF_MAMOUNT;
c->snapdist = CONF_SNAPDIST;
TAILQ_INIT(&c->ignoreq);
TAILQ_INIT(&c->cmdq);
@ -85,79 +197,20 @@ conf_init(struct conf *c)
TAILQ_INIT(&c->autogroupq);
TAILQ_INIT(&c->mousebindingq);
conf_bindname(c, "CM-Return", "terminal");
conf_bindname(c, "CM-Delete", "lock");
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");
for (i = 0; i < nitems(kb_binds); i++)
conf_bindname(c, kb_binds[i].key, kb_binds[i].func);
conf_bindname(c, "M-h", "moveleft");
conf_bindname(c, "M-j", "movedown");
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");
for (i = 0; i < nitems(m_binds); i++)
conf_mousebind(c, m_binds[i].key, m_binds[i].func);
conf_bindname(c, "CM-h", "resizeleft");
conf_bindname(c, "CM-j", "resizedown");
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");
for (i = 0; i < nitems(color_binds); i++)
c->color[i].name = xstrdup(color_binds[i].name);
/* Default term/lock */
strlcpy(c->termpath, "xterm", sizeof(c->termpath));
strlcpy(c->lockpath, "xlock", sizeof(c->lockpath));
(void)strlcpy(c->termpath, "xterm", sizeof(c->termpath));
(void)strlcpy(c->lockpath, "xlock", sizeof(c->lockpath));
c->DefaultFontName = xstrdup(DEFAULTFONTNAME);
c->font = xstrdup(CONF_FONT);
}
void
@ -168,6 +221,7 @@ conf_clear(struct conf *c)
struct winmatch *wm;
struct cmd *cmd;
struct mousebinding *mb;
int i;
while ((cmd = TAILQ_FIRST(&c->cmdq)) != NULL) {
TAILQ_REMOVE(&c->cmdq, cmd, entry);
@ -184,7 +238,6 @@ conf_clear(struct conf *c)
xfree(ag->class);
if (ag->name)
xfree(ag->name);
xfree(ag->group);
xfree(ag);
}
@ -198,31 +251,42 @@ conf_clear(struct conf *c)
xfree(mb);
}
xfree(c->DefaultFontName);
for (i = 0; i < CWM_COLOR_MAX; i++)
xfree(c->color[i].name);
xfree(c->font);
}
void
conf_setup(struct conf *c, const char *conf_file)
{
char *home;
struct stat sb;
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));
int parse = 0;
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
@ -232,23 +296,18 @@ conf_client(struct client_ctx *cc)
char *wname = cc->name;
int ignore = 0;
/* Can wname be NULL? */
if (wname != NULL) {
TAILQ_FOREACH(wm, &Conf.ignoreq, entry) {
if (strncasecmp(wm->title, wname, strlen(wm->title))
== 0) {
ignore = 1;
break;
}
TAILQ_FOREACH(wm, &Conf.ignoreq, entry) {
if (strncasecmp(wm->title, wname, strlen(wm->title)) == 0) {
ignore = 1;
break;
}
} else
ignore = 1;
}
cc->bwidth = ignore ? 0 : Conf.bwidth;
cc->flags |= ignore ? CLIENT_IGNORE : 0;
}
struct {
static struct {
char *tag;
void (*handler)(struct client_ctx *, union arg *);
int flags;
@ -272,12 +331,43 @@ struct {
{ "group7", kbfunc_client_group, 0, {.i = 7} },
{ "group8", kbfunc_client_group, 0, {.i = 8} },
{ "group9", kbfunc_client_group, 0, {.i = 9} },
{ "grouponly1", kbfunc_client_grouponly, 0, {.i = 1} },
{ "grouponly2", kbfunc_client_grouponly, 0, {.i = 2} },
{ "grouponly3", kbfunc_client_grouponly, 0, {.i = 3} },
{ "grouponly4", kbfunc_client_grouponly, 0, {.i = 4} },
{ "grouponly5", kbfunc_client_grouponly, 0, {.i = 5} },
{ "grouponly6", kbfunc_client_grouponly, 0, {.i = 6} },
{ "grouponly7", kbfunc_client_grouponly, 0, {.i = 7} },
{ "grouponly8", kbfunc_client_grouponly, 0, {.i = 8} },
{ "grouponly9", kbfunc_client_grouponly, 0, {.i = 9} },
{ "movetogroup1", kbfunc_client_movetogroup, KBFLAG_NEEDCLIENT,
{.i = 1} },
{ "movetogroup2", kbfunc_client_movetogroup, KBFLAG_NEEDCLIENT,
{.i = 2} },
{ "movetogroup3", kbfunc_client_movetogroup, KBFLAG_NEEDCLIENT,
{.i = 3} },
{ "movetogroup4", kbfunc_client_movetogroup, KBFLAG_NEEDCLIENT,
{.i = 4} },
{ "movetogroup5", kbfunc_client_movetogroup, KBFLAG_NEEDCLIENT,
{.i = 5} },
{ "movetogroup6", kbfunc_client_movetogroup, KBFLAG_NEEDCLIENT,
{.i = 6} },
{ "movetogroup7", kbfunc_client_movetogroup, KBFLAG_NEEDCLIENT,
{.i = 7} },
{ "movetogroup8", kbfunc_client_movetogroup, KBFLAG_NEEDCLIENT,
{.i = 8} },
{ "movetogroup9", kbfunc_client_movetogroup, KBFLAG_NEEDCLIENT,
{.i = 9} },
{ "nogroup", kbfunc_client_nogroup, 0, {0} },
{ "cyclegroup", kbfunc_client_cyclegroup, 0, {.i = CWM_CYCLEGROUP} },
{ "rcyclegroup", kbfunc_client_cyclegroup, 0, {.i = CWM_RCYCLEGROUP} },
{ "cyclegroup", kbfunc_client_cyclegroup, 0, {.i = CWM_CYCLE} },
{ "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}},
{ "maximize", kbfunc_client_maximize, 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} },
{ "quit", kbfunc_quit_wm, 0, {0} },
{ "exec", kbfunc_exec, 0, {.i = CWM_EXEC_PROGRAM} },
@ -330,7 +420,6 @@ struct {
{.i = (CWM_LEFT|CWM_PTRMOVE|CWM_BIGMOVE)} },
{ "bigptrmoveright", kbfunc_moveresize, 0,
{.i = (CWM_RIGHT|CWM_PTRMOVE|CWM_BIGMOVE)} },
{ NULL, NULL, 0, {0}},
};
/*
@ -349,7 +438,6 @@ conf_grab(struct conf *c, struct keybinding *kb)
TAILQ_FOREACH(sc, &Screenq, entry)
xu_key_grab(sc->rootwin, kb->modmask, kb->keysym);
}
/*
@ -365,36 +453,39 @@ conf_ungrab(struct conf *c, struct keybinding *kb)
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
conf_bindname(struct conf *c, char *name, char *binding)
{
struct keybinding *current_binding;
char *substring;
char *substring, *tmp;
int iter;
XCALLOC(current_binding, struct keybinding);
current_binding = xcalloc(1, sizeof(*current_binding));
if (strchr(name, 'C') != NULL &&
strchr(name, 'C') < strchr(name, '-'))
current_binding->modmask |= ControlMask;
if ((substring = strchr(name, '-')) != NULL) {
for (iter = 0; iter < nitems(bind_mods); iter++) {
if ((tmp = strchr(name, bind_mods[iter].chr)) !=
NULL && tmp < substring) {
current_binding->modmask |=
bind_mods[iter].mask;
}
}
if (strchr(name, 'M') != NULL &&
strchr(name, 'M') < strchr(name, '-'))
current_binding->modmask |= Mod1Mask;
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)
/* skip past the modifiers */
substring++;
} else {
substring = name;
}
if (substring[0] == '[' &&
substring[strlen(substring)-1] == ']') {
@ -417,7 +508,7 @@ conf_bindname(struct conf *c, char *name, char *binding)
if (strcmp("unmap", binding) == 0)
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)
continue;
@ -434,10 +525,9 @@ conf_bindname(struct conf *c, char *name, char *binding)
current_binding->flags = 0;
conf_grab(c, current_binding);
TAILQ_INSERT_TAIL(&c->keybindingq, current_binding, entry);
return;
}
void
static void
conf_unbind(struct conf *c, struct keybinding *unbind)
{
struct keybinding *key = NULL, *keynxt;
@ -459,7 +549,7 @@ conf_unbind(struct conf *c, struct keybinding *unbind)
}
}
struct {
static struct {
char *tag;
void (*handler)(struct client_ctx *, void *);
int context;
@ -469,42 +559,35 @@ struct {
{ "window_grouptoggle", mousefunc_window_grouptoggle,
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 },
{ "menu_group", mousefunc_menu_group, MOUSEBIND_CTX_ROOT },
{ "menu_unhide", mousefunc_menu_unhide, MOUSEBIND_CTX_ROOT },
{ "menu_cmd", mousefunc_menu_cmd, MOUSEBIND_CTX_ROOT },
{ NULL, NULL, 0 },
};
void
conf_mousebind(struct conf *c, char *name, char *binding)
{
struct mousebinding *current_binding;
char *substring;
char *substring, *tmp;
const char *errstr;
int iter;
XCALLOC(current_binding, struct mousebinding);
current_binding = xcalloc(1, sizeof(*current_binding));
if (strchr(name, 'C') != NULL &&
strchr(name, 'C') < strchr(name, '-'))
current_binding->modmask |= ControlMask;
if ((substring = strchr(name, '-')) != NULL) {
for (iter = 0; iter < nitems(bind_mods); iter++) {
if ((tmp = strchr(name, bind_mods[iter].chr)) !=
NULL && tmp < substring) {
current_binding->modmask |=
bind_mods[iter].mask;
}
}
if (strchr(name, 'M') != NULL &&
strchr(name, 'M') < strchr(name, '-'))
current_binding->modmask |= Mod1Mask;
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)
/* skip past the modifiers */
substring++;
} else
substring = name;
current_binding->button = strtonum(substring, 1, 3, &errstr);
@ -516,7 +599,7 @@ conf_mousebind(struct conf *c, char *name, char *binding)
if (strcmp("unmap", binding) == 0)
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)
continue;
@ -527,7 +610,7 @@ conf_mousebind(struct conf *c, char *name, char *binding)
}
}
void
static void
conf_mouseunbind(struct conf *c, struct mousebinding *unbind)
{
struct mousebinding *mb = NULL, *mbnxt;

114
cwm.1
View File

@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: September 22 2008 $
.Dd $Mdocdate: September 25 2010 $
.Dt CWM 1
.Os
.Sh NAME
@ -36,29 +36,29 @@ The following notation is used throughout this page:
.Pp
.Bl -tag -width Ds -offset indent -compact
.It Ic C
Control
Control.
.It Ic M
Meta
Meta.
.It Ic S
Shift
Shift.
.It Ic M1
Left mouse button
Left mouse button.
.It Ic M2
Middle mouse button
Middle mouse button.
.It Ic M3
Right mouse button
Right mouse button.
.El
.Pp
.Nm
is very simple in its use.
Most of the actions are initiated via keybindings.
The current keybindings are described below;
Most of the actions are initiated via key bindings.
The current key bindings are described below;
their functionality is described in more detail later.
.Pp
.Bl -tag -width "C-M-EscapeXXX" -offset indent -compact
.It Ic C-M-Return
.Bl -tag -width "CM-EscapeXXXXX" -offset indent -compact
.It Ic CM-Return
Spawn a new terminal.
.It Ic C-M-Delete
.It Ic CM-Delete
Lock the screen.
.It Ic M-Return
Hide current window.
@ -70,50 +70,54 @@ Raise current window.
Search for windows.
.It Ic C-/
Search for applications.
.It Ic C-M-n
.It Ic CM-n
Label current window.
.It Ic M-Tab
Cycle through currently visible windows.
.It Ic M-S-Tab
.It Ic MS-Tab
Reverse cycle through currently visible windows.
.It Ic C-M-x
.It Ic CM-x
Delete current window.
.It Ic C-M-[n]
.It Ic CM-[n]
Select group n, where n is 1-9.
.It Ic C-M-0
.It Ic CM-0
Select all groups.
.It Ic C-M-g
.It Ic CM-g
Toggle group membership of current window.
.It Ic M-Right
Cycle through active groups.
.It Ic M-Left
Reverse cycle through active groups.
.It Ic C-M-f
.It Ic CMS-f
Toggle freezing geometry of current window.
.It Ic CM-f
Toggle full-screen size of current window.
.It Ic C-M-=
.It Ic CM-=
Toggle vertical maximization of current window.
.It Ic CMS-=
Toggle horizontal maximization of current window.
.It Ic M-?
Spawn
.Dq Exec program
.Dq exec program
dialog.
.It Ic M-.
Spawn
.Dq Ssh to
.Dq ssh to
dialog.
This parses
.Pa $HOME/.ssh/known_hosts
to provide host auto-completion.
.Xr ssh 1
will be executed via the configured terminal emulator.
.It Ic C-M-w
.It Ic CM-w
Spawn
.Dq Exec WindowManager
.Dq exec WindowManager
dialog; allows you to switch from
.Nm
to another window manager without restarting the X server.
.It Ic C-M-S-r
.It Ic CMS-r
Reload configuration.
.It Ic C-M-S-q
.It Ic CMS-q
Quit
.Nm .
.El
@ -121,15 +125,15 @@ Quit
The mouse bindings are also important, they are:
.Pp
.Bl -tag -width Ds -offset indent -compact
.It M-M1
.It Ic M-M1
Move current window.
.It C-M-M1
.It Ic CM-M1
Toggle group membership of current window.
.It M-M2
.It Ic M-M2
Resize current window
.It M-M3
.It Ic M-M3
Lower current window.
.It CMS-M3
.It Ic CMS-M3
Hide current window.
.El
.Pp
@ -145,22 +149,34 @@ Specify the display to use.
.El
.Sh POINTER MOVEMENT
The pointer can be moved with the use of the keyboard through bindings.
C-[UP|DOWN|LEFT|RIGHT] moves the pointer a small amount, while
C-shift-[UP|DOWN|LEFT|RIGHT] moves the pointer a larger amount.
.Ic C-[Up|Down|Left|Right]
moves the pointer a small amount, while
.Ic CS-[Up|Down|Left|Right]
moves the pointer a larger amount.
For example, to move the pointer to the left by a small amount,
press C-LEFT.
To move the pointer down by a larger amount, press C-shift-DOWN.
press
.Ic C-Left .
To move the pointer down by a larger amount, press
.Ic CS-Down .
.Sh WINDOW MOVEMENT AND RESIZING
.Nm
windows can be moved with the use of the keyboard through Vi-like bindings.
M-[hjkl] moves the current window a small amount, while M-shift-[hjkl] moves
the current window a larger amount.
For example, to move the current window to the left a small amount, press M-h.
To move the current window down by a larger amount, press M-shift-j.
windows can be moved with the use of the keyboard through
.Cm vi Ns -like
bindings.
.Ic M-[hjkl]
moves the current window a small amount, while
.Ic MS-[hjkl]
moves the current window a larger amount.
For example, to move the current window to the left a small amount, press
.Ic M-h .
To move the current window down by a larger amount, press
.Ic MS-j .
.Pp
Similarly, windows may be resized with the same keybindings with the addition
Similarly, windows may be resized with the same key bindings with the addition
of the Control key.
C-M-[hjkl] resizes the window a small amount and C-M-shift-[hjkl]
.Ic CM-[hjkl]
resizes the window a small amount and
.Ic CMS-[hjkl]
resizes by a larger increment.
.Sh SEARCH
.Nm
@ -174,14 +190,14 @@ keeps a history of the 5 previous titles of a window.
When searching, the leftmost character of the result list may show a
flag:
.Pp
.Bl -tag -width 10n -offset -indent -compact
.Bl -tag -width 10n -offset indent -compact
.It !
The window is the currently focused window.
.It &
The window is hidden.
.El
.Pp
The following keybindings may be used to navigate the result list:
The following key bindings may be used to navigate the result list:
.Pp
.Bl -tag -width "[Down] or C-s or M-j" -offset indent -compact
.It Ic [Down], C-s No or Ic M-j
@ -216,14 +232,14 @@ and a red border will be shown on those just removed.
.Sh MENUS
Menus are recalled by clicking the mouse on the root window:
.Pp
.Bl -tag -width 10n -offset -indent -compact
.It M1
.Bl -tag -width 10n -offset indent -compact
.It Ic M1
Show list of currently hidden windows.
Clicking on an item will unhide that window.
.It M2
.It Ic M2
Show list of currently defined groups.
Clicking on an item will hide/unhide that group.
.It M3
.It Ic M3
Show list of applications as defined in
.Pa ~/.cwmrc .
Clicking on an item will spawn that application.
@ -252,7 +268,7 @@ with contributions from
.An Andy Adamson Aq dros@monkey.org ,
.An Niels Provos Aq provos@monkey.org ,
and
.An Antti Nyk<EFBFBD>nen Aq aon@iki.fi .
.An Antti Nyk\(:anen Aq aon@iki.fi .
Ideas, discussion with many others.
.Sh HISTORY
.Nm

90
cwmrc.5
View File

@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: February 7 2009 $
.Dd $Mdocdate: September 8 2011 $
.Dt CWMRC 5
.Os
.Sh NAME
@ -24,12 +24,24 @@
This manual page describes the
.Xr cwm 1
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
.Bl -tag -width Ds -compact
.It Ic autogroup Ar group Dq windowclass
.It Ic autogroup Ar group Dq windowclass,windowname
Control automatic window grouping, based on the class and/or name
.It Ic autogroup Ar group windowname
.It Ic autogroup Ar group windowname,windowclass
Control automatic window grouping, based on the name and/or class
properties, where
.Ar group
is a number between 0 and 9.
@ -38,10 +50,10 @@ allow for
.Dq sticky
windows in sticky group mode.
.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 .
.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
keybinding.
The modifier keys come first, followed by a
@ -84,7 +96,28 @@ application.
Set the window border width to
.Ar pixels .
.Pp
.It Ic command Ar name Ar path
.It Ic color activeborder Ar color
Set the color of the active border.
.Pp
.It Ic color font Ar color
Set menu font color.
.Pp
.It Ic color groupborder Ar color
Set the color of the border while grouping a window.
.Pp
.It Ic color inactiveborder Ar color
Set the color of the inactive border.
.Pp
.It Ic color menubg Ar color
Set menu background color.
.Pp
.It Ic color menufg Ar color
Set menu foreground color.
.Pp
.It Ic color ungroupborder Ar color
Set the color of the border while ungrouping a window.
.Pp
.It Ic command Ar name path
Every
.Ar name
entry is shown in the application menu.
@ -126,16 +159,16 @@ can be used for applications such as
where the user may wish to remain visible.
.Pp
.It Ic ignore Ar windowname
Ignore windows with the name
Ignore, and do not warp to, windows with the name
.Ar windowname
when drawing borders and cycling through windows.
.Pp
.It Ic mousebind Ar buttons Ar command
.It Ic mousebind Ar buttons command
Cause the creation of a mouse binding, or replacement of a default
mouse binding.
The modifier keys come first, followed by a
.Sq - .
.Pb
.Pp
The following modifiers are recognised:
.Pp
.Bl -tag -width Ds -offset indent -compact
@ -152,15 +185,14 @@ The Mod4 key (normally the windows key).
The
.Sq -
should be followed by number:
.Pb
.Bl -tag -width Ds -offset indent -compact
.Pp
.Bl -tag -width Ds -offset indent -compact
.It 1
Left mouse button.
.It 2
Right mouse button.
.It 3
Middle mouse button.
.It 3
Right mouse button.
.El
.Pp
The
@ -174,6 +206,10 @@ Set a default size for the keyboard movement bindings,
in pixels.
The default is 1.
.Pp
.It Ic snapdist Ar pixels
Minimum distance to snap-to adjacent edge, in pixels.
The default is 0.
.Pp
.It Ic sticky Ic yes Ns \&| Ns Ic no
Toggle sticky group mode.
The default behavior for new windows is to not assign any group.
@ -208,6 +244,12 @@ ignore xclock
bind CM-r label
bind CS-Return "xterm -e top"
bind 4-o unmap
bind M-1 grouponly1
bind M-2 grouponly2
bind M-3 grouponly3
bind MS-1 movetogroup1
bind MS-2 movetogroup2
bind MS-3 movetogroup3
# Mousebindings
mousebind M-2 window_lower
@ -242,10 +284,16 @@ Launch
menu.
.It group[n]
Select group n, where n is 1-9.
.It grouponly[n]
Like
.Ar group[n]
but also hides the other groups.
.It nogroup
Select all groups.
.It grouptoggle
Toggle group membership of current window.
.It movetogroup[n]
Hide current window from display and move to group n, where n is 1-9.
.It cyclegroup
Forward cycle through groups.
.It rcyclegroup
@ -254,6 +302,10 @@ Reverse cycle through groups.
Forward cycle through windows.
.It rcycle
Reverse cycle through windows.
.It cycleingroup
Forward cycle through windows in current group.
.It rcycleingroup
Reverse cycle through windows in current group.
.It delete
Delete current window.
.It hide
@ -264,10 +316,14 @@ Lower current window.
Raise current window.
.It label
Label current window.
.It freeze
Freeze current window geometry.
.It maximize
Maximize current window full-screen.
.It vmaximize
Maximize current window vertically.
.It hmaximize
Maximize current window horizontally.
.It moveup
Move window
.Ar moveamount
@ -373,6 +429,8 @@ Move current window.
Resize current window.
.It window_lower
Lower current window.
.It window_raise
Raise current window.
.It window_hide
Hide current window.
.It window_grouptoggle
@ -380,7 +438,7 @@ Toggle group membership of current window.
.It menu_group
Launch group list.
.It menu_unhide
Launch group list.
Launch hidden window list.
.It menu_cmd
Launch command list.
.El

61
font.c
View File

@ -1,5 +1,5 @@
/*
* font.c - cwm font abstraction
* calmwm - the calm window manager
*
* Copyright (c) 2005 Marius Eriksen <marius@monkey.org>
*
@ -14,38 +14,64 @@
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $OpenBSD$
*/
#include "headers.h"
#include <sys/param.h>
#include <sys/queue.h>
#include <err.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "calmwm.h"
void
font_init(struct screen_ctx *sc)
int
font_ascent(struct screen_ctx *sc)
{
XColor xcolor, tmp;
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,
DefaultVisual(X_Dpy, sc->which), DefaultColormap(X_Dpy, sc->which));
if (sc->xftdraw == NULL)
errx(1, "XftDrawCreate");
if (!XAllocNamedColor(X_Dpy, DefaultColormap(X_Dpy, sc->which),
"black", &xcolor, &tmp))
errx(1, "XAllocNamedColor");
sc->xftcolor.color.red = xcolor.red;
sc->xftcolor.color.green = xcolor.green;
sc->xftcolor.color.blue = xcolor.blue;
sc->xftcolor.color.alpha = 0x00ff00;
sc->xftcolor.pixel = xcolor.pixel;
if (sc->xftcolor.pixel)
XftColorFree(X_Dpy, DefaultVisual(X_Dpy, sc->which),
DefaultColormap(X_Dpy, sc->which), &sc->xftcolor);
if (!XftColorAllocName(X_Dpy, DefaultVisual(X_Dpy, sc->which),
DefaultColormap(X_Dpy, sc->which), color, &sc->xftcolor))
errx(1, "XftColorAllocName");
}
int
font_width(const char *text, int len)
font_width(struct screen_ctx *sc, const char *text, int len)
{
XGlyphInfo extents;
XftTextExtents8(X_Dpy, Conf.DefaultFont, (const XftChar8*)text,
XftTextExtentsUtf8(X_Dpy, sc->font, (const FcChar8*)text,
len, &extents);
return (extents.xOff);
@ -56,8 +82,7 @@ font_draw(struct screen_ctx *sc, const char *text, int len,
Drawable d, int x, int y)
{
XftDrawChange(sc->xftdraw, d);
/* Really needs to be UTF8'd. */
XftDrawString8(sc->xftdraw, &sc->xftcolor, Conf.DefaultFont, x, y,
XftDrawStringUtf8(sc->xftdraw, &sc->xftcolor, sc->font, x, y,
(const FcChar8*)text, len);
}

366
group.c
View File

@ -16,24 +16,29 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* 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"
#define CALMWM_NGROUPS 9
static void _group_add(struct group_ctx *, struct client_ctx *);
static void _group_remove(struct client_ctx *);
static void _group_hide(struct group_ctx *);
static void _group_show(struct group_ctx *);
static void _group_fix_hidden_state(struct group_ctx *);
struct group_ctx *Group_active = NULL;
struct group_ctx Groups[CALMWM_NGROUPS];
int Grouphideall = 0;
struct group_ctx_q Groupq;
static void group_add(struct group_ctx *, struct client_ctx *);
static void group_remove(struct client_ctx *);
static void group_hide(struct screen_ctx *, struct group_ctx *);
static void group_show(struct screen_ctx *, struct group_ctx *);
static void group_fix_hidden_state(struct group_ctx *);
static void group_setactive(struct screen_ctx *, long);
static void group_set_names(struct screen_ctx *);
const char *shortcut_to_name[] = {
"nogroup", "one", "two", "three", "four", "five", "six",
@ -41,10 +46,13 @@ const char *shortcut_to_name[] = {
};
static void
_group_add(struct group_ctx *gc, struct client_ctx *cc)
group_add(struct group_ctx *gc, struct client_ctx *cc)
{
long no;
if (cc == NULL || gc == NULL)
errx(1, "_group_add: a ctx is NULL");
errx(1, "group_add: a ctx is NULL");
no = gc->shortcut - 1;
if (cc->group == gc)
return;
@ -52,33 +60,34 @@ _group_add(struct group_ctx *gc, struct client_ctx *cc)
if (cc->group != NULL)
TAILQ_REMOVE(&cc->group->clients, cc, group_entry);
XChangeProperty(X_Dpy, cc->win, _CWM_GRP, XA_STRING,
8, PropModeReplace, gc->name, strlen(gc->name));
XChangeProperty(X_Dpy, cc->win, _NET_WM_DESKTOP, XA_CARDINAL,
32, PropModeReplace, (unsigned char *)&no, 1);
TAILQ_INSERT_TAIL(&gc->clients, cc, group_entry);
cc->group = gc;
}
static void
_group_remove(struct client_ctx *cc)
group_remove(struct client_ctx *cc)
{
if (cc == NULL || cc->group == NULL)
errx(1, "_group_remove: a ctx is NULL");
long no = 0xffffffff;
XChangeProperty(X_Dpy, cc->win, _CWM_GRP, XA_STRING, 8,
PropModeReplace, shortcut_to_name[0],
strlen(shortcut_to_name[0]));
if (cc == NULL || cc->group == NULL)
errx(1, "group_remove: a ctx is NULL");
XChangeProperty(X_Dpy, cc->win, _NET_WM_DESKTOP, XA_CARDINAL,
32, PropModeReplace, (unsigned char *)&no, 1);
TAILQ_REMOVE(&cc->group->clients, cc, group_entry);
cc->group = NULL;
}
static void
_group_hide(struct group_ctx *gc)
group_hide(struct screen_ctx *sc, struct group_ctx *gc)
{
struct client_ctx *cc;
screen_updatestackingorder();
screen_updatestackingorder(sc);
gc->nhidden = 0;
gc->highstack = 0;
@ -92,13 +101,18 @@ _group_hide(struct group_ctx *gc)
}
static void
_group_show(struct group_ctx *gc)
group_show(struct screen_ctx *sc, struct group_ctx *gc)
{
struct client_ctx *cc;
Window *winlist;
u_int i;
int lastempty = -1;
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));
/*
@ -125,25 +139,96 @@ _group_show(struct group_ctx *gc)
xfree(winlist);
gc->hidden = 0;
Group_active = gc;
group_setactive(sc, gc->shortcut - 1);
}
void
group_init(void)
group_init(struct screen_ctx *sc)
{
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++) {
TAILQ_INIT(&Groups[i].clients);
Groups[i].hidden = 0;
Groups[i].shortcut = i + 1;
Groups[i].name = shortcut_to_name[Groups[i].shortcut];
TAILQ_INSERT_TAIL(&Groupq, &Groups[i], entry);
TAILQ_INIT(&sc->groups[i].clients);
sc->groups[i].hidden = 0;
sc->groups[i].shortcut = i + 1;
TAILQ_INSERT_TAIL(&sc->groupq, &sc->groups[i], entry);
}
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
group_movetogroup(struct client_ctx *cc, int idx)
{
struct screen_ctx *sc = cc->sc;
struct group_ctx *gc;
if (idx < 0 || idx >= CALMWM_NGROUPS)
err(1, "group_movetogroup: index out of range (%d)", idx);
gc = &sc->groups[idx];
if (cc->group == gc)
return;
if (gc->hidden) {
client_hide(cc);
gc->nhidden++;
}
group_add(gc, cc);
}
/*
@ -152,16 +237,17 @@ group_init(void)
void
group_sticky_toggle_enter(struct client_ctx *cc)
{
struct screen_ctx *sc = cc->sc;
struct group_ctx *gc;
gc = Group_active;
gc = sc->group_active;
if (gc == cc->group) {
_group_remove(cc);
cc->highlight = CLIENT_HIGHLIGHT_RED;
group_remove(cc);
cc->highlight = CLIENT_HIGHLIGHT_UNGROUP;
} else {
_group_add(gc, cc);
cc->highlight = CLIENT_HIGHLIGHT_BLUE;
group_add(gc, cc);
cc->highlight = CLIENT_HIGHLIGHT_GROUP;
}
client_draw_border(cc);
@ -178,7 +264,7 @@ group_sticky_toggle_exit(struct client_ctx *cc)
* if group_hidetoggle would produce no effect, toggle the group's hidden state
*/
static void
_group_fix_hidden_state(struct group_ctx *gc)
group_fix_hidden_state(struct group_ctx *gc)
{
struct client_ctx *cc;
int same = 0;
@ -193,23 +279,39 @@ _group_fix_hidden_state(struct group_ctx *gc)
}
void
group_hidetoggle(int idx)
group_hidetoggle(struct screen_ctx *sc, int idx)
{
struct group_ctx *gc;
if (idx < 0 || idx >= CALMWM_NGROUPS)
err(1, "group_hidetoggle: index out of range (%d)", idx);
gc = &Groups[idx];
_group_fix_hidden_state(gc);
gc = &sc->groups[idx];
group_fix_hidden_state(gc);
if (gc->hidden)
_group_show(gc);
group_show(sc, gc);
else {
_group_hide(gc);
group_hide(sc, gc);
/* XXX wtf? */
if (TAILQ_EMPTY(&gc->clients))
Group_active = gc;
group_setactive(sc, idx);
}
}
void
group_only(struct screen_ctx *sc, int idx)
{
int i;
if (idx < 0 || idx >= CALMWM_NGROUPS)
err(1, "group_only: index out of range (%d)", idx);
for (i = 0; i < CALMWM_NGROUPS; i++) {
if (i == idx)
group_show(sc, &sc->groups[i]);
else
group_hide(sc, &sc->groups[i]);
}
}
@ -217,37 +319,37 @@ group_hidetoggle(int idx)
* Cycle through active groups. If none exist, then just stay put.
*/
void
group_cycle(int reverse)
group_cycle(struct screen_ctx *sc, int flags)
{
struct group_ctx *gc, *showgroup = NULL;
assert(Group_active != NULL);
assert(sc->group_active != NULL);
gc = Group_active;
gc = sc->group_active;
for (;;) {
gc = reverse ? TAILQ_PREV(gc, group_ctx_q, entry) :
TAILQ_NEXT(gc, entry);
gc = (flags & CWM_RCYCLE) ? TAILQ_PREV(gc, group_ctx_q,
entry) : TAILQ_NEXT(gc, entry);
if (gc == NULL)
gc = reverse ? TAILQ_LAST(&Groupq, group_ctx_q) :
TAILQ_FIRST(&Groupq);
if (gc == Group_active)
gc = (flags & CWM_RCYCLE) ? TAILQ_LAST(&sc->groupq,
group_ctx_q) : TAILQ_FIRST(&sc->groupq);
if (gc == sc->group_active)
break;
if (!TAILQ_EMPTY(&gc->clients) && showgroup == NULL)
showgroup = gc;
else if (!gc->hidden)
_group_hide(gc);
group_hide(sc, gc);
}
if (showgroup == NULL)
return;
_group_hide(Group_active);
group_hide(sc, sc->group_active);
if (showgroup->hidden)
_group_show(showgroup);
group_show(sc, showgroup);
else
Group_active = showgroup;
group_setactive(sc, showgroup->shortcut - 1);
}
/* called when a client is deleted */
@ -264,26 +366,28 @@ group_client_delete(struct client_ctx *cc)
void
group_menu(XButtonEvent *e)
{
struct screen_ctx *sc;
struct group_ctx *gc;
struct menu *mi;
struct menu_q menuq;
int i;
sc = screen_fromroot(e->root);
TAILQ_INIT(&menuq);
for (i = 0; i < CALMWM_NGROUPS; i++) {
gc = &Groups[i];
gc = &sc->groups[i];
if (TAILQ_EMPTY(&gc->clients))
continue;
XCALLOC(mi, struct menu);
mi = xcalloc(1, sizeof(*mi));
if (gc->hidden)
snprintf(mi->text, sizeof(mi->text), "%d: [%s]",
gc->shortcut, shortcut_to_name[gc->shortcut]);
(void)snprintf(mi->text, sizeof(mi->text), "%d: [%s]",
gc->shortcut, sc->group_names[i]);
else
snprintf(mi->text, sizeof(mi->text), "%d: %s",
gc->shortcut, shortcut_to_name[gc->shortcut]);
(void)snprintf(mi->text, sizeof(mi->text), "%d: %s",
gc->shortcut, sc->group_names[i]);
mi->ctx = gc;
TAILQ_INSERT_TAIL(&menuq, mi, entry);
}
@ -291,17 +395,14 @@ group_menu(XButtonEvent *e)
if (TAILQ_EMPTY(&menuq))
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)
goto cleanup;
gc = (struct group_ctx *)mi->ctx;
if (gc->hidden)
_group_show(gc);
else
_group_hide(gc);
(gc->hidden) ? group_show(sc, gc) : group_hide(sc, gc);
cleanup:
while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
@ -311,59 +412,138 @@ cleanup:
}
void
group_alltoggle(void)
group_alltoggle(struct screen_ctx *sc)
{
int i;
for (i = 0; i < CALMWM_NGROUPS; i++) {
if (Grouphideall)
_group_show(&Groups[i]);
if (sc->group_hideall)
group_show(sc, &sc->groups[i]);
else
_group_hide(&Groups[i]);
group_hide(sc, &sc->groups[i]);
}
if (Grouphideall)
Grouphideall = 0;
else
Grouphideall = 1;
sc->group_hideall = (!sc->group_hideall);
}
void
group_autogroup(struct client_ctx *cc)
{
struct screen_ctx *sc = cc->sc;
struct autogroupwin *aw;
struct group_ctx *gc;
unsigned char *grpstr = NULL;
char group[CALMWM_MAXNAMELEN];
int no = -1;
long *grpno;
if (cc->app_class == NULL || cc->app_name == NULL)
return;
if (xu_getprop(cc, _CWM_GRP, XA_STRING,
(CALMWM_MAXNAMELEN - 1)/sizeof(long), &grpstr) > 0) {
strlcpy(group, grpstr, sizeof(group));
XFree(grpstr);
if (xu_getprop(cc->win, _NET_WM_DESKTOP, XA_CARDINAL,
1, (unsigned char **)&grpno) > 0) {
if (*grpno == 0xffffffff)
no = 0;
else if (*grpno > CALMWM_NGROUPS || *grpno < 0)
no = CALMWM_NGROUPS - 1;
else
no = *grpno + 1;
XFree(grpno);
} else {
TAILQ_FOREACH(aw, &Conf.autogroupq, entry) {
if (strcmp(aw->class, cc->app_class) == 0 &&
(aw->name == NULL ||
strcmp(aw->name, cc->app_name) == 0)) {
strlcpy(group, aw->group, sizeof(group));
no = aw->num;
break;
}
}
}
if (strncmp("nogroup", group, 7) == 0)
/* no group please */
if (no == 0)
return;
TAILQ_FOREACH(gc, &Groupq, entry) {
if (strcmp(shortcut_to_name[gc->shortcut], group) == 0) {
_group_add(gc, cc);
TAILQ_FOREACH(gc, &sc->groupq, entry) {
if (gc->shortcut == no) {
group_add(gc, cc);
return;
}
}
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,56 +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/types.h>
#include <sys/queue.h>
#include <sys/wait.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <dirent.h>
#include <getopt.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <ctype.h>
#include <X11/cursorfont.h>
#include <X11/extensions/Xinerama.h>
#include <X11/extensions/Xrandr.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include <X11/Xatom.h>
#include <X11/Xproto.h>
#include <X11/Intrinsic.h>
#include <X11/Xos.h>
#include <X11/Xft/Xft.h>
#include <err.h>
#endif /* _CALMWM_HEADERS_H_ */

111
input.c
View File

@ -1,111 +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';
if (state & ShiftMask)
ks = XKeycodeToKeysym(X_Dpy, kc, 1);
else
ks = XKeycodeToKeysym(X_Dpy, kc, 0);
/* Look for control characters. */
switch (ks) {
case XK_BackSpace:
*ctl = CTL_ERASEONE;
break;
case XK_Return:
*ctl = CTL_RETURN;
break;
case XK_Up:
*ctl = CTL_UP;
break;
case XK_Down:
*ctl = CTL_DOWN;
break;
case XK_Escape:
*ctl = CTL_ABORT;
break;
}
if (*ctl == CTL_NONE && (state & ControlMask)) {
switch (ks) {
case XK_s:
case XK_S:
/* Emacs "next" */
*ctl = CTL_DOWN;
break;
case XK_r:
case XK_R:
/* Emacs "previous" */
*ctl = CTL_UP;
break;
case XK_u:
case XK_U:
*ctl = CTL_WIPE;
break;
case XK_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);
}

233
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
* purpose with or without fee is hereby granted, provided that the above
@ -15,18 +15,27 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* 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 <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "headers.h"
#include "calmwm.h"
#define KNOWN_HOSTS ".ssh/known_hosts"
#define HASH_MARKER "|1|"
extern int _xev_quit;
extern sig_atomic_t xev_quit;
void
kbfunc_client_lower(struct client_ctx *cc, union arg *arg)
@ -40,8 +49,8 @@ kbfunc_client_raise(struct client_ctx *cc, union arg *arg)
client_raise(cc);
}
#define typemask (CWM_MOVE | CWM_RESIZE | CWM_PTRMOVE)
#define movemask (CWM_UP | CWM_DOWN | CWM_LEFT | CWM_RIGHT)
#define TYPEMASK (CWM_MOVE | CWM_RESIZE | CWM_PTRMOVE)
#define MOVEMASK (CWM_UP | CWM_DOWN | CWM_LEFT | CWM_RIGHT)
void
kbfunc_moveresize(struct client_ctx *cc, union arg *arg)
{
@ -49,7 +58,10 @@ kbfunc_moveresize(struct client_ctx *cc, union arg *arg)
int x, y, flags, amt;
u_int mx, my;
sc = screen_current();
if (cc->flags & CLIENT_FREEZE)
return;
sc = cc->sc;
mx = my = 0;
flags = arg->i;
@ -60,7 +72,7 @@ kbfunc_moveresize(struct client_ctx *cc, union arg *arg)
amt = amt * 10;
}
switch (flags & movemask) {
switch (flags & MOVEMASK) {
case CWM_UP:
my -= amt;
break;
@ -74,7 +86,7 @@ kbfunc_moveresize(struct client_ctx *cc, union arg *arg)
mx -= amt;
break;
}
switch (flags & typemask) {
switch (flags & TYPEMASK) {
case CWM_MOVE:
cc->geom.y += my;
if (cc->geom.y + cc->geom.height < 0)
@ -88,6 +100,13 @@ kbfunc_moveresize(struct client_ctx *cc, union arg *arg)
if (cc->geom.x > cc->sc->xmax - 1)
cc->geom.x = cc->sc->xmax - 1;
cc->geom.x += client_snapcalc(cc->geom.x,
cc->geom.width, cc->sc->xmax,
cc->bwidth, Conf.snapdist);
cc->geom.y += client_snapcalc(cc->geom.y,
cc->geom.height, cc->sc->ymax,
cc->bwidth, Conf.snapdist);
client_move(cc);
xu_ptr_getpos(cc->win, &x, &y);
cc->ptr.y = y + my;
@ -110,13 +129,8 @@ kbfunc_moveresize(struct client_ctx *cc, union arg *arg)
client_ptrwarp(cc);
break;
case CWM_PTRMOVE:
if (cc) {
xu_ptr_getpos(cc->win, &x, &y);
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);
}
xu_ptr_getpos(sc->rootwin, &x, &y);
xu_ptr_setpos(sc->rootwin, x + mx, y + my);
break;
default:
warnx("invalid flags passed to kbfunc_client_moveresize");
@ -124,24 +138,26 @@ kbfunc_moveresize(struct client_ctx *cc, union arg *arg)
}
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_q menuq;
sc = cc->sc;
old_cc = client_current();
TAILQ_INIT(&menuq);
TAILQ_FOREACH(cc, &Clientq, entry) {
XCALLOC(mi, struct menu);
strlcpy(mi->text, cc->name, sizeof(mi->text));
mi = xcalloc(1, sizeof(*mi));
(void)strlcpy(mi->text, cc->name, sizeof(mi->text));
mi->ctx = cc;
TAILQ_INSERT_TAIL(&menuq, mi, entry);
}
if ((mi = menu_filter(&menuq, "window", NULL, 0,
if ((mi = menu_filter(sc, &menuq, "window", NULL, 0,
search_match_client, search_print_client)) != NULL) {
cc = (struct client_ctx *)mi->ctx;
if (cc->flags & CLIENT_HIDDEN)
@ -159,22 +175,24 @@ kbfunc_client_search(struct client_ctx *scratch, union arg *arg)
}
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 menu *mi;
struct menu_q menuq;
struct screen_ctx *sc;
struct cmd *cmd;
struct menu *mi;
struct menu_q menuq;
sc = cc->sc;
TAILQ_INIT(&menuq);
TAILQ_FOREACH(cmd, &Conf.cmdq, entry) {
XCALLOC(mi, struct menu);
strlcpy(mi->text, cmd->label, sizeof(mi->text));
mi = xcalloc(1, sizeof(*mi));
(void)strlcpy(mi->text, cmd->label, sizeof(mi->text));
mi->ctx = cmd;
TAILQ_INSERT_TAIL(&menuq, mi, entry);
}
if ((mi = menu_filter(&menuq, "application", NULL, 0,
if ((mi = menu_filter(sc, &menuq, "application", NULL, 0,
search_match_text, NULL)) != NULL)
u_spawn(((struct cmd *)mi->ctx)->image);
@ -185,17 +203,17 @@ kbfunc_menu_search(struct client_ctx *scratch, union arg *arg)
}
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;
sc = screen_current();
sc = cc->sc;
/* XXX for X apps that ignore events */
XGrabKeyboard(X_Dpy, sc->rootwin, True,
GrabModeAsync, GrabModeAsync, CurrentTime);
client_cycle(arg->i);
client_cycle(sc, arg->i);
}
void
@ -223,21 +241,19 @@ kbfunc_lock(struct client_ctx *cc, union arg *arg)
}
void
kbfunc_exec(struct client_ctx *scratch, union arg *arg)
kbfunc_exec(struct client_ctx *cc, union arg *arg)
{
#define NPATHS 256
char **ap, *paths[NPATHS], *path, *pathcpy, *label;
char tpath[MAXPATHLEN];
int l, i, j, ngroups;
gid_t mygroups[NGROUPS_MAX];
uid_t ruid, euid, suid;
DIR *dirp;
struct dirent *dp;
struct menu *mi;
struct menu_q menuq;
struct stat sb;
struct screen_ctx *sc;
char **ap, *paths[NPATHS], *path, *pathcpy, *label;
char tpath[MAXPATHLEN];
DIR *dirp;
struct dirent *dp;
struct menu *mi;
struct menu_q menuq;
int l, i, cmd = arg->i;
int cmd = arg->i;
sc = cc->sc;
switch (cmd) {
case CWM_EXEC_PROGRAM:
label = "exec";
@ -250,11 +266,6 @@ kbfunc_exec(struct client_ctx *scratch, union arg *arg)
/*NOTREACHED*/
}
if (getgroups(0, mygroups) == -1)
err(1, "getgroups failure");
if ((ngroups = getresuid(&ruid, &euid, &suid)) == -1)
err(1, "getresuid failure");
TAILQ_INIT(&menuq);
if ((path = getenv("PATH")) == NULL)
@ -275,45 +286,27 @@ kbfunc_exec(struct client_ctx *scratch, union arg *arg)
/* skip everything but regular files and symlinks */
if (dp->d_type != DT_REG && dp->d_type != DT_LNK)
continue;
memset(tpath, '\0', sizeof(tpath));
(void)memset(tpath, '\0', sizeof(tpath));
l = snprintf(tpath, sizeof(tpath), "%s/%s", paths[i],
dp->d_name);
/* check for truncation etc */
if (l == -1 || l >= (int)sizeof(tpath))
continue;
/* just ignore on stat failure */
if (stat(tpath, &sb) == -1)
continue;
/* may we execute this file? */
if (euid == sb.st_uid) {
if (sb.st_mode & S_IXUSR)
goto executable;
else
continue;
if (access(tpath, X_OK) == 0) {
mi = xcalloc(1, sizeof(*mi));
(void)strlcpy(mi->text,
dp->d_name, sizeof(mi->text));
TAILQ_INSERT_TAIL(&menuq, mi, entry);
}
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 */
XCALLOC(mi, struct menu);
strlcpy(mi->text, dp->d_name, sizeof(mi->text));
TAILQ_INSERT_TAIL(&menuq, mi, entry);
}
(void)closedir(dirp);
}
xfree(path);
if ((mi = menu_filter(&menuq, label, NULL, 1,
if ((mi = menu_filter(sc, &menuq, label, NULL, 1,
search_match_exec, NULL)) != NULL) {
if (mi->text[0] == '\0')
goto out;
switch (cmd) {
case CWM_EXEC_PROGRAM:
u_spawn(mi->text);
@ -327,7 +320,7 @@ kbfunc_exec(struct client_ctx *scratch, union arg *arg)
break;
}
}
out:
if (mi != NULL && mi->dummy)
xfree(mi);
while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
@ -337,16 +330,19 @@ kbfunc_exec(struct client_ctx *scratch, union arg *arg)
}
void
kbfunc_ssh(struct client_ctx *scratch, union arg *arg)
kbfunc_ssh(struct client_ctx *cc, union arg *arg)
{
struct menu *mi;
struct menu_q menuq;
FILE *fp;
char *buf, *lbuf, *p, *home;
char hostbuf[MAXHOSTNAMELEN], filename[MAXPATHLEN];
char cmd[256];
int l;
size_t len;
struct screen_ctx *sc;
struct menu *mi;
struct menu_q menuq;
FILE *fp;
char *buf, *lbuf, *p, *home;
char hostbuf[MAXHOSTNAMELEN], filename[MAXPATHLEN];
char cmd[256];
int l;
size_t len;
sc = cc->sc;
if ((home = getenv("HOME")) == NULL)
return;
@ -366,7 +362,7 @@ kbfunc_ssh(struct client_ctx *scratch, union arg *arg)
else {
/* EOF without EOL, copy and add the NUL */
lbuf = xmalloc(len + 1);
memcpy(lbuf, buf, len);
(void)memcpy(lbuf, buf, len);
lbuf[len] = '\0';
buf = lbuf;
}
@ -379,22 +375,24 @@ kbfunc_ssh(struct client_ctx *scratch, union arg *arg)
/* ignore badness */
if (p - buf + 1 > sizeof(hostbuf))
continue;
(void) strlcpy(hostbuf, buf, p - buf + 1);
XCALLOC(mi, struct menu);
(void) strlcpy(mi->text, hostbuf, sizeof(mi->text));
(void)strlcpy(hostbuf, buf, p - buf + 1);
mi = xcalloc(1, sizeof(*mi));
(void)strlcpy(mi->text, hostbuf, sizeof(mi->text));
TAILQ_INSERT_TAIL(&menuq, mi, entry);
}
xfree(lbuf);
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) {
if (mi->text[0] == '\0')
goto out;
l = snprintf(cmd, sizeof(cmd), "%s -e ssh %s", Conf.termpath,
mi->text);
if (l != -1 && l < sizeof(cmd))
u_spawn(cmd);
}
out:
if (mi != NULL && mi->dummy)
xfree(mi);
while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
@ -408,22 +406,19 @@ kbfunc_client_label(struct client_ctx *cc, union arg *arg)
{
struct menu *mi;
struct menu_q menuq;
char *current;
TAILQ_INIT(&menuq);
if (cc->label != NULL)
current = cc->label;
else
current = NULL;
if ((mi = menu_filter(&menuq, "label", current, 1,
search_match_text, NULL)) != NULL) {
/* dummy is set, so this will always return */
mi = menu_filter(cc->sc, &menuq, "label", cc->label, 1,
search_match_text, NULL);
if (!mi->abort) {
if (cc->label != NULL)
xfree(cc->label);
cc->label = xstrdup(mi->text);
xfree(mi);
}
xfree(mi);
}
void
@ -435,19 +430,25 @@ kbfunc_client_delete(struct client_ctx *cc, union arg *arg)
void
kbfunc_client_group(struct client_ctx *cc, union arg *arg)
{
group_hidetoggle(KBTOGROUP(arg->i));
group_hidetoggle(cc->sc, KBTOGROUP(arg->i));
}
void
kbfunc_client_grouponly(struct client_ctx *cc, union arg *arg)
{
group_only(cc->sc, KBTOGROUP(arg->i));
}
void
kbfunc_client_cyclegroup(struct client_ctx *cc, union arg *arg)
{
group_cycle(arg->i);
group_cycle(cc->sc, arg->i);
}
void
kbfunc_client_nogroup(struct client_ctx *cc, union arg *arg)
{
group_alltoggle();
group_alltoggle(cc->sc);
}
void
@ -460,6 +461,12 @@ kbfunc_client_grouptoggle(struct client_ctx *cc, union arg *arg)
group_sticky_toggle_enter(cc);
}
void
kbfunc_client_movetogroup(struct client_ctx *cc, union arg *arg)
{
group_movetogroup(cc, KBTOGROUP(arg->i));
}
void
kbfunc_client_maximize(struct client_ctx *cc, union arg *arg)
{
@ -472,10 +479,22 @@ kbfunc_client_vmaximize(struct client_ctx *cc, union arg *arg)
client_vertmaximize(cc);
}
void
kbfunc_client_hmaximize(struct client_ctx *cc, union arg *arg)
{
client_horizmaximize(cc);
}
void
kbfunc_client_freeze(struct client_ctx *cc, union arg *arg)
{
client_freeze(cc);
}
void
kbfunc_quit_wm(struct client_ctx *cc, union arg *arg)
{
_xev_quit = 1;
xev_quit = 1;
}
void

282
menu.c
View File

@ -1,4 +1,6 @@
/*
* calmwm - the calm window manager
*
* Copyright (c) 2008 Owain G. Ainsworth <oga@openbsd.org>
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
*
@ -13,18 +15,30 @@
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $OpenBSD$
*/
#include "headers.h"
#include <sys/param.h>
#include <sys/queue.h>
#include <err.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "calmwm.h"
#define KeyMask (KeyPressMask|ExposureMask)
#define MenuMask (ButtonMask|ButtonMotionMask|ExposureMask| \
PointerMotionMask)
#define MenuGrabMask (ButtonMask|ButtonMotionMask|StructureNotifyMask|\
PointerMotionMask)
#define PROMPT_SCHAR '<27>'
#define PROMPT_ECHAR '<27>'
#define PROMPT_SCHAR "\xc2\xbb"
#define PROMPT_ECHAR "\xc2\xab"
enum ctltype {
CTL_NONE = -1,
CTL_ERASEONE = 0, CTL_WIPE, CTL_UP, CTL_DOWN, CTL_RETURN,
CTL_ABORT, CTL_ALL
};
struct menu_ctx {
char searchstr[MENU_MAXENTRY + 1];
@ -48,34 +62,51 @@ static struct menu *menu_handle_key(XEvent *, struct menu_ctx *,
struct menu_q *, struct menu_q *);
static void menu_handle_move(XEvent *, struct menu_ctx *,
struct screen_ctx *);
struct menu *menu_handle_release(XEvent *, struct menu_ctx *,
static struct menu *menu_handle_release(XEvent *, struct menu_ctx *,
struct screen_ctx *, struct menu_q *);
static void menu_draw(struct screen_ctx *, struct menu_ctx *,
struct menu_q *, struct menu_q *);
static int menu_calc_entry(struct screen_ctx *, struct menu_ctx *,
int, int);
static int menu_keycode(KeyCode, u_int, enum ctltype *,
char *);
void
menu_init(struct screen_ctx *sc)
{
sc->menuwin = XCreateSimpleWindow(X_Dpy, sc->rootwin, 0, 0,
1, 1, 1, sc->blackpixl, sc->whitepixl);
XGCValues gv;
if (sc->menuwin)
XDestroyWindow(X_Dpy, sc->menuwin);
sc->menuwin = XCreateSimpleWindow(X_Dpy, sc->rootwin, 0, 0, 1, 1,
Conf.bwidth,
sc->color[CWM_COLOR_FG_MENU].pixel,
sc->color[CWM_COLOR_BG_MENU].pixel);
gv.foreground =
sc->color[CWM_COLOR_FG_MENU].pixel^sc->color[CWM_COLOR_BG_MENU].pixel;
gv.background = sc->color[CWM_COLOR_BG_MENU].pixel;
gv.function = GXxor;
if (sc->gc)
XFreeGC(X_Dpy, sc->gc);
sc->gc = XCreateGC(X_Dpy, sc->menuwin,
GCForeground|GCBackground|GCFunction, &gv);
}
struct menu *
menu_filter(struct 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 (*print)(struct menu *, int))
{
struct screen_ctx *sc;
struct menu_ctx mc;
struct menu_q resultq;
struct menu *mi = NULL;
XEvent e;
Window focuswin;
int Mask, focusrevert;
sc = screen_current();
int evmask, focusrevert;
int xsave, ysave, xcur, ycur;
TAILQ_INIT(&resultq);
@ -83,22 +114,25 @@ menu_filter(struct menu_q *menuq, char *prompt, char *initial, int dummy,
xu_ptr_getpos(sc->rootwin, &mc.x, &mc.y);
xsave = mc.x;
ysave = mc.y;
if (prompt == NULL) {
Mask = MenuMask;
evmask = MENUMASK;
mc.promptstr[0] = '\0';
mc.list = 1;
} else {
Mask = MenuMask | KeyMask; /* only accept keys if prompt */
snprintf(mc.promptstr, sizeof(mc.promptstr), "%s%c", prompt,
PROMPT_SCHAR);
snprintf(mc.dispstr, sizeof(mc.dispstr), "%s%s%c", mc.promptstr,
mc.searchstr, PROMPT_ECHAR);
mc.width = font_width(mc.dispstr, strlen(mc.dispstr));
evmask = MENUMASK | KEYMASK; /* only accept keys if prompt */
(void)snprintf(mc.promptstr, sizeof(mc.promptstr), "%s%s",
prompt, PROMPT_SCHAR);
(void)snprintf(mc.dispstr, sizeof(mc.dispstr), "%s%s%s",
mc.promptstr, mc.searchstr, PROMPT_ECHAR);
mc.width = font_width(sc, mc.dispstr, strlen(mc.dispstr));
mc.hasprompt = 1;
}
if (initial != NULL)
strlcpy(mc.searchstr, initial, sizeof(mc.searchstr));
(void)strlcpy(mc.searchstr, initial, sizeof(mc.searchstr));
else
mc.searchstr[0] = '\0';
@ -107,11 +141,11 @@ menu_filter(struct menu_q *menuq, char *prompt, char *initial, int dummy,
mc.entry = mc.prev = -1;
XMoveResizeWindow(X_Dpy, sc->menuwin, mc.x, mc.y, mc.width,
font_height());
XSelectInput(X_Dpy, sc->menuwin, Mask);
font_height(sc));
XSelectInput(X_Dpy, sc->menuwin, evmask);
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);
return (NULL);
}
@ -126,11 +160,9 @@ menu_filter(struct menu_q *menuq, char *prompt, char *initial, int dummy,
for (;;) {
mc.changed = 0;
XWindowEvent(X_Dpy, sc->menuwin, Mask, &e);
XWindowEvent(X_Dpy, sc->menuwin, evmask, &e);
switch (e.type) {
default:
break;
case KeyPress:
if ((mi = menu_handle_key(&e, &mc, menuq, &resultq))
!= NULL)
@ -147,16 +179,23 @@ menu_filter(struct menu_q *menuq, char *prompt, char *initial, int dummy,
!= NULL)
goto out;
break;
default:
break;
}
}
out:
if ((dummy == 0 && mi->dummy) || (mi->text[0] == '\0')) { /* no match */
xfree (mi);
if (dummy == 0 && mi->dummy) { /* no mouse based match */
xfree(mi);
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);
XUngrabKeyboard(X_Dpy, CurrentTime);
@ -172,8 +211,7 @@ menu_handle_key(XEvent *e, struct menu_ctx *mc, struct menu_q *menuq,
char chr;
size_t len;
if (input_keycodetrans(e->xkey.keycode, e->xkey.state,
&ctl, &chr) < 0)
if (menu_keycode(e->xkey.keycode, e->xkey.state, &ctl, &chr) < 0)
return (NULL);
switch (ctl) {
@ -210,6 +248,7 @@ menu_handle_key(XEvent *e, struct menu_ctx *mc, struct menu_q *menuq,
mc->searchstr, sizeof(mi->text));
mi->dummy = 1;
}
mi->abort = 0;
return (mi);
case CTL_WIPE:
mc->searchstr[0] = '\0';
@ -222,6 +261,7 @@ menu_handle_key(XEvent *e, struct menu_ctx *mc, struct menu_q *menuq,
mi = xmalloc(sizeof *mi);
mi->text[0] = '\0';
mi->dummy = 1;
mi->abort = 1;
return (mi);
default:
break;
@ -233,18 +273,18 @@ menu_handle_key(XEvent *e, struct menu_ctx *mc, struct menu_q *menuq,
str[0] = chr;
str[1] = '\0';
mc->changed = 1;
strlcat(mc->searchstr, str, sizeof(mc->searchstr));
(void)strlcat(mc->searchstr, str, sizeof(mc->searchstr));
}
mc->noresult = 0;
if (mc->changed && strlen(mc->searchstr) > 0) {
if (mc->changed && mc->searchstr[0] != '\0') {
(*mc->match)(menuq, resultq, mc->searchstr);
/* If menuq is empty, never show we've failed */
mc->noresult = TAILQ_EMPTY(resultq) && !TAILQ_EMPTY(menuq);
} else if (mc->changed)
TAILQ_INIT(resultq);
if (!mc->list && mc->listing && !mc->changed) {
if (!mc->list && mc->listing && !mc->changed) {
TAILQ_INIT(resultq);
mc->listing = 0;
}
@ -256,8 +296,10 @@ static void
menu_draw(struct screen_ctx *sc, struct menu_ctx *mc, struct menu_q *menuq,
struct menu_q *resultq)
{
struct menu *mi;
int n, dy, xsave, ysave;
struct menu *mi;
XineramaScreenInfo *xine;
int xmin, xmax, ymin, ymax;
int n, dy, xsave, ysave;
if (mc->list) {
if (TAILQ_EMPTY(resultq) && mc->list) {
@ -275,10 +317,10 @@ menu_draw(struct screen_ctx *sc, struct menu_ctx *mc, struct menu_q *menuq,
mc->width = 0;
dy = 0;
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->width = font_width(mc->dispstr, strlen(mc->dispstr));
dy = font_height();
mc->width = font_width(sc, mc->dispstr, strlen(mc->dispstr));
dy = font_height(sc);
mc->num = 1;
}
@ -293,24 +335,39 @@ menu_draw(struct screen_ctx *sc, struct menu_ctx *mc, struct menu_q *menuq,
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)));
dy += font_height();
dy += font_height(sc);
mc->num++;
}
xine = screen_find_xinerama(sc, mc->x, mc->y);
if (xine) {
xmin = xine->x_org;
xmax = xine->x_org + xine->width;
ymin = xine->y_org;
ymax = xine->y_org + xine->height;
} else {
xmin = ymin = 0;
xmax = sc->xmax;
ymax = sc->ymax;
}
xsave = mc->x;
ysave = mc->y;
if (mc->x < 0)
mc->x = 0;
else if (mc->x + mc->width >= sc->xmax)
mc->x = sc->xmax - mc->width;
if (mc->y + dy >= sc->ymax)
mc->y = sc->ymax - dy;
if (mc->x < xmin)
mc->x = xmin;
else if (mc->x + mc->width >= xmax)
mc->x = xmax - mc->width;
if (mc->y + dy >= ymax)
mc->y = ymax - dy;
/* never hide the top of the menu */
if (mc->y < 0)
mc->y = 0;
if (mc->y < ymin) {
mc->y = ymin;
dy = ymax - ymin;
}
if (mc->x != xsave || mc->y != ysave)
xu_ptr_setpos(sc->rootwin, mc->x, mc->y);
@ -320,7 +377,7 @@ menu_draw(struct screen_ctx *sc, struct menu_ctx *mc, struct menu_q *menuq,
if (mc->hasprompt) {
font_draw(sc, mc->dispstr, strlen(mc->dispstr), sc->menuwin,
0, font_ascent() + 1);
0, font_ascent(sc) + 1);
n = 1;
} else
n = 0;
@ -330,20 +387,20 @@ menu_draw(struct screen_ctx *sc, struct menu_ctx *mc, struct menu_q *menuq,
mi->print : mi->text;
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++;
}
if (mc->hasprompt && n > 1)
if (mc->hasprompt && n > 1 && (mc->searchstr[0] != '\0'))
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)
XFillRectangle(X_Dpy, sc->menuwin, sc->gc,
0, 0, mc->width, font_height());
0, 0, mc->width, font_height(sc));
}
void
static void
menu_handle_move(XEvent *e, struct menu_ctx *mc, struct screen_ctx *sc)
{
mc->prev = mc->entry;
@ -351,16 +408,16 @@ menu_handle_move(XEvent *e, struct menu_ctx *mc, struct screen_ctx *sc)
if (mc->prev != -1)
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) {
xu_ptr_regrab(MenuGrabMask, Cursor_select);
(void)xu_ptr_regrab(MENUGRABMASK, Cursor_normal);
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
xu_ptr_regrab(MenuGrabMask, Cursor_default);
(void)xu_ptr_regrab(MENUGRABMASK, Cursor_default);
}
struct menu *
static struct menu *
menu_handle_release(XEvent *e, struct menu_ctx *mc, struct screen_ctx *sc,
struct menu_q *resultq)
{
@ -368,7 +425,6 @@ menu_handle_release(XEvent *e, struct menu_ctx *mc, struct screen_ctx *sc,
int entry, i = 0;
entry = menu_calc_entry(sc, mc, e->xbutton.x, e->xbutton.y);
xu_ptr_ungrab();
if (mc->hasprompt)
i = 1;
@ -377,7 +433,7 @@ menu_handle_release(XEvent *e, struct menu_ctx *mc, struct screen_ctx *sc,
if (entry == i++)
break;
if (mi == NULL) {
XMALLOC(mi, struct menu);
mi = xmalloc(sizeof(*mi));
mi->text[0] = '\0';
mi->dummy = 1;
}
@ -389,11 +445,11 @@ menu_calc_entry(struct screen_ctx *sc, struct menu_ctx *mc, int x, int y)
{
int entry;
entry = y / font_height();
entry = y / font_height(sc);
/* in bounds? */
if (x < 0 || x > mc->width || y < 0 || y > font_height() * mc->num ||
entry < 0 || entry >= mc->num)
if (x <= 0 || x > mc->width || y <= 0 ||
y > font_height(sc) * mc->num || entry < 0 || entry >= mc->num)
entry = -1;
if (mc->hasprompt && entry == 0)
@ -401,3 +457,89 @@ menu_calc_entry(struct screen_ctx *sc, struct menu_ctx *mc, int x, int y)
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) 2008 rivo nurges <rix@estpak.ee>
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
* Copyright (c) 2008 rivo nurges <rix@estpak.ee>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -16,42 +16,33 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* 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"
static int _mousefunc_sweep_calc(struct client_ctx *, int, int, int, int);
static void _mousefunc_sweep_draw(struct client_ctx *, int, int);
#define ADJUST_HEIGHT(cc, dy) ((cc->geom.height - cc->geom.min_dy) / dy)
#define ADJUST_WIDTH(cc, dx) ((cc->geom.width - cc->geom.min_dx) / dx)
static int mousefunc_sweep_calc(struct client_ctx *, int, int, int, int);
static void mousefunc_sweep_draw(struct client_ctx *);
static int
_mousefunc_sweep_calc(struct client_ctx *cc, int x, int y, int mx, int my)
mousefunc_sweep_calc(struct client_ctx *cc, int x, int y, int mx, int my)
{
int width = cc->geom.width, height = cc->geom.height;
cc->geom.width = abs(x - mx) - cc->bwidth;
cc->geom.height = abs(y - my) - cc->bwidth;
if (cc->size->flags & PResizeInc) {
cc->geom.width -=
(cc->geom.width - cc->geom.min_dx) % cc->size->width_inc;
cc->geom.height -=
(cc->geom.height - cc->geom.min_dy) % cc->size->height_inc;
}
if (cc->size->flags & PMinSize) {
cc->geom.width = MAX(cc->geom.width, cc->size->min_width);
cc->geom.height = MAX(cc->geom.height, cc->size->min_height);
}
if (cc->size->flags & PMaxSize) {
cc->geom.width = MIN(cc->geom.width, cc->size->max_width);
cc->geom.height = MIN(cc->geom.height, cc->size->max_height);
}
client_applysizehints(cc);
cc->geom.x = x <= mx ? x : x - cc->geom.width;
cc->geom.y = y <= my ? y : y - cc->geom.height;
@ -60,65 +51,71 @@ _mousefunc_sweep_calc(struct client_ctx *cc, int x, int y, int mx, int my)
}
static void
_mousefunc_sweep_draw(struct client_ctx *cc, int dx, int dy)
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" */
int wide, height, wide_size, wide_name;
int x = cc->geom.x, y = cc->geom.y;
int width, width_size, width_name;
snprintf(asize, sizeof(asize), "%dx%d",
ADJUST_WIDTH(cc, dx), ADJUST_HEIGHT(cc, dy));
wide_size = font_width(asize, strlen(asize)) + 4;
wide_name = font_width(cc->name, strlen(cc->name)) + 4;
wide = MAX(wide_size, wide_name);
height = font_ascent() + font_descent() + 1;
(void)snprintf(asize, sizeof(asize), "%dx%d",
(cc->geom.width - cc->hint.basew) / cc->hint.incw,
(cc->geom.height - cc->hint.baseh) / cc->hint.inch);
width_size = font_width(sc, asize, strlen(asize)) + 4;
width_name = font_width(sc, cc->name, strlen(cc->name)) + 4;
width = MAX(width_size, width_name);
XMoveResizeWindow(X_Dpy, sc->menuwin, x, y, wide, height * 2);
XMapWindow(X_Dpy, sc->menuwin);
XReparentWindow(X_Dpy, sc->menuwin, cc->win, 0, 0);
XMoveResizeWindow(X_Dpy, sc->menuwin, 0, 0, width, font_height(sc) * 2);
XMapWindow(X_Dpy, sc->menuwin);
XClearWindow(X_Dpy, sc->menuwin);
font_draw(sc, cc->name, strlen(cc->name), sc->menuwin,
2, font_ascent() + 1);
2, font_ascent(sc) + 1);
font_draw(sc, asize, strlen(asize), sc->menuwin,
wide / 2 - wide_size / 2, height + font_ascent() + 1);
width / 2 - width_size / 2, font_height(sc) + font_ascent(sc) + 1);
}
void
mousefunc_window_resize(struct client_ctx *cc, void *arg)
{
XEvent ev;
struct screen_ctx *sc = CCTOSC(cc);
int dx, dy;
Time ltime = 0;
struct screen_ctx *sc = cc->sc;
int x = cc->geom.x, y = cc->geom.y;
dx = MAX(1, cc->size->width_inc);
dy = MAX(1, cc->size->height_inc);
if (cc->flags & CLIENT_FREEZE)
return;
client_raise(cc);
client_ptrsave(cc);
if (xu_ptr_grab(sc->rootwin, MouseMask, Cursor_resize) < 0)
if (xu_ptr_grab(cc->win, MOUSEMASK, Cursor_resize) < 0)
return;
xu_ptr_setpos(cc->win, cc->geom.width, cc->geom.height);
_mousefunc_sweep_draw(cc, dx, dy);
mousefunc_sweep_draw(cc);
for (;;) {
XMaskEvent(X_Dpy, MouseMask|ExposureMask, &ev);
XMaskEvent(X_Dpy, MOUSEMASK|ExposureMask, &ev);
switch (ev.type) {
case Expose:
client_draw_border(cc);
break;
case MotionNotify:
if (_mousefunc_sweep_calc(cc, x, y,
ev.xmotion.x, ev.xmotion.y))
if (mousefunc_sweep_calc(cc, x, y,
ev.xmotion.x_root, ev.xmotion.y_root))
/* Recompute window output */
_mousefunc_sweep_draw(cc, dx, dy);
client_resize(cc);
mousefunc_sweep_draw(cc);
/* don't resize more than 60 times / second */
if ((ev.xmotion.time - ltime) > (1000 / 60)) {
ltime = ev.xmotion.time;
client_resize(cc);
}
break;
case ButtonRelease:
if (ltime)
client_resize(cc);
XUnmapWindow(X_Dpy, sc->menuwin);
XReparentWindow(X_Dpy, sc->menuwin, sc->rootwin, 0, 0);
xu_ptr_ungrab();
@ -129,7 +126,6 @@ mousefunc_window_resize(struct client_ctx *cc, void *arg)
if (cc->ptr.y > cc->geom.height)
cc->ptr.y = cc->geom.height - cc->bwidth;
client_ptrwarp(cc);
return;
}
}
@ -140,30 +136,46 @@ void
mousefunc_window_move(struct client_ctx *cc, void *arg)
{
XEvent ev;
struct screen_ctx *sc = CCTOSC(cc);
int mx, my;
int x = cc->geom.x, y = cc->geom.y;
Time ltime = 0;
int px, py;
client_raise(cc);
if (xu_ptr_grab(sc->rootwin, MouseMask, Cursor_move) < 0)
if (cc->flags & CLIENT_FREEZE)
return;
xu_ptr_getpos(sc->rootwin, &mx, &my);
if (xu_ptr_grab(cc->win, MOUSEMASK, Cursor_move) < 0)
return;
xu_ptr_getpos(cc->win, &px, &py);
for (;;) {
XMaskEvent(X_Dpy, MouseMask|ExposureMask, &ev);
XMaskEvent(X_Dpy, MOUSEMASK|ExposureMask, &ev);
switch (ev.type) {
case Expose:
client_draw_border(cc);
break;
case MotionNotify:
cc->geom.x = x + (ev.xmotion.x - mx);
cc->geom.y = y + (ev.xmotion.y - my);
client_move(cc);
cc->geom.x = ev.xmotion.x_root - px - cc->bwidth;
cc->geom.y = ev.xmotion.y_root - py - cc->bwidth;
cc->geom.x += client_snapcalc(cc->geom.x,
cc->geom.width, cc->sc->xmax,
cc->bwidth, Conf.snapdist);
cc->geom.y += client_snapcalc(cc->geom.y,
cc->geom.height, cc->sc->ymax,
cc->bwidth, Conf.snapdist);
/* don't move more than 60 times / second */
if ((ev.xmotion.time - ltime) > (1000 / 60)) {
ltime = ev.xmotion.time;
client_move(cc);
}
break;
case ButtonRelease:
if (ltime)
client_move(cc);
xu_ptr_ungrab();
return;
}
@ -184,6 +196,12 @@ mousefunc_window_lower(struct client_ctx *cc, void *arg)
client_lower(cc);
}
void
mousefunc_window_raise(struct client_ctx *cc, void *arg)
{
client_raise(cc);
}
void
mousefunc_window_hide(struct client_ctx *cc, void *arg)
{
@ -199,26 +217,24 @@ mousefunc_menu_group(struct client_ctx *cc, void *arg)
void
mousefunc_menu_unhide(struct client_ctx *cc, void *arg)
{
struct screen_ctx *sc;
struct client_ctx *old_cc;
struct menu *mi;
struct menu_q menuq;
char *wname;
sc = cc->sc;
old_cc = client_current();
TAILQ_INIT(&menuq);
TAILQ_FOREACH(cc, &Clientq, entry)
if (cc->flags & CLIENT_HIDDEN) {
if (cc->label != NULL)
wname = cc->label;
else
wname = cc->name;
wname = (cc->label) ? cc->label : cc->name;
if (wname == NULL)
continue;
XCALLOC(mi, struct menu);
strlcpy(mi->text, wname, sizeof(mi->text));
mi = xcalloc(1, sizeof(*mi));
(void)strlcpy(mi->text, wname, sizeof(mi->text));
mi->ctx = cc;
TAILQ_INSERT_TAIL(&menuq, mi, entry);
}
@ -226,7 +242,7 @@ mousefunc_menu_unhide(struct client_ctx *cc, void *arg)
if (TAILQ_EMPTY(&menuq))
return;
mi = menu_filter(&menuq, NULL, NULL, 0, NULL, NULL);
mi = menu_filter(sc, &menuq, NULL, NULL, 0, NULL, NULL);
if (mi != NULL) {
cc = (struct client_ctx *)mi->ctx;
client_unhide(cc);
@ -245,21 +261,24 @@ mousefunc_menu_unhide(struct client_ctx *cc, void *arg)
void
mousefunc_menu_cmd(struct client_ctx *cc, void *arg)
{
struct menu *mi;
struct menu_q menuq;
struct cmd *cmd;
struct screen_ctx *sc;
struct menu *mi;
struct menu_q menuq;
struct cmd *cmd;
sc = cc->sc;
TAILQ_INIT(&menuq);
TAILQ_FOREACH(cmd, &Conf.cmdq, entry) {
XCALLOC(mi, struct menu);
strlcpy(mi->text, cmd->label, sizeof(mi->text));
mi = xcalloc(1, sizeof(*mi));
(void)strlcpy(mi->text, cmd->label, sizeof(mi->text));
mi->ctx = cmd;
TAILQ_INSERT_TAIL(&menuq, mi, entry);
}
if (TAILQ_EMPTY(&menuq))
return;
mi = menu_filter(&menuq, NULL, NULL, 0, NULL, NULL);
mi = menu_filter(sc, &menuq, NULL, NULL, 0, NULL, NULL);
if (mi != NULL)
u_spawn(((struct cmd *)mi->ctx)->image);
else

112
parse.y
View File

@ -21,7 +21,11 @@
%{
#include <sys/param.h>
#include <sys/queue.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
@ -29,7 +33,6 @@
#include <stdlib.h>
#include <string.h>
#include "headers.h"
#include "calmwm.h"
TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files);
@ -67,6 +70,10 @@ typedef struct {
%token FONTNAME STICKY GAP MOUSEBIND
%token AUTOGROUP BIND COMMAND IGNORE
%token YES NO BORDERWIDTH MOVEAMOUNT
%token COLOR SNAPDIST
%token ACTIVEBORDER INACTIVEBORDER
%token GROUPBORDER UNGROUPBORDER
%token MENUBG MENUFG FONTCOLOR
%token ERROR
%token <v.string> STRING
%token <v.number> NUMBER
@ -77,6 +84,7 @@ typedef struct {
grammar : /* empty */
| grammar '\n'
| grammar main '\n'
| grammar color '\n'
| grammar error '\n' { file->errors++; }
;
@ -98,8 +106,8 @@ yesno : YES { $$ = 1; }
;
main : FONTNAME STRING {
free(conf->DefaultFontName);
conf->DefaultFontName = $2;
free(conf->font);
conf->font = $2;
}
| STICKY yesno {
if ($2 == 0)
@ -113,42 +121,29 @@ main : FONTNAME STRING {
| MOVEAMOUNT NUMBER {
conf->mamount = $2;
}
| SNAPDIST NUMBER {
conf->snapdist = $2;
}
| COMMAND STRING string {
conf_cmd_add(conf, $3, $2, 0);
free($2);
free($3);
}
| AUTOGROUP NUMBER STRING {
struct autogroupwin *aw;
char *p;
if ($2 < 0 || $2 > 9) {
free($3);
yyerror("autogroup number out of range: %d", $2);
YYERROR;
}
XCALLOC(aw, struct autogroupwin);
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);
group_make_autogroup(conf, $3, $2);
free($3);
}
| IGNORE STRING {
struct winmatch *wm;
XCALLOC(wm, struct winmatch);
strlcpy(wm->title, $2, sizeof(wm->title));
wm = xcalloc(1, sizeof(*wm));
(void)strlcpy(wm->title, $2, sizeof(wm->title));
TAILQ_INSERT_TAIL(&conf->ignoreq, wm, entry);
free($2);
@ -159,10 +154,10 @@ main : FONTNAME STRING {
free($3);
}
| GAP NUMBER NUMBER NUMBER NUMBER {
conf->gap_top = $2;
conf->gap_bottom = $3;
conf->gap_left = $4;
conf->gap_right = $5;
conf->gap.top = $2;
conf->gap.bottom = $3;
conf->gap.left = $4;
conf->gap.right = $5;
}
| MOUSEBIND STRING string {
conf_mousebind(conf, $2, $3);
@ -170,6 +165,39 @@ main : FONTNAME STRING {
free($3);
}
;
color : COLOR colors
;
colors : ACTIVEBORDER STRING {
free(conf->color[CWM_COLOR_BORDER_ACTIVE].name);
conf->color[CWM_COLOR_BORDER_ACTIVE].name = $2;
}
| INACTIVEBORDER STRING {
free(conf->color[CWM_COLOR_BORDER_INACTIVE].name);
conf->color[CWM_COLOR_BORDER_INACTIVE].name = $2;
}
| GROUPBORDER STRING {
free(conf->color[CWM_COLOR_BORDER_GROUP].name);
conf->color[CWM_COLOR_BORDER_GROUP].name = $2;
}
| UNGROUPBORDER STRING {
free(conf->color[CWM_COLOR_BORDER_UNGROUP].name);
conf->color[CWM_COLOR_BORDER_UNGROUP].name = $2;
}
| MENUBG STRING {
free(conf->color[CWM_COLOR_BG_MENU].name);
conf->color[CWM_COLOR_BG_MENU].name = $2;
}
| MENUFG STRING {
free(conf->color[CWM_COLOR_FG_MENU].name);
conf->color[CWM_COLOR_FG_MENU].name = $2;
}
| FONTCOLOR STRING {
free(conf->color[CWM_COLOR_FONT].name);
conf->color[CWM_COLOR_FONT].name = $2;
}
;
%%
struct keywords {
@ -202,17 +230,26 @@ lookup(char *s)
{
/* this has to be sorted always */
static const struct keywords keywords[] = {
{ "activeborder", ACTIVEBORDER},
{ "autogroup", AUTOGROUP},
{ "bind", BIND},
{ "borderwidth", BORDERWIDTH},
{ "color", COLOR},
{ "command", COMMAND},
{ "font", FONTCOLOR},
{ "fontname", FONTNAME},
{ "gap", GAP},
{ "groupborder", GROUPBORDER},
{ "ignore", IGNORE},
{ "inactiveborder", INACTIVEBORDER},
{ "menubg", MENUBG},
{ "menufg", MENUFG},
{ "mousebind", MOUSEBIND},
{ "moveamount", MOVEAMOUNT},
{ "no", NO},
{ "snapdist", SNAPDIST},
{ "sticky", STICKY},
{ "ungroupborder", UNGROUPBORDER},
{ "yes", YES}
};
const struct keywords *p;
@ -349,9 +386,10 @@ yylex(void)
return (0);
if (next == quotec || c == ' ' || c == '\t')
c = next;
else if (next == '\n')
else if (next == '\n') {
file->lineno++;
continue;
else
} else
lungetc(next);
} else if (c == quotec) {
*p = '\0';
@ -440,8 +478,6 @@ pushfile(const char *name)
nfile->name = xstrdup(name);
if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
if (errno != ENOENT)
warn("%s", nfile->name);
free(nfile->name);
free(nfile);
return (NULL);
@ -473,14 +509,14 @@ parse_config(const char *filename, struct conf *xconf)
{
int errors = 0;
XCALLOC(conf, struct conf);
conf = xcalloc(1, sizeof(*conf));
if ((file = pushfile(filename)) == NULL) {
free(conf);
return (-1);
}
strlcpy(conf->conf_path, filename, sizeof(conf->conf_path));
(void)strlcpy(conf->conf_path, filename, sizeof(conf->conf_path));
conf_init(conf);
@ -498,12 +534,15 @@ parse_config(const char *filename, struct conf *xconf)
struct winmatch *wm;
struct cmd *cmd;
struct mousebinding *mb;
int i;
conf_clear(xconf);
xconf->flags = conf->flags;
xconf->bwidth = conf->bwidth;
xconf->mamount = conf->mamount;
xconf->snapdist = conf->snapdist;
xconf->gap = conf->gap;
while ((cmd = TAILQ_FIRST(&conf->cmdq)) != NULL) {
TAILQ_REMOVE(&conf->cmdq, cmd, entry);
@ -530,14 +569,15 @@ parse_config(const char *filename, struct conf *xconf)
TAILQ_INSERT_TAIL(&xconf->mousebindingq, mb, entry);
}
strlcpy(xconf->termpath, conf->termpath,
(void)strlcpy(xconf->termpath, conf->termpath,
sizeof(xconf->termpath));
strlcpy(xconf->lockpath, conf->lockpath,
(void)strlcpy(xconf->lockpath, conf->lockpath,
sizeof(xconf->lockpath));
xconf->DefaultFontName = conf->DefaultFontName;
for (i = 0; i < CWM_COLOR_MAX; i++)
xconf->color[i].name = conf->color[i].name;
bcopy(&(conf->gap_top), &(xconf->gap_top), sizeof(int) * 4);
xconf->font = conf->font;
}
free(conf);

View File

@ -15,14 +15,20 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id$
* $OpenBSD$
*/
#include "headers.h"
#include "calmwm.h"
#include <sys/param.h>
#include <sys/queue.h>
extern struct screen_ctx_q Screenq;
extern struct screen_ctx *Curscreen;
#include <err.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "calmwm.h"
struct screen_ctx *
screen_fromroot(Window rootwin)
@ -37,22 +43,13 @@ screen_fromroot(Window rootwin)
return (TAILQ_FIRST(&Screenq));
}
struct screen_ctx *
screen_current(void)
{
return (Curscreen);
}
void
screen_updatestackingorder(void)
screen_updatestackingorder(struct screen_ctx *sc)
{
Window *wins, w0, w1;
struct screen_ctx *sc;
struct client_ctx *cc;
u_int nwins, i, s;
sc = screen_current();
if (!XQueryTree(X_Dpy, sc->rootwin, &w0, &w1, &wins, &nwins))
return;
@ -78,10 +75,10 @@ screen_init_xinerama(struct screen_ctx *sc)
HasXinerama = 0;
sc->xinerama_no = 0;
}
info = XineramaQueryScreens(X_Dpy, &no);
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)
HasXinerama = 0;
return;
@ -104,9 +101,33 @@ screen_find_xinerama(struct screen_ctx *sc, int x, int y)
for (i = 0; i < sc->xinerama_no; i++) {
info = &sc->xinerama[i];
if (x > info->x_org && x < info->x_org + info->width &&
y > info->y_org && y < info->y_org + info->height)
if (x >= info->x_org && x < info->x_org + info->width &&
y >= info->y_org && y < info->y_org + info->height)
return (info);
}
return (NULL);
}
void
screen_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
*
* 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.
@ -14,15 +15,24 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* 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 <fnmatch.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "calmwm.h"
#define SearchMask (KeyPressMask|ExposureMask)
static int _strsubmatch(char *, char *, int);
static int strsubmatch(char *, char *, int);
/*
* Match: label, title, class.
@ -33,13 +43,10 @@ search_match_client(struct menu_q *menuq, struct menu_q *resultq, char *search)
{
struct winname *wn;
struct menu *mi, *tierp[4], *before = NULL;
int ntiers;
ntiers = sizeof(tierp) / sizeof(tierp[0]);
TAILQ_INIT(resultq);
memset(tierp, 0, sizeof(tierp));
(void)memset(tierp, 0, sizeof(tierp));
/*
* In order of rank:
@ -54,7 +61,7 @@ search_match_client(struct menu_q *menuq, struct menu_q *resultq, char *search)
struct client_ctx *cc = mi->ctx;
/* First, try to match on labels. */
if (cc->label != NULL && _strsubmatch(search, cc->label, 0)) {
if (cc->label != NULL && strsubmatch(search, cc->label, 0)) {
cc->matchname = cc->label;
tier = 0;
}
@ -62,19 +69,15 @@ search_match_client(struct menu_q *menuq, struct menu_q *resultq, char *search)
/* Then, on window names. */
if (tier < 0) {
TAILQ_FOREACH_REVERSE(wn, &cc->nameq, winname_q, entry)
if (_strsubmatch(search, wn->name, 0)) {
if (strsubmatch(search, wn->name, 0)) {
cc->matchname = wn->name;
tier = 2;
break;
}
}
/*
* See if there is a match on the window class
* name.
*/
if (tier < 0 && _strsubmatch(search, cc->app_class, 0)) {
/* Then if there is a match on the window class name. */
if (tier < 0 && strsubmatch(search, cc->app_class, 0)) {
cc->matchname = cc->app_class;
tier = 3;
}
@ -87,16 +90,14 @@ search_match_client(struct menu_q *menuq, struct menu_q *resultq, char *search)
* window. Furthermore, this is denoted by a "!" when
* printing the window name in the search menu.
*/
if (cc == client_current() && tier < ntiers - 1)
if (cc == client_current() && tier < nitems(tierp) - 1)
tier++;
/*
* Clients that are hidden get ranked one up.
*/
/* Clients that are hidden get ranked one up. */
if (cc->flags & CLIENT_HIDDEN && tier > 0)
tier--;
assert(tier < ntiers);
assert(tier < nitems(tierp));
/*
* If you have a tierp, insert after it, and make it
@ -105,7 +106,6 @@ search_match_client(struct menu_q *menuq, struct menu_q *resultq, char *search)
* Always make your current tierp the newly inserted
* entry.
*/
for (t = tier; t >= 0 && ((before = tierp[t]) == NULL); t--)
;
@ -134,7 +134,8 @@ search_print_client(struct menu *mi, int list)
if (list)
cc->matchname = cc->name;
snprintf(mi->print, sizeof(mi->print), "%c%s", flag, cc->matchname);
(void)snprintf(mi->print, sizeof(mi->print), "%c%s", flag,
cc->matchname);
if (!list && cc->matchname != cc->name &&
strlen(mi->print) < sizeof(mi->print) - 1) {
@ -154,8 +155,8 @@ search_print_client(struct menu *mi, int list)
diff = strlen(cc->name);
}
strlcpy(buf, mi->print, sizeof(buf));
snprintf(mi->print, sizeof(mi->print),
(void)strlcpy(buf, mi->print, sizeof(buf));
(void)snprintf(mi->print, sizeof(mi->print),
"%s:%.*s%s", buf, diff, cc->name, marker);
}
}
@ -168,7 +169,7 @@ search_match_text(struct menu_q *menuq, struct menu_q *resultq, char *search)
TAILQ_INIT(resultq);
TAILQ_FOREACH(mi, menuq, entry)
if (_strsubmatch(search, mi->text, 0))
if (strsubmatch(search, mi->text, 0))
TAILQ_INSERT_TAIL(resultq, mi, resultentry);
}
@ -180,8 +181,9 @@ search_match_exec(struct menu_q *menuq, struct menu_q *resultq, char *search)
TAILQ_INIT(resultq);
TAILQ_FOREACH(mi, menuq, entry) {
if (_strsubmatch(search, mi->text, 1) == 0)
continue;
if (strsubmatch(search, mi->text, 1) == 0 &&
fnmatch(search, mi->text, 0) == FNM_NOMATCH)
continue;
for (mj = TAILQ_FIRST(resultq); mj != NULL;
mj = TAILQ_NEXT(mj, resultentry)) {
if (strcasecmp(mi->text, mj->text) < 0) {
@ -195,7 +197,7 @@ search_match_exec(struct menu_q *menuq, struct menu_q *resultq, char *search)
}
static int
_strsubmatch(char *sub, char *str, int zeroidx)
strsubmatch(char *sub, char *str, int zeroidx)
{
size_t len, sublen;
u_int n, flen;

22
util.c
View File

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

373
xevents.c
View File

@ -15,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id$
* $OpenBSD$
*/
/*
@ -24,16 +24,54 @@
* management of the xevent's.
*/
#include "headers.h"
#include <sys/param.h>
#include <sys/queue.h>
#include <err.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "calmwm.h"
/*
* NOTE: in reality, many of these should move to client.c now that
* we've got this nice event layer.
*/
static void xev_handle_maprequest(XEvent *);
static void xev_handle_unmapnotify(XEvent *);
static void xev_handle_destroynotify(XEvent *);
static void xev_handle_configurerequest(XEvent *);
static void xev_handle_propertynotify(XEvent *);
static void xev_handle_enternotify(XEvent *);
static void xev_handle_leavenotify(XEvent *);
static void xev_handle_buttonpress(XEvent *);
static void xev_handle_buttonrelease(XEvent *);
static void xev_handle_keypress(XEvent *);
static void xev_handle_keyrelease(XEvent *);
static void xev_handle_expose(XEvent *);
static void xev_handle_clientmessage(XEvent *);
static void xev_handle_randr(XEvent *);
static void xev_handle_mappingnotify(XEvent *);
void
xev_handle_maprequest(struct xevent *xev, XEvent *ee)
void (*xev_handlers[LASTEvent])(XEvent *) = {
[MapRequest] = xev_handle_maprequest,
[UnmapNotify] = xev_handle_unmapnotify,
[ConfigureRequest] = xev_handle_configurerequest,
[PropertyNotify] = xev_handle_propertynotify,
[EnterNotify] = xev_handle_enternotify,
[LeaveNotify] = xev_handle_leavenotify,
[ButtonPress] = xev_handle_buttonpress,
[ButtonRelease] = xev_handle_buttonrelease,
[KeyPress] = xev_handle_keypress,
[KeyRelease] = xev_handle_keyrelease,
[Expose] = xev_handle_expose,
[DestroyNotify] = xev_handle_destroynotify,
[ClientMessage] = xev_handle_clientmessage,
[MappingNotify] = xev_handle_mappingnotify,
};
static void
xev_handle_maprequest(XEvent *ee)
{
XMapRequestEvent *e = &ee->xmaprequest;
struct client_ctx *cc = NULL, *old_cc;
@ -47,12 +85,12 @@ xev_handle_maprequest(struct xevent *xev, XEvent *ee)
cc = client_new(e->window, screen_fromroot(xattr.root), 1);
}
client_ptrwarp(cc);
xev_register(xev);
if ((cc->flags & CLIENT_IGNORE) == 0)
client_ptrwarp(cc);
}
void
xev_handle_unmapnotify(struct xevent *xev, XEvent *ee)
static void
xev_handle_unmapnotify(XEvent *ee)
{
XUnmapEvent *e = &ee->xunmap;
XEvent ev;
@ -76,24 +114,20 @@ xev_handle_unmapnotify(struct xevent *xev, XEvent *ee)
client_hide(cc);
}
XUngrabServer(X_Dpy);
xev_register(xev);
}
void
xev_handle_destroynotify(struct xevent *xev, XEvent *ee)
static void
xev_handle_destroynotify(XEvent *ee)
{
XDestroyWindowEvent *e = &ee->xdestroywindow;
struct client_ctx *cc;
if ((cc = client_find(e->window)) != NULL)
client_delete(cc);
xev_register(xev);
}
void
xev_handle_configurerequest(struct xevent *xev, XEvent *ee)
static void
xev_handle_configurerequest(XEvent *ee)
{
XConfigureRequestEvent *e = &ee->xconfigurerequest;
struct client_ctx *cc;
@ -101,7 +135,7 @@ xev_handle_configurerequest(struct xevent *xev, XEvent *ee)
XWindowChanges wc;
if ((cc = client_find(e->window)) != NULL) {
sc = CCTOSC(cc);
sc = cc->sc;
if (e->value_mask & CWWidth)
cc->geom.width = e->width;
@ -127,7 +161,7 @@ xev_handle_configurerequest(struct xevent *xev, XEvent *ee)
wc.border_width = cc->bwidth;
XConfigureWindow(X_Dpy, cc->win, e->value_mask, &wc);
xev_reconfig(cc);
xu_configure(cc);
} else {
/* let it do what it wants, it'll be ours when we map it. */
wc.x = e->x;
@ -140,79 +174,65 @@ xev_handle_configurerequest(struct xevent *xev, XEvent *ee)
XConfigureWindow(X_Dpy, e->window, e->value_mask, &wc);
}
xev_register(xev);
}
void
xev_handle_propertynotify(struct xevent *xev, XEvent *ee)
static void
xev_handle_propertynotify(XEvent *ee)
{
XPropertyEvent *e = &ee->xproperty;
struct screen_ctx *sc;
struct client_ctx *cc;
long tmp;
if ((cc = client_find(e->window)) != NULL) {
switch (e->atom) {
case XA_WM_NORMAL_HINTS:
XGetWMNormalHints(X_Dpy, cc->win, cc->size, &tmp);
client_getsizehints(cc);
break;
case XA_WM_NAME:
client_setname(cc);
break;
case XA_WM_TRANSIENT_FOR:
client_transient(cc);
break;
default:
/* do nothing */
break;
}
} else {
TAILQ_FOREACH(sc, &Screenq, entry)
if (sc->rootwin == e->window)
goto test;
return;
test:
if (e->atom == _NET_DESKTOP_NAMES)
group_update_names(sc);
}
xev_register(xev);
}
void
xev_reconfig(struct client_ctx *cc)
{
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
xev_handle_enternotify(struct xevent *xev, XEvent *ee)
static void
xev_handle_enternotify(XEvent *ee)
{
XCrossingEvent *e = &ee->xcrossing;
struct client_ctx *cc;
if ((cc = client_find(e->window)) != NULL)
client_setactive(cc, 1);
xev_register(xev);
}
void
xev_handle_leavenotify(struct xevent *xev, XEvent *ee)
static void
xev_handle_leavenotify(XEvent *ee)
{
client_leave(NULL);
xev_register(xev);
}
/* We can split this into two event handlers. */
void
xev_handle_buttonpress(struct xevent *xev, XEvent *ee)
static void
xev_handle_buttonpress(XEvent *ee)
{
XButtonEvent *e = &ee->xbutton;
struct client_ctx *cc;
struct client_ctx *cc, fakecc;
struct screen_ctx *sc;
struct mousebinding *mb;
@ -228,38 +248,32 @@ xev_handle_buttonpress(struct xevent *xev, XEvent *ee)
}
if (mb == NULL)
goto out;
return;
if (mb->context == MOUSEBIND_CTX_ROOT) {
if (e->window != sc->rootwin)
goto out;
} else if (mb->context == MOUSEBIND_CTX_WIN) {
cc = client_find(e->window);
if (cc == NULL)
goto out;
}
return;
cc = &fakecc;
cc->sc = screen_fromroot(e->window);
} else if (cc == NULL) /* (mb->context == MOUSEBIND_CTX_WIN */
return;
(*mb->callback)(cc, e);
out:
xev_register(xev);
}
void
xev_handle_buttonrelease(struct xevent *xev, XEvent *ee)
static void
xev_handle_buttonrelease(XEvent *ee)
{
struct client_ctx *cc;
if ((cc = client_current()) != NULL)
group_sticky_toggle_exit(cc);
xev_register(xev);
}
void
xev_handle_keypress(struct xevent *xev, XEvent *ee)
static void
xev_handle_keypress(XEvent *ee)
{
XKeyEvent *e = &ee->xkey;
struct client_ctx *cc = NULL;
struct client_ctx *cc = NULL, fakecc;
struct keybinding *kb;
KeySym keysym, skeysym;
int modshift;
@ -286,25 +300,24 @@ xev_handle_keypress(struct xevent *xev, XEvent *ee)
}
if (kb == NULL)
goto out;
if ((kb->flags & (KBFLAG_NEEDCLIENT)) &&
(cc = client_find(e->window)) == NULL &&
(cc = client_current()) == NULL)
if (kb->flags & KBFLAG_NEEDCLIENT)
goto out;
return;
if (kb->flags & KBFLAG_NEEDCLIENT) {
if (((cc = client_find(e->window)) == NULL) &&
(cc = client_current()) == NULL)
return;
} else {
cc = &fakecc;
cc->sc = screen_fromroot(e->window);
}
(*kb->callback)(cc, &kb->argument);
out:
xev_register(xev);
}
/*
* This is only used for the alt suppression detection.
*/
void
xev_handle_keyrelease(struct xevent *xev, XEvent *ee)
static void
xev_handle_keyrelease(XEvent *ee)
{
XKeyEvent *e = &ee->xkey;
struct screen_ctx *sc;
@ -316,7 +329,7 @@ xev_handle_keyrelease(struct xevent *xev, XEvent *ee)
keysym = XKeycodeToKeysym(X_Dpy, e->keycode, 0);
if (keysym != XK_Alt_L && keysym != XK_Alt_R)
goto out;
return;
sc->altpersist = 0;
@ -330,13 +343,10 @@ xev_handle_keyrelease(struct xevent *xev, XEvent *ee)
group_sticky_toggle_exit(cc);
XUngrabKeyboard(X_Dpy, CurrentTime);
}
out:
xev_register(xev);
}
void
xev_handle_clientmessage(struct xevent *xev, XEvent *ee)
static void
xev_handle_clientmessage(XEvent *ee)
{
XClientMessageEvent *e = &ee->xclient;
Atom xa_wm_change_state;
@ -345,37 +355,36 @@ xev_handle_clientmessage(struct xevent *xev, XEvent *ee)
xa_wm_change_state = XInternAtom(X_Dpy, "WM_CHANGE_STATE", False);
if ((cc = client_find(e->window)) == NULL)
goto out;
return;
if (e->message_type == xa_wm_change_state && e->format == 32 &&
e->data.l[0] == IconicState)
client_hide(cc);
out:
xev_register(xev);
}
void
xev_handle_randr(struct xevent *xev, XEvent *ee)
static void
xev_handle_randr(XEvent *ee)
{
XRRScreenChangeNotifyEvent *rev = (XRRScreenChangeNotifyEvent *)ee;
struct client_ctx *cc;
struct screen_ctx *sc;
int i;
if ((cc = client_find(rev->window)) != NULL) {
XRRUpdateConfiguration(ee);
sc = CCTOSC(cc);
sc->xmax = rev->width;
sc->ymax = rev->height;
screen_init_xinerama(sc);
i = XRRRootToScreen(X_Dpy, rev->root);
TAILQ_FOREACH(sc, &Screenq, entry) {
if (sc->which == (u_int)i) {
XRRUpdateConfiguration(ee);
screen_update_geometry(sc, rev->width, rev->height);
screen_init_xinerama(sc);
}
}
}
/*
/*
* Called when the keymap has changed.
* Ungrab all keys, reload keymap and then regrab
*/
void
xev_handle_mapping(struct xevent *xev, XEvent *ee)
static void
xev_handle_mappingnotify(XEvent *ee)
{
XMappingEvent *e = &ee->xmapping;
struct keybinding *kb;
@ -387,160 +396,30 @@ xev_handle_mapping(struct xevent *xev, XEvent *ee)
TAILQ_FOREACH(kb, &Conf.keybindingq, entry)
conf_grab(&Conf, kb);
xev_register(xev);
}
/*
* X Event handling
*/
static struct xevent_q _xevq, _xevq_putaway;
static short _xev_q_lock = 0;
volatile sig_atomic_t _xev_quit = 0;
void
xev_init(void)
{
TAILQ_INIT(&_xevq);
TAILQ_INIT(&_xevq_putaway);
}
struct xevent *
xev_new(Window *win, Window *root,
int type, void (*cb)(struct xevent *, XEvent *), void *arg)
{
struct xevent *xev;
XMALLOC(xev, struct xevent);
xev->xev_win = win;
xev->xev_root = root;
xev->xev_type = type;
xev->xev_cb = cb;
xev->xev_arg = arg;
return (xev);
}
void
xev_register(struct xevent *xev)
{
struct xevent_q *xq;
xq = _xev_q_lock ? &_xevq_putaway : &_xevq;
TAILQ_INSERT_TAIL(xq, xev, entry);
}
void
_xev_reincorporate(void)
{
struct xevent *xev;
while ((xev = TAILQ_FIRST(&_xevq_putaway)) != NULL) {
TAILQ_REMOVE(&_xevq_putaway, xev, entry);
TAILQ_INSERT_TAIL(&_xevq, xev, entry);
}
}
void
xev_handle_expose(struct xevent *xev, XEvent *ee)
static void
xev_handle_expose(XEvent *ee)
{
XExposeEvent *e = &ee->xexpose;
struct client_ctx *cc;
if ((cc = client_find(e->window)) != NULL && e->count == 0)
client_draw_border(cc);
xev_register(xev);
}
#define ASSIGN(xtype) do { \
root = e. xtype .root; \
win = e. xtype .window; \
} while (0)
#define ASSIGN1(xtype) do { \
win = e. xtype .window; \
} while (0)
volatile sig_atomic_t xev_quit = 0;
void
xev_loop(void)
{
Window win, root;
XEvent e;
struct xevent *xev = NULL, *nextxev;
int type;
while (_xev_quit == 0) {
#ifdef DIAGNOSTIC
if (TAILQ_EMPTY(&_xevq))
errx(1, "X event queue empty");
#endif
while (xev_quit == 0) {
XNextEvent(X_Dpy, &e);
type = e.type;
win = root = 0;
switch (type) {
case MapRequest:
ASSIGN1(xmaprequest);
break;
case UnmapNotify:
ASSIGN1(xunmap);
break;
case ConfigureRequest:
ASSIGN1(xconfigurerequest);
break;
case PropertyNotify:
ASSIGN1(xproperty);
break;
case EnterNotify:
case LeaveNotify:
ASSIGN(xcrossing);
break;
case ButtonPress:
ASSIGN(xbutton);
break;
case ButtonRelease:
ASSIGN(xbutton);
break;
case KeyPress:
case KeyRelease:
ASSIGN(xkey);
break;
case DestroyNotify:
ASSIGN1(xdestroywindow);
break;
case ClientMessage:
ASSIGN1(xclient);
break;
default:
if (e.type == Randr_ev)
xev_handle_randr(xev, &e);
break;
}
/*
* Now, search for matches, and call each of them.
*/
_xev_q_lock = 1;
for (xev = TAILQ_FIRST(&_xevq); xev != NULL; xev = nextxev) {
nextxev = TAILQ_NEXT(xev, entry);
if ((type != xev->xev_type && xev->xev_type != 0) ||
(xev->xev_win != NULL && win != *xev->xev_win) ||
(xev->xev_root != NULL && root != *xev->xev_root))
continue;
TAILQ_REMOVE(&_xevq, xev, entry);
(*xev->xev_cb)(xev, &e);
}
_xev_q_lock = 0;
_xev_reincorporate();
if (e.type - Randr_ev == RRScreenChangeNotify)
xev_handle_randr(&e);
else if (e.type < LASTEvent && xev_handlers[e.type] != NULL)
(*xev_handlers[e.type])(&e);
}
}
#undef ASSIGN
#undef ASSIGN1

View File

@ -15,10 +15,19 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* 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"
void *

155
xutil.c
View File

@ -15,13 +15,22 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* 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"
unsigned int ign_mods[] = { 0, LockMask, Mod2Mask, Mod2Mask | LockMask };
static unsigned int ign_mods[] = { 0, LockMask, Mod2Mask, Mod2Mask | LockMask };
int
xu_ptr_grab(Window win, int mask, Cursor curs)
@ -48,9 +57,9 @@ void
xu_btn_grab(Window win, int mask, u_int btn)
{
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,
False, ButtonMask, GrabModeAsync,
False, BUTTONMASK, GrabModeAsync,
GrabModeSync, None, None);
}
@ -58,7 +67,7 @@ void
xu_btn_ungrab(Window win, int mask, u_int btn)
{
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);
}
@ -89,7 +98,7 @@ xu_key_grab(Window win, int mask, int keysym)
(XKeycodeToKeysym(X_Dpy, code, 1) == keysym))
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,
True, GrabModeAsync, GrabModeAsync);
}
@ -105,34 +114,53 @@ xu_key_ungrab(Window win, int mask, int keysym)
(XKeycodeToKeysym(X_Dpy, code, 1) == keysym))
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);
}
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;
memset(&e, 0, sizeof(e));
(void)memset(&e, 0, sizeof(e));
e.xclient.type = ClientMessage;
e.xclient.window = cc->win;
e.xclient.window = win;
e.xclient.message_type = atm;
e.xclient.format = 32;
e.xclient.data.l[0] = val;
e.xclient.data.l[1] = CurrentTime;
XSendEvent(X_Dpy, cc->win, False, 0, &e);
XSendEvent(X_Dpy, win, False, 0, &e);
}
int
xu_getprop(struct client_ctx *cc, Atom atm, Atom type, long len, u_char **p)
xu_getprop(Window win, Atom atm, Atom type, long len, u_char **p)
{
Atom realtype;
u_long n, extra;
int format;
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)
return (-1);
@ -142,12 +170,44 @@ xu_getprop(struct client_ctx *cc, Atom atm, Atom type, long len, u_char **p)
return (n);
}
int
xu_getstrprop(Window win, Atom atm, char **text) {
XTextProperty prop;
char **list;
int nitems = 0;
*text = NULL;
XGetTextProperty(X_Dpy, win, &prop, atm);
if (!prop.nitems)
return (0);
if (Xutf8TextPropertyToTextList(X_Dpy, &prop, &list,
&nitems) == Success && nitems > 0 && *list) {
if (nitems > 1) {
XTextProperty prop2;
if (Xutf8TextListToTextProperty(X_Dpy, list, nitems,
XUTF8StringStyle, &prop2) == Success) {
*text = xstrdup(prop2.value);
XFree(prop2.value);
}
} else {
*text = xstrdup(*list);
}
XFreeStringList(list);
}
XFree(prop.value);
return (nitems);
}
int
xu_getstate(struct client_ctx *cc, int *state)
{
long *p = NULL;
if (xu_getprop(cc, WM_STATE, WM_STATE, 2L, (u_char **)&p) <= 0)
if (xu_getprop(cc->win, WM_STATE, WM_STATE, 2L, (u_char **)&p) <= 0)
return (-1);
*state = (int)*p;
@ -161,8 +221,8 @@ xu_setstate(struct client_ctx *cc, int state)
{
long dat[2];
dat[0] = (long)state;
dat[1] = (long)None;
dat[0] = state;
dat[1] = None;
cc->state = state;
XChangeProperty(X_Dpy, cc->win, WM_STATE, WM_STATE, 32,
@ -176,7 +236,21 @@ char *atoms[CWM_NO_ATOMS] = {
"WM_TAKE_FOCUS",
"WM_PROTOCOLS",
"_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
@ -184,3 +258,48 @@ xu_getatoms(void)
{
XInternAtoms(X_Dpy, atoms, CWM_NO_ATOMS, False, cwm_atoms);
}
void
xu_setwmname(struct screen_ctx *sc)
{
/*
* set up the _NET_SUPPORTED hint with all netwm atoms that we
* know about.
*/
XChangeProperty(X_Dpy, sc->rootwin, _NET_SUPPORTED, XA_ATOM, 32,
PropModeReplace, (unsigned char *)&_NET_SUPPORTED,
CWM_NO_ATOMS - CWM_NETWM_START);
/*
* netwm spec says that to prove that the hint is not stale you must
* provide _NET_SUPPORTING_WM_CHECK containing a window (we use the
* menu window). The property must be set on the root window and the
* window itself, the window also must have _NET_WM_NAME set with the
* window manager name.
*/
XChangeProperty(X_Dpy, sc->rootwin, _NET_SUPPORTING_WM_CHECK,
XA_WINDOW, 32, PropModeReplace, (unsigned char *)&sc->menuwin, 1);
XChangeProperty(X_Dpy, sc->menuwin, _NET_SUPPORTING_WM_CHECK,
XA_WINDOW, 32, PropModeReplace, (unsigned char *)&sc->menuwin, 1);
XChangeProperty(X_Dpy, sc->menuwin, _NET_WM_NAME, UTF8_STRING,
8, PropModeReplace, WMNAME, strlen(WMNAME));
}
unsigned long
xu_getcolor(struct screen_ctx *sc, char *name)
{
XColor color, tmp;
if (!XAllocNamedColor(X_Dpy, DefaultColormap(X_Dpy, sc->which),
name, &color, &tmp)) {
warnx("XAllocNamedColor error: '%s'", name);
return 0;
}
return color.pixel;
}
void
xu_freecolor(struct screen_ctx *sc, unsigned long pixel)
{
XFreeColors(X_Dpy, DefaultColormap(X_Dpy, sc->which), &pixel, 1, 0L);
}