42 Commits

Author SHA1 Message Date
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
19 changed files with 792 additions and 807 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.

View File

@@ -31,19 +31,13 @@ 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 dpy_init(const char *);
@@ -69,10 +63,6 @@ main(int argc, char **argv)
argc -= optind;
argv += optind;
/* Ignore a few signals. */
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
err(1, "signal");
if (signal(SIGCHLD, _sigchld_cb) == SIG_ERR)
err(1, "signal");
@@ -83,10 +73,12 @@ main(int argc, char **argv)
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,
@@ -119,7 +111,7 @@ dpy_init(const char *dpyname)
XSetErrorHandler(x_errorhandler);
Doshape = XShapeQueryExtension(X_Dpy, &Shape_ev, &i);
HasRandr = XRRQueryExtension(X_Dpy, &Randr_ev, &i);
TAILQ_INIT(&Screenq);
}
@@ -131,9 +123,8 @@ x_setup(void)
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++) {
XCALLOC(sc, struct screen_ctx);
x_setupscreen(sc, i);
TAILQ_INSERT_TAIL(&Screenq, sc, entry);
}
@@ -145,7 +136,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);
@@ -161,11 +151,11 @@ x_setupscreen(struct screen_ctx *sc, u_int which)
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);
@@ -181,7 +171,7 @@ x_setupscreen(struct screen_ctx *sc, u_int which)
XAllocNamedColor(X_Dpy, DefaultColormap(X_Dpy, which),
"red", &sc->redcolor, &tmp);
XAllocNamedColor(X_Dpy, DefaultColormap(X_Dpy, which),
"#00ccc8", &sc->cyancolor, &tmp);
"#666666", &sc->graycolor, &tmp);
XAllocNamedColor(X_Dpy, DefaultColormap(X_Dpy, which),
"white", &sc->whitecolor, &tmp);
XAllocNamedColor(X_Dpy, DefaultColormap(X_Dpy, which),
@@ -191,19 +181,7 @@ x_setupscreen(struct screen_ctx *sc, u_int 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));
sc->graypixl = sc->graycolor.pixel;
gv.foreground = sc->blackpixl^sc->whitepixl;
gv.background = sc->whitepixl;
@@ -229,11 +207,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,37 +221,23 @@ 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
x_errorhandler(Display *dpy, XErrorEvent *e)
{

122
calmwm.h
View File

@@ -45,14 +45,11 @@ struct screen_ctx {
Window rootwin;
Window menuwin;
Colormap colormap;
XColor bgcolor, fgcolor, fccolor, redcolor, cyancolor,
XColor bgcolor, fgcolor, fccolor, redcolor, graycolor,
whitecolor, blackcolor;
char *display;
unsigned long blackpixl, whitepixl, redpixl, bluepixl, cyanpixl;
unsigned long blackpixl, whitepixl, redpixl, bluepixl, graypixl;
GC gc;
Pixmap gray, blue, red;
int altpersist;
int xmax;
@@ -62,6 +59,9 @@ struct screen_ctx {
XftDraw *xftdraw;
XftColor xftcolor;
int xinerama_no;
XineramaScreenInfo *xinerama;
};
TAILQ_HEAD(screen_ctx_q, screen_ctx);
@@ -81,7 +81,6 @@ TAILQ_HEAD(screen_ctx_q, screen_ctx);
#define CLIENT_HIGHLIGHT_BLUE 1
#define CLIENT_HIGHLIGHT_RED 2
struct winname {
TAILQ_ENTRY(winname) entry;
char *name;
@@ -101,8 +100,6 @@ struct client_ctx {
Colormap cmap;
Window pwin;
u_int bwidth;
struct {
int x, y, width, height;
@@ -113,8 +110,6 @@ struct client_ctx {
int x,y;
} ptr;
int beepbeep;
int xproto;
int flags;
@@ -139,15 +134,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;
@@ -213,14 +205,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 +254,10 @@ struct conf {
#define CONF_STICKY_GROUPS 0x0001
int flags;
#define CONF_BWIDTH 1
int bwidth;
#define CONF_MAMOUNT 1
int mamount;
char termpath[MAXPATHLEN];
char lockpath[MAXPATHLEN];
@@ -310,16 +311,14 @@ int input_keycodetrans(KeyCode, u_int, enum ctltype *,
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);
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,7 +328,6 @@ 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 *);
@@ -339,8 +337,6 @@ 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);
@@ -348,7 +344,6 @@ 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 *),
@@ -368,7 +363,7 @@ 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_randr(struct xevent *, XEvent *);
void xev_handle_mapping(struct xevent *, XEvent *);
#define XEV_QUICK(a, b, c, d, e) do { \
@@ -384,6 +379,7 @@ struct xevent *xev_new(Window *, Window *, int,
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);
@@ -403,9 +399,6 @@ int xu_getstate(struct client_ctx *, int *);
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);
@@ -417,6 +410,8 @@ char *xstrdup(const char *);
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 *);
@@ -429,30 +424,40 @@ void conf_mouseunbind(struct conf *, struct mousebinding *);
void conf_grab_mouse(struct client_ctx *);
void conf_reload(struct conf *);
void conf_font(struct conf *);
void conf_init(struct conf *);
void conf_clear(struct conf *);
void conf_cmd_add(struct conf *, char *, char *, int);
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_cyclegroup(struct client_ctx *,
union arg *);
void kbfunc_client_nogroup(struct client_ctx *,
union arg *);
void kbfunc_client_grouptoggle(struct client_ctx *,
union arg *);
void kbfunc_client_maximize(struct client_ctx *,
union arg *);
void kbfunc_client_vmaximize(struct client_ctx *,
union arg *);
void kbfunc_reload(struct client_ctx *, union arg *);
void kbfunc_quit_wm(struct client_ctx *, union arg *);
void kbfunc_moveresize(struct client_ctx *, union arg *);
void kbfunc_menu_search(struct client_ctx *, union arg *);
void kbfunc_exec(struct client_ctx *, union arg *);
void kbfunc_ssh(struct client_ctx *, union arg *);
void kbfunc_term(struct client_ctx *, union arg *);
void kbfunc_lock(struct client_ctx *, union arg *);
void mousefunc_window_resize(struct client_ctx *, void *);
void mousefunc_window_move(struct client_ctx *, void *);
@@ -507,11 +512,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_ */

353
client.c
View File

@@ -21,10 +21,9 @@
#include "headers.h"
#include "calmwm.h"
int _inwindowbounds(struct client_ctx *, int, int);
static int _client_inbound(struct client_ctx *, int, int);
static char emptystring[] = "";
struct client_ctx *_curcc = NULL;
void
@@ -39,7 +38,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,11 +48,10 @@ 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);
@@ -66,6 +64,7 @@ client_new(Window win, struct screen_ctx *sc, int mapped)
cc->sc = sc;
cc->win = win;
cc->size = XAllocSizeHints();
XGetWMNormalHints(X_Dpy, cc->win, cc->size, &tmp);
if (cc->size->width_inc == 0)
cc->size->width_inc = 1;
if (cc->size->height_inc == 0)
@@ -79,7 +78,6 @@ client_new(Window win, struct screen_ctx *sc, int mapped)
*/
conf_client(cc);
XGetWMNormalHints(X_Dpy, cc->win, cc->size, &tmp);
XGetWindowAttributes(X_Dpy, cc->win, &wattr);
if (cc->size->flags & PBaseSize) {
@@ -94,8 +92,6 @@ client_new(Window win, struct screen_ctx *sc, int mapped)
cc->ptr.x = -1;
cc->ptr.y = -1;
client_gravitate(cc, 1);
cc->geom.x = wattr.x;
cc->geom.y = wattr.y;
cc->geom.width = wattr.width;
@@ -110,7 +106,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,41 +116,15 @@ 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);
}
else
client_unhide(cc);
xu_setstate(cc, cc->state);
@@ -171,51 +143,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);
@@ -296,42 +235,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 +279,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 +320,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
@@ -414,7 +359,7 @@ client_ptrwarp(struct client_ctx *cc)
else
client_raise(cc);
xu_ptr_setpos(cc->pwin, x, y);
xu_ptr_setpos(cc->win, x, y);
}
void
@@ -422,8 +367,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 +378,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,7 +391,7 @@ 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;
@@ -455,88 +400,44 @@ client_unhide(struct client_ctx *cc)
void
client_draw_border(struct client_ctx *cc)
{
struct screen_ctx *sc = CCTOSC(cc);
if (cc->active) {
XSetWindowBackground(X_Dpy, cc->pwin, client_bg_pixel(cc));
XClearWindow(X_Dpy, cc->pwin);
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);
}
}
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;
}
if (cc->active)
switch (cc->highlight) {
case CLIENT_HIGHLIGHT_BLUE:
pixl = sc->bluepixl;
break;
case CLIENT_HIGHLIGHT_RED:
pixl = sc->redpixl;
break;
default:
pixl = sc->whitepixl;
break;
}
else
pixl = sc->graypixl;
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);
XSetWindowBorderWidth(X_Dpy, cc->win, cc->bwidth);
XSetWindowBorder(X_Dpy, cc->win, pixl);
}
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 +446,9 @@ 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);
}
@@ -667,46 +563,68 @@ 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;
}
}
}
@@ -734,7 +652,6 @@ 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 +661,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))
@@ -783,12 +699,11 @@ client_freehints(struct client_ctx *cc)
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);

