243 Commits

Author SHA1 Message Date
schwarze
a119fe5240 cvsimport 2010-09-25 21:58:18 +00:00
Christian Neukirchen
f2e8fad75c cvsimport 2010-09-25 22:21:23 +00:00
schwarze
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
schwarze
ff3df256a1 s/\.Pb/.Pp/ for correct vertical spacing; found by mandoc -Tlint 2010-09-25 21:48:08 +00:00
okan
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
okan
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
okan
917bce4b8d spacing nits 2010-09-25 20:01:27 +00:00
okan
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
okan
aaca5b7e45 fix backwards example (after r1.45 of group.c); noticed by phessler@
ok oga@ phessler@
2010-07-23 15:13:00 +00:00
okan
2a5e1791d4 fix window name and class to match cwmrc(5); from Holger Mikolon - thanks!
ok oga@
2010-06-28 12:29:04 +00:00
okan
e0c9657773 cvsimport 2010-05-22 22:32:08 +00:00
okan
85a53083cb initialize nitems
ok oga@
2010-05-22 22:32:08 +00:00
okan
72e6d2d0a9 replace XFetchName() with something more intelligent which attempts to
use the appropriate netwm Atom first, as well as deal with utf8.

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

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

ok okan@. Prompted by something todd noticed.
2010-04-12 16:17:46 +00:00
okan
b12e6fc5cd clean up a few xu_* functions to just accept what they need (Window).
ok oga@
2010-04-11 16:51:26 +00:00
schwarze
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
Christian Neukirchen
d90ab51111 Add missing functions 2010-02-21 19:18:12 +01:00
Christian Neukirchen
50aff37f50 Import linux.patch
Patch largely based on cwmbuild.sh from http://tamentis.com/hacks/cwm/
written by Bertrand Janin, updated by Christian Neukirchen.
2010-02-21 19:15:27 +01:00
okan
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
stsp
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
okan
e88bda0df5 - allow per-screen gap; not (yet) user configurable.
- teach _NET_WORKAREA about gap.

ok oga@
2010-01-27 03:04:50 +00:00
okan
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
okan
09a2d7fb98 spacing 2009-12-15 03:38:11 +00:00
okan
b27c3c22b5 pull these headers only into files that need them.
ok oga@
2009-12-15 03:34:34 +00:00
okan
2ad2b5f31d rid ourselves of these functional macros; convert to real functions.
ok oga@
2009-12-15 03:26:22 +00:00
okan
597cb25820 mostly irrelevant now, so remove.
ok oga@
2009-12-15 03:25:22 +00:00
okan
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
okan
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
okan
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
okan
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
okan
ab4d36531c we already have sc from the passed cc, so just used that instead.
ok oga@
2009-12-07 19:45:36 +00:00
okan
892e1e1c0d be consistent
ok oga@
2009-12-07 19:44:31 +00:00
okan
4e2014863b remove unused extern
ok oga@
2009-12-07 19:42:59 +00:00
tobias
42bf29fb20 style (whitespaces)
ok oga, okan
2009-11-28 17:52:12 +00:00
tobias
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
okan
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
tobias
38ad2e1d9c style
ok oga
2009-09-05 14:10:11 +00:00
okan
7295c51155 unroll the CCTOSC macro; from Thomas Pfaff
ok oga@
2009-08-27 01:38:08 +00:00
okan
b9f8367089 static; ok oga@ 2009-08-25 12:05:11 +00:00
okan
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
okan
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
okan
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
okan
82911249e2 remove unnecessary Ar macros
ok jmc@
2009-08-08 17:27:51 +00:00
okan
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
okan
f44862be9c static local functions and data; almost identical diff from Thomas Pfaff
ok oga@
2009-06-26 12:21:58 +00:00
okan
b13d592c57 tidy up startup/init routines
ok oga@
2009-06-23 21:52:38 +00:00
okan
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
okan
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
okan
18c7d89c98 spacing 2009-06-20 00:19:56 +00:00
sobrado
ee59e4a5a1 `exec'' and `ssh'' are lowercase.
ok martynas@
2009-06-19 10:43:49 +00:00
sobrado
055b244bb4 items on the first list should have full stops too.
ok martynas@
2009-06-18 20:44:40 +00:00
sobrado
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
okan
11b4b7fec6 remove unnecessary casts; from Thomas Pfaff
ok oga@
2009-06-17 13:08:37 +00:00
okan
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
okan
d7589ca80b move like defines to a central, logical location; no binary change.
aok oga@
2009-06-17 12:30:17 +00:00
okan
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
okan
d1b84c5415 re-order a bit for readability.
"if it makes you happy" oga@
2009-05-30 00:30:17 +00:00
okan
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
sthen
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
okan
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
okan
9be7726606 redraw all borders at once on reload
"sure" oga@
2009-05-17 23:54:17 +00:00
okan
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
okan
5d51c8e0e5 minor bit of knf, just to be consistent; oga@ doesn't mind that much 2009-05-17 23:37:52 +00:00
okan
4c10afe2cc unbreak 2009-05-17 22:48:47 +00:00
sthen
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
sthen
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
okan
fbb1edf2b3 right and middle mouse buttons swapped; from rgouveia@cosmico.net 2009-05-04 22:01:35 +00:00
okan
64f0038db7 no need to use the global here.
ok todd@ oga@
2009-05-04 19:13:33 +00:00
okan
4f34392258 properly document menu_unhide; tweak a patch from rgouveia@cosmico.net - thanks.
ok oga@
2009-05-04 18:05:21 +00:00
okan
655c33c489 fix the other 50% of xrandr cases; reported by sthen@
"commit that" oga@, ok sthen@
2009-05-01 17:50:20 +00:00
okan
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
okan
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
okan
8a490fc270 we include sys/param.h, so remove sys/types.h; sort while here.
ok oga@
2009-04-12 23:51:10 +00:00
martynas
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
martynas
17ae65adc5 add 'moveamount' to cwmrc; it sets keyboard movement amount, making
it more useful on large screens
manpage tweak & ok jmc@
ok okan@, oga@
2009-02-07 21:07:00 +00:00
martynas
507b65a27f remove leftover from mdoc.samples; ok jmc@ 2009-02-07 16:59:11 +00:00
martynas
4fe12f528c fix off-by-one in geom.[xy], after pwin changes. keyboard movement
to the rightmost or bottommost corners would confuse cwm:
- there's no way to get the window back
- tab cycling breaks
ok okan@, oga@
2009-02-03 22:20:31 +00:00
okan
6ad198022b remove Nscreens and x_screenname() - we really don't need them.
ok oga@
2009-01-27 02:16:20 +00:00
oga
c750462d13 One of the most annoying things to do was restart cwm and lose all of
your group state. Fix this up by using an X Atom (_CWM_GRP) to store the
name of the group that we're using (the name, not the number is because
at one point we may make the group numbers dynamic). I've been talking
about this since c2k8. so CM-w means you keep all of your windows grouped
properly.

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

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

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

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

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

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

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

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

