77 Commits

Author SHA1 Message Date
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
21 changed files with 1324 additions and 1332 deletions

View File

@@ -4,14 +4,16 @@
PROG= cwm
SRCS= calmwm.c screen.c xmalloc.c client.c grab.c menu.c \
SRCS= calmwm.c screen.c xmalloc.c client.c menu.c \
search.c util.c xutil.c conf.c input.c xevents.c group.c \
kbfunc.c mousefunc.c font.c parse.y
CPPFLAGS+= -I${X11BASE}/include -I${X11BASE}/include/freetype2 -I${.CURDIR}
LDADD+= -L${X11BASE}/lib -lXft -lXrender -lX11 -lXau -lXdmcp -lXext \
-lfontconfig -lexpat -lfreetype -lz
CFLAGS+= -Wall
LDADD+= -L${X11BASE}/lib -lXft -lXrender -lX11 -lXau -lXdmcp \
-lfontconfig -lexpat -lfreetype -lz -lXinerama -lXrandr -lXext
MANDIR= ${X11BASE}/man/cat
MAN= cwm.1 cwmrc.5

2
TODO
View File

@@ -16,8 +16,6 @@
- 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.

174
calmwm.c
View File

@@ -31,21 +31,19 @@ Cursor Cursor_question;
struct screen_ctx_q Screenq;
struct screen_ctx *Curscreen;
u_int Nscreens;
struct client_ctx_q Clientq;
int Doshape, Shape_ev;
int HasXinerama, HasRandr, Randr_ev;
int Starting;
struct conf Conf;
/* 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)
@@ -69,46 +67,30 @@ main(int argc, char **argv)
argc -= optind;
argv += optind;
/* Ignore a few signals. */
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
if (signal(SIGCHLD, sigchld_cb) == SIG_ERR)
err(1, "signal");
if (signal(SIGCHLD, _sigchld_cb) == SIG_ERR)
err(1, "signal");
group_init();
Starting = 1;
dpy_init(display_name);
screen_init();
group_init();
client_init();
bzero(&Conf, sizeof(Conf));
conf_setup(&Conf, conf_file);
client_setup();
xu_getatoms();
x_setup();
Starting = 0;
xev_init();
XEV_QUICK(NULL, NULL, MapRequest, xev_handle_maprequest, NULL);
XEV_QUICK(NULL, NULL, UnmapNotify, xev_handle_unmapnotify, NULL);
XEV_QUICK(NULL, NULL, ConfigureRequest,
xev_handle_configurerequest, NULL);
XEV_QUICK(NULL, NULL, PropertyNotify, xev_handle_propertynotify, NULL);
XEV_QUICK(NULL, NULL, EnterNotify, xev_handle_enternotify, NULL);
XEV_QUICK(NULL, NULL, LeaveNotify, xev_handle_leavenotify, NULL);
XEV_QUICK(NULL, NULL, ButtonPress, xev_handle_buttonpress, NULL);
XEV_QUICK(NULL, NULL, ButtonRelease, xev_handle_buttonrelease, NULL);
XEV_QUICK(NULL, NULL, KeyPress, xev_handle_keypress, NULL);
XEV_QUICK(NULL, NULL, KeyRelease, xev_handle_keyrelease, NULL);
XEV_QUICK(NULL, NULL, Expose, xev_handle_expose, NULL);
XEV_QUICK(NULL, NULL, DestroyNotify, xev_handle_destroynotify, NULL);
XEV_QUICK(NULL, NULL, ClientMessage, xev_handle_clientmessage, NULL);
XEV_QUICK(NULL, NULL, MappingNotify, xev_handle_mapping, NULL);
xev_loop();
x_teardown();
return (0);
}
void
static void
dpy_init(const char *dpyname)
{
int i;
@@ -119,21 +101,18 @@ dpy_init(const char *dpyname)
XSetErrorHandler(x_errorhandler);
Doshape = XShapeQueryExtension(X_Dpy, &Shape_ev, &i);
TAILQ_INIT(&Screenq);
HasRandr = XRRQueryExtension(X_Dpy, &Randr_ev, &i);
}
void
static void
x_setup(void)
{
struct screen_ctx *sc;
struct keybinding *kb;
int i;
Nscreens = ScreenCount(X_Dpy);
for (i = 0; i < (int)Nscreens; i++) {
XMALLOC(sc, struct screen_ctx);
for (i = 0; i < ScreenCount(X_Dpy); i++) {
sc = xcalloc(1, sizeof(*sc));
x_setupscreen(sc, i);
TAILQ_INSERT_TAIL(&Screenq, sc, entry);
}
@@ -145,7 +124,6 @@ x_setup(void)
TAILQ_FOREACH(kb, &Conf.keybindingq, entry)
conf_grab(&Conf, kb);
Cursor_move = XCreateFontCursor(X_Dpy, XC_fleur);
Cursor_resize = XCreateFontCursor(X_Dpy, XC_bottom_right_corner);
Cursor_select = XCreateFontCursor(X_Dpy, XC_hand1);
@@ -153,67 +131,34 @@ x_setup(void)
Cursor_question = XCreateFontCursor(X_Dpy, XC_question_arrow);
}
void
static void
x_teardown(void)
{
struct screen_ctx *sc;
TAILQ_FOREACH(sc, &Screenq, entry)
XFreeGC(X_Dpy, sc->gc);
XCloseDisplay(X_Dpy);
}
static void
x_setupscreen(struct screen_ctx *sc, u_int which)
{
XColor tmp;
XGCValues gv;
Window *wins, w0, w1;
XWindowAttributes winattr;
XSetWindowAttributes rootattr;
int fake;
u_int nwins, i;
Curscreen = sc;
sc->display = x_screenname(which);
sc->which = which;
sc->rootwin = RootWindow(X_Dpy, which);
sc->rootwin = RootWindow(X_Dpy, sc->which);
sc->xmax = DisplayWidth(X_Dpy, sc->which);
sc->ymax = DisplayHeight(X_Dpy, sc->which);
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->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);
conf_color(&Conf);
font_init(sc);
conf_font(&Conf);
@@ -229,11 +174,8 @@ x_setupscreen(struct screen_ctx *sc, u_int which)
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);
winattr.map_state != IsViewable)
continue;
}
client_new(wins[i], sc, winattr.map_state != IsUnmapped);
}
XFree(wins);
@@ -246,38 +188,22 @@ x_setupscreen(struct screen_ctx *sc, u_int which)
XChangeWindowAttributes(X_Dpy, sc->rootwin,
CWEventMask, &rootattr);
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 = strrchr(dstr, ':')) == NULL)
return (NULL);
if ((cp = strchr(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
@@ -303,7 +229,7 @@ x_errorhandler(Display *dpy, XErrorEvent *e)
}
static void
_sigchld_cb(int which)
sigchld_cb(int which)
{
pid_t pid;
int save_errno = errno;

217
calmwm.h
View File

@@ -33,6 +33,27 @@
#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 client_ctx;
@@ -44,14 +65,9 @@ struct screen_ctx {
u_int which;
Window rootwin;
Window menuwin;
Colormap colormap;
XColor bgcolor, fgcolor, fccolor, redcolor, cyancolor,
whitecolor, blackcolor;
char *display;
unsigned long blackpixl, whitepixl, redpixl, bluepixl, cyanpixl;
GC gc;
Pixmap gray, blue, red;
struct color color[CWM_COLOR_MAX];
GC gc;
int altpersist;
@@ -62,6 +78,9 @@ struct screen_ctx {
XftDraw *xftdraw;
XftColor xftcolor;
int xinerama_no;
XineramaScreenInfo *xinerama;
};
TAILQ_HEAD(screen_ctx_q, screen_ctx);
@@ -78,9 +97,8 @@ TAILQ_HEAD(screen_ctx_q, screen_ctx);
#define CLIENT_DOVMAXIMIZE 0x10
#define CLIENT_VMAXIMIZED 0x20
#define CLIENT_HIGHLIGHT_BLUE 1
#define CLIENT_HIGHLIGHT_RED 2
#define CLIENT_HIGHLIGHT_GROUP 1
#define CLIENT_HIGHLIGHT_UNGROUP 2
struct winname {
TAILQ_ENTRY(winname) entry;
@@ -101,8 +119,6 @@ struct client_ctx {
Colormap cmap;
Window pwin;
u_int bwidth;
struct {
int x, y, width, height;
@@ -113,8 +129,6 @@ struct client_ctx {
int x,y;
} ptr;
int beepbeep;
int xproto;
int flags;
@@ -139,15 +153,12 @@ struct client_ctx {
TAILQ_HEAD(client_ctx_q, client_ctx);
static char *shortcut_to_name[] = {
"nogroup", "one", "two", "three",
"four", "five", "six", "seven",
"eight", "nine"
};
extern const char *shortcut_to_name[];
struct group_ctx {
TAILQ_ENTRY(group_ctx) entry;
struct client_ctx_q clients;
const char *name;
int shortcut;
int hidden;
int nhidden;
@@ -167,18 +178,6 @@ struct autogroupwin {
TAILQ_HEAD(autogroupwin_q, autogroupwin);
/* NULL/0 values indicate match any. */
struct xevent {
TAILQ_ENTRY(xevent) entry;
Window *xev_win;
Window *xev_root;
int xev_type;
void (*xev_cb)(struct xevent *, XEvent *);
void *xev_arg;
};
TAILQ_HEAD(xevent_q, xevent);
#define CWM_MOVE 0x01
#define CWM_RESIZE 0x02
#define CWM_PTRMOVE 0x04
@@ -213,14 +212,19 @@ TAILQ_HEAD(winmatch_q, winmatch);
#define KBTOGROUP(X) ((X) - 1)
union arg {
char *c;
int i;
};
struct keybinding {
TAILQ_ENTRY(keybinding) entry;
void (*callback)(struct client_ctx *, union arg *);
union arg argument;
int modmask;
int keysym;
int keycode;
int flags;
void (*callback)(struct client_ctx *, void *);
void *argument;
TAILQ_ENTRY(keybinding) entry;
};
struct cmd {
@@ -257,6 +261,18 @@ struct conf {
#define CONF_STICKY_GROUPS 0x0001
int flags;
#define CONF_BWIDTH 1
int bwidth;
#define CONF_MAMOUNT 1
int mamount;
#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];
@@ -308,18 +324,13 @@ struct mwm_hints {
int input_keycodetrans(KeyCode, u_int, enum ctltype *,
char *);
int x_errorhandler(Display *, XErrorEvent *);
void x_setup(void);
char *x_screenname(int);
void x_setupscreen(struct screen_ctx *, u_int);
__dead void usage(void);
struct client_ctx *client_find(Window);
void client_setup(void);
void client_init(void);
struct client_ctx *client_new(Window, struct screen_ctx *, int);
int client_delete(struct client_ctx *, int, int);
int client_delete(struct client_ctx *);
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 *);
@@ -329,61 +340,28 @@ 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_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 *);
void client_mtf(struct client_ctx *);
struct client_ctx *client_cycle(int);
struct client_ctx *client_mrunext(struct client_ctx *);
struct client_ctx *client_mruprev(struct client_ctx *);
void client_gethints(struct client_ctx *);
void client_freehints(struct client_ctx *);
void client_do_shape(struct client_ctx *);
struct menu *menu_filter(struct menu_q *, char *, char *, int,
void (*)(struct menu_q *, struct menu_q *, char *),
void (*)(struct menu *, int));
void menu_init(struct screen_ctx *);
void xev_handle_maprequest(struct xevent *, XEvent *);
void xev_handle_unmapnotify(struct xevent *, XEvent *);
void xev_handle_destroynotify(struct xevent *, XEvent *);
void xev_handle_configurerequest(struct xevent *, XEvent *);
void xev_handle_propertynotify(struct xevent *, XEvent *);
void xev_handle_enternotify(struct xevent *, XEvent *);
void xev_handle_leavenotify(struct xevent *, XEvent *);
void xev_handle_buttonpress(struct xevent *, XEvent *);
void xev_handle_buttonrelease(struct xevent *, XEvent *);
void xev_handle_keypress(struct xevent *, XEvent *);
void xev_handle_keyrelease(struct xevent *, XEvent *);
void xev_handle_expose(struct xevent *, XEvent *);
void xev_handle_clientmessage(struct xevent *, XEvent *);
void xev_handle_shape(struct xevent *, XEvent *);
void xev_handle_mapping(struct xevent *, XEvent *);
#define XEV_QUICK(a, b, c, d, e) do { \
xev_register(xev_new(a, b, c, d, e)); \
} while (0)
/* XXX should be xu_ */
void xev_reconfig(struct client_ctx *);
void xev_init(void);
struct xevent *xev_new(Window *, Window *, int,
void (*)(struct xevent *, XEvent *), void *);
void xev_register(struct xevent *);
void xev_loop(void);
void xu_getatoms(void);
int xu_ptr_grab(Window, int, Cursor);
void xu_btn_grab(Window, int, u_int);
int xu_ptr_regrab(int, Cursor);
@@ -399,60 +377,72 @@ int xu_getprop(struct client_ctx *, Atom, Atom, long,
char *xu_getstrprop(struct client_ctx *, Atom atm);
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);
int u_spawn(char *);
void u_exec(char *);
void grab_sweep(struct client_ctx *);
void grab_drag(struct client_ctx *);
void xfree(void *);
void *xmalloc(size_t);
void *xcalloc(size_t, size_t);
char *xstrdup(const char *);
#define XMALLOC(p, t) ((p) = (t *)xmalloc(sizeof * (p)))
#define XCALLOC(p, t) ((p) = (t *)xcalloc(1, sizeof * (p)))
void screen_init(void);
struct screen_ctx *screen_fromroot(Window);
struct screen_ctx *screen_current(void);
void screen_updatestackingorder(void);
void screen_init_xinerama(struct screen_ctx *);
XineramaScreenInfo *screen_find_xinerama(struct screen_ctx *, int, int);
void conf_setup(struct conf *, const char *);
void conf_client(struct client_ctx *);
void conf_grab(struct conf *, struct keybinding *);
void conf_ungrab(struct conf *, struct keybinding *);
void conf_bindname(struct conf *, char *, char *);
void conf_unbind(struct conf *, struct keybinding *);
void conf_mousebind(struct conf *, char *, char *);
void conf_mouseunbind(struct conf *, struct mousebinding *);
void conf_grab_mouse(struct client_ctx *);
void conf_reload(struct conf *);
void conf_font(struct conf *);
void conf_color(struct conf *);
void conf_init(struct conf *);
void conf_clear(struct conf *);
void conf_cmd_add(struct conf *, char *, char *, int);
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 *, void *);
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_group(struct client_ctx *, void *);
void kbfunc_client_cyclegroup(struct client_ctx *, void *);
void kbfunc_client_nogroup(struct client_ctx *, void *);
void kbfunc_client_grouptoggle(struct client_ctx *, void *);
void kbfunc_client_maximize(struct client_ctx *, void *);
void kbfunc_client_vmaximize(struct client_ctx *, void *);
void kbfunc_reload(struct client_ctx *, void *);
void kbfunc_quit_wm(struct client_ctx *, void *);
void kbfunc_moveresize(struct client_ctx *, void *);
void kbfunc_menu_search(struct client_ctx *, void *);
void kbfunc_exec(struct client_ctx *, void *);
void kbfunc_ssh(struct client_ctx *, void *);
void kbfunc_term(struct client_ctx *, void *);
void kbfunc_lock(struct client_ctx *, void *);
int parse_config(const char *, struct conf *);
void kbfunc_client_lower(struct client_ctx *, union arg *);
void kbfunc_client_raise(struct client_ctx *, union arg *);
void kbfunc_client_search(struct client_ctx *, union arg *);
void kbfunc_client_hide(struct client_ctx *, union arg *);
void kbfunc_client_cycle(struct client_ctx *, union arg *);
void kbfunc_client_rcycle(struct client_ctx *, union arg *);
void kbfunc_cmdexec(struct client_ctx *, union arg *);
void kbfunc_client_label(struct client_ctx *, union arg *);
void kbfunc_client_delete(struct client_ctx *, union arg *);
void kbfunc_client_group(struct client_ctx *, union arg *);
void kbfunc_client_grouponly(struct client_ctx *,
union arg *);
void kbfunc_client_cyclegroup(struct client_ctx *,
union arg *);
void kbfunc_client_nogroup(struct client_ctx *,
union arg *);
void kbfunc_client_grouptoggle(struct client_ctx *,
union arg *);
void kbfunc_client_movetogroup(struct client_ctx *,
union arg *);
void kbfunc_client_maximize(struct client_ctx *,
union arg *);
void kbfunc_client_vmaximize(struct client_ctx *,
union arg *);
void kbfunc_reload(struct client_ctx *, union arg *);
void kbfunc_quit_wm(struct client_ctx *, union arg *);
void kbfunc_moveresize(struct client_ctx *, union arg *);
void kbfunc_menu_search(struct client_ctx *, union arg *);
void kbfunc_exec(struct client_ctx *, union arg *);
void kbfunc_ssh(struct client_ctx *, union arg *);
void kbfunc_term(struct client_ctx *, union arg *);
void kbfunc_lock(struct client_ctx *, union arg *);
void mousefunc_window_resize(struct client_ctx *, void *);
void mousefunc_window_move(struct client_ctx *, void *);
@@ -474,6 +464,7 @@ void search_match_exec(struct menu_q *, struct menu_q *,
void group_init(void);
void group_hidetoggle(int);
void group_only(int);
void group_cycle(int);
void group_sticky(struct client_ctx *);
void group_client_delete(struct client_ctx *);
@@ -482,6 +473,7 @@ void group_alltoggle(void);
void group_sticky_toggle_enter(struct client_ctx *);
void group_sticky_toggle_exit(struct client_ctx *);
void group_autogroup(struct client_ctx *);
void group_movetogroup(struct client_ctx *, int);
void font_init(struct screen_ctx *);
int font_width(const char *, int);
@@ -507,11 +499,20 @@ 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;
#define WM_STATE cwm_atoms[0]
#define WM_DELETE_WINDOW cwm_atoms[1]
#define WM_TAKE_FOCUS cwm_atoms[2]
#define WM_PROTOCOLS cwm_atoms[3]
#define _MOTIF_WM_HINTS cwm_atoms[4]
#define _CWM_GRP cwm_atoms[5]
#define CWM_NO_ATOMS 6
extern Atom cwm_atoms[CWM_NO_ATOMS];
#endif /* _CALMWM_H_ */

408
client.c
View File

@@ -21,14 +21,19 @@
#include "headers.h"
#include "calmwm.h"
int _inwindowbounds(struct client_ctx *, int, int);
static struct client_ctx *client_mrunext(struct client_ctx *);
static struct client_ctx *client_mruprev(struct client_ctx *);
static void client_placecalc(struct client_ctx *);
static void client_update(struct client_ctx *);
static void client_gethints(struct client_ctx *);
static void client_freehints(struct client_ctx *);
static int client_inbound(struct client_ctx *, int, int);
static char emptystring[] = "";
struct client_ctx *_curcc = NULL;
void
client_setup(void)
client_init(void)
{
TAILQ_INIT(&Clientq);
}
@@ -39,7 +44,7 @@ client_find(Window win)
struct client_ctx *cc;
TAILQ_FOREACH(cc, &Clientq, entry)
if (cc->pwin == win || cc->win == win)
if (cc->win == win)
return (cc);
return (NULL);
@@ -49,16 +54,15 @@ struct client_ctx *
client_new(Window win, struct screen_ctx *sc, int mapped)
{
struct client_ctx *cc;
XSetWindowAttributes pxattr;
XWindowAttributes wattr;
XWMHints *wmhints;
long tmp;
int x, y, height, width, state;
int state;
if (win == None)
return (NULL);
XCALLOC(cc, struct client_ctx);
cc = xcalloc(1, sizeof(*cc));
XGrabServer(X_Dpy);
@@ -66,22 +70,8 @@ client_new(Window win, struct screen_ctx *sc, int mapped)
cc->sc = sc;
cc->win = win;
cc->size = XAllocSizeHints();
if (cc->size->width_inc == 0)
cc->size->width_inc = 1;
if (cc->size->height_inc == 0)
cc->size->height_inc = 1;
TAILQ_INIT(&cc->nameq);
client_setname(cc);
/*
* conf_client() needs at least cc->win and cc->name
*/
conf_client(cc);
XGetWMNormalHints(X_Dpy, cc->win, cc->size, &tmp);
XGetWindowAttributes(X_Dpy, cc->win, &wattr);
if (cc->size->flags & PBaseSize) {
cc->geom.min_dx = cc->size->base_width;
cc->geom.min_dy = cc->size->base_height;
@@ -90,12 +80,16 @@ client_new(Window win, struct screen_ctx *sc, int mapped)
cc->geom.min_dy = cc->size->min_height;
}
TAILQ_INIT(&cc->nameq);
client_setname(cc);
conf_client(cc);
/* Saved pointer position */
cc->ptr.x = -1;
cc->ptr.y = -1;
client_gravitate(cc, 1);
XGetWindowAttributes(X_Dpy, cc->win, &wattr);
cc->geom.x = wattr.x;
cc->geom.y = wattr.y;
cc->geom.width = wattr.width;
@@ -110,7 +104,9 @@ client_new(Window win, struct screen_ctx *sc, int mapped)
XFree(wmhints);
}
client_move(cc);
}
client_draw_border(cc);
if (xu_getstate(cc, &state) < 0)
state = NormalState;
@@ -118,42 +114,12 @@ client_new(Window win, struct screen_ctx *sc, int mapped)
XSelectInput(X_Dpy, cc->win, ColormapChangeMask | EnterWindowMask |
PropertyChangeMask | KeyReleaseMask);
x = cc->geom.x - cc->bwidth;
y = cc->geom.y - cc->bwidth;
width = cc->geom.width;
height = cc->geom.height;
if (cc->bwidth > 1) {
width += (cc->bwidth)*2;
height += (cc->bwidth)*2;
}
pxattr.override_redirect = True;
pxattr.background_pixel = sc->bgcolor.pixel;
pxattr.event_mask = ChildMask | ButtonPressMask | ButtonReleaseMask |
ExposureMask | EnterWindowMask;
cc->pwin = XCreateWindow(X_Dpy, sc->rootwin, x, y,
width, height, 0, /* XXX */
DefaultDepth(X_Dpy, sc->which), CopyFromParent,
DefaultVisual(X_Dpy, sc->which),
CWOverrideRedirect | CWBackPixel | CWEventMask, &pxattr);
cc->active = 0;
XAddToSaveSet(X_Dpy, cc->win);
XSetWindowBorderWidth(X_Dpy, cc->win, 0);
XReparentWindow(X_Dpy, cc->win, cc->pwin, cc->bwidth, cc->bwidth);
/* Notify client of its configuration. */
xev_reconfig(cc);
if (state == IconicState)
client_hide(cc);
else {
XMapRaised(X_Dpy, cc->pwin);
XMapWindow(X_Dpy, cc->win);
}
(state == IconicState) ? client_hide(cc) : client_unhide(cc);
xu_setstate(cc, cc->state);
XSync(X_Dpy, False);
@@ -171,51 +137,18 @@ client_new(Window win, struct screen_ctx *sc, int mapped)
return (cc);
}
void
client_do_shape(struct client_ctx *cc)
{
/* Windows not rectangular require more effort */
XRectangle *r;
int n, tmp;
if (Doshape) {
XShapeSelectInput(X_Dpy, cc->win, ShapeNotifyMask);
r = XShapeGetRectangles(X_Dpy, cc->win, ShapeBounding,
&n, &tmp);
if (n > 1)
XShapeCombineShape(X_Dpy, cc->pwin, ShapeBounding,
cc->bwidth, cc->bwidth, cc->win, ShapeBounding,
ShapeSet);
XFree(r);
}
}
int
client_delete(struct client_ctx *cc, int sendevent, int ignorewindow)
client_delete(struct client_ctx *cc)
{
struct screen_ctx *sc = CCTOSC(cc);
struct winname *wn;
if (cc->state == IconicState && !sendevent)
return (1);
group_client_delete(cc);
XGrabServer(X_Dpy);
xu_setstate(cc, WithdrawnState);
XRemoveFromSaveSet(X_Dpy, cc->win);
if (!ignorewindow) {
client_gravitate(cc, 0);
XSetWindowBorderWidth(X_Dpy, cc->win, 1); /* XXX */
XReparentWindow(X_Dpy, cc->win,
sc->rootwin, cc->geom.x, cc->geom.y);
}
if (cc->pwin)
XDestroyWindow(X_Dpy, cc->pwin);
XSync(X_Dpy, False);
XUngrabServer(X_Dpy);
@@ -235,7 +168,6 @@ client_delete(struct client_ctx *cc, int sendevent, int ignorewindow)
}
client_freehints(cc);
xfree(cc);
return (0);
@@ -296,42 +228,40 @@ client_current(void)
return (_curcc);
}
void
client_gravitate(struct client_ctx *cc, int yes)
{
int dx = 0, dy = 0, mult = yes ? 1 : -1;
int gravity = (cc->size->flags & PWinGravity) ?
cc->size->win_gravity : NorthWestGravity;
switch (gravity) {
case NorthWestGravity:
case SouthWestGravity:
case NorthEastGravity:
case StaticGravity:
dx = cc->bwidth;
case NorthGravity:
dy = cc->bwidth;
break;
}
cc->geom.x += mult * dx;
cc->geom.y += mult * dy;
}
void
client_maximize(struct client_ctx *cc)
{
struct screen_ctx *sc = CCTOSC(cc);
int xmax = sc->xmax, ymax = sc->ymax;
int x_org = 0, y_org = 0;
if (cc->flags & CLIENT_MAXIMIZED) {
cc->geom = cc->savegeom;
} else {
if (!(cc->flags & CLIENT_VMAXIMIZED))
cc->savegeom = cc->geom;
cc->geom.x = Conf.gap_left;
cc->geom.y = Conf.gap_top;
cc->geom.height = sc->ymax - (Conf.gap_top + Conf.gap_bottom);
cc->geom.width = sc->xmax - (Conf.gap_left + Conf.gap_right);
if (HasXinerama) {
XineramaScreenInfo *xine;
/*
* pick screen that the middle of the window is on.
* that's probably more fair than if just the origin of
* a window is poking over a boundary
*/
xine = screen_find_xinerama(CCTOSC(cc),
cc->geom.x + cc->geom.width / 2,
cc->geom.y + cc->geom.height / 2);
if (xine == NULL)
goto calc;
x_org = xine->x_org;
y_org = xine->y_org;
xmax = xine->width;
ymax = xine->height;
}
calc:
cc->geom.x = x_org - cc->bwidth + Conf.gap_left;
cc->geom.y = y_org - cc->bwidth + Conf.gap_top;
cc->geom.height = ymax - (Conf.gap_top + Conf.gap_bottom);
cc->geom.width = xmax - (Conf.gap_left + Conf.gap_right);
cc->flags |= CLIENT_DOMAXIMIZE;
}
@@ -342,15 +272,27 @@ void
client_vertmaximize(struct client_ctx *cc)
{
struct screen_ctx *sc = CCTOSC(cc);
int y_org = 0, ymax = sc->ymax;
if (cc->flags & CLIENT_VMAXIMIZED) {
cc->geom = cc->savegeom;
} else {
if (!(cc->flags & CLIENT_MAXIMIZED))
cc->savegeom = cc->geom;
cc->geom.y = cc->bwidth + Conf.gap_top;
cc->geom.height = (sc->ymax - cc->bwidth * 2) -
(Conf.gap_top + Conf.gap_bottom);
if (HasXinerama) {
XineramaScreenInfo *xine;
xine = screen_find_xinerama(CCTOSC(cc),
cc->geom.x + cc->geom.width / 2,
cc->geom.y + cc->geom.height / 2);
if (xine == NULL)
goto calc;
y_org = xine->y_org;
ymax = xine->height;
}
calc:
cc->geom.y = y_org + Conf.gap_top;
cc->geom.height = ymax - (cc->bwidth * 2) - (Conf.gap_top +
Conf.gap_bottom);
cc->flags |= CLIENT_DOVMAXIMIZE;
}
@@ -371,32 +313,28 @@ client_resize(struct client_ctx *cc)
cc->flags |= CLIENT_VMAXIMIZED;
}
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);
XMoveResizeWindow(X_Dpy, cc->win, cc->geom.x,
cc->geom.y, cc->geom.width, cc->geom.height);
xev_reconfig(cc);
}
void
client_move(struct client_ctx *cc)
{
XMoveWindow(X_Dpy, cc->pwin,
cc->geom.x - cc->bwidth, cc->geom.y - cc->bwidth);
XMoveWindow(X_Dpy, cc->win, cc->geom.x, cc->geom.y);
xev_reconfig(cc);
}
void
client_lower(struct client_ctx *cc)
{
XLowerWindow(X_Dpy, cc->pwin);
XLowerWindow(X_Dpy, cc->win);
}
void
client_raise(struct client_ctx *cc)
{
XRaiseWindow(X_Dpy, cc->pwin);
XRaiseWindow(X_Dpy, cc->win);
}
void
@@ -409,12 +347,8 @@ client_ptrwarp(struct client_ctx *cc)
y = cc->geom.height / 2;
}
if (cc->state == IconicState)
client_unhide(cc);
else
client_raise(cc);
xu_ptr_setpos(cc->pwin, x, y);
(cc->state == IconicState) ? client_unhide(cc) : client_raise(cc);
xu_ptr_setpos(cc->win, x, y);
}
void
@@ -422,8 +356,8 @@ client_ptrsave(struct client_ctx *cc)
{
int x, y;
xu_ptr_getpos(cc->pwin, &x, &y);
if (_inwindowbounds(cc, x, y)) {
xu_ptr_getpos(cc->win, &x, &y);
if (client_inbound(cc, x, y)) {
cc->ptr.x = x;
cc->ptr.y = y;
}
@@ -433,7 +367,7 @@ void
client_hide(struct client_ctx *cc)
{
/* XXX - add wm_state stuff */
XUnmapWindow(X_Dpy, cc->pwin);
XUnmapWindow(X_Dpy, cc->win);
cc->active = 0;
cc->flags |= CLIENT_HIDDEN;
@@ -446,97 +380,54 @@ client_hide(struct client_ctx *cc)
void
client_unhide(struct client_ctx *cc)
{
XMapRaised(X_Dpy, cc->pwin);
XMapRaised(X_Dpy, cc->win);
cc->highlight = 0;
cc->flags &= ~CLIENT_HIDDEN;
xu_setstate(cc, NormalState);
client_draw_border(cc);
}
void
client_draw_border(struct client_ctx *cc)
{
struct screen_ctx *sc = CCTOSC(cc);
unsigned long pixel;
if (cc->active) {
XSetWindowBackground(X_Dpy, cc->pwin, client_bg_pixel(cc));
XClearWindow(X_Dpy, cc->pwin);
if (cc->active)
switch (cc->highlight) {
case CLIENT_HIGHLIGHT_GROUP:
pixel = sc->color[CWM_COLOR_BORDER_GROUP].pixel;
break;
case CLIENT_HIGHLIGHT_UNGROUP:
pixel = sc->color[CWM_COLOR_BORDER_UNGROUP].pixel;
break;
default:
pixel = sc->color[CWM_COLOR_BORDOR_ACTIVE].pixel;
break;
}
else
pixel = sc->color[CWM_COLOR_BORDER_INACTIVE].pixel;
if (!cc->highlight && cc->bwidth > 1)
XDrawRectangle(X_Dpy, cc->pwin, sc->gc, 1, 1,
cc->geom.width + cc->bwidth,
cc->geom.height + cc->bwidth);
} else {
if (cc->bwidth > 1)
XSetWindowBackgroundPixmap(X_Dpy,
cc->pwin, client_bg_pixmap(cc));
XClearWindow(X_Dpy, cc->pwin);
}
XSetWindowBorderWidth(X_Dpy, cc->win, cc->bwidth);
XSetWindowBorder(X_Dpy, cc->win, pixel);
}
u_long
client_bg_pixel(struct client_ctx *cc)
{
struct screen_ctx *sc = CCTOSC(cc);
u_long pixl;
switch (cc->highlight) {
case CLIENT_HIGHLIGHT_BLUE:
pixl = sc->bluepixl;
break;
case CLIENT_HIGHLIGHT_RED:
pixl = sc->redpixl;
break;
default:
pixl = sc->blackpixl;
break;
}
return (pixl);
}
Pixmap
client_bg_pixmap(struct client_ctx *cc)
{
struct screen_ctx *sc = CCTOSC(cc);
Pixmap pix;
switch (cc->highlight) {
case CLIENT_HIGHLIGHT_BLUE:
pix = sc->blue;
break;
case CLIENT_HIGHLIGHT_RED:
pix = sc->red;
break;
default:
pix = sc->gray;
break;
}
return (pix);
}
void
static void
client_update(struct client_ctx *cc)
{
Atom *p, wm_delete, wm_protocols, wm_take_focus;
Atom *p;
int i;
long n;
/* XXX cache these. */
wm_delete = XInternAtom(X_Dpy, "WM_DELETE_WINDOW", False);
wm_protocols = XInternAtom(X_Dpy, "WM_PROTOCOLS", False);
wm_take_focus = XInternAtom(X_Dpy, "WM_TAKE_FOCUS", False);
if ((n = xu_getprop(cc, wm_protocols,
if ((n = xu_getprop(cc, WM_PROTOCOLS,
XA_ATOM, 20L, (u_char **)&p)) <= 0)
return;
for (i = 0; i < n; i++)
if (p[i] == wm_delete)
if (p[i] == WM_DELETE_WINDOW)
cc->xproto |= CLIENT_PROTO_DELETE;
else if (p[i] == wm_take_focus)
else if (p[i] == WM_TAKE_FOCUS)
cc->xproto |= CLIENT_PROTO_TAKEFOCUS;
XFree(p);
@@ -545,14 +436,8 @@ client_update(struct client_ctx *cc)
void
client_send_delete(struct client_ctx *cc)
{
Atom wm_delete, wm_protocols;
/* XXX - cache */
wm_delete = XInternAtom(X_Dpy, "WM_DELETE_WINDOW", False);
wm_protocols = XInternAtom(X_Dpy, "WM_PROTOCOLS", False);
if (cc->xproto & CLIENT_PROTO_DELETE)
xu_sendmsg(cc, wm_protocols, wm_delete);
xu_sendmsg(cc, WM_PROTOCOLS, WM_DELETE_WINDOW);
else
XKillClient(X_Dpy, cc->win);
}
@@ -575,7 +460,7 @@ client_setname(struct client_ctx *cc)
goto match;
}
XMALLOC(wn, struct winname);
wn = xmalloc(sizeof(*wn));
wn->name = newname;
TAILQ_INSERT_TAIL(&cc->nameq, wn, entry);
cc->nameqlen++;
@@ -643,7 +528,7 @@ client_cycle(int reverse)
return (newcc);
}
struct client_ctx *
static struct client_ctx *
client_mrunext(struct client_ctx *cc)
{
struct screen_ctx *sc = CCTOSC(cc);
@@ -653,7 +538,7 @@ client_mrunext(struct client_ctx *cc)
ccc : TAILQ_FIRST(&sc->mruq));
}
struct client_ctx *
static struct client_ctx *
client_mruprev(struct client_ctx *cc)
{
struct screen_ctx *sc = CCTOSC(cc);
@@ -663,50 +548,72 @@ client_mruprev(struct client_ctx *cc)
ccc : TAILQ_LAST(&sc->mruq, cycle_entry_q));
}
void
static void
client_placecalc(struct client_ctx *cc)
{
struct screen_ctx *sc = CCTOSC(cc);
int yslack, xslack, xmouse, ymouse;
yslack = sc->ymax - cc->geom.height - cc->bwidth;
xslack = sc->xmax - cc->geom.width - cc->bwidth;
xu_ptr_getpos(sc->rootwin, &xmouse, &ymouse);
xmouse = MAX(xmouse, cc->bwidth) - cc->geom.width / 2;
ymouse = MAX(ymouse, cc->bwidth) - cc->geom.height / 2;
xmouse = MAX(xmouse, (int)cc->bwidth);
ymouse = MAX(ymouse, (int)cc->bwidth);
int xslack, yslack;
if (cc->size->flags & USPosition) {
if (cc->size->x >= 0)
cc->geom.x = MAX(MIN(cc->size->x, xslack), cc->bwidth);
else
cc->geom.x = cc->bwidth;
if (cc->size->y >= 0)
cc->geom.y = MAX(MIN(cc->size->y, yslack), cc->bwidth);
else
cc->geom.y = cc->bwidth;
/*
* Ignore XINERAMA screens, just make sure it's somewhere
* in the virtual desktop. else it stops people putting xterms
* at startup in the screen the mouse doesn't start in *sigh*.
* XRandR bits mean that {x,y}max shouldn't be outside what's
* currently there.
*/
xslack = sc->xmax - cc->geom.width - cc->bwidth * 2;
yslack = sc->ymax - cc->geom.height - cc->bwidth * 2;
if (cc->size->x > 0)
cc->geom.x = MIN(cc->size->x, xslack);
if (cc->size->y > 0)
cc->geom.y = MIN(cc->size->y, yslack);
} else {
if (xslack >= 0) {
XineramaScreenInfo *info;
int xmouse, ymouse, xorig, yorig;
int xmax, ymax;
xu_ptr_getpos(sc->rootwin, &xmouse, &ymouse);
if (HasXinerama) {
info = screen_find_xinerama(sc, xmouse, ymouse);
if (info == NULL)
goto noxine;
xorig = info->x_org;
yorig = info->y_org;
xmax = xorig + info->width;
ymax = yorig + info->height;
} else {
noxine:
xorig = yorig = 0;
xmax = sc->xmax;
ymax = sc->ymax;
}
xmouse = MAX(xmouse, xorig) - cc->geom.width / 2;
ymouse = MAX(ymouse, yorig) - cc->geom.height / 2;
xmouse = MAX(xmouse, xorig);
ymouse = MAX(ymouse, yorig);
xslack = xmax - cc->geom.width - cc->bwidth * 2;
yslack = ymax - cc->geom.height - cc->bwidth * 2;
if (xslack >= xorig) {
cc->geom.x = MAX(MIN(xmouse, xslack),
Conf.gap_left + cc->bwidth);
xorig + Conf.gap_left);
if (cc->geom.x > (xslack - Conf.gap_right))
cc->geom.x -= Conf.gap_right;
} else {
cc->geom.x = cc->bwidth + Conf.gap_left;
cc->geom.width = sc->xmax - Conf.gap_left;
cc->geom.x = xorig + Conf.gap_left;
cc->geom.width = xmax - Conf.gap_left;
}
if (yslack >= 0) {
if (yslack >= yorig) {
cc->geom.y = MAX(MIN(ymouse, yslack),
Conf.gap_top + cc->bwidth);
yorig + Conf.gap_top);
if (cc->geom.y > (yslack - Conf.gap_bottom))
cc->geom.y -= Conf.gap_bottom;
} else {
cc->geom.y = cc->bwidth + Conf.gap_top;
cc->geom.height = sc->ymax - Conf.gap_top;
cc->geom.y = yorig + Conf.gap_top;
cc->geom.height = ymax - Conf.gap_top;
}
}
}
@@ -728,13 +635,12 @@ client_mtf(struct client_ctx *cc)
TAILQ_INSERT_HEAD(&sc->mruq, cc, mru_entry);
}
void
static void
client_gethints(struct client_ctx *cc)
{
XClassHint xch;
int argc;
char **argv;
Atom mha;
struct mwm_hints *mwmh;
if (XGetClassHint(X_Dpy, cc->win, &xch)) {
@@ -744,9 +650,8 @@ client_gethints(struct client_ctx *cc)
cc->app_class = xch.res_class;
}
mha = XInternAtom(X_Dpy, "_MOTIF_WM_HINTS", False);
if (xu_getprop(cc, mha, mha, PROP_MWM_HINTS_ELEMENTS,
(u_char **)&mwmh) == MWM_NUMHINTS)
if (xu_getprop(cc, _MOTIF_WM_HINTS, _MOTIF_WM_HINTS,
PROP_MWM_HINTS_ELEMENTS, (u_char **)&mwmh) == MWM_NUMHINTS)
if (mwmh->flags & MWM_HINTS_DECORATIONS &&
!(mwmh->decorations & MWM_DECOR_ALL) &&
!(mwmh->decorations & MWM_DECOR_BORDER))
@@ -776,19 +681,18 @@ client_gethints(struct client_ctx *cc)
}
}
void
static void
client_freehints(struct client_ctx *cc)
{
if (cc->app_name != NULL)
XFree(cc->app_name);
if (cc->app_class != NULL)
XFree(cc->app_class);
if (cc->app_cliarg != NULL)
xfree(cc->app_cliarg);
xfree(cc->app_cliarg);
}
int
_inwindowbounds(struct client_ctx *cc, int x, int y)
static int
client_inbound(struct client_ctx *cc, int x, int y)
{
return (x < cc->geom.width && x >= 0 &&
y < cc->geom.height && y >= 0);

269
conf.c
View File

@@ -28,6 +28,9 @@
((tsp)->tv_sec cmp (usp)->tv_sec))
#endif
static void conf_mouseunbind(struct conf *, struct mousebinding *);
static void conf_unbind(struct conf *, struct keybinding *);
extern struct screen_ctx *Curscreen;
/* Add an command menu entry to the end of the menu */
@@ -41,8 +44,7 @@ conf_cmd_add(struct conf *c, char *image, char *label, int flags)
else if (strcmp(label, "lock") == 0)
strlcpy(c->lockpath, image, sizeof(c->lockpath));
else {
struct cmd *cmd;
XMALLOC(cmd, struct cmd);
struct cmd *cmd = xmalloc(sizeof(*cmd));
cmd->flags = flags;
strlcpy(cmd->image, image, sizeof(cmd->image));
strlcpy(cmd->label, label, sizeof(cmd->label));
@@ -57,18 +59,37 @@ conf_font(struct conf *c)
sc = screen_current();
c->DefaultFont = font_make(sc, Conf.DefaultFontName);
c->DefaultFont = font_make(sc, c->DefaultFontName);
c->FontHeight = font_ascent() + font_descent() + 1;
}
void
conf_color(struct conf *c)
{
struct screen_ctx *sc;
int i;
sc = screen_current();
for (i = 0; i < CWM_COLOR_MAX; i++) {
xu_freecolor(sc, sc->color[i].pixel);
sc->color[i].pixel = xu_getcolor(sc, c->color[i].name);
}
}
void
conf_reload(struct conf *c)
{
struct client_ctx *cc;
if (parse_config(c->conf_path, c) == -1) {
warnx("config file %s has errors, not reloading", c->conf_path);
return;
}
conf_color(c);
TAILQ_FOREACH(cc, &Clientq, entry)
client_draw_border(cc);
conf_font(c);
}
@@ -76,6 +97,8 @@ void
conf_init(struct conf *c)
{
c->flags = 0;
c->bwidth = CONF_BWIDTH;
c->mamount = CONF_MAMOUNT;
TAILQ_INIT(&c->ignoreq);
TAILQ_INIT(&c->cmdq);
@@ -155,9 +178,67 @@ conf_init(struct conf *c)
strlcpy(c->termpath, "xterm", sizeof(c->termpath));
strlcpy(c->lockpath, "xlock", sizeof(c->lockpath));
c->color[CWM_COLOR_BORDOR_ACTIVE].name =
xstrdup(CONF_COLOR_ACTIVEBORDER);
c->color[CWM_COLOR_BORDER_INACTIVE].name =
xstrdup(CONF_COLOR_INACTIVEBORDER);
c->color[CWM_COLOR_BORDER_GROUP].name =
xstrdup(CONF_COLOR_GROUPBORDER);
c->color[CWM_COLOR_BORDER_UNGROUP].name =
xstrdup(CONF_COLOR_UNGROUPBORDER);
c->color[CWM_COLOR_FG_MENU].name =
xstrdup(CONF_COLOR_MENUFG);
c->color[CWM_COLOR_BG_MENU].name =
xstrdup(CONF_COLOR_MENUBG);
c->DefaultFontName = xstrdup(DEFAULTFONTNAME);
}
void
conf_clear(struct conf *c)
{
struct autogroupwin *ag;
struct keybinding *kb;
struct winmatch *wm;
struct cmd *cmd;
struct mousebinding *mb;
int i;
while ((cmd = TAILQ_FIRST(&c->cmdq)) != NULL) {
TAILQ_REMOVE(&c->cmdq, cmd, entry);
xfree(cmd);
}
while ((kb = TAILQ_FIRST(&c->keybindingq)) != NULL) {
TAILQ_REMOVE(&c->keybindingq, kb, entry);
xfree(kb);
}
while ((ag = TAILQ_FIRST(&c->autogroupq)) != NULL) {
TAILQ_REMOVE(&c->autogroupq, ag, entry);
xfree(ag->class);
if (ag->name)
xfree(ag->name);
xfree(ag->group);
xfree(ag);
}
while ((wm = TAILQ_FIRST(&c->ignoreq)) != NULL) {
TAILQ_REMOVE(&c->ignoreq, wm, entry);
xfree(wm);
}
while ((mb = TAILQ_FIRST(&c->mousebindingq)) != NULL) {
TAILQ_REMOVE(&c->mousebindingq, mb, entry);
xfree(mb);
}
for (i = 0; i < CWM_COLOR_MAX; i++)
xfree(c->color[i].name);
xfree(c->DefaultFontName);
}
void
conf_setup(struct conf *c, const char *conf_file)
{
@@ -189,105 +270,127 @@ conf_client(struct client_ctx *cc)
char *wname = cc->name;
int ignore = 0;
/* Can wname be NULL? */
if (wname != NULL) {
TAILQ_FOREACH(wm, &Conf.ignoreq, entry) {
if (strncasecmp(wm->title, wname, strlen(wm->title))
== 0) {
ignore = 1;
break;
}
TAILQ_FOREACH(wm, &Conf.ignoreq, entry) {
if (strncasecmp(wm->title, wname, strlen(wm->title)) == 0) {
ignore = 1;
break;
}
} else
ignore = 1;
}
cc->bwidth = ignore ? 0 : 3;
cc->bwidth = ignore ? 0 : Conf.bwidth;
cc->flags |= ignore ? CLIENT_IGNORE : 0;
}
struct {
char *tag;
void (*handler)(struct client_ctx *, void *);
int flags;
void *argument;
static struct {
char *tag;
void (*handler)(struct client_ctx *, union arg *);
int flags;
union arg argument;
} name_to_kbfunc[] = {
{ "lower", kbfunc_client_lower, KBFLAG_NEEDCLIENT, 0 },
{ "raise", kbfunc_client_raise, KBFLAG_NEEDCLIENT, 0 },
{ "search", kbfunc_client_search, 0, 0 },
{ "menusearch", kbfunc_menu_search, 0, 0 },
{ "hide", kbfunc_client_hide, KBFLAG_NEEDCLIENT, 0 },
{ "cycle", kbfunc_client_cycle, 0, (void *)CWM_CYCLE },
{ "rcycle", kbfunc_client_cycle, 0, (void *)CWM_RCYCLE },
{ "label", kbfunc_client_label, KBFLAG_NEEDCLIENT, 0 },
{ "delete", kbfunc_client_delete, KBFLAG_NEEDCLIENT, 0 },
{ "group1", kbfunc_client_group, 0, (void *)1 },
{ "group2", kbfunc_client_group, 0, (void *)2 },
{ "group3", kbfunc_client_group, 0, (void *)3 },
{ "group4", kbfunc_client_group, 0, (void *)4 },
{ "group5", kbfunc_client_group, 0, (void *)5 },
{ "group6", kbfunc_client_group, 0, (void *)6 },
{ "group7", kbfunc_client_group, 0, (void *)7 },
{ "group8", kbfunc_client_group, 0, (void *)8 },
{ "group9", kbfunc_client_group, 0, (void *)9 },
{ "nogroup", kbfunc_client_nogroup, 0, 0 },
{ "cyclegroup", kbfunc_client_cyclegroup, 0, (void *)CWM_CYCLEGROUP },
{ "rcyclegroup", kbfunc_client_cyclegroup, 0, (void *)CWM_RCYCLEGROUP },
{ "grouptoggle", kbfunc_client_grouptoggle, KBFLAG_NEEDCLIENT, 0},
{ "maximize", kbfunc_client_maximize, KBFLAG_NEEDCLIENT, 0 },
{ "vmaximize", kbfunc_client_vmaximize, KBFLAG_NEEDCLIENT, 0 },
{ "reload", kbfunc_reload, 0, 0 },
{ "quit", kbfunc_quit_wm, 0, 0 },
{ "exec", kbfunc_exec, 0, (void *)CWM_EXEC_PROGRAM },
{ "exec_wm", kbfunc_exec, 0, (void *)CWM_EXEC_WM },
{ "ssh", kbfunc_ssh, 0, 0 },
{ "terminal", kbfunc_term, 0, 0 },
{ "lock", kbfunc_lock, 0, 0 },
{ "lower", kbfunc_client_lower, KBFLAG_NEEDCLIENT, {0} },
{ "raise", kbfunc_client_raise, KBFLAG_NEEDCLIENT, {0} },
{ "search", kbfunc_client_search, 0, {0} },
{ "menusearch", kbfunc_menu_search, 0, {0} },
{ "hide", kbfunc_client_hide, KBFLAG_NEEDCLIENT, {0} },
{ "cycle", kbfunc_client_cycle, 0, {.i = CWM_CYCLE} },
{ "rcycle", kbfunc_client_cycle, 0, {.i = CWM_RCYCLE} },
{ "label", kbfunc_client_label, KBFLAG_NEEDCLIENT, {0} },
{ "delete", kbfunc_client_delete, KBFLAG_NEEDCLIENT, {0} },
{ "group1", kbfunc_client_group, 0, {.i = 1} },
{ "group2", kbfunc_client_group, 0, {.i = 2} },
{ "group3", kbfunc_client_group, 0, {.i = 3} },
{ "group4", kbfunc_client_group, 0, {.i = 4} },
{ "group5", kbfunc_client_group, 0, {.i = 5} },
{ "group6", kbfunc_client_group, 0, {.i = 6} },
{ "group7", kbfunc_client_group, 0, {.i = 7} },
{ "group8", kbfunc_client_group, 0, {.i = 8} },
{ "group9", kbfunc_client_group, 0, {.i = 9} },
{ "grouponly1", kbfunc_client_grouponly, 0, {.i = 1} },
{ "grouponly2", kbfunc_client_grouponly, 0, {.i = 2} },
{ "grouponly3", kbfunc_client_grouponly, 0, {.i = 3} },
{ "grouponly4", kbfunc_client_grouponly, 0, {.i = 4} },
{ "grouponly5", kbfunc_client_grouponly, 0, {.i = 5} },
{ "grouponly6", kbfunc_client_grouponly, 0, {.i = 6} },
{ "grouponly7", kbfunc_client_grouponly, 0, {.i = 7} },
{ "grouponly8", kbfunc_client_grouponly, 0, {.i = 8} },
{ "grouponly9", kbfunc_client_grouponly, 0, {.i = 9} },
{ "movetogroup1", kbfunc_client_movetogroup, KBFLAG_NEEDCLIENT,
{.i = 1} },
{ "movetogroup2", kbfunc_client_movetogroup, KBFLAG_NEEDCLIENT,
{.i = 2} },
{ "movetogroup3", kbfunc_client_movetogroup, KBFLAG_NEEDCLIENT,
{.i = 3} },
{ "movetogroup4", kbfunc_client_movetogroup, KBFLAG_NEEDCLIENT,
{.i = 4} },
{ "movetogroup5", kbfunc_client_movetogroup, KBFLAG_NEEDCLIENT,
{.i = 5} },
{ "movetogroup6", kbfunc_client_movetogroup, KBFLAG_NEEDCLIENT,
{.i = 6} },
{ "movetogroup7", kbfunc_client_movetogroup, KBFLAG_NEEDCLIENT,
{.i = 7} },
{ "movetogroup8", kbfunc_client_movetogroup, KBFLAG_NEEDCLIENT,
{.i = 8} },
{ "movetogroup9", kbfunc_client_movetogroup, KBFLAG_NEEDCLIENT,
{.i = 9} },
{ "nogroup", kbfunc_client_nogroup, 0, {0} },
{ "cyclegroup", kbfunc_client_cyclegroup, 0, {.i = CWM_CYCLEGROUP} },
{ "rcyclegroup", kbfunc_client_cyclegroup, 0, {.i = CWM_RCYCLEGROUP} },
{ "grouptoggle", kbfunc_client_grouptoggle, KBFLAG_NEEDCLIENT, {0}},
{ "maximize", kbfunc_client_maximize, KBFLAG_NEEDCLIENT, {0} },
{ "vmaximize", kbfunc_client_vmaximize, KBFLAG_NEEDCLIENT, {0} },
{ "reload", kbfunc_reload, 0, {0} },
{ "quit", kbfunc_quit_wm, 0, {0} },
{ "exec", kbfunc_exec, 0, {.i = CWM_EXEC_PROGRAM} },
{ "exec_wm", kbfunc_exec, 0, {.i = CWM_EXEC_WM} },
{ "ssh", kbfunc_ssh, 0, {0} },
{ "terminal", kbfunc_term, 0, {0} },
{ "lock", kbfunc_lock, 0, {0} },
{ "moveup", kbfunc_moveresize, KBFLAG_NEEDCLIENT,
(void *)(CWM_UP|CWM_MOVE) },
{.i = (CWM_UP|CWM_MOVE)} },
{ "movedown", kbfunc_moveresize, KBFLAG_NEEDCLIENT,
(void *)(CWM_DOWN|CWM_MOVE) },
{.i = (CWM_DOWN|CWM_MOVE)} },
{ "moveright", kbfunc_moveresize, KBFLAG_NEEDCLIENT,
(void *)(CWM_RIGHT|CWM_MOVE) },
{.i = (CWM_RIGHT|CWM_MOVE)} },
{ "moveleft", kbfunc_moveresize, KBFLAG_NEEDCLIENT,
(void *)(CWM_LEFT|CWM_MOVE) },
{.i = (CWM_LEFT|CWM_MOVE)} },
{ "bigmoveup", kbfunc_moveresize, KBFLAG_NEEDCLIENT,
(void *)(CWM_UP|CWM_MOVE|CWM_BIGMOVE) },
{.i = (CWM_UP|CWM_MOVE|CWM_BIGMOVE)} },
{ "bigmovedown", kbfunc_moveresize, KBFLAG_NEEDCLIENT,
(void *)(CWM_DOWN|CWM_MOVE|CWM_BIGMOVE) },
{.i = (CWM_DOWN|CWM_MOVE|CWM_BIGMOVE)} },
{ "bigmoveright", kbfunc_moveresize, KBFLAG_NEEDCLIENT,
(void *)(CWM_RIGHT|CWM_MOVE|CWM_BIGMOVE) },
{.i = (CWM_RIGHT|CWM_MOVE|CWM_BIGMOVE)} },
{ "bigmoveleft", kbfunc_moveresize, KBFLAG_NEEDCLIENT,
(void *)(CWM_LEFT|CWM_MOVE|CWM_BIGMOVE) },
{.i = (CWM_LEFT|CWM_MOVE|CWM_BIGMOVE)} },
{ "resizeup", kbfunc_moveresize, KBFLAG_NEEDCLIENT,
(void *)(CWM_UP|CWM_RESIZE) },
{.i = (CWM_UP|CWM_RESIZE)} },
{ "resizedown", kbfunc_moveresize, KBFLAG_NEEDCLIENT,
(void *)(CWM_DOWN|CWM_RESIZE) },
{.i = (CWM_DOWN|CWM_RESIZE)} },
{ "resizeright", kbfunc_moveresize, KBFLAG_NEEDCLIENT,
(void *)(CWM_RIGHT|CWM_RESIZE) },
{.i = (CWM_RIGHT|CWM_RESIZE)} },
{ "resizeleft", kbfunc_moveresize, KBFLAG_NEEDCLIENT,
(void *)(CWM_LEFT|CWM_RESIZE) },
{.i = (CWM_LEFT|CWM_RESIZE)} },
{ "bigresizeup", kbfunc_moveresize, KBFLAG_NEEDCLIENT,
(void *)(CWM_UP|CWM_RESIZE|CWM_BIGMOVE) },
{.i = (CWM_UP|CWM_RESIZE|CWM_BIGMOVE)} },
{ "bigresizedown", kbfunc_moveresize, KBFLAG_NEEDCLIENT,
(void *)(CWM_DOWN|CWM_RESIZE|CWM_BIGMOVE) },
{.i = (CWM_DOWN|CWM_RESIZE|CWM_BIGMOVE)} },
{ "bigresizeright", kbfunc_moveresize, KBFLAG_NEEDCLIENT,
(void *)(CWM_RIGHT|CWM_RESIZE|CWM_BIGMOVE) },
{.i = (CWM_RIGHT|CWM_RESIZE|CWM_BIGMOVE)} },
{ "bigresizeleft", kbfunc_moveresize, KBFLAG_NEEDCLIENT,
(void *)(CWM_LEFT|CWM_RESIZE|CWM_BIGMOVE) },
{ "ptrmoveup", kbfunc_moveresize, 0, (void *)(CWM_UP|CWM_PTRMOVE) },
{ "ptrmovedown", kbfunc_moveresize, 0, (void *)(CWM_DOWN|CWM_PTRMOVE) },
{ "ptrmoveleft", kbfunc_moveresize, 0, (void *)(CWM_LEFT|CWM_PTRMOVE) },
{.i = (CWM_LEFT|CWM_RESIZE|CWM_BIGMOVE)} },
{ "ptrmoveup", kbfunc_moveresize, 0, {.i = (CWM_UP|CWM_PTRMOVE)} },
{ "ptrmovedown", kbfunc_moveresize, 0, {.i = (CWM_DOWN|CWM_PTRMOVE)} },
{ "ptrmoveleft", kbfunc_moveresize, 0, {.i = (CWM_LEFT|CWM_PTRMOVE)} },
{ "ptrmoveright", kbfunc_moveresize, 0,
(void *)(CWM_RIGHT|CWM_PTRMOVE) },
{.i = (CWM_RIGHT|CWM_PTRMOVE)} },
{ "bigptrmoveup", kbfunc_moveresize, 0,
(void *)(CWM_UP|CWM_PTRMOVE|CWM_BIGMOVE) },
{.i = (CWM_UP|CWM_PTRMOVE|CWM_BIGMOVE)} },
{ "bigptrmovedown", kbfunc_moveresize, 0,
(void *)(CWM_DOWN|CWM_PTRMOVE|CWM_BIGMOVE) },
{.i = (CWM_DOWN|CWM_PTRMOVE|CWM_BIGMOVE)} },
{ "bigptrmoveleft", kbfunc_moveresize, 0,
(void *)(CWM_LEFT|CWM_PTRMOVE|CWM_BIGMOVE) },
{.i = (CWM_LEFT|CWM_PTRMOVE|CWM_BIGMOVE)} },
{ "bigptrmoveright", kbfunc_moveresize, 0,
(void *)(CWM_RIGHT|CWM_PTRMOVE|CWM_BIGMOVE) },
{ NULL, NULL, 0, 0},
{.i = (CWM_RIGHT|CWM_PTRMOVE|CWM_BIGMOVE)} },
{ NULL, NULL, 0, {0}},
};
/*
@@ -306,7 +409,6 @@ conf_grab(struct conf *c, struct keybinding *kb)
TAILQ_FOREACH(sc, &Screenq, entry)
xu_key_grab(sc->rootwin, kb->modmask, kb->keysym);
}
/*
@@ -329,7 +431,7 @@ conf_bindname(struct conf *c, char *name, char *binding)
char *substring;
int iter;
XCALLOC(current_binding, struct keybinding);
current_binding = xcalloc(1, sizeof(*current_binding));
if (strchr(name, 'C') != NULL &&
strchr(name, 'C') < strchr(name, '-'))
@@ -387,14 +489,14 @@ conf_bindname(struct conf *c, char *name, char *binding)
}
current_binding->callback = kbfunc_cmdexec;
current_binding->argument = xstrdup(binding);
current_binding->argument.c = xstrdup(binding);
current_binding->flags = 0;
conf_grab(c, current_binding);
TAILQ_INSERT_TAIL(&c->keybindingq, current_binding, entry);
return;
}
void
static void
conf_unbind(struct conf *c, struct keybinding *unbind)
{
struct keybinding *key = NULL, *keynxt;
@@ -416,7 +518,7 @@ conf_unbind(struct conf *c, struct keybinding *unbind)
}
}
struct {
static struct {
char *tag;
void (*handler)(struct client_ctx *, void *);
int context;
@@ -441,7 +543,7 @@ conf_mousebind(struct conf *c, char *name, char *binding)
const char *errstr;
int iter;
XCALLOC(current_binding, struct mousebinding);
current_binding = xcalloc(1, sizeof(*current_binding));
if (strchr(name, 'C') != NULL &&
strchr(name, 'C') < strchr(name, '-'))
@@ -484,7 +586,7 @@ conf_mousebind(struct conf *c, char *name, char *binding)
}
}
void
static void
conf_mouseunbind(struct conf *c, struct mousebinding *unbind)
{
struct mousebinding *mb = NULL, *mbnxt;
@@ -528,7 +630,8 @@ conf_grab_mouse(struct client_ctx *cc)
break;
default:
warnx("strange button in mousebinding\n");
continue;
}
xu_btn_grab(cc->pwin, mb->modmask, button);
xu_btn_grab(cc->win, mb->modmask, button);
}
}

106
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 $Mdocdate: July 11 2008 $
.Dd $Mdocdate: June 18 2009 $
.Dt CWM 1
.Os
.Sh NAME
@@ -37,29 +36,29 @@ The following notation is used throughout this page:
.Pp
.Bl -tag -width Ds -offset indent -compact
.It Ic C
Control
Control.
.It Ic M
Meta
Meta.
.It Ic S
Shift
Shift.
.It Ic M1
Left mouse button
Left mouse button.
.It Ic M2
Middle mouse button
Middle mouse button.
.It Ic M3
Right mouse button
Right mouse button.
.El
.Pp
.Nm
is very simple in its use.
Most of the actions are initiated via keybindings.
The current keybindings are described below;
Most of the actions are initiated via key bindings.
The current key bindings are described below;
their functionality is described in more detail later.
.Pp
.Bl -tag -width "C-M-EscapeXXX" -offset indent -compact
.It Ic C-M-Return
.Bl -tag -width "CM-EscapeXXXXX" -offset indent -compact
.It Ic CM-Return
Spawn a new terminal.
.It Ic C-M-Delete
.It Ic CM-Delete
Lock the screen.
.It Ic M-Return
Hide current window.
@@ -71,50 +70,50 @@ Raise current window.
Search for windows.
.It Ic C-/
Search for applications.
.It Ic C-M-n
.It Ic CM-n
Label current window.
.It Ic M-Tab
Cycle through currently visible windows.
.It Ic M-S-Tab
.It Ic MS-Tab
Reverse cycle through currently visible windows.
.It Ic C-M-x
.It Ic CM-x
Delete current window.
.It Ic C-M-[n]
.It Ic CM-[n]
Select group n, where n is 1-9.
.It Ic C-M-0
.It Ic CM-0
Select all groups.
.It Ic C-M-g
.It Ic CM-g
Toggle group membership of current window.
.It Ic M-Right
Cycle through active groups.
.It Ic M-Left
Reverse cycle through active groups.
.It Ic C-M-f
.It Ic CM-f
Toggle full-screen size of current window.
.It Ic C-M-=
.It Ic CM-=
Toggle vertical maximization of current window.
.It Ic M-?
Spawn
.Dq Exec program
.Dq exec program
dialog.
.It Ic M-.
Spawn
.Dq Ssh to
.Dq ssh to
dialog.
This parses
.Pa $HOME/.ssh/known_hosts
to provide host auto-completion.
.Xr ssh 1
will be executed via the configured terminal emulator.
.It Ic C-M-w
.It Ic CM-w
Spawn
.Dq Exec WindowManager
.Dq exec WindowManager
dialog; allows you to switch from
.Nm
to another window manager without restarting the X server.
.It Ic C-M-S-r
.It Ic CMS-r
Reload configuration.
.It Ic C-M-S-q
.It Ic CMS-q
Quit
.Nm .
.El
@@ -122,15 +121,15 @@ Quit
The mouse bindings are also important, they are:
.Pp
.Bl -tag -width Ds -offset indent -compact
.It M-M1
.It Ic M-M1
Move current window.
.It C-M-M1
.It Ic CM-M1
Toggle group membership of current window.
.It M-M2
.It Ic M-M2
Resize current window
.It M-M3
.It Ic M-M3
Lower current window.
.It CMS-M3
.It Ic CMS-M3
Hide current window.
.El
.Pp
@@ -146,22 +145,34 @@ Specify the display to use.
.El
.Sh POINTER MOVEMENT
The pointer can be moved with the use of the keyboard through bindings.
C-[UP|DOWN|LEFT|RIGHT] moves the pointer a small amount, while
C-shift-[UP|DOWN|LEFT|RIGHT] moves the pointer a larger amount.
.Ic C-[Up|Down|Left|Right]
moves the pointer a small amount, while
.Ic CS-[Up|Down|Left|Right]
moves the pointer a larger amount.
For example, to move the pointer to the left by a small amount,
press C-LEFT.
To move the pointer down by a larger amount, press C-shift-DOWN.
press
.Ic C-Left .
To move the pointer down by a larger amount, press
.Ic CS-Down .
.Sh WINDOW MOVEMENT AND RESIZING
.Nm
windows can be moved with the use of the keyboard through Vi-like bindings.
M-[hjkl] moves the current window a small amount, while M-shift-[hjkl] moves
the current window a larger amount.
For example, to move the current window to the left a small amount, press M-h.
To move the current window down by a larger amount, press M-shift-j.
windows can be moved with the use of the keyboard through
.Cm vi Ns -like
bindings.
.Ic M-[hjkl]
moves the current window a small amount, while
.Ic MS-[hjkl]
moves the current window a larger amount.
For example, to move the current window to the left a small amount, press
.Ic M-h .
To move the current window down by a larger amount, press
.Ic MS-j .
.Pp
Similarly, windows may be resized with the same keybindings with the addition
Similarly, windows may be resized with the same key bindings with the addition
of the Control key.
C-M-[hjkl] resizes the window a small amount and C-M-shift-[hjkl]
.Ic CM-[hjkl]
resizes the window a small amount and
.Ic CMS-[hjkl]
resizes by a larger increment.
.Sh SEARCH
.Nm
@@ -182,7 +193,7 @@ The window is the currently focused window.
The window is hidden.
.El
.Pp
The following keybindings may be used to navigate the result list:
The following key bindings may be used to navigate the result list:
.Pp
.Bl -tag -width "[Down] or C-s or M-j" -offset indent -compact
.It Ic [Down], C-s No or Ic M-j
@@ -218,13 +229,13 @@ and a red border will be shown on those just removed.
Menus are recalled by clicking the mouse on the root window:
.Pp
.Bl -tag -width 10n -offset -indent -compact
.It M1
.It Ic M1
Show list of currently hidden windows.
Clicking on an item will unhide that window.
.It M2
.It Ic M2
Show list of currently defined groups.
Clicking on an item will hide/unhide that group.
.It M3
.It Ic M3
Show list of applications as defined in
.Pa ~/.cwmrc .
Clicking on an item will spawn that application.
@@ -240,6 +251,7 @@ option is given.
.Sh FILES
.Bl -tag -width Ds
.It Pa ~/.cwmrc
.El
.Sh SEE ALSO
.Xr cwmrc 5
.Sh AUTHORS

147
cwmrc.5
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 $Mdocdate: July 11 2008 $
.Dd $Mdocdate: May 17 2009 $
.Dt CWMRC 5
.Os
.Sh NAME
@@ -35,7 +34,7 @@ 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
allow for
.Dq sticky
windows in sticky group mode.
.Pp
@@ -81,6 +80,22 @@ 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 Ar path
Every
.Ar name
@@ -123,8 +138,9 @@ can be used for applications such as
where the user may wish to remain visible.
.Pp
.It Ic ignore Ar windowname
Ignore drawing borders around a window with the name
.Ar windowname .
Ignore windows with the name
.Ar windowname
when drawing borders and cycling through windows.
.Pp
.It Ic mousebind Ar buttons Ar command
Cause the creation of a mouse binding, or replacement of a default
@@ -135,7 +151,7 @@ The modifier keys come first, followed by a
The following modifiers are recognised:
.Pp
.Bl -tag -width Ds -offset indent -compact
.It C
.It C
The Control key.
.It M
The Meta key.
@@ -154,9 +170,9 @@ should be followed by number:
.It 1
Left mouse button.
.It 2
Right mouse button.
.It 3
Middle mouse button.
.It 3
Right mouse button.
.El
.Pp
The
@@ -165,6 +181,11 @@ 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.
@@ -199,6 +220,12 @@ ignore xclock
bind CM-r label
bind CS-Return "xterm -e top"
bind 4-o unmap
bind M-1 grouponly1
bind M-2 grouponly2
bind M-3 grouponly3
bind MS-1 movetogroup1
bind MS-2 movetogroup2
bind MS-3 movetogroup3
# Mousebindings
mousebind M-2 window_lower
@@ -233,10 +260,16 @@ Launch
menu.
.It group[n]
Select group n, where n is 1-9.
.It grouponly[n]
Like
.Ar group[n]
but also hides the other groups.
.It nogroup
Select all groups.
.It grouptoggle
Toggle group membership of current window.
.It movetogroup[n]
Hide current window from display and move to group n, where n is 1-9.
.It cyclegroup
Forward cycle through groups.
.It rcyclegroup
@@ -260,53 +293,101 @@ Maximize current window full-screen.
.It vmaximize
Maximize current window vertically.
.It moveup
Move window 1 pixel up.
Move window
.Ar moveamount
pixels up.
.It movedown
Move window 1 pixel down.
Move window
.Ar moveamount
pixels down.
.It moveright
Move window 1 pixel right.
Move window
.Ar moveamount
pixels right.
.It moveleft
Move window 1 pixel left.
Move window
.Ar moveamount
pixels left.
.It bigmoveup
Move window 10 pixels up.
Move window 10 times
.Ar moveamount
pixels up.
.It bigmovedown
Move window 10 pixels down.
Move window 10 times
.Ar moveamount
pixels down.
.It bigmoveright
Move window 10 pixels right.
Move window 10 times
.Ar moveamount
pixels right.
.It bigmoveleft
Move window 10 pixels left.
Move window 10 times
.Ar moveamount
pixels left.
.It resizeup
Resize window 1 pixel up.
Resize window
.Ar moveamount
pixels up.
.It resizedown
Resize window 1 pixel down.
Resize window
.Ar moveamount
pixels down.
.It resizeright
Resize window 1 pixel right.
Resize window
.Ar moveamount
pixels right.
.It resizeleft
Resize window 1 pixel left.
Resize window
.Ar moveamount
pixels left.
.It bigresizeup
Resize window 10 pixels up.
Resize window 10 times
.Ar moveamount
pixels up.
.It bigresizedown
Resize window 10 pixels down.
Resize window 10 times
.Ar moveamount
pixels down.
.It bigresizeright
Resize window 10 pixels right.
Resize window 10 times
.Ar moveamount
pixels right.
.It bigresizeleft
Resize window 10 pixels left.
Resize window 10 times
.Ar moveamount
pixels left.
.It ptrmoveup
Move pointer 1 pixel up.
Move pointer
.Ar moveamount
pixels up.
.It ptrmovedown
Move pointer 1 pixel down.
Move pointer
.Ar moveamount
pixels down.
.It ptrmoveright
Move pointer 1 pixel right.
Move pointer
.Ar moveamount
pixels right.
.It ptrmoveleft
Move pointer 1 pixel left.
Move pointer
.Ar moveamount
pixels left.
.It bigptrmoveup
Move pointer 10 pixels up.
Move pointer 10 times
.Ar moveamount
pixels up.
.It bigptrmovedown
Move pointer 10 pixels down.
Move pointer 10 times
.Ar moveamount
pixels down.
.It bigptrmoveright
Move pointer 10 pixels right.
Move pointer 10 times
.Ar moveamount
pixels right.
.It bigptrmoveleft
Move pointer 10 pixels left.
Move pointer 10 times
.Ar moveamount
pixels left.
.El
.Sh MOUSEBIND COMMAND LIST
.Bl -tag -width 18n -compact
@@ -323,7 +404,7 @@ Toggle group membership of current window.
.It menu_group
Launch group list.
.It menu_unhide
Launch group list.
Launch hidden window list.
.It menu_cmd
Launch command list.
.El

16
font.c
View File

@@ -22,22 +22,14 @@
void
font_init(struct screen_ctx *sc)
{
XColor xcolor, tmp;
sc->xftdraw = XftDrawCreate(X_Dpy, sc->rootwin,
DefaultVisual(X_Dpy, sc->which), DefaultColormap(X_Dpy, sc->which));
if (sc->xftdraw == NULL)
errx(1, "XftDrawCreate");
if (!XAllocNamedColor(X_Dpy, DefaultColormap(X_Dpy, sc->which),
"black", &xcolor, &tmp))
errx(1, "XAllocNamedColor");
sc->xftcolor.color.red = xcolor.red;
sc->xftcolor.color.green = xcolor.green;
sc->xftcolor.color.blue = xcolor.blue;
sc->xftcolor.color.alpha = 0x00ff00;
sc->xftcolor.pixel = xcolor.pixel;
if (!XftColorAllocName(X_Dpy, DefaultVisual(X_Dpy, sc->which),
DefaultColormap(X_Dpy, sc->which), "black", &sc->xftcolor))
errx(1, "XftColorAllocName");
}
int
@@ -68,7 +60,7 @@ font_make(struct screen_ctx *sc, const char *name)
FcPattern *pat, *patx;
XftResult res;
if ((pat = FcNameParse(name)) == NULL)
if ((pat = FcNameParse((const FcChar8*)name)) == NULL)
return (NULL);
if ((patx = XftFontMatch(X_Dpy, sc->which, pat, &res)) != NULL)

184
grab.c
View File

@@ -1,184 +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);
#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);
char asize[10]; /* fits "nnnnxnnnn\0" */
int wide, height, wide_size, wide_name;
int x = cc->geom.x, y = cc->geom.y;
snprintf(asize, sizeof(asize), "%dx%d",
ADJUST_WIDTH(cc, dx), ADJUST_HEIGHT(cc, dy));
wide_size = font_width(asize, strlen(asize)) + 4;
wide_name = font_width(cc->name, strlen(cc->name)) + 4;
wide = MAX(wide_size, wide_name);
height = font_ascent() + font_descent() + 1;
XMoveResizeWindow(X_Dpy, sc->menuwin, x, y, wide, 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() + 1);
font_draw(sc, asize, strlen(asize), sc->menuwin,
wide / 2 - wide_size / 2, height + font_ascent() + 1);
}
void
grab_sweep(struct client_ctx *cc)
{
XEvent ev;
struct screen_ctx *sc = CCTOSC(cc);
int x = cc->geom.x, y = cc->geom.y, 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, x, y, 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);
client_do_shape(cc);
break;
case ButtonRelease:
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
grab_drag(struct client_ctx *cc)
{
XEvent ev;
struct screen_ctx *sc = CCTOSC(cc);
int x = cc->geom.x, y = cc->geom.y, xm, ym;
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 = x + (ev.xmotion.x - xm);
cc->geom.y = y + (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 */
}
static int
_sweepcalc(struct client_ctx *cc, int x, int y, int motionx, int motiony)
{
int width, height;
width = cc->geom.width;
height = cc->geom.height;
cc->geom.width = abs(x - motionx);
cc->geom.height = abs(y - 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 = x <= motionx ? x : x - cc->geom.width;
cc->geom.y = y <= motiony ? y : y - cc->geom.height;
return (width != cc->geom.width || height != cc->geom.height);
}

128
group.c
View File

@@ -24,16 +24,27 @@
#define CALMWM_NGROUPS 9
static void group_add(struct group_ctx *, struct client_ctx *);
static void group_remove(struct client_ctx *);
static void group_hide(struct group_ctx *);
static void group_show(struct group_ctx *);
static void group_fix_hidden_state(struct group_ctx *);
struct group_ctx *Group_active = NULL;
struct group_ctx Groups[CALMWM_NGROUPS];
int Grouphideall = 0;
struct group_ctx_q Groupq;
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)
{
if (cc == NULL || gc == NULL)
errx(1, "_group_add: a ctx is NULL");
errx(1, "group_add: a ctx is NULL");
if (cc->group == gc)
return;
@@ -41,22 +52,29 @@ _group_add(struct group_ctx *gc, struct client_ctx *cc)
if (cc->group != NULL)
TAILQ_REMOVE(&cc->group->clients, cc, group_entry);
XChangeProperty(X_Dpy, cc->win, _CWM_GRP, XA_STRING,
8, PropModeReplace, gc->name, strlen(gc->name));
TAILQ_INSERT_TAIL(&gc->clients, cc, group_entry);
cc->group = gc;
}
static void
_group_remove(struct client_ctx *cc)
group_remove(struct client_ctx *cc)
{
if (cc == NULL || cc->group == NULL)
errx(1, "_group_remove: a ctx is NULL");
errx(1, "group_remove: a ctx is NULL");
XChangeProperty(X_Dpy, cc->win, _CWM_GRP, XA_STRING, 8,
PropModeReplace, shortcut_to_name[0],
strlen(shortcut_to_name[0]));
TAILQ_REMOVE(&cc->group->clients, cc, group_entry);
cc->group = NULL;
}
static void
_group_hide(struct group_ctx *gc)
group_hide(struct group_ctx *gc)
{
struct client_ctx *cc;
@@ -74,7 +92,7 @@ _group_hide(struct group_ctx *gc)
}
static void
_group_show(struct group_ctx *gc)
group_show(struct group_ctx *gc)
{
struct client_ctx *cc;
Window *winlist;
@@ -88,7 +106,7 @@ _group_show(struct group_ctx *gc)
* 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);
}
@@ -121,12 +139,24 @@ group_init(void)
TAILQ_INIT(&Groups[i].clients);
Groups[i].hidden = 0;
Groups[i].shortcut = i + 1;
Groups[i].name = shortcut_to_name[Groups[i].shortcut];
TAILQ_INSERT_TAIL(&Groupq, &Groups[i], entry);
}
Group_active = &Groups[0];
}
void
group_movetogroup(struct client_ctx *cc, int idx)
{
if (idx < 0 || idx >= CALMWM_NGROUPS)
err(1, "group_movetogroup: index out of range (%d)", idx);
if(Group_active != &Groups[idx])
client_hide(cc);
group_add(&Groups[idx], cc);
}
/*
* Colouring for groups upon add/remove.
*/
@@ -138,11 +168,11 @@ group_sticky_toggle_enter(struct client_ctx *cc)
gc = 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);
@@ -156,13 +186,10 @@ group_sticky_toggle_exit(struct client_ctx *cc)
}
/*
* selection list display
* if group_hidetoggle would produce no effect, toggle the group's hidden state
*/
/* if group_hidetoggle would produce no effect, toggle the group's hidden state
*/
void
_group_fix_hidden_state(struct group_ctx *gc)
static void
group_fix_hidden_state(struct group_ctx *gc)
{
struct client_ctx *cc;
int same = 0;
@@ -186,17 +213,33 @@ group_hidetoggle(int idx)
gc = &Groups[idx];
_group_fix_hidden_state(gc);
group_fix_hidden_state(gc);
if (gc->hidden)
_group_show(gc);
group_show(gc);
else {
_group_hide(gc);
group_hide(gc);
if (TAILQ_EMPTY(&gc->clients))
Group_active = gc;
}
}
void
group_only(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(&Groups[i]);
else
group_hide(&Groups[i]);
}
}
/*
* Cycle through active groups. If none exist, then just stay put.
*/
@@ -220,16 +263,16 @@ group_cycle(int reverse)
if (!TAILQ_EMPTY(&gc->clients) && showgroup == NULL)
showgroup = gc;
else if (!gc->hidden)
_group_hide(gc);
group_hide(gc);
}
if (showgroup == NULL)
return;
_group_hide(Group_active);
group_hide(Group_active);
if (showgroup->hidden)
_group_show(showgroup);
group_show(showgroup);
else
Group_active = showgroup;
}
@@ -261,7 +304,7 @@ group_menu(XButtonEvent *e)
if (TAILQ_EMPTY(&gc->clients))
continue;
XCALLOC(mi, struct menu);
mi = xcalloc(1, sizeof(*mi));
if (gc->hidden)
snprintf(mi->text, sizeof(mi->text), "%d: [%s]",
gc->shortcut, shortcut_to_name[gc->shortcut]);
@@ -282,10 +325,7 @@ group_menu(XButtonEvent *e)
gc = (struct group_ctx *)mi->ctx;
if (gc->hidden)
_group_show(gc);
else
_group_hide(gc);
(gc->hidden) ? group_show(gc) : group_hide(gc);
cleanup:
while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
@@ -301,15 +341,12 @@ group_alltoggle(void)
for (i = 0; i < CALMWM_NGROUPS; i++) {
if (Grouphideall)
_group_show(&Groups[i]);
group_show(&Groups[i]);
else
_group_hide(&Groups[i]);
group_hide(&Groups[i]);
}
if (Grouphideall)
Grouphideall = 0;
else
Grouphideall = 1;
Grouphideall = (Grouphideall) ? 0 : 1;
}
void
@@ -317,16 +354,23 @@ group_autogroup(struct client_ctx *cc)
{
struct autogroupwin *aw;
struct group_ctx *gc;
unsigned char *grpstr = NULL;
char group[CALMWM_MAXNAMELEN];
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, _CWM_GRP, XA_STRING,
(CALMWM_MAXNAMELEN - 1)/sizeof(long), &grpstr) > 0) {
strlcpy(group, grpstr, sizeof(group));
XFree(grpstr);
} else {
TAILQ_FOREACH(aw, &Conf.autogroupq, entry) {
if (strcmp(aw->class, cc->app_class) == 0 &&
(aw->name == NULL ||
strcmp(aw->name, cc->app_name) == 0)) {
strlcpy(group, aw->group, sizeof(group));
break;
}
}
}
@@ -335,12 +379,12 @@ group_autogroup(struct client_ctx *cc)
TAILQ_FOREACH(gc, &Groupq, entry) {
if (strcmp(shortcut_to_name[gc->shortcut], group) == 0) {
_group_add(gc, cc);
group_add(gc, cc);
return;
}
}
if (Conf.flags & CONF_STICKY_GROUPS)
_group_add(Group_active, cc);
group_add(Group_active, cc);
}