170
conf.c
View File

@@ -76,6 +76,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);
@@ -158,6 +160,47 @@ conf_init(struct conf *c)
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;
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);
}
xfree(c->DefaultFontName);
}
void
conf_setup(struct conf *c, const char *conf_file)
{
@@ -201,93 +244,93 @@ conf_client(struct client_ctx *cc)
} 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;
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} },
{ "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}},
};
/*
@@ -387,7 +430,7 @@ 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);
@@ -528,7 +571,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);
}
}

4
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: September 22 2008 $
.Dt CWM 1
.Os
.Sh NAME
@@ -240,6 +239,7 @@ option is given.
.Sh FILES
.Bl -tag -width Ds
.It Pa ~/.cwmrc
.El
.Sh SEE ALSO
.Xr cwmrc 5
.Sh AUTHORS

117
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: February 7 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,10 @@ 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 command Ar name Ar path
Every
.Ar name
@@ -123,8 +126,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 +139,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.
@@ -165,6 +169,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.
@@ -260,53 +269,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

2
font.c
View File

@@ -68,7 +68,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);
}

47
group.c
View File

@@ -24,11 +24,22 @@
#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)
{
@@ -41,6 +52,9 @@ _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;
}
@@ -51,6 +65,10 @@ _group_remove(struct client_ctx *cc)
if (cc == NULL || cc->group == 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;
}
@@ -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,6 +139,7 @@ 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);
}
@@ -156,12 +175,9 @@ 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
static void
_group_fix_hidden_state(struct group_ctx *gc)
{
struct client_ctx *cc;
@@ -317,16 +333,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;
}
}
}

View File

@@ -40,7 +40,8 @@
#include <ctype.h>
#include <X11/cursorfont.h>
#include <X11/extensions/shape.h>
#include <X11/extensions/Xinerama.h>
#include <X11/extensions/Xrandr.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>

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;
@@ -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;
@@ -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";
@@ -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;
@@ -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;
@@ -428,59 +427,59 @@ 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_cyclegroup(struct client_ctx *cc, union arg *arg)
{
group_cycle((int)arg);
group_cycle(arg->i);
}
void
kbfunc_client_nogroup(struct client_ctx *cc, void *arg)
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_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);
}

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,153 @@
#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 *, int, int);
#define ADJUST_HEIGHT(cc, dy) ((cc->geom.height - cc->geom.min_dy) / dy)
#define ADJUST_WIDTH(cc, dx) ((cc->geom.width - cc->geom.min_dx) / dx)
static int
_mousefunc_sweep_calc(struct client_ctx *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, 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
mousefunc_window_resize(struct client_ctx *cc, void *arg)
{
grab_sweep(cc);
client_resize(cc);
XEvent ev;
struct screen_ctx *sc = CCTOSC(cc);
int dx, dy;
int x = cc->geom.x, y = cc->geom.y;
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);
_mousefunc_sweep_draw(cc, dx, dy);
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, ev.xmotion.y))
/* Recompute window output */
_mousefunc_sweep_draw(cc, dx, dy);
client_resize(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
mousefunc_window_move(struct client_ctx *cc, void *arg)
{
grab_drag(cc);
client_move(cc);
XEvent ev;
struct screen_ctx *sc = CCTOSC(cc);
int mx, my;
int x = cc->geom.x, y = cc->geom.y;
client_raise(cc);
if (xu_ptr_grab(sc->rootwin, MouseMask, Cursor_move) < 0)
return;
xu_ptr_getpos(sc->rootwin, &mx, &my);
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 - mx);
cc->geom.y = y + (ev.xmotion.y - my);
client_move(cc);
break;
case ButtonRelease:
xu_ptr_ungrab();
return;
}
}
/* NOTREACHED */
}
void