Todd confirmed this fixes the `race'.

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

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

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

lots of feedback from todd and oga - thanks!

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

based on a heavily modified diff from Martynas.

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

Fixes a bug i introduced in the last commit here.

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

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

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

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

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

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

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

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

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

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

brought up by todd@

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

from Edd Barrett

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

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

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

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

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

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

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

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

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

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

allows one to exec with mixed case unmatched commands.

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

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

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

Based on an initial diff from Andrew Fresh, thanks!

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

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

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

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

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

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

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

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

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

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

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

Kill some unused variables while i'm here.

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

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

feedback from jmc@ - thanks!

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

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

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

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

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

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

This means constructs like this work in .cwmrc:

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

or alternatively:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

knocks about 4k off the i386 binary for me.

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

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

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

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

Fixes for these will be forthcoming.

ok simon@.
2008-03-18 00:48:56 +00:00
sthen
a466ddaa2d typo fix. ok oga 2008-03-14 14:38:10 +00:00
29 changed files with 4790 additions and 3924 deletions

View File

@@ -1,25 +1,54 @@
# $OpenBSD$
.include <bsd.own.mk>
X11BASE?= /usr/X11R6
#.include <bsd.xconf.mk>
PROG= cwm
SRCS= calmwm.c screen.c xmalloc.c client.c grab.c search.c \
util.c xutil.c conf.c input.c xevents.c group.c \
kbfunc.c font.c
BINDIR= /usr/bin
CPPFLAGS+= -I${X11BASE}/include -I${X11BASE}/include/freetype2
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 \
kbfunc.c mousefunc.c font.c parse.y
OBJS= calmwm.o screen.o xmalloc.o client.o menu.o \
search.o util.o xutil.o conf.o input.o xevents.o group.o \
kbfunc.o mousefunc.o font.o strlcpy.o strlcat.o y.tab.o \
strtonum.o fgetln.o
X11BASE= /usr
CPPFLAGS+= -I${X11BASE}/include -I${X11BASE}/include/freetype2 -I.
CFLAGS+= -Wall
LDADD+= -L${X11BASE}/lib -lXft -lXrender -lX11 -lXau -lXdmcp \
-lfontconfig -lexpat -lfreetype -lz -lX11 -lXau -lXdmcp -lXext
-lfontconfig -lexpat -lfreetype -lz -lXinerama -lXrandr -lXext
MANDIR= ${X11BASE}/man/cat
MAN= cwm.1 cwmrc.5
CLEANFILES= cwm.cat1
CLEANFILES= cwm.cat1 cwmrc.cat5
obj: _xenocara_obj
.include <bsd.prog.mk>
.include <bsd.xorg.mk>
all: $(PROG)
clean:
rm -rf $(OBJS) $(PROG) y.tab.c
y.tab.c: parse.y
byacc parse.y
$(PROG): $(OBJS) y.tab.o
$(CC) $(OBJS) ${LDADD} -o ${PROG}
$(OBJS): %.o: %.c
$(CC) -c $(CFLAGS) $(CPPFLAGS) $<
install: ${PROG}
install -m 755 cwm /usr/local/bin/
install -m 644 cwm.1 /usr/local/man/man1
install -m 644 cwmrc.5 /usr/local/man/man5
#.include <bsd.prog.mk>
#.include <bsd.xorg.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/

28
TODO
View File

@@ -1,28 +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)
- search should ignore the current window. (not add to match list).
- make kbd shortcuts/events more general. the ability to associate an
event with a mode (i.e. prioritize). gets rid of hacky-ness in
groups, etc.
- figure out what's up when alt-tab goes back to the current window
once before moving on.
- cache all the atoms somewhere.

333
calmwm.c
View File

@@ -18,7 +18,19 @@
* $Id$
*/
#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;
@@ -29,47 +41,35 @@ Cursor Cursor_select;
Cursor Cursor_default;
Cursor Cursor_question;
struct screen_ctx_q Screenq;
struct screen_ctx *Curscreen;
u_int Nscreens;
struct screen_ctx_q Screenq = TAILQ_HEAD_INITIALIZER(Screenq);
struct client_ctx_q Clientq = TAILQ_HEAD_INITIALIZER(Clientq);
struct client_ctx_q Clientq;
int Doshape, Shape_ev;
int HasXinerama, HasRandr, Randr_ev;
int Starting;
struct conf Conf;
struct fontdesc *DefaultFont;
char *DefaultFontName;
/* From TWM */
#define gray_width 2
#define gray_height 2
static char gray_bits[] = {0x02, 0x01};
static void _sigchld_cb(int);
static void sigchld_cb(int);
static void dpy_init(const char *);
static int x_errorhandler(Display *, XErrorEvent *);
static void x_setup(void);
static void x_setupscreen(struct screen_ctx *, u_int);
static void x_teardown(void);
int
main(int argc, char **argv)
{
int ch;
int conf_flags = 0;
const char *conf_file = NULL;
char *display_name = NULL;
int ch;
char *display_name = NULL;
DefaultFontName = "sans-serif:pixelsize=14:bold";
while ((ch = getopt(argc, argv, "d:sf:")) != -1) {
while ((ch = getopt(argc, argv, "c:d:")) != -1) {
switch (ch) {
case 'c':
conf_file = optarg;
break;
case 'd':
display_name = optarg;
break;
case 's':
conf_flags |= CONF_STICKY_GROUPS;
break;
case 'f':
DefaultFontName = xstrdup(optarg);
break;
default:
usage();
}
@@ -77,67 +77,59 @@ main(int argc, char **argv)
argc -= optind;
argv += optind;
/* Ignore a few signals. */
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
err(1, "signal");
if (signal(SIGCHLD, _sigchld_cb) == SIG_ERR)
err(1, "signal");
group_init();
if (signal(SIGCHLD, sigchld_cb) == SIG_ERR)
err(1, "signal");
Starting = 1;
conf_setup(&Conf);
Conf.flags |= conf_flags;
client_setup();
x_setup(display_name);
dpy_init(display_name);
bzero(&Conf, sizeof(Conf));
conf_setup(&Conf, conf_file);
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_loop();
x_teardown();
return (0);
}
void
x_setup(char *display_name)
static void
dpy_init(const char *dpyname)
{
int i;
struct screen_ctx *sc;
char *fontname;
int i;
TAILQ_INIT(&Screenq);
if ((X_Dpy = XOpenDisplay(display_name)) == NULL)
if ((X_Dpy = XOpenDisplay(dpyname)) == NULL)
errx(1, "unable to open display \"%s\"",
XDisplayName(display_name));
XDisplayName(dpyname));
XSetErrorHandler(x_errorhandler);
Doshape = XShapeQueryExtension(X_Dpy, &Shape_ev, &i);
HasRandr = XRRQueryExtension(X_Dpy, &Randr_ev, &i);
}
Nscreens = ScreenCount(X_Dpy);
for (i = 0; i < (int)Nscreens; i++) {
XMALLOC(sc, struct screen_ctx);
static void
x_setup(void)
{
struct screen_ctx *sc;
struct keybinding *kb;
int i;
for (i = 0; i < ScreenCount(X_Dpy); i++) {
sc = xcalloc(1, sizeof(*sc));
x_setupscreen(sc, i);
TAILQ_INSERT_TAIL(&Screenq, sc, entry);
}
/*
* XXX key grabs weren't done before, since Screenq was empty,
* do them here for now (this needs changing).
*/
TAILQ_FOREACH(kb, &Conf.keybindingq, entry)
conf_grab(&Conf, kb);
Cursor_move = XCreateFontCursor(X_Dpy, XC_fleur);
Cursor_resize = XCreateFontCursor(X_Dpy, XC_bottom_right_corner);
Cursor_select = XCreateFontCursor(X_Dpy, XC_hand1);
@@ -145,147 +137,81 @@ x_setup(char *display_name)
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, gv1/* , gv2 */;
Window *wins, w0, w1;
u_int nwins, i = 0;
XWindowAttributes winattr;
XSetWindowAttributes rootattr;
struct keybinding *kb;
sc->display = x_screenname(which);
Window *wins, w0, w1;
XWindowAttributes winattr;
XSetWindowAttributes rootattr;
int fake;
u_int nwins, i;
sc->which = which;
sc->rootwin = RootWindow(X_Dpy, 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),
"#00ccc8", &sc->cyancolor, &tmp);
XAllocNamedColor(X_Dpy, DefaultColormap(X_Dpy, which),
"white", &sc->whitecolor, &tmp);
XAllocNamedColor(X_Dpy, DefaultColormap(X_Dpy, which),
"black", &sc->blackcolor, &tmp);
sc->rootwin = RootWindow(X_Dpy, sc->which);
TAILQ_FOREACH(kb, &Conf.keybindingq, entry)
xu_key_grab(sc->rootwin, kb->modmask, kb->keysym);
conf_gap(&Conf, sc);
screen_update_geometry(sc, DisplayWidth(X_Dpy, sc->which),
DisplayHeight(X_Dpy, sc->which));
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->cyanpixl = sc->cyancolor.pixel;
sc->gray = XCreatePixmapFromBitmapData(X_Dpy, sc->rootwin,
gray_bits, gray_width, gray_height,
sc->blackpixl, sc->whitepixl, DefaultDepth(X_Dpy, sc->which));
sc->blue = XCreatePixmapFromBitmapData(X_Dpy, sc->rootwin,
gray_bits, gray_width, gray_height,
sc->bluepixl, sc->whitepixl, DefaultDepth(X_Dpy, sc->which));
sc->red = XCreatePixmapFromBitmapData(X_Dpy, sc->rootwin,
gray_bits, gray_width, gray_height,
sc->redpixl, sc->whitepixl, DefaultDepth(X_Dpy, sc->which));
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);
sc->hlgc = XCreateGC(X_Dpy, sc->rootwin,
GCForeground|GCBackground|GCFunction|
GCLineWidth|GCSubwindowMode, &gv);
gv1.function = GXinvert;
gv1.subwindow_mode = IncludeInferiors;
gv1.line_width = 1;
sc->invgc = XCreateGC(X_Dpy, sc->rootwin,
GCFunction|GCSubwindowMode|GCLineWidth, &gv1);
conf_color(&Conf, sc);
group_init(sc);
font_init(sc);
DefaultFont = font_getx(sc, DefaultFontName);
conf_font(&Conf, sc);
/*
* XXX - this should *really* be in screen_init(). ordering
* problem.
*/
TAILQ_INIT(&sc->mruq);
/* Initialize menu window. */
grab_menuinit(sc);
search_init(sc);
menu_init(sc);
/* Deal with existing clients. */
XQueryTree(X_Dpy, sc->rootwin, &w0, &w1, &wins, &nwins);
for (i = 0; i < nwins; i++) {
XGetWindowAttributes(X_Dpy, wins[i], &winattr);
if (winattr.override_redirect ||
winattr.map_state != IsViewable) {
char *name;
XFetchName(X_Dpy, wins[i], &name);
continue;
}
client_new(wins[i], sc, winattr.map_state != IsUnmapped);
}
XFree(wins);
Curscreen = sc; /* XXX */
screen_init();
screen_updatestackingorder();
xu_setwmname(sc);
rootattr.event_mask = ChildMask|PropertyChangeMask|EnterWindowMask|
LeaveWindowMask|ColormapChangeMask|ButtonMask;
XChangeWindowAttributes(X_Dpy, sc->rootwin,
/* CWCursor| */CWEventMask, &rootattr);
CWEventMask, &rootattr);
/* Deal with existing clients. */
XQueryTree(X_Dpy, sc->rootwin, &w0, &w1, &wins, &nwins);
for (i = 0; i < nwins; i++) {
XGetWindowAttributes(X_Dpy, wins[i], &winattr);
if (winattr.override_redirect ||
winattr.map_state != IsViewable)
continue;
client_new(wins[i], sc, winattr.map_state != IsUnmapped);
}
XFree(wins);
screen_updatestackingorder(sc);
if (XineramaQueryExtension(X_Dpy, &fake, &fake) == 1 &&
((HasXinerama = XineramaIsActive(X_Dpy)) == 1))
HasXinerama = 1;
if (HasRandr)
XRRSelectInput(X_Dpy, sc->rootwin, RRScreenChangeNotifyMask);
/*
* initial setup of xinerama screens, if we're using RandR then we'll
* redo this whenever the screen changes since a CTRC may have been
* added or removed
*/
screen_init_xinerama(sc);
XSync(X_Dpy, False);
return;
}
char *
x_screenname(int which)
{
char *cp, *dstr, *sn;
size_t snlen;
if (which > 9)
errx(1, "Can't handle more than 9 screens. If you need it, "
"tell <marius@monkey.org>. It's a trivial fix.");
dstr = xstrdup(DisplayString(X_Dpy));
if ((cp = rindex(dstr, ':')) == NULL)
return (NULL);
if ((cp = index(cp, '.')) != NULL)
*cp = '\0';
snlen = strlen(dstr) + 3; /* string, dot, number, null */
sn = (char *)xmalloc(snlen);
snprintf(sn, snlen, "%s.%d", dstr, which);
free(dstr);
return (sn);
}
int
static int
x_errorhandler(Display *dpy, XErrorEvent *e)
{
#ifdef DEBUG
@@ -301,32 +227,35 @@ x_errorhandler(Display *dpy, XErrorEvent *e)
}
#endif
if (Starting &&
e->error_code == BadAccess &&
e->request_code == X_GrabKey)
if (Starting &&
e->error_code == BadAccess &&
e->request_code == X_GrabKey)
errx(1, "root window unavailable - perhaps another "
"wm is running?");
"wm is running?");
return (0);
}
static void
_sigchld_cb(int which)
sigchld_cb(int which)
{
pid_t pid;
int status;
pid_t pid;
int save_errno = errno;
int status;
/* Collect dead children. */
while ((pid = waitpid(-1, &status, WNOHANG)) > 0 ||
(pid < 0 && errno == EINTR))
/* Collect dead children. */
while ((pid = waitpid(-1, &status, WNOHANG)) > 0 ||
(pid < 0 && errno == EINTR))
;
errno = save_errno;
}
__dead void
usage(void)
{
extern char *__progname;
extern char *__progname;
fprintf(stderr, "usage: %s [-s] [-d display] [-f fontname] \n", __progname);
fprintf(stderr, "usage: %s [-c file] [-d display]\n", __progname);
exit(1);
}

717
calmwm.h
View File

@@ -21,98 +21,132 @@
#ifndef _CALMWM_H_
#define _CALMWM_H_
#define CALMWM_MAXNAMELEN 256
/* ugly stuff */
#define TAILQ_END(head) NULL
#define __dead
#include "hash.h"
#include <X11/Xatom.h>
#include <X11/Xft/Xft.h>
#include <X11/Xlib.h>
#include <X11/Xproto.h>
#include <X11/Xutil.h>
#include <X11/cursorfont.h>
#include <X11/extensions/Xinerama.h>
#include <X11/extensions/Xrandr.h>
#include <X11/keysym.h>
#define CALMWM_MAXNAMELEN 256
#undef MIN
#undef MAX
#define MIN(x, y) ((x) < (y) ? (x) : (y))
#define MAX(x, y) ((x) > (y) ? (x) : (y))
enum conftype {
CONF_BWIDTH, CONF_IGNORE, CONF_NOTIFIER,
};
#define CONFFILE ".cwmrc"
#define WMNAME "CWM"
#define ChildMask (SubstructureRedirectMask|SubstructureNotifyMask)
#define ButtonMask (ButtonPressMask|ButtonReleaseMask)
#define MouseMask (ButtonMask|PointerMotionMask)
#define KeyMask (KeyPressMask|ExposureMask)
#define MenuMask (ButtonMask|ButtonMotionMask|ExposureMask| \
PointerMotionMask)
#define MenuGrabMask (ButtonMask|ButtonMotionMask|StructureNotifyMask|\
PointerMotionMask)
#define SearchMask (KeyPressMask|ExposureMask)
enum cwmcolor {
CWM_COLOR_BORDOR_ACTIVE,
CWM_COLOR_BORDER_INACTIVE,
CWM_COLOR_BORDER_GROUP,
CWM_COLOR_BORDER_UNGROUP,
CWM_COLOR_FG_MENU,
CWM_COLOR_BG_MENU,
CWM_COLOR_MAX
};
struct color {
unsigned long pixel;
char *name;
};
struct gap {
int top;
int bottom;
int left;
int right;
};
struct client_ctx;
TAILQ_HEAD(cycle_entry_q, client_ctx);
TAILQ_HEAD(group_ctx_q, group_ctx);
TAILQ_HEAD(client_ctx_q, client_ctx);
/* #define CYCLE_FOREACH_MRU(cy, ctx) TAILQ_FOREACH((ctx), */
struct screen_ctx;
struct fontdesc {
const char *name;
XftFont *fn;
struct screen_ctx *sc;
HASH_ENTRY(fontdesc) node;
#define CALMWM_NGROUPS 9
struct group_ctx {
TAILQ_ENTRY(group_ctx) entry;
struct client_ctx_q clients;
int shortcut;
int hidden;
int nhidden;
int highstack;
};
int fontdesc_cmp(struct fontdesc *a, struct fontdesc *b);
HASH_HEAD(fonthash, fontdesc, 16);
HASH_PROTOTYPE(fonthash, fontdesc, node, fontdesc_cmp);
struct screen_ctx {
TAILQ_ENTRY(screen_ctx) entry;
TAILQ_ENTRY(screen_ctx) entry;
u_int which;
Window rootwin;
Window menuwin;
Window searchwin;
Window groupwin;
Window infowin;
Colormap colormap;
GC invcg;
XColor bgcolor, fgcolor, fccolor, redcolor, cyancolor,
whitecolor, blackcolor;
char *display;
unsigned long blackpixl, whitepixl, redpixl, bluepixl, cyanpixl;
GC gc, invgc, hlgc;
u_int which;
Window rootwin;
Window menuwin;
Pixmap gray, blue, red;
struct color color[CWM_COLOR_MAX];
GC gc;
int altpersist;
int altpersist;
int maxinitialised;
int xmax;
int ymax;
int xmax;
int ymax;
FILE *notifier;
struct gap gap;
struct cycle_entry_q mruq;
struct cycle_entry_q mruq;
XftDraw *xftdraw;
XftColor xftcolor;
XftFont *font;
u_int fontheight;
struct client_ctx* cycle_client;
struct fonthash fonthash;
XftDraw *xftdraw;
XftColor xftcolor;
int xinerama_no;
XineramaScreenInfo *xinerama;
struct group_ctx *group_active;
struct group_ctx groups[CALMWM_NGROUPS];
int group_hideall;
struct group_ctx_q groupq;
char **group_names;
int group_nonames;
};
TAILQ_HEAD(screen_ctx_q, screen_ctx);
#define CLIENT_PROTO_DELETE 0x01
#define CLIENT_PROTO_TAKEFOCUS 0x02
#define CLIENT_PROTO_DELETE 0x01
#define CLIENT_PROTO_TAKEFOCUS 0x02
#define CLIENT_MAXNAMEQLEN 5
#define CLIENT_MAXNAMEQLEN 5
#define CLIENT_HIDDEN 0x01
#define CLIENT_IGNORE 0x02
#define CLIENT_INQUEUE 0x04 /* tmp used by search code */
#define CLIENT_MAXIMIZED 0x08
#define CLIENT_HIGHLIGHT_BLUE 1
#define CLIENT_HIGHLIGHT_RED 2
#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_DOHMAXIMIZE 0x40
#define CLIENT_HMAXIMIZED 0x80
#define CLIENT_HIGHLIGHT_GROUP 1
#define CLIENT_HIGHLIGHT_UNGROUP 2
struct winname {
TAILQ_ENTRY(winname) entry;
char *name;
TAILQ_ENTRY(winname) entry;
char *name;
};
TAILQ_HEAD(winname_q, winname);
@@ -127,22 +161,19 @@ struct client_ctx {
Window win;
XSizeHints *size;
Colormap cmap;
Window pwin;
Colormap cmap;
u_int bwidth;
struct {
int x, y, width, height;
int min_dx, min_dy;
int x, y, width, height, basew, baseh,
minw, minh, maxw, maxh, incw, inch;
float mina, maxa;
} geom, savegeom;
struct {
int x,y;
} ptr;
int beepbeep;
int xproto;
int flags;
@@ -156,117 +187,129 @@ struct client_ctx {
int highlight;
char *matchname;
struct group_ctx *group;
int groupcommit;
struct group_ctx *group;
int stackingorder;
int stackingorder;
char *app_class;
char *app_name;
char *app_cliarg;
char *app_class;
char *app_name;
char *app_cliarg;
};
TAILQ_HEAD(client_ctx_q, client_ctx);
struct group_ctx {
TAILQ_ENTRY(group_ctx) entry;
struct client_ctx_q clients;
char *name;
int shortcut;
int hidden;
int nhidden;
int highstack;
};
TAILQ_HEAD(group_ctx_q, group_ctx);
extern const char *shortcut_to_name[];
/* Autogroups */
struct autogroupwin {
TAILQ_ENTRY(autogroupwin) entry;
char *class;
char *name;
char *group;
TAILQ_ENTRY(autogroupwin) entry;
char *class;
char *name;
int num;
};
TAILQ_HEAD(autogroupwin_q, autogroupwin);
/* NULL/0 values indicate match any. */
struct xevent {
TAILQ_ENTRY(xevent) entry;
Window *xev_win;
Window *xev_root;
int xev_type;
void (*xev_cb)(struct xevent *, XEvent *);
void *xev_arg;
#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(xevent_q, xevent);
/* Keybindings */
enum kbtype {
KB_DELETE, KB_NEWTERM0, KB_NEWTERM1, KB_HIDE,
KB_LOWER, KB_RAISE, KB_SEARCH, KB_CYCLE, KB_LABEL,
KB_GROUPSELECT, KB_VERTMAXIMIZE, KB_MAXIMIZE,
/* Group numbers need to be in order. */
KB_GROUP_1, KB_GROUP_2, KB_GROUP_3, KB_GROUP_4, KB_GROUP_5,
KB_GROUP_6, KB_GROUP_7, KB_GROUP_8, KB_GROUP_9, KB_NOGROUP,
KB_NEXTGROUP, KB_PREVGROUP,
KB_MOVE_WEST, KB_MOVE_EAST, KB_MOVE_NORTH, KB_MOVE_SOUTH,
KB__LAST
};
#define CWM_BIGMOVE 0x1000
enum directions {
CWM_UP=0, CWM_DOWN, CWM_LEFT, CWM_RIGHT,
};
TAILQ_HEAD(winmatch_q, winmatch);
/* for cwm_exec */
#define CWM_EXEC_PROGRAM 0x1
#define CWM_EXEC_WM 0x2
/* for alt-tab */
#define CWM_CYCLE 0x0
#define CWM_RCYCLE 0x1
/* for group cycle */
#define CWM_CYCLEGROUP 0x0
#define CWM_RCYCLEGROUP 0x1
#define KBFLAG_NEEDCLIENT 0x01
#define KBFLAG_FINDCLIENT 0x02
#define KBTOGROUP(X) ((X) - 1)
union arg {
char *c;
int i;
};
struct keybinding {
int modmask;
int keysym;
int keycode;
int flags;
void (*callback)(struct client_ctx *, void *);
void *argument;
TAILQ_ENTRY(keybinding) entry;
TAILQ_ENTRY(keybinding) entry;
void (*callback)(struct client_ctx *, union arg *);
union arg argument;
int modmask;
int keysym;
int keycode;
int flags;
};
struct cmd {
TAILQ_ENTRY(cmd) entry;
int flags;
#define CMD_STATIC 0x01 /* static configuration in conf.c */
char image[MAXPATHLEN];
char label[256];
TAILQ_ENTRY(cmd) entry;
int flags;
char image[MAXPATHLEN];
char label[256];
/* (argv) */
};
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 conf {
struct keybinding_q keybindingq;
struct autogroupwin_q autogroupq;
char menu_path[MAXPATHLEN];
struct cmd_q cmdq;
struct keybinding_q keybindingq;
struct autogroupwin_q autogroupq;
struct winmatch_q ignoreq;
char conf_path[MAXPATHLEN];
struct cmd_q cmdq;
struct mousebinding_q mousebindingq;
int flags;
#define CONF_STICKY_GROUPS 0x0001
#define CONF_STICKY_GROUPS 0x0001
int flags;
#define CONF_BWIDTH 1
int bwidth;
#define CONF_MAMOUNT 1
int mamount;
struct gap gap;
char termpath[MAXPATHLEN];
char lockpath[MAXPATHLEN];
#define CONF_COLOR_ACTIVEBORDER "#CCCCCC"
#define CONF_COLOR_INACTIVEBORDER "#666666"
#define CONF_COLOR_GROUPBORDER "blue"
#define CONF_COLOR_UNGROUPBORDER "red"
#define CONF_COLOR_MENUFG "black"
#define CONF_COLOR_MENUBG "white"
struct color color[CWM_COLOR_MAX];
char termpath[MAXPATHLEN];
char lockpath[MAXPATHLEN];
#define DEFAULTFONTNAME "sans-serif:pixelsize=14:bold"
char *DefaultFontName;
};
/* Menu stuff */
@@ -274,13 +317,14 @@ struct conf {
#define MENU_MAXENTRY 50
struct menu {
TAILQ_ENTRY(menu) entry;
TAILQ_ENTRY(menu) resultentry;
TAILQ_ENTRY(menu) entry;
TAILQ_ENTRY(menu) resultentry;
char text[MENU_MAXENTRY + 1];
char print[MENU_MAXENTRY + 1];
void *ctx;
short dummy;
char text[MENU_MAXENTRY + 1];
char print[MENU_MAXENTRY + 1];
void *ctx;
short dummy;
short abort;
};
TAILQ_HEAD(menu_q, menu);
@@ -294,217 +338,187 @@ enum ctltype {
/* MWM hints */
struct mwm_hints {
u_long flags;
u_long functions;
u_long decorations;
u_long flags;
u_long functions;
u_long decorations;
};
#define MWM_NUMHINTS 3
#define PROP_MWM_HINTS_ELEMENTS 3
#define MWM_HINTS_DECORATIONS (1 << 1)
#define MWM_DECOR_ALL (1 << 0)
#define MWM_DECOR_BORDER (1 << 1)
#define PROP_MWM_HINTS_ELEMENTS 3
#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);
int input_keycodetrans(KeyCode, u_int, enum ctltype *,
char *);
int x_errorhandler(Display *, XErrorEvent *);
void x_setup(char *display_name);
char *x_screenname(int);
void x_setupscreen(struct screen_ctx *, u_int);
__dead void usage(void);
__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 *, int, int);
void client_setactive(struct client_ctx *, int);
void client_gravitate(struct client_ctx *, int);
void client_resize(struct client_ctx *);
void client_lower(struct client_ctx *);
void client_raise(struct client_ctx *);
void client_move(struct client_ctx *);
void client_leave(struct client_ctx *);
void client_send_delete(struct client_ctx *);
struct client_ctx *client_current(void);
void client_hide(struct client_ctx *);
void client_unhide(struct client_ctx *);
void client_nocurrent(void);
void client_setname(struct client_ctx *);
void client_warp(struct client_ctx *);
void client_ptrwarp(struct client_ctx *);
void client_ptrsave(struct client_ctx *);
void client_draw_border(struct client_ctx *);
void client_update(struct client_ctx *);
void client_cycle(struct client_ctx *);
void client_placecalc(struct client_ctx *);
void client_maximize(struct client_ctx *);
void client_vertmaximize(struct client_ctx *);
u_long client_bg_pixel(struct client_ctx *);
Pixmap client_bg_pixmap(struct client_ctx *);
void client_map(struct client_ctx *cc);
void client_mtf(struct client_ctx *cc);
struct client_ctx *client_cyclenext(int reverse);
void client_cycleinfo(struct client_ctx *cc);
void client_altrelease();
struct client_ctx *client_mrunext(struct client_ctx *cc);
struct client_ctx *client_mruprev(struct client_ctx *cc);
void client_gethints(struct client_ctx *cc);
void client_freehints(struct client_ctx *cc);
struct client_ctx *client_find(Window);
struct client_ctx *client_new(Window, struct screen_ctx *, int);
int client_delete(struct client_ctx *);
void client_setactive(struct client_ctx *, int);
void client_resize(struct client_ctx *);
void client_lower(struct client_ctx *);
void client_raise(struct client_ctx *);
void client_move(struct client_ctx *);
void client_leave(struct client_ctx *);
void client_send_delete(struct client_ctx *);
struct client_ctx *client_current(void);
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_draw_border(struct client_ctx *);
void client_maximize(struct client_ctx *);
void client_vertmaximize(struct client_ctx *);
void client_horizmaximize(struct client_ctx *);
void client_map(struct client_ctx *);
void client_mtf(struct client_ctx *);
struct client_ctx *client_cycle(struct screen_ctx *, int);
void client_getsizehints(struct client_ctx *);
void client_applysizehints(struct client_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 *);
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 *);
#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_reconfig(struct client_ctx *); /* XXX should be xu_ */
void xev_loop(void);
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(Window, Atom, long);
int xu_getprop(Window, Atom, Atom, long, u_char **);
int xu_getstrprop(Window, Atom, char **);
void xu_setstate(struct client_ctx *, int);
int xu_getstate(struct client_ctx *, int *);
unsigned long xu_getcolor(struct screen_ctx *, char *);
void xu_freecolor(struct screen_ctx *, unsigned long);
void xu_setwmname(struct screen_ctx *);
int xu_ptr_grab(Window, int, Cursor);
int xu_btn_grab(Window, int, u_int);
int xu_ptr_regrab(int, Cursor);
void xu_btn_ungrab(Window, int, u_int);
void xu_ptr_ungrab(void);
void xu_ptr_setpos(Window, int, int);
void xu_ptr_getpos(Window, int *, int *);
void xu_key_grab(Window, int, int);
void xu_sendmsg(struct client_ctx *, Atom, long);
int xu_getprop(struct client_ctx *, Atom, Atom, long, u_char **);
char *xu_getstrprop(struct client_ctx *, Atom atm);
void xu_setstate(struct client_ctx *, int);
int xu_getstate(struct client_ctx *, int *);
void xu_key_grab_keycode(Window, int, int);
int u_spawn(char *);
void u_exec(char *);
int dirent_exists(char *);
int dirent_isdir(char *);
int dirent_islink(char *);
int u_spawn(char *);
void exec_wm(char *);
void xfree(void *);
void *xmalloc(size_t);
void *xcalloc(size_t, size_t);
char *xstrdup(const char *);
void grab_sweep(struct client_ctx *);
void grab_drag(struct client_ctx *);
void grab_menuinit(struct screen_ctx *);
void *grab_menu(XButtonEvent *, struct menu_q *);
void grab_label(struct client_ctx *);
struct screen_ctx *screen_fromroot(Window);
void screen_updatestackingorder(struct screen_ctx *);
void screen_update_geometry(struct screen_ctx *, int, int);
void screen_init_xinerama(struct screen_ctx *);
XineramaScreenInfo *screen_find_xinerama(struct screen_ctx *, int, int);
void xfree(void *);
void *xmalloc(size_t);
void *xcalloc(size_t);
char *xstrdup(const char *);
void conf_setup(struct conf *, const char *);
void conf_client(struct client_ctx *);
void conf_grab(struct conf *, struct keybinding *);
void conf_ungrab(struct conf *, struct keybinding *);
void conf_bindname(struct conf *, char *, char *);
void conf_mousebind(struct conf *, char *, char *);
void conf_grab_mouse(struct client_ctx *);
void conf_reload(struct conf *);
void conf_gap(struct conf *, struct screen_ctx *);
void conf_font(struct conf *, struct screen_ctx *);
void conf_color(struct conf *, struct screen_ctx *);
void conf_init(struct conf *);
void conf_clear(struct conf *);
void conf_cmd_add(struct conf *, char *, char *, int);
#define XMALLOC(p, t) ((p) = (t *)xmalloc(sizeof * (p)))
#define XCALLOC(p, t) ((p) = (t *)xcalloc(sizeof * (p)))
int parse_config(const char *, struct conf *);
void screen_init(void);
struct screen_ctx *screen_fromroot(Window);
struct screen_ctx *screen_current(void);
void screen_updatestackingorder(void);
void screen_infomsg(char *);
void kbfunc_client_lower(struct client_ctx *, union arg *);
void kbfunc_client_raise(struct client_ctx *, union arg *);
void kbfunc_client_search(struct client_ctx *, union arg *);
void kbfunc_client_hide(struct client_ctx *, union arg *);
void kbfunc_client_cycle(struct client_ctx *, union arg *);
void kbfunc_client_rcycle(struct client_ctx *, union arg *);
void kbfunc_cmdexec(struct client_ctx *, union arg *);
void kbfunc_client_label(struct client_ctx *, union arg *);
void kbfunc_client_delete(struct client_ctx *, union arg *);
void kbfunc_client_group(struct client_ctx *, union arg *);
void kbfunc_client_grouponly(struct client_ctx *,
union arg *);
void kbfunc_client_cyclegroup(struct client_ctx *,
union arg *);
void kbfunc_client_nogroup(struct client_ctx *,
union arg *);
void kbfunc_client_grouptoggle(struct client_ctx *,
union arg *);
void kbfunc_client_movetogroup(struct client_ctx *,
union arg *);
void kbfunc_client_maximize(struct client_ctx *,
union arg *);
void kbfunc_client_vmaximize(struct client_ctx *,
union arg *);
void kbfunc_client_hmaximize(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_setup(struct conf *);
int conf_get_int(struct client_ctx *, enum conftype);
void conf_client(struct client_ctx *);
void conf_bindkey(struct conf *, void (*)(struct client_ctx *, void *),
int, int, int, void *);
void conf_bindname(struct conf *, char *, char *);
void conf_unbind(struct conf *, struct keybinding *);
void conf_parsekeys(struct conf *, char *);
void conf_parsesettings(struct conf *, char *);
void conf_parseignores(struct conf *, char *);
void conf_parseautogroups(struct conf *, char *);
void conf_cmd_clear(struct conf *);
int conf_cmd_changed(char *);
void conf_cmd_populate(struct conf *, char *);
void conf_cmd_refresh(struct conf *c);
char *conf_get_str(struct client_ctx *, enum conftype);
void 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 kbfunc_client_lower(struct client_ctx *, void *);
void kbfunc_client_raise(struct client_ctx *, void *);
void kbfunc_client_search(struct client_ctx *, void *);
void kbfunc_client_hide(struct client_ctx *, void *);
void kbfunc_client_cycle(struct client_ctx *, void *);
void kbfunc_client_rcycle(struct client_ctx *cc, void *arg);
void kbfunc_cmdexec(struct client_ctx *, void *);
void kbfunc_client_label(struct client_ctx *, void *);
void kbfunc_client_delete(struct client_ctx *, void *);
void kbfunc_client_groupselect(struct client_ctx *, void *);
void kbfunc_client_group(struct client_ctx *, void *);
void kbfunc_client_nextgroup(struct client_ctx *, void *);
void kbfunc_client_prevgroup(struct client_ctx *, void *);
void kbfunc_client_nogroup(struct client_ctx *, void *);
void kbfunc_client_maximize(struct client_ctx *, void *);
void kbfunc_client_vmaximize(struct client_ctx *, void *);
void kbfunc_client_move(struct client_ctx *, void *);
void kbfunc_client_resize(struct client_ctx *, void *);
void kbfunc_menu_search(struct client_ctx *, void *);
void kbfunc_exec(struct client_ctx *, void *);
void kbfunc_ptrmove(struct client_ctx *, void *);
void kbfunc_ssh(struct client_ctx *, void *);
void kbfunc_term(struct client_ctx *cc, void *arg);
void kbfunc_lock(struct client_ctx *cc, void *arg);
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 search_init(struct screen_ctx *);
struct menu *search_start(struct menu_q *menuq,
void (*match)(struct menu_q *, struct menu_q *, char *),
void (*rank)(struct menu_q *, char *),
void (*print)(struct menu *mi, int),
char *, int);
void search_match_client(struct menu_q *, struct menu_q *, char *);
void search_print_client(struct menu *mi, int list);
void search_match_text(struct menu_q *, struct menu_q *, char *);
void search_match_exec(struct menu_q *, struct menu_q *, char *);
void search_rank_text(struct menu_q *, char *);
void group_init(struct screen_ctx *);
void group_make_autogroup(struct conf *, char *, int);
void group_update_names(struct screen_ctx *);
void group_hidetoggle(struct screen_ctx *, int);
void group_only(struct screen_ctx *, int);
void group_cycle(struct screen_ctx *, int);
void group_sticky(struct client_ctx *);
void group_client_delete(struct client_ctx *);
void group_menu(XButtonEvent *);
void group_alltoggle(struct screen_ctx *);
void group_sticky_toggle_enter(struct client_ctx *);
void group_sticky_toggle_exit(struct client_ctx *);
void group_autogroup(struct client_ctx *);
void group_movetogroup(struct client_ctx *, int);
void group_init(void);
void group_select(int);
void group_enter(void);
void group_exit(int);
void group_click(struct client_ctx *);
void group_display_init(struct screen_ctx *);
void group_display_draw(struct screen_ctx *);
void group_display_keypress(KeyCode);
void group_hidetoggle(int);
void group_slide(int);
void group_sticky(struct client_ctx *);
void group_client_delete(struct client_ctx *);
void group_menu(XButtonEvent *);
void group_namemode(void);
void group_alltoggle(void);
void group_deletecurrent(void);
void group_done(void);
void group_sticky_toggle_enter(struct client_ctx *);
void group_sticky_toggle_exit(struct client_ctx *);
void group_autogroup(struct client_ctx *);
void notification_init(struct screen_ctx *);
void font_init(struct screen_ctx *sc);
struct fontdesc *font_get(struct screen_ctx *sc, const char *name);
int font_width(struct fontdesc *fdp, const char *text, int len);
void font_draw(struct fontdesc *fdp, const char *text, int len,
Drawable d, int x, int y);
int font_ascent(struct fontdesc *fdp);
int font_descent(struct fontdesc *fdp);
struct fontdesc *font_getx(struct screen_ctx *sc, const char *name);
#define CCTOSC(cc) (cc->sc)
int font_ascent(struct screen_ctx *);
int font_descent(struct screen_ctx *);
u_int font_height(struct screen_ctx *);
void font_init(struct screen_ctx *);
int font_width(struct screen_ctx *, const char *, int);
void font_draw(struct screen_ctx *, const char *, int,
Drawable, int, int);
XftFont *font_make(struct screen_ctx *, const char *);
/* Externs */
@@ -518,15 +532,40 @@ extern Cursor Cursor_question;
extern struct screen_ctx_q Screenq;
extern struct screen_ctx *curscreen;
extern u_int Nscreens;
extern struct client_ctx_q Clientq;
extern int Doshape, Shape_ev;
extern int HasXinerama, HasRandr, Randr_ev;
extern struct conf Conf;
extern int Groupmode;
extern struct fontdesc *DefaultFont;
#define WM_STATE cwm_atoms[0]
#define WM_DELETE_WINDOW cwm_atoms[1]
#define WM_TAKE_FOCUS cwm_atoms[2]
#define WM_PROTOCOLS cwm_atoms[3]
#define _MOTIF_WM_HINTS cwm_atoms[4]
#define UTF8_STRING cwm_atoms[5]
/*
* please make all hints below this point netwm hints, starting with
* _NET_SUPPORTED. If you change other hints make sure you update
* CWM_NETWM_START
*/
#define _NET_SUPPORTED cwm_atoms[6]
#define _NET_SUPPORTING_WM_CHECK cwm_atoms[7]
#define _NET_WM_NAME cwm_atoms[8]
#define _NET_ACTIVE_WINDOW cwm_atoms[9]
#define _NET_CLIENT_LIST cwm_atoms[10]
#define _NET_NUMBER_OF_DESKTOPS cwm_atoms[11]
#define _NET_CURRENT_DESKTOP cwm_atoms[12]
#define _NET_DESKTOP_VIEWPORT cwm_atoms[13]
#define _NET_DESKTOP_GEOMETRY cwm_atoms[14]
#define _NET_VIRTUAL_ROOTS cwm_atoms[15]
#define _NET_SHOWING_DESKTOP cwm_atoms[16]
#define _NET_DESKTOP_NAMES cwm_atoms[17]
#define _NET_WM_DESKTOP cwm_atoms[18]
#define _NET_WORKAREA cwm_atoms[19]
#define CWM_NO_ATOMS 20
#define CWM_NETWM_START 6
extern Atom cwm_atoms[CWM_NO_ATOMS];
#endif /* _CALMWM_H_ */

963
client.c

File diff suppressed because it is too large Load Diff

1008
conf.c

File diff suppressed because it is too large Load Diff

285
cwm.1
View File

@@ -14,8 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.\" The following requests are required for all man pages.
.Dd June 29, 2007
.Dd $Mdocdate: August 24 2009 $
.Dt CWM 1
.Os
.Sh NAME
@@ -24,9 +23,8 @@
.Sh SYNOPSIS
.\" For a program: program [-abc] file ...
.Nm cwm
.Op Fl s
.Op Fl c Ar file
.Op Fl d Ar display
.Op Fl f Ar fontname
.Sh DESCRIPTION
.Nm
is a window manager for X11 which contains many features that
@@ -38,31 +36,31 @@ 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 (Alt on PCs)
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-Enter
.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-Enter
.It Ic M-Return
Hide current window.
.It Ic M-Down
Lower current window.
@@ -72,100 +70,111 @@ 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-Escape
Enter group edit mode.
.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 CM-g
Toggle group membership of current window.
.It Ic M-Right
Switch to next group.
Cycle through active groups.
.It Ic M-Left
Switch to previous group.
.It Ic C-M-f
Toggle full-screen size of window.
.It Ic C-M-=
Toggle vertical maximization of window.
Reverse cycle through active groups.
.It Ic CM-f
Toggle full-screen size of current window.
.It Ic CM-=
Toggle vertical maximization of current window.
.It Ic CMS-=
Toggle horizontal maximization of current window.
.It Ic M-?
Spawn
.Dq Exec program
.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-q
.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 CMS-r
Reload configuration.
.It Ic CMS-q
Quit
.Nm .
.El
.Pp
The mouse bindings are also important, they are:
.Pp
.Bl -tag -width Ds -offset indent -compact
.It M-M1
Move a window.
.It C-M-M1
Toggle a window's membership in the current group.
A blue highlight indicates the window has been added to the group;
a red highlight indicates it has been removed.
.It M-M2
Resize a window/select a window.
.It M-M3
Lower a window.
.It Ic M-M1
Move current window.
.It Ic CM-M1
Toggle group membership of current window.
.It Ic M-M2
Resize current window
.It Ic M-M3
Lower current window.
.It Ic CMS-M3
Hide current window.
.El
.Pp
The options for
.Nm
are as follows:
.Bl -tag -width Ds
.It Fl c Ar file
Specify the config file to use. Defaults to
.Pa ~/.cwmrc .
.It Fl d Ar display
Specify the display to use.
.It Fl f Ar fontname
Makes the
.Xr Xft 3
font string
.Ar fontname
the default font.
.It Fl s
Set sticky group mode on.
The default behavior for new windows is to not assign any group.
This changes the default behavior to assigning the currrently selected
group to any newly created windows.
.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
@@ -179,26 +188,28 @@ 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-sXXX" -offset indent -compact
.It Ic [Down] No or Ic C-s
.Bl -tag -width "[Down] or C-s or M-j" -offset indent -compact
.It Ic [Down], C-s No or Ic M-j
Select the next window in the list.
.It Ic [Up] No or Ic C-r
.It Ic [Up], C-r No or Ic M-k
Select the previous window in the list.
.It Ic [Backspace] No or Ic C-h
Backspace.
.It Ic C-u
Clear the input.
.It Ic [Enter]
.It Ic [Return]
Focus the selected window.
.It Ic [Esc]
Quit.
Cancel.
.It Ic C-a
Whenever there are no matching windows, list every window.
.El
@@ -209,27 +220,26 @@ perform operations on the entire group instead of just one window.
Currently, the only operation that is supported is to hide and unhide
the grouped windows.
Together with the
.Fl s
.Pa sticky
option, this can be used to emulate virtual desktops.
.Pp
To edit groups, enter the group edit mode, and select/unselect the
groups with the group selection mouse click.
A blue border will be shown on the currently selected windows.
The group selection keyboard shortcuts can also be used to change
which group to edit.
To edit groups, use the group selection commands to toggle membership
of a group.
A blue border will be shown briefly on windows added to the current group,
and a red border will be shown on those just removed.
.Sh MENUS
Menus are recalled by clicking the mouse on the root window:
.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 ~/.calmwm .
.Pa ~/.cwmrc .
Clicking on an item will spawn that application.
.El
.Sh ENVIRONMENT
@@ -242,111 +252,10 @@ option is given.
.El
.Sh FILES
.Bl -tag -width Ds
.It Pa ~/.calmwm
Any directory entries here are shown in the application menu.
When it is selected, the image is executed with
.Xr execve 2 .
One use of this is to create symbolic links for your favorite
applications in this directory using
.Xr ln 1 .
.Pp
The entries
.Nm term
and
.Nm lock
have a special meaning.
When they exist they point to the terminal program and screen locking
programs used by the keybindings specified above.
The defaults for these are
.Xr xterm 1
and
.Xr xlock 1 ,
respectively.
.It Pa ~/.calmwm/.autogroup
Symlinks in this directory are read upon startup and control the
automatic grouping feature, which is based on the window name and class
properties.
To obtain the name and class of a window, use
.Ql xprop WM_CLASS ,
then click on the window.
The first quoted string is the window name; the second one is the
window class.
.Pp
The name of a link can be the window class, or the window class and name
separated by a comma.
The link target is a group name (one, two, \&..., nine).
For example, to make all windows in the
.Xr xterm 1
class go to the third group:
.Bd -literal -offset indent
$ ln -s three ~/.calmwm/.autogroup/XTerm
.Ed
.It Pa ~/.calmwm/.settings
Files in this directory cause various configuration options to be
set or unset.
Currently the only setting availiable is whether or not sticky groups
are activated.
To activate sticky groups create a file in this directory with the name
``sticky''.
.It Pa ~/.calmwm/.ignore
Any files in this directory cause
.Nm
to ignore programs by that name by not drawing borders around them.
For example the command
.Bd -literal -offset indent
$ ln -s three ~/.calmwm/.ignore/xclock
.Ed
will cause any instances of
.Xr xclock 1
to not have borders.
.It Pa ~/.calmwm/.keys
Symlinks in this directory cause the creation of keyboard shortcuts.
The default shortcuts will always be created. In case of conflict,
user-defined shortcuts take precidence.
The name of a link here is first the modifier keys, followed by a ``-''.
The following modifiers are recognised:
.Bl -tag -width Ds
.It Pa C
The Control key.
.It Pa M
The Meta key.
.It Pa S
The Shift key.
.It Pa 2
The Mod2 key.
.It Pa 3
The Mod3 key.
.It Pa 4
The Mod4 key (normally the windows key).
.El
The ``-'' should be followed by either a keysym name, taken from
.Pa /usr/X11R6/include/X11/keysymdef.h ,
or a numerical keycode value enclosed in ``[]''.
The target of the link should be either the name of a task from the
``name_to_kbfunc''
structure in
.Pa conf.c ,
or, alternatively it should be the commandline that is wished to be executed.
A special case is the ``unmap'' keyword, which causes any bindings using the
named shortcut to be removed. This can be used to remove a binding which conflicts
with an application.
For example, to cause
.Ic C-M-r
to add a label to a window:
.Bd -literal -offset indent
$ ln -s "label" ~/.calmwm/.keys/CM-r
.Ed
Launch an xterm running
.Xr top 1
with C-S-Enter:
.Bd -literal -offset indent
$ ln -s "/usr/X11R6/bin/xterm -e top" ~/.calmwm/.keys/CS-Return
.Ed
Remove a keybinding for Mod4-o
.Bd -literal -offset indent
$ ln -s "unmap" 4-o
.Ed
.It Pa ~/.cwmrc
.El
.Sh SEE ALSO
.Xr cwmrc 5
.Sh AUTHORS
.An -nosplit
.Pp
@@ -357,7 +266,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

425
cwmrc.5 Normal file
View File

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

106
fgetln.c Normal file
View File

@@ -0,0 +1,106 @@
/* $NetBSD: fgetln.c,v 1.9 2008/04/29 06:53:03 martin Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Christos Zoulas.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#if !HAVE_FGETLN
#include <stdlib.h>
#ifndef HAVE_NBTOOL_CONFIG_H
/* These headers are required, but included from nbtool_config.h */
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#endif
char *
fgetln(FILE *fp, size_t *len)
{
static char *buf = NULL;
static size_t bufsiz = 0;
char *ptr;
if (buf == NULL) {
bufsiz = BUFSIZ;
if ((buf = malloc(bufsiz)) == NULL)
return NULL;
}
if (fgets(buf, bufsiz, fp) == NULL)
return NULL;
*len = 0;
while ((ptr = strchr(&buf[*len], '\n')) == NULL) {
size_t nbufsiz = bufsiz + BUFSIZ;
char *nbuf = realloc(buf, nbufsiz);
if (nbuf == NULL) {
int oerrno = errno;
free(buf);
errno = oerrno;
buf = NULL;
return NULL;
} else
buf = nbuf;
if (fgets(&buf[bufsiz], BUFSIZ, fp) == NULL) {
buf[bufsiz] = '\0';
*len = strlen(buf);
return buf;
}
*len = bufsiz;
bufsiz = nbufsiz;
}
*len = (ptr - buf) + 1;
return buf;
}
#endif
#ifdef TEST
int
main(int argc, char *argv[])
{
char *p;
size_t len;
while ((p = fgetln(stdin, &len)) != NULL) {
(void)printf("%zu %s", len, p);
free(p);
}
return 0;
}
#endif

136
font.c
View File

@@ -16,137 +16,78 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "hash.h"
#include "headers.h"
#include <sys/param.h>
#include <sys/queue.h>
#include <err.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "calmwm.h"
static XftFont *_make_font(struct screen_ctx *sc, struct fontdesc *fdp);
HASH_GENERATE(fonthash, fontdesc, node, fontdesc_cmp);
int
fontdesc_cmp(struct fontdesc *a, struct fontdesc *b)
font_ascent(struct screen_ctx *sc)
{
return strcmp(a->name, b->name);
return (sc->font->ascent);
}
/*
* Fowler/Noll/Vo hash
* http://www.isthe.com/chongo/tech/comp/fnv/
*/
#define FNV_P_32 ((unsigned int)0x01000193) /* 16777619 */
#define FNV_1_32 ((unsigned int)0x811c9dc5) /* 2166136261 */
unsigned int
fontdesc_hash(struct fontdesc *fdp)
int
font_descent(struct screen_ctx *sc)
{
const unsigned char *p, *end, *start;
unsigned int hash = FNV_1_32;
return (sc->font->descent);
}
start = fdp->name;
end = (const unsigned char *)fdp->name + strlen(fdp->name);
for (p = start; p < end; p++) {
hash *= FNV_P_32;
hash ^= (unsigned int)*p;
}
return (hash);
u_int
font_height(struct screen_ctx *sc)
{
return (sc->fontheight);
}
void
font_init(struct screen_ctx *sc)
{
XColor xcolor, tmp;
HASH_INIT(&sc->fonthash, fontdesc_hash);
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;
}
struct fontdesc *
font_getx(struct screen_ctx *sc, const char *name)
{
struct fontdesc *fdp;
if ((fdp = font_get(sc, name)) == NULL)
errx(1, "font_get()");
return (fdp);
}
struct fontdesc *
font_get(struct screen_ctx *sc, const char *name)
{
struct fontdesc fd, *fdp;
XftFont *fn;
fd.name = name;
if ((fdp = HASH_FIND(fonthash, &sc->fonthash, &fd)) == NULL
&& (fn = _make_font(sc, &fd)) != NULL) {
fdp = xmalloc(sizeof(*fdp));
fdp->name = xstrdup(fd.name);
fdp->fn = fn;
fdp->sc = sc;
HASH_INSERT(fonthash, &sc->fonthash, fdp);
}
return (fdp);
if (!XftColorAllocName(X_Dpy, DefaultVisual(X_Dpy, sc->which),
DefaultColormap(X_Dpy, sc->which), "black", &sc->xftcolor))
errx(1, "XftColorAllocName");
}
int
font_width(struct fontdesc *fdp, const char *text, int len)
font_width(struct screen_ctx *sc, const char *text, int len)
{
XGlyphInfo extents;
XftTextExtents8(X_Dpy, fdp->fn, (const XftChar8*)text, len, &extents);
XGlyphInfo extents;
return (extents.xOff);
XftTextExtents8(X_Dpy, sc->font, (const XftChar8*)text,
len, &extents);
return (extents.xOff);
}
void
font_draw(struct fontdesc *fdp, const char *text, int len,
font_draw(struct screen_ctx *sc, const char *text, int len,
Drawable d, int x, int y)
{
XftDrawChange(fdp->sc->xftdraw, d);
XftDrawChange(sc->xftdraw, d);
/* Really needs to be UTF8'd. */
XftDrawString8(fdp->sc->xftdraw, &fdp->sc->xftcolor, fdp->fn, x, y,
XftDrawString8(sc->xftdraw, &sc->xftcolor, sc->font, x, y,
(const FcChar8*)text, len);
}
int
font_ascent(struct fontdesc *fdp)
XftFont *
font_make(struct screen_ctx *sc, const char *name)
{
return fdp->fn->ascent;
}
XftFont *fn = NULL;
FcPattern *pat, *patx;
XftResult res;
int
font_descent(struct fontdesc *fdp)
{
return fdp->fn->descent;
}
static XftFont *
_make_font(struct screen_ctx *sc, struct fontdesc *fdp)
{
XftFont *fn = NULL;
FcPattern *pat, *patx;
XftResult res;
if ((pat = FcNameParse(fdp->name)) == NULL)
if ((pat = FcNameParse((const FcChar8*)name)) == NULL)
return (NULL);
if ((patx = XftFontMatch(X_Dpy, sc->which, pat, &res)) != NULL)
@@ -156,4 +97,3 @@ _make_font(struct screen_ctx *sc, struct fontdesc *fdp)
return (fn);
}

401
grab.c
View File

@@ -1,401 +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"
static int _sweepcalc(struct client_ctx *, int, int, int, int);
static int menu_calc_entry(int, int, int, 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)
void
grab_sweep_draw(struct client_ctx *cc, int dx, int dy)
{
struct screen_ctx *sc = CCTOSC(cc);
int x0 = cc->geom.x, y0 = cc->geom.y;
char asize[10]; /* fits "nnnnxnnnn\0" */
int wide, height, wide_size, wide_name;
struct fontdesc *font = DefaultFont;
snprintf(asize, sizeof(asize), "%dx%d",
ADJUST_WIDTH(cc, dx), ADJUST_HEIGHT(cc, dy));
wide_size = font_width(font, asize, strlen(asize)) + 4;
wide_name = font_width(font, cc->name, strlen(cc->name)) + 4;
wide = MAX(wide_size, wide_name);
height = font_ascent(font) + font_descent(font) + 1;
XMoveResizeWindow(X_Dpy, sc->menuwin, x0, y0, wide, height * 2);
XMapWindow(X_Dpy, sc->menuwin);
XReparentWindow(X_Dpy, sc->menuwin, cc->win, 0, 0);
XClearWindow(X_Dpy, sc->menuwin);
font_draw(font, cc->name, strlen(cc->name), sc->menuwin,
2, font_ascent(font) + 1);
font_draw(font, asize, strlen(asize), sc->menuwin,
wide/2 - wide_size/2, height + font_ascent(font) + 1);
}
void
grab_sweep(struct client_ctx *cc)
{
XEvent ev;
struct screen_ctx *sc = CCTOSC(cc);
int x0 = cc->geom.x, y0 = cc->geom.y;
int dx, dy;
dx = MAX(1, cc->size->width_inc);
dy = MAX(1, cc->size->height_inc);
client_raise(cc);
client_ptrsave(cc);
if (xu_ptr_grab(sc->rootwin, MouseMask, Cursor_resize) < 0)
return;
xu_ptr_setpos(cc->win, cc->geom.width, cc->geom.height);
grab_sweep_draw(cc, dx, dy);
for (;;) {
/* Look for changes in ptr position. */
XMaskEvent(X_Dpy, MouseMask|ExposureMask, &ev);
switch (ev.type) {
case Expose:
client_draw_border(cc);
break;
case MotionNotify:
if (_sweepcalc(cc, x0, y0, ev.xmotion.x, ev.xmotion.y))
/* Recompute window output */
grab_sweep_draw(cc, dx, dy);
XMoveResizeWindow(X_Dpy, cc->pwin,
cc->geom.x - cc->bwidth,
cc->geom.y - cc->bwidth,
cc->geom.width + cc->bwidth*2,
cc->geom.height + cc->bwidth*2);
XMoveResizeWindow(X_Dpy, cc->win,
cc->bwidth, cc->bwidth,
cc->geom.width, cc->geom.height);
break;
case ButtonRelease:
XUnmapWindow(X_Dpy, sc->menuwin);
XReparentWindow(X_Dpy, sc->menuwin, sc->rootwin, 0, 0);
xu_ptr_ungrab();
client_ptrwarp(cc);
return;
}
}
/* NOTREACHED */
}
void
grab_drag(struct client_ctx *cc)
{
int x0 = cc->geom.x, y0 = cc->geom.y, xm, ym;
struct screen_ctx *sc = CCTOSC(cc);
XEvent ev;
client_raise(cc);
if (xu_ptr_grab(sc->rootwin, MouseMask, Cursor_move) < 0)
return;
xu_ptr_getpos(sc->rootwin, &xm, &ym);
for (;;) {
XMaskEvent(X_Dpy, MouseMask|ExposureMask, &ev);
switch (ev.type) {
case Expose:
client_draw_border(cc);
break;
case MotionNotify:
cc->geom.x = x0 + (ev.xmotion.x - xm);
cc->geom.y = y0 + (ev.xmotion.y - ym);
XMoveWindow(X_Dpy, cc->pwin,
cc->geom.x - cc->bwidth, cc->geom.y - cc->bwidth);
break;
case ButtonRelease:
xu_ptr_ungrab();
return;
}
}
/* NOTREACHED */
}
#define MenuMask (ButtonMask|ButtonMotionMask|ExposureMask)
#define MenuGrabMask (ButtonMask|ButtonMotionMask|StructureNotifyMask)
#define AllButtonMask (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask)
void *
grab_menu(XButtonEvent *e, struct menu_q *menuq)
{
struct screen_ctx *sc;
struct menu *mi;
XEvent event;
struct fontdesc *font = DefaultFont;
int x, y, width, height, tothigh, i, no, entry, prev;
int fx, fy;
no = i = width = 0;
if ((sc = screen_fromroot(e->root)) == NULL || e->window == sc->menuwin)
return (NULL);
TAILQ_FOREACH(mi, menuq, entry) {
i = font_width(font, mi->text, strlen(mi->text)) + 4;
if (i > width)
width = i;
no++;
}
if (!sc->maxinitialised) {
sc->xmax = DisplayWidth(X_Dpy, sc->which);
sc->ymax = DisplayHeight(X_Dpy, sc->which);
}
height = font_ascent(font) + font_descent(font) + 1;
tothigh = height * no;
x = e->x - width/2;
y = e->y - height/2;
/* does it fit on the screen? */
if (x < 0)
x = 0;
else if (x+width >= sc->xmax)
x = sc->xmax - width;
if (y < 0)
y = 0;
else if (y+tothigh >= sc->ymax)
y = sc->ymax - tothigh;
xu_ptr_setpos(e->root, x + width/2, y + height/2);
XMoveResizeWindow(X_Dpy, sc->menuwin, x, y, width, tothigh);
XSelectInput(X_Dpy, sc->menuwin, MenuMask);
XMapRaised(X_Dpy, sc->menuwin);
if (xu_ptr_grab(sc->menuwin, MenuGrabMask, Cursor_select) < 0) {
XUnmapWindow(X_Dpy, sc->menuwin);
return (NULL);
}
entry = prev = -1;
for (;;) {
XMaskEvent(X_Dpy, MenuMask, &event);
switch (event.type) {
case Expose:
XClearWindow(X_Dpy, sc->menuwin);
i = 0;
TAILQ_FOREACH(mi, menuq, entry) {
fx = (width - font_width(font, mi->text,
strlen(mi->text)))/2;
fy = height*i + font_ascent(font) + 1;
font_draw(font, mi->text, strlen(mi->text),
sc->menuwin, fx, fy);
i++;
}
/* FALLTHROUGH */
case MotionNotify:
prev = entry;
entry = menu_calc_entry(event.xbutton.x,
event.xbutton.y, width, height, no);
if (prev != -1)
XFillRectangle(X_Dpy, sc->menuwin, sc->hlgc,
0, height*prev, width, height);
if (entry != -1) {
xu_ptr_regrab(MenuGrabMask, Cursor_select);
XFillRectangle(X_Dpy, sc->menuwin, sc->hlgc,
0, height*entry, width, height);
} else
xu_ptr_regrab(MenuGrabMask, Cursor_default);
break;
case ButtonRelease:
if (event.xbutton.button != e->button)
break;
entry = menu_calc_entry(event.xbutton.x,
event.xbutton.y, width, height, no);
xu_ptr_ungrab();
XUnmapWindow(X_Dpy, sc->menuwin);
i = 0;
TAILQ_FOREACH(mi, menuq, entry)
if (entry == i++)
break;
return (mi);
default:
break;
}
}
}
void
grab_menuinit(struct screen_ctx *sc)
{
sc->menuwin = XCreateSimpleWindow(X_Dpy, sc->rootwin, 0, 0,
1, 1, 1, sc->blackpixl, sc->whitepixl);
}
#define LABEL_MAXLEN 256
#define LabelMask (KeyPressMask|ExposureMask)
void
grab_label(struct client_ctx *cc)
{
struct screen_ctx *sc = screen_current();
int x, y, dx, dy, fontheight, focusrevert;
XEvent e;
char labelstr[LABEL_MAXLEN];
char dispstr[LABEL_MAXLEN + sizeof("label>") - 1];
Window focuswin;
char chr;
enum ctltype ctl;
size_t len;
struct fontdesc *font = DefaultFont;
if (cc->label != NULL)
strlcpy(labelstr, cc->label, sizeof(labelstr));
else
labelstr[0] = '\0';
xu_ptr_getpos(sc->rootwin, &x, &y);
dy = fontheight = font_ascent(font) + font_descent(font) + 1;
dx = font_width(font, "label>", 6);
XMoveResizeWindow(X_Dpy, sc->searchwin, x, y, dx, dy);
XSelectInput(X_Dpy, sc->searchwin, LabelMask);
XMapRaised(X_Dpy, sc->searchwin);
XGetInputFocus(X_Dpy, &focuswin, &focusrevert);
XSetInputFocus(X_Dpy, sc->searchwin,
RevertToPointerRoot, CurrentTime);
for (;;) {
XMaskEvent(X_Dpy, LabelMask, &e);
switch (e.type) {
case KeyPress:
if (input_keycodetrans(e.xkey.keycode, e.xkey.state,
&ctl, &chr, 0) < 0)
continue;
switch (ctl) {
case CTL_ERASEONE:
if ((len = strlen(labelstr)) > 0)
labelstr[len - 1] = '\0';
break;
case CTL_RETURN:
/* Done */
if (strlen(labelstr) == 0)
goto out;
if (cc->label != NULL)
xfree(cc->label);
cc->label = xstrdup(labelstr);
/* FALLTHROUGH */
case CTL_ABORT:
goto out;
default:
break;
}
if (chr != '\0') {
char str[2];
str[0] = chr;
str[1] = '\0';
strlcat(labelstr, str, sizeof(labelstr));
}
case Expose:
snprintf(dispstr, sizeof(dispstr), "label>%s", labelstr);
dx = font_width(font, dispstr, strlen(dispstr));
dy = fontheight;
XClearWindow(X_Dpy, sc->searchwin);
XResizeWindow(X_Dpy, sc->searchwin, dx, dy);
font_draw(font, dispstr, strlen(dispstr),
sc->searchwin, 0, font_ascent(font) + 1);
break;
}
}
out:
XSetInputFocus(X_Dpy, focuswin,
focusrevert, CurrentTime);
XUnmapWindow(X_Dpy, sc->searchwin);
}
static int
_sweepcalc(struct client_ctx *cc, int x0, int y0, int motionx, int motiony)
{
int width, height;
width = cc->geom.width;
height = cc->geom.height;
cc->geom.width = abs(x0 - motionx);
cc->geom.height = abs(y0 - motiony);
if (cc->size->flags & PResizeInc) {
cc->geom.width -=
(cc->geom.width - cc->geom.min_dx) % cc->size->width_inc;
cc->geom.height -=
(cc->geom.height - cc->geom.min_dy) % cc->size->height_inc;
}
if (cc->size->flags & PMinSize) {
cc->geom.width = MAX(cc->geom.width, cc->size->min_width);
cc->geom.height = MAX(cc->geom.height, cc->size->min_height);
}
if (cc->size->flags & PMaxSize) {
cc->geom.width = MIN(cc->geom.width, cc->size->max_width);
cc->geom.height = MIN(cc->geom.height, cc->size->max_height);
}
cc->geom.x = x0 <= motionx ? x0 : x0 - cc->geom.width;
cc->geom.y = y0 <= motiony ? y0 : y0 - cc->geom.height;
return (width != cc->geom.width || height != cc->geom.height);
}
static int
menu_calc_entry(int x, int y, int width, int height, int noentries)
{
int entry = y/height;
/* in bounds? */
if (x < 0 || x > width || y < 0 || y > height*noentries ||
entry < 0 || entry >= noentries)
entry = -1;
return entry;
}

678
group.c
View File

@@ -19,36 +19,40 @@
* $Id$
*/
#include "headers.h"
#include <sys/param.h>
#include <sys/queue.h>
#include <assert.h>
#include <err.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "calmwm.h"
#define CALMWM_NGROUPS 9
static void group_add(struct group_ctx *, struct client_ctx *);
static void group_remove(struct client_ctx *);
static void group_hide(struct screen_ctx *, struct group_ctx *);
static void group_show(struct screen_ctx *, struct group_ctx *);
static void group_fix_hidden_state(struct group_ctx *);
static void group_setactive(struct screen_ctx *, long);
static void group_set_names(struct screen_ctx *);
int Groupmode = 0;
int Groupnamemode = 0;
struct group_ctx *Group_active = NULL;
struct group_ctx *Group_current = NULL;
struct group_ctx Groups[CALMWM_NGROUPS];
char Group_name[256];
int Groupfocusset = 0;
Window Groupfocuswin;
int Groupfocusrevert;
int Grouphideall = 0;
struct group_ctx_q Groupq;
#define GroupMask (KeyPressMask|ExposureMask)
static char *shortcut_to_name[] = {
"XXX", "one", "two", "three",
"four", "five", "six", "seven",
"eight", "nine",
const char *shortcut_to_name[] = {
"nogroup", "one", "two", "three", "four", "five", "six",
"seven", "eight", "nine"
};
static void
_group_add(struct group_ctx *gc, struct client_ctx *cc)
group_add(struct group_ctx *gc, struct client_ctx *cc)
{
long no;
if (cc == NULL || gc == NULL)
errx(1, "_group_add: a ctx is NULL");
errx(1, "group_add: a ctx is NULL");
no = gc->shortcut - 1;
if (cc->group == gc)
return;
@@ -56,56 +60,34 @@ _group_add(struct group_ctx *gc, struct client_ctx *cc)
if (cc->group != NULL)
TAILQ_REMOVE(&cc->group->clients, cc, group_entry);
XChangeProperty(X_Dpy, cc->win, _NET_WM_DESKTOP, XA_CARDINAL,
32, PropModeReplace, (unsigned char *)&no, 1);
TAILQ_INSERT_TAIL(&gc->clients, cc, group_entry);
cc->group = gc;
cc->groupcommit = 0;
}
static void
_group_remove(struct client_ctx *cc)
group_remove(struct client_ctx *cc)
{
long no = 0xffffffff;
if (cc == NULL || cc->group == NULL)
errx(1, "_group_remove: a ctx is NULL");
errx(1, "group_remove: a ctx is NULL");
XChangeProperty(X_Dpy, cc->win, _NET_WM_DESKTOP, XA_CARDINAL,
32, PropModeReplace, (unsigned char *)&no, 1);
TAILQ_REMOVE(&cc->group->clients, cc, group_entry);
cc->group = NULL;
cc->groupcommit = 0;
cc->highlight = 0;
client_draw_border(cc);
}
static void
_group_commit(struct group_ctx *gc)
group_hide(struct screen_ctx *sc, struct group_ctx *gc)
{
struct client_ctx *cc;
struct client_ctx *cc;
if (gc == NULL)
errx(1, "_group_commit: ctx is null");
TAILQ_FOREACH(cc, &gc->clients, group_entry)
cc->groupcommit = 1;
}
static void
_group_purge(struct group_ctx *gc)
{
struct client_ctx *cc;
if (gc == NULL)
errx(1, "_group_purge: ctx is null");
TAILQ_FOREACH(cc, &gc->clients, group_entry)
if (cc->groupcommit == 0)
_group_remove(cc);
}
static void
_group_hide(struct group_ctx *gc)
{
struct client_ctx *cc;
screen_updatestackingorder();
screen_updatestackingorder(sc);
gc->nhidden = 0;
gc->highstack = 0;
@@ -119,21 +101,21 @@ _group_hide(struct group_ctx *gc)
}
static void
_group_show(struct group_ctx *gc)
group_show(struct screen_ctx *sc, struct group_ctx *gc)
{
struct client_ctx *cc;
Window *winlist;
u_int i;
int lastempty = -1;
struct client_ctx *cc;
Window *winlist;
u_int i;
int lastempty = -1;
winlist = (Window *) xcalloc(sizeof(*winlist) * (gc->highstack + 1));
winlist = (Window *) xcalloc(sizeof(*winlist), (gc->highstack + 1));
/*
* Invert the stacking order as XRestackWindows() expects them
* top-to-bottom.
*/
TAILQ_FOREACH(cc, &gc->clients, group_entry) {
winlist[gc->highstack - cc->stackingorder] = cc->pwin;
winlist[gc->highstack - cc->stackingorder] = cc->win;
client_unhide(cc);
}
@@ -152,159 +134,109 @@ _group_show(struct group_ctx *gc)
xfree(winlist);
gc->hidden = 0;
Group_active = gc;
}
static void
_group_destroy(struct group_ctx *gc)
{
struct client_ctx *cc;
if (gc->name != NULL) {
xfree(gc->name);
gc->name = NULL;
}
while ((cc = TAILQ_FIRST(&gc->clients)) != NULL) {
TAILQ_REMOVE(&gc->clients, cc, group_entry);
cc->group = NULL;
cc->groupcommit = 0;
cc->highlight = 0;
client_draw_border(cc);
}
group_setactive(sc, gc->shortcut - 1);
}
void
group_init(void)
group_init(struct screen_ctx *sc)
{
int i;
int i;
long viewports[2] = {0, 0};
long ndesks = CALMWM_NGROUPS, zero = 0;
TAILQ_INIT(&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;
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_current = 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);
}
/*
* manipulate the 'current group'
*/
/* change the current group */
void
group_select(int idx)
group_make_autogroup(struct conf *conf, char *val, int no)
{
struct group_ctx *gc = Group_current;
struct client_ctx *cc;
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;
if (idx < 0 || idx >= CALMWM_NGROUPS)
return;
err(1, "group_movetogroup: index out of range (%d)", idx);
TAILQ_FOREACH(cc, &gc->clients, group_entry) {
cc->highlight = 0;
client_draw_border(cc);
}
_group_commit(gc);
Group_current = &Groups[idx];
group_display_draw(screen_current());
return;
}
/* enter group mode */
void
group_enter(void)
{
if (Groupmode != 0)
errx(1, "group_enter called twice");
if (Group_current == NULL)
Group_current = &Groups[0];
/* setup input buffer */
Group_name[0] = '\0';
Groupmode = 1;
group_display_init(screen_current());
group_display_draw(screen_current());
}
/* exit group mode */
void
group_exit(int commit)
{
struct group_ctx *gc = Group_current;
struct client_ctx *cc;
if (Groupmode != 1)
errx(1, "group_exit called twice");
TAILQ_FOREACH(cc, &gc->clients, group_entry) {
cc->highlight = 0;
client_draw_border(cc);
}
if (commit) {
_group_commit(gc);
} else {
/* abort */
_group_purge(gc);
if (!TAILQ_EMPTY(&gc->clients))
_group_destroy(gc);
}
XUnmapWindow(X_Dpy, screen_current()->groupwin);
if (Groupnamemode) {
XSetInputFocus(X_Dpy, Groupfocuswin, Groupfocusrevert,
CurrentTime);
Groupfocusset = 0;
}
Groupmode = Groupnamemode = 0;
}
void
group_click(struct client_ctx *cc)
{
struct group_ctx *gc = Group_current;
if (gc == cc->group)
_group_remove(cc);
else
_group_add(gc, cc);
group_display_draw(screen_current());
}
/* Used to add a newly mapped window to the active group */
void
group_sticky(struct client_ctx *cc)
{
_group_add(Group_active, cc);
if(sc->group_active != &sc->groups[idx])
client_hide(cc);
group_add(&sc->groups[idx], cc);
}
/*
* Colouring for groups upon add/remove.
*/
void
group_sticky_toggle_enter(struct client_ctx *cc)
{
struct group_ctx *gc = Group_active;
struct screen_ctx *sc = cc->sc;
struct group_ctx *gc;
gc = sc->group_active;
if (gc == cc->group) {
_group_remove(cc);
cc->highlight = CLIENT_HIGHLIGHT_RED;
group_remove(cc);
cc->highlight = CLIENT_HIGHLIGHT_UNGROUP;
} else {
_group_add(gc, cc);
cc->highlight = CLIENT_HIGHLIGHT_BLUE;
group_add(gc, cc);
cc->highlight = CLIENT_HIGHLIGHT_GROUP;
}
client_draw_border(cc);
@@ -318,95 +250,13 @@ group_sticky_toggle_exit(struct client_ctx *cc)
}
/*
* selection list display
* if group_hidetoggle would produce no effect, toggle the group's hidden state
*/
void
group_display_init(struct screen_ctx *sc)
static void
group_fix_hidden_state(struct group_ctx *gc)
{
sc->groupwin = XCreateSimpleWindow(X_Dpy, sc->rootwin, 0, 0,
1, 1, 1, sc->blackpixl, sc->whitepixl);
}
void
group_display_draw(struct screen_ctx *sc)
{
struct group_ctx *gc = Group_current;
int x, y, dx, dy, fontheight;
struct client_ctx *cc;
char titlebuf[1024];
struct fontdesc *font = DefaultFont;
snprintf(titlebuf, sizeof(titlebuf), "Editing group %d", gc->shortcut);
x = y = 0;
fontheight = font_ascent(font) + font_descent(font) + 1;
dx = font_width(font, titlebuf, strlen(titlebuf));
dy = fontheight;
TAILQ_FOREACH(cc, &gc->clients, group_entry) {
cc->highlight = CLIENT_HIGHLIGHT_BLUE;
client_draw_border(cc);
}
XMoveResizeWindow(X_Dpy, sc->groupwin, x, y, dx, dy);
/* XXX */
XSelectInput(X_Dpy, sc->groupwin, GroupMask);
XMapRaised(X_Dpy, sc->groupwin);
XClearWindow(X_Dpy, sc->groupwin);
font_draw(font, titlebuf, strlen(titlebuf), sc->groupwin,
0, font_ascent(font) + 1);
}
void
group_display_keypress(KeyCode k)
{
struct group_ctx * gc = Group_current;
char chr;
enum ctltype ctl;
int len;
if (!Groupnamemode)
return;
if (input_keycodetrans(k, 0, &ctl, &chr, 1) < 0)
goto out;
switch (ctl) {
case CTL_ERASEONE:
if ((len = strlen(Group_name)) > 0)
Group_name[len - 1] = '\0';
break;
case CTL_RETURN:
if (gc->name != NULL)
xfree(gc->name);
gc->name = xstrdup(Group_name);
group_exit(1);
return;
default:
break;
}
if (chr != '\0')
snprintf(Group_name, sizeof(Group_name), "%s%c",
Group_name, chr);
out:
group_display_draw(screen_current());
}
/* if group_hidetoggle would produce no effect, toggle the group's hidden state
*/
void
_group_fix_hidden_state(struct group_ctx *gc)
{
struct client_ctx *cc;
int same = 0;
struct client_ctx *cc;
int same = 0;
TAILQ_FOREACH(cc, &gc->clients, group_entry) {
if (gc->hidden == ((cc->flags & CLIENT_HIDDEN) ? 1 : 0))
@@ -418,72 +268,77 @@ _group_fix_hidden_state(struct group_ctx *gc)
}
void
group_hidetoggle(int idx)
group_hidetoggle(struct screen_ctx *sc, int idx)
{
struct group_ctx *gc;
#ifdef notyet
char buf[128];
#endif
struct group_ctx *gc;
if (idx < 0 || idx >= CALMWM_NGROUPS)
err(1, "group_hidetoggle: index out of range (%d)", idx);
gc = &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);
}
#ifdef notyet
snprintf(buf, sizeof(buf), "Group %d", idx + 1);
screen_infomsg(buf);
#endif
}
#define GROUP_NEXT(gc, fwd) (fwd) ? \
TAILQ_NEXT(gc, entry) : TAILQ_PREV(gc, group_ctx_q, entry)
void
group_only(struct screen_ctx *sc, int idx)
{
int i;
if (idx < 0 || idx >= CALMWM_NGROUPS)
err(1, "group_only: index out of range (%d)", idx);
for (i = 0; i < CALMWM_NGROUPS; i++) {
if (i == idx)
group_show(sc, &sc->groups[i]);
else
group_hide(sc, &sc->groups[i]);
}
}
/*
* Jump to the next/previous active group. If none exist, then just
* stay put.
* Cycle through active groups. If none exist, then just stay put.
*/
void
group_slide(int fwd)
group_cycle(struct screen_ctx *sc, int reverse)
{
struct group_ctx *gc, *showgroup = NULL;
struct group_ctx *gc, *showgroup = NULL;
assert(Group_active != NULL);
assert(sc->group_active != NULL);
gc = Group_active;
gc = sc->group_active;
for (;;) {
gc = GROUP_NEXT(gc, fwd);
gc = reverse ? TAILQ_PREV(gc, group_ctx_q, entry) :
TAILQ_NEXT(gc, entry);
if (gc == NULL)
gc = fwd ? TAILQ_FIRST(&Groupq) :
TAILQ_LAST(&Groupq, group_ctx_q);
if (gc == Group_active)
gc = reverse ? 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 */
@@ -491,39 +346,37 @@ void
group_client_delete(struct client_ctx *cc)
{
if (cc->group == NULL)
return;
return;
TAILQ_REMOVE(&cc->group->clients, cc, group_entry);
cc->group = NULL; /* he he */
cc->groupcommit = 0;
}
void
group_menu(XButtonEvent *e)
{
struct menu_q menuq;
struct menu *mi;
int i;
struct group_ctx *gc;
struct screen_ctx *sc;
struct group_ctx *gc;
struct menu *mi;
struct menu_q menuq;
int i;
sc = screen_fromroot(e->root);
TAILQ_INIT(&menuq);
for (i = 0; i < CALMWM_NGROUPS; i++) {
gc = &Groups[i];
gc = &sc->groups[i];
if (TAILQ_EMPTY(&gc->clients))
continue;
if (gc->name == NULL)
gc->name = xstrdup(shortcut_to_name[gc->shortcut]);
XCALLOC(mi, struct menu);
mi = xcalloc(1, sizeof(*mi));
if (gc->hidden)
snprintf(mi->text, sizeof(mi->text), "%d: [%s]",
gc->shortcut, gc->name);
gc->shortcut, sc->group_names[i]);
else
snprintf(mi->text, sizeof(mi->text), "%d: %s",
gc->shortcut, gc->name);
gc->shortcut, sc->group_names[i]);
mi->ctx = gc;
TAILQ_INSERT_TAIL(&menuq, mi, entry);
}
@@ -531,19 +384,16 @@ group_menu(XButtonEvent *e)
if (TAILQ_EMPTY(&menuq))
return;
mi = (struct menu *)grab_menu(e, &menuq);
mi = menu_filter(sc, &menuq, NULL, NULL, 0, NULL, NULL);
if (mi == NULL || mi->ctx == NULL)
goto cleanup;
gc = (struct group_ctx *)mi->ctx;
if (gc->hidden)
_group_show(gc);
else
_group_hide(gc);
(gc->hidden) ? group_show(sc, gc) : group_hide(sc, gc);
cleanup:
cleanup:
while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
TAILQ_REMOVE(&menuq, mi, entry);
xfree(mi);
@@ -551,74 +401,138 @@ group_menu(XButtonEvent *e)
}
void
group_namemode(void)
group_alltoggle(struct screen_ctx *sc)
{
Groupnamemode = 1;
int i;
group_display_draw(screen_current());
}
void
group_alltoggle(void)
{
int i;
for (i=0; i < CALMWM_NGROUPS; i++) {
if (Grouphideall)
_group_show(&Groups[i]);
for (i = 0; i < CALMWM_NGROUPS; 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;
}
void
group_deletecurrent(void)
{
_group_destroy(Group_current);
XUnmapWindow(X_Dpy, screen_current()->groupwin);
Groupmode = Groupnamemode = 0;
}
void
group_done(void)
{
struct group_ctx *gc = Group_current;
if (gc->name != NULL)
xfree(gc->name);
gc->name = xstrdup(shortcut_to_name[gc->shortcut]);
group_exit(1);
sc->group_hideall = (!sc->group_hideall);
}
void
group_autogroup(struct client_ctx *cc)
{
struct autogroupwin *aw;
struct group_ctx *gc;
char group[CALMWM_MAXNAMELEN];
struct screen_ctx *sc = cc->sc;
struct autogroupwin *aw;
struct group_ctx *gc;
int no = -1;
long *grpno;
if (cc->app_class == NULL || cc->app_name == NULL)
return;
TAILQ_FOREACH(aw, &Conf.autogroupq, entry) {
if (strcmp(aw->class, cc->app_class) == 0 &&
(aw->name == NULL || strcmp(aw->name, cc->app_name) == 0)) {
strlcpy(group, aw->group, sizeof(group));
break;
if (xu_getprop(cc->win, _NET_WM_DESKTOP, XA_CARDINAL,
1, (unsigned char **)&grpno) > 0) {
if (*grpno == 0xffffffff)
no = 0;
else if (*grpno > CALMWM_NGROUPS || *grpno < 0)
no = CALMWM_NGROUPS - 1;
else
no = *grpno + 1;
XFree(grpno);
} else {
TAILQ_FOREACH(aw, &Conf.autogroupq, entry) {
if (strcmp(aw->class, cc->app_class) == 0 &&
(aw->name == NULL ||
strcmp(aw->name, cc->app_name) == 0)) {
no = aw->num;
break;
}
}
}
TAILQ_FOREACH(gc, &Groupq, entry) {
if (strcmp(shortcut_to_name[gc->shortcut], group) == 0)
_group_add(gc, cc);
/* no group please */
if (no == 0)
return;
TAILQ_FOREACH(gc, &sc->groupq, entry) {
if (gc->shortcut == no) {
group_add(gc, cc);
return;
}
}
if (Conf.flags & CONF_STICKY_GROUPS)
group_add(sc->group_active, cc);
}
void
group_update_names(struct screen_ctx *sc)
{
char **strings, *p;
unsigned char *prop_ret;
Atom type_ret;
int format_ret, i = 0, nstrings = 0, n, setnames = 0;
unsigned long bytes_after, num_ret;
if (XGetWindowProperty(X_Dpy, sc->rootwin, _NET_DESKTOP_NAMES, 0,
0xffffff, False, UTF8_STRING, &type_ret, &format_ret,
&num_ret, &bytes_after, &prop_ret) == Success &&
prop_ret != NULL && format_ret == 8) {
/* failure, just set defaults */
prop_ret[num_ret - 1] = '\0'; /* paranoia */
while (i < num_ret) {
if (prop_ret[i++] == '\0')
nstrings++;
}
}
strings = xmalloc((nstrings < CALMWM_NGROUPS ? CALMWM_NGROUPS :
nstrings) * sizeof(*strings));
i = n = 0;
p = prop_ret;
while (n < nstrings) {
strings[n++] = xstrdup(p);
p += strlen(p) + 1;
}
/*
* make sure we always set our defaults if nothing is there to
* replace them.
*/
if (n < CALMWM_NGROUPS) {
setnames = 1;
i = 1;
while (n < CALMWM_NGROUPS)
strings[n++] = xstrdup(shortcut_to_name[i++]);
}
if (prop_ret != NULL)
XFree(prop_ret);
if (sc->group_nonames != 0)
free(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;
strlcpy(q, sc->group_names[i], tlen);
tlen -= slen;
q += slen;
}
XChangeProperty(X_Dpy, sc->rootwin, _NET_DESKTOP_NAMES,
UTF8_STRING, 8, PropModeReplace, p, len);
}

68
hash.h
View File

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

View File

@@ -1,55 +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/shape.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include <X11/Xatom.h>
#include <X11/Xproto.h>
#include <X11/Intrinsic.h>
#include <X11/Xos.h>
#include <X11/Xft/Xft.h>
#include <err.h>
#endif /* _CALMWM_HEADERS_H_ */

42
input.c
View File

@@ -18,22 +18,27 @@
* $Id$
*/
#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"
int
input_keycodetrans(KeyCode kc, u_int state,
enum ctltype *ctl, char *chr, int normalize)
input_keycodetrans(KeyCode kc, u_int state, enum ctltype *ctl, char *chr)
{
int ks;
int ks;
*ctl = CTL_NONE;
*chr = '\0';
if (state & ShiftMask)
ks = XKeycodeToKeysym(X_Dpy, kc, 1);
else
ks = XKeycodeToKeysym(X_Dpy, kc, 0);
ks = XKeycodeToKeysym(X_Dpy, kc, (state & ShiftMask) ? 1 : 0);
/* Look for control characters. */
switch (ks) {
@@ -70,6 +75,10 @@ input_keycodetrans(KeyCode kc, u_int state,
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;
@@ -77,6 +86,21 @@ input_keycodetrans(KeyCode kc, u_int state,
}
}
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);
@@ -88,8 +112,6 @@ input_keycodetrans(KeyCode kc, u_int state,
return (-1);
*chr = (char)ks;
if (normalize)
*chr = tolower(*chr);
return (0);
}

443
kbfunc.c
View File

@@ -1,6 +1,6 @@
/*
* calmwm - the calm window manager
*
*
* Copyright (c) 2004 Martin Murray <mmurray@monkey.org>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -18,130 +18,62 @@
* $Id$
*/
#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|"
#define MOVE_AMOUNT 1
#define KNOWN_HOSTS ".ssh/known_hosts"
#define HASH_MARKER "|1|"
extern int _xev_quit;
void
kbfunc_client_lower(struct client_ctx *cc, void *arg)
kbfunc_client_lower(struct client_ctx *cc, union arg *arg)
{
client_lower(cc);
}
void
kbfunc_client_raise(struct client_ctx *cc, void *arg)
kbfunc_client_raise(struct client_ctx *cc, union arg *arg)
{
client_raise(cc);
}
#define typemask (CWM_MOVE | CWM_RESIZE | CWM_PTRMOVE)
#define movemask (CWM_UP | CWM_DOWN | CWM_LEFT | CWM_RIGHT)
void
kbfunc_client_move(struct client_ctx *cc, void *arg)
kbfunc_moveresize(struct client_ctx *cc, union arg *arg)
{
int x,y,flags,amt;
u_int mx,my;
struct screen_ctx *sc;
int x, y, flags, amt;
u_int mx, my;
sc = cc->sc;
mx = my = 0;
flags = (int)arg;
amt = MOVE_AMOUNT;
if (flags & CWM_BIGMOVE) {
flags -= CWM_BIGMOVE;
amt = amt*10;
}
switch(flags) {
case CWM_UP:
my -= amt;
break;
case CWM_DOWN:
my += amt;
break;
case CWM_RIGHT:
mx += amt;
break;
case CWM_LEFT:
mx -= amt;
break;
}
cc->geom.y += my;
cc->geom.x += mx;
client_move(cc);
xu_ptr_getpos(cc->pwin, &x, &y);
cc->ptr.y = y + my;
cc->ptr.x = x + mx;
client_ptrwarp(cc);
}
void
kbfunc_client_resize(struct client_ctx *cc, void *arg)
{
int flags,mx,my;
u_int amt;
mx = my = 0;
flags = (int)arg;
amt = MOVE_AMOUNT;
if (flags & CWM_BIGMOVE) {
flags -= CWM_BIGMOVE;
amt = amt*10;
}
switch(flags) {
case CWM_UP:
my -= amt;
break;
case CWM_DOWN:
my += amt;
break;
case CWM_RIGHT:
mx += amt;
break;
case CWM_LEFT:
mx -= amt;
break;
}
cc->geom.height += my;
cc->geom.width += mx;
client_resize(cc);
/*
* Moving the cursor while resizing is problematic. Just place
* it in the middle of the window.
*/
cc->ptr.x = -1;
cc->ptr.y = -1;
client_ptrwarp(cc);
}
void
kbfunc_ptrmove(struct client_ctx *cc, void *arg)
{
int px,py,mx,my,flags,amt;
struct screen_ctx *sc = screen_current();
my = mx = 0;
flags = (int)arg;
amt = MOVE_AMOUNT;
flags = arg->i;
amt = Conf.mamount;
if (flags & CWM_BIGMOVE) {
flags -= CWM_BIGMOVE;
amt = amt * 10;
}
switch(flags) {
switch (flags & movemask) {
case CWM_UP:
my -= amt;
break;
case CWM_DOWN:
case CWM_DOWN:
my += amt;
break;
case CWM_RIGHT:
@@ -151,35 +83,77 @@ kbfunc_ptrmove(struct client_ctx *cc, void *arg)
mx -= amt;
break;
}
switch (flags & typemask) {
case CWM_MOVE:
cc->geom.y += my;
if (cc->geom.y + cc->geom.height < 0)
cc->geom.y = -cc->geom.height;
if (cc->geom.y > cc->sc->ymax - 1)
cc->geom.y = cc->sc->ymax - 1;
if (cc) {
xu_ptr_getpos(cc->pwin, &px, &py);
xu_ptr_setpos(cc->pwin, px + mx, py + my);
} else {
xu_ptr_getpos(sc->rootwin, &px, &py);
xu_ptr_setpos(sc->rootwin, px + mx, py + my);
cc->geom.x += mx;
if (cc->geom.x + cc->geom.width < 0)
cc->geom.x = -cc->geom.width;
if (cc->geom.x > cc->sc->xmax - 1)
cc->geom.x = cc->sc->xmax - 1;
client_move(cc);
xu_ptr_getpos(cc->win, &x, &y);
cc->ptr.y = y + my;
cc->ptr.x = x + mx;
client_ptrwarp(cc);
break;
case CWM_RESIZE:
if ((cc->geom.height += my) < 1)
cc->geom.height = 1;
if ((cc->geom.width += mx) < 1)
cc->geom.width = 1;
client_resize(cc);
/* Make sure the pointer stays within the window. */
xu_ptr_getpos(cc->win, &cc->ptr.x, &cc->ptr.y);
if (cc->ptr.x > cc->geom.width)
cc->ptr.x = cc->geom.width - cc->bwidth;
if (cc->ptr.y > cc->geom.height)
cc->ptr.y = cc->geom.height - cc->bwidth;
client_ptrwarp(cc);
break;
case CWM_PTRMOVE:
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);
}
break;
default:
warnx("invalid flags passed to kbfunc_client_moveresize");
}
}
void
kbfunc_client_search(struct client_ctx *scratch, void *arg)
kbfunc_client_search(struct client_ctx *cc, union arg *arg)
{
struct menu_q menuq;
struct client_ctx *cc, *old_cc = client_current();
struct menu *mi;
struct screen_ctx *sc;
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);
mi = xcalloc(1, sizeof(*mi));
strlcpy(mi->text, cc->name, sizeof(mi->text));
mi->ctx = cc;
TAILQ_INSERT_TAIL(&menuq, mi, entry);
}
if ((mi = search_start(&menuq,
search_match_client, NULL,
search_print_client, "window", 0)) != NULL) {
if ((mi = menu_filter(sc, &menuq, "window", NULL, 0,
search_match_client, search_print_client)) != NULL) {
cc = (struct client_ctx *)mi->ctx;
if (cc->flags & CLIENT_HIDDEN)
client_unhide(cc);
@@ -196,24 +170,25 @@ kbfunc_client_search(struct client_ctx *scratch, void *arg)
}
void
kbfunc_menu_search(struct client_ctx *scratch, void *arg)
kbfunc_menu_search(struct client_ctx *cc, union arg *arg)
{
struct menu_q menuq;
struct menu *mi;
struct cmd *cmd;
struct screen_ctx *sc;
struct cmd *cmd;
struct menu *mi;
struct menu_q menuq;
sc = cc->sc;
TAILQ_INIT(&menuq);
conf_cmd_refresh(&Conf);
TAILQ_FOREACH(cmd, &Conf.cmdq, entry) {
XCALLOC(mi, struct menu);
mi = xcalloc(1, sizeof(*mi));
strlcpy(mi->text, cmd->label, sizeof(mi->text));
mi->ctx = cmd;
TAILQ_INSERT_TAIL(&menuq, mi, entry);
}
if ((mi = search_start(&menuq,
search_match_text, NULL, NULL, "application", 0)) != NULL)
if ((mi = menu_filter(sc, &menuq, "application", NULL, 0,
search_match_text, NULL)) != NULL)
u_spawn(((struct cmd *)mi->ctx)->image);
while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
@@ -223,60 +198,58 @@ kbfunc_menu_search(struct client_ctx *scratch, void *arg)
}
void
kbfunc_client_cycle(struct client_ctx *scratch, void *arg)
kbfunc_client_cycle(struct client_ctx *cc, union arg *arg)
{
client_cyclenext(0);
struct screen_ctx *sc;
sc = cc->sc;
/* XXX for X apps that ignore events */
XGrabKeyboard(X_Dpy, sc->rootwin, True,
GrabModeAsync, GrabModeAsync, CurrentTime);
client_cycle(sc, arg->i);
}
void
kbfunc_client_rcycle(struct client_ctx *scratch, void *arg)
{
client_cyclenext(1);
}
void
kbfunc_client_hide(struct client_ctx *cc, void *arg)
kbfunc_client_hide(struct client_ctx *cc, union arg *arg)
{
client_hide(cc);
}
void
kbfunc_cmdexec(struct client_ctx *cc, void *arg)
kbfunc_cmdexec(struct client_ctx *cc, union arg *arg)
{
u_spawn((char *)arg);
u_spawn(arg->c);
}
void
kbfunc_term(struct client_ctx *cc, void *arg)
kbfunc_term(struct client_ctx *cc, union arg *arg)
{
conf_cmd_refresh(&Conf);
u_spawn(Conf.termpath);
}
void
kbfunc_lock(struct client_ctx *cc, void *arg)
kbfunc_lock(struct client_ctx *cc, union arg *arg)
{
conf_cmd_refresh(&Conf);
u_spawn(Conf.lockpath);
}
void
kbfunc_exec(struct client_ctx *scratch, void *arg)
kbfunc_exec(struct client_ctx *cc, union arg *arg)
{
#define NPATHS 256
char **ap, *paths[NPATHS], *path, tpath[MAXPATHLEN];
int l, i, j, ngroups;
gid_t mygroups[NGROUPS_MAX];
uid_t ruid, euid, suid;
DIR *dirp;
struct dirent *dp;
struct stat sb;
struct menu_q menuq;
struct menu *mi;
char *label;
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 = (int)arg;
switch(cmd) {
sc = cc->sc;
switch (cmd) {
case CWM_EXEC_PROGRAM:
label = "exec";
break;
@@ -288,16 +261,14 @@ kbfunc_exec(struct client_ctx *scratch, void *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);
/* just use default path until we have config to set this */
path = xstrdup(_PATH_DEFPATH);
if ((path = getenv("PATH")) == NULL)
path = _PATH_DEFPATH;
pathcpy = path = xstrdup(path);
for (ap = paths; ap < &paths[NPATHS - 1] &&
(*ap = strsep(&path, ":")) != NULL;) {
(*ap = strsep(&pathcpy, ":")) != NULL;) {
if (**ap != '\0')
ap++;
}
@@ -316,67 +287,56 @@ kbfunc_exec(struct client_ctx *scratch, void *arg)
/* 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;
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);
if (access(tpath, X_OK) == 0) {
mi = xcalloc(1, sizeof(*mi));
strlcpy(mi->text, dp->d_name, sizeof(mi->text));
TAILQ_INSERT_TAIL(&menuq, mi, entry);
}
}
(void) closedir(dirp);
(void)closedir(dirp);
}
xfree(path);
if ((mi = search_start(&menuq,
search_match_exec, NULL, NULL, label, 1)) != NULL) {
if ((mi = menu_filter(sc, &menuq, label, NULL, 1,
search_match_exec, NULL)) != NULL) {
if (mi->text[0] == '\0')
goto out;
switch (cmd) {
case CWM_EXEC_PROGRAM:
u_spawn(mi->text);
break;
case CWM_EXEC_WM:
exec_wm(mi->text);
u_exec(mi->text);
warn("%s", mi->text);
break;
default:
err(1, "kb_func: egad, cmd changed value!");
break;
}
}
out:
if (mi != NULL && mi->dummy)
xfree(mi);
while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
TAILQ_REMOVE(&menuq, mi, entry);
xfree(mi);
}
xfree(path);
}
void
kbfunc_ssh(struct client_ctx *scratch, void *arg)
kbfunc_ssh(struct client_ctx *cc, union arg *arg)
{
struct menu_q menuq;
struct menu *mi;
FILE *fp;
size_t len;
char *buf, *lbuf, *p, *home;
char hostbuf[MAXHOSTNAMELEN], filename[MAXPATHLEN], cmd[256];
int l;
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;
@@ -410,23 +370,23 @@ kbfunc_ssh(struct client_ctx *scratch, void *arg)
if (p - buf + 1 > sizeof(hostbuf))
continue;
(void) strlcpy(hostbuf, buf, p - buf + 1);
XCALLOC(mi, struct menu);
mi = xcalloc(1, sizeof(*mi));
(void) strlcpy(mi->text, hostbuf, sizeof(mi->text));
TAILQ_INSERT_TAIL(&menuq, mi, entry);
}
xfree(lbuf);
fclose(fp);
if ((mi = search_start(&menuq,
search_match_exec, NULL, NULL, "ssh", 1)) != NULL) {
conf_cmd_refresh(&Conf);
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) {
@@ -436,64 +396,97 @@ kbfunc_ssh(struct client_ctx *scratch, void *arg)
}
void
kbfunc_client_label(struct client_ctx *cc, void *arg)
kbfunc_client_label(struct client_ctx *cc, union arg *arg)
{
grab_label(cc);
struct menu *mi;
struct menu_q menuq;
TAILQ_INIT(&menuq);
/* dummy is set, so this will always return */
mi = menu_filter(cc->sc, &menuq, "label", cc->label, 1,
search_match_text, NULL);
if (!mi->abort) {
if (cc->label != NULL)
xfree(cc->label);
cc->label = xstrdup(mi->text);
}
xfree(mi);
}
void
kbfunc_client_delete(struct client_ctx *cc, void *arg)
kbfunc_client_delete(struct client_ctx *cc, union arg *arg)
{
client_send_delete(cc);
}
void
kbfunc_client_groupselect(struct client_ctx *cc, void *arg)
kbfunc_client_group(struct client_ctx *cc, union arg *arg)
{
if (Groupmode)
group_done();
else
group_enter();
group_hidetoggle(cc->sc, KBTOGROUP(arg->i));
}
void
kbfunc_client_group(struct client_ctx *cc, void *arg)
kbfunc_client_grouponly(struct client_ctx *cc, union arg *arg)
{
if (Groupmode)
group_select(KBTOGROUP((int)arg));
else
group_hidetoggle(KBTOGROUP((int)arg));
group_only(cc->sc, KBTOGROUP(arg->i));
}
void
kbfunc_client_nextgroup(struct client_ctx *cc, void *arg)
kbfunc_client_cyclegroup(struct client_ctx *cc, union arg *arg)
{
group_slide(1);
group_cycle(cc->sc, arg->i);
}
void
kbfunc_client_prevgroup(struct client_ctx *cc, void *arg)
kbfunc_client_nogroup(struct client_ctx *cc, union arg *arg)
{
group_slide(0);
group_alltoggle(cc->sc);
}
void
kbfunc_client_nogroup(struct client_ctx *cc, void *arg)
kbfunc_client_grouptoggle(struct client_ctx *cc, union arg *arg)
{
if (Groupmode)
group_deletecurrent();
else
group_alltoggle();
/* XXX for stupid X apps like xpdf and gvim */
XGrabKeyboard(X_Dpy, cc->win, True,
GrabModeAsync, GrabModeAsync, CurrentTime);
group_sticky_toggle_enter(cc);
}
void
kbfunc_client_maximize(struct client_ctx *cc, void *arg)
kbfunc_client_movetogroup(struct client_ctx *cc, union arg *arg)
{
group_movetogroup(cc, KBTOGROUP(arg->i));
}
void
kbfunc_client_maximize(struct client_ctx *cc, union arg *arg)
{
client_maximize(cc);
}
void
kbfunc_client_vmaximize(struct client_ctx *cc, void *arg)
kbfunc_client_vmaximize(struct client_ctx *cc, union arg *arg)
{
client_vertmaximize(cc);
}
void
kbfunc_client_hmaximize(struct client_ctx *cc, union arg *arg)
{
client_horizmaximize(cc);
}
void
kbfunc_quit_wm(struct client_ctx *cc, union arg *arg)
{
_xev_quit = 1;
}
void
kbfunc_reload(struct client_ctx *cc, union arg *arg)
{
conf_reload(&Conf);
}

418
menu.c Normal file
View File

@@ -0,0 +1,418 @@
/*
* Copyright (c) 2008 Owain G. Ainsworth <oga@openbsd.org>
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/param.h>
#include <sys/queue.h>
#include <err.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "calmwm.h"
#define PROMPT_SCHAR '<27>'
#define PROMPT_ECHAR '<27>'
struct menu_ctx {
char searchstr[MENU_MAXENTRY + 1];
char dispstr[MENU_MAXENTRY*2 + 1];
char promptstr[MENU_MAXENTRY + 1];
int hasprompt;
int list;
int listing;
int changed;
int noresult;
int prev;
int entry;
int width;
int num;
int x;
int y;
void (*match)(struct menu_q *, struct menu_q *, char *);
void (*print)(struct menu *, int);
};
static struct menu *menu_handle_key(XEvent *, struct menu_ctx *,
struct menu_q *, struct menu_q *);
static void menu_handle_move(XEvent *, struct menu_ctx *,
struct screen_ctx *);
static struct menu *menu_handle_release(XEvent *, struct menu_ctx *,
struct screen_ctx *, struct menu_q *);
static void menu_draw(struct screen_ctx *, struct menu_ctx *,
struct menu_q *, struct menu_q *);
static int menu_calc_entry(struct screen_ctx *, struct menu_ctx *,
int, int);
void
menu_init(struct screen_ctx *sc)
{
XGCValues gv;
sc->menuwin = XCreateSimpleWindow(X_Dpy, sc->rootwin, 0, 0, 1, 1, 0,
sc->color[CWM_COLOR_BG_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;
sc->gc = XCreateGC(X_Dpy, sc->menuwin,
GCForeground|GCBackground|GCFunction, &gv);
}
struct menu *
menu_filter(struct screen_ctx *sc, struct menu_q *menuq, char *prompt,
char *initial, int dummy,
void (*match)(struct menu_q *, struct menu_q *, char *),
void (*print)(struct menu *, int))
{
struct menu_ctx mc;
struct menu_q resultq;
struct menu *mi = NULL;
XEvent e;
Window focuswin;
int evmask, focusrevert;
TAILQ_INIT(&resultq);
bzero(&mc, sizeof(mc));
xu_ptr_getpos(sc->rootwin, &mc.x, &mc.y);
if (prompt == NULL) {
evmask = MenuMask;
mc.promptstr[0] = '\0';
mc.list = 1;
} else {
evmask = 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(sc, mc.dispstr, strlen(mc.dispstr));
mc.hasprompt = 1;
}
if (initial != NULL)
strlcpy(mc.searchstr, initial, sizeof(mc.searchstr));
else
mc.searchstr[0] = '\0';
mc.match = match;
mc.print = print;
mc.entry = mc.prev = -1;
XMoveResizeWindow(X_Dpy, sc->menuwin, mc.x, mc.y, mc.width,
font_height(sc));
XSelectInput(X_Dpy, sc->menuwin, evmask);
XMapRaised(X_Dpy, sc->menuwin);
if (xu_ptr_grab(sc->menuwin, MenuGrabMask, Cursor_question) < 0) {
XUnmapWindow(X_Dpy, sc->menuwin);
return (NULL);
}
XGetInputFocus(X_Dpy, &focuswin, &focusrevert);
XSetInputFocus(X_Dpy, sc->menuwin, RevertToPointerRoot, CurrentTime);
/* make sure keybindings don't remove keys from the menu stream */
XGrabKeyboard(X_Dpy, sc->menuwin, True,
GrabModeAsync, GrabModeAsync, CurrentTime);
for (;;) {
mc.changed = 0;
XWindowEvent(X_Dpy, sc->menuwin, evmask, &e);
switch (e.type) {
default:
break;
case KeyPress:
if ((mi = menu_handle_key(&e, &mc, menuq, &resultq))
!= NULL)
goto out;
/* FALLTHROUGH */
case Expose:
menu_draw(sc, &mc, menuq, &resultq);
break;
case MotionNotify:
menu_handle_move(&e, &mc, sc);
break;
case ButtonRelease:
if ((mi = menu_handle_release(&e, &mc, sc, &resultq))
!= NULL)
goto out;
break;
}
}
out:
if (dummy == 0 && mi->dummy) { /* no match */
xfree (mi);
mi = NULL;
xu_ptr_ungrab();
XSetInputFocus(X_Dpy, focuswin, focusrevert, CurrentTime);
}
XUnmapWindow(X_Dpy, sc->menuwin);
XUngrabKeyboard(X_Dpy, CurrentTime);
return (mi);
}
static struct menu *
menu_handle_key(XEvent *e, struct menu_ctx *mc, struct menu_q *menuq,
struct menu_q *resultq)
{
struct menu *mi;
enum ctltype ctl;
char chr;
size_t len;
if (input_keycodetrans(e->xkey.keycode, e->xkey.state,
&ctl, &chr) < 0)
return (NULL);
switch (ctl) {
case CTL_ERASEONE:
if ((len = strlen(mc->searchstr)) > 0) {
mc->searchstr[len - 1] = '\0';
mc->changed = 1;
}
break;
case CTL_UP:
mi = TAILQ_LAST(resultq, menu_q);
if (mi == NULL)
break;
TAILQ_REMOVE(resultq, mi, resultentry);
TAILQ_INSERT_HEAD(resultq, mi, resultentry);
break;
case CTL_DOWN:
mi = TAILQ_FIRST(resultq);
if (mi == NULL)
break;
TAILQ_REMOVE(resultq, mi, resultentry);
TAILQ_INSERT_TAIL(resultq, mi, resultentry);
break;
case CTL_RETURN:
/*
* Return whatever the cursor is currently on. Else
* even if dummy is zero, we need to return something.
*/
if ((mi = TAILQ_FIRST(resultq)) == NULL) {
mi = xmalloc(sizeof *mi);
(void)strlcpy(mi->text,
mc->searchstr, sizeof(mi->text));
mi->dummy = 1;
}
mi->abort = 0;
return (mi);
case CTL_WIPE:
mc->searchstr[0] = '\0';
mc->changed = 1;
break;
case CTL_ALL:
mc->list = !mc->list;
break;
case CTL_ABORT:
mi = xmalloc(sizeof *mi);
mi->text[0] = '\0';
mi->dummy = 1;
mi->abort = 1;
return (mi);
default:
break;
}
if (chr != '\0') {
char str[2];
str[0] = chr;
str[1] = '\0';
mc->changed = 1;
strlcat(mc->searchstr, str, sizeof(mc->searchstr));
}
mc->noresult = 0;
if (mc->changed && mc->searchstr[0] != '\0') {
(*mc->match)(menuq, resultq, mc->searchstr);
/* If menuq is empty, never show we've failed */
mc->noresult = TAILQ_EMPTY(resultq) && !TAILQ_EMPTY(menuq);
} else if (mc->changed)
TAILQ_INIT(resultq);
if (!mc->list && mc->listing && !mc->changed) {
TAILQ_INIT(resultq);
mc->listing = 0;
}
return (NULL);
}
static void
menu_draw(struct screen_ctx *sc, struct menu_ctx *mc, struct menu_q *menuq,
struct menu_q *resultq)
{
struct menu *mi;
int n, dy, xsave, ysave;
if (mc->list) {
if (TAILQ_EMPTY(resultq) && mc->list) {
/* Copy them all over. */
TAILQ_FOREACH(mi, menuq, entry)
TAILQ_INSERT_TAIL(resultq, mi,
resultentry);
mc->listing = 1;
} else if (mc->changed)
mc->listing = 0;
}
mc->num = 0;
mc->width = 0;
dy = 0;
if (mc->hasprompt) {
snprintf(mc->dispstr, sizeof(mc->dispstr), "%s%s%c",
mc->promptstr, mc->searchstr, PROMPT_ECHAR);
mc->width = font_width(sc, mc->dispstr, strlen(mc->dispstr));
dy = font_height(sc);
mc->num = 1;
}
TAILQ_FOREACH(mi, resultq, resultentry) {
char *text;
if (mc->print != NULL) {
(*mc->print)(mi, mc->listing);
text = mi->print;
} else {
mi->print[0] = '\0';
text = mi->text;
}
mc->width = MAX(mc->width, font_width(sc, text,
MIN(strlen(text), MENU_MAXENTRY)));
dy += font_height(sc);
mc->num++;
}
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;
/* never hide the top of the menu */
if (mc->y < 0)
mc->y = 0;
if (mc->x != xsave || mc->y != ysave)
xu_ptr_setpos(sc->rootwin, mc->x, mc->y);
XClearWindow(X_Dpy, sc->menuwin);
XMoveResizeWindow(X_Dpy, sc->menuwin, mc->x, mc->y, mc->width, dy);
if (mc->hasprompt) {
font_draw(sc, mc->dispstr, strlen(mc->dispstr), sc->menuwin,
0, font_ascent(sc) + 1);
n = 1;
} else
n = 0;
TAILQ_FOREACH(mi, resultq, resultentry) {
char *text = mi->print[0] != '\0' ?
mi->print : mi->text;
font_draw(sc, text, MIN(strlen(text), MENU_MAXENTRY),
sc->menuwin, 0, n * font_height(sc) + font_ascent(sc) + 1);
n++;
}
if (mc->hasprompt && n > 1)
XFillRectangle(X_Dpy, sc->menuwin, sc->gc,
0, font_height(sc), mc->width, font_height(sc));
if (mc->noresult)
XFillRectangle(X_Dpy, sc->menuwin, sc->gc,
0, 0, mc->width, font_height(sc));
}
static void
menu_handle_move(XEvent *e, struct menu_ctx *mc, struct screen_ctx *sc)
{
mc->prev = mc->entry;
mc->entry = menu_calc_entry(sc, mc, e->xbutton.x, e->xbutton.y);
if (mc->prev != -1)
XFillRectangle(X_Dpy, sc->menuwin, sc->gc, 0,
font_height(sc) * mc->prev, mc->width, font_height(sc));
if (mc->entry != -1) {
xu_ptr_regrab(MenuGrabMask, Cursor_select);
XFillRectangle(X_Dpy, sc->menuwin, sc->gc, 0,
font_height(sc) * mc->entry, mc->width, font_height(sc));
} else
xu_ptr_regrab(MenuGrabMask, Cursor_default);
}
static struct menu *
menu_handle_release(XEvent *e, struct menu_ctx *mc, struct screen_ctx *sc,
struct menu_q *resultq)
{
struct menu *mi;
int entry, i = 0;
entry = menu_calc_entry(sc, mc, e->xbutton.x, e->xbutton.y);
xu_ptr_ungrab();
if (mc->hasprompt)
i = 1;
TAILQ_FOREACH(mi, resultq, resultentry)
if (entry == i++)
break;
if (mi == NULL) {
mi = xmalloc(sizeof(*mi));
mi->text[0] = '\0';
mi->dummy = 1;
}
return (mi);
}
static int
menu_calc_entry(struct screen_ctx *sc, struct menu_ctx *mc, int x, int y)
{
int entry;
entry = y / font_height(sc);
/* in bounds? */
if (x <= 0 || x > mc->width || y <= 0 ||
y > font_height(sc) * mc->num || entry < 0 || entry >= mc->num)
entry = -1;
if (mc->hasprompt && entry == 0)
entry = -1;
return (entry);
}

279
mousefunc.c Normal file
View File

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

567
parse.y Normal file
View File

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

115
screen.c
View File

@@ -18,23 +18,22 @@
* $Id$
*/
#include "headers.h"
#include <sys/param.h>
#include <sys/queue.h>
#include <err.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "calmwm.h"
extern struct screen_ctx_q Screenq;
extern struct screen_ctx *Curscreen;
static void
_clearwindow_cb(int sig)
{
struct screen_ctx *sc = screen_current();
XUnmapWindow(X_Dpy, sc->infowin);
}
struct screen_ctx *
screen_fromroot(Window rootwin)
{
struct screen_ctx *sc;
struct screen_ctx *sc;
TAILQ_FOREACH(sc, &Screenq, entry)
if (sc->rootwin == rootwin)
@@ -44,19 +43,12 @@ 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 = screen_current();
u_int nwins, i, s;
struct client_ctx *cc;
Window *wins, w0, w1;
struct client_ctx *cc;
u_int nwins, i, s;
if (!XQueryTree(X_Dpy, sc->rootwin, &w0, &w1, &wins, &nwins))
return;
@@ -74,41 +66,68 @@ screen_updatestackingorder(void)
}
void
screen_init(void)
screen_init_xinerama(struct screen_ctx *sc)
{
XineramaScreenInfo *info;
int no;
struct screen_ctx *sc = screen_current();
if (HasXinerama == 0 || XineramaIsActive(X_Dpy) == 0) {
HasXinerama = 0;
sc->xinerama_no = 0;
}
sc->cycle_client = NULL;
info = XineramaQueryScreens(X_Dpy, &no);
if (info == NULL) {
/* Is xinerama actually off, instead of a malloc failure? */
if (sc->xinerama == NULL)
HasXinerama = 0;
return;
}
sc->infowin = XCreateSimpleWindow(X_Dpy, sc->rootwin, 0, 0,
1, 1, 1, sc->blackpixl, sc->whitepixl);
if (sc->xinerama != NULL)
XFree(sc->xinerama);
sc->xinerama = info;
sc->xinerama_no = no;
}
/* XXX - marius. */
if (signal(SIGALRM, _clearwindow_cb) == SIG_ERR)
err(1, "signal");
/*
* Find which xinerama screen the coordinates (x,y) is on.
*/
XineramaScreenInfo *
screen_find_xinerama(struct screen_ctx *sc, int x, int y)
{
XineramaScreenInfo *info;
int i;
for (i = 0; i < sc->xinerama_no; i++) {
info = &sc->xinerama[i];
if (x > info->x_org && x < info->x_org + info->width &&
y > info->y_org && y < info->y_org + info->height)
return (info);
}
return (NULL);
}
void
screen_infomsg(char *msg)
screen_update_geometry(struct screen_ctx *sc, int width, int height)
{
struct screen_ctx *sc = screen_current();
char buf[1024];
int dy, dx;
struct fontdesc *font = DefaultFont;
long geom[2], workareas[CALMWM_NGROUPS][4];
int i;
XUnmapWindow(X_Dpy, sc->infowin);
alarm(0);
sc->xmax = geom[0] = width;
sc->ymax = geom[1] = height;
XChangeProperty(X_Dpy, sc->rootwin, _NET_DESKTOP_GEOMETRY,
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)geom , 2);
snprintf(buf, sizeof(buf), ">%s", msg);
dy = font_ascent(font) + font_descent(font) + 1;
dx = font_width(font, buf, strlen(buf));
/* x, y, width, height. */
for (i = 0; i < CALMWM_NGROUPS; i++) {
workareas[i][0] = sc->gap.left;
workareas[i][1] = sc->gap.top;
workareas[i][2] = width - (sc->gap.left + sc->gap.right);
workareas[i][3] = height - (sc->gap.top + sc->gap.bottom);
}
XMoveResizeWindow(X_Dpy, sc->infowin, 0, 0, dx, dy);
XMapRaised(X_Dpy, sc->infowin);
font_draw(font, buf, strlen(buf), sc->infowin,
0, font_ascent(font) + 1);
alarm(1);
XChangeProperty(X_Dpy, sc->rootwin, _NET_WORKAREA,
XA_CARDINAL, 32, PropModeReplace,
(unsigned char *)workareas, CALMWM_NGROUPS * 4);
}

375
search.c
View File

@@ -17,291 +17,21 @@
* $Id$
*/
#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);
void
search_init(struct screen_ctx *sc)
{
sc->searchwin = XCreateSimpleWindow(X_Dpy, sc->rootwin, 0, 0,
1, 1, 1, sc->blackpixl, sc->whitepixl);
}
/*
* ranking. each rank type is assigned a weight. multiply this by
* the rank given. add them up. simple linear combination.
*/
/*
* Input: list of items,
* Output: choose one
* so, exactly like menus
*/
struct menu *
search_start(struct menu_q *menuq,
void (*match)(struct menu_q *, struct menu_q *, char *),
void (*rank)(struct menu_q *resultq, char *search),
void (*print)(struct menu *mi, int print),
char *prompt, int dummy)
{
struct screen_ctx *sc = screen_current();
int x, y, dx, dy, fontheight,
focusrevert, mutated, xmax, ymax, warp, added, beobnoxious = 0;
XEvent e;
char searchstr[MENU_MAXENTRY + 1];
char dispstr[MENU_MAXENTRY*2 + 1];
char promptstr[MENU_MAXENTRY + 1];
Window focuswin;
struct menu *mi = NULL, *dummy_mi = NULL;
struct menu_q resultq;
char chr;
enum ctltype ctl;
size_t len;
u_int n;
static int list = 0;
int listing = 0;
char endchar = '<EFBFBD>';
struct fontdesc *font = DefaultFont;
if (prompt == NULL)
prompt = "search";
TAILQ_INIT(&resultq);
xmax = DisplayWidth(X_Dpy, sc->which);
ymax = DisplayHeight(X_Dpy, sc->which);
xu_ptr_getpos(sc->rootwin, &x, &y);
searchstr[0] = '\0';
snprintf(promptstr, sizeof(promptstr), "%s <20>", prompt);
dy = fontheight = font_ascent(font) + font_descent(font) + 1;
snprintf(dispstr, sizeof(dispstr), "%s%c", promptstr, endchar);
dx = font_width(font, dispstr, strlen(dispstr));
XMoveResizeWindow(X_Dpy, sc->searchwin, x, y, dx, dy);
XSelectInput(X_Dpy, sc->searchwin, SearchMask);
XMapRaised(X_Dpy, sc->searchwin);
/*
* TODO: eventually, the mouse should be able to select
* results as well. Right now we grab it only to set a fancy
* cursor.
*/
if (xu_ptr_grab(sc->searchwin, 0, Cursor_question) < 0) {
XUnmapWindow(X_Dpy, sc->searchwin);
return (NULL);
}
XGetInputFocus(X_Dpy, &focuswin, &focusrevert);
XSetInputFocus(X_Dpy, sc->searchwin, RevertToPointerRoot, CurrentTime);
for (;;) {
added = mutated = 0;
XMaskEvent(X_Dpy, SearchMask, &e);
switch (e.type) {
case KeyPress:
/*
* XXX - C-s & C-r for next and prev.
*/
if (input_keycodetrans(e.xkey.keycode, e.xkey.state,
&ctl, &chr, 1) < 0)
continue;
switch (ctl) {
case CTL_ERASEONE:
if ((len = strlen(searchstr)) > 0) {
searchstr[len - 1] = '\0';
mutated = 1;
}
break;
case CTL_UP:
mi = TAILQ_LAST(&resultq, menu_q);
if (mi == NULL)
break;
TAILQ_REMOVE(&resultq, mi, resultentry);
TAILQ_INSERT_HEAD(&resultq, mi, resultentry);
break;
case CTL_DOWN:
mi = TAILQ_FIRST(&resultq);
if (mi == NULL)
break;
TAILQ_REMOVE(&resultq, mi, resultentry);
TAILQ_INSERT_TAIL(&resultq, mi, resultentry);
break;
case CTL_RETURN:
/* This is just picking the match the
* cursor is over. */
if ((mi = TAILQ_FIRST(&resultq)) != NULL) {
goto found;
} else if (dummy) {
dummy_mi = xmalloc(sizeof *dummy_mi);
(void) strlcpy(dummy_mi->text,
searchstr, sizeof(dummy_mi->text));
dummy_mi->dummy = 1;
goto found;
}
goto out;
case CTL_WIPE:
searchstr[0] = '\0';
mutated = 1;
break;
case CTL_ALL:
list = !list;
break;
case CTL_ABORT:
goto out;
default:
break;
}
if (chr != '\0') {
char str[2];
str[0] = chr;
str[1] = '\0';
mutated = 1;
added =
strlcat(searchstr, str, sizeof(searchstr));
}
beobnoxious = 0;
if (mutated && strlen(searchstr) > 0) {
(*match)(menuq, &resultq, searchstr);
beobnoxious = TAILQ_EMPTY(&resultq);
if (!beobnoxious && rank != NULL)
(*rank)(&resultq, searchstr);
} else if (mutated)
TAILQ_INIT(&resultq);
if (!list && listing && !mutated) {
TAILQ_INIT(&resultq);
listing = 0;
}
case Expose:
if (list) {
if (TAILQ_EMPTY(&resultq) && list) {
/* Copy them over and rank them. */
TAILQ_FOREACH(mi, menuq, entry)
TAILQ_INSERT_TAIL(&resultq, mi,
resultentry);
if (rank != NULL)
(*rank)(&resultq, searchstr);
listing = 1;
} else if (mutated)
listing = 0;
}
snprintf(dispstr, sizeof(dispstr), "%s%s%c",
promptstr, searchstr, endchar);
dx = font_width(font, dispstr, strlen(dispstr));
dy = fontheight;
TAILQ_FOREACH(mi, &resultq, resultentry) {
char *text;
if (print != NULL) {
(*print)(mi, listing);
text = mi->print;
} else {
mi->print[0] = '\0';
text = mi->text;
}
dx = MAX(dx, font_width(font, text,
MIN(strlen(text), MENU_MAXENTRY)));
dy += fontheight;
}
/*
* Calculate new geometry.
*
* XXX - put this into a util function -- it's
* used elsewhere, too.
*/
warp = 0;
if (x < 0) {
x = 0;
warp = 1;
}
if (x + dx >= xmax) {
x = xmax - dx;
warp = 1;
}
if (y < 0) {
y = 0;
warp = 1;
}
if (y + dy >= ymax) {
y = ymax - dy;
/* If the menu is too high, never hide the
* top of the menu.
*/
if (y < 0)
y = 0;
warp = 1;
}
if (warp)
xu_ptr_setpos(sc->rootwin, x, y);
XClearWindow(X_Dpy, sc->searchwin);
XMoveResizeWindow(X_Dpy, sc->searchwin, x, y, dx, dy);
font_draw(font, dispstr, strlen(dispstr), sc->searchwin,
0, font_ascent(font) + 1);
n = 1;
TAILQ_FOREACH(mi, &resultq, resultentry) {
char *text = mi->print[0] != '\0' ?
mi->print : mi->text;
font_draw(font, text,
MIN(strlen(text), MENU_MAXENTRY),
sc->searchwin,
0, n*fontheight + font_ascent(font) + 1);
n++;
}
if (n > 1)
XFillRectangle(X_Dpy, sc->searchwin, sc->gc,
0, fontheight, dx, fontheight);
if (beobnoxious)
XFillRectangle(X_Dpy, sc->searchwin, sc->gc,
0, 0, dx, fontheight);
break;
}
}
out:
/* (if no match) */
xu_ptr_ungrab();
XSetInputFocus(X_Dpy, focuswin, focusrevert, CurrentTime);
found:
XUnmapWindow(X_Dpy, sc->searchwin);
if (dummy && dummy_mi != NULL)
return (dummy_mi);
return (mi);
}
static int strsubmatch(char *, char *, int);
/*
* Match: label, title, class.
@@ -310,9 +40,11 @@ found:
void
search_match_client(struct menu_q *menuq, struct menu_q *resultq, char *search)
{
struct winname *wn;
struct menu *mi, *tierp[4], *before = NULL;
int ntiers = sizeof(tierp)/sizeof(tierp[0]);
struct winname *wn;
struct menu *mi, *tierp[4], *before = NULL;
int ntiers;
ntiers = sizeof(tierp) / sizeof(tierp[0]);
TAILQ_INIT(resultq);
@@ -331,27 +63,23 @@ search_match_client(struct menu_q *menuq, struct menu_q *resultq, char *search)
struct client_ctx *cc = mi->ctx;
/* First, try to match on labels. */
if (cc->label != NULL && _strsubmatch(search, cc->label, 0)) {
if (cc->label != NULL && strsubmatch(search, cc->label, 0)) {
cc->matchname = cc->label;
tier = 0;
}
}
/* Then, on window names. */
if (tier < 0) {
TAILQ_FOREACH_REVERSE(wn, &cc->nameq, winname_q, entry)
if (_strsubmatch(search, wn->name, 0)) {
cc->matchname = wn->name;
tier = 2;
break;
}
if (strsubmatch(search, wn->name, 0)) {
cc->matchname = wn->name;
tier = 2;
break;
}
}
/*
* See if there is a match on the window class
* name.
*/
if (tier < 0 && _strsubmatch(search, cc->app_class, 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;
}
@@ -367,9 +95,7 @@ search_match_client(struct menu_q *menuq, struct menu_q *resultq, char *search)
if (cc == client_current() && tier < ntiers - 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--;
@@ -382,7 +108,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--)
;
@@ -398,8 +123,10 @@ search_match_client(struct menu_q *menuq, struct menu_q *resultq, char *search)
void
search_print_client(struct menu *mi, int list)
{
struct client_ctx *cc = mi->ctx;
char flag = ' ';
struct client_ctx *cc;
char flag = ' ';
cc = mi->ctx;
if (cc == client_current())
flag = '!';
@@ -407,15 +134,17 @@ search_print_client(struct menu *mi, int list)
flag = '&';
if (list)
cc->matchname = TAILQ_FIRST(&cc->nameq)->name;
cc->matchname = cc->name;
snprintf(mi->print, sizeof(mi->print), "%c%s", flag, cc->matchname);
if (!list && cc->matchname != cc->name &&
strlen(mi->print) < sizeof(mi->print) - 1) {
int diff = sizeof(mi->print) - 1 - strlen(mi->print);
const char *marker = "";
char buf[MENU_MAXENTRY + 1];
const char *marker = "";
char buf[MENU_MAXENTRY + 1];
int diff;
diff = sizeof(mi->print) - 1 - strlen(mi->print);
/* One for the ':' */
diff -= 1;
@@ -436,32 +165,43 @@ search_print_client(struct menu *mi, int list)
void
search_match_text(struct menu_q *menuq, struct menu_q *resultq, char *search)
{
struct menu *mi;
struct menu *mi;
TAILQ_INIT(resultq);
TAILQ_FOREACH(mi, menuq, entry)
if (_strsubmatch(search, mi->text, 0))
if (strsubmatch(search, mi->text, 0))
TAILQ_INSERT_TAIL(resultq, mi, resultentry);
}
void
search_match_exec(struct menu_q *menuq, struct menu_q *resultq, char *search)
{
struct menu *mi;
struct menu *mi, *mj;
TAILQ_INIT(resultq);
TAILQ_FOREACH(mi, menuq, entry)
if (_strsubmatch(search, mi->text, 1))
TAILQ_FOREACH(mi, menuq, entry) {
if (strsubmatch(search, mi->text, 1) == 0 &&
fnmatch(search, mi->text, 0) == FNM_NOMATCH)
continue;
for (mj = TAILQ_FIRST(resultq); mj != NULL;
mj = TAILQ_NEXT(mj, resultentry)) {
if (strcasecmp(mi->text, mj->text) < 0) {
TAILQ_INSERT_BEFORE(mj, mi, resultentry);
break;
}
}
if (mj == NULL)
TAILQ_INSERT_TAIL(resultq, mi, resultentry);
}
}
static int
_strsubmatch(char *sub, char *str, int zeroidx)
strsubmatch(char *sub, char *str, int zeroidx)
{
size_t len, sublen;
u_int n, flen;
size_t len, sublen;
u_int n, flen;
if (sub == NULL || str == NULL)
return (0);
@@ -476,6 +216,7 @@ _strsubmatch(char *sub, char *str, int zeroidx)
flen = len - sublen;
else
flen = 0;
for (n = 0; n <= flen; n++)
if (strncasecmp(sub, str + n, sublen) == 0)
return (1);

61
strlcat.c Normal file
View File

@@ -0,0 +1,61 @@
/* $OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */
/*
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* OPENBSD ORIGINAL: lib/libc/string/strlcat.c */
#ifndef HAVE_STRLCAT
#include <sys/types.h>
#include <string.h>
/*
* Appends src to string dst of size siz (unlike strncat, siz is the
* full size of dst, not space left). At most siz-1 characters
* will be copied. Always NUL terminates (unless siz <= strlen(dst)).
* Returns strlen(src) + MIN(siz, strlen(initial dst)).
* If retval >= siz, truncation occurred.
*/
size_t
strlcat(char *dst, const char *src, size_t siz)
{
char *d = dst;
const char *s = src;
size_t n = siz;
size_t dlen;
/* Find the end of dst and adjust bytes left but don't go past end */
while (n-- != 0 && *d != '\0')
d++;
dlen = d - dst;
n = siz - dlen;
if (n == 0)
return(dlen + strlen(s));
while (*s != '\0') {
if (n != 1) {
*d++ = *s;
n--;
}
s++;
}
*d = '\0';
return(dlen + (s - src)); /* count does not include NUL */
}
#endif /* !HAVE_STRLCAT */

57
strlcpy.c Normal file
View File

@@ -0,0 +1,57 @@
/* $OpenBSD: strlcpy.c,v 1.10 2005/08/08 08:05:37 espie Exp $ */
/*
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* OPENBSD ORIGINAL: lib/libc/string/strlcpy.c */
#ifndef HAVE_STRLCPY
#include <sys/types.h>
#include <string.h>
/*
* Copy src to string dst of size siz. At most siz-1 characters
* will be copied. Always NUL terminates (unless siz == 0).
* Returns strlen(src); if retval >= siz, truncation occurred.
*/
size_t
strlcpy(char *dst, const char *src, size_t siz)
{
char *d = dst;
const char *s = src;
size_t n = siz;
/* Copy as many bytes as will fit */
if (n != 0 && --n != 0) {
do {
if ((*d++ = *s++) == 0)
break;
} while (--n != 0);
}
/* Not enough room in dst, add NUL and traverse rest of src */
if (n == 0) {
if (siz != 0)
*d = '\0'; /* NUL-terminate dst */
while (*s++)
;
}
return(s - src - 1); /* count does not include NUL */
}
#endif /* !HAVE_STRLCPY */

70
strtonum.c Normal file
View File

@@ -0,0 +1,70 @@
/* $OpenBSD: strtonum.c,v 1.6 2004/08/03 19:38:01 millert Exp $ */
/*
* Copyright (c) 2004 Ted Unangst and Todd Miller
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* OPENBSD ORIGINAL: lib/libc/stdlib/strtonum.c */
#ifndef HAVE_STRTONUM
#include <stdlib.h>
#include <limits.h>
#include <errno.h>
#define INVALID 1
#define TOOSMALL 2
#define TOOLARGE 3
long long
strtonum(const char *numstr, long long minval, long long maxval,
const char **errstrp)
{
long long ll = 0;
char *ep;
int error = 0;
struct errval {
const char *errstr;
int err;
} ev[4] = {
{ NULL, 0 },
{ "invalid", EINVAL },
{ "too small", ERANGE },
{ "too large", ERANGE },
};
ev[0].err = errno;
errno = 0;
if (minval > maxval)
error = INVALID;
else {
ll = strtoll(numstr, &ep, 10);
if (numstr == ep || *ep != '\0')
error = INVALID;
else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval)
error = TOOSMALL;
else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval)
error = TOOLARGE;
}
if (errstrp != NULL)
*errstrp = ev[error].errstr;
errno = ev[error].err;
if (error)
ll = 0;
return (ll);
}
#endif /* HAVE_STRTONUM */

78
util.c
View File

@@ -18,7 +18,16 @@
* $Id$
*/
#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
@@ -26,19 +35,10 @@
int
u_spawn(char *argstr)
{
char *args[MAXARGLEN], **ap;
char **end = &args[MAXARGLEN - 1];
switch (fork()) {
case 0:
ap = args;
while (ap < end && (*ap = strsep(&argstr, " \t")) != NULL)
ap++;
*ap = NULL;
setsid();
execvp(args[0], args);
err(1, args[0]);
u_exec(argstr);
err(1, "%s", argstr);
break;
case -1:
warn("fork");
@@ -51,42 +51,34 @@ u_spawn(char *argstr)
}
void
exec_wm(char *argstr)
u_exec(char *argstr)
{
char *args[MAXARGLEN], **ap = args;
char **end = &args[MAXARGLEN - 1];
char *args[MAXARGLEN], **ap = args;
char **end = &args[MAXARGLEN - 1], *tmp;
while (ap < end && (*ap = strsep(&argstr, " \t")) != NULL)
while (ap < end && (*ap = strsep(&argstr, " \t")) != NULL) {
if (**ap == '\0')
continue;
ap++;
if (argstr != NULL) {
/* deal with quoted strings */
switch(argstr[0]) {
case '"':
case '\'':
if ((tmp = strchr(argstr + 1, argstr[0]))
!= NULL) {
*(tmp++) = '\0';
*(ap++) = ++argstr;
argstr = tmp;
}
break;
default:
break;
}
}
}
*ap = NULL;
setsid();
execvp(args[0], args);
warn(args[0]);
}
int dirent_isdir(char *filename) {
struct stat buffer;
int return_value;
return_value = stat(filename, &buffer);
if(return_value == -1)
return 0;
else
return S_ISDIR(buffer.st_mode);
}
int dirent_islink(char *filename) {
struct stat buffer;
int return_value;
return_value = lstat(filename, &buffer);
if(return_value == -1)
return 0;
else
return S_ISLNK(buffer.st_mode);
}

668
xevents.c
View File

@@ -24,94 +24,125 @@
* management of the xevent's.
*/
#include "headers.h"
#include <sys/param.h>
#include <sys/queue.h>
#include <err.h>
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "calmwm.h"
/*
* 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 = client_current();
XWindowAttributes xattr;
struct screen_ctx *sc;
#ifdef notyet
int state;
#endif
XMapRequestEvent *e = &ee->xmaprequest;
struct client_ctx *cc = NULL, *old_cc;
XWindowAttributes xattr;
struct winmatch *wm;
if (old_cc != NULL)
if ((old_cc = client_current()) != NULL)
client_ptrsave(old_cc);
if ((cc = client_find(e->window)) == NULL) {
if ((cc = client_find(e->window)) == NULL) {
XGetWindowAttributes(X_Dpy, e->window, &xattr);
cc = client_new(e->window, screen_fromroot(xattr.root), 1);
sc = CCTOSC(cc);
} else {
cc->beepbeep = 1;
}
#ifdef notyet /* XXX - possibly, we shouldn't map if
* the window is withdrawn. */
if (xu_getstate(cc, &state) == 0 && state == WithdrawnState)
warnx("WITHDRAWNSTATE for %s", cc->name);
#endif
TAILQ_FOREACH(wm, &Conf.ignoreq, entry) {
if (strncasecmp(wm->title, cc->name, strlen(wm->title)) == 0)
return;
}
client_ptrwarp(cc);
xev_register(xev);
}
void
xev_handle_unmapnotify(struct xevent *xev, XEvent *ee)
static void
xev_handle_unmapnotify(XEvent *ee)
{
XUnmapEvent *e = &ee->xunmap;
struct client_ctx *cc;
struct screen_ctx *sc;
int wascurrent;
XUnmapEvent *e = &ee->xunmap;
XEvent ev;
struct client_ctx *cc;
/* XXX, we need a recursive locking wrapper around grab server */
XGrabServer(X_Dpy);
if ((cc = client_find(e->window)) != NULL) {
sc = CCTOSC(cc);
wascurrent = cc == client_current();
client_delete(cc, e->send_event, 0);
#ifdef notyet
/* XXX disable the ptrwarp until we handle it
* better. */
if (!client_delete(cc, e->send_event, 0) && wascurrent)
;/* client_ptrwarp(new_cc); */
#endif
/*
* If it's going to die anyway, nuke it.
*
* Else, if it's a synthetic event delete state, since they
* want it to be withdrawn. ICCM recommends you withdraw on
* this even if we haven't alredy been told to iconify, to
* deal with legacy clients.
*/
if (XCheckTypedWindowEvent(X_Dpy, cc->win,
DestroyNotify, &ev) || e->send_event != 0) {
client_delete(cc);
} else
client_hide(cc);
}
xev_register(xev);
XUngrabServer(X_Dpy);
}
void
xev_handle_destroynotify(struct xevent *xev, XEvent *ee)
static void
xev_handle_destroynotify(XEvent *ee)
{
XDestroyWindowEvent *e = &ee->xdestroywindow;
struct client_ctx *cc;
XDestroyWindowEvent *e = &ee->xdestroywindow;
struct client_ctx *cc;
if ((cc = client_find(e->window)) != NULL)
client_delete(cc, 1, 1);
xev_register(xev);
client_delete(cc);
}
void
xev_handle_configurerequest(struct xevent *xev, XEvent *ee)
static void
xev_handle_configurerequest(XEvent *ee)
{
XConfigureRequestEvent *e = &ee->xconfigurerequest;
struct client_ctx *cc;
struct screen_ctx *sc;
XWindowChanges wc;
XConfigureRequestEvent *e = &ee->xconfigurerequest;
struct client_ctx *cc;
struct screen_ctx *sc;
XWindowChanges wc;
if ((cc = client_find(e->window)) != NULL) {
sc = CCTOSC(cc);
sc = cc->sc;
client_gravitate(cc, 0);
if (e->value_mask & CWWidth)
cc->geom.width = e->width;
if (e->value_mask & CWHeight)
@@ -120,53 +151,48 @@ xev_handle_configurerequest(struct xevent *xev, XEvent *ee)
cc->geom.x = e->x;
if (e->value_mask & CWY)
cc->geom.y = e->y;
if (e->value_mask & CWBorderWidth)
wc.border_width = e->border_width;
if (cc->geom.x == 0 &&
cc->geom.width >= DisplayWidth(X_Dpy, sc->which))
if (cc->geom.x == 0 && cc->geom.width >= sc->xmax)
cc->geom.x -= cc->bwidth;
if (cc->geom.y == 0 &&
cc->geom.height >= DisplayHeight(X_Dpy, sc->which))
cc->geom.y -= cc->bwidth;
if (cc->geom.y == 0 && cc->geom.height >= sc->ymax)
cc->geom.y -= cc->bwidth;
client_gravitate(cc, 1);
wc.x = cc->geom.x;
wc.y = cc->geom.y;
wc.width = cc->geom.width;
wc.height = cc->geom.height;
wc.border_width = cc->bwidth;
wc.x = cc->geom.x - cc->bwidth;
wc.y = cc->geom.y - cc->bwidth;
wc.width = cc->geom.width + cc->bwidth*2;
wc.height = cc->geom.height + cc->bwidth*2;
wc.border_width = 0;
/* We need to move the parent window, too. */
XConfigureWindow(X_Dpy, cc->pwin, e->value_mask, &wc);
XConfigureWindow(X_Dpy, cc->win, e->value_mask, &wc);
xev_reconfig(cc);
} else {
/* let it do what it wants, it'll be ours when we map it. */
wc.x = e->x;
wc.y = e->y;
wc.width = e->width;
wc.height = e->height;
wc.border_width = e->border_width;
wc.stack_mode = Above;
e->value_mask &= ~CWStackMode;
XConfigureWindow(X_Dpy, e->window, e->value_mask, &wc);
}
wc.x = cc != NULL ? 0 : e->x;
wc.y = cc != NULL ? 0 : e->y;
wc.width = e->width;
wc.height = e->height;
wc.stack_mode = Above;
wc.border_width = 0;
e->value_mask &= ~CWStackMode;
e->value_mask |= CWBorderWidth;
XConfigureWindow(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 client_ctx *cc;
long tmp;
XPropertyEvent *e = &ee->xproperty;
struct screen_ctx *sc;
struct client_ctx *cc;
if ((cc = client_find(e->window)) != NULL) {
switch(e->atom) {
switch (e->atom) {
case XA_WM_NORMAL_HINTS:
XGetWMNormalHints(X_Dpy, cc->win, cc->size, &tmp);
client_getsizehints(cc);
break;
case XA_WM_NAME:
client_setname(cc);
@@ -175,15 +201,23 @@ xev_handle_propertynotify(struct xevent *xev, XEvent *ee)
/* 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;
XConfigureEvent ce;
ce.type = ConfigureNotify;
ce.event = cc->win;
@@ -192,194 +226,87 @@ xev_reconfig(struct client_ctx *cc)
ce.y = cc->geom.y;
ce.width = cc->geom.width;
ce.height = cc->geom.height;
ce.border_width = 0;
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;
XCrossingEvent *e = &ee->xcrossing;
struct client_ctx *cc;
if ((cc = client_find(e->window)) == NULL) {
/*
* XXX - later. messes up unclutter. but may be
* needed when we introduce menu windows and such into
* the main event loop.
*/
#ifdef notyet
if (e->window != e->root)
client_nocurrent();
#endif
} else
if ((cc = client_find(e->window)) != NULL)
client_setactive(cc, 1);
xev_register(xev);
}
void
xev_handle_leavenotify(struct xevent *xev, XEvent *ee)
static void
xev_handle_leavenotify(XEvent *ee)
{
client_leave(NULL);
xev_register(xev);
}
/* We can split this into two event handlers. */
void
xev_handle_buttonpress(struct xevent *xev, XEvent *ee)
static void
xev_handle_buttonpress(XEvent *ee)
{
XButtonEvent *e = &ee->xbutton;
struct client_ctx *cc, *old_cc = client_current();
struct screen_ctx *sc = screen_fromroot(e->root);
char *wname;
int altcontrol = e->state == (ControlMask|Mod1Mask);
XButtonEvent *e = &ee->xbutton;
struct client_ctx *cc, fakecc;
struct screen_ctx *sc;
struct mousebinding *mb;
sc = screen_fromroot(e->root);
cc = client_find(e->window);
if (sc->rootwin == e->window && !altcontrol) {
struct menu_q menuq;
struct menu *mi;
/* Ignore caps lock and numlock */
e->state &= ~(Mod2Mask | LockMask);
/* XXXSIGH!!!! */
if (e->button == Button2) {
group_menu(e);
goto out;
}
TAILQ_INIT(&menuq);
switch (e->button) {
case Button1:
TAILQ_FOREACH(cc, &Clientq, entry) {
if (cc->flags & CLIENT_HIDDEN) {
if (cc->label != NULL)
wname = cc->label;
else
wname = cc->name;
if (wname == NULL)
continue;
XCALLOC(mi, struct menu);
strlcpy(mi->text,
wname, sizeof(mi->text));
mi->ctx = cc;
TAILQ_INSERT_TAIL(&menuq, mi, entry);
}
}
TAILQ_FOREACH(mb, &Conf.mousebindingq, entry) {
if (e->button == mb->button && e->state == mb->modmask)
break;
case Button3: {
struct cmd *cmd;
if (conf_cmd_changed(Conf.menu_path)) {
conf_cmd_clear(&Conf);
conf_cmd_populate(&Conf, Conf.menu_path);
}
TAILQ_FOREACH(cmd, &Conf.cmdq, entry) {
XCALLOC(mi, struct menu);
strlcpy(mi->text, cmd->label, sizeof(mi->text));
mi->ctx = cmd;
TAILQ_INSERT_TAIL(&menuq, mi, entry);
}
break;
}
default:
break;
}
if (TAILQ_EMPTY(&menuq))
goto out;
mi = (struct menu *)grab_menu(e, &menuq);
if (mi == NULL)
goto cleanup;
switch (e->button) {
case Button1:
cc = (struct client_ctx *)mi->ctx;
client_unhide(cc);
if (old_cc != NULL)
client_ptrsave(old_cc);
client_ptrwarp(cc);
break;
case Button3:
u_spawn(((struct cmd *)mi->ctx)->image);
break;
default:
break;
}
cleanup:
while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
TAILQ_REMOVE(&menuq, mi, entry);
xfree(mi);
}
goto out;
}
if (cc == NULL || e->state == 0)
goto out;
if (mb == NULL)
return;
if (mb->context == MOUSEBIND_CTX_ROOT) {
if (e->window != sc->rootwin)
return;
cc = &fakecc;
cc->sc = screen_fromroot(e->window);
} else if (cc == NULL) /* (mb->context == MOUSEBIND_CTX_WIN */
return;
sc = CCTOSC(cc);
switch (e->button) {
case Button1:
if (altcontrol && !Groupmode)
group_sticky_toggle_enter(cc);
else {
grab_drag(cc);
client_move(cc);
}
break;
case Button2:
/* XXXSIGH!!! */
if (Groupmode)
group_click(cc);
else {
grab_sweep(cc);
client_resize(cc);
}
break;
case Button3:
client_ptrsave(cc);
client_lower(cc);
break;
}
out:
xev_register(xev);
(*mb->callback)(cc, e);
}
void
xev_handle_buttonrelease(struct xevent *xev, XEvent *ee)
static void
xev_handle_buttonrelease(XEvent *ee)
{
struct client_ctx *cc = client_current();
struct client_ctx *cc;
if (cc != NULL && !Groupmode)
if ((cc = client_current()) != NULL)
group_sticky_toggle_exit(cc);
xev_register(xev);
}
void
xev_handle_keypress(struct xevent *xev, XEvent *ee)
static void
xev_handle_keypress(XEvent *ee)
{
XKeyEvent *e = &ee->xkey;
struct client_ctx *cc = NULL; /* Make gcc happy. */
struct keybinding *kb;
KeySym keysym, skeysym;
int modshift;
XKeyEvent *e = &ee->xkey;
struct client_ctx *cc = NULL, fakecc;
struct keybinding *kb;
KeySym keysym, skeysym;
int modshift;
keysym = XKeycodeToKeysym(X_Dpy, e->keycode, 0);
skeysym = XKeycodeToKeysym(X_Dpy, e->keycode, 1);
TAILQ_FOREACH(kb, &Conf.keybindingq, entry) {
/* we don't care about caps lock and numlock here */
e->state &= ~(LockMask | Mod2Mask);
TAILQ_FOREACH(kb, &Conf.keybindingq, entry) {
if (keysym != kb->keysym && skeysym == kb->keysym)
modshift = ShiftMask;
else
@@ -389,224 +316,133 @@ xev_handle_keypress(struct xevent *xev, XEvent *ee)
continue;
if ((kb->keycode != 0 && kb->keysym == NoSymbol &&
kb->keycode == e->keycode) || kb->keysym ==
(modshift == 0 ? keysym : skeysym))
kb->keycode == e->keycode) || kb->keysym ==
(modshift == 0 ? keysym : skeysym))
break;
}
if (kb == NULL && e->window == screen_current()->groupwin)
group_display_keypress(e->keycode);
}
if (kb == NULL)
goto out;
return;
if (kb->flags & KBFLAG_NEEDCLIENT) {
if (((cc = client_find(e->window)) == NULL) &&
(cc = client_current()) == NULL)
return;
} else {
cc = &fakecc;
cc->sc = screen_fromroot(e->window);
}
if ((kb->flags & (KBFLAG_NEEDCLIENT|KBFLAG_FINDCLIENT)) &&
(cc = client_find(e->window)) == NULL &&
(cc = client_current()) == NULL)
if (kb->flags & KBFLAG_NEEDCLIENT)
goto out;
(*kb->callback)(cc, kb->argument);
out:
xev_register(xev);
(*kb->callback)(cc, &kb->argument);
}
/*
* This is only used for the alt suppression detection.
*/
void
xev_handle_keyrelease(struct xevent *xev, XEvent *ee)
static void
xev_handle_keyrelease(XEvent *ee)
{
XKeyEvent *e = &ee->xkey;
struct screen_ctx *sc = screen_fromroot(e->root);
int keysym;
XKeyEvent *e = &ee->xkey;
struct screen_ctx *sc;
struct client_ctx *cc;
int keysym;
sc = screen_fromroot(e->root);
cc = client_current();
keysym = XKeycodeToKeysym(X_Dpy, e->keycode, 0);
if (keysym != XK_Alt_L && keysym != XK_Alt_R)
goto out;
return;
sc->altpersist = 0;
/*
* XXX - better interface... xevents should not know about
* how/when to mtf.
*/
client_mtf(NULL);
client_altrelease();
out:
xev_register(xev);
if (cc != NULL) {
group_sticky_toggle_exit(cc);
XUngrabKeyboard(X_Dpy, CurrentTime);
}
}
void
xev_handle_clientmessage(struct xevent *xev, XEvent *ee)
static void
xev_handle_clientmessage(XEvent *ee)
{
XClientMessageEvent *e = &ee->xclient;
struct client_ctx *cc = client_find(e->window);
Atom xa_wm_change_state = XInternAtom(X_Dpy, "WM_CHANGE_STATE", False);
XClientMessageEvent *e = &ee->xclient;
Atom xa_wm_change_state;
struct client_ctx *cc;
if (cc == NULL)
goto out;
xa_wm_change_state = XInternAtom(X_Dpy, "WM_CHANGE_STATE", False);
if ((cc = client_find(e->window)) == NULL)
return;
if (e->message_type == xa_wm_change_state && e->format == 32 &&
e->data.l[0] == IconicState)
client_hide(cc);
out:
xev_register(xev);
}
/*
* X Event handling
*/
static struct xevent_q _xevq, _xevq_putaway;
static short _xev_q_lock = 0;
void
xev_init(void)
static void
xev_handle_randr(XEvent *ee)
{
TAILQ_INIT(&_xevq);
TAILQ_INIT(&_xevq_putaway);
}
XRRScreenChangeNotifyEvent *rev = (XRRScreenChangeNotifyEvent *)ee;
struct screen_ctx *sc;
int i;
struct xevent *
xev_new(Window *win, Window *root,
int type, void (*cb)(struct xevent *, XEvent *), void *arg)
{
struct xevent *xev;
XMALLOC(xev, struct xevent);
xev->xev_win = win;
xev->xev_root = root;
xev->xev_type = type;
xev->xev_cb = cb;
xev->xev_arg = arg;
return (xev);
}
void
xev_register(struct xevent *xev)
{
struct xevent_q *xq;
xq = _xev_q_lock ? &_xevq_putaway : &_xevq;
TAILQ_INSERT_TAIL(xq, xev, entry);
}
void
_xev_reincorporate(void)
{
struct xevent *xev;
while ((xev = TAILQ_FIRST(&_xevq_putaway)) != NULL) {
TAILQ_REMOVE(&_xevq_putaway, xev, entry);
TAILQ_INSERT_TAIL(&_xevq, xev, entry);
i = XRRRootToScreen(X_Dpy, rev->root);
TAILQ_FOREACH(sc, &Screenq, entry) {
if (sc->which == (u_int)i) {
XRRUpdateConfiguration(ee);
screen_update_geometry(sc, rev->width, rev->height);
screen_init_xinerama(sc);
}
}
}
void
xev_handle_expose(struct xevent *xev, XEvent *ee)
/*
* Called when the keymap has changed.
* Ungrab all keys, reload keymap and then regrab
*/
static void
xev_handle_mappingnotify(XEvent *ee)
{
XExposeEvent *e = &ee->xexpose;
struct screen_ctx *sc = screen_current();
struct client_ctx *cc;
XMappingEvent *e = &ee->xmapping;
struct keybinding *kb;
if ((cc = client_find(e->window)) != NULL)
client_draw_border(cc);
TAILQ_FOREACH(kb, &Conf.keybindingq, entry)
conf_ungrab(&Conf, kb);
if (sc->groupwin == e->window)
group_display_draw(sc);
XRefreshKeyboardMapping(e);
xev_register(xev);
TAILQ_FOREACH(kb, &Conf.keybindingq, entry)
conf_grab(&Conf, kb);
}
#define ASSIGN(xtype) do { \
root = e. xtype .root; \
win = e. xtype .window; \
} while (0)
static void
xev_handle_expose(XEvent *ee)
{
XExposeEvent *e = &ee->xexpose;
struct client_ctx *cc;
#define ASSIGN1(xtype) do { \
win = e. xtype .window; \
} while (0)
if ((cc = client_find(e->window)) != NULL && e->count == 0)
client_draw_border(cc);
}
volatile sig_atomic_t _xev_quit = 0;
void
xev_loop(void)
{
Window win, root;
int type;
XEvent e;
struct xevent *xev, *nextxev;
for (;;) {
#ifdef DIAGNOSTIC
if (TAILQ_EMPTY(&_xevq))
errx(1, "X event queue empty");
#endif
XEvent e;
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: /* XXX - still need shape event support. */
break;
}
/*
* Now, search for matches, and call each of them.
*/
_xev_q_lock = 1;
for (xev = TAILQ_FIRST(&_xevq); xev != NULL; xev = nextxev) {
nextxev = TAILQ_NEXT(xev, entry);
if ((type != xev->xev_type && xev->xev_type != 0) ||
(xev->xev_win != NULL && win != *xev->xev_win) ||
(xev->xev_root != NULL && root != *xev->xev_root))
continue;
TAILQ_REMOVE(&_xevq, xev, entry);
(*xev->xev_cb)(xev, &e);
}
_xev_q_lock = 0;
_xev_reincorporate();
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

@@ -18,13 +18,22 @@
* $Id$
*/
#include "headers.h"
#include <sys/param.h>
#include <sys/queue.h>
#include <err.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "calmwm.h"
void *
xmalloc(size_t siz)
{
void *p;
void *p;
if ((p = malloc(siz)) == NULL)
err(1, "malloc");
@@ -33,11 +42,11 @@ xmalloc(size_t siz)
}
void *
xcalloc(size_t siz)
xcalloc(size_t no, size_t siz)
{
void *p;
void *p;
if ((p = calloc(1, siz)) == NULL)
if ((p = calloc(no, siz)) == NULL)
err(1, "calloc");
return (p);
@@ -52,7 +61,7 @@ xfree(void *p)
char *
xstrdup(const char *str)
{
char *p;
char *p;
if ((p = strdup(str)) == NULL)
err(1, "strdup");

206
xutil.c
View File

@@ -18,22 +18,33 @@
* $Id$
*/
#include "headers.h"
#include <sys/param.h>
#include <sys/queue.h>
#include <err.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "calmwm.h"
static unsigned int ign_mods[] = { 0, LockMask, Mod2Mask, Mod2Mask | LockMask };
int
xu_ptr_grab(Window win, int mask, Cursor curs)
{
return (XGrabPointer(X_Dpy, win, False, mask,
GrabModeAsync, GrabModeAsync,
None, curs, CurrentTime) == GrabSuccess ? 0 : -1);
GrabModeAsync, GrabModeAsync,
None, curs, CurrentTime) == GrabSuccess ? 0 : -1);
}
int
xu_ptr_regrab(int mask, Cursor curs)
{
return (XChangeActivePointerGrab(X_Dpy, mask,
curs, CurrentTime) == GrabSuccess ? 0 : -1);
curs, CurrentTime) == GrabSuccess ? 0 : -1);
}
void
@@ -42,28 +53,32 @@ xu_ptr_ungrab(void)
XUngrabPointer(X_Dpy, CurrentTime);
}
int
void
xu_btn_grab(Window win, int mask, u_int btn)
{
return (XGrabButton(X_Dpy, btn, mask, win,
int i;
for (i = 0; i < sizeof(ign_mods)/sizeof(*ign_mods); i++)
XGrabButton(X_Dpy, btn, (mask | ign_mods[i]), win,
False, ButtonMask, GrabModeAsync,
GrabModeSync, None, None) == GrabSuccess ? 0 : -1);
GrabModeSync, None, None);
}
void
xu_btn_ungrab(Window win, int mask, u_int btn)
{
XUngrabButton(X_Dpy, btn, mask, win);
int i;
for (i = 0; i < sizeof(ign_mods)/sizeof(*ign_mods); i++)
XUngrabButton(X_Dpy, btn, (mask | ign_mods[i]), win);
}
void
xu_ptr_getpos(Window rootwin, int *x, int *y)
{
int tmp0, tmp1;
u_int tmp2;
Window w0, w1;
Window w0, w1;
int tmp0, tmp1;
u_int tmp2;
XQueryPointer(X_Dpy, rootwin, &w0, &w1, &tmp0, &tmp1, x, y, &tmp2);
XQueryPointer(X_Dpy, rootwin, &w0, &w1, &tmp0, &tmp1, x, y, &tmp2);
}
void
@@ -75,42 +90,59 @@ xu_ptr_setpos(Window win, int x, int y)
void
xu_key_grab(Window win, int mask, int keysym)
{
KeyCode code;
KeyCode code;
int i;
code = XKeysymToKeycode(X_Dpy, keysym);
if ((XKeycodeToKeysym(X_Dpy, code, 0) != keysym) &&
(XKeycodeToKeysym(X_Dpy, code, 1) == keysym))
mask |= ShiftMask;
XGrabKey(X_Dpy, XKeysymToKeycode(X_Dpy, keysym), mask, win, True,
GrabModeAsync, GrabModeAsync);
for (i = 0; i < sizeof(ign_mods)/sizeof(*ign_mods); i++)
XGrabKey(X_Dpy, code, (mask | ign_mods[i]), win,
True, GrabModeAsync, GrabModeAsync);
}
void
xu_sendmsg(struct client_ctx *cc, Atom atm, long val)
xu_key_ungrab(Window win, int mask, int keysym)
{
XEvent e;
KeyCode code;
int i;
code = XKeysymToKeycode(X_Dpy, keysym);
if ((XKeycodeToKeysym(X_Dpy, code, 0) != keysym) &&
(XKeycodeToKeysym(X_Dpy, code, 1) == keysym))
mask |= ShiftMask;
for (i = 0; i < sizeof(ign_mods)/sizeof(*ign_mods); i++)
XUngrabKey(X_Dpy, code, (mask | ign_mods[i]), win);
}
void
xu_sendmsg(Window win, Atom atm, long val)
{
XEvent e;
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;
Atom realtype;
u_long n, extra;
int format;
if (XGetWindowProperty(X_Dpy, cc->win, atm, 0L, len, False, type,
&realtype, &format, &n, &extra, p) != Success || *p == NULL)
if (XGetWindowProperty(X_Dpy, win, atm, 0L, len, False, type,
&realtype, &format, &n, &extra, p) != Success || *p == NULL)
return (-1);
if (n == 0)
@@ -119,13 +151,44 @@ xu_getprop(struct client_ctx *cc, Atom atm, Atom type, long len, u_char **p)
return (n);
}
int
xu_getstrprop(Window win, Atom atm, char **text) {
XTextProperty prop;
char **list;
int nitems = 0;
*text = NULL;
XGetTextProperty(X_Dpy, win, &prop, atm);
if (!prop.nitems)
return (0);
if (Xutf8TextPropertyToTextList(X_Dpy, &prop, &list,
&nitems) == Success && nitems > 0 && *list) {
if (nitems > 1) {
XTextProperty prop2;
if (Xutf8TextListToTextProperty(X_Dpy, list, nitems,
XUTF8StringStyle, &prop2) == Success) {
*text = xstrdup(prop2.value);
XFree(prop2.value);
}
} else {
*text = xstrdup(*list);
}
XFreeStringList(list);
}
XFree(prop.value);
return (nitems);
}
int
xu_getstate(struct client_ctx *cc, int *state)
{
Atom wm_state = XInternAtom(X_Dpy, "WM_STATE", False);
long *p = NULL;
long *p = NULL;
if (xu_getprop(cc, wm_state, wm_state, 2L, (u_char **)&p) <= 0)
if (xu_getprop(cc->win, WM_STATE, WM_STATE, 2L, (u_char **)&p) <= 0)
return (-1);
*state = (int)*p;
@@ -137,16 +200,87 @@ xu_getstate(struct client_ctx *cc, int *state)
void
xu_setstate(struct client_ctx *cc, int state)
{
long dat[2];
Atom wm_state;
long dat[2];
/* XXX cache */
wm_state = XInternAtom(X_Dpy, "WM_STATE", False);
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,
XChangeProperty(X_Dpy, cc->win, WM_STATE, WM_STATE, 32,
PropModeReplace, (unsigned char *)dat, 2);
}
Atom cwm_atoms[CWM_NO_ATOMS];
char *atoms[CWM_NO_ATOMS] = {
"WM_STATE",
"WM_DELETE_WINDOW",
"WM_TAKE_FOCUS",
"WM_PROTOCOLS",
"_MOTIF_WM_HINTS",
"UTF8_STRING",
"_NET_SUPPORTED",
"_NET_SUPPORTING_WM_CHECK",
"_NET_WM_NAME",
"_NET_ACTIVE_WINDOW",
"_NET_CLIENT_LIST",
"_NET_NUMBER_OF_DESKTOPS",
"_NET_CURRENT_DESKTOP",
"_NET_DESKTOP_VIEWPORT",
"_NET_DESKTOP_GEOMETRY",
"_NET_VIRTUAL_ROOTS",
"_NET_SHOWING_DESKTOP",
"_NET_DESKTOP_NAMES",
"_NET_WM_DESKTOP",
"_NET_WORKAREA",
};
void
xu_getatoms(void)
{
XInternAtoms(X_Dpy, atoms, CWM_NO_ATOMS, False, cwm_atoms);
}
void
xu_setwmname(struct screen_ctx *sc)
{
/*
* set up the _NET_SUPPORTED hint with all netwm atoms that we
* know about.
*/
XChangeProperty(X_Dpy, sc->rootwin, _NET_SUPPORTED, XA_ATOM, 32,
PropModeReplace, (unsigned char *)&_NET_SUPPORTED,
CWM_NO_ATOMS - CWM_NETWM_START);
/*
* netwm spec says that to prove that the hint is not stale you must
* provide _NET_SUPPORTING_WM_CHECK containing a window (we use the
* menu window). The property must be set on the root window and the
* window itself, the window also must have _NET_WM_NAME set with the
* window manager name.
*/
XChangeProperty(X_Dpy, sc->rootwin, _NET_SUPPORTING_WM_CHECK,
XA_WINDOW, 32, PropModeReplace, (unsigned char *)&sc->menuwin, 1);
XChangeProperty(X_Dpy, sc->menuwin, _NET_SUPPORTING_WM_CHECK,
XA_WINDOW, 32, PropModeReplace, (unsigned char *)&sc->menuwin, 1);
XChangeProperty(X_Dpy, sc->menuwin, _NET_WM_NAME, UTF8_STRING,
8, PropModeReplace, WMNAME, strlen(WMNAME));
}
unsigned long
xu_getcolor(struct screen_ctx *sc, char *name)
{
XColor color, tmp;
if (!XAllocNamedColor(X_Dpy, DefaultColormap(X_Dpy, sc->which),
name, &color, &tmp)) {
warnx("XAllocNamedColor error: '%s'", name);
return 0;
}
return color.pixel;
}
void
xu_freecolor(struct screen_ctx *sc, unsigned long pixel)
{
XFreeColors(X_Dpy, DefaultColormap(X_Dpy, sc->which), &pixel, 1, 0L);
}