View File

@@ -21,35 +21,33 @@
#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/queue.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <dirent.h>
#include <getopt.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <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/Xatom.h>
#include <X11/Xft/Xft.h>
#include <err.h>
#include <X11/Xlib.h>
#include <X11/Xos.h>
#include <X11/Xproto.h>
#include <X11/Xutil.h>
#include <X11/cursorfont.h>
#include <X11/extensions/Xinerama.h>
#include <X11/extensions/Xrandr.h>
#include <X11/keysym.h>
#endif /* _CALMWM_HEADERS_H_ */

View File

@@ -29,10 +29,7 @@ input_keycodetrans(KeyCode kc, u_int state, enum ctltype *ctl, char *chr)
*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) {

102
kbfunc.c
View File

@@ -25,18 +25,17 @@
#define KNOWN_HOSTS ".ssh/known_hosts"
#define HASH_MARKER "|1|"
#define MOVE_AMOUNT 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);
}
@@ -44,7 +43,7 @@ kbfunc_client_raise(struct client_ctx *cc, void *arg)
#define typemask (CWM_MOVE | CWM_RESIZE | CWM_PTRMOVE)
#define movemask (CWM_UP | CWM_DOWN | CWM_LEFT | CWM_RIGHT)
void
kbfunc_moveresize(struct client_ctx *cc, void *arg)
kbfunc_moveresize(struct client_ctx *cc, union arg *arg)
{
struct screen_ctx *sc;
int x, y, flags, amt;
@@ -53,8 +52,8 @@ kbfunc_moveresize(struct client_ctx *cc, void *arg)
sc = screen_current();
mx = my = 0;
flags = (int)arg;
amt = MOVE_AMOUNT;
flags = arg->i;
amt = Conf.mamount;
if (flags & CWM_BIGMOVE) {
flags -= CWM_BIGMOVE;
@@ -80,17 +79,17 @@ kbfunc_moveresize(struct client_ctx *cc, void *arg)
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)
cc->geom.y = cc->sc->ymax;
if (cc->geom.y > cc->sc->ymax - 1)
cc->geom.y = cc->sc->ymax - 1;
cc->geom.x += mx;
if (cc->geom.x + cc->geom.width < 0)
cc->geom.x = -cc->geom.width;
if (cc->geom.x > cc->sc->xmax)
cc->geom.x = cc->sc->xmax;
if (cc->geom.x > cc->sc->xmax - 1)
cc->geom.x = cc->sc->xmax - 1;
client_move(cc);
xu_ptr_getpos(cc->pwin, &x, &y);
xu_ptr_getpos(cc->win, &x, &y);
cc->ptr.y = y + my;
cc->ptr.x = x + mx;
client_ptrwarp(cc);
@@ -103,7 +102,7 @@ kbfunc_moveresize(struct client_ctx *cc, void *arg)
client_resize(cc);
/* Make sure the pointer stays within the window. */
xu_ptr_getpos(cc->pwin, &cc->ptr.x, &cc->ptr.y);
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)
@@ -112,8 +111,8 @@ kbfunc_moveresize(struct client_ctx *cc, void *arg)
break;
case CWM_PTRMOVE:
if (cc) {
xu_ptr_getpos(cc->pwin, &x, &y);
xu_ptr_setpos(cc->pwin, x + mx, y + my);
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);
@@ -125,7 +124,7 @@ kbfunc_moveresize(struct client_ctx *cc, void *arg)
}
void
kbfunc_client_search(struct client_ctx *scratch, void *arg)
kbfunc_client_search(struct client_ctx *scratch, union arg *arg)
{
struct client_ctx *cc, *old_cc;
struct menu *mi;
@@ -136,7 +135,7 @@ kbfunc_client_search(struct client_ctx *scratch, void *arg)
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);
@@ -160,7 +159,7 @@ 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 *scratch, union arg *arg)
{
struct cmd *cmd;
struct menu *mi;
@@ -169,7 +168,7 @@ kbfunc_menu_search(struct client_ctx *scratch, void *arg)
TAILQ_INIT(&menuq);
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);
@@ -186,7 +185,7 @@ 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 *scratch, union arg *arg)
{
struct screen_ctx *sc;
@@ -196,35 +195,35 @@ kbfunc_client_cycle(struct client_ctx *scratch, void *arg)
XGrabKeyboard(X_Dpy, sc->rootwin, True,
GrabModeAsync, GrabModeAsync, CurrentTime);
client_cycle((int)arg);
client_cycle(arg->i);
}
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)
{
u_spawn(Conf.termpath);
}
void
kbfunc_lock(struct client_ctx *cc, void *arg)
kbfunc_lock(struct client_ctx *cc, union arg *arg)
{
u_spawn(Conf.lockpath);
}
void
kbfunc_exec(struct client_ctx *scratch, void *arg)
kbfunc_exec(struct client_ctx *scratch, union arg *arg)
{
#define NPATHS 256
char **ap, *paths[NPATHS], *path, *pathcpy, *label;
@@ -238,7 +237,7 @@ kbfunc_exec(struct client_ctx *scratch, void *arg)
struct menu_q menuq;
struct stat sb;
int cmd = (int)arg;
int cmd = arg->i;
switch (cmd) {
case CWM_EXEC_PROGRAM:
label = "exec";
@@ -305,7 +304,7 @@ kbfunc_exec(struct client_ctx *scratch, void *arg)
continue;
executable:
/* the thing in tpath, we may execute */
XCALLOC(mi, struct menu);
mi = xcalloc(1, sizeof(*mi));
strlcpy(mi->text, dp->d_name, sizeof(mi->text));
TAILQ_INSERT_TAIL(&menuq, mi, entry);
}
@@ -338,7 +337,7 @@ kbfunc_exec(struct client_ctx *scratch, void *arg)
}
void
kbfunc_ssh(struct client_ctx *scratch, void *arg)
kbfunc_ssh(struct client_ctx *scratch, union arg *arg)
{
struct menu *mi;
struct menu_q menuq;
@@ -381,7 +380,7 @@ 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);
}
@@ -405,7 +404,7 @@ 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)
{
struct menu *mi;
struct menu_q menuq;
@@ -413,10 +412,7 @@ kbfunc_client_label(struct client_ctx *cc, void *arg)
TAILQ_INIT(&menuq);
if (cc->label != NULL)
current = cc->label;
else
current = NULL;
current = cc->label;
if ((mi = menu_filter(&menuq, "label", current, 1,
search_match_text, NULL)) != NULL) {
@@ -428,59 +424,71 @@ kbfunc_client_label(struct client_ctx *cc, void *arg)
}
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_group(struct client_ctx *cc, void *arg)
kbfunc_client_group(struct client_ctx *cc, union arg *arg)
{
group_hidetoggle(KBTOGROUP((int)arg));
group_hidetoggle(KBTOGROUP(arg->i));
}
void
kbfunc_client_cyclegroup(struct client_ctx *cc, void *arg)
kbfunc_client_grouponly(struct client_ctx *cc, union arg *arg)
{
group_cycle((int)arg);
group_only(KBTOGROUP(arg->i));
}
void
kbfunc_client_nogroup(struct client_ctx *cc, void *arg)
kbfunc_client_cyclegroup(struct client_ctx *cc, union arg *arg)
{
group_cycle(arg->i);
}
void
kbfunc_client_nogroup(struct client_ctx *cc, union arg *arg)
{
group_alltoggle();
}
void
kbfunc_client_grouptoggle(struct client_ctx *cc, void *arg)
kbfunc_client_grouptoggle(struct client_ctx *cc, union arg *arg)
{
/* XXX for stupid X apps like xpdf and gvim */
XGrabKeyboard(X_Dpy, cc->pwin, True,
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_quit_wm(struct client_ctx *cc, void *arg)
kbfunc_quit_wm(struct client_ctx *cc, union arg *arg)
{
_xev_quit = 1;
}
void
kbfunc_reload(struct client_ctx *cc, void *arg)
kbfunc_reload(struct client_ctx *cc, union arg *arg)
{
conf_reload(&Conf);
}

40
menu.c
View File

@@ -18,11 +18,6 @@
#include "headers.h"
#include "calmwm.h"
#define KeyMask (KeyPressMask|ExposureMask)
#define MenuMask (ButtonMask|ButtonMotionMask|ExposureMask| \
PointerMotionMask)
#define MenuGrabMask (ButtonMask|ButtonMotionMask|StructureNotifyMask|\
PointerMotionMask)
#define PROMPT_SCHAR '<27>'
#define PROMPT_ECHAR '<27>'
@@ -48,7 +43,7 @@ static struct menu *menu_handle_key(XEvent *, struct menu_ctx *,
struct menu_q *, struct menu_q *);
static void menu_handle_move(XEvent *, struct menu_ctx *,
struct screen_ctx *);
struct menu *menu_handle_release(XEvent *, struct menu_ctx *,
static struct menu *menu_handle_release(XEvent *, struct menu_ctx *,
struct screen_ctx *, struct menu_q *);
static void menu_draw(struct screen_ctx *, struct menu_ctx *,
struct menu_q *, struct menu_q *);
@@ -58,8 +53,19 @@ static int menu_calc_entry(struct screen_ctx *, struct menu_ctx *,
void
menu_init(struct screen_ctx *sc)
{
sc->menuwin = XCreateSimpleWindow(X_Dpy, sc->rootwin, 0, 0,
1, 1, 1, sc->blackpixl, sc->whitepixl);
XGCValues gv;
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 *
@@ -73,7 +79,7 @@ menu_filter(struct menu_q *menuq, char *prompt, char *initial, int dummy,
struct menu *mi = NULL;
XEvent e;
Window focuswin;
int Mask, focusrevert;
int evmask, focusrevert;
sc = screen_current();
@@ -84,11 +90,11 @@ menu_filter(struct menu_q *menuq, char *prompt, char *initial, int dummy,
xu_ptr_getpos(sc->rootwin, &mc.x, &mc.y);
if (prompt == NULL) {
Mask = MenuMask;
evmask = MenuMask;
mc.promptstr[0] = '\0';
mc.list = 1;
} else {
Mask = MenuMask | KeyMask; /* only accept keys if prompt */
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,
@@ -108,7 +114,7 @@ menu_filter(struct menu_q *menuq, char *prompt, char *initial, int dummy,
XMoveResizeWindow(X_Dpy, sc->menuwin, mc.x, mc.y, mc.width,
font_height());
XSelectInput(X_Dpy, sc->menuwin, Mask);
XSelectInput(X_Dpy, sc->menuwin, evmask);
XMapRaised(X_Dpy, sc->menuwin);
if (xu_ptr_grab(sc->menuwin, MenuGrabMask, Cursor_question) < 0) {
@@ -126,7 +132,7 @@ menu_filter(struct menu_q *menuq, char *prompt, char *initial, int dummy,
for (;;) {
mc.changed = 0;
XWindowEvent(X_Dpy, sc->menuwin, Mask, &e);
XWindowEvent(X_Dpy, sc->menuwin, evmask, &e);
switch (e.type) {
default:
@@ -150,7 +156,7 @@ menu_filter(struct menu_q *menuq, char *prompt, char *initial, int dummy,
}
}
out:
if ((dummy == 0 && mi->dummy) || (mi->text[0] == '\0')) { /* no match */
if (dummy == 0 && mi->dummy) { /* no match */
xfree (mi);
mi = NULL;
xu_ptr_ungrab();
@@ -343,7 +349,7 @@ menu_draw(struct screen_ctx *sc, struct menu_ctx *mc, struct menu_q *menuq,
0, 0, mc->width, font_height());
}
void
static void
menu_handle_move(XEvent *e, struct menu_ctx *mc, struct screen_ctx *sc)
{
mc->prev = mc->entry;
@@ -360,7 +366,7 @@ menu_handle_move(XEvent *e, struct menu_ctx *mc, struct screen_ctx *sc)
xu_ptr_regrab(MenuGrabMask, Cursor_default);
}
struct menu *
static struct menu *
menu_handle_release(XEvent *e, struct menu_ctx *mc, struct screen_ctx *sc,
struct menu_q *resultq)
{
@@ -377,7 +383,7 @@ menu_handle_release(XEvent *e, struct menu_ctx *mc, struct screen_ctx *sc,
if (entry == i++)
break;
if (mi == NULL) {
XMALLOC(mi, struct menu);
mi = xmalloc(sizeof(*mi));
mi->text[0] = '\0';
mi->dummy = 1;
}

View File

@@ -1,6 +1,7 @@
/*
* 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
@@ -21,18 +22,170 @@
#include "headers.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;
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 = 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 = CCTOSC(cc);
char asize[10]; /* fits "nnnnxnnnn\0" */
int width, height, width_size, width_name;
snprintf(asize, sizeof(asize), "%dx%d",
(cc->geom.width - cc->geom.min_dx) / cc->size->width_inc,
(cc->geom.height - cc->geom.min_dy) / cc->size->height_inc);
width_size = font_width(asize, strlen(asize)) + 4;
width_name = font_width(cc->name, strlen(cc->name)) + 4;
width = MAX(width_size, width_name);
height = font_ascent() + font_descent() + 1;
XMoveResizeWindow(X_Dpy, sc->menuwin, cc->geom.x, cc->geom.y,
width, height * 2);
XMapWindow(X_Dpy, sc->menuwin);
XReparentWindow(X_Dpy, sc->menuwin, cc->win, 0, 0);
XClearWindow(X_Dpy, sc->menuwin);
font_draw(sc, cc->name, strlen(cc->name), sc->menuwin,
2, font_ascent() + 1);
font_draw(sc, asize, strlen(asize), sc->menuwin,
width / 2 - width_size / 2, height + font_ascent() + 1);
}
void
mousefunc_window_resize(struct client_ctx *cc, void *arg)
{
grab_sweep(cc);
client_resize(cc);
XEvent ev;
Time time = 0;
struct screen_ctx *sc = CCTOSC(cc);
int x = cc->geom.x, y = cc->geom.y;
cc->size->width_inc = MAX(1, cc->size->width_inc);
cc->size->height_inc = MAX(1, cc->size->height_inc);
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)
{
grab_drag(cc);
client_move(cc);
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
@@ -73,15 +226,11 @@ mousefunc_menu_unhide(struct client_ctx *cc, void *arg)
TAILQ_INIT(&menuq);
TAILQ_FOREACH(cc, &Clientq, entry)
if (cc->flags & CLIENT_HIDDEN) {
if (cc->label != NULL)
wname = cc->label;
else
wname = cc->name;
wname = (cc->label) ? cc->label : cc->name;
if (wname == NULL)
continue;
XCALLOC(mi, struct menu);
mi = xcalloc(1, sizeof(*mi));
strlcpy(mi->text, wname, sizeof(mi->text));
mi->ctx = cc;
TAILQ_INSERT_TAIL(&menuq, mi, entry);
@@ -115,7 +264,7 @@ mousefunc_menu_cmd(struct client_ctx *cc, void *arg)
TAILQ_INIT(&menuq);
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);

108
parse.y
View File

@@ -54,8 +54,6 @@ int findeol(void);
static struct conf *conf;
extern char *shortcut_to_name[];
typedef struct {
union {
int64_t number;
@@ -68,7 +66,10 @@ typedef struct {
%token FONTNAME STICKY GAP MOUSEBIND
%token AUTOGROUP BIND COMMAND IGNORE
%token YES NO
%token YES NO BORDERWIDTH MOVEAMOUNT
%token COLOR
%token ACTIVEBORDER INACTIVEBORDER
%token GROUPBORDER UNGROUPBORDER
%token ERROR
%token <v.string> STRING
%token <v.number> NUMBER
@@ -79,6 +80,7 @@ typedef struct {
grammar : /* empty */
| grammar '\n'
| grammar main '\n'
| grammar color '\n'
| grammar error '\n' { file->errors++; }
;
@@ -109,6 +111,12 @@ main : FONTNAME STRING {
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);
@@ -124,7 +132,7 @@ main : FONTNAME STRING {
YYERROR;
}
XCALLOC(aw, struct autogroupwin);
aw = xcalloc(1, sizeof(*aw));
if ((p = strchr($3, ',')) == NULL) {
aw->name = NULL;
@@ -143,7 +151,7 @@ main : FONTNAME STRING {
| IGNORE STRING {
struct winmatch *wm;
XCALLOC(wm, struct winmatch);
wm = xcalloc(1, sizeof(*wm));
strlcpy(wm->title, $2, sizeof(wm->title));
TAILQ_INSERT_TAIL(&conf->ignoreq, wm, entry);
@@ -166,6 +174,27 @@ main : FONTNAME STRING {
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 {
@@ -198,15 +227,22 @@ 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;
@@ -462,56 +498,12 @@ popfile(void)
return (EOF);
}
void
conf_clear(struct conf *c)
{
struct autogroupwin *ag;
struct keybinding *kb;
struct winmatch *wm;
struct cmd *cmd;
struct mousebinding *mb;
while (cmd = TAILQ_FIRST(&c->cmdq)) {
TAILQ_REMOVE(&c->cmdq, cmd, entry);
free(cmd);
}
while (kb = TAILQ_FIRST(&c->keybindingq)) {
TAILQ_REMOVE(&c->keybindingq, kb, entry);
free(kb);
}
while (ag = TAILQ_FIRST(&c->autogroupq)) {
TAILQ_REMOVE(&c->autogroupq, ag, entry);
free(ag->class);
if (ag->name)
free(ag->name);
free(ag->group);
free(ag);
}
while (wm = TAILQ_FIRST(&c->ignoreq)) {
TAILQ_REMOVE(&c->ignoreq, wm, entry);
free(wm);
}
while (mb = TAILQ_FIRST(&c->mousebindingq)) {
TAILQ_REMOVE(&c->mousebindingq, mb, entry);
free(mb);
}
if (c->DefaultFontName != NULL &&
c->DefaultFontName != DEFAULTFONTNAME)
free(c->DefaultFontName);
}
int
parse_config(const char *filename, struct conf *xconf)
{
int errors = 0;
XCALLOC(conf, struct conf);
conf = xcalloc(1, sizeof(*conf));
if ((file = pushfile(filename)) == NULL) {
free(conf);
@@ -536,32 +528,35 @@ parse_config(const char *filename, struct conf *xconf)
struct winmatch *wm;
struct cmd *cmd;
struct mousebinding *mb;
int i;
conf_clear(xconf);
xconf->flags = conf->flags;
xconf->bwidth = conf->bwidth;
xconf->mamount = conf->mamount;
while (cmd = TAILQ_FIRST(&conf->cmdq)) {
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)) {
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)) {
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)) {
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)) {
while ((mb = TAILQ_FIRST(&conf->mousebindingq)) != NULL) {
TAILQ_REMOVE(&conf->mousebindingq, mb, entry);
TAILQ_INSERT_TAIL(&xconf->mousebindingq, mb, entry);
}
@@ -571,6 +566,9 @@ parse_config(const char *filename, struct conf *xconf)
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;
bcopy(&(conf->gap_top), &(xconf->gap_top), sizeof(int) * 4);

View File

@@ -21,9 +21,14 @@
#include "headers.h"
#include "calmwm.h"
extern struct screen_ctx_q Screenq;
extern struct screen_ctx *Curscreen;
void
screen_init(void)
{
TAILQ_INIT(&Screenq);
}
struct screen_ctx *
screen_fromroot(Window rootwin)
{
@@ -67,3 +72,46 @@ screen_updatestackingorder(void)
XFree(wins);
}
void
screen_init_xinerama(struct screen_ctx *sc)
{
XineramaScreenInfo *info;
int no;
if (HasXinerama == 0 || XineramaIsActive(X_Dpy) == 0) {
HasXinerama = 0;
sc->xinerama_no = 0;
}
info = XineramaQueryScreens(X_Dpy, &no);
if (info == NULL) {
/*is xinerama is actually off, instead of a malloc failure? */
if (sc->xinerama == NULL)
HasXinerama = 0;
return;
}
if (sc->xinerama != NULL)
XFree(sc->xinerama);
sc->xinerama = info;
sc->xinerama_no = no;
}
/*
* 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);
}

View File

@@ -17,12 +17,11 @@
* $Id$
*/
#include <fnmatch.h>
#include "headers.h"
#include "calmwm.h"
#define SearchMask (KeyPressMask|ExposureMask)
static int _strsubmatch(char *, char *, int);
static int strsubmatch(char *, char *, int);
/*
* Match: label, title, class.
@@ -54,7 +53,7 @@ search_match_client(struct menu_q *menuq, struct menu_q *resultq, char *search)
struct client_ctx *cc = mi->ctx;
/* First, try to match on labels. */
if (cc->label != NULL && _strsubmatch(search, cc->label, 0)) {
if (cc->label != NULL && strsubmatch(search, cc->label, 0)) {
cc->matchname = cc->label;
tier = 0;
}
@@ -62,7 +61,7 @@ search_match_client(struct menu_q *menuq, struct menu_q *resultq, char *search)
/* Then, on window names. */
if (tier < 0) {
TAILQ_FOREACH_REVERSE(wn, &cc->nameq, winname_q, entry)
if (_strsubmatch(search, wn->name, 0)) {
if (strsubmatch(search, wn->name, 0)) {
cc->matchname = wn->name;
tier = 2;
break;
@@ -74,7 +73,7 @@ search_match_client(struct menu_q *menuq, struct menu_q *resultq, char *search)
* name.
*/
if (tier < 0 && _strsubmatch(search, cc->app_class, 0)) {
if (tier < 0 && strsubmatch(search, cc->app_class, 0)) {
cc->matchname = cc->app_class;
tier = 3;
}
@@ -132,7 +131,7 @@ 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);
@@ -168,24 +167,35 @@ search_match_text(struct menu_q *menuq, struct menu_q *resultq, char *search)
TAILQ_INIT(resultq);
TAILQ_FOREACH(mi, menuq, entry)
if (_strsubmatch(search, mi->text, 0))
if (strsubmatch(search, mi->text, 0))
TAILQ_INSERT_TAIL(resultq, mi, resultentry);
}
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;

398
xevents.c
View File

@@ -27,22 +27,46 @@
#include "headers.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;
XWindowAttributes xattr;
struct client_ctx *cc = NULL, *old_cc;
struct screen_ctx *sc;
#ifdef notyet
int state;
#endif
XWindowAttributes xattr;
if ((old_cc = client_current()) != NULL)
client_ptrsave(old_cc);
@@ -50,46 +74,50 @@ xev_handle_maprequest(struct xevent *xev, XEvent *ee)
if ((cc = client_find(e->window)) == NULL) {
XGetWindowAttributes(X_Dpy, e->window, &xattr);
cc = client_new(e->window, screen_fromroot(xattr.root), 1);
sc = CCTOSC(cc);
} else
cc->beepbeep = 1;
#ifdef notyet /* XXX - possibly, we shouldn't map if
* the window is withdrawn. */
if (xu_getstate(cc, &state) == 0 && state == WithdrawnState)
warnx("WITHDRAWNSTATE for %s", cc->name);
#endif
}
client_ptrwarp(cc);
xev_register(xev);
}
void
xev_handle_unmapnotify(struct xevent *xev, XEvent *ee)
static void
xev_handle_unmapnotify(XEvent *ee)
{
XUnmapEvent *e = &ee->xunmap;
XEvent ev;
struct client_ctx *cc;
if ((cc = client_find(e->window)) != NULL)
client_delete(cc, e->send_event, 0);
xev_register(xev);
/* XXX, we need a recursive locking wrapper around grab server */
XGrabServer(X_Dpy);
if ((cc = client_find(e->window)) != NULL) {
/*
* 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);
}
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;
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;
@@ -99,7 +127,6 @@ xev_handle_configurerequest(struct xevent *xev, XEvent *ee)
if ((cc = client_find(e->window)) != NULL) {
sc = CCTOSC(cc);
client_gravitate(cc, 0);
if (e->value_mask & CWWidth)
cc->geom.width = e->width;
if (e->value_mask & CWHeight)
@@ -108,44 +135,39 @@ 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))
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 ? cc->bwidth : e->x;
wc.y = cc != NULL ? cc->bwidth : 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;
@@ -164,8 +186,6 @@ xev_handle_propertynotify(struct xevent *xev, XEvent *ee)
break;
}
}
xev_register(xev);
}
void
@@ -180,52 +200,37 @@ 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;
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;
struct screen_ctx *sc;
struct mousebinding *mb;
char *wname;
sc = screen_fromroot(e->root);
cc = client_find(e->window);
@@ -239,35 +244,31 @@ xev_handle_buttonpress(struct xevent *xev, XEvent *ee)
}
if (mb == NULL)
goto out;
return;
if (mb->context == MOUSEBIND_CTX_ROOT) {
if (e->window != sc->rootwin)
goto out;
return;
} else if (mb->context == MOUSEBIND_CTX_WIN) {
cc = client_find(e->window);
if (cc == NULL)
goto out;
return;
}
(*mb->callback)(cc, e);
out:
xev_register(xev);
}
void
xev_handle_buttonrelease(struct xevent *xev, XEvent *ee)
static void
xev_handle_buttonrelease(XEvent *ee)
{
struct client_ctx *cc;
if ((cc = client_current()) != NULL)
group_sticky_toggle_exit(cc);
xev_register(xev);
}
void
xev_handle_keypress(struct xevent *xev, XEvent *ee)
static void
xev_handle_keypress(XEvent *ee)
{
XKeyEvent *e = &ee->xkey;
struct client_ctx *cc = NULL;
@@ -297,25 +298,22 @@ xev_handle_keypress(struct xevent *xev, XEvent *ee)
}
if (kb == NULL)
goto out;
return;
if ((kb->flags & (KBFLAG_NEEDCLIENT)) &&
(cc = client_find(e->window)) == NULL &&
(cc = client_current()) == NULL)
if (kb->flags & KBFLAG_NEEDCLIENT)
goto out;
return;
(*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;
@@ -327,7 +325,7 @@ xev_handle_keyrelease(struct xevent *xev, XEvent *ee)
keysym = XKeycodeToKeysym(X_Dpy, e->keycode, 0);
if (keysym != XK_Alt_L && keysym != XK_Alt_R)
goto out;
return;
sc->altpersist = 0;
@@ -341,13 +339,10 @@ xev_handle_keyrelease(struct xevent *xev, XEvent *ee)
group_sticky_toggle_exit(cc);
XUngrabKeyboard(X_Dpy, CurrentTime);
}
out:
xev_register(xev);
}
void
xev_handle_clientmessage(struct xevent *xev, XEvent *ee)
static void
xev_handle_clientmessage(XEvent *ee)
{
XClientMessageEvent *e = &ee->xclient;
Atom xa_wm_change_state;
@@ -356,31 +351,37 @@ xev_handle_clientmessage(struct xevent *xev, XEvent *ee)
xa_wm_change_state = XInternAtom(X_Dpy, "WM_CHANGE_STATE", False);
if ((cc = client_find(e->window)) == NULL)
goto out;
return;
if (e->message_type == xa_wm_change_state && e->format == 32 &&
e->data.l[0] == IconicState)
client_hide(cc);
out:
xev_register(xev);
}
void
xev_handle_shape(struct xevent *xev, XEvent *ee)
static void
xev_handle_randr(XEvent *ee)
{
XShapeEvent *sev = (XShapeEvent *) ee;
struct client_ctx *cc;
XRRScreenChangeNotifyEvent *rev = (XRRScreenChangeNotifyEvent *)ee;
struct screen_ctx *sc;
int i;
if ((cc = client_find(sev->window)) != NULL)
client_do_shape(cc);
i = XRRRootToScreen(X_Dpy, rev->root);
TAILQ_FOREACH(sc, &Screenq, entry) {
if (sc->which == (u_int)i) {
XRRUpdateConfiguration(ee);
sc->xmax = rev->width;
sc->ymax = rev->height;
screen_init_xinerama(sc);
}
}
}
/*
* Called when the keymap has changed.
* Ungrab all keys, reload keymap and then regrab
*/
void
xev_handle_mapping(struct xevent *xev, XEvent *ee)
static void
xev_handle_mappingnotify(XEvent *ee)
{
XMappingEvent *e = &ee->xmapping;
struct keybinding *kb;
@@ -392,162 +393,31 @@ xev_handle_mapping(struct xevent *xev, XEvent *ee)
TAILQ_FOREACH(kb, &Conf.keybindingq, entry)
conf_grab(&Conf, kb);
xev_register(xev);
}
/*
* X Event handling
*/
static struct xevent_q _xevq, _xevq_putaway;
static short _xev_q_lock = 0;
volatile sig_atomic_t _xev_quit = 0;
void
xev_init(void)
{
TAILQ_INIT(&_xevq);
TAILQ_INIT(&_xevq_putaway);
}
struct xevent *
xev_new(Window *win, Window *root,
int type, void (*cb)(struct xevent *, XEvent *), void *arg)
{
struct xevent *xev;
XMALLOC(xev, struct xevent);
xev->xev_win = win;
xev->xev_root = root;
xev->xev_type = type;
xev->xev_cb = cb;
xev->xev_arg = arg;
return (xev);
}
void
xev_register(struct xevent *xev)
{
struct xevent_q *xq;
xq = _xev_q_lock ? &_xevq_putaway : &_xevq;
TAILQ_INSERT_TAIL(xq, xev, entry);
}
void
_xev_reincorporate(void)
{
struct xevent *xev;
while ((xev = TAILQ_FIRST(&_xevq_putaway)) != NULL) {
TAILQ_REMOVE(&_xevq_putaway, xev, entry);
TAILQ_INSERT_TAIL(&_xevq, xev, entry);
}
}
void
xev_handle_expose(struct xevent *xev, XEvent *ee)
static void
xev_handle_expose(XEvent *ee)
{
XExposeEvent *e = &ee->xexpose;
struct client_ctx *cc;
if ((cc = client_find(e->window)) != NULL && e->count == 0) {
if ((cc = client_find(e->window)) != NULL && e->count == 0)
client_draw_border(cc);
client_do_shape(cc);
}
xev_register(xev);
}
#define ASSIGN(xtype) do { \
root = e. xtype .root; \
win = e. xtype .window; \
} while (0)
#define ASSIGN1(xtype) do { \
win = e. xtype .window; \
} while (0)
volatile sig_atomic_t _xev_quit = 0;
void
xev_loop(void)
{
Window win, root;
XEvent e;
struct xevent *xev = NULL, *nextxev;
int type;
while (_xev_quit == 0) {
#ifdef DIAGNOSTIC
if (TAILQ_EMPTY(&_xevq))
errx(1, "X event queue empty");
#endif
XNextEvent(X_Dpy, &e);
type = e.type;
win = root = 0;
switch (type) {
case MapRequest:
ASSIGN1(xmaprequest);
break;
case UnmapNotify:
ASSIGN1(xunmap);
break;
case ConfigureRequest:
ASSIGN1(xconfigurerequest);
break;
case PropertyNotify:
ASSIGN1(xproperty);
break;
case EnterNotify:
case LeaveNotify:
ASSIGN(xcrossing);
break;
case ButtonPress:
ASSIGN(xbutton);
break;
case ButtonRelease:
ASSIGN(xbutton);
break;
case KeyPress:
case KeyRelease:
ASSIGN(xkey);
break;
case DestroyNotify:
ASSIGN1(xdestroywindow);
break;
case ClientMessage:
ASSIGN1(xclient);
break;
default:
if (e.type == Shape_ev)
xev_handle_shape(xev, &e);
break;
}
/*
* Now, search for matches, and call each of them.
*/
_xev_q_lock = 1;
for (xev = TAILQ_FIRST(&_xevq); xev != NULL; xev = nextxev) {
nextxev = TAILQ_NEXT(xev, entry);
if ((type != xev->xev_type && xev->xev_type != 0) ||
(xev->xev_win != NULL && win != *xev->xev_win) ||
(xev->xev_root != NULL && root != *xev->xev_root))
continue;
TAILQ_REMOVE(&_xevq, xev, entry);
(*xev->xev_cb)(xev, &e);
}
_xev_q_lock = 0;
_xev_reincorporate();
if (e.type - Randr_ev == RRScreenChangeNotify)
xev_handle_randr(&e);
else if (e.type < LASTEvent && xev_handlers[e.type] != NULL)
(*xev_handlers[e.type])(&e);
}
}
#undef ASSIGN
#undef ASSIGN1

53
xutil.c
View File

@@ -21,7 +21,7 @@
#include "headers.h"
#include "calmwm.h"
unsigned int ign_mods[] = { 0, LockMask, Mod2Mask, Mod2Mask | LockMask };
static unsigned int ign_mods[] = { 0, LockMask, Mod2Mask, Mod2Mask | LockMask };
int
xu_ptr_grab(Window win, int mask, Cursor curs)
@@ -145,12 +145,9 @@ xu_getprop(struct client_ctx *cc, Atom atm, Atom type, long len, u_char **p)
int
xu_getstate(struct client_ctx *cc, int *state)
{
Atom wm_state;
long *p = NULL;
wm_state = XInternAtom(X_Dpy, "WM_STATE", False);
if (xu_getprop(cc, wm_state, wm_state, 2L, (u_char **)&p) <= 0)
if (xu_getprop(cc, WM_STATE, WM_STATE, 2L, (u_char **)&p) <= 0)
return (-1);
*state = (int)*p;
@@ -162,16 +159,48 @@ xu_getstate(struct client_ctx *cc, int *state)
void
xu_setstate(struct client_ctx *cc, int state)
{
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",
"_CWM_GRP",
};
void
xu_getatoms(void)
{
XInternAtoms(X_Dpy, atoms, CWM_NO_ATOMS, False, cwm_atoms);
}
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);
}