68
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,7 @@ typedef struct {
%token FONTNAME STICKY GAP MOUSEBIND
%token AUTOGROUP BIND COMMAND IGNORE
%token YES NO
%token YES NO BORDERWIDTH MOVEAMOUNT
%token ERROR
%token <v.string> STRING
%token <v.number> NUMBER
@@ -109,6 +107,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);
@@ -200,11 +204,13 @@ lookup(char *s)
static const struct keywords keywords[] = {
{ "autogroup", AUTOGROUP},
{ "bind", BIND},
{ "borderwidth", BORDERWIDTH},
{ "command", COMMAND},
{ "fontname", FONTNAME},
{ "gap", GAP},
{ "ignore", IGNORE},
{ "mousebind", MOUSEBIND},
{ "moveamount", MOVEAMOUNT},
{ "no", NO},
{ "sticky", STICKY},
{ "yes", YES}
@@ -462,50 +468,6 @@ 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)
{
@@ -540,28 +502,30 @@ parse_config(const char *filename, struct conf *xconf)
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);
}

View File

@@ -67,3 +67,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

@@ -132,7 +132,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);
@@ -175,13 +175,23 @@ search_match_text(struct menu_q *menuq, struct menu_q *resultq, char *search)
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)
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

127
xevents.c
View File

@@ -36,13 +36,8 @@ void
xev_handle_maprequest(struct xevent *xev, 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,15 +45,7 @@ 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);
@@ -68,10 +55,27 @@ void
xev_handle_unmapnotify(struct xevent *xev, 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);
/* 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);
xev_register(xev);
}
@@ -83,7 +87,7 @@ xev_handle_destroynotify(struct xevent *xev, XEvent *ee)
struct client_ctx *cc;
if ((cc = client_find(e->window)) != NULL)
client_delete(cc, 1, 1);
client_delete(cc);
xev_register(xev);
}
@@ -99,7 +103,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,39 +111,36 @@ 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);
}
@@ -180,7 +180,7 @@ 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;
@@ -193,17 +193,7 @@ xev_handle_enternotify(struct xevent *xev, XEvent *ee)
XCrossingEvent *e = &ee->xcrossing;
struct client_ctx *cc;
if ((cc = client_find(e->window)) == NULL) {
/*
* XXX - later. messes up unclutter. but may be
* needed when we introduce menu windows and such into
* the main event loop.
*/
#ifdef notyet
if (e->window != e->root)
client_nocurrent();
#endif
} else
if ((cc = client_find(e->window)) != NULL)
client_setactive(cc, 1);
xev_register(xev);
@@ -225,7 +215,6 @@ xev_handle_buttonpress(struct xevent *xev, XEvent *ee)
struct client_ctx *cc;
struct screen_ctx *sc;
struct mousebinding *mb;
char *wname;
sc = screen_fromroot(e->root);
cc = client_find(e->window);
@@ -305,7 +294,7 @@ xev_handle_keypress(struct xevent *xev, XEvent *ee)
if (kb->flags & KBFLAG_NEEDCLIENT)
goto out;
(*kb->callback)(cc, kb->argument);
(*kb->callback)(cc, &kb->argument);
out:
xev_register(xev);
@@ -366,13 +355,19 @@ out:
}
void
xev_handle_shape(struct xevent *xev, XEvent *ee)
xev_handle_randr(struct xevent *xev, XEvent *ee)
{
XShapeEvent *sev = (XShapeEvent *) ee;
struct client_ctx *cc;
XRRScreenChangeNotifyEvent *rev = (XRRScreenChangeNotifyEvent *)ee;
struct client_ctx *cc;
struct screen_ctx *sc;
if ((cc = client_find(sev->window)) != NULL)
client_do_shape(cc);
if ((cc = client_find(rev->window)) != NULL) {
XRRUpdateConfiguration(ee);
sc = CCTOSC(cc);
sc->xmax = rev->width;
sc->ymax = rev->height;
screen_init_xinerama(sc);
}
}
/*
@@ -453,10 +448,8 @@ xev_handle_expose(struct xevent *xev, 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);
}
@@ -523,8 +516,8 @@ xev_loop(void)
ASSIGN1(xclient);
break;
default:
if (e.type == Shape_ev)
xev_handle_shape(xev, &e);
if (e.type == Randr_ev)
xev_handle_randr(xev, &e);
break;
}

27
xutil.c
View File

@@ -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,28 @@ 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;
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);
}