mirror of
https://github.com/leahneukirchen/cwm.git
synced 2023-08-10 21:13:12 +03:00
Compare commits
243 Commits
OPENBSD_4_
...
ignorewarp
Author | SHA1 | Date | |
---|---|---|---|
![]() |
a119fe5240 | ||
![]() |
f2e8fad75c | ||
![]() |
1f310d57e2 | ||
![]() |
ff3df256a1 | ||
![]() |
dee6ac5b7d | ||
![]() |
2d66003e4b | ||
![]() |
917bce4b8d | ||
![]() |
2440efad06 | ||
![]() |
aaca5b7e45 | ||
![]() |
2a5e1791d4 | ||
![]() |
e0c9657773 | ||
![]() |
85a53083cb | ||
![]() |
72e6d2d0a9 | ||
![]() |
f769df540d | ||
![]() |
a292c96977 | ||
![]() |
b12e6fc5cd | ||
![]() |
46c9b5cbae | ||
![]() |
d90ab51111 | ||
![]() |
50aff37f50 | ||
![]() |
507480a695 | ||
![]() |
c4a97053cd | ||
![]() |
e88bda0df5 | ||
![]() |
ccb207a8a8 | ||
![]() |
09a2d7fb98 | ||
![]() |
b27c3c22b5 | ||
![]() |
2ad2b5f31d | ||
![]() |
597cb25820 | ||
![]() |
b6b7d273d4 | ||
![]() |
49661d405b | ||
![]() |
3b87bdb047 | ||
![]() |
28e94b2fbc | ||
![]() |
a0ec2515e9 | ||
![]() |
b35cbf81d8 | ||
![]() |
9b04930f24 | ||
![]() |
a7c3a7cac3 | ||
![]() |
134e777cf0 | ||
![]() |
ee7df6a95f | ||
![]() |
aa88d5848e | ||
![]() |
728d2a40dd | ||
![]() |
3c60d854db | ||
![]() |
3e309894c1 | ||
![]() |
46630531f8 | ||
![]() |
ab4d36531c | ||
![]() |
892e1e1c0d | ||
![]() |
4e2014863b | ||
![]() |
42bf29fb20 | ||
![]() |
afaf69cefc | ||
![]() |
85d8697676 | ||
![]() |
4af6a60d84 | ||
![]() |
38ad2e1d9c | ||
![]() |
7295c51155 | ||
![]() |
b9f8367089 | ||
![]() |
0a44f2e5c4 | ||
![]() |
1968561fcc | ||
![]() |
95f65b8be6 | ||
![]() |
8fd4ff1c7c | ||
![]() |
fcb2684db1 | ||
![]() |
e2b1cb98c1 | ||
![]() |
028a1778db | ||
![]() |
09d88f4a18 | ||
![]() |
e7f0d63413 | ||
![]() |
82911249e2 | ||
![]() |
e095e955a8 | ||
![]() |
590eb4f37b | ||
![]() |
f44862be9c | ||
![]() |
b13d592c57 | ||
![]() |
bcc0f73bb6 | ||
![]() |
58d12134b1 | ||
![]() |
18c7d89c98 | ||
![]() |
ee59e4a5a1 | ||
![]() |
055b244bb4 | ||
![]() |
71ad069846 | ||
![]() |
11b4b7fec6 | ||
![]() |
61f841ea58 | ||
![]() |
d7589ca80b | ||
![]() |
3eec3b3802 | ||
![]() |
d1b84c5415 | ||
![]() |
6e9fa7548b | ||
![]() |
8bbc376fd9 | ||
![]() |
2c29a1de65 | ||
![]() |
d2cfeb40b4 | ||
![]() |
382662d003 | ||
![]() |
9be7726606 | ||
![]() |
4d5dc5d9ea | ||
![]() |
5d51c8e0e5 | ||
![]() |
4c10afe2cc | ||
![]() |
eb7803269e | ||
![]() |
6df7cba24e | ||
![]() |
29cdc29c6e | ||
![]() |
3de90d44fc | ||
![]() |
fbb1edf2b3 | ||
![]() |
64f0038db7 | ||
![]() |
4f34392258 | ||
![]() |
655c33c489 | ||
![]() |
cc68490fe1 | ||
![]() |
ea96e92ac8 | ||
![]() |
8a490fc270 | ||
![]() |
8346de997f | ||
![]() |
17ae65adc5 | ||
![]() |
507b65a27f | ||
![]() |
4fe12f528c | ||
![]() |
6ad198022b | ||
![]() |
c750462d13 | ||
![]() |
9203c7e8ca | ||
![]() |
b23cef2e4a | ||
![]() |
01af04a342 | ||
![]() |
7660bf0db0 | ||
![]() |
779177a53d | ||
![]() |
87964e5c7e | ||
![]() |
e239976078 | ||
![]() |
712f3f62c7 | ||
![]() |
e2f3810fe8 | ||
![]() |
1b269199c1 | ||
![]() |
0548673f2f | ||
![]() |
bd4c4d7734 | ||
![]() |
fa87ef4a9e | ||
![]() |
399253a4ff | ||
![]() |
ec8e6052ba | ||
![]() |
5c757cc7f4 | ||
![]() |
49e218cf53 | ||
![]() |
7e110f379b | ||
![]() |
c07123ec78 | ||
![]() |
d1050afb60 | ||
![]() |
dcfae161a2 | ||
![]() |
0aca400461 | ||
![]() |
590169ce24 | ||
![]() |
99afa5091f | ||
![]() |
b47283ab41 | ||
![]() |
b523788c0e | ||
![]() |
ee0ec9a453 | ||
![]() |
d2a54bc115 | ||
![]() |
841c646a2b | ||
![]() |
25af744559 | ||
![]() |
be5dfb4ea4 | ||
![]() |
a0739c6cd4 | ||
![]() |
e2610449d1 | ||
![]() |
2bd5e53c2e | ||
![]() |
60a88f54cc | ||
![]() |
61601991b5 | ||
![]() |
a0082c58a4 | ||
![]() |
04441482d4 | ||
![]() |
0df9e0673c | ||
![]() |
436a9e5c54 | ||
![]() |
20052e0248 | ||
![]() |
13b640ea29 | ||
![]() |
2f8639d37b | ||
![]() |
556f7a0871 | ||
![]() |
2798cdc9a7 | ||
![]() |
8afabd6c55 | ||
![]() |
96f03c8cbc | ||
![]() |
6d268bfa4a | ||
![]() |
b6dab5ccf3 | ||
![]() |
a556d3fa1f | ||
![]() |
6ea4b1bd3b | ||
![]() |
8be175b175 | ||
![]() |
85e6c61360 | ||
![]() |
b23fad3987 | ||
![]() |
734f45ab4b | ||
![]() |
993fd4311f | ||
![]() |
a6ec6cd9e9 | ||
![]() |
05b17bf803 | ||
![]() |
2dfd021f8b | ||
![]() |
77058c59e2 | ||
![]() |
187e7dfad2 | ||
![]() |
6f1ed5bfe3 | ||
![]() |
e21e7680e4 | ||
![]() |
2bddbe12f4 | ||
![]() |
0ba60f0b94 | ||
![]() |
4f2d4724c9 | ||
![]() |
19ba704ee3 | ||
![]() |
9657664c7b | ||
![]() |
867652c484 | ||
![]() |
07cd0b1ac5 | ||
![]() |
96d7310b4a | ||
![]() |
160228210b | ||
![]() |
9d9c61b8f6 | ||
![]() |
bdcbbe7f53 | ||
![]() |
b4ae492b7b | ||
![]() |
01eecac5d4 | ||
![]() |
077173527b | ||
![]() |
ff9e573e1d | ||
![]() |
198bb381a9 | ||
![]() |
6f1f3592d4 | ||
![]() |
78c8bf08cb | ||
![]() |
4377b5ac3f | ||
![]() |
9037043088 | ||
![]() |
610e8e83ac | ||
![]() |
efbfc5fa42 | ||
![]() |
b86d3cfae9 | ||
![]() |
72bc2a295b | ||
![]() |
48528d9ba1 | ||
![]() |
779cf04f05 | ||
![]() |
1e46ba72f7 | ||
![]() |
3bb0b451f7 | ||
![]() |
53116c4ec3 | ||
![]() |
981c2480db | ||
![]() |
6733ac217f | ||
![]() |
71f99ab78f | ||
![]() |
d347aa3d9a | ||
![]() |
43d6e147c2 | ||
![]() |
7957a470fd | ||
![]() |
a94f4bbb7a | ||
![]() |
5a0128bdc7 | ||
![]() |
5fee379cb5 | ||
![]() |
b700be764a | ||
![]() |
27b023ebcb | ||
![]() |
5c402536fa | ||
![]() |
a21a064a9b | ||
![]() |
0f50af616e | ||
![]() |
9a58e74401 | ||
![]() |
5034a77849 | ||
![]() |
ec77265b87 | ||
![]() |
458f96936d | ||
![]() |
cd0ce46817 | ||
![]() |
79569a4d59 | ||
![]() |
e3971fc758 | ||
![]() |
898bfff36a | ||
![]() |
cd5c340e01 | ||
![]() |
f473dc3d12 | ||
![]() |
f67772be65 | ||
![]() |
642afbdf8c | ||
![]() |
d5794a6b02 | ||
![]() |
887a5aa65f | ||
![]() |
75182c6d9c | ||
![]() |
3a94c57afc | ||
![]() |
4bbb472a25 | ||
![]() |
fe80d40063 | ||
![]() |
343ec1bb4f | ||
![]() |
eb77aabea1 | ||
![]() |
9702d4cfd7 | ||
![]() |
539b5c6534 | ||
![]() |
0f18223042 | ||
![]() |
cb2cc70c3f | ||
![]() |
ef0859de20 | ||
![]() |
34c0a0635f | ||
![]() |
e704b57d33 | ||
![]() |
c3aa344e78 | ||
![]() |
38ff7a904e | ||
![]() |
36c1aac90f | ||
![]() |
cd46788d85 | ||
![]() |
fead0d511f | ||
![]() |
f85ba10437 | ||
![]() |
a466ddaa2d |
53
Makefile
53
Makefile
@@ -1,25 +1,54 @@
|
|||||||
# $OpenBSD$
|
# $OpenBSD$
|
||||||
|
|
||||||
.include <bsd.own.mk>
|
#.include <bsd.xconf.mk>
|
||||||
|
|
||||||
X11BASE?= /usr/X11R6
|
|
||||||
|
|
||||||
PROG= cwm
|
PROG= cwm
|
||||||
|
|
||||||
SRCS= calmwm.c screen.c xmalloc.c client.c grab.c search.c \
|
BINDIR= /usr/bin
|
||||||
util.c xutil.c conf.c input.c xevents.c group.c \
|
|
||||||
kbfunc.c font.c
|
|
||||||
|
|
||||||
CPPFLAGS+= -I${X11BASE}/include -I${X11BASE}/include/freetype2
|
SRCS= calmwm.c screen.c xmalloc.c client.c menu.c \
|
||||||
|
search.c util.c xutil.c conf.c input.c xevents.c group.c \
|
||||||
|
kbfunc.c mousefunc.c font.c parse.y
|
||||||
|
|
||||||
|
OBJS= calmwm.o screen.o xmalloc.o client.o menu.o \
|
||||||
|
search.o util.o xutil.o conf.o input.o xevents.o group.o \
|
||||||
|
kbfunc.o mousefunc.o font.o strlcpy.o strlcat.o y.tab.o \
|
||||||
|
strtonum.o fgetln.o
|
||||||
|
|
||||||
|
X11BASE= /usr
|
||||||
|
|
||||||
|
CPPFLAGS+= -I${X11BASE}/include -I${X11BASE}/include/freetype2 -I.
|
||||||
|
|
||||||
|
CFLAGS+= -Wall
|
||||||
|
|
||||||
LDADD+= -L${X11BASE}/lib -lXft -lXrender -lX11 -lXau -lXdmcp \
|
LDADD+= -L${X11BASE}/lib -lXft -lXrender -lX11 -lXau -lXdmcp \
|
||||||
-lfontconfig -lexpat -lfreetype -lz -lX11 -lXau -lXdmcp -lXext
|
-lfontconfig -lexpat -lfreetype -lz -lXinerama -lXrandr -lXext
|
||||||
|
|
||||||
MANDIR= ${X11BASE}/man/cat
|
MANDIR= ${X11BASE}/man/cat
|
||||||
|
MAN= cwm.1 cwmrc.5
|
||||||
|
|
||||||
CLEANFILES= cwm.cat1
|
CLEANFILES= cwm.cat1 cwmrc.cat5
|
||||||
|
|
||||||
obj: _xenocara_obj
|
|
||||||
|
|
||||||
.include <bsd.prog.mk>
|
all: $(PROG)
|
||||||
.include <bsd.xorg.mk>
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(OBJS) $(PROG) y.tab.c
|
||||||
|
|
||||||
|
y.tab.c: parse.y
|
||||||
|
byacc parse.y
|
||||||
|
|
||||||
|
|
||||||
|
$(PROG): $(OBJS) y.tab.o
|
||||||
|
$(CC) $(OBJS) ${LDADD} -o ${PROG}
|
||||||
|
|
||||||
|
$(OBJS): %.o: %.c
|
||||||
|
$(CC) -c $(CFLAGS) $(CPPFLAGS) $<
|
||||||
|
|
||||||
|
install: ${PROG}
|
||||||
|
install -m 755 cwm /usr/local/bin/
|
||||||
|
install -m 644 cwm.1 /usr/local/man/man1
|
||||||
|
install -m 644 cwmrc.5 /usr/local/man/man5
|
||||||
|
|
||||||
|
#.include <bsd.prog.mk>
|
||||||
|
#.include <bsd.xorg.mk>
|
||||||
|
58
README
58
README
@@ -1,58 +0,0 @@
|
|||||||
--------------------------------------------------------------------------------
|
|
||||||
cwm release three
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
by Marius Aamodt Eriksen <marius@monkey.org>
|
|
||||||
contributions by Andy Adamson <dros@monkey.org>,
|
|
||||||
Niels Provos <provos@monkey.org>,
|
|
||||||
Martin Murray <mmurray@monkey.org>,
|
|
||||||
Dimitris Economou <dimeco@stanford.edu> &
|
|
||||||
Antti Nyk<79>nen <aon@iki.fi>.
|
|
||||||
|
|
||||||
http://monkey.org/~marius/cwm
|
|
||||||
|
|
||||||
DESCRIPTION
|
|
||||||
|
|
||||||
cwm is a window manager initially inspired by evilwm[1]. It
|
|
||||||
developed out of modifications to evilwm, but eventually the code
|
|
||||||
base of evilwm did not accomodate well for the new features added.
|
|
||||||
So calmwm was written from scratch.
|
|
||||||
|
|
||||||
Its main goal is to be as efficient as possible, while providing
|
|
||||||
a very clean, simple & attractive aesthetic.
|
|
||||||
|
|
||||||
cwm has several novel features, including the ability to search
|
|
||||||
for windows.
|
|
||||||
|
|
||||||
HIGHLIGHTS IN RELEASE TWO
|
|
||||||
|
|
||||||
* Improved alt-tabbing, including the ability to reverse cycle.
|
|
||||||
* Display of a context menu when alt-tabbing, showing the previous,
|
|
||||||
current and next window in the cycle order.
|
|
||||||
* Much improved ranking in search.
|
|
||||||
* In search-menus, the ability to list every item.
|
|
||||||
|
|
||||||
HIGHLIGHTS IN RELEASE THREE
|
|
||||||
|
|
||||||
* More search ranking improvements
|
|
||||||
* Many contributions by Antti Nyk<79>nen: keyboard binding "i18n",
|
|
||||||
show window labels in minimized window menu, automatic window
|
|
||||||
grouping, MWM hints support & some bug fixes.
|
|
||||||
* Xft support & the addition of the -f flag (see manpage).
|
|
||||||
|
|
||||||
INSTALL
|
|
||||||
|
|
||||||
./configure
|
|
||||||
make
|
|
||||||
su
|
|
||||||
make install
|
|
||||||
|
|
||||||
DOCUMENTATION
|
|
||||||
|
|
||||||
See the manpage cwm(1).
|
|
||||||
|
|
||||||
LICENSE
|
|
||||||
|
|
||||||
cwm is distributed under a BSD like license. Please see the LICENSE
|
|
||||||
file or the top of any source file for more information.
|
|
||||||
|
|
||||||
[1] http://evilwm.sourceforge.net/
|
|
28
TODO
28
TODO
@@ -1,28 +0,0 @@
|
|||||||
- window initial position
|
|
||||||
|
|
||||||
- don't map windows if it's within [some time increment] of active typing,
|
|
||||||
this is part of the "calm" goal. also, it helps if you're mindlessly
|
|
||||||
typing in a password and the keyboard input ends up in some other window,
|
|
||||||
bad...
|
|
||||||
|
|
||||||
- integrate everything into /ONE/ event loop.
|
|
||||||
register handlers, with the ability to select, for example,
|
|
||||||
a window, or an event, etc. (no, maybe not...)
|
|
||||||
|
|
||||||
- ignoreq, always lower them. perhaps implement by lowering the entire
|
|
||||||
queue on each XLower...
|
|
||||||
|
|
||||||
- search window should try to stay inside of the screen boundaries.
|
|
||||||
|
|
||||||
- geographical keyboard navigation (window switching)
|
|
||||||
|
|
||||||
- search should ignore the current window. (not add to match list).
|
|
||||||
|
|
||||||
- make kbd shortcuts/events more general. the ability to associate an
|
|
||||||
event with a mode (i.e. prioritize). gets rid of hacky-ness in
|
|
||||||
groups, etc.
|
|
||||||
|
|
||||||
- figure out what's up when alt-tab goes back to the current window
|
|
||||||
once before moving on.
|
|
||||||
|
|
||||||
- cache all the atoms somewhere.
|
|
289
calmwm.c
289
calmwm.c
@@ -18,7 +18,19 @@
|
|||||||
* $Id$
|
* $Id$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "headers.h"
|
#include <sys/param.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
|
#include <err.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "calmwm.h"
|
#include "calmwm.h"
|
||||||
|
|
||||||
Display *X_Dpy;
|
Display *X_Dpy;
|
||||||
@@ -29,47 +41,35 @@ Cursor Cursor_select;
|
|||||||
Cursor Cursor_default;
|
Cursor Cursor_default;
|
||||||
Cursor Cursor_question;
|
Cursor Cursor_question;
|
||||||
|
|
||||||
struct screen_ctx_q Screenq;
|
struct screen_ctx_q Screenq = TAILQ_HEAD_INITIALIZER(Screenq);
|
||||||
struct screen_ctx *Curscreen;
|
struct client_ctx_q Clientq = TAILQ_HEAD_INITIALIZER(Clientq);
|
||||||
u_int Nscreens;
|
|
||||||
|
|
||||||
struct client_ctx_q Clientq;
|
int HasXinerama, HasRandr, Randr_ev;
|
||||||
|
|
||||||
int Doshape, Shape_ev;
|
|
||||||
int Starting;
|
int Starting;
|
||||||
struct conf Conf;
|
struct conf Conf;
|
||||||
struct fontdesc *DefaultFont;
|
|
||||||
char *DefaultFontName;
|
|
||||||
|
|
||||||
/* From TWM */
|
static void sigchld_cb(int);
|
||||||
#define gray_width 2
|
static void dpy_init(const char *);
|
||||||
#define gray_height 2
|
static int x_errorhandler(Display *, XErrorEvent *);
|
||||||
static char gray_bits[] = {0x02, 0x01};
|
static void x_setup(void);
|
||||||
|
static void x_setupscreen(struct screen_ctx *, u_int);
|
||||||
|
static void x_teardown(void);
|
||||||
static void _sigchld_cb(int);
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int ch;
|
const char *conf_file = NULL;
|
||||||
int conf_flags = 0;
|
|
||||||
|
|
||||||
char *display_name = NULL;
|
char *display_name = NULL;
|
||||||
|
int ch;
|
||||||
|
|
||||||
DefaultFontName = "sans-serif:pixelsize=14:bold";
|
while ((ch = getopt(argc, argv, "c:d:")) != -1) {
|
||||||
|
|
||||||
while ((ch = getopt(argc, argv, "d:sf:")) != -1) {
|
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
|
case 'c':
|
||||||
|
conf_file = optarg;
|
||||||
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
display_name = optarg;
|
display_name = optarg;
|
||||||
break;
|
break;
|
||||||
case 's':
|
|
||||||
conf_flags |= CONF_STICKY_GROUPS;
|
|
||||||
break;
|
|
||||||
case 'f':
|
|
||||||
DefaultFontName = xstrdup(optarg);
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
usage();
|
usage();
|
||||||
}
|
}
|
||||||
@@ -77,67 +77,59 @@ main(int argc, char **argv)
|
|||||||
argc -= optind;
|
argc -= optind;
|
||||||
argv += optind;
|
argv += optind;
|
||||||
|
|
||||||
/* Ignore a few signals. */
|
if (signal(SIGCHLD, sigchld_cb) == SIG_ERR)
|
||||||
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
|
|
||||||
err(1, "signal");
|
err(1, "signal");
|
||||||
|
|
||||||
if (signal(SIGCHLD, _sigchld_cb) == SIG_ERR)
|
|
||||||
err(1, "signal");
|
|
||||||
|
|
||||||
group_init();
|
|
||||||
|
|
||||||
Starting = 1;
|
Starting = 1;
|
||||||
conf_setup(&Conf);
|
dpy_init(display_name);
|
||||||
Conf.flags |= conf_flags;
|
|
||||||
client_setup();
|
bzero(&Conf, sizeof(Conf));
|
||||||
x_setup(display_name);
|
conf_setup(&Conf, conf_file);
|
||||||
|
xu_getatoms();
|
||||||
|
x_setup();
|
||||||
Starting = 0;
|
Starting = 0;
|
||||||
|
|
||||||
xev_init();
|
|
||||||
XEV_QUICK(NULL, NULL, MapRequest, xev_handle_maprequest, NULL);
|
|
||||||
XEV_QUICK(NULL, NULL, UnmapNotify, xev_handle_unmapnotify, NULL);
|
|
||||||
XEV_QUICK(NULL, NULL, ConfigureRequest,
|
|
||||||
xev_handle_configurerequest, NULL);
|
|
||||||
XEV_QUICK(NULL, NULL, PropertyNotify, xev_handle_propertynotify, NULL);
|
|
||||||
XEV_QUICK(NULL, NULL, EnterNotify, xev_handle_enternotify, NULL);
|
|
||||||
XEV_QUICK(NULL, NULL, LeaveNotify, xev_handle_leavenotify, NULL);
|
|
||||||
XEV_QUICK(NULL, NULL, ButtonPress, xev_handle_buttonpress, NULL);
|
|
||||||
XEV_QUICK(NULL, NULL, ButtonRelease, xev_handle_buttonrelease, NULL);
|
|
||||||
XEV_QUICK(NULL, NULL, KeyPress, xev_handle_keypress, NULL);
|
|
||||||
XEV_QUICK(NULL, NULL, KeyRelease, xev_handle_keyrelease, NULL);
|
|
||||||
XEV_QUICK(NULL, NULL, Expose, xev_handle_expose, NULL);
|
|
||||||
XEV_QUICK(NULL, NULL, DestroyNotify, xev_handle_destroynotify, NULL);
|
|
||||||
XEV_QUICK(NULL, NULL, ClientMessage, xev_handle_clientmessage, NULL);
|
|
||||||
|
|
||||||
xev_loop();
|
xev_loop();
|
||||||
|
|
||||||
|
x_teardown();
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
x_setup(char *display_name)
|
dpy_init(const char *dpyname)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct screen_ctx *sc;
|
|
||||||
char *fontname;
|
|
||||||
|
|
||||||
TAILQ_INIT(&Screenq);
|
if ((X_Dpy = XOpenDisplay(dpyname)) == NULL)
|
||||||
|
|
||||||
if ((X_Dpy = XOpenDisplay(display_name)) == NULL)
|
|
||||||
errx(1, "unable to open display \"%s\"",
|
errx(1, "unable to open display \"%s\"",
|
||||||
XDisplayName(display_name));
|
XDisplayName(dpyname));
|
||||||
|
|
||||||
XSetErrorHandler(x_errorhandler);
|
XSetErrorHandler(x_errorhandler);
|
||||||
|
|
||||||
Doshape = XShapeQueryExtension(X_Dpy, &Shape_ev, &i);
|
HasRandr = XRRQueryExtension(X_Dpy, &Randr_ev, &i);
|
||||||
|
}
|
||||||
|
|
||||||
Nscreens = ScreenCount(X_Dpy);
|
static void
|
||||||
for (i = 0; i < (int)Nscreens; i++) {
|
x_setup(void)
|
||||||
XMALLOC(sc, struct screen_ctx);
|
{
|
||||||
|
struct screen_ctx *sc;
|
||||||
|
struct keybinding *kb;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ScreenCount(X_Dpy); i++) {
|
||||||
|
sc = xcalloc(1, sizeof(*sc));
|
||||||
x_setupscreen(sc, i);
|
x_setupscreen(sc, i);
|
||||||
TAILQ_INSERT_TAIL(&Screenq, sc, entry);
|
TAILQ_INSERT_TAIL(&Screenq, sc, entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XXX key grabs weren't done before, since Screenq was empty,
|
||||||
|
* do them here for now (this needs changing).
|
||||||
|
*/
|
||||||
|
TAILQ_FOREACH(kb, &Conf.keybindingq, entry)
|
||||||
|
conf_grab(&Conf, kb);
|
||||||
|
|
||||||
Cursor_move = XCreateFontCursor(X_Dpy, XC_fleur);
|
Cursor_move = XCreateFontCursor(X_Dpy, XC_fleur);
|
||||||
Cursor_resize = XCreateFontCursor(X_Dpy, XC_bottom_right_corner);
|
Cursor_resize = XCreateFontCursor(X_Dpy, XC_bottom_right_corner);
|
||||||
Cursor_select = XCreateFontCursor(X_Dpy, XC_hand1);
|
Cursor_select = XCreateFontCursor(X_Dpy, XC_hand1);
|
||||||
@@ -145,89 +137,50 @@ x_setup(char *display_name)
|
|||||||
Cursor_question = XCreateFontCursor(X_Dpy, XC_question_arrow);
|
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)
|
x_setupscreen(struct screen_ctx *sc, u_int which)
|
||||||
{
|
{
|
||||||
XColor tmp;
|
|
||||||
XGCValues gv, gv1/* , gv2 */;
|
|
||||||
Window *wins, w0, w1;
|
Window *wins, w0, w1;
|
||||||
u_int nwins, i = 0;
|
|
||||||
XWindowAttributes winattr;
|
XWindowAttributes winattr;
|
||||||
XSetWindowAttributes rootattr;
|
XSetWindowAttributes rootattr;
|
||||||
struct keybinding *kb;
|
int fake;
|
||||||
|
u_int nwins, i;
|
||||||
sc->display = x_screenname(which);
|
|
||||||
sc->which = which;
|
sc->which = which;
|
||||||
sc->rootwin = RootWindow(X_Dpy, which);
|
sc->rootwin = RootWindow(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);
|
|
||||||
|
|
||||||
TAILQ_FOREACH(kb, &Conf.keybindingq, entry)
|
conf_gap(&Conf, sc);
|
||||||
xu_key_grab(sc->rootwin, kb->modmask, kb->keysym);
|
screen_update_geometry(sc, DisplayWidth(X_Dpy, sc->which),
|
||||||
|
DisplayHeight(X_Dpy, sc->which));
|
||||||
|
|
||||||
sc->blackpixl = BlackPixel(X_Dpy, sc->which);
|
conf_color(&Conf, sc);
|
||||||
sc->whitepixl = WhitePixel(X_Dpy, sc->which);
|
|
||||||
sc->bluepixl = sc->fccolor.pixel;
|
|
||||||
sc->redpixl = sc->redcolor.pixel;
|
|
||||||
sc->cyanpixl = sc->cyancolor.pixel;
|
|
||||||
|
|
||||||
sc->gray = XCreatePixmapFromBitmapData(X_Dpy, sc->rootwin,
|
|
||||||
gray_bits, gray_width, gray_height,
|
|
||||||
sc->blackpixl, sc->whitepixl, DefaultDepth(X_Dpy, sc->which));
|
|
||||||
|
|
||||||
sc->blue = XCreatePixmapFromBitmapData(X_Dpy, sc->rootwin,
|
|
||||||
gray_bits, gray_width, gray_height,
|
|
||||||
sc->bluepixl, sc->whitepixl, DefaultDepth(X_Dpy, sc->which));
|
|
||||||
|
|
||||||
sc->red = XCreatePixmapFromBitmapData(X_Dpy, sc->rootwin,
|
|
||||||
gray_bits, gray_width, gray_height,
|
|
||||||
sc->redpixl, sc->whitepixl, DefaultDepth(X_Dpy, sc->which));
|
|
||||||
|
|
||||||
gv.foreground = sc->blackpixl^sc->whitepixl;
|
|
||||||
gv.background = sc->whitepixl;
|
|
||||||
gv.function = GXxor;
|
|
||||||
gv.line_width = 1;
|
|
||||||
gv.subwindow_mode = IncludeInferiors;
|
|
||||||
|
|
||||||
sc->gc = XCreateGC(X_Dpy, sc->rootwin,
|
|
||||||
GCForeground|GCBackground|GCFunction|
|
|
||||||
GCLineWidth|GCSubwindowMode, &gv);
|
|
||||||
|
|
||||||
sc->hlgc = XCreateGC(X_Dpy, sc->rootwin,
|
|
||||||
GCForeground|GCBackground|GCFunction|
|
|
||||||
GCLineWidth|GCSubwindowMode, &gv);
|
|
||||||
|
|
||||||
gv1.function = GXinvert;
|
|
||||||
gv1.subwindow_mode = IncludeInferiors;
|
|
||||||
gv1.line_width = 1;
|
|
||||||
|
|
||||||
sc->invgc = XCreateGC(X_Dpy, sc->rootwin,
|
|
||||||
GCFunction|GCSubwindowMode|GCLineWidth, &gv1);
|
|
||||||
|
|
||||||
|
group_init(sc);
|
||||||
font_init(sc);
|
font_init(sc);
|
||||||
DefaultFont = font_getx(sc, DefaultFontName);
|
conf_font(&Conf, sc);
|
||||||
|
|
||||||
/*
|
|
||||||
* XXX - this should *really* be in screen_init(). ordering
|
|
||||||
* problem.
|
|
||||||
*/
|
|
||||||
TAILQ_INIT(&sc->mruq);
|
TAILQ_INIT(&sc->mruq);
|
||||||
|
|
||||||
/* Initialize menu window. */
|
/* Initialize menu window. */
|
||||||
grab_menuinit(sc);
|
menu_init(sc);
|
||||||
search_init(sc);
|
|
||||||
|
xu_setwmname(sc);
|
||||||
|
|
||||||
|
rootattr.event_mask = ChildMask|PropertyChangeMask|EnterWindowMask|
|
||||||
|
LeaveWindowMask|ColormapChangeMask|ButtonMask;
|
||||||
|
|
||||||
|
XChangeWindowAttributes(X_Dpy, sc->rootwin,
|
||||||
|
CWEventMask, &rootattr);
|
||||||
|
|
||||||
/* Deal with existing clients. */
|
/* Deal with existing clients. */
|
||||||
XQueryTree(X_Dpy, sc->rootwin, &w0, &w1, &wins, &nwins);
|
XQueryTree(X_Dpy, sc->rootwin, &w0, &w1, &wins, &nwins);
|
||||||
@@ -235,57 +188,30 @@ x_setupscreen(struct screen_ctx *sc, u_int which)
|
|||||||
for (i = 0; i < nwins; i++) {
|
for (i = 0; i < nwins; i++) {
|
||||||
XGetWindowAttributes(X_Dpy, wins[i], &winattr);
|
XGetWindowAttributes(X_Dpy, wins[i], &winattr);
|
||||||
if (winattr.override_redirect ||
|
if (winattr.override_redirect ||
|
||||||
winattr.map_state != IsViewable) {
|
winattr.map_state != IsViewable)
|
||||||
char *name;
|
|
||||||
XFetchName(X_Dpy, wins[i], &name);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
client_new(wins[i], sc, winattr.map_state != IsUnmapped);
|
client_new(wins[i], sc, winattr.map_state != IsUnmapped);
|
||||||
}
|
}
|
||||||
XFree(wins);
|
XFree(wins);
|
||||||
|
|
||||||
Curscreen = sc; /* XXX */
|
screen_updatestackingorder(sc);
|
||||||
screen_init();
|
|
||||||
screen_updatestackingorder();
|
|
||||||
|
|
||||||
rootattr.event_mask = ChildMask|PropertyChangeMask|EnterWindowMask|
|
if (XineramaQueryExtension(X_Dpy, &fake, &fake) == 1 &&
|
||||||
LeaveWindowMask|ColormapChangeMask|ButtonMask;
|
((HasXinerama = XineramaIsActive(X_Dpy)) == 1))
|
||||||
|
HasXinerama = 1;
|
||||||
XChangeWindowAttributes(X_Dpy, sc->rootwin,
|
if (HasRandr)
|
||||||
/* CWCursor| */CWEventMask, &rootattr);
|
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);
|
XSync(X_Dpy, False);
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char *
|
static int
|
||||||
x_screenname(int which)
|
|
||||||
{
|
|
||||||
char *cp, *dstr, *sn;
|
|
||||||
size_t snlen;
|
|
||||||
|
|
||||||
if (which > 9)
|
|
||||||
errx(1, "Can't handle more than 9 screens. If you need it, "
|
|
||||||
"tell <marius@monkey.org>. It's a trivial fix.");
|
|
||||||
|
|
||||||
dstr = xstrdup(DisplayString(X_Dpy));
|
|
||||||
|
|
||||||
if ((cp = rindex(dstr, ':')) == NULL)
|
|
||||||
return (NULL);
|
|
||||||
|
|
||||||
if ((cp = index(cp, '.')) != NULL)
|
|
||||||
*cp = '\0';
|
|
||||||
|
|
||||||
snlen = strlen(dstr) + 3; /* string, dot, number, null */
|
|
||||||
sn = (char *)xmalloc(snlen);
|
|
||||||
snprintf(sn, snlen, "%s.%d", dstr, which);
|
|
||||||
free(dstr);
|
|
||||||
|
|
||||||
return (sn);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
x_errorhandler(Display *dpy, XErrorEvent *e)
|
x_errorhandler(Display *dpy, XErrorEvent *e)
|
||||||
{
|
{
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
@@ -311,15 +237,18 @@ x_errorhandler(Display *dpy, XErrorEvent *e)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_sigchld_cb(int which)
|
sigchld_cb(int which)
|
||||||
{
|
{
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
int save_errno = errno;
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
/* Collect dead children. */
|
/* Collect dead children. */
|
||||||
while ((pid = waitpid(-1, &status, WNOHANG)) > 0 ||
|
while ((pid = waitpid(-1, &status, WNOHANG)) > 0 ||
|
||||||
(pid < 0 && errno == EINTR))
|
(pid < 0 && errno == EINTR))
|
||||||
;
|
;
|
||||||
|
|
||||||
|
errno = save_errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
__dead void
|
__dead void
|
||||||
@@ -327,6 +256,6 @@ usage(void)
|
|||||||
{
|
{
|
||||||
extern char *__progname;
|
extern char *__progname;
|
||||||
|
|
||||||
fprintf(stderr, "usage: %s [-s] [-d display] [-f fontname] \n", __progname);
|
fprintf(stderr, "usage: %s [-c file] [-d display]\n", __progname);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
529
calmwm.h
529
calmwm.h
@@ -21,77 +21,108 @@
|
|||||||
#ifndef _CALMWM_H_
|
#ifndef _CALMWM_H_
|
||||||
#define _CALMWM_H_
|
#define _CALMWM_H_
|
||||||
|
|
||||||
#define CALMWM_MAXNAMELEN 256
|
/* ugly stuff */
|
||||||
|
#define TAILQ_END(head) NULL
|
||||||
|
#define __dead
|
||||||
|
|
||||||
#include "hash.h"
|
#include <X11/Xatom.h>
|
||||||
|
#include <X11/Xft/Xft.h>
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include <X11/Xproto.h>
|
||||||
|
#include <X11/Xutil.h>
|
||||||
|
#include <X11/cursorfont.h>
|
||||||
|
#include <X11/extensions/Xinerama.h>
|
||||||
|
#include <X11/extensions/Xrandr.h>
|
||||||
|
#include <X11/keysym.h>
|
||||||
|
|
||||||
|
#define CALMWM_MAXNAMELEN 256
|
||||||
|
|
||||||
#undef MIN
|
#undef MIN
|
||||||
#undef MAX
|
#undef MAX
|
||||||
#define MIN(x, y) ((x) < (y) ? (x) : (y))
|
#define MIN(x, y) ((x) < (y) ? (x) : (y))
|
||||||
#define MAX(x, y) ((x) > (y) ? (x) : (y))
|
#define MAX(x, y) ((x) > (y) ? (x) : (y))
|
||||||
|
|
||||||
enum conftype {
|
#define CONFFILE ".cwmrc"
|
||||||
CONF_BWIDTH, CONF_IGNORE, CONF_NOTIFIER,
|
#define WMNAME "CWM"
|
||||||
};
|
|
||||||
|
|
||||||
#define ChildMask (SubstructureRedirectMask|SubstructureNotifyMask)
|
#define ChildMask (SubstructureRedirectMask|SubstructureNotifyMask)
|
||||||
#define ButtonMask (ButtonPressMask|ButtonReleaseMask)
|
#define ButtonMask (ButtonPressMask|ButtonReleaseMask)
|
||||||
#define MouseMask (ButtonMask|PointerMotionMask)
|
#define MouseMask (ButtonMask|PointerMotionMask)
|
||||||
|
#define KeyMask (KeyPressMask|ExposureMask)
|
||||||
|
#define MenuMask (ButtonMask|ButtonMotionMask|ExposureMask| \
|
||||||
|
PointerMotionMask)
|
||||||
|
#define MenuGrabMask (ButtonMask|ButtonMotionMask|StructureNotifyMask|\
|
||||||
|
PointerMotionMask)
|
||||||
|
#define SearchMask (KeyPressMask|ExposureMask)
|
||||||
|
|
||||||
|
enum cwmcolor {
|
||||||
|
CWM_COLOR_BORDOR_ACTIVE,
|
||||||
|
CWM_COLOR_BORDER_INACTIVE,
|
||||||
|
CWM_COLOR_BORDER_GROUP,
|
||||||
|
CWM_COLOR_BORDER_UNGROUP,
|
||||||
|
CWM_COLOR_FG_MENU,
|
||||||
|
CWM_COLOR_BG_MENU,
|
||||||
|
CWM_COLOR_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
struct color {
|
||||||
|
unsigned long pixel;
|
||||||
|
char *name;
|
||||||
|
};
|
||||||
|
struct gap {
|
||||||
|
int top;
|
||||||
|
int bottom;
|
||||||
|
int left;
|
||||||
|
int right;
|
||||||
|
};
|
||||||
|
|
||||||
struct client_ctx;
|
struct client_ctx;
|
||||||
|
|
||||||
TAILQ_HEAD(cycle_entry_q, client_ctx);
|
TAILQ_HEAD(cycle_entry_q, client_ctx);
|
||||||
|
TAILQ_HEAD(group_ctx_q, group_ctx);
|
||||||
|
TAILQ_HEAD(client_ctx_q, client_ctx);
|
||||||
|
|
||||||
/* #define CYCLE_FOREACH_MRU(cy, ctx) TAILQ_FOREACH((ctx), */
|
#define CALMWM_NGROUPS 9
|
||||||
|
struct group_ctx {
|
||||||
struct screen_ctx;
|
TAILQ_ENTRY(group_ctx) entry;
|
||||||
|
struct client_ctx_q clients;
|
||||||
struct fontdesc {
|
int shortcut;
|
||||||
const char *name;
|
int hidden;
|
||||||
XftFont *fn;
|
int nhidden;
|
||||||
struct screen_ctx *sc;
|
int highstack;
|
||||||
HASH_ENTRY(fontdesc) node;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int fontdesc_cmp(struct fontdesc *a, struct fontdesc *b);
|
|
||||||
|
|
||||||
HASH_HEAD(fonthash, fontdesc, 16);
|
|
||||||
HASH_PROTOTYPE(fonthash, fontdesc, node, fontdesc_cmp);
|
|
||||||
|
|
||||||
struct screen_ctx {
|
struct screen_ctx {
|
||||||
TAILQ_ENTRY(screen_ctx) entry;
|
TAILQ_ENTRY(screen_ctx) entry;
|
||||||
|
|
||||||
u_int which;
|
u_int which;
|
||||||
Window rootwin;
|
Window rootwin;
|
||||||
Window menuwin;
|
Window menuwin;
|
||||||
Window searchwin;
|
|
||||||
Window groupwin;
|
|
||||||
Window infowin;
|
|
||||||
Colormap colormap;
|
|
||||||
GC invcg;
|
|
||||||
XColor bgcolor, fgcolor, fccolor, redcolor, cyancolor,
|
|
||||||
whitecolor, blackcolor;
|
|
||||||
char *display;
|
|
||||||
unsigned long blackpixl, whitepixl, redpixl, bluepixl, cyanpixl;
|
|
||||||
GC gc, invgc, hlgc;
|
|
||||||
|
|
||||||
Pixmap gray, blue, red;
|
struct color color[CWM_COLOR_MAX];
|
||||||
|
GC gc;
|
||||||
|
|
||||||
int altpersist;
|
int altpersist;
|
||||||
|
|
||||||
int maxinitialised;
|
|
||||||
int xmax;
|
int xmax;
|
||||||
int ymax;
|
int ymax;
|
||||||
|
|
||||||
FILE *notifier;
|
struct gap gap;
|
||||||
|
|
||||||
struct cycle_entry_q mruq;
|
struct cycle_entry_q mruq;
|
||||||
|
|
||||||
struct client_ctx* cycle_client;
|
|
||||||
|
|
||||||
struct fonthash fonthash;
|
|
||||||
XftDraw *xftdraw;
|
XftDraw *xftdraw;
|
||||||
XftColor xftcolor;
|
XftColor xftcolor;
|
||||||
|
XftFont *font;
|
||||||
|
u_int fontheight;
|
||||||
|
|
||||||
|
int xinerama_no;
|
||||||
|
XineramaScreenInfo *xinerama;
|
||||||
|
struct group_ctx *group_active;
|
||||||
|
struct group_ctx groups[CALMWM_NGROUPS];
|
||||||
|
int group_hideall;
|
||||||
|
struct group_ctx_q groupq;
|
||||||
|
char **group_names;
|
||||||
|
int group_nonames;
|
||||||
};
|
};
|
||||||
|
|
||||||
TAILQ_HEAD(screen_ctx_q, screen_ctx);
|
TAILQ_HEAD(screen_ctx_q, screen_ctx);
|
||||||
@@ -103,12 +134,15 @@ TAILQ_HEAD(screen_ctx_q, screen_ctx);
|
|||||||
|
|
||||||
#define CLIENT_HIDDEN 0x01
|
#define CLIENT_HIDDEN 0x01
|
||||||
#define CLIENT_IGNORE 0x02
|
#define CLIENT_IGNORE 0x02
|
||||||
#define CLIENT_INQUEUE 0x04 /* tmp used by search code */
|
#define CLIENT_DOMAXIMIZE 0x04
|
||||||
#define CLIENT_MAXIMIZED 0x08
|
#define CLIENT_MAXIMIZED 0x08
|
||||||
|
#define CLIENT_DOVMAXIMIZE 0x10
|
||||||
|
#define CLIENT_VMAXIMIZED 0x20
|
||||||
|
#define CLIENT_DOHMAXIMIZE 0x40
|
||||||
|
#define CLIENT_HMAXIMIZED 0x80
|
||||||
|
|
||||||
#define CLIENT_HIGHLIGHT_BLUE 1
|
#define CLIENT_HIGHLIGHT_GROUP 1
|
||||||
#define CLIENT_HIGHLIGHT_RED 2
|
#define CLIENT_HIGHLIGHT_UNGROUP 2
|
||||||
|
|
||||||
|
|
||||||
struct winname {
|
struct winname {
|
||||||
TAILQ_ENTRY(winname) entry;
|
TAILQ_ENTRY(winname) entry;
|
||||||
@@ -129,20 +163,17 @@ struct client_ctx {
|
|||||||
|
|
||||||
Colormap cmap;
|
Colormap cmap;
|
||||||
|
|
||||||
Window pwin;
|
|
||||||
|
|
||||||
u_int bwidth;
|
u_int bwidth;
|
||||||
struct {
|
struct {
|
||||||
int x, y, width, height;
|
int x, y, width, height, basew, baseh,
|
||||||
int min_dx, min_dy;
|
minw, minh, maxw, maxh, incw, inch;
|
||||||
|
float mina, maxa;
|
||||||
} geom, savegeom;
|
} geom, savegeom;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
int x,y;
|
int x,y;
|
||||||
} ptr;
|
} ptr;
|
||||||
|
|
||||||
int beepbeep;
|
|
||||||
|
|
||||||
int xproto;
|
int xproto;
|
||||||
|
|
||||||
int flags;
|
int flags;
|
||||||
@@ -157,7 +188,6 @@ struct client_ctx {
|
|||||||
|
|
||||||
char *matchname;
|
char *matchname;
|
||||||
struct group_ctx *group;
|
struct group_ctx *group;
|
||||||
int groupcommit;
|
|
||||||
|
|
||||||
int stackingorder;
|
int stackingorder;
|
||||||
|
|
||||||
@@ -166,107 +196,120 @@ struct client_ctx {
|
|||||||
char *app_cliarg;
|
char *app_cliarg;
|
||||||
};
|
};
|
||||||
|
|
||||||
TAILQ_HEAD(client_ctx_q, client_ctx);
|
extern const char *shortcut_to_name[];
|
||||||
|
|
||||||
struct group_ctx {
|
|
||||||
TAILQ_ENTRY(group_ctx) entry;
|
|
||||||
struct client_ctx_q clients;
|
|
||||||
char *name;
|
|
||||||
int shortcut;
|
|
||||||
int hidden;
|
|
||||||
int nhidden;
|
|
||||||
int highstack;
|
|
||||||
};
|
|
||||||
|
|
||||||
TAILQ_HEAD(group_ctx_q, group_ctx);
|
|
||||||
|
|
||||||
/* Autogroups */
|
/* Autogroups */
|
||||||
struct autogroupwin {
|
struct autogroupwin {
|
||||||
TAILQ_ENTRY(autogroupwin) entry;
|
TAILQ_ENTRY(autogroupwin) entry;
|
||||||
|
|
||||||
char *class;
|
char *class;
|
||||||
char *name;
|
char *name;
|
||||||
char *group;
|
int num;
|
||||||
};
|
};
|
||||||
|
|
||||||
TAILQ_HEAD(autogroupwin_q, autogroupwin);
|
TAILQ_HEAD(autogroupwin_q, autogroupwin);
|
||||||
|
|
||||||
/* NULL/0 values indicate match any. */
|
#define CWM_MOVE 0x01
|
||||||
struct xevent {
|
#define CWM_RESIZE 0x02
|
||||||
TAILQ_ENTRY(xevent) entry;
|
#define CWM_PTRMOVE 0x04
|
||||||
Window *xev_win;
|
#define CWM_BIGMOVE 0x08
|
||||||
Window *xev_root;
|
#define CWM_UP 0x10
|
||||||
int xev_type;
|
#define CWM_DOWN 0x20
|
||||||
void (*xev_cb)(struct xevent *, XEvent *);
|
#define CWM_LEFT 0x40
|
||||||
void *xev_arg;
|
#define CWM_RIGHT 0x80
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Match a window.
|
||||||
|
*/
|
||||||
|
#define CONF_MAX_WINTITLE 256
|
||||||
|
struct winmatch {
|
||||||
|
TAILQ_ENTRY(winmatch) entry;
|
||||||
|
char title[CONF_MAX_WINTITLE];
|
||||||
};
|
};
|
||||||
|
|
||||||
TAILQ_HEAD(xevent_q, xevent);
|
TAILQ_HEAD(winmatch_q, winmatch);
|
||||||
|
|
||||||
/* Keybindings */
|
|
||||||
enum kbtype {
|
|
||||||
KB_DELETE, KB_NEWTERM0, KB_NEWTERM1, KB_HIDE,
|
|
||||||
KB_LOWER, KB_RAISE, KB_SEARCH, KB_CYCLE, KB_LABEL,
|
|
||||||
KB_GROUPSELECT, KB_VERTMAXIMIZE, KB_MAXIMIZE,
|
|
||||||
|
|
||||||
/* Group numbers need to be in order. */
|
|
||||||
KB_GROUP_1, KB_GROUP_2, KB_GROUP_3, KB_GROUP_4, KB_GROUP_5,
|
|
||||||
KB_GROUP_6, KB_GROUP_7, KB_GROUP_8, KB_GROUP_9, KB_NOGROUP,
|
|
||||||
KB_NEXTGROUP, KB_PREVGROUP,
|
|
||||||
|
|
||||||
KB_MOVE_WEST, KB_MOVE_EAST, KB_MOVE_NORTH, KB_MOVE_SOUTH,
|
|
||||||
|
|
||||||
KB__LAST
|
|
||||||
};
|
|
||||||
|
|
||||||
#define CWM_BIGMOVE 0x1000
|
|
||||||
enum directions {
|
|
||||||
CWM_UP=0, CWM_DOWN, CWM_LEFT, CWM_RIGHT,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* for cwm_exec */
|
/* for cwm_exec */
|
||||||
#define CWM_EXEC_PROGRAM 0x1
|
#define CWM_EXEC_PROGRAM 0x1
|
||||||
#define CWM_EXEC_WM 0x2
|
#define CWM_EXEC_WM 0x2
|
||||||
|
/* for alt-tab */
|
||||||
|
#define CWM_CYCLE 0x0
|
||||||
|
#define CWM_RCYCLE 0x1
|
||||||
|
/* for group cycle */
|
||||||
|
#define CWM_CYCLEGROUP 0x0
|
||||||
|
#define CWM_RCYCLEGROUP 0x1
|
||||||
|
|
||||||
#define KBFLAG_NEEDCLIENT 0x01
|
#define KBFLAG_NEEDCLIENT 0x01
|
||||||
#define KBFLAG_FINDCLIENT 0x02
|
|
||||||
|
|
||||||
#define KBTOGROUP(X) ((X) - 1)
|
#define KBTOGROUP(X) ((X) - 1)
|
||||||
|
|
||||||
|
union arg {
|
||||||
|
char *c;
|
||||||
|
int i;
|
||||||
|
};
|
||||||
|
|
||||||
struct keybinding {
|
struct keybinding {
|
||||||
|
TAILQ_ENTRY(keybinding) entry;
|
||||||
|
void (*callback)(struct client_ctx *, union arg *);
|
||||||
|
union arg argument;
|
||||||
int modmask;
|
int modmask;
|
||||||
int keysym;
|
int keysym;
|
||||||
int keycode;
|
int keycode;
|
||||||
int flags;
|
int flags;
|
||||||
void (*callback)(struct client_ctx *, void *);
|
|
||||||
void *argument;
|
|
||||||
TAILQ_ENTRY(keybinding) entry;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct cmd {
|
struct cmd {
|
||||||
TAILQ_ENTRY(cmd) entry;
|
TAILQ_ENTRY(cmd) entry;
|
||||||
int flags;
|
int flags;
|
||||||
#define CMD_STATIC 0x01 /* static configuration in conf.c */
|
|
||||||
char image[MAXPATHLEN];
|
char image[MAXPATHLEN];
|
||||||
char label[256];
|
char label[256];
|
||||||
/* (argv) */
|
/* (argv) */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct mousebinding {
|
||||||
|
int modmask;
|
||||||
|
int button;
|
||||||
|
int context;
|
||||||
|
void (*callback)(struct client_ctx *, void *);
|
||||||
|
TAILQ_ENTRY(mousebinding) entry;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MOUSEBIND_CTX_ROOT 1
|
||||||
|
#define MOUSEBIND_CTX_WIN 2
|
||||||
|
|
||||||
TAILQ_HEAD(keybinding_q, keybinding);
|
TAILQ_HEAD(keybinding_q, keybinding);
|
||||||
TAILQ_HEAD(cmd_q, cmd);
|
TAILQ_HEAD(cmd_q, cmd);
|
||||||
|
TAILQ_HEAD(mousebinding_q, mousebinding);
|
||||||
|
|
||||||
/* Global configuration */
|
/* Global configuration */
|
||||||
struct conf {
|
struct conf {
|
||||||
struct keybinding_q keybindingq;
|
struct keybinding_q keybindingq;
|
||||||
struct autogroupwin_q autogroupq;
|
struct autogroupwin_q autogroupq;
|
||||||
char menu_path[MAXPATHLEN];
|
struct winmatch_q ignoreq;
|
||||||
|
char conf_path[MAXPATHLEN];
|
||||||
struct cmd_q cmdq;
|
struct cmd_q cmdq;
|
||||||
|
struct mousebinding_q mousebindingq;
|
||||||
|
|
||||||
int flags;
|
|
||||||
#define CONF_STICKY_GROUPS 0x0001
|
#define CONF_STICKY_GROUPS 0x0001
|
||||||
|
int flags;
|
||||||
|
#define CONF_BWIDTH 1
|
||||||
|
int bwidth;
|
||||||
|
#define CONF_MAMOUNT 1
|
||||||
|
int mamount;
|
||||||
|
struct gap gap;
|
||||||
|
|
||||||
|
#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 termpath[MAXPATHLEN];
|
||||||
char lockpath[MAXPATHLEN];
|
char lockpath[MAXPATHLEN];
|
||||||
|
|
||||||
|
#define DEFAULTFONTNAME "sans-serif:pixelsize=14:bold"
|
||||||
|
char *DefaultFontName;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Menu stuff */
|
/* Menu stuff */
|
||||||
@@ -281,6 +324,7 @@ struct menu {
|
|||||||
char print[MENU_MAXENTRY + 1];
|
char print[MENU_MAXENTRY + 1];
|
||||||
void *ctx;
|
void *ctx;
|
||||||
short dummy;
|
short dummy;
|
||||||
|
short abort;
|
||||||
};
|
};
|
||||||
|
|
||||||
TAILQ_HEAD(menu_q, menu);
|
TAILQ_HEAD(menu_q, menu);
|
||||||
@@ -306,20 +350,15 @@ struct mwm_hints {
|
|||||||
#define MWM_DECOR_ALL (1 << 0)
|
#define MWM_DECOR_ALL (1 << 0)
|
||||||
#define MWM_DECOR_BORDER (1 << 1)
|
#define MWM_DECOR_BORDER (1 << 1)
|
||||||
|
|
||||||
int input_keycodetrans(KeyCode, u_int, enum ctltype *, char *, int);
|
int input_keycodetrans(KeyCode, u_int, enum ctltype *,
|
||||||
|
char *);
|
||||||
|
|
||||||
int x_errorhandler(Display *, XErrorEvent *);
|
|
||||||
void x_setup(char *display_name);
|
|
||||||
char *x_screenname(int);
|
|
||||||
void x_setupscreen(struct screen_ctx *, u_int);
|
|
||||||
__dead void usage(void);
|
__dead void usage(void);
|
||||||
|
|
||||||
struct client_ctx *client_find(Window);
|
struct client_ctx *client_find(Window);
|
||||||
void client_setup(void);
|
|
||||||
struct client_ctx *client_new(Window, struct screen_ctx *, int);
|
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_setactive(struct client_ctx *, int);
|
||||||
void client_gravitate(struct client_ctx *, int);
|
|
||||||
void client_resize(struct client_ctx *);
|
void client_resize(struct client_ctx *);
|
||||||
void client_lower(struct client_ctx *);
|
void client_lower(struct client_ctx *);
|
||||||
void client_raise(struct client_ctx *);
|
void client_raise(struct client_ctx *);
|
||||||
@@ -329,182 +368,157 @@ void client_send_delete(struct client_ctx *);
|
|||||||
struct client_ctx *client_current(void);
|
struct client_ctx *client_current(void);
|
||||||
void client_hide(struct client_ctx *);
|
void client_hide(struct client_ctx *);
|
||||||
void client_unhide(struct client_ctx *);
|
void client_unhide(struct client_ctx *);
|
||||||
void client_nocurrent(void);
|
|
||||||
void client_setname(struct client_ctx *);
|
void client_setname(struct client_ctx *);
|
||||||
void client_warp(struct client_ctx *);
|
void client_warp(struct client_ctx *);
|
||||||
void client_ptrwarp(struct client_ctx *);
|
void client_ptrwarp(struct client_ctx *);
|
||||||
void client_ptrsave(struct client_ctx *);
|
void client_ptrsave(struct client_ctx *);
|
||||||
void client_draw_border(struct client_ctx *);
|
void client_draw_border(struct client_ctx *);
|
||||||
void client_update(struct client_ctx *);
|
|
||||||
void client_cycle(struct client_ctx *);
|
|
||||||
void client_placecalc(struct client_ctx *);
|
|
||||||
void client_maximize(struct client_ctx *);
|
void client_maximize(struct client_ctx *);
|
||||||
void client_vertmaximize(struct client_ctx *);
|
void client_vertmaximize(struct client_ctx *);
|
||||||
u_long client_bg_pixel(struct client_ctx *);
|
void client_horizmaximize(struct client_ctx *);
|
||||||
Pixmap client_bg_pixmap(struct client_ctx *);
|
void client_map(struct client_ctx *);
|
||||||
void client_map(struct client_ctx *cc);
|
void client_mtf(struct client_ctx *);
|
||||||
void client_mtf(struct client_ctx *cc);
|
struct client_ctx *client_cycle(struct screen_ctx *, int);
|
||||||
struct client_ctx *client_cyclenext(int reverse);
|
void client_getsizehints(struct client_ctx *);
|
||||||
void client_cycleinfo(struct client_ctx *cc);
|
void client_applysizehints(struct client_ctx *);
|
||||||
void client_altrelease();
|
|
||||||
struct client_ctx *client_mrunext(struct client_ctx *cc);
|
|
||||||
struct client_ctx *client_mruprev(struct client_ctx *cc);
|
|
||||||
void client_gethints(struct client_ctx *cc);
|
|
||||||
void client_freehints(struct client_ctx *cc);
|
|
||||||
|
|
||||||
void xev_handle_maprequest(struct xevent *, XEvent *);
|
struct menu *menu_filter(struct screen_ctx *, struct menu_q *,
|
||||||
void xev_handle_unmapnotify(struct xevent *, XEvent *);
|
char *, char *, int,
|
||||||
void xev_handle_destroynotify(struct xevent *, XEvent *);
|
void (*)(struct menu_q *, struct menu_q *, char *),
|
||||||
void xev_handle_configurerequest(struct xevent *, XEvent *);
|
void (*)(struct menu *, int));
|
||||||
void xev_handle_propertynotify(struct xevent *, XEvent *);
|
void menu_init(struct screen_ctx *);
|
||||||
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 *);
|
|
||||||
|
|
||||||
#define XEV_QUICK(a, b, c, d, e) do { \
|
/* XXX should be xu_ */
|
||||||
xev_register(xev_new(a, b, c, d, e)); \
|
void xev_reconfig(struct client_ctx *);
|
||||||
} while (0)
|
|
||||||
|
|
||||||
void xev_reconfig(struct client_ctx *); /* XXX should be xu_ */
|
|
||||||
|
|
||||||
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 xev_loop(void);
|
||||||
|
|
||||||
|
void xu_getatoms(void);
|
||||||
int xu_ptr_grab(Window, int, Cursor);
|
int xu_ptr_grab(Window, int, Cursor);
|
||||||
int xu_btn_grab(Window, int, u_int);
|
void xu_btn_grab(Window, int, u_int);
|
||||||
int xu_ptr_regrab(int, Cursor);
|
int xu_ptr_regrab(int, Cursor);
|
||||||
void xu_btn_ungrab(Window, int, u_int);
|
void xu_btn_ungrab(Window, int, u_int);
|
||||||
void xu_ptr_ungrab(void);
|
void xu_ptr_ungrab(void);
|
||||||
void xu_ptr_setpos(Window, int, int);
|
void xu_ptr_setpos(Window, int, int);
|
||||||
void xu_ptr_getpos(Window, int *, int *);
|
void xu_ptr_getpos(Window, int *, int *);
|
||||||
void xu_key_grab(Window, int, int);
|
void xu_key_grab(Window, int, int);
|
||||||
void xu_sendmsg(struct client_ctx *, Atom, long);
|
void xu_key_ungrab(Window, int, int);
|
||||||
int xu_getprop(struct client_ctx *, Atom, Atom, long, u_char **);
|
void xu_sendmsg(Window, Atom, long);
|
||||||
char *xu_getstrprop(struct client_ctx *, Atom atm);
|
int xu_getprop(Window, Atom, Atom, long, u_char **);
|
||||||
|
int xu_getstrprop(Window, Atom, char **);
|
||||||
void xu_setstate(struct client_ctx *, int);
|
void xu_setstate(struct client_ctx *, int);
|
||||||
int xu_getstate(struct client_ctx *, int *);
|
int xu_getstate(struct client_ctx *, int *);
|
||||||
void xu_key_grab_keycode(Window, int, int);
|
unsigned long xu_getcolor(struct screen_ctx *, char *);
|
||||||
|
void xu_freecolor(struct screen_ctx *, unsigned long);
|
||||||
|
void xu_setwmname(struct screen_ctx *);
|
||||||
|
|
||||||
int dirent_exists(char *);
|
|
||||||
int dirent_isdir(char *);
|
|
||||||
int dirent_islink(char *);
|
|
||||||
int u_spawn(char *);
|
int u_spawn(char *);
|
||||||
void exec_wm(char *);
|
void u_exec(char *);
|
||||||
|
|
||||||
void grab_sweep(struct client_ctx *);
|
|
||||||
void grab_drag(struct client_ctx *);
|
|
||||||
void grab_menuinit(struct screen_ctx *);
|
|
||||||
void *grab_menu(XButtonEvent *, struct menu_q *);
|
|
||||||
void grab_label(struct client_ctx *);
|
|
||||||
|
|
||||||
void xfree(void *);
|
void xfree(void *);
|
||||||
void *xmalloc(size_t);
|
void *xmalloc(size_t);
|
||||||
void *xcalloc(size_t);
|
void *xcalloc(size_t, size_t);
|
||||||
char *xstrdup(const char *);
|
char *xstrdup(const char *);
|
||||||
|
|
||||||
#define XMALLOC(p, t) ((p) = (t *)xmalloc(sizeof * (p)))
|
|
||||||
#define XCALLOC(p, t) ((p) = (t *)xcalloc(sizeof * (p)))
|
|
||||||
|
|
||||||
void screen_init(void);
|
|
||||||
struct screen_ctx *screen_fromroot(Window);
|
struct screen_ctx *screen_fromroot(Window);
|
||||||
struct screen_ctx *screen_current(void);
|
void screen_updatestackingorder(struct screen_ctx *);
|
||||||
void screen_updatestackingorder(void);
|
void screen_update_geometry(struct screen_ctx *, int, int);
|
||||||
void screen_infomsg(char *);
|
void screen_init_xinerama(struct screen_ctx *);
|
||||||
|
XineramaScreenInfo *screen_find_xinerama(struct screen_ctx *, int, int);
|
||||||
|
|
||||||
void conf_setup(struct conf *);
|
void conf_setup(struct conf *, const char *);
|
||||||
int conf_get_int(struct client_ctx *, enum conftype);
|
|
||||||
void conf_client(struct client_ctx *);
|
void conf_client(struct client_ctx *);
|
||||||
void conf_bindkey(struct conf *, void (*)(struct client_ctx *, void *),
|
void conf_grab(struct conf *, struct keybinding *);
|
||||||
int, int, int, void *);
|
void conf_ungrab(struct conf *, struct keybinding *);
|
||||||
void conf_bindname(struct conf *, char *, char *);
|
void conf_bindname(struct conf *, char *, char *);
|
||||||
void conf_unbind(struct conf *, struct keybinding *);
|
void conf_mousebind(struct conf *, char *, char *);
|
||||||
void conf_parsekeys(struct conf *, char *);
|
void conf_grab_mouse(struct client_ctx *);
|
||||||
void conf_parsesettings(struct conf *, char *);
|
void conf_reload(struct conf *);
|
||||||
void conf_parseignores(struct conf *, char *);
|
void conf_gap(struct conf *, struct screen_ctx *);
|
||||||
void conf_parseautogroups(struct conf *, char *);
|
void conf_font(struct conf *, struct screen_ctx *);
|
||||||
void conf_cmd_clear(struct conf *);
|
void conf_color(struct conf *, struct screen_ctx *);
|
||||||
int conf_cmd_changed(char *);
|
void conf_init(struct conf *);
|
||||||
void conf_cmd_populate(struct conf *, char *);
|
void conf_clear(struct conf *);
|
||||||
void conf_cmd_refresh(struct conf *c);
|
void conf_cmd_add(struct conf *, char *, char *, int);
|
||||||
char *conf_get_str(struct client_ctx *, enum conftype);
|
|
||||||
|
|
||||||
void kbfunc_client_lower(struct client_ctx *, void *);
|
int parse_config(const char *, struct conf *);
|
||||||
void kbfunc_client_raise(struct client_ctx *, void *);
|
|
||||||
void kbfunc_client_search(struct client_ctx *, void *);
|
|
||||||
void kbfunc_client_hide(struct client_ctx *, void *);
|
|
||||||
void kbfunc_client_cycle(struct client_ctx *, void *);
|
|
||||||
void kbfunc_client_rcycle(struct client_ctx *cc, void *arg);
|
|
||||||
void kbfunc_cmdexec(struct client_ctx *, void *);
|
|
||||||
void kbfunc_client_label(struct client_ctx *, void *);
|
|
||||||
void kbfunc_client_delete(struct client_ctx *, void *);
|
|
||||||
void kbfunc_client_groupselect(struct client_ctx *, void *);
|
|
||||||
void kbfunc_client_group(struct client_ctx *, void *);
|
|
||||||
void kbfunc_client_nextgroup(struct client_ctx *, void *);
|
|
||||||
void kbfunc_client_prevgroup(struct client_ctx *, void *);
|
|
||||||
void kbfunc_client_nogroup(struct client_ctx *, void *);
|
|
||||||
void kbfunc_client_maximize(struct client_ctx *, void *);
|
|
||||||
void kbfunc_client_vmaximize(struct client_ctx *, void *);
|
|
||||||
void kbfunc_client_move(struct client_ctx *, void *);
|
|
||||||
void kbfunc_client_resize(struct client_ctx *, void *);
|
|
||||||
void kbfunc_menu_search(struct client_ctx *, void *);
|
|
||||||
void kbfunc_exec(struct client_ctx *, void *);
|
|
||||||
void kbfunc_ptrmove(struct client_ctx *, void *);
|
|
||||||
void kbfunc_ssh(struct client_ctx *, void *);
|
|
||||||
void kbfunc_term(struct client_ctx *cc, void *arg);
|
|
||||||
void kbfunc_lock(struct client_ctx *cc, void *arg);
|
|
||||||
|
|
||||||
void search_init(struct screen_ctx *);
|
void kbfunc_client_lower(struct client_ctx *, union arg *);
|
||||||
struct menu *search_start(struct menu_q *menuq,
|
void kbfunc_client_raise(struct client_ctx *, union arg *);
|
||||||
void (*match)(struct menu_q *, struct menu_q *, char *),
|
void kbfunc_client_search(struct client_ctx *, union arg *);
|
||||||
void (*rank)(struct menu_q *, char *),
|
void kbfunc_client_hide(struct client_ctx *, union arg *);
|
||||||
void (*print)(struct menu *mi, int),
|
void kbfunc_client_cycle(struct client_ctx *, union arg *);
|
||||||
char *, int);
|
void kbfunc_client_rcycle(struct client_ctx *, union arg *);
|
||||||
void search_match_client(struct menu_q *, struct menu_q *, char *);
|
void kbfunc_cmdexec(struct client_ctx *, union arg *);
|
||||||
void search_print_client(struct menu *mi, int list);
|
void kbfunc_client_label(struct client_ctx *, union arg *);
|
||||||
void search_match_text(struct menu_q *, struct menu_q *, char *);
|
void kbfunc_client_delete(struct client_ctx *, union arg *);
|
||||||
void search_match_exec(struct menu_q *, struct menu_q *, char *);
|
void kbfunc_client_group(struct client_ctx *, union arg *);
|
||||||
void search_rank_text(struct menu_q *, char *);
|
void kbfunc_client_grouponly(struct client_ctx *,
|
||||||
|
union arg *);
|
||||||
|
void kbfunc_client_cyclegroup(struct client_ctx *,
|
||||||
|
union arg *);
|
||||||
|
void kbfunc_client_nogroup(struct client_ctx *,
|
||||||
|
union arg *);
|
||||||
|
void kbfunc_client_grouptoggle(struct client_ctx *,
|
||||||
|
union arg *);
|
||||||
|
void kbfunc_client_movetogroup(struct client_ctx *,
|
||||||
|
union arg *);
|
||||||
|
void kbfunc_client_maximize(struct client_ctx *,
|
||||||
|
union arg *);
|
||||||
|
void kbfunc_client_vmaximize(struct client_ctx *,
|
||||||
|
union arg *);
|
||||||
|
void kbfunc_client_hmaximize(struct client_ctx *,
|
||||||
|
union arg *);
|
||||||
|
void kbfunc_reload(struct client_ctx *, union arg *);
|
||||||
|
void kbfunc_quit_wm(struct client_ctx *, union arg *);
|
||||||
|
void kbfunc_moveresize(struct client_ctx *, union arg *);
|
||||||
|
void kbfunc_menu_search(struct client_ctx *, union arg *);
|
||||||
|
void kbfunc_exec(struct client_ctx *, union arg *);
|
||||||
|
void kbfunc_ssh(struct client_ctx *, union arg *);
|
||||||
|
void kbfunc_term(struct client_ctx *, union arg *);
|
||||||
|
void kbfunc_lock(struct client_ctx *, union arg *);
|
||||||
|
|
||||||
void group_init(void);
|
void mousefunc_window_resize(struct client_ctx *, void *);
|
||||||
void group_select(int);
|
void mousefunc_window_move(struct client_ctx *, void *);
|
||||||
void group_enter(void);
|
void mousefunc_window_grouptoggle(struct client_ctx *,
|
||||||
void group_exit(int);
|
void *);
|
||||||
void group_click(struct client_ctx *);
|
void mousefunc_window_lower(struct client_ctx *, void *);
|
||||||
void group_display_init(struct screen_ctx *);
|
void mousefunc_window_hide(struct client_ctx *, void *);
|
||||||
void group_display_draw(struct screen_ctx *);
|
void mousefunc_menu_group(struct client_ctx *, void *);
|
||||||
void group_display_keypress(KeyCode);
|
void mousefunc_menu_unhide(struct client_ctx *, void *);
|
||||||
void group_hidetoggle(int);
|
void mousefunc_menu_cmd(struct client_ctx *, void *);
|
||||||
void group_slide(int);
|
|
||||||
|
void search_match_client(struct menu_q *, struct menu_q *,
|
||||||
|
char *);
|
||||||
|
void search_print_client(struct menu *, int);
|
||||||
|
void search_match_text(struct menu_q *, struct menu_q *,
|
||||||
|
char *);
|
||||||
|
void search_match_exec(struct menu_q *, struct menu_q *,
|
||||||
|
char *);
|
||||||
|
|
||||||
|
void group_init(struct screen_ctx *);
|
||||||
|
void group_make_autogroup(struct conf *, char *, int);
|
||||||
|
void group_update_names(struct screen_ctx *);
|
||||||
|
void group_hidetoggle(struct screen_ctx *, int);
|
||||||
|
void group_only(struct screen_ctx *, int);
|
||||||
|
void group_cycle(struct screen_ctx *, int);
|
||||||
void group_sticky(struct client_ctx *);
|
void group_sticky(struct client_ctx *);
|
||||||
void group_client_delete(struct client_ctx *);
|
void group_client_delete(struct client_ctx *);
|
||||||
void group_menu(XButtonEvent *);
|
void group_menu(XButtonEvent *);
|
||||||
void group_namemode(void);
|
void group_alltoggle(struct screen_ctx *);
|
||||||
void group_alltoggle(void);
|
|
||||||
void group_deletecurrent(void);
|
|
||||||
void group_done(void);
|
|
||||||
void group_sticky_toggle_enter(struct client_ctx *);
|
void group_sticky_toggle_enter(struct client_ctx *);
|
||||||
void group_sticky_toggle_exit(struct client_ctx *);
|
void group_sticky_toggle_exit(struct client_ctx *);
|
||||||
void group_autogroup(struct client_ctx *);
|
void group_autogroup(struct client_ctx *);
|
||||||
|
void group_movetogroup(struct client_ctx *, int);
|
||||||
|
|
||||||
void notification_init(struct screen_ctx *);
|
int font_ascent(struct screen_ctx *);
|
||||||
|
int font_descent(struct screen_ctx *);
|
||||||
void font_init(struct screen_ctx *sc);
|
u_int font_height(struct screen_ctx *);
|
||||||
struct fontdesc *font_get(struct screen_ctx *sc, const char *name);
|
void font_init(struct screen_ctx *);
|
||||||
int font_width(struct fontdesc *fdp, const char *text, int len);
|
int font_width(struct screen_ctx *, const char *, int);
|
||||||
void font_draw(struct fontdesc *fdp, const char *text, int len,
|
void font_draw(struct screen_ctx *, const char *, int,
|
||||||
Drawable d, int x, int y);
|
Drawable, int, int);
|
||||||
int font_ascent(struct fontdesc *fdp);
|
XftFont *font_make(struct screen_ctx *, const char *);
|
||||||
int font_descent(struct fontdesc *fdp);
|
|
||||||
struct fontdesc *font_getx(struct screen_ctx *sc, const char *name);
|
|
||||||
|
|
||||||
#define CCTOSC(cc) (cc->sc)
|
|
||||||
|
|
||||||
/* Externs */
|
/* Externs */
|
||||||
|
|
||||||
@@ -518,15 +532,40 @@ extern Cursor Cursor_question;
|
|||||||
|
|
||||||
extern struct screen_ctx_q Screenq;
|
extern struct screen_ctx_q Screenq;
|
||||||
extern struct screen_ctx *curscreen;
|
extern struct screen_ctx *curscreen;
|
||||||
extern u_int Nscreens;
|
|
||||||
|
|
||||||
extern struct client_ctx_q Clientq;
|
extern struct client_ctx_q Clientq;
|
||||||
|
|
||||||
extern int Doshape, Shape_ev;
|
extern int HasXinerama, HasRandr, Randr_ev;
|
||||||
extern struct conf Conf;
|
extern struct conf Conf;
|
||||||
|
|
||||||
extern int Groupmode;
|
#define WM_STATE cwm_atoms[0]
|
||||||
extern struct fontdesc *DefaultFont;
|
#define WM_DELETE_WINDOW cwm_atoms[1]
|
||||||
|
#define WM_TAKE_FOCUS cwm_atoms[2]
|
||||||
|
#define WM_PROTOCOLS cwm_atoms[3]
|
||||||
|
#define _MOTIF_WM_HINTS cwm_atoms[4]
|
||||||
|
#define UTF8_STRING cwm_atoms[5]
|
||||||
|
/*
|
||||||
|
* please make all hints below this point netwm hints, starting with
|
||||||
|
* _NET_SUPPORTED. If you change other hints make sure you update
|
||||||
|
* CWM_NETWM_START
|
||||||
|
*/
|
||||||
|
#define _NET_SUPPORTED cwm_atoms[6]
|
||||||
|
#define _NET_SUPPORTING_WM_CHECK cwm_atoms[7]
|
||||||
|
#define _NET_WM_NAME cwm_atoms[8]
|
||||||
|
#define _NET_ACTIVE_WINDOW cwm_atoms[9]
|
||||||
|
#define _NET_CLIENT_LIST cwm_atoms[10]
|
||||||
|
#define _NET_NUMBER_OF_DESKTOPS cwm_atoms[11]
|
||||||
|
#define _NET_CURRENT_DESKTOP cwm_atoms[12]
|
||||||
|
#define _NET_DESKTOP_VIEWPORT cwm_atoms[13]
|
||||||
|
#define _NET_DESKTOP_GEOMETRY cwm_atoms[14]
|
||||||
|
#define _NET_VIRTUAL_ROOTS cwm_atoms[15]
|
||||||
|
#define _NET_SHOWING_DESKTOP cwm_atoms[16]
|
||||||
|
#define _NET_DESKTOP_NAMES cwm_atoms[17]
|
||||||
|
#define _NET_WM_DESKTOP cwm_atoms[18]
|
||||||
|
#define _NET_WORKAREA cwm_atoms[19]
|
||||||
|
#define CWM_NO_ATOMS 20
|
||||||
|
#define CWM_NETWM_START 6
|
||||||
|
|
||||||
|
extern Atom cwm_atoms[CWM_NO_ATOMS];
|
||||||
|
|
||||||
#endif /* _CALMWM_H_ */
|
#endif /* _CALMWM_H_ */
|
||||||
|
285
cwm.1
285
cwm.1
@@ -14,8 +14,7 @@
|
|||||||
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
.\"
|
.\"
|
||||||
.\" The following requests are required for all man pages.
|
.Dd $Mdocdate: August 24 2009 $
|
||||||
.Dd June 29, 2007
|
|
||||||
.Dt CWM 1
|
.Dt CWM 1
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@@ -24,9 +23,8 @@
|
|||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.\" For a program: program [-abc] file ...
|
.\" For a program: program [-abc] file ...
|
||||||
.Nm cwm
|
.Nm cwm
|
||||||
.Op Fl s
|
.Op Fl c Ar file
|
||||||
.Op Fl d Ar display
|
.Op Fl d Ar display
|
||||||
.Op Fl f Ar fontname
|
|
||||||
.Sh DESCRIPTION
|
.Sh DESCRIPTION
|
||||||
.Nm
|
.Nm
|
||||||
is a window manager for X11 which contains many features that
|
is a window manager for X11 which contains many features that
|
||||||
@@ -38,31 +36,31 @@ The following notation is used throughout this page:
|
|||||||
.Pp
|
.Pp
|
||||||
.Bl -tag -width Ds -offset indent -compact
|
.Bl -tag -width Ds -offset indent -compact
|
||||||
.It Ic C
|
.It Ic C
|
||||||
Control
|
Control.
|
||||||
.It Ic M
|
.It Ic M
|
||||||
Meta (Alt on PCs)
|
Meta.
|
||||||
.It Ic S
|
.It Ic S
|
||||||
Shift
|
Shift.
|
||||||
.It Ic M1
|
.It Ic M1
|
||||||
Left mouse button
|
Left mouse button.
|
||||||
.It Ic M2
|
.It Ic M2
|
||||||
Middle mouse button
|
Middle mouse button.
|
||||||
.It Ic M3
|
.It Ic M3
|
||||||
Right mouse button
|
Right mouse button.
|
||||||
.El
|
.El
|
||||||
.Pp
|
.Pp
|
||||||
.Nm
|
.Nm
|
||||||
is very simple in its use.
|
is very simple in its use.
|
||||||
Most of the actions are initiated via keybindings.
|
Most of the actions are initiated via key bindings.
|
||||||
The current keybindings are described below;
|
The current key bindings are described below;
|
||||||
their functionality is described in more detail later.
|
their functionality is described in more detail later.
|
||||||
.Pp
|
.Pp
|
||||||
.Bl -tag -width "C-M-EscapeXXX" -offset indent -compact
|
.Bl -tag -width "CM-EscapeXXXXX" -offset indent -compact
|
||||||
.It Ic C-M-Enter
|
.It Ic CM-Return
|
||||||
Spawn a new terminal.
|
Spawn a new terminal.
|
||||||
.It Ic C-M-Delete
|
.It Ic CM-Delete
|
||||||
Lock the screen.
|
Lock the screen.
|
||||||
.It Ic M-Enter
|
.It Ic M-Return
|
||||||
Hide current window.
|
Hide current window.
|
||||||
.It Ic M-Down
|
.It Ic M-Down
|
||||||
Lower current window.
|
Lower current window.
|
||||||
@@ -72,100 +70,111 @@ Raise current window.
|
|||||||
Search for windows.
|
Search for windows.
|
||||||
.It Ic C-/
|
.It Ic C-/
|
||||||
Search for applications.
|
Search for applications.
|
||||||
.It Ic C-M-n
|
.It Ic CM-n
|
||||||
Label current window.
|
Label current window.
|
||||||
.It Ic M-Tab
|
.It Ic M-Tab
|
||||||
Cycle through currently visible windows.
|
Cycle through currently visible windows.
|
||||||
.It Ic M-S-Tab
|
.It Ic MS-Tab
|
||||||
Reverse cycle through currently visible windows.
|
Reverse cycle through currently visible windows.
|
||||||
.It Ic C-M-x
|
.It Ic CM-x
|
||||||
Delete current window.
|
Delete current window.
|
||||||
.It Ic C-M-Escape
|
.It Ic CM-[n]
|
||||||
Enter group edit mode.
|
|
||||||
.It Ic C-M-[n]
|
|
||||||
Select group n, where n is 1-9.
|
Select group n, where n is 1-9.
|
||||||
.It Ic C-M-0
|
.It Ic CM-0
|
||||||
Select all groups.
|
Select all groups.
|
||||||
|
.It Ic CM-g
|
||||||
|
Toggle group membership of current window.
|
||||||
.It Ic M-Right
|
.It Ic M-Right
|
||||||
Switch to next group.
|
Cycle through active groups.
|
||||||
.It Ic M-Left
|
.It Ic M-Left
|
||||||
Switch to previous group.
|
Reverse cycle through active groups.
|
||||||
.It Ic C-M-f
|
.It Ic CM-f
|
||||||
Toggle full-screen size of window.
|
Toggle full-screen size of current window.
|
||||||
.It Ic C-M-=
|
.It Ic CM-=
|
||||||
Toggle vertical maximization of window.
|
Toggle vertical maximization of current window.
|
||||||
|
.It Ic CMS-=
|
||||||
|
Toggle horizontal maximization of current window.
|
||||||
.It Ic M-?
|
.It Ic M-?
|
||||||
Spawn
|
Spawn
|
||||||
.Dq Exec program
|
.Dq exec program
|
||||||
dialog.
|
dialog.
|
||||||
.It Ic M-.
|
.It Ic M-.
|
||||||
Spawn
|
Spawn
|
||||||
.Dq Ssh to
|
.Dq ssh to
|
||||||
dialog.
|
dialog.
|
||||||
This parses
|
This parses
|
||||||
.Pa $HOME/.ssh/known_hosts
|
.Pa $HOME/.ssh/known_hosts
|
||||||
to provide host auto-completion.
|
to provide host auto-completion.
|
||||||
.Xr ssh 1
|
.Xr ssh 1
|
||||||
will be executed via the configured terminal emulator.
|
will be executed via the configured terminal emulator.
|
||||||
.It Ic C-M-q
|
.It Ic CM-w
|
||||||
Spawn
|
Spawn
|
||||||
.Dq Exec WindowManager
|
.Dq exec WindowManager
|
||||||
dialog; allows you to switch from
|
dialog; allows you to switch from
|
||||||
.Nm
|
.Nm
|
||||||
to another window manager without restarting the X server.
|
to another window manager without restarting the X server.
|
||||||
|
.It Ic CMS-r
|
||||||
|
Reload configuration.
|
||||||
|
.It Ic CMS-q
|
||||||
|
Quit
|
||||||
|
.Nm .
|
||||||
.El
|
.El
|
||||||
.Pp
|
.Pp
|
||||||
The mouse bindings are also important, they are:
|
The mouse bindings are also important, they are:
|
||||||
.Pp
|
.Pp
|
||||||
.Bl -tag -width Ds -offset indent -compact
|
.Bl -tag -width Ds -offset indent -compact
|
||||||
.It M-M1
|
.It Ic M-M1
|
||||||
Move a window.
|
Move current window.
|
||||||
.It C-M-M1
|
.It Ic CM-M1
|
||||||
Toggle a window's membership in the current group.
|
Toggle group membership of current window.
|
||||||
A blue highlight indicates the window has been added to the group;
|
.It Ic M-M2
|
||||||
a red highlight indicates it has been removed.
|
Resize current window
|
||||||
.It M-M2
|
.It Ic M-M3
|
||||||
Resize a window/select a window.
|
Lower current window.
|
||||||
.It M-M3
|
.It Ic CMS-M3
|
||||||
Lower a window.
|
Hide current window.
|
||||||
.El
|
.El
|
||||||
.Pp
|
.Pp
|
||||||
The options for
|
The options for
|
||||||
.Nm
|
.Nm
|
||||||
are as follows:
|
are as follows:
|
||||||
.Bl -tag -width Ds
|
.Bl -tag -width Ds
|
||||||
|
.It Fl c Ar file
|
||||||
|
Specify the config file to use. Defaults to
|
||||||
|
.Pa ~/.cwmrc .
|
||||||
.It Fl d Ar display
|
.It Fl d Ar display
|
||||||
Specify the display to use.
|
Specify the display to use.
|
||||||
.It Fl f Ar fontname
|
|
||||||
Makes the
|
|
||||||
.Xr Xft 3
|
|
||||||
font string
|
|
||||||
.Ar fontname
|
|
||||||
the default font.
|
|
||||||
.It Fl s
|
|
||||||
Set sticky group mode on.
|
|
||||||
The default behavior for new windows is to not assign any group.
|
|
||||||
This changes the default behavior to assigning the currrently selected
|
|
||||||
group to any newly created windows.
|
|
||||||
.El
|
.El
|
||||||
.Sh POINTER MOVEMENT
|
.Sh POINTER MOVEMENT
|
||||||
The pointer can be moved with the use of the keyboard through bindings.
|
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
|
.Ic C-[Up|Down|Left|Right]
|
||||||
C-shift-[UP|DOWN|LEFT|RIGHT] moves the pointer a larger amount.
|
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,
|
For example, to move the pointer to the left by a small amount,
|
||||||
press C-LEFT.
|
press
|
||||||
To move the pointer down by a larger amount, press C-shift-DOWN.
|
.Ic C-Left .
|
||||||
|
To move the pointer down by a larger amount, press
|
||||||
|
.Ic CS-Down .
|
||||||
.Sh WINDOW MOVEMENT AND RESIZING
|
.Sh WINDOW MOVEMENT AND RESIZING
|
||||||
.Nm
|
.Nm
|
||||||
windows can be moved with the use of the keyboard through Vi-like bindings.
|
windows can be moved with the use of the keyboard through
|
||||||
M-[hjkl] moves the current window a small amount, while M-shift-[hjkl] moves
|
.Cm vi Ns -like
|
||||||
the current window a larger amount.
|
bindings.
|
||||||
For example, to move the current window to the left a small amount, press M-h.
|
.Ic M-[hjkl]
|
||||||
To move the current window down by a larger amount, press M-shift-j.
|
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
|
.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.
|
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.
|
resizes by a larger increment.
|
||||||
.Sh SEARCH
|
.Sh SEARCH
|
||||||
.Nm
|
.Nm
|
||||||
@@ -179,26 +188,28 @@ keeps a history of the 5 previous titles of a window.
|
|||||||
When searching, the leftmost character of the result list may show a
|
When searching, the leftmost character of the result list may show a
|
||||||
flag:
|
flag:
|
||||||
.Pp
|
.Pp
|
||||||
.Bl -tag -width 10n -offset -indent -compact
|
.Bl -tag -width 10n -offset indent -compact
|
||||||
.It !
|
.It !
|
||||||
The window is the currently focused window.
|
The window is the currently focused window.
|
||||||
.It &
|
.It &
|
||||||
The window is hidden.
|
The window is hidden.
|
||||||
.El
|
.El
|
||||||
.Pp
|
.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
|
.Pp
|
||||||
.Bl -tag -width "[Down] or C-sXXX" -offset indent -compact
|
.Bl -tag -width "[Down] or C-s or M-j" -offset indent -compact
|
||||||
.It Ic [Down] No or Ic C-s
|
.It Ic [Down], C-s No or Ic M-j
|
||||||
Select the next window in the list.
|
Select the next window in the list.
|
||||||
.It Ic [Up] No or Ic C-r
|
.It Ic [Up], C-r No or Ic M-k
|
||||||
Select the previous window in the list.
|
Select the previous window in the list.
|
||||||
|
.It Ic [Backspace] No or Ic C-h
|
||||||
|
Backspace.
|
||||||
.It Ic C-u
|
.It Ic C-u
|
||||||
Clear the input.
|
Clear the input.
|
||||||
.It Ic [Enter]
|
.It Ic [Return]
|
||||||
Focus the selected window.
|
Focus the selected window.
|
||||||
.It Ic [Esc]
|
.It Ic [Esc]
|
||||||
Quit.
|
Cancel.
|
||||||
.It Ic C-a
|
.It Ic C-a
|
||||||
Whenever there are no matching windows, list every window.
|
Whenever there are no matching windows, list every window.
|
||||||
.El
|
.El
|
||||||
@@ -209,27 +220,26 @@ perform operations on the entire group instead of just one window.
|
|||||||
Currently, the only operation that is supported is to hide and unhide
|
Currently, the only operation that is supported is to hide and unhide
|
||||||
the grouped windows.
|
the grouped windows.
|
||||||
Together with the
|
Together with the
|
||||||
.Fl s
|
.Pa sticky
|
||||||
option, this can be used to emulate virtual desktops.
|
option, this can be used to emulate virtual desktops.
|
||||||
.Pp
|
.Pp
|
||||||
To edit groups, enter the group edit mode, and select/unselect the
|
To edit groups, use the group selection commands to toggle membership
|
||||||
groups with the group selection mouse click.
|
of a group.
|
||||||
A blue border will be shown on the currently selected windows.
|
A blue border will be shown briefly on windows added to the current group,
|
||||||
The group selection keyboard shortcuts can also be used to change
|
and a red border will be shown on those just removed.
|
||||||
which group to edit.
|
|
||||||
.Sh MENUS
|
.Sh MENUS
|
||||||
Menus are recalled by clicking the mouse on the root window:
|
Menus are recalled by clicking the mouse on the root window:
|
||||||
.Pp
|
.Pp
|
||||||
.Bl -tag -width 10n -offset -indent -compact
|
.Bl -tag -width 10n -offset indent -compact
|
||||||
.It M1
|
.It Ic M1
|
||||||
Show list of currently hidden windows.
|
Show list of currently hidden windows.
|
||||||
Clicking on an item will unhide that window.
|
Clicking on an item will unhide that window.
|
||||||
.It M2
|
.It Ic M2
|
||||||
Show list of currently defined groups.
|
Show list of currently defined groups.
|
||||||
Clicking on an item will hide/unhide that group.
|
Clicking on an item will hide/unhide that group.
|
||||||
.It M3
|
.It Ic M3
|
||||||
Show list of applications as defined in
|
Show list of applications as defined in
|
||||||
.Pa ~/.calmwm .
|
.Pa ~/.cwmrc .
|
||||||
Clicking on an item will spawn that application.
|
Clicking on an item will spawn that application.
|
||||||
.El
|
.El
|
||||||
.Sh ENVIRONMENT
|
.Sh ENVIRONMENT
|
||||||
@@ -242,111 +252,10 @@ option is given.
|
|||||||
.El
|
.El
|
||||||
.Sh FILES
|
.Sh FILES
|
||||||
.Bl -tag -width Ds
|
.Bl -tag -width Ds
|
||||||
.It Pa ~/.calmwm
|
.It Pa ~/.cwmrc
|
||||||
Any directory entries here are shown in the application menu.
|
|
||||||
When it is selected, the image is executed with
|
|
||||||
.Xr execve 2 .
|
|
||||||
One use of this is to create symbolic links for your favorite
|
|
||||||
applications in this directory using
|
|
||||||
.Xr ln 1 .
|
|
||||||
.Pp
|
|
||||||
The entries
|
|
||||||
.Nm term
|
|
||||||
and
|
|
||||||
.Nm lock
|
|
||||||
have a special meaning.
|
|
||||||
When they exist they point to the terminal program and screen locking
|
|
||||||
programs used by the keybindings specified above.
|
|
||||||
The defaults for these are
|
|
||||||
.Xr xterm 1
|
|
||||||
and
|
|
||||||
.Xr xlock 1 ,
|
|
||||||
respectively.
|
|
||||||
.It Pa ~/.calmwm/.autogroup
|
|
||||||
Symlinks in this directory are read upon startup and control the
|
|
||||||
automatic grouping feature, which is based on the window name and class
|
|
||||||
properties.
|
|
||||||
To obtain the name and class of a window, use
|
|
||||||
.Ql xprop WM_CLASS ,
|
|
||||||
then click on the window.
|
|
||||||
The first quoted string is the window name; the second one is the
|
|
||||||
window class.
|
|
||||||
.Pp
|
|
||||||
The name of a link can be the window class, or the window class and name
|
|
||||||
separated by a comma.
|
|
||||||
The link target is a group name (one, two, \&..., nine).
|
|
||||||
For example, to make all windows in the
|
|
||||||
.Xr xterm 1
|
|
||||||
class go to the third group:
|
|
||||||
.Bd -literal -offset indent
|
|
||||||
$ ln -s three ~/.calmwm/.autogroup/XTerm
|
|
||||||
.Ed
|
|
||||||
.It Pa ~/.calmwm/.settings
|
|
||||||
Files in this directory cause various configuration options to be
|
|
||||||
set or unset.
|
|
||||||
Currently the only setting availiable is whether or not sticky groups
|
|
||||||
are activated.
|
|
||||||
To activate sticky groups create a file in this directory with the name
|
|
||||||
``sticky''.
|
|
||||||
.It Pa ~/.calmwm/.ignore
|
|
||||||
Any files in this directory cause
|
|
||||||
.Nm
|
|
||||||
to ignore programs by that name by not drawing borders around them.
|
|
||||||
For example the command
|
|
||||||
.Bd -literal -offset indent
|
|
||||||
$ ln -s three ~/.calmwm/.ignore/xclock
|
|
||||||
.Ed
|
|
||||||
will cause any instances of
|
|
||||||
.Xr xclock 1
|
|
||||||
to not have borders.
|
|
||||||
.It Pa ~/.calmwm/.keys
|
|
||||||
Symlinks in this directory cause the creation of keyboard shortcuts.
|
|
||||||
The default shortcuts will always be created. In case of conflict,
|
|
||||||
user-defined shortcuts take precidence.
|
|
||||||
The name of a link here is first the modifier keys, followed by a ``-''.
|
|
||||||
The following modifiers are recognised:
|
|
||||||
.Bl -tag -width Ds
|
|
||||||
.It Pa C
|
|
||||||
The Control key.
|
|
||||||
.It Pa M
|
|
||||||
The Meta key.
|
|
||||||
.It Pa S
|
|
||||||
The Shift key.
|
|
||||||
.It Pa 2
|
|
||||||
The Mod2 key.
|
|
||||||
.It Pa 3
|
|
||||||
The Mod3 key.
|
|
||||||
.It Pa 4
|
|
||||||
The Mod4 key (normally the windows key).
|
|
||||||
.El
|
|
||||||
The ``-'' should be followed by either a keysym name, taken from
|
|
||||||
.Pa /usr/X11R6/include/X11/keysymdef.h ,
|
|
||||||
or a numerical keycode value enclosed in ``[]''.
|
|
||||||
The target of the link should be either the name of a task from the
|
|
||||||
``name_to_kbfunc''
|
|
||||||
structure in
|
|
||||||
.Pa conf.c ,
|
|
||||||
or, alternatively it should be the commandline that is wished to be executed.
|
|
||||||
A special case is the ``unmap'' keyword, which causes any bindings using the
|
|
||||||
named shortcut to be removed. This can be used to remove a binding which conflicts
|
|
||||||
with an application.
|
|
||||||
For example, to cause
|
|
||||||
.Ic C-M-r
|
|
||||||
to add a label to a window:
|
|
||||||
.Bd -literal -offset indent
|
|
||||||
$ ln -s "label" ~/.calmwm/.keys/CM-r
|
|
||||||
.Ed
|
|
||||||
Launch an xterm running
|
|
||||||
.Xr top 1
|
|
||||||
with C-S-Enter:
|
|
||||||
.Bd -literal -offset indent
|
|
||||||
$ ln -s "/usr/X11R6/bin/xterm -e top" ~/.calmwm/.keys/CS-Return
|
|
||||||
.Ed
|
|
||||||
Remove a keybinding for Mod4-o
|
|
||||||
.Bd -literal -offset indent
|
|
||||||
$ ln -s "unmap" 4-o
|
|
||||||
.Ed
|
|
||||||
.El
|
.El
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr cwmrc 5
|
||||||
.Sh AUTHORS
|
.Sh AUTHORS
|
||||||
.An -nosplit
|
.An -nosplit
|
||||||
.Pp
|
.Pp
|
||||||
@@ -357,7 +266,7 @@ with contributions from
|
|||||||
.An Andy Adamson Aq dros@monkey.org ,
|
.An Andy Adamson Aq dros@monkey.org ,
|
||||||
.An Niels Provos Aq provos@monkey.org ,
|
.An Niels Provos Aq provos@monkey.org ,
|
||||||
and
|
and
|
||||||
.An Antti Nyk<EFBFBD>nen Aq aon@iki.fi .
|
.An Antti Nyk\(:anen Aq aon@iki.fi .
|
||||||
Ideas, discussion with many others.
|
Ideas, discussion with many others.
|
||||||
.Sh HISTORY
|
.Sh HISTORY
|
||||||
.Nm
|
.Nm
|
||||||
|
425
cwmrc.5
Normal file
425
cwmrc.5
Normal file
@@ -0,0 +1,425 @@
|
|||||||
|
.\" $OpenBSD$
|
||||||
|
.\"
|
||||||
|
.\" Copyright (c) 2004,2005 Marius Aamodt Eriksen <marius@monkey.org>
|
||||||
|
.\"
|
||||||
|
.\" Permission to use, copy, modify, and distribute this software for any
|
||||||
|
.\" purpose with or without fee is hereby granted, provided that the above
|
||||||
|
.\" copyright notice and this permission notice appear in all copies.
|
||||||
|
.\"
|
||||||
|
.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
.\"
|
||||||
|
.Dd $Mdocdate: September 25 2010 $
|
||||||
|
.Dt CWMRC 5
|
||||||
|
.Os
|
||||||
|
.Sh NAME
|
||||||
|
.Nm cwmrc
|
||||||
|
.Nd calm window manager configuration file
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
This manual page describes the
|
||||||
|
.Xr cwm 1
|
||||||
|
configuration file.
|
||||||
|
The following options are accepted in the configuration file:
|
||||||
|
.Pp
|
||||||
|
.Bl -tag -width Ds -compact
|
||||||
|
.It Ic autogroup Ar group windowname
|
||||||
|
.It Ic autogroup Ar group windowname,windowclass
|
||||||
|
Control automatic window grouping, based on the name and/or class
|
||||||
|
properties, where
|
||||||
|
.Ar group
|
||||||
|
is a number between 0 and 9.
|
||||||
|
If the group number is 0, then the window will not be grouped; this to
|
||||||
|
allow for
|
||||||
|
.Dq sticky
|
||||||
|
windows in sticky group mode.
|
||||||
|
.Pp
|
||||||
|
The name and class of a window may be obtained using
|
||||||
|
.Xr xprop 1 .
|
||||||
|
.Pp
|
||||||
|
.It Ic bind Ar keys command
|
||||||
|
Cause the creation of a keybinding, or replacement of a default
|
||||||
|
keybinding.
|
||||||
|
The modifier keys come first, followed by a
|
||||||
|
.Sq - .
|
||||||
|
.Pp
|
||||||
|
The following modifiers are recognised:
|
||||||
|
.Pp
|
||||||
|
.Bl -tag -width Ds -offset indent -compact
|
||||||
|
.It C
|
||||||
|
The Control key.
|
||||||
|
.It M
|
||||||
|
The Meta key.
|
||||||
|
.It S
|
||||||
|
The Shift key.
|
||||||
|
.It 4
|
||||||
|
The Mod4 key (normally the windows key).
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Sq -
|
||||||
|
should be followed by either a keysym name, taken from
|
||||||
|
.Pa /usr/X11R6/include/X11/keysymdef.h ,
|
||||||
|
or a numerical keycode value enclosed in
|
||||||
|
.Dq [] .
|
||||||
|
The
|
||||||
|
.Ar command
|
||||||
|
may either be one from the
|
||||||
|
.Sx BIND COMMAND LIST
|
||||||
|
(see below) or the command line that is to be executed.
|
||||||
|
.Pp
|
||||||
|
A special
|
||||||
|
.Ar command
|
||||||
|
keyword
|
||||||
|
.Dq unmap
|
||||||
|
can be used to remove the named keybinding.
|
||||||
|
This can be used to remove a binding which conflicts with an
|
||||||
|
application.
|
||||||
|
.Pp
|
||||||
|
.It Ic borderwidth Ar pixels
|
||||||
|
Set the window border width to
|
||||||
|
.Ar pixels .
|
||||||
|
.Pp
|
||||||
|
.It Ic color activeborder Ar color
|
||||||
|
Set the color of the active border.
|
||||||
|
.Pp
|
||||||
|
.It Ic color groupborder Ar color
|
||||||
|
Set the color of the border while grouping a window.
|
||||||
|
.Pp
|
||||||
|
.It Ic color inactiveborder Ar color
|
||||||
|
Set the color of the inactive border.
|
||||||
|
.Pp
|
||||||
|
.It Ic color ungroupborder Ar color
|
||||||
|
Set the color of the border while ungrouping a window.
|
||||||
|
.Pp
|
||||||
|
.It Ic command Ar name path
|
||||||
|
Every
|
||||||
|
.Ar name
|
||||||
|
entry is shown in the application menu.
|
||||||
|
When selected, the defined
|
||||||
|
.Ar path
|
||||||
|
is executed with
|
||||||
|
.Xr execve 2 .
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Ar name
|
||||||
|
entries
|
||||||
|
.Nm term
|
||||||
|
and
|
||||||
|
.Nm lock
|
||||||
|
have a special meaning.
|
||||||
|
They point to the terminal and screen locking programs specified by
|
||||||
|
keybindings.
|
||||||
|
The defaults are
|
||||||
|
.Xr xterm 1
|
||||||
|
and
|
||||||
|
.Xr xlock 1 ,
|
||||||
|
respectively.
|
||||||
|
.Pp
|
||||||
|
.It Ic fontname Ar font
|
||||||
|
Change the default
|
||||||
|
.Ar font
|
||||||
|
for
|
||||||
|
.Xr Xft 3 .
|
||||||
|
.Pp
|
||||||
|
.It Ic gap Ar top bottom left right
|
||||||
|
Define a
|
||||||
|
.Dq gap
|
||||||
|
in pixels at the edge of the screen, so that when a
|
||||||
|
window is maximized it will not overlap this area.
|
||||||
|
This
|
||||||
|
.Dq gap
|
||||||
|
can be used for applications such as
|
||||||
|
.Xr xclock 1 ,
|
||||||
|
where the user may wish to remain visible.
|
||||||
|
.Pp
|
||||||
|
.It Ic ignore Ar windowname
|
||||||
|
Ignore, and do not warp to, windows with the name
|
||||||
|
.Ar windowname
|
||||||
|
when drawing borders and cycling through windows.
|
||||||
|
.Pp
|
||||||
|
.It Ic mousebind Ar buttons command
|
||||||
|
Cause the creation of a mouse binding, or replacement of a default
|
||||||
|
mouse binding.
|
||||||
|
The modifier keys come first, followed by a
|
||||||
|
.Sq - .
|
||||||
|
.Pp
|
||||||
|
The following modifiers are recognised:
|
||||||
|
.Pp
|
||||||
|
.Bl -tag -width Ds -offset indent -compact
|
||||||
|
.It C
|
||||||
|
The Control key.
|
||||||
|
.It M
|
||||||
|
The Meta key.
|
||||||
|
.It S
|
||||||
|
The Shift key.
|
||||||
|
.It 4
|
||||||
|
The Mod4 key (normally the windows key).
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Sq -
|
||||||
|
should be followed by number:
|
||||||
|
.Pp
|
||||||
|
.Bl -tag -width Ds -offset indent -compact
|
||||||
|
.It 1
|
||||||
|
Left mouse button.
|
||||||
|
.It 2
|
||||||
|
Middle mouse button.
|
||||||
|
.It 3
|
||||||
|
Right mouse button.
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Ar command
|
||||||
|
may be taken from the
|
||||||
|
.Sx MOUSEBIND COMMAND LIST
|
||||||
|
(see below).
|
||||||
|
.Pp
|
||||||
|
.It Ic moveamount Ar pixels
|
||||||
|
Set a default size for the keyboard movement bindings,
|
||||||
|
in pixels.
|
||||||
|
The default is 1.
|
||||||
|
.Pp
|
||||||
|
.It Ic sticky Ic yes Ns \&| Ns Ic no
|
||||||
|
Toggle sticky group mode.
|
||||||
|
The default behavior for new windows is to not assign any group.
|
||||||
|
By enabling sticky group mode,
|
||||||
|
.Xr cwm 1
|
||||||
|
will assign new windows to the currently selected group.
|
||||||
|
.El
|
||||||
|
.Sh EXAMPLE CONFIGURATION
|
||||||
|
.Bd -literal
|
||||||
|
# Set default Xft(3) font
|
||||||
|
fontname "sans-serif:pixelsize=14:bold"
|
||||||
|
|
||||||
|
# Turn on sticky-group mode
|
||||||
|
sticky yes
|
||||||
|
|
||||||
|
# Any entry here is shown in the application menu
|
||||||
|
command firefox firefox
|
||||||
|
command xmms xmms
|
||||||
|
command top "xterm -e top"
|
||||||
|
|
||||||
|
# Autogroup definitions
|
||||||
|
autogroup 3 "aterm,XTerm"
|
||||||
|
autogroup 3 "xterm,XTerm"
|
||||||
|
|
||||||
|
# Ignore programs by that name by not drawing borders around them.
|
||||||
|
ignore XMMS
|
||||||
|
ignore xwi
|
||||||
|
ignore xapm
|
||||||
|
ignore xclock
|
||||||
|
|
||||||
|
# Keybindings
|
||||||
|
bind CM-r label
|
||||||
|
bind CS-Return "xterm -e top"
|
||||||
|
bind 4-o unmap
|
||||||
|
bind M-1 grouponly1
|
||||||
|
bind M-2 grouponly2
|
||||||
|
bind M-3 grouponly3
|
||||||
|
bind MS-1 movetogroup1
|
||||||
|
bind MS-2 movetogroup2
|
||||||
|
bind MS-3 movetogroup3
|
||||||
|
|
||||||
|
# Mousebindings
|
||||||
|
mousebind M-2 window_lower
|
||||||
|
mousebind M-3 window_resize
|
||||||
|
.Ed
|
||||||
|
.Sh BIND COMMAND LIST
|
||||||
|
.Bl -tag -width 18n -compact
|
||||||
|
.It reload
|
||||||
|
Reload configuration.
|
||||||
|
.It quit
|
||||||
|
Quit
|
||||||
|
.Xr cwm 1 .
|
||||||
|
.It terminal
|
||||||
|
Spawn a new terminal.
|
||||||
|
.It lock
|
||||||
|
Lock the screen.
|
||||||
|
.It search
|
||||||
|
Launch window search menu.
|
||||||
|
.It menusearch
|
||||||
|
Launch application search menu.
|
||||||
|
.It exec
|
||||||
|
Launch
|
||||||
|
.Dq exec program
|
||||||
|
menu.
|
||||||
|
.It exec_wm
|
||||||
|
Launch
|
||||||
|
.Dq exec WindowManager
|
||||||
|
menu.
|
||||||
|
.It ssh
|
||||||
|
Launch
|
||||||
|
.Dq ssh
|
||||||
|
menu.
|
||||||
|
.It group[n]
|
||||||
|
Select group n, where n is 1-9.
|
||||||
|
.It grouponly[n]
|
||||||
|
Like
|
||||||
|
.Ar group[n]
|
||||||
|
but also hides the other groups.
|
||||||
|
.It nogroup
|
||||||
|
Select all groups.
|
||||||
|
.It grouptoggle
|
||||||
|
Toggle group membership of current window.
|
||||||
|
.It movetogroup[n]
|
||||||
|
Hide current window from display and move to group n, where n is 1-9.
|
||||||
|
.It cyclegroup
|
||||||
|
Forward cycle through groups.
|
||||||
|
.It rcyclegroup
|
||||||
|
Reverse cycle through groups.
|
||||||
|
.It cycle
|
||||||
|
Forward cycle through windows.
|
||||||
|
.It rcycle
|
||||||
|
Reverse cycle through windows.
|
||||||
|
.It delete
|
||||||
|
Delete current window.
|
||||||
|
.It hide
|
||||||
|
Hide current window.
|
||||||
|
.It lower
|
||||||
|
Lower current window.
|
||||||
|
.It raise
|
||||||
|
Raise current window.
|
||||||
|
.It label
|
||||||
|
Label current window.
|
||||||
|
.It maximize
|
||||||
|
Maximize current window full-screen.
|
||||||
|
.It vmaximize
|
||||||
|
Maximize current window vertically.
|
||||||
|
.It hmaximize
|
||||||
|
Maximize current window horizontally.
|
||||||
|
.It moveup
|
||||||
|
Move window
|
||||||
|
.Ar moveamount
|
||||||
|
pixels up.
|
||||||
|
.It movedown
|
||||||
|
Move window
|
||||||
|
.Ar moveamount
|
||||||
|
pixels down.
|
||||||
|
.It moveright
|
||||||
|
Move window
|
||||||
|
.Ar moveamount
|
||||||
|
pixels right.
|
||||||
|
.It moveleft
|
||||||
|
Move window
|
||||||
|
.Ar moveamount
|
||||||
|
pixels left.
|
||||||
|
.It bigmoveup
|
||||||
|
Move window 10 times
|
||||||
|
.Ar moveamount
|
||||||
|
pixels up.
|
||||||
|
.It bigmovedown
|
||||||
|
Move window 10 times
|
||||||
|
.Ar moveamount
|
||||||
|
pixels down.
|
||||||
|
.It bigmoveright
|
||||||
|
Move window 10 times
|
||||||
|
.Ar moveamount
|
||||||
|
pixels right.
|
||||||
|
.It bigmoveleft
|
||||||
|
Move window 10 times
|
||||||
|
.Ar moveamount
|
||||||
|
pixels left.
|
||||||
|
.It resizeup
|
||||||
|
Resize window
|
||||||
|
.Ar moveamount
|
||||||
|
pixels up.
|
||||||
|
.It resizedown
|
||||||
|
Resize window
|
||||||
|
.Ar moveamount
|
||||||
|
pixels down.
|
||||||
|
.It resizeright
|
||||||
|
Resize window
|
||||||
|
.Ar moveamount
|
||||||
|
pixels right.
|
||||||
|
.It resizeleft
|
||||||
|
Resize window
|
||||||
|
.Ar moveamount
|
||||||
|
pixels left.
|
||||||
|
.It bigresizeup
|
||||||
|
Resize window 10 times
|
||||||
|
.Ar moveamount
|
||||||
|
pixels up.
|
||||||
|
.It bigresizedown
|
||||||
|
Resize window 10 times
|
||||||
|
.Ar moveamount
|
||||||
|
pixels down.
|
||||||
|
.It bigresizeright
|
||||||
|
Resize window 10 times
|
||||||
|
.Ar moveamount
|
||||||
|
pixels right.
|
||||||
|
.It bigresizeleft
|
||||||
|
Resize window 10 times
|
||||||
|
.Ar moveamount
|
||||||
|
pixels left.
|
||||||
|
.It ptrmoveup
|
||||||
|
Move pointer
|
||||||
|
.Ar moveamount
|
||||||
|
pixels up.
|
||||||
|
.It ptrmovedown
|
||||||
|
Move pointer
|
||||||
|
.Ar moveamount
|
||||||
|
pixels down.
|
||||||
|
.It ptrmoveright
|
||||||
|
Move pointer
|
||||||
|
.Ar moveamount
|
||||||
|
pixels right.
|
||||||
|
.It ptrmoveleft
|
||||||
|
Move pointer
|
||||||
|
.Ar moveamount
|
||||||
|
pixels left.
|
||||||
|
.It bigptrmoveup
|
||||||
|
Move pointer 10 times
|
||||||
|
.Ar moveamount
|
||||||
|
pixels up.
|
||||||
|
.It bigptrmovedown
|
||||||
|
Move pointer 10 times
|
||||||
|
.Ar moveamount
|
||||||
|
pixels down.
|
||||||
|
.It bigptrmoveright
|
||||||
|
Move pointer 10 times
|
||||||
|
.Ar moveamount
|
||||||
|
pixels right.
|
||||||
|
.It bigptrmoveleft
|
||||||
|
Move pointer 10 times
|
||||||
|
.Ar moveamount
|
||||||
|
pixels left.
|
||||||
|
.El
|
||||||
|
.Sh MOUSEBIND COMMAND LIST
|
||||||
|
.Bl -tag -width 18n -compact
|
||||||
|
.It window_move
|
||||||
|
Move current window.
|
||||||
|
.It window_resize
|
||||||
|
Resize current window.
|
||||||
|
.It window_lower
|
||||||
|
Lower current window.
|
||||||
|
.It window_hide
|
||||||
|
Hide current window.
|
||||||
|
.It window_grouptoggle
|
||||||
|
Toggle group membership of current window.
|
||||||
|
.It menu_group
|
||||||
|
Launch group list.
|
||||||
|
.It menu_unhide
|
||||||
|
Launch hidden window list.
|
||||||
|
.It menu_cmd
|
||||||
|
Launch command list.
|
||||||
|
.El
|
||||||
|
.Sh FILES
|
||||||
|
.Bl -tag -width "~/.cwmrcXXX" -compact
|
||||||
|
.It Pa ~/.cwmrc
|
||||||
|
default
|
||||||
|
.Xr cwm 1
|
||||||
|
configuration file
|
||||||
|
.El
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr cwm 1
|
||||||
|
.Sh HISTORY
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
file format first appeared in
|
||||||
|
.Ox 4.4 .
|
106
fgetln.c
Normal file
106
fgetln.c
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
/* $NetBSD: fgetln.c,v 1.9 2008/04/29 06:53:03 martin Exp $ */
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This code is derived from software contributed to The NetBSD Foundation
|
||||||
|
* by Christos Zoulas.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||||
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||||
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_NBTOOL_CONFIG_H
|
||||||
|
#include "nbtool_config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !HAVE_FGETLN
|
||||||
|
#include <stdlib.h>
|
||||||
|
#ifndef HAVE_NBTOOL_CONFIG_H
|
||||||
|
/* These headers are required, but included from nbtool_config.h */
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
char *
|
||||||
|
fgetln(FILE *fp, size_t *len)
|
||||||
|
{
|
||||||
|
static char *buf = NULL;
|
||||||
|
static size_t bufsiz = 0;
|
||||||
|
char *ptr;
|
||||||
|
|
||||||
|
|
||||||
|
if (buf == NULL) {
|
||||||
|
bufsiz = BUFSIZ;
|
||||||
|
if ((buf = malloc(bufsiz)) == NULL)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fgets(buf, bufsiz, fp) == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
*len = 0;
|
||||||
|
while ((ptr = strchr(&buf[*len], '\n')) == NULL) {
|
||||||
|
size_t nbufsiz = bufsiz + BUFSIZ;
|
||||||
|
char *nbuf = realloc(buf, nbufsiz);
|
||||||
|
|
||||||
|
if (nbuf == NULL) {
|
||||||
|
int oerrno = errno;
|
||||||
|
free(buf);
|
||||||
|
errno = oerrno;
|
||||||
|
buf = NULL;
|
||||||
|
return NULL;
|
||||||
|
} else
|
||||||
|
buf = nbuf;
|
||||||
|
|
||||||
|
if (fgets(&buf[bufsiz], BUFSIZ, fp) == NULL) {
|
||||||
|
buf[bufsiz] = '\0';
|
||||||
|
*len = strlen(buf);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
*len = bufsiz;
|
||||||
|
bufsiz = nbufsiz;
|
||||||
|
}
|
||||||
|
|
||||||
|
*len = (ptr - buf) + 1;
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef TEST
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
while ((p = fgetln(stdin, &len)) != NULL) {
|
||||||
|
(void)printf("%zu %s", len, p);
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
126
font.c
126
font.c
@@ -16,137 +16,78 @@
|
|||||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "hash.h"
|
#include <sys/param.h>
|
||||||
#include "headers.h"
|
#include <sys/queue.h>
|
||||||
|
|
||||||
|
#include <err.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "calmwm.h"
|
#include "calmwm.h"
|
||||||
|
|
||||||
static XftFont *_make_font(struct screen_ctx *sc, struct fontdesc *fdp);
|
|
||||||
|
|
||||||
HASH_GENERATE(fonthash, fontdesc, node, fontdesc_cmp);
|
|
||||||
|
|
||||||
int
|
int
|
||||||
fontdesc_cmp(struct fontdesc *a, struct fontdesc *b)
|
font_ascent(struct screen_ctx *sc)
|
||||||
{
|
{
|
||||||
return strcmp(a->name, b->name);
|
return (sc->font->ascent);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
int
|
||||||
* Fowler/Noll/Vo hash
|
font_descent(struct screen_ctx *sc)
|
||||||
* http://www.isthe.com/chongo/tech/comp/fnv/
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define FNV_P_32 ((unsigned int)0x01000193) /* 16777619 */
|
|
||||||
#define FNV_1_32 ((unsigned int)0x811c9dc5) /* 2166136261 */
|
|
||||||
|
|
||||||
unsigned int
|
|
||||||
fontdesc_hash(struct fontdesc *fdp)
|
|
||||||
{
|
{
|
||||||
const unsigned char *p, *end, *start;
|
return (sc->font->descent);
|
||||||
unsigned int hash = FNV_1_32;
|
}
|
||||||
|
|
||||||
start = fdp->name;
|
u_int
|
||||||
end = (const unsigned char *)fdp->name + strlen(fdp->name);
|
font_height(struct screen_ctx *sc)
|
||||||
|
{
|
||||||
for (p = start; p < end; p++) {
|
return (sc->fontheight);
|
||||||
hash *= FNV_P_32;
|
|
||||||
hash ^= (unsigned int)*p;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (hash);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
font_init(struct screen_ctx *sc)
|
font_init(struct screen_ctx *sc)
|
||||||
{
|
{
|
||||||
XColor xcolor, tmp;
|
|
||||||
|
|
||||||
HASH_INIT(&sc->fonthash, fontdesc_hash);
|
|
||||||
sc->xftdraw = XftDrawCreate(X_Dpy, sc->rootwin,
|
sc->xftdraw = XftDrawCreate(X_Dpy, sc->rootwin,
|
||||||
DefaultVisual(X_Dpy, sc->which), DefaultColormap(X_Dpy, sc->which));
|
DefaultVisual(X_Dpy, sc->which), DefaultColormap(X_Dpy, sc->which));
|
||||||
if (sc->xftdraw == NULL)
|
if (sc->xftdraw == NULL)
|
||||||
errx(1, "XftDrawCreate");
|
errx(1, "XftDrawCreate");
|
||||||
|
|
||||||
if (!XAllocNamedColor(X_Dpy, DefaultColormap(X_Dpy, sc->which),
|
if (!XftColorAllocName(X_Dpy, DefaultVisual(X_Dpy, sc->which),
|
||||||
"black", &xcolor, &tmp))
|
DefaultColormap(X_Dpy, sc->which), "black", &sc->xftcolor))
|
||||||
errx(1, "XAllocNamedColor");
|
errx(1, "XftColorAllocName");
|
||||||
|
|
||||||
sc->xftcolor.color.red = xcolor.red;
|
|
||||||
sc->xftcolor.color.green = xcolor.green;
|
|
||||||
sc->xftcolor.color.blue = xcolor.blue;
|
|
||||||
sc->xftcolor.color.alpha = 0x00ff00;
|
|
||||||
sc->xftcolor.pixel = xcolor.pixel;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct fontdesc *
|
|
||||||
font_getx(struct screen_ctx *sc, const char *name)
|
|
||||||
{
|
|
||||||
struct fontdesc *fdp;
|
|
||||||
|
|
||||||
if ((fdp = font_get(sc, name)) == NULL)
|
|
||||||
errx(1, "font_get()");
|
|
||||||
|
|
||||||
return (fdp);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct fontdesc *
|
|
||||||
font_get(struct screen_ctx *sc, const char *name)
|
|
||||||
{
|
|
||||||
struct fontdesc fd, *fdp;
|
|
||||||
XftFont *fn;
|
|
||||||
|
|
||||||
fd.name = name;
|
|
||||||
|
|
||||||
if ((fdp = HASH_FIND(fonthash, &sc->fonthash, &fd)) == NULL
|
|
||||||
&& (fn = _make_font(sc, &fd)) != NULL) {
|
|
||||||
fdp = xmalloc(sizeof(*fdp));
|
|
||||||
fdp->name = xstrdup(fd.name);
|
|
||||||
fdp->fn = fn;
|
|
||||||
fdp->sc = sc;
|
|
||||||
HASH_INSERT(fonthash, &sc->fonthash, fdp);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (fdp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
font_width(struct fontdesc *fdp, const char *text, int len)
|
font_width(struct screen_ctx *sc, const char *text, int len)
|
||||||
{
|
{
|
||||||
XGlyphInfo extents;
|
XGlyphInfo extents;
|
||||||
XftTextExtents8(X_Dpy, fdp->fn, (const XftChar8*)text, len, &extents);
|
|
||||||
|
XftTextExtents8(X_Dpy, sc->font, (const XftChar8*)text,
|
||||||
|
len, &extents);
|
||||||
|
|
||||||
return (extents.xOff);
|
return (extents.xOff);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
font_draw(struct fontdesc *fdp, const char *text, int len,
|
font_draw(struct screen_ctx *sc, const char *text, int len,
|
||||||
Drawable d, int x, int y)
|
Drawable d, int x, int y)
|
||||||
{
|
{
|
||||||
XftDrawChange(fdp->sc->xftdraw, d);
|
XftDrawChange(sc->xftdraw, d);
|
||||||
/* Really needs to be UTF8'd. */
|
/* Really needs to be UTF8'd. */
|
||||||
XftDrawString8(fdp->sc->xftdraw, &fdp->sc->xftcolor, fdp->fn, x, y,
|
XftDrawString8(sc->xftdraw, &sc->xftcolor, sc->font, x, y,
|
||||||
(const FcChar8*)text, len);
|
(const FcChar8*)text, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
XftFont *
|
||||||
font_ascent(struct fontdesc *fdp)
|
font_make(struct screen_ctx *sc, const char *name)
|
||||||
{
|
|
||||||
return fdp->fn->ascent;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
font_descent(struct fontdesc *fdp)
|
|
||||||
{
|
|
||||||
return fdp->fn->descent;
|
|
||||||
}
|
|
||||||
|
|
||||||
static XftFont *
|
|
||||||
_make_font(struct screen_ctx *sc, struct fontdesc *fdp)
|
|
||||||
{
|
{
|
||||||
XftFont *fn = NULL;
|
XftFont *fn = NULL;
|
||||||
FcPattern *pat, *patx;
|
FcPattern *pat, *patx;
|
||||||
XftResult res;
|
XftResult res;
|
||||||
|
|
||||||
if ((pat = FcNameParse(fdp->name)) == NULL)
|
if ((pat = FcNameParse((const FcChar8*)name)) == NULL)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
|
||||||
if ((patx = XftFontMatch(X_Dpy, sc->which, pat, &res)) != NULL)
|
if ((patx = XftFontMatch(X_Dpy, sc->which, pat, &res)) != NULL)
|
||||||
@@ -156,4 +97,3 @@ _make_font(struct screen_ctx *sc, struct fontdesc *fdp)
|
|||||||
|
|
||||||
return (fn);
|
return (fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
401
grab.c
401
grab.c
@@ -1,401 +0,0 @@
|
|||||||
/*
|
|
||||||
* calmwm - the calm window manager
|
|
||||||
*
|
|
||||||
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
|
|
||||||
*
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
|
||||||
* copyright notice and this permission notice appear in all copies.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*
|
|
||||||
* $Id$
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "headers.h"
|
|
||||||
#include "calmwm.h"
|
|
||||||
|
|
||||||
static int _sweepcalc(struct client_ctx *, int, int, int, int);
|
|
||||||
static int menu_calc_entry(int, int, int, int, int);
|
|
||||||
|
|
||||||
#define ADJUST_HEIGHT(cc, dy) ((cc->geom.height - cc->geom.min_dy)/ dy)
|
|
||||||
#define ADJUST_WIDTH(cc, dx) ((cc->geom.width - cc->geom.min_dx)/ dx)
|
|
||||||
|
|
||||||
void
|
|
||||||
grab_sweep_draw(struct client_ctx *cc, int dx, int dy)
|
|
||||||
{
|
|
||||||
struct screen_ctx *sc = CCTOSC(cc);
|
|
||||||
int x0 = cc->geom.x, y0 = cc->geom.y;
|
|
||||||
char asize[10]; /* fits "nnnnxnnnn\0" */
|
|
||||||
int wide, height, wide_size, wide_name;
|
|
||||||
struct fontdesc *font = DefaultFont;
|
|
||||||
|
|
||||||
snprintf(asize, sizeof(asize), "%dx%d",
|
|
||||||
ADJUST_WIDTH(cc, dx), ADJUST_HEIGHT(cc, dy));
|
|
||||||
wide_size = font_width(font, asize, strlen(asize)) + 4;
|
|
||||||
wide_name = font_width(font, cc->name, strlen(cc->name)) + 4;
|
|
||||||
wide = MAX(wide_size, wide_name);
|
|
||||||
height = font_ascent(font) + font_descent(font) + 1;
|
|
||||||
|
|
||||||
XMoveResizeWindow(X_Dpy, sc->menuwin, x0, y0, wide, height * 2);
|
|
||||||
XMapWindow(X_Dpy, sc->menuwin);
|
|
||||||
XReparentWindow(X_Dpy, sc->menuwin, cc->win, 0, 0);
|
|
||||||
XClearWindow(X_Dpy, sc->menuwin);
|
|
||||||
font_draw(font, cc->name, strlen(cc->name), sc->menuwin,
|
|
||||||
2, font_ascent(font) + 1);
|
|
||||||
font_draw(font, asize, strlen(asize), sc->menuwin,
|
|
||||||
wide/2 - wide_size/2, height + font_ascent(font) + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
grab_sweep(struct client_ctx *cc)
|
|
||||||
{
|
|
||||||
XEvent ev;
|
|
||||||
struct screen_ctx *sc = CCTOSC(cc);
|
|
||||||
int x0 = cc->geom.x, y0 = cc->geom.y;
|
|
||||||
int dx, dy;
|
|
||||||
|
|
||||||
dx = MAX(1, cc->size->width_inc);
|
|
||||||
dy = MAX(1, cc->size->height_inc);
|
|
||||||
|
|
||||||
client_raise(cc);
|
|
||||||
client_ptrsave(cc);
|
|
||||||
|
|
||||||
if (xu_ptr_grab(sc->rootwin, MouseMask, Cursor_resize) < 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
xu_ptr_setpos(cc->win, cc->geom.width, cc->geom.height);
|
|
||||||
grab_sweep_draw(cc, dx, dy);
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
/* Look for changes in ptr position. */
|
|
||||||
XMaskEvent(X_Dpy, MouseMask|ExposureMask, &ev);
|
|
||||||
|
|
||||||
switch (ev.type) {
|
|
||||||
case Expose:
|
|
||||||
client_draw_border(cc);
|
|
||||||
break;
|
|
||||||
case MotionNotify:
|
|
||||||
if (_sweepcalc(cc, x0, y0, ev.xmotion.x, ev.xmotion.y))
|
|
||||||
/* Recompute window output */
|
|
||||||
grab_sweep_draw(cc, dx, dy);
|
|
||||||
|
|
||||||
XMoveResizeWindow(X_Dpy, cc->pwin,
|
|
||||||
cc->geom.x - cc->bwidth,
|
|
||||||
cc->geom.y - cc->bwidth,
|
|
||||||
cc->geom.width + cc->bwidth*2,
|
|
||||||
cc->geom.height + cc->bwidth*2);
|
|
||||||
XMoveResizeWindow(X_Dpy, cc->win,
|
|
||||||
cc->bwidth, cc->bwidth,
|
|
||||||
cc->geom.width, cc->geom.height);
|
|
||||||
|
|
||||||
break;
|
|
||||||
case ButtonRelease:
|
|
||||||
XUnmapWindow(X_Dpy, sc->menuwin);
|
|
||||||
XReparentWindow(X_Dpy, sc->menuwin, sc->rootwin, 0, 0);
|
|
||||||
xu_ptr_ungrab();
|
|
||||||
client_ptrwarp(cc);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* NOTREACHED */
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
grab_drag(struct client_ctx *cc)
|
|
||||||
{
|
|
||||||
int x0 = cc->geom.x, y0 = cc->geom.y, xm, ym;
|
|
||||||
struct screen_ctx *sc = CCTOSC(cc);
|
|
||||||
XEvent ev;
|
|
||||||
|
|
||||||
client_raise(cc);
|
|
||||||
|
|
||||||
if (xu_ptr_grab(sc->rootwin, MouseMask, Cursor_move) < 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
xu_ptr_getpos(sc->rootwin, &xm, &ym);
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
XMaskEvent(X_Dpy, MouseMask|ExposureMask, &ev);
|
|
||||||
|
|
||||||
switch (ev.type) {
|
|
||||||
case Expose:
|
|
||||||
client_draw_border(cc);
|
|
||||||
break;
|
|
||||||
case MotionNotify:
|
|
||||||
cc->geom.x = x0 + (ev.xmotion.x - xm);
|
|
||||||
cc->geom.y = y0 + (ev.xmotion.y - ym);
|
|
||||||
|
|
||||||
XMoveWindow(X_Dpy, cc->pwin,
|
|
||||||
cc->geom.x - cc->bwidth, cc->geom.y - cc->bwidth);
|
|
||||||
|
|
||||||
break;
|
|
||||||
case ButtonRelease:
|
|
||||||
xu_ptr_ungrab();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* NOTREACHED */
|
|
||||||
}
|
|
||||||
|
|
||||||
#define MenuMask (ButtonMask|ButtonMotionMask|ExposureMask)
|
|
||||||
#define MenuGrabMask (ButtonMask|ButtonMotionMask|StructureNotifyMask)
|
|
||||||
#define AllButtonMask (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask)
|
|
||||||
|
|
||||||
void *
|
|
||||||
grab_menu(XButtonEvent *e, struct menu_q *menuq)
|
|
||||||
{
|
|
||||||
struct screen_ctx *sc;
|
|
||||||
struct menu *mi;
|
|
||||||
XEvent event;
|
|
||||||
struct fontdesc *font = DefaultFont;
|
|
||||||
int x, y, width, height, tothigh, i, no, entry, prev;
|
|
||||||
int fx, fy;
|
|
||||||
|
|
||||||
no = i = width = 0;
|
|
||||||
|
|
||||||
if ((sc = screen_fromroot(e->root)) == NULL || e->window == sc->menuwin)
|
|
||||||
return (NULL);
|
|
||||||
|
|
||||||
TAILQ_FOREACH(mi, menuq, entry) {
|
|
||||||
i = font_width(font, mi->text, strlen(mi->text)) + 4;
|
|
||||||
if (i > width)
|
|
||||||
width = i;
|
|
||||||
no++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!sc->maxinitialised) {
|
|
||||||
sc->xmax = DisplayWidth(X_Dpy, sc->which);
|
|
||||||
sc->ymax = DisplayHeight(X_Dpy, sc->which);
|
|
||||||
}
|
|
||||||
|
|
||||||
height = font_ascent(font) + font_descent(font) + 1;
|
|
||||||
tothigh = height * no;
|
|
||||||
|
|
||||||
x = e->x - width/2;
|
|
||||||
y = e->y - height/2;
|
|
||||||
|
|
||||||
/* does it fit on the screen? */
|
|
||||||
if (x < 0)
|
|
||||||
x = 0;
|
|
||||||
else if (x+width >= sc->xmax)
|
|
||||||
x = sc->xmax - width;
|
|
||||||
|
|
||||||
if (y < 0)
|
|
||||||
y = 0;
|
|
||||||
else if (y+tothigh >= sc->ymax)
|
|
||||||
y = sc->ymax - tothigh;
|
|
||||||
|
|
||||||
xu_ptr_setpos(e->root, x + width/2, y + height/2);
|
|
||||||
|
|
||||||
XMoveResizeWindow(X_Dpy, sc->menuwin, x, y, width, tothigh);
|
|
||||||
XSelectInput(X_Dpy, sc->menuwin, MenuMask);
|
|
||||||
XMapRaised(X_Dpy, sc->menuwin);
|
|
||||||
|
|
||||||
if (xu_ptr_grab(sc->menuwin, MenuGrabMask, Cursor_select) < 0) {
|
|
||||||
XUnmapWindow(X_Dpy, sc->menuwin);
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
entry = prev = -1;
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
XMaskEvent(X_Dpy, MenuMask, &event);
|
|
||||||
switch (event.type) {
|
|
||||||
case Expose:
|
|
||||||
XClearWindow(X_Dpy, sc->menuwin);
|
|
||||||
i = 0;
|
|
||||||
TAILQ_FOREACH(mi, menuq, entry) {
|
|
||||||
fx = (width - font_width(font, mi->text,
|
|
||||||
strlen(mi->text)))/2;
|
|
||||||
fy = height*i + font_ascent(font) + 1;
|
|
||||||
font_draw(font, mi->text, strlen(mi->text),
|
|
||||||
sc->menuwin, fx, fy);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
/* FALLTHROUGH */
|
|
||||||
case MotionNotify:
|
|
||||||
prev = entry;
|
|
||||||
entry = menu_calc_entry(event.xbutton.x,
|
|
||||||
event.xbutton.y, width, height, no);
|
|
||||||
if (prev != -1)
|
|
||||||
XFillRectangle(X_Dpy, sc->menuwin, sc->hlgc,
|
|
||||||
0, height*prev, width, height);
|
|
||||||
if (entry != -1) {
|
|
||||||
xu_ptr_regrab(MenuGrabMask, Cursor_select);
|
|
||||||
XFillRectangle(X_Dpy, sc->menuwin, sc->hlgc,
|
|
||||||
0, height*entry, width, height);
|
|
||||||
} else
|
|
||||||
xu_ptr_regrab(MenuGrabMask, Cursor_default);
|
|
||||||
break;
|
|
||||||
case ButtonRelease:
|
|
||||||
if (event.xbutton.button != e->button)
|
|
||||||
break;
|
|
||||||
entry = menu_calc_entry(event.xbutton.x,
|
|
||||||
event.xbutton.y, width, height, no);
|
|
||||||
xu_ptr_ungrab();
|
|
||||||
XUnmapWindow(X_Dpy, sc->menuwin);
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
TAILQ_FOREACH(mi, menuq, entry)
|
|
||||||
if (entry == i++)
|
|
||||||
break;
|
|
||||||
return (mi);
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
grab_menuinit(struct screen_ctx *sc)
|
|
||||||
{
|
|
||||||
sc->menuwin = XCreateSimpleWindow(X_Dpy, sc->rootwin, 0, 0,
|
|
||||||
1, 1, 1, sc->blackpixl, sc->whitepixl);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define LABEL_MAXLEN 256
|
|
||||||
#define LabelMask (KeyPressMask|ExposureMask)
|
|
||||||
|
|
||||||
void
|
|
||||||
grab_label(struct client_ctx *cc)
|
|
||||||
{
|
|
||||||
struct screen_ctx *sc = screen_current();
|
|
||||||
int x, y, dx, dy, fontheight, focusrevert;
|
|
||||||
XEvent e;
|
|
||||||
char labelstr[LABEL_MAXLEN];
|
|
||||||
char dispstr[LABEL_MAXLEN + sizeof("label>") - 1];
|
|
||||||
Window focuswin;
|
|
||||||
char chr;
|
|
||||||
enum ctltype ctl;
|
|
||||||
size_t len;
|
|
||||||
struct fontdesc *font = DefaultFont;
|
|
||||||
|
|
||||||
if (cc->label != NULL)
|
|
||||||
strlcpy(labelstr, cc->label, sizeof(labelstr));
|
|
||||||
else
|
|
||||||
labelstr[0] = '\0';
|
|
||||||
|
|
||||||
xu_ptr_getpos(sc->rootwin, &x, &y);
|
|
||||||
|
|
||||||
dy = fontheight = font_ascent(font) + font_descent(font) + 1;
|
|
||||||
dx = font_width(font, "label>", 6);
|
|
||||||
|
|
||||||
XMoveResizeWindow(X_Dpy, sc->searchwin, x, y, dx, dy);
|
|
||||||
XSelectInput(X_Dpy, sc->searchwin, LabelMask);
|
|
||||||
XMapRaised(X_Dpy, sc->searchwin);
|
|
||||||
|
|
||||||
XGetInputFocus(X_Dpy, &focuswin, &focusrevert);
|
|
||||||
XSetInputFocus(X_Dpy, sc->searchwin,
|
|
||||||
RevertToPointerRoot, CurrentTime);
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
XMaskEvent(X_Dpy, LabelMask, &e);
|
|
||||||
|
|
||||||
switch (e.type) {
|
|
||||||
case KeyPress:
|
|
||||||
if (input_keycodetrans(e.xkey.keycode, e.xkey.state,
|
|
||||||
&ctl, &chr, 0) < 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
switch (ctl) {
|
|
||||||
case CTL_ERASEONE:
|
|
||||||
if ((len = strlen(labelstr)) > 0)
|
|
||||||
labelstr[len - 1] = '\0';
|
|
||||||
break;
|
|
||||||
case CTL_RETURN:
|
|
||||||
/* Done */
|
|
||||||
if (strlen(labelstr) == 0)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (cc->label != NULL)
|
|
||||||
xfree(cc->label);
|
|
||||||
|
|
||||||
cc->label = xstrdup(labelstr);
|
|
||||||
/* FALLTHROUGH */
|
|
||||||
case CTL_ABORT:
|
|
||||||
goto out;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (chr != '\0') {
|
|
||||||
char str[2];
|
|
||||||
|
|
||||||
str[0] = chr;
|
|
||||||
str[1] = '\0';
|
|
||||||
strlcat(labelstr, str, sizeof(labelstr));
|
|
||||||
}
|
|
||||||
|
|
||||||
case Expose:
|
|
||||||
snprintf(dispstr, sizeof(dispstr), "label>%s", labelstr);
|
|
||||||
dx = font_width(font, dispstr, strlen(dispstr));
|
|
||||||
dy = fontheight;
|
|
||||||
|
|
||||||
XClearWindow(X_Dpy, sc->searchwin);
|
|
||||||
XResizeWindow(X_Dpy, sc->searchwin, dx, dy);
|
|
||||||
|
|
||||||
font_draw(font, dispstr, strlen(dispstr),
|
|
||||||
sc->searchwin, 0, font_ascent(font) + 1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
XSetInputFocus(X_Dpy, focuswin,
|
|
||||||
focusrevert, CurrentTime);
|
|
||||||
XUnmapWindow(X_Dpy, sc->searchwin);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
_sweepcalc(struct client_ctx *cc, int x0, int y0, int motionx, int motiony)
|
|
||||||
{
|
|
||||||
int width, height;
|
|
||||||
|
|
||||||
width = cc->geom.width;
|
|
||||||
height = cc->geom.height;
|
|
||||||
|
|
||||||
cc->geom.width = abs(x0 - motionx);
|
|
||||||
cc->geom.height = abs(y0 - motiony);
|
|
||||||
|
|
||||||
if (cc->size->flags & PResizeInc) {
|
|
||||||
cc->geom.width -=
|
|
||||||
(cc->geom.width - cc->geom.min_dx) % cc->size->width_inc;
|
|
||||||
cc->geom.height -=
|
|
||||||
(cc->geom.height - cc->geom.min_dy) % cc->size->height_inc;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cc->size->flags & PMinSize) {
|
|
||||||
cc->geom.width = MAX(cc->geom.width, cc->size->min_width);
|
|
||||||
cc->geom.height = MAX(cc->geom.height, cc->size->min_height);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cc->size->flags & PMaxSize) {
|
|
||||||
cc->geom.width = MIN(cc->geom.width, cc->size->max_width);
|
|
||||||
cc->geom.height = MIN(cc->geom.height, cc->size->max_height);
|
|
||||||
}
|
|
||||||
|
|
||||||
cc->geom.x = x0 <= motionx ? x0 : x0 - cc->geom.width;
|
|
||||||
cc->geom.y = y0 <= motiony ? y0 : y0 - cc->geom.height;
|
|
||||||
|
|
||||||
return (width != cc->geom.width || height != cc->geom.height);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
menu_calc_entry(int x, int y, int width, int height, int noentries)
|
|
||||||
{
|
|
||||||
int entry = y/height;
|
|
||||||
|
|
||||||
/* in bounds? */
|
|
||||||
if (x < 0 || x > width || y < 0 || y > height*noentries ||
|
|
||||||
entry < 0 || entry >= noentries)
|
|
||||||
entry = -1;
|
|
||||||
|
|
||||||
return entry;
|
|
||||||
}
|
|
654
group.c
654
group.c
@@ -19,36 +19,40 @@
|
|||||||
* $Id$
|
* $Id$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "headers.h"
|
#include <sys/param.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <err.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "calmwm.h"
|
#include "calmwm.h"
|
||||||
|
|
||||||
#define CALMWM_NGROUPS 9
|
static void group_add(struct group_ctx *, struct client_ctx *);
|
||||||
|
static void group_remove(struct client_ctx *);
|
||||||
|
static void group_hide(struct screen_ctx *, struct group_ctx *);
|
||||||
|
static void group_show(struct screen_ctx *, struct group_ctx *);
|
||||||
|
static void group_fix_hidden_state(struct group_ctx *);
|
||||||
|
static void group_setactive(struct screen_ctx *, long);
|
||||||
|
static void group_set_names(struct screen_ctx *);
|
||||||
|
|
||||||
int Groupmode = 0;
|
const char *shortcut_to_name[] = {
|
||||||
int Groupnamemode = 0;
|
"nogroup", "one", "two", "three", "four", "five", "six",
|
||||||
struct group_ctx *Group_active = NULL;
|
"seven", "eight", "nine"
|
||||||
struct group_ctx *Group_current = NULL;
|
|
||||||
struct group_ctx Groups[CALMWM_NGROUPS];
|
|
||||||
char Group_name[256];
|
|
||||||
int Groupfocusset = 0;
|
|
||||||
Window Groupfocuswin;
|
|
||||||
int Groupfocusrevert;
|
|
||||||
int Grouphideall = 0;
|
|
||||||
struct group_ctx_q Groupq;
|
|
||||||
|
|
||||||
#define GroupMask (KeyPressMask|ExposureMask)
|
|
||||||
|
|
||||||
static char *shortcut_to_name[] = {
|
|
||||||
"XXX", "one", "two", "three",
|
|
||||||
"four", "five", "six", "seven",
|
|
||||||
"eight", "nine",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_group_add(struct group_ctx *gc, struct client_ctx *cc)
|
group_add(struct group_ctx *gc, struct client_ctx *cc)
|
||||||
{
|
{
|
||||||
|
long no;
|
||||||
if (cc == NULL || gc == NULL)
|
if (cc == NULL || gc == NULL)
|
||||||
errx(1, "_group_add: a ctx is NULL");
|
errx(1, "group_add: a ctx is NULL");
|
||||||
|
|
||||||
|
no = gc->shortcut - 1;
|
||||||
|
|
||||||
if (cc->group == gc)
|
if (cc->group == gc)
|
||||||
return;
|
return;
|
||||||
@@ -56,56 +60,34 @@ _group_add(struct group_ctx *gc, struct client_ctx *cc)
|
|||||||
if (cc->group != NULL)
|
if (cc->group != NULL)
|
||||||
TAILQ_REMOVE(&cc->group->clients, cc, group_entry);
|
TAILQ_REMOVE(&cc->group->clients, cc, group_entry);
|
||||||
|
|
||||||
|
XChangeProperty(X_Dpy, cc->win, _NET_WM_DESKTOP, XA_CARDINAL,
|
||||||
|
32, PropModeReplace, (unsigned char *)&no, 1);
|
||||||
|
|
||||||
TAILQ_INSERT_TAIL(&gc->clients, cc, group_entry);
|
TAILQ_INSERT_TAIL(&gc->clients, cc, group_entry);
|
||||||
cc->group = gc;
|
cc->group = gc;
|
||||||
cc->groupcommit = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_group_remove(struct client_ctx *cc)
|
group_remove(struct client_ctx *cc)
|
||||||
{
|
{
|
||||||
|
long no = 0xffffffff;
|
||||||
|
|
||||||
if (cc == NULL || cc->group == NULL)
|
if (cc == NULL || cc->group == NULL)
|
||||||
errx(1, "_group_remove: a ctx is NULL");
|
errx(1, "group_remove: a ctx is NULL");
|
||||||
|
|
||||||
|
XChangeProperty(X_Dpy, cc->win, _NET_WM_DESKTOP, XA_CARDINAL,
|
||||||
|
32, PropModeReplace, (unsigned char *)&no, 1);
|
||||||
|
|
||||||
TAILQ_REMOVE(&cc->group->clients, cc, group_entry);
|
TAILQ_REMOVE(&cc->group->clients, cc, group_entry);
|
||||||
cc->group = NULL;
|
cc->group = NULL;
|
||||||
cc->groupcommit = 0;
|
|
||||||
cc->highlight = 0;
|
|
||||||
client_draw_border(cc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_group_commit(struct group_ctx *gc)
|
group_hide(struct screen_ctx *sc, struct group_ctx *gc)
|
||||||
{
|
{
|
||||||
struct client_ctx *cc;
|
struct client_ctx *cc;
|
||||||
|
|
||||||
if (gc == NULL)
|
screen_updatestackingorder(sc);
|
||||||
errx(1, "_group_commit: ctx is null");
|
|
||||||
|
|
||||||
TAILQ_FOREACH(cc, &gc->clients, group_entry)
|
|
||||||
cc->groupcommit = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
_group_purge(struct group_ctx *gc)
|
|
||||||
{
|
|
||||||
struct client_ctx *cc;
|
|
||||||
|
|
||||||
if (gc == NULL)
|
|
||||||
errx(1, "_group_purge: ctx is null");
|
|
||||||
|
|
||||||
TAILQ_FOREACH(cc, &gc->clients, group_entry)
|
|
||||||
if (cc->groupcommit == 0)
|
|
||||||
_group_remove(cc);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
_group_hide(struct group_ctx *gc)
|
|
||||||
{
|
|
||||||
struct client_ctx *cc;
|
|
||||||
|
|
||||||
screen_updatestackingorder();
|
|
||||||
|
|
||||||
gc->nhidden = 0;
|
gc->nhidden = 0;
|
||||||
gc->highstack = 0;
|
gc->highstack = 0;
|
||||||
@@ -119,21 +101,21 @@ _group_hide(struct group_ctx *gc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_group_show(struct group_ctx *gc)
|
group_show(struct screen_ctx *sc, struct group_ctx *gc)
|
||||||
{
|
{
|
||||||
struct client_ctx *cc;
|
struct client_ctx *cc;
|
||||||
Window *winlist;
|
Window *winlist;
|
||||||
u_int i;
|
u_int i;
|
||||||
int lastempty = -1;
|
int lastempty = -1;
|
||||||
|
|
||||||
winlist = (Window *) xcalloc(sizeof(*winlist) * (gc->highstack + 1));
|
winlist = (Window *) xcalloc(sizeof(*winlist), (gc->highstack + 1));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Invert the stacking order as XRestackWindows() expects them
|
* Invert the stacking order as XRestackWindows() expects them
|
||||||
* top-to-bottom.
|
* top-to-bottom.
|
||||||
*/
|
*/
|
||||||
TAILQ_FOREACH(cc, &gc->clients, group_entry) {
|
TAILQ_FOREACH(cc, &gc->clients, group_entry) {
|
||||||
winlist[gc->highstack - cc->stackingorder] = cc->pwin;
|
winlist[gc->highstack - cc->stackingorder] = cc->win;
|
||||||
client_unhide(cc);
|
client_unhide(cc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,159 +134,109 @@ _group_show(struct group_ctx *gc)
|
|||||||
xfree(winlist);
|
xfree(winlist);
|
||||||
|
|
||||||
gc->hidden = 0;
|
gc->hidden = 0;
|
||||||
Group_active = gc;
|
group_setactive(sc, gc->shortcut - 1);
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
_group_destroy(struct group_ctx *gc)
|
|
||||||
{
|
|
||||||
struct client_ctx *cc;
|
|
||||||
|
|
||||||
if (gc->name != NULL) {
|
|
||||||
xfree(gc->name);
|
|
||||||
gc->name = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((cc = TAILQ_FIRST(&gc->clients)) != NULL) {
|
|
||||||
TAILQ_REMOVE(&gc->clients, cc, group_entry);
|
|
||||||
cc->group = NULL;
|
|
||||||
cc->groupcommit = 0;
|
|
||||||
cc->highlight = 0;
|
|
||||||
client_draw_border(cc);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
group_init(void)
|
group_init(struct screen_ctx *sc)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
long viewports[2] = {0, 0};
|
||||||
|
long ndesks = CALMWM_NGROUPS, zero = 0;
|
||||||
|
|
||||||
TAILQ_INIT(&Groupq);
|
TAILQ_INIT(&sc->groupq);
|
||||||
|
sc->group_hideall = 0;
|
||||||
|
/* see if any group names have already been set and update the property
|
||||||
|
* with ours if they'll have changed.
|
||||||
|
*/
|
||||||
|
group_update_names(sc);
|
||||||
|
|
||||||
for (i = 0; i < CALMWM_NGROUPS; i++) {
|
for (i = 0; i < CALMWM_NGROUPS; i++) {
|
||||||
TAILQ_INIT(&Groups[i].clients);
|
TAILQ_INIT(&sc->groups[i].clients);
|
||||||
Groups[i].hidden = 0;
|
sc->groups[i].hidden = 0;
|
||||||
Groups[i].shortcut = i + 1;
|
sc->groups[i].shortcut = i + 1;
|
||||||
TAILQ_INSERT_TAIL(&Groupq, &Groups[i], entry);
|
TAILQ_INSERT_TAIL(&sc->groupq, &sc->groups[i], entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
Group_current = Group_active = &Groups[0];
|
/* we don't support large desktops, so this is always (0, 0) */
|
||||||
|
XChangeProperty(X_Dpy, sc->rootwin, _NET_DESKTOP_VIEWPORT,
|
||||||
|
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)viewports, 2);
|
||||||
|
XChangeProperty(X_Dpy, sc->rootwin, _NET_NUMBER_OF_DESKTOPS,
|
||||||
|
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&ndesks, 1);
|
||||||
|
/*
|
||||||
|
* we don't use virtual roots, so make sure it's not there from a
|
||||||
|
* previous wm.
|
||||||
|
*/
|
||||||
|
XDeleteProperty(X_Dpy, sc->rootwin, _NET_VIRTUAL_ROOTS);
|
||||||
|
/*
|
||||||
|
* We don't really have a ``showing desktop'' mode, so this is zero
|
||||||
|
* always. XXX Note that when we hide all groups, or when all groups
|
||||||
|
* are hidden we could technically set this later on.
|
||||||
|
*/
|
||||||
|
XChangeProperty(X_Dpy, sc->rootwin, _NET_SHOWING_DESKTOP,
|
||||||
|
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&zero, 1);
|
||||||
|
group_setactive(sc, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
group_make_autogroup(struct conf *conf, char *val, int no)
|
||||||
|
{
|
||||||
|
struct autogroupwin *aw;
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
aw = xcalloc(1, sizeof(*aw));
|
||||||
|
|
||||||
|
if ((p = strchr(val, ',')) == NULL) {
|
||||||
|
aw->name = NULL;
|
||||||
|
aw->class = xstrdup(val);
|
||||||
|
} else {
|
||||||
|
*(p++) = '\0';
|
||||||
|
aw->name = xstrdup(val);
|
||||||
|
aw->class = xstrdup(p);
|
||||||
|
}
|
||||||
|
aw->num = no;
|
||||||
|
|
||||||
|
TAILQ_INSERT_TAIL(&conf->autogroupq, aw, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
group_setactive(struct screen_ctx *sc, long idx)
|
||||||
|
{
|
||||||
|
sc->group_active = &sc->groups[idx];
|
||||||
|
XChangeProperty(X_Dpy, sc->rootwin, _NET_CURRENT_DESKTOP,
|
||||||
|
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&idx, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
group_movetogroup(struct client_ctx *cc, int idx)
|
||||||
|
{
|
||||||
|
struct screen_ctx *sc = cc->sc;
|
||||||
|
|
||||||
|
if (idx < 0 || idx >= CALMWM_NGROUPS)
|
||||||
|
err(1, "group_movetogroup: index out of range (%d)", idx);
|
||||||
|
|
||||||
|
if(sc->group_active != &sc->groups[idx])
|
||||||
|
client_hide(cc);
|
||||||
|
group_add(&sc->groups[idx], cc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* manipulate the 'current group'
|
* Colouring for groups upon add/remove.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* change the current group */
|
|
||||||
void
|
|
||||||
group_select(int idx)
|
|
||||||
{
|
|
||||||
struct group_ctx *gc = Group_current;
|
|
||||||
struct client_ctx *cc;
|
|
||||||
|
|
||||||
if (idx < 0 || idx >= CALMWM_NGROUPS)
|
|
||||||
return;
|
|
||||||
|
|
||||||
TAILQ_FOREACH(cc, &gc->clients, group_entry) {
|
|
||||||
cc->highlight = 0;
|
|
||||||
client_draw_border(cc);
|
|
||||||
}
|
|
||||||
|
|
||||||
_group_commit(gc);
|
|
||||||
Group_current = &Groups[idx];
|
|
||||||
|
|
||||||
group_display_draw(screen_current());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* enter group mode */
|
|
||||||
void
|
|
||||||
group_enter(void)
|
|
||||||
{
|
|
||||||
if (Groupmode != 0)
|
|
||||||
errx(1, "group_enter called twice");
|
|
||||||
|
|
||||||
if (Group_current == NULL)
|
|
||||||
Group_current = &Groups[0];
|
|
||||||
|
|
||||||
/* setup input buffer */
|
|
||||||
Group_name[0] = '\0';
|
|
||||||
|
|
||||||
Groupmode = 1;
|
|
||||||
|
|
||||||
group_display_init(screen_current());
|
|
||||||
group_display_draw(screen_current());
|
|
||||||
}
|
|
||||||
|
|
||||||
/* exit group mode */
|
|
||||||
void
|
|
||||||
group_exit(int commit)
|
|
||||||
{
|
|
||||||
struct group_ctx *gc = Group_current;
|
|
||||||
struct client_ctx *cc;
|
|
||||||
|
|
||||||
if (Groupmode != 1)
|
|
||||||
errx(1, "group_exit called twice");
|
|
||||||
|
|
||||||
TAILQ_FOREACH(cc, &gc->clients, group_entry) {
|
|
||||||
cc->highlight = 0;
|
|
||||||
client_draw_border(cc);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (commit) {
|
|
||||||
_group_commit(gc);
|
|
||||||
} else {
|
|
||||||
/* abort */
|
|
||||||
_group_purge(gc);
|
|
||||||
if (!TAILQ_EMPTY(&gc->clients))
|
|
||||||
_group_destroy(gc);
|
|
||||||
}
|
|
||||||
|
|
||||||
XUnmapWindow(X_Dpy, screen_current()->groupwin);
|
|
||||||
|
|
||||||
if (Groupnamemode) {
|
|
||||||
XSetInputFocus(X_Dpy, Groupfocuswin, Groupfocusrevert,
|
|
||||||
CurrentTime);
|
|
||||||
Groupfocusset = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Groupmode = Groupnamemode = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
group_click(struct client_ctx *cc)
|
|
||||||
{
|
|
||||||
struct group_ctx *gc = Group_current;
|
|
||||||
|
|
||||||
if (gc == cc->group)
|
|
||||||
_group_remove(cc);
|
|
||||||
else
|
|
||||||
_group_add(gc, cc);
|
|
||||||
group_display_draw(screen_current());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Used to add a newly mapped window to the active group */
|
|
||||||
|
|
||||||
void
|
|
||||||
group_sticky(struct client_ctx *cc)
|
|
||||||
{
|
|
||||||
_group_add(Group_active, cc);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
group_sticky_toggle_enter(struct client_ctx *cc)
|
group_sticky_toggle_enter(struct client_ctx *cc)
|
||||||
{
|
{
|
||||||
struct group_ctx *gc = Group_active;
|
struct screen_ctx *sc = cc->sc;
|
||||||
|
struct group_ctx *gc;
|
||||||
|
|
||||||
|
gc = sc->group_active;
|
||||||
|
|
||||||
if (gc == cc->group) {
|
if (gc == cc->group) {
|
||||||
_group_remove(cc);
|
group_remove(cc);
|
||||||
cc->highlight = CLIENT_HIGHLIGHT_RED;
|
cc->highlight = CLIENT_HIGHLIGHT_UNGROUP;
|
||||||
} else {
|
} else {
|
||||||
_group_add(gc, cc);
|
group_add(gc, cc);
|
||||||
cc->highlight = CLIENT_HIGHLIGHT_BLUE;
|
cc->highlight = CLIENT_HIGHLIGHT_GROUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
client_draw_border(cc);
|
client_draw_border(cc);
|
||||||
@@ -318,92 +250,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
|
||||||
*/
|
*/
|
||||||
|
static void
|
||||||
void
|
group_fix_hidden_state(struct group_ctx *gc)
|
||||||
group_display_init(struct screen_ctx *sc)
|
|
||||||
{
|
|
||||||
sc->groupwin = XCreateSimpleWindow(X_Dpy, sc->rootwin, 0, 0,
|
|
||||||
1, 1, 1, sc->blackpixl, sc->whitepixl);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
group_display_draw(struct screen_ctx *sc)
|
|
||||||
{
|
|
||||||
struct group_ctx *gc = Group_current;
|
|
||||||
int x, y, dx, dy, fontheight;
|
|
||||||
struct client_ctx *cc;
|
|
||||||
char titlebuf[1024];
|
|
||||||
struct fontdesc *font = DefaultFont;
|
|
||||||
|
|
||||||
snprintf(titlebuf, sizeof(titlebuf), "Editing group %d", gc->shortcut);
|
|
||||||
|
|
||||||
x = y = 0;
|
|
||||||
|
|
||||||
fontheight = font_ascent(font) + font_descent(font) + 1;
|
|
||||||
dx = font_width(font, titlebuf, strlen(titlebuf));
|
|
||||||
dy = fontheight;
|
|
||||||
|
|
||||||
TAILQ_FOREACH(cc, &gc->clients, group_entry) {
|
|
||||||
cc->highlight = CLIENT_HIGHLIGHT_BLUE;
|
|
||||||
client_draw_border(cc);
|
|
||||||
}
|
|
||||||
|
|
||||||
XMoveResizeWindow(X_Dpy, sc->groupwin, x, y, dx, dy);
|
|
||||||
|
|
||||||
/* XXX */
|
|
||||||
XSelectInput(X_Dpy, sc->groupwin, GroupMask);
|
|
||||||
|
|
||||||
XMapRaised(X_Dpy, sc->groupwin);
|
|
||||||
XClearWindow(X_Dpy, sc->groupwin);
|
|
||||||
font_draw(font, titlebuf, strlen(titlebuf), sc->groupwin,
|
|
||||||
0, font_ascent(font) + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
group_display_keypress(KeyCode k)
|
|
||||||
{
|
|
||||||
struct group_ctx * gc = Group_current;
|
|
||||||
char chr;
|
|
||||||
enum ctltype ctl;
|
|
||||||
int len;
|
|
||||||
|
|
||||||
if (!Groupnamemode)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (input_keycodetrans(k, 0, &ctl, &chr, 1) < 0)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
switch (ctl) {
|
|
||||||
case CTL_ERASEONE:
|
|
||||||
if ((len = strlen(Group_name)) > 0)
|
|
||||||
Group_name[len - 1] = '\0';
|
|
||||||
break;
|
|
||||||
case CTL_RETURN:
|
|
||||||
if (gc->name != NULL)
|
|
||||||
xfree(gc->name);
|
|
||||||
|
|
||||||
gc->name = xstrdup(Group_name);
|
|
||||||
|
|
||||||
group_exit(1);
|
|
||||||
return;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (chr != '\0')
|
|
||||||
snprintf(Group_name, sizeof(Group_name), "%s%c",
|
|
||||||
Group_name, chr);
|
|
||||||
|
|
||||||
out:
|
|
||||||
group_display_draw(screen_current());
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if group_hidetoggle would produce no effect, toggle the group's hidden state
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
_group_fix_hidden_state(struct group_ctx *gc)
|
|
||||||
{
|
{
|
||||||
struct client_ctx *cc;
|
struct client_ctx *cc;
|
||||||
int same = 0;
|
int same = 0;
|
||||||
@@ -418,72 +268,77 @@ _group_fix_hidden_state(struct group_ctx *gc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
group_hidetoggle(int idx)
|
group_hidetoggle(struct screen_ctx *sc, int idx)
|
||||||
{
|
{
|
||||||
struct group_ctx *gc;
|
struct group_ctx *gc;
|
||||||
#ifdef notyet
|
|
||||||
char buf[128];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (idx < 0 || idx >= CALMWM_NGROUPS)
|
if (idx < 0 || idx >= CALMWM_NGROUPS)
|
||||||
err(1, "group_hidetoggle: index out of range (%d)", idx);
|
err(1, "group_hidetoggle: index out of range (%d)", idx);
|
||||||
|
|
||||||
gc = &Groups[idx];
|
gc = &sc->groups[idx];
|
||||||
|
group_fix_hidden_state(gc);
|
||||||
_group_fix_hidden_state(gc);
|
|
||||||
|
|
||||||
if (gc->hidden)
|
if (gc->hidden)
|
||||||
_group_show(gc);
|
group_show(sc, gc);
|
||||||
else {
|
else {
|
||||||
_group_hide(gc);
|
group_hide(sc, gc);
|
||||||
|
/* XXX wtf? */
|
||||||
if (TAILQ_EMPTY(&gc->clients))
|
if (TAILQ_EMPTY(&gc->clients))
|
||||||
Group_active = gc;
|
group_setactive(sc, idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef notyet
|
|
||||||
snprintf(buf, sizeof(buf), "Group %d", idx + 1);
|
|
||||||
screen_infomsg(buf);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define GROUP_NEXT(gc, fwd) (fwd) ? \
|
void
|
||||||
TAILQ_NEXT(gc, entry) : TAILQ_PREV(gc, group_ctx_q, entry)
|
group_only(struct screen_ctx *sc, int idx)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (idx < 0 || idx >= CALMWM_NGROUPS)
|
||||||
|
err(1, "group_only: index out of range (%d)", idx);
|
||||||
|
|
||||||
|
for (i = 0; i < CALMWM_NGROUPS; i++) {
|
||||||
|
if (i == idx)
|
||||||
|
group_show(sc, &sc->groups[i]);
|
||||||
|
else
|
||||||
|
group_hide(sc, &sc->groups[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Jump to the next/previous active group. If none exist, then just
|
* Cycle through active groups. If none exist, then just stay put.
|
||||||
* stay put.
|
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
group_slide(int fwd)
|
group_cycle(struct screen_ctx *sc, int reverse)
|
||||||
{
|
{
|
||||||
struct group_ctx *gc, *showgroup = NULL;
|
struct group_ctx *gc, *showgroup = NULL;
|
||||||
|
|
||||||
assert(Group_active != NULL);
|
assert(sc->group_active != NULL);
|
||||||
|
|
||||||
gc = Group_active;
|
gc = sc->group_active;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
gc = GROUP_NEXT(gc, fwd);
|
gc = reverse ? TAILQ_PREV(gc, group_ctx_q, entry) :
|
||||||
|
TAILQ_NEXT(gc, entry);
|
||||||
if (gc == NULL)
|
if (gc == NULL)
|
||||||
gc = fwd ? TAILQ_FIRST(&Groupq) :
|
gc = reverse ? TAILQ_LAST(&sc->groupq, group_ctx_q) :
|
||||||
TAILQ_LAST(&Groupq, group_ctx_q);
|
TAILQ_FIRST(&sc->groupq);
|
||||||
if (gc == Group_active)
|
if (gc == sc->group_active)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (!TAILQ_EMPTY(&gc->clients) && showgroup == NULL)
|
if (!TAILQ_EMPTY(&gc->clients) && showgroup == NULL)
|
||||||
showgroup = gc;
|
showgroup = gc;
|
||||||
else if (!gc->hidden)
|
else if (!gc->hidden)
|
||||||
_group_hide(gc);
|
group_hide(sc, gc);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (showgroup == NULL)
|
if (showgroup == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_group_hide(Group_active);
|
group_hide(sc, sc->group_active);
|
||||||
|
|
||||||
if (showgroup->hidden)
|
if (showgroup->hidden)
|
||||||
_group_show(showgroup);
|
group_show(sc, showgroup);
|
||||||
else
|
else
|
||||||
Group_active = showgroup;
|
group_setactive(sc, showgroup->shortcut - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* called when a client is deleted */
|
/* called when a client is deleted */
|
||||||
@@ -495,35 +350,33 @@ group_client_delete(struct client_ctx *cc)
|
|||||||
|
|
||||||
TAILQ_REMOVE(&cc->group->clients, cc, group_entry);
|
TAILQ_REMOVE(&cc->group->clients, cc, group_entry);
|
||||||
cc->group = NULL; /* he he */
|
cc->group = NULL; /* he he */
|
||||||
cc->groupcommit = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
group_menu(XButtonEvent *e)
|
group_menu(XButtonEvent *e)
|
||||||
{
|
{
|
||||||
struct menu_q menuq;
|
struct screen_ctx *sc;
|
||||||
struct menu *mi;
|
|
||||||
int i;
|
|
||||||
struct group_ctx *gc;
|
struct group_ctx *gc;
|
||||||
|
struct menu *mi;
|
||||||
|
struct menu_q menuq;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
sc = screen_fromroot(e->root);
|
||||||
TAILQ_INIT(&menuq);
|
TAILQ_INIT(&menuq);
|
||||||
|
|
||||||
for (i = 0; i < CALMWM_NGROUPS; i++) {
|
for (i = 0; i < CALMWM_NGROUPS; i++) {
|
||||||
gc = &Groups[i];
|
gc = &sc->groups[i];
|
||||||
|
|
||||||
if (TAILQ_EMPTY(&gc->clients))
|
if (TAILQ_EMPTY(&gc->clients))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (gc->name == NULL)
|
mi = xcalloc(1, sizeof(*mi));
|
||||||
gc->name = xstrdup(shortcut_to_name[gc->shortcut]);
|
|
||||||
|
|
||||||
XCALLOC(mi, struct menu);
|
|
||||||
if (gc->hidden)
|
if (gc->hidden)
|
||||||
snprintf(mi->text, sizeof(mi->text), "%d: [%s]",
|
snprintf(mi->text, sizeof(mi->text), "%d: [%s]",
|
||||||
gc->shortcut, gc->name);
|
gc->shortcut, sc->group_names[i]);
|
||||||
else
|
else
|
||||||
snprintf(mi->text, sizeof(mi->text), "%d: %s",
|
snprintf(mi->text, sizeof(mi->text), "%d: %s",
|
||||||
gc->shortcut, gc->name);
|
gc->shortcut, sc->group_names[i]);
|
||||||
mi->ctx = gc;
|
mi->ctx = gc;
|
||||||
TAILQ_INSERT_TAIL(&menuq, mi, entry);
|
TAILQ_INSERT_TAIL(&menuq, mi, entry);
|
||||||
}
|
}
|
||||||
@@ -531,19 +384,16 @@ group_menu(XButtonEvent *e)
|
|||||||
if (TAILQ_EMPTY(&menuq))
|
if (TAILQ_EMPTY(&menuq))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mi = (struct menu *)grab_menu(e, &menuq);
|
mi = menu_filter(sc, &menuq, NULL, NULL, 0, NULL, NULL);
|
||||||
|
|
||||||
if (mi == NULL || mi->ctx == NULL)
|
if (mi == NULL || mi->ctx == NULL)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
gc = (struct group_ctx *)mi->ctx;
|
gc = (struct group_ctx *)mi->ctx;
|
||||||
|
|
||||||
if (gc->hidden)
|
(gc->hidden) ? group_show(sc, gc) : group_hide(sc, gc);
|
||||||
_group_show(gc);
|
|
||||||
else
|
|
||||||
_group_hide(gc);
|
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
|
while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
|
||||||
TAILQ_REMOVE(&menuq, mi, entry);
|
TAILQ_REMOVE(&menuq, mi, entry);
|
||||||
xfree(mi);
|
xfree(mi);
|
||||||
@@ -551,74 +401,138 @@ group_menu(XButtonEvent *e)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
group_namemode(void)
|
group_alltoggle(struct screen_ctx *sc)
|
||||||
{
|
|
||||||
Groupnamemode = 1;
|
|
||||||
|
|
||||||
group_display_draw(screen_current());
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
group_alltoggle(void)
|
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i=0; i < CALMWM_NGROUPS; i++) {
|
for (i = 0; i < CALMWM_NGROUPS; i++) {
|
||||||
if (Grouphideall)
|
if (sc->group_hideall)
|
||||||
_group_show(&Groups[i]);
|
group_show(sc, &sc->groups[i]);
|
||||||
else
|
else
|
||||||
_group_hide(&Groups[i]);
|
group_hide(sc, &sc->groups[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Grouphideall)
|
sc->group_hideall = (!sc->group_hideall);
|
||||||
Grouphideall = 0;
|
|
||||||
else
|
|
||||||
Grouphideall = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
group_deletecurrent(void)
|
|
||||||
{
|
|
||||||
_group_destroy(Group_current);
|
|
||||||
XUnmapWindow(X_Dpy, screen_current()->groupwin);
|
|
||||||
|
|
||||||
Groupmode = Groupnamemode = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
group_done(void)
|
|
||||||
{
|
|
||||||
struct group_ctx *gc = Group_current;
|
|
||||||
|
|
||||||
if (gc->name != NULL)
|
|
||||||
xfree(gc->name);
|
|
||||||
|
|
||||||
gc->name = xstrdup(shortcut_to_name[gc->shortcut]);
|
|
||||||
|
|
||||||
group_exit(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
group_autogroup(struct client_ctx *cc)
|
group_autogroup(struct client_ctx *cc)
|
||||||
{
|
{
|
||||||
|
struct screen_ctx *sc = cc->sc;
|
||||||
struct autogroupwin *aw;
|
struct autogroupwin *aw;
|
||||||
struct group_ctx *gc;
|
struct group_ctx *gc;
|
||||||
char group[CALMWM_MAXNAMELEN];
|
int no = -1;
|
||||||
|
long *grpno;
|
||||||
|
|
||||||
if (cc->app_class == NULL || cc->app_name == NULL)
|
if (cc->app_class == NULL || cc->app_name == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (xu_getprop(cc->win, _NET_WM_DESKTOP, XA_CARDINAL,
|
||||||
|
1, (unsigned char **)&grpno) > 0) {
|
||||||
|
if (*grpno == 0xffffffff)
|
||||||
|
no = 0;
|
||||||
|
else if (*grpno > CALMWM_NGROUPS || *grpno < 0)
|
||||||
|
no = CALMWM_NGROUPS - 1;
|
||||||
|
else
|
||||||
|
no = *grpno + 1;
|
||||||
|
XFree(grpno);
|
||||||
|
} else {
|
||||||
TAILQ_FOREACH(aw, &Conf.autogroupq, entry) {
|
TAILQ_FOREACH(aw, &Conf.autogroupq, entry) {
|
||||||
if (strcmp(aw->class, cc->app_class) == 0 &&
|
if (strcmp(aw->class, cc->app_class) == 0 &&
|
||||||
(aw->name == NULL || strcmp(aw->name, cc->app_name) == 0)) {
|
(aw->name == NULL ||
|
||||||
strlcpy(group, aw->group, sizeof(group));
|
strcmp(aw->name, cc->app_name) == 0)) {
|
||||||
|
no = aw->num;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TAILQ_FOREACH(gc, &Groupq, entry) {
|
|
||||||
if (strcmp(shortcut_to_name[gc->shortcut], group) == 0)
|
|
||||||
_group_add(gc, cc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* no group please */
|
||||||
|
if (no == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
TAILQ_FOREACH(gc, &sc->groupq, entry) {
|
||||||
|
if (gc->shortcut == no) {
|
||||||
|
group_add(gc, cc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Conf.flags & CONF_STICKY_GROUPS)
|
||||||
|
group_add(sc->group_active, cc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
group_update_names(struct screen_ctx *sc)
|
||||||
|
{
|
||||||
|
char **strings, *p;
|
||||||
|
unsigned char *prop_ret;
|
||||||
|
Atom type_ret;
|
||||||
|
int format_ret, i = 0, nstrings = 0, n, setnames = 0;
|
||||||
|
unsigned long bytes_after, num_ret;
|
||||||
|
|
||||||
|
if (XGetWindowProperty(X_Dpy, sc->rootwin, _NET_DESKTOP_NAMES, 0,
|
||||||
|
0xffffff, False, UTF8_STRING, &type_ret, &format_ret,
|
||||||
|
&num_ret, &bytes_after, &prop_ret) == Success &&
|
||||||
|
prop_ret != NULL && format_ret == 8) {
|
||||||
|
/* failure, just set defaults */
|
||||||
|
prop_ret[num_ret - 1] = '\0'; /* paranoia */
|
||||||
|
while (i < num_ret) {
|
||||||
|
if (prop_ret[i++] == '\0')
|
||||||
|
nstrings++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
strings = xmalloc((nstrings < CALMWM_NGROUPS ? CALMWM_NGROUPS :
|
||||||
|
nstrings) * sizeof(*strings));
|
||||||
|
|
||||||
|
i = n = 0;
|
||||||
|
p = prop_ret;
|
||||||
|
while (n < nstrings) {
|
||||||
|
strings[n++] = xstrdup(p);
|
||||||
|
p += strlen(p) + 1;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* make sure we always set our defaults if nothing is there to
|
||||||
|
* replace them.
|
||||||
|
*/
|
||||||
|
if (n < CALMWM_NGROUPS) {
|
||||||
|
setnames = 1;
|
||||||
|
i = 1;
|
||||||
|
while (n < CALMWM_NGROUPS)
|
||||||
|
strings[n++] = xstrdup(shortcut_to_name[i++]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prop_ret != NULL)
|
||||||
|
XFree(prop_ret);
|
||||||
|
if (sc->group_nonames != 0)
|
||||||
|
free(sc->group_names);
|
||||||
|
|
||||||
|
sc->group_names = strings;
|
||||||
|
sc->group_nonames = n;
|
||||||
|
if (setnames)
|
||||||
|
group_set_names(sc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
group_set_names(struct screen_ctx *sc)
|
||||||
|
{
|
||||||
|
unsigned char *p, *q;
|
||||||
|
size_t len = 0, tlen, slen;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < sc->group_nonames; i++)
|
||||||
|
len += strlen(sc->group_names[i]) + 1;
|
||||||
|
q = p = xcalloc(len, sizeof(*p));
|
||||||
|
|
||||||
|
tlen = len;
|
||||||
|
for (i = 0; i < sc->group_nonames; i++) {
|
||||||
|
slen = strlen(sc->group_names[i]) + 1;
|
||||||
|
strlcpy(q, sc->group_names[i], tlen);
|
||||||
|
tlen -= slen;
|
||||||
|
q += slen;
|
||||||
|
}
|
||||||
|
|
||||||
|
XChangeProperty(X_Dpy, sc->rootwin, _NET_DESKTOP_NAMES,
|
||||||
|
UTF8_STRING, 8, PropModeReplace, p, len);
|
||||||
}
|
}
|
||||||
|
68
hash.h
68
hash.h
@@ -1,68 +0,0 @@
|
|||||||
/*
|
|
||||||
* hash.h - generic hash template, akin to queue.h & tree.h
|
|
||||||
*
|
|
||||||
* Copyright (c) 2005 Marius Eriksen <marius@monkey.org>
|
|
||||||
*
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
|
||||||
* copyright notice and this permission notice appear in all copies.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _HASH_H_ /* Possibly this is too generic. */
|
|
||||||
#define _HASH_H_
|
|
||||||
|
|
||||||
#include <sys/tree.h>
|
|
||||||
|
|
||||||
#define HASH_ENTRY SPLAY_ENTRY
|
|
||||||
|
|
||||||
#define HASH_HEAD(name, type, nbuckets) \
|
|
||||||
SPLAY_HEAD(name##_HASH_TREE, type); \
|
|
||||||
struct name { \
|
|
||||||
struct name##_HASH_TREE buckets[nbuckets]; \
|
|
||||||
unsigned int (*hashfn)(struct type *elm); \
|
|
||||||
};
|
|
||||||
|
|
||||||
#define HASH_NBUCKETS(head) \
|
|
||||||
(sizeof((head)->buckets)/sizeof((head)->buckets[0]))
|
|
||||||
|
|
||||||
#define HASH_INIT(head, fn) do { \
|
|
||||||
int i; \
|
|
||||||
for (i = 0; i < HASH_NBUCKETS(head); i++) { \
|
|
||||||
SPLAY_INIT(&(head)->buckets[i]); \
|
|
||||||
} \
|
|
||||||
(head)->hashfn = fn; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define HASH_PROTOTYPE(name, type, field, cmp) \
|
|
||||||
SPLAY_PROTOTYPE(name##_HASH_TREE, type, field, cmp) \
|
|
||||||
struct type *name##_HASH_TREE_FIND(struct name *head, struct type *find); \
|
|
||||||
void name##_HASH_TREE_INSERT(struct name *head, struct type *insert);
|
|
||||||
|
|
||||||
#define HASH_GENERATE(name, type, field, cmp) \
|
|
||||||
SPLAY_GENERATE(name##_HASH_TREE, type, field, cmp) \
|
|
||||||
struct type *name##_HASH_TREE_FIND(struct name *head, struct type *find) \
|
|
||||||
{ \
|
|
||||||
struct name##_HASH_TREE *bucket = \
|
|
||||||
&head->buckets[(*head->hashfn)(find) % HASH_NBUCKETS(head)]; \
|
|
||||||
return SPLAY_FIND(name##_HASH_TREE, bucket, find); \
|
|
||||||
} \
|
|
||||||
void name##_HASH_TREE_INSERT(struct name *head, struct type *insert) \
|
|
||||||
{ \
|
|
||||||
struct name##_HASH_TREE *bucket = \
|
|
||||||
&head->buckets[(*head->hashfn)(insert) % HASH_NBUCKETS(head)]; \
|
|
||||||
\
|
|
||||||
SPLAY_INSERT(name##_HASH_TREE, bucket, insert); \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define HASH_FIND(name, head, find) name##_HASH_TREE_FIND((head), (find))
|
|
||||||
#define HASH_INSERT(name, head, insert) name##_HASH_TREE_INSERT((head), (insert))
|
|
||||||
|
|
||||||
#endif /* _HASH_H_ */
|
|
55
headers.h
55
headers.h
@@ -1,55 +0,0 @@
|
|||||||
/*
|
|
||||||
* calmwm - the calm window manager
|
|
||||||
*
|
|
||||||
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
|
|
||||||
*
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
|
||||||
* copyright notice and this permission notice appear in all copies.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*
|
|
||||||
* $Id$
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _CALMWM_HEADERS_H_
|
|
||||||
#define _CALMWM_HEADERS_H_
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
#include <sys/queue.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
#include <sys/param.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <dirent.h>
|
|
||||||
#include <getopt.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
|
|
||||||
#include <X11/cursorfont.h>
|
|
||||||
#include <X11/extensions/shape.h>
|
|
||||||
#include <X11/Xlib.h>
|
|
||||||
#include <X11/Xutil.h>
|
|
||||||
#include <X11/keysym.h>
|
|
||||||
#include <X11/Xatom.h>
|
|
||||||
#include <X11/Xproto.h>
|
|
||||||
#include <X11/Intrinsic.h>
|
|
||||||
#include <X11/Xos.h>
|
|
||||||
#include <X11/Xft/Xft.h>
|
|
||||||
|
|
||||||
#include <err.h>
|
|
||||||
|
|
||||||
#endif /* _CALMWM_HEADERS_H_ */
|
|
40
input.c
40
input.c
@@ -18,22 +18,27 @@
|
|||||||
* $Id$
|
* $Id$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "headers.h"
|
#include <sys/param.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
|
|
||||||
|
#include <err.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "calmwm.h"
|
#include "calmwm.h"
|
||||||
|
|
||||||
int
|
int
|
||||||
input_keycodetrans(KeyCode kc, u_int state,
|
input_keycodetrans(KeyCode kc, u_int state, enum ctltype *ctl, char *chr)
|
||||||
enum ctltype *ctl, char *chr, int normalize)
|
|
||||||
{
|
{
|
||||||
int ks;
|
int ks;
|
||||||
|
|
||||||
*ctl = CTL_NONE;
|
*ctl = CTL_NONE;
|
||||||
*chr = '\0';
|
*chr = '\0';
|
||||||
|
|
||||||
if (state & ShiftMask)
|
ks = XKeycodeToKeysym(X_Dpy, kc, (state & ShiftMask) ? 1 : 0);
|
||||||
ks = XKeycodeToKeysym(X_Dpy, kc, 1);
|
|
||||||
else
|
|
||||||
ks = XKeycodeToKeysym(X_Dpy, kc, 0);
|
|
||||||
|
|
||||||
/* Look for control characters. */
|
/* Look for control characters. */
|
||||||
switch (ks) {
|
switch (ks) {
|
||||||
@@ -70,6 +75,10 @@ input_keycodetrans(KeyCode kc, u_int state,
|
|||||||
case XK_U:
|
case XK_U:
|
||||||
*ctl = CTL_WIPE;
|
*ctl = CTL_WIPE;
|
||||||
break;
|
break;
|
||||||
|
case XK_h:
|
||||||
|
case XK_H:
|
||||||
|
*ctl = CTL_ERASEONE;
|
||||||
|
break;
|
||||||
case XK_a:
|
case XK_a:
|
||||||
case XK_A:
|
case XK_A:
|
||||||
*ctl = CTL_ALL;
|
*ctl = CTL_ALL;
|
||||||
@@ -77,6 +86,21 @@ input_keycodetrans(KeyCode kc, u_int state,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (*ctl == CTL_NONE && (state & Mod1Mask)) {
|
||||||
|
switch (ks) {
|
||||||
|
case XK_j:
|
||||||
|
case XK_J:
|
||||||
|
/* Vi "down" */
|
||||||
|
*ctl = CTL_DOWN;
|
||||||
|
break;
|
||||||
|
case XK_k:
|
||||||
|
case XK_K:
|
||||||
|
/* Vi "up" */
|
||||||
|
*ctl = CTL_UP;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (*ctl != CTL_NONE)
|
if (*ctl != CTL_NONE)
|
||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
@@ -88,8 +112,6 @@ input_keycodetrans(KeyCode kc, u_int state,
|
|||||||
return (-1);
|
return (-1);
|
||||||
|
|
||||||
*chr = (char)ks;
|
*chr = (char)ks;
|
||||||
if (normalize)
|
|
||||||
*chr = tolower(*chr);
|
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
405
kbfunc.c
405
kbfunc.c
@@ -18,126 +18,58 @@
|
|||||||
* $Id$
|
* $Id$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <paths.h>
|
#include <sys/param.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
|
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <err.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <paths.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "headers.h"
|
|
||||||
#include "calmwm.h"
|
#include "calmwm.h"
|
||||||
|
|
||||||
#define KNOWN_HOSTS ".ssh/known_hosts"
|
#define KNOWN_HOSTS ".ssh/known_hosts"
|
||||||
#define HASH_MARKER "|1|"
|
#define HASH_MARKER "|1|"
|
||||||
#define MOVE_AMOUNT 1
|
|
||||||
|
extern int _xev_quit;
|
||||||
|
|
||||||
void
|
void
|
||||||
kbfunc_client_lower(struct client_ctx *cc, void *arg)
|
kbfunc_client_lower(struct client_ctx *cc, union arg *arg)
|
||||||
{
|
{
|
||||||
client_lower(cc);
|
client_lower(cc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
kbfunc_client_raise(struct client_ctx *cc, void *arg)
|
kbfunc_client_raise(struct client_ctx *cc, union arg *arg)
|
||||||
{
|
{
|
||||||
client_raise(cc);
|
client_raise(cc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define typemask (CWM_MOVE | CWM_RESIZE | CWM_PTRMOVE)
|
||||||
|
#define movemask (CWM_UP | CWM_DOWN | CWM_LEFT | CWM_RIGHT)
|
||||||
void
|
void
|
||||||
kbfunc_client_move(struct client_ctx *cc, void *arg)
|
kbfunc_moveresize(struct client_ctx *cc, union arg *arg)
|
||||||
{
|
{
|
||||||
int x,y,flags,amt;
|
struct screen_ctx *sc;
|
||||||
u_int mx,my;
|
int x, y, flags, amt;
|
||||||
|
u_int mx, my;
|
||||||
|
|
||||||
|
sc = cc->sc;
|
||||||
mx = my = 0;
|
mx = my = 0;
|
||||||
|
|
||||||
flags = (int)arg;
|
flags = arg->i;
|
||||||
amt = MOVE_AMOUNT;
|
amt = Conf.mamount;
|
||||||
|
|
||||||
if (flags & CWM_BIGMOVE) {
|
|
||||||
flags -= CWM_BIGMOVE;
|
|
||||||
amt = amt*10;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(flags) {
|
|
||||||
case CWM_UP:
|
|
||||||
my -= amt;
|
|
||||||
break;
|
|
||||||
case CWM_DOWN:
|
|
||||||
my += amt;
|
|
||||||
break;
|
|
||||||
case CWM_RIGHT:
|
|
||||||
mx += amt;
|
|
||||||
break;
|
|
||||||
case CWM_LEFT:
|
|
||||||
mx -= amt;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
cc->geom.y += my;
|
|
||||||
cc->geom.x += mx;
|
|
||||||
client_move(cc);
|
|
||||||
xu_ptr_getpos(cc->pwin, &x, &y);
|
|
||||||
cc->ptr.y = y + my;
|
|
||||||
cc->ptr.x = x + mx;
|
|
||||||
client_ptrwarp(cc);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
kbfunc_client_resize(struct client_ctx *cc, void *arg)
|
|
||||||
{
|
|
||||||
int flags,mx,my;
|
|
||||||
u_int amt;
|
|
||||||
|
|
||||||
mx = my = 0;
|
|
||||||
|
|
||||||
flags = (int)arg;
|
|
||||||
amt = MOVE_AMOUNT;
|
|
||||||
|
|
||||||
if (flags & CWM_BIGMOVE) {
|
|
||||||
flags -= CWM_BIGMOVE;
|
|
||||||
amt = amt*10;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(flags) {
|
|
||||||
case CWM_UP:
|
|
||||||
my -= amt;
|
|
||||||
break;
|
|
||||||
case CWM_DOWN:
|
|
||||||
my += amt;
|
|
||||||
break;
|
|
||||||
case CWM_RIGHT:
|
|
||||||
mx += amt;
|
|
||||||
break;
|
|
||||||
case CWM_LEFT:
|
|
||||||
mx -= amt;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
cc->geom.height += my;
|
|
||||||
cc->geom.width += mx;
|
|
||||||
client_resize(cc);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Moving the cursor while resizing is problematic. Just place
|
|
||||||
* it in the middle of the window.
|
|
||||||
*/
|
|
||||||
cc->ptr.x = -1;
|
|
||||||
cc->ptr.y = -1;
|
|
||||||
client_ptrwarp(cc);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
kbfunc_ptrmove(struct client_ctx *cc, void *arg)
|
|
||||||
{
|
|
||||||
int px,py,mx,my,flags,amt;
|
|
||||||
struct screen_ctx *sc = screen_current();
|
|
||||||
my = mx = 0;
|
|
||||||
|
|
||||||
flags = (int)arg;
|
|
||||||
amt = MOVE_AMOUNT;
|
|
||||||
|
|
||||||
if (flags & CWM_BIGMOVE) {
|
if (flags & CWM_BIGMOVE) {
|
||||||
flags -= CWM_BIGMOVE;
|
flags -= CWM_BIGMOVE;
|
||||||
amt = amt * 10;
|
amt = amt * 10;
|
||||||
}
|
}
|
||||||
switch(flags) {
|
|
||||||
|
switch (flags & movemask) {
|
||||||
case CWM_UP:
|
case CWM_UP:
|
||||||
my -= amt;
|
my -= amt;
|
||||||
break;
|
break;
|
||||||
@@ -151,35 +83,77 @@ kbfunc_ptrmove(struct client_ctx *cc, void *arg)
|
|||||||
mx -= amt;
|
mx -= amt;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
switch (flags & typemask) {
|
||||||
|
case CWM_MOVE:
|
||||||
|
cc->geom.y += my;
|
||||||
|
if (cc->geom.y + cc->geom.height < 0)
|
||||||
|
cc->geom.y = -cc->geom.height;
|
||||||
|
if (cc->geom.y > cc->sc->ymax - 1)
|
||||||
|
cc->geom.y = cc->sc->ymax - 1;
|
||||||
|
|
||||||
|
cc->geom.x += mx;
|
||||||
|
if (cc->geom.x + cc->geom.width < 0)
|
||||||
|
cc->geom.x = -cc->geom.width;
|
||||||
|
if (cc->geom.x > cc->sc->xmax - 1)
|
||||||
|
cc->geom.x = cc->sc->xmax - 1;
|
||||||
|
|
||||||
|
client_move(cc);
|
||||||
|
xu_ptr_getpos(cc->win, &x, &y);
|
||||||
|
cc->ptr.y = y + my;
|
||||||
|
cc->ptr.x = x + mx;
|
||||||
|
client_ptrwarp(cc);
|
||||||
|
break;
|
||||||
|
case CWM_RESIZE:
|
||||||
|
if ((cc->geom.height += my) < 1)
|
||||||
|
cc->geom.height = 1;
|
||||||
|
if ((cc->geom.width += mx) < 1)
|
||||||
|
cc->geom.width = 1;
|
||||||
|
client_resize(cc);
|
||||||
|
|
||||||
|
/* Make sure the pointer stays within the window. */
|
||||||
|
xu_ptr_getpos(cc->win, &cc->ptr.x, &cc->ptr.y);
|
||||||
|
if (cc->ptr.x > cc->geom.width)
|
||||||
|
cc->ptr.x = cc->geom.width - cc->bwidth;
|
||||||
|
if (cc->ptr.y > cc->geom.height)
|
||||||
|
cc->ptr.y = cc->geom.height - cc->bwidth;
|
||||||
|
client_ptrwarp(cc);
|
||||||
|
break;
|
||||||
|
case CWM_PTRMOVE:
|
||||||
if (cc) {
|
if (cc) {
|
||||||
xu_ptr_getpos(cc->pwin, &px, &py);
|
xu_ptr_getpos(cc->win, &x, &y);
|
||||||
xu_ptr_setpos(cc->pwin, px + mx, py + my);
|
xu_ptr_setpos(cc->win, x + mx, y + my);
|
||||||
} else {
|
} else {
|
||||||
xu_ptr_getpos(sc->rootwin, &px, &py);
|
xu_ptr_getpos(sc->rootwin, &x, &y);
|
||||||
xu_ptr_setpos(sc->rootwin, px + mx, py + my);
|
xu_ptr_setpos(sc->rootwin, x + mx, y + my);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
warnx("invalid flags passed to kbfunc_client_moveresize");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
kbfunc_client_search(struct client_ctx *scratch, void *arg)
|
kbfunc_client_search(struct client_ctx *cc, union arg *arg)
|
||||||
{
|
{
|
||||||
struct menu_q menuq;
|
struct screen_ctx *sc;
|
||||||
struct client_ctx *cc, *old_cc = client_current();
|
struct client_ctx *old_cc;
|
||||||
struct menu *mi;
|
struct menu *mi;
|
||||||
|
struct menu_q menuq;
|
||||||
|
|
||||||
|
sc = cc->sc;
|
||||||
|
old_cc = client_current();
|
||||||
|
|
||||||
TAILQ_INIT(&menuq);
|
TAILQ_INIT(&menuq);
|
||||||
|
|
||||||
TAILQ_FOREACH(cc, &Clientq, entry) {
|
TAILQ_FOREACH(cc, &Clientq, entry) {
|
||||||
XCALLOC(mi, struct menu);
|
mi = xcalloc(1, sizeof(*mi));
|
||||||
strlcpy(mi->text, cc->name, sizeof(mi->text));
|
strlcpy(mi->text, cc->name, sizeof(mi->text));
|
||||||
mi->ctx = cc;
|
mi->ctx = cc;
|
||||||
TAILQ_INSERT_TAIL(&menuq, mi, entry);
|
TAILQ_INSERT_TAIL(&menuq, mi, entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((mi = search_start(&menuq,
|
if ((mi = menu_filter(sc, &menuq, "window", NULL, 0,
|
||||||
search_match_client, NULL,
|
search_match_client, search_print_client)) != NULL) {
|
||||||
search_print_client, "window", 0)) != NULL) {
|
|
||||||
cc = (struct client_ctx *)mi->ctx;
|
cc = (struct client_ctx *)mi->ctx;
|
||||||
if (cc->flags & CLIENT_HIDDEN)
|
if (cc->flags & CLIENT_HIDDEN)
|
||||||
client_unhide(cc);
|
client_unhide(cc);
|
||||||
@@ -196,24 +170,25 @@ kbfunc_client_search(struct client_ctx *scratch, void *arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
kbfunc_menu_search(struct client_ctx *scratch, void *arg)
|
kbfunc_menu_search(struct client_ctx *cc, union arg *arg)
|
||||||
{
|
{
|
||||||
struct menu_q menuq;
|
struct screen_ctx *sc;
|
||||||
struct menu *mi;
|
|
||||||
struct cmd *cmd;
|
struct cmd *cmd;
|
||||||
|
struct menu *mi;
|
||||||
|
struct menu_q menuq;
|
||||||
|
|
||||||
|
sc = cc->sc;
|
||||||
TAILQ_INIT(&menuq);
|
TAILQ_INIT(&menuq);
|
||||||
|
|
||||||
conf_cmd_refresh(&Conf);
|
|
||||||
TAILQ_FOREACH(cmd, &Conf.cmdq, entry) {
|
TAILQ_FOREACH(cmd, &Conf.cmdq, entry) {
|
||||||
XCALLOC(mi, struct menu);
|
mi = xcalloc(1, sizeof(*mi));
|
||||||
strlcpy(mi->text, cmd->label, sizeof(mi->text));
|
strlcpy(mi->text, cmd->label, sizeof(mi->text));
|
||||||
mi->ctx = cmd;
|
mi->ctx = cmd;
|
||||||
TAILQ_INSERT_TAIL(&menuq, mi, entry);
|
TAILQ_INSERT_TAIL(&menuq, mi, entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((mi = search_start(&menuq,
|
if ((mi = menu_filter(sc, &menuq, "application", NULL, 0,
|
||||||
search_match_text, NULL, NULL, "application", 0)) != NULL)
|
search_match_text, NULL)) != NULL)
|
||||||
u_spawn(((struct cmd *)mi->ctx)->image);
|
u_spawn(((struct cmd *)mi->ctx)->image);
|
||||||
|
|
||||||
while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
|
while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
|
||||||
@@ -223,60 +198,58 @@ kbfunc_menu_search(struct client_ctx *scratch, void *arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
kbfunc_client_cycle(struct client_ctx *scratch, void *arg)
|
kbfunc_client_cycle(struct client_ctx *cc, union arg *arg)
|
||||||
{
|
{
|
||||||
client_cyclenext(0);
|
struct screen_ctx *sc;
|
||||||
|
|
||||||
|
sc = cc->sc;
|
||||||
|
|
||||||
|
/* XXX for X apps that ignore events */
|
||||||
|
XGrabKeyboard(X_Dpy, sc->rootwin, True,
|
||||||
|
GrabModeAsync, GrabModeAsync, CurrentTime);
|
||||||
|
|
||||||
|
client_cycle(sc, arg->i);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
kbfunc_client_rcycle(struct client_ctx *scratch, void *arg)
|
kbfunc_client_hide(struct client_ctx *cc, union arg *arg)
|
||||||
{
|
|
||||||
client_cyclenext(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
kbfunc_client_hide(struct client_ctx *cc, void *arg)
|
|
||||||
{
|
{
|
||||||
client_hide(cc);
|
client_hide(cc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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
|
void
|
||||||
kbfunc_term(struct client_ctx *cc, void *arg)
|
kbfunc_term(struct client_ctx *cc, union arg *arg)
|
||||||
{
|
{
|
||||||
conf_cmd_refresh(&Conf);
|
|
||||||
u_spawn(Conf.termpath);
|
u_spawn(Conf.termpath);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
kbfunc_lock(struct client_ctx *cc, void *arg)
|
kbfunc_lock(struct client_ctx *cc, union arg *arg)
|
||||||
{
|
{
|
||||||
conf_cmd_refresh(&Conf);
|
|
||||||
u_spawn(Conf.lockpath);
|
u_spawn(Conf.lockpath);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
kbfunc_exec(struct client_ctx *scratch, void *arg)
|
kbfunc_exec(struct client_ctx *cc, union arg *arg)
|
||||||
{
|
{
|
||||||
#define NPATHS 256
|
#define NPATHS 256
|
||||||
char **ap, *paths[NPATHS], *path, tpath[MAXPATHLEN];
|
struct screen_ctx *sc;
|
||||||
int l, i, j, ngroups;
|
char **ap, *paths[NPATHS], *path, *pathcpy, *label;
|
||||||
gid_t mygroups[NGROUPS_MAX];
|
char tpath[MAXPATHLEN];
|
||||||
uid_t ruid, euid, suid;
|
|
||||||
DIR *dirp;
|
DIR *dirp;
|
||||||
struct dirent *dp;
|
struct dirent *dp;
|
||||||
struct stat sb;
|
|
||||||
struct menu_q menuq;
|
|
||||||
struct menu *mi;
|
struct menu *mi;
|
||||||
char *label;
|
struct menu_q menuq;
|
||||||
|
int l, i, cmd = arg->i;
|
||||||
|
|
||||||
int cmd = (int)arg;
|
sc = cc->sc;
|
||||||
switch(cmd) {
|
switch (cmd) {
|
||||||
case CWM_EXEC_PROGRAM:
|
case CWM_EXEC_PROGRAM:
|
||||||
label = "exec";
|
label = "exec";
|
||||||
break;
|
break;
|
||||||
@@ -288,16 +261,14 @@ kbfunc_exec(struct client_ctx *scratch, void *arg)
|
|||||||
/*NOTREACHED*/
|
/*NOTREACHED*/
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getgroups(0, mygroups) == -1)
|
|
||||||
err(1, "getgroups failure");
|
|
||||||
if ((ngroups = getresuid(&ruid, &euid, &suid)) == -1)
|
|
||||||
err(1, "getresuid failure");
|
|
||||||
|
|
||||||
TAILQ_INIT(&menuq);
|
TAILQ_INIT(&menuq);
|
||||||
/* just use default path until we have config to set this */
|
|
||||||
path = xstrdup(_PATH_DEFPATH);
|
if ((path = getenv("PATH")) == NULL)
|
||||||
|
path = _PATH_DEFPATH;
|
||||||
|
pathcpy = path = xstrdup(path);
|
||||||
|
|
||||||
for (ap = paths; ap < &paths[NPATHS - 1] &&
|
for (ap = paths; ap < &paths[NPATHS - 1] &&
|
||||||
(*ap = strsep(&path, ":")) != NULL;) {
|
(*ap = strsep(&pathcpy, ":")) != NULL;) {
|
||||||
if (**ap != '\0')
|
if (**ap != '\0')
|
||||||
ap++;
|
ap++;
|
||||||
}
|
}
|
||||||
@@ -316,67 +287,56 @@ kbfunc_exec(struct client_ctx *scratch, void *arg)
|
|||||||
/* check for truncation etc */
|
/* check for truncation etc */
|
||||||
if (l == -1 || l >= (int)sizeof(tpath))
|
if (l == -1 || l >= (int)sizeof(tpath))
|
||||||
continue;
|
continue;
|
||||||
/* just ignore on stat failure */
|
if (access(tpath, X_OK) == 0) {
|
||||||
if (stat(tpath, &sb) == -1)
|
mi = xcalloc(1, sizeof(*mi));
|
||||||
continue;
|
|
||||||
/* may we execute this file? */
|
|
||||||
if (euid == sb.st_uid)
|
|
||||||
if (sb.st_mode & S_IXUSR)
|
|
||||||
goto executable;
|
|
||||||
else
|
|
||||||
continue;
|
|
||||||
for (j = 0; j < ngroups; j++)
|
|
||||||
if (mygroups[j] == sb.st_gid)
|
|
||||||
if (sb.st_mode & S_IXGRP)
|
|
||||||
goto executable;
|
|
||||||
else
|
|
||||||
continue;
|
|
||||||
if (sb.st_mode & S_IXOTH)
|
|
||||||
goto executable;
|
|
||||||
continue;
|
|
||||||
executable:
|
|
||||||
/* the thing in tpath, we may execute */
|
|
||||||
XCALLOC(mi, struct menu);
|
|
||||||
strlcpy(mi->text, dp->d_name, sizeof(mi->text));
|
strlcpy(mi->text, dp->d_name, sizeof(mi->text));
|
||||||
TAILQ_INSERT_TAIL(&menuq, mi, entry);
|
TAILQ_INSERT_TAIL(&menuq, mi, entry);
|
||||||
}
|
}
|
||||||
(void) closedir(dirp);
|
|
||||||
}
|
}
|
||||||
|
(void)closedir(dirp);
|
||||||
|
}
|
||||||
|
xfree(path);
|
||||||
|
|
||||||
if ((mi = search_start(&menuq,
|
if ((mi = menu_filter(sc, &menuq, label, NULL, 1,
|
||||||
search_match_exec, NULL, NULL, label, 1)) != NULL) {
|
search_match_exec, NULL)) != NULL) {
|
||||||
|
if (mi->text[0] == '\0')
|
||||||
|
goto out;
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case CWM_EXEC_PROGRAM:
|
case CWM_EXEC_PROGRAM:
|
||||||
u_spawn(mi->text);
|
u_spawn(mi->text);
|
||||||
break;
|
break;
|
||||||
case CWM_EXEC_WM:
|
case CWM_EXEC_WM:
|
||||||
exec_wm(mi->text);
|
u_exec(mi->text);
|
||||||
|
warn("%s", mi->text);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
err(1, "kb_func: egad, cmd changed value!");
|
err(1, "kb_func: egad, cmd changed value!");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
out:
|
||||||
if (mi != NULL && mi->dummy)
|
if (mi != NULL && mi->dummy)
|
||||||
xfree(mi);
|
xfree(mi);
|
||||||
while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
|
while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
|
||||||
TAILQ_REMOVE(&menuq, mi, entry);
|
TAILQ_REMOVE(&menuq, mi, entry);
|
||||||
xfree(mi);
|
xfree(mi);
|
||||||
}
|
}
|
||||||
xfree(path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
kbfunc_ssh(struct client_ctx *scratch, void *arg)
|
kbfunc_ssh(struct client_ctx *cc, union arg *arg)
|
||||||
{
|
{
|
||||||
struct menu_q menuq;
|
struct screen_ctx *sc;
|
||||||
struct menu *mi;
|
struct menu *mi;
|
||||||
|
struct menu_q menuq;
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
size_t len;
|
|
||||||
char *buf, *lbuf, *p, *home;
|
char *buf, *lbuf, *p, *home;
|
||||||
char hostbuf[MAXHOSTNAMELEN], filename[MAXPATHLEN], cmd[256];
|
char hostbuf[MAXHOSTNAMELEN], filename[MAXPATHLEN];
|
||||||
|
char cmd[256];
|
||||||
int l;
|
int l;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
sc = cc->sc;
|
||||||
|
|
||||||
if ((home = getenv("HOME")) == NULL)
|
if ((home = getenv("HOME")) == NULL)
|
||||||
return;
|
return;
|
||||||
@@ -410,23 +370,23 @@ kbfunc_ssh(struct client_ctx *scratch, void *arg)
|
|||||||
if (p - buf + 1 > sizeof(hostbuf))
|
if (p - buf + 1 > sizeof(hostbuf))
|
||||||
continue;
|
continue;
|
||||||
(void) strlcpy(hostbuf, buf, p - buf + 1);
|
(void) strlcpy(hostbuf, buf, p - buf + 1);
|
||||||
XCALLOC(mi, struct menu);
|
mi = xcalloc(1, sizeof(*mi));
|
||||||
(void) strlcpy(mi->text, hostbuf, sizeof(mi->text));
|
(void) strlcpy(mi->text, hostbuf, sizeof(mi->text));
|
||||||
TAILQ_INSERT_TAIL(&menuq, mi, entry);
|
TAILQ_INSERT_TAIL(&menuq, mi, entry);
|
||||||
}
|
}
|
||||||
xfree(lbuf);
|
xfree(lbuf);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
|
if ((mi = menu_filter(sc, &menuq, "ssh", NULL, 1,
|
||||||
if ((mi = search_start(&menuq,
|
search_match_exec, NULL)) != NULL) {
|
||||||
search_match_exec, NULL, NULL, "ssh", 1)) != NULL) {
|
if (mi->text[0] == '\0')
|
||||||
conf_cmd_refresh(&Conf);
|
goto out;
|
||||||
l = snprintf(cmd, sizeof(cmd), "%s -e ssh %s", Conf.termpath,
|
l = snprintf(cmd, sizeof(cmd), "%s -e ssh %s", Conf.termpath,
|
||||||
mi->text);
|
mi->text);
|
||||||
if (l != -1 && l < sizeof(cmd))
|
if (l != -1 && l < sizeof(cmd))
|
||||||
u_spawn(cmd);
|
u_spawn(cmd);
|
||||||
}
|
}
|
||||||
|
out:
|
||||||
if (mi != NULL && mi->dummy)
|
if (mi != NULL && mi->dummy)
|
||||||
xfree(mi);
|
xfree(mi);
|
||||||
while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
|
while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
|
||||||
@@ -436,64 +396,97 @@ kbfunc_ssh(struct client_ctx *scratch, void *arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
kbfunc_client_label(struct client_ctx *cc, void *arg)
|
kbfunc_client_label(struct client_ctx *cc, union arg *arg)
|
||||||
{
|
{
|
||||||
grab_label(cc);
|
struct menu *mi;
|
||||||
|
struct menu_q menuq;
|
||||||
|
|
||||||
|
TAILQ_INIT(&menuq);
|
||||||
|
|
||||||
|
/* dummy is set, so this will always return */
|
||||||
|
mi = menu_filter(cc->sc, &menuq, "label", cc->label, 1,
|
||||||
|
search_match_text, NULL);
|
||||||
|
|
||||||
|
if (!mi->abort) {
|
||||||
|
if (cc->label != NULL)
|
||||||
|
xfree(cc->label);
|
||||||
|
cc->label = xstrdup(mi->text);
|
||||||
|
}
|
||||||
|
xfree(mi);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
kbfunc_client_delete(struct client_ctx *cc, void *arg)
|
kbfunc_client_delete(struct client_ctx *cc, union arg *arg)
|
||||||
{
|
{
|
||||||
client_send_delete(cc);
|
client_send_delete(cc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
kbfunc_client_groupselect(struct client_ctx *cc, void *arg)
|
kbfunc_client_group(struct client_ctx *cc, union arg *arg)
|
||||||
{
|
{
|
||||||
if (Groupmode)
|
group_hidetoggle(cc->sc, KBTOGROUP(arg->i));
|
||||||
group_done();
|
|
||||||
else
|
|
||||||
group_enter();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
kbfunc_client_group(struct client_ctx *cc, void *arg)
|
kbfunc_client_grouponly(struct client_ctx *cc, union arg *arg)
|
||||||
{
|
{
|
||||||
if (Groupmode)
|
group_only(cc->sc, KBTOGROUP(arg->i));
|
||||||
group_select(KBTOGROUP((int)arg));
|
|
||||||
else
|
|
||||||
group_hidetoggle(KBTOGROUP((int)arg));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
kbfunc_client_nextgroup(struct client_ctx *cc, void *arg)
|
kbfunc_client_cyclegroup(struct client_ctx *cc, union arg *arg)
|
||||||
{
|
{
|
||||||
group_slide(1);
|
group_cycle(cc->sc, arg->i);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
kbfunc_client_prevgroup(struct client_ctx *cc, void *arg)
|
kbfunc_client_nogroup(struct client_ctx *cc, union arg *arg)
|
||||||
{
|
{
|
||||||
group_slide(0);
|
group_alltoggle(cc->sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
kbfunc_client_nogroup(struct client_ctx *cc, void *arg)
|
kbfunc_client_grouptoggle(struct client_ctx *cc, union arg *arg)
|
||||||
{
|
{
|
||||||
if (Groupmode)
|
/* XXX for stupid X apps like xpdf and gvim */
|
||||||
group_deletecurrent();
|
XGrabKeyboard(X_Dpy, cc->win, True,
|
||||||
else
|
GrabModeAsync, GrabModeAsync, CurrentTime);
|
||||||
group_alltoggle();
|
|
||||||
|
group_sticky_toggle_enter(cc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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);
|
client_maximize(cc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
kbfunc_client_vmaximize(struct client_ctx *cc, void *arg)
|
kbfunc_client_vmaximize(struct client_ctx *cc, union arg *arg)
|
||||||
{
|
{
|
||||||
client_vertmaximize(cc);
|
client_vertmaximize(cc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
kbfunc_client_hmaximize(struct client_ctx *cc, union arg *arg)
|
||||||
|
{
|
||||||
|
client_horizmaximize(cc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
kbfunc_quit_wm(struct client_ctx *cc, union arg *arg)
|
||||||
|
{
|
||||||
|
_xev_quit = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
kbfunc_reload(struct client_ctx *cc, union arg *arg)
|
||||||
|
{
|
||||||
|
conf_reload(&Conf);
|
||||||
|
}
|
||||||
|
418
menu.c
Normal file
418
menu.c
Normal file
@@ -0,0 +1,418 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2008 Owain G. Ainsworth <oga@openbsd.org>
|
||||||
|
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
|
|
||||||
|
#include <err.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "calmwm.h"
|
||||||
|
|
||||||
|
#define PROMPT_SCHAR '<27>'
|
||||||
|
#define PROMPT_ECHAR '<27>'
|
||||||
|
|
||||||
|
struct menu_ctx {
|
||||||
|
char searchstr[MENU_MAXENTRY + 1];
|
||||||
|
char dispstr[MENU_MAXENTRY*2 + 1];
|
||||||
|
char promptstr[MENU_MAXENTRY + 1];
|
||||||
|
int hasprompt;
|
||||||
|
int list;
|
||||||
|
int listing;
|
||||||
|
int changed;
|
||||||
|
int noresult;
|
||||||
|
int prev;
|
||||||
|
int entry;
|
||||||
|
int width;
|
||||||
|
int num;
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
void (*match)(struct menu_q *, struct menu_q *, char *);
|
||||||
|
void (*print)(struct menu *, int);
|
||||||
|
};
|
||||||
|
static struct menu *menu_handle_key(XEvent *, struct menu_ctx *,
|
||||||
|
struct menu_q *, struct menu_q *);
|
||||||
|
static void menu_handle_move(XEvent *, struct menu_ctx *,
|
||||||
|
struct screen_ctx *);
|
||||||
|
static struct menu *menu_handle_release(XEvent *, struct menu_ctx *,
|
||||||
|
struct screen_ctx *, struct menu_q *);
|
||||||
|
static void menu_draw(struct screen_ctx *, struct menu_ctx *,
|
||||||
|
struct menu_q *, struct menu_q *);
|
||||||
|
static int menu_calc_entry(struct screen_ctx *, struct menu_ctx *,
|
||||||
|
int, int);
|
||||||
|
|
||||||
|
void
|
||||||
|
menu_init(struct screen_ctx *sc)
|
||||||
|
{
|
||||||
|
XGCValues gv;
|
||||||
|
|
||||||
|
sc->menuwin = XCreateSimpleWindow(X_Dpy, sc->rootwin, 0, 0, 1, 1, 0,
|
||||||
|
sc->color[CWM_COLOR_BG_MENU].pixel,
|
||||||
|
sc->color[CWM_COLOR_BG_MENU].pixel);
|
||||||
|
|
||||||
|
gv.foreground =
|
||||||
|
sc->color[CWM_COLOR_FG_MENU].pixel^sc->color[CWM_COLOR_BG_MENU].pixel;
|
||||||
|
gv.background = sc->color[CWM_COLOR_BG_MENU].pixel;
|
||||||
|
gv.function = GXxor;
|
||||||
|
|
||||||
|
sc->gc = XCreateGC(X_Dpy, sc->menuwin,
|
||||||
|
GCForeground|GCBackground|GCFunction, &gv);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct menu *
|
||||||
|
menu_filter(struct screen_ctx *sc, struct menu_q *menuq, char *prompt,
|
||||||
|
char *initial, int dummy,
|
||||||
|
void (*match)(struct menu_q *, struct menu_q *, char *),
|
||||||
|
void (*print)(struct menu *, int))
|
||||||
|
{
|
||||||
|
struct menu_ctx mc;
|
||||||
|
struct menu_q resultq;
|
||||||
|
struct menu *mi = NULL;
|
||||||
|
XEvent e;
|
||||||
|
Window focuswin;
|
||||||
|
int evmask, focusrevert;
|
||||||
|
|
||||||
|
TAILQ_INIT(&resultq);
|
||||||
|
|
||||||
|
bzero(&mc, sizeof(mc));
|
||||||
|
|
||||||
|
xu_ptr_getpos(sc->rootwin, &mc.x, &mc.y);
|
||||||
|
|
||||||
|
if (prompt == NULL) {
|
||||||
|
evmask = MenuMask;
|
||||||
|
mc.promptstr[0] = '\0';
|
||||||
|
mc.list = 1;
|
||||||
|
} else {
|
||||||
|
evmask = MenuMask | KeyMask; /* only accept keys if prompt */
|
||||||
|
snprintf(mc.promptstr, sizeof(mc.promptstr), "%s%c", prompt,
|
||||||
|
PROMPT_SCHAR);
|
||||||
|
snprintf(mc.dispstr, sizeof(mc.dispstr), "%s%s%c", mc.promptstr,
|
||||||
|
mc.searchstr, PROMPT_ECHAR);
|
||||||
|
mc.width = font_width(sc, mc.dispstr, strlen(mc.dispstr));
|
||||||
|
mc.hasprompt = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (initial != NULL)
|
||||||
|
strlcpy(mc.searchstr, initial, sizeof(mc.searchstr));
|
||||||
|
else
|
||||||
|
mc.searchstr[0] = '\0';
|
||||||
|
|
||||||
|
mc.match = match;
|
||||||
|
mc.print = print;
|
||||||
|
mc.entry = mc.prev = -1;
|
||||||
|
|
||||||
|
XMoveResizeWindow(X_Dpy, sc->menuwin, mc.x, mc.y, mc.width,
|
||||||
|
font_height(sc));
|
||||||
|
XSelectInput(X_Dpy, sc->menuwin, evmask);
|
||||||
|
XMapRaised(X_Dpy, sc->menuwin);
|
||||||
|
|
||||||
|
if (xu_ptr_grab(sc->menuwin, MenuGrabMask, Cursor_question) < 0) {
|
||||||
|
XUnmapWindow(X_Dpy, sc->menuwin);
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
XGetInputFocus(X_Dpy, &focuswin, &focusrevert);
|
||||||
|
XSetInputFocus(X_Dpy, sc->menuwin, RevertToPointerRoot, CurrentTime);
|
||||||
|
|
||||||
|
/* make sure keybindings don't remove keys from the menu stream */
|
||||||
|
XGrabKeyboard(X_Dpy, sc->menuwin, True,
|
||||||
|
GrabModeAsync, GrabModeAsync, CurrentTime);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
mc.changed = 0;
|
||||||
|
|
||||||
|
XWindowEvent(X_Dpy, sc->menuwin, evmask, &e);
|
||||||
|
|
||||||
|
switch (e.type) {
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
case KeyPress:
|
||||||
|
if ((mi = menu_handle_key(&e, &mc, menuq, &resultq))
|
||||||
|
!= NULL)
|
||||||
|
goto out;
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
case Expose:
|
||||||
|
menu_draw(sc, &mc, menuq, &resultq);
|
||||||
|
break;
|
||||||
|
case MotionNotify:
|
||||||
|
menu_handle_move(&e, &mc, sc);
|
||||||
|
break;
|
||||||
|
case ButtonRelease:
|
||||||
|
if ((mi = menu_handle_release(&e, &mc, sc, &resultq))
|
||||||
|
!= NULL)
|
||||||
|
goto out;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
if (dummy == 0 && mi->dummy) { /* no match */
|
||||||
|
xfree (mi);
|
||||||
|
mi = NULL;
|
||||||
|
xu_ptr_ungrab();
|
||||||
|
XSetInputFocus(X_Dpy, focuswin, focusrevert, CurrentTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
XUnmapWindow(X_Dpy, sc->menuwin);
|
||||||
|
XUngrabKeyboard(X_Dpy, CurrentTime);
|
||||||
|
|
||||||
|
return (mi);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct menu *
|
||||||
|
menu_handle_key(XEvent *e, struct menu_ctx *mc, struct menu_q *menuq,
|
||||||
|
struct menu_q *resultq)
|
||||||
|
{
|
||||||
|
struct menu *mi;
|
||||||
|
enum ctltype ctl;
|
||||||
|
char chr;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
if (input_keycodetrans(e->xkey.keycode, e->xkey.state,
|
||||||
|
&ctl, &chr) < 0)
|
||||||
|
return (NULL);
|
||||||
|
|
||||||
|
switch (ctl) {
|
||||||
|
case CTL_ERASEONE:
|
||||||
|
if ((len = strlen(mc->searchstr)) > 0) {
|
||||||
|
mc->searchstr[len - 1] = '\0';
|
||||||
|
mc->changed = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CTL_UP:
|
||||||
|
mi = TAILQ_LAST(resultq, menu_q);
|
||||||
|
if (mi == NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
TAILQ_REMOVE(resultq, mi, resultentry);
|
||||||
|
TAILQ_INSERT_HEAD(resultq, mi, resultentry);
|
||||||
|
break;
|
||||||
|
case CTL_DOWN:
|
||||||
|
mi = TAILQ_FIRST(resultq);
|
||||||
|
if (mi == NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
TAILQ_REMOVE(resultq, mi, resultentry);
|
||||||
|
TAILQ_INSERT_TAIL(resultq, mi, resultentry);
|
||||||
|
break;
|
||||||
|
case CTL_RETURN:
|
||||||
|
/*
|
||||||
|
* Return whatever the cursor is currently on. Else
|
||||||
|
* even if dummy is zero, we need to return something.
|
||||||
|
*/
|
||||||
|
if ((mi = TAILQ_FIRST(resultq)) == NULL) {
|
||||||
|
mi = xmalloc(sizeof *mi);
|
||||||
|
(void)strlcpy(mi->text,
|
||||||
|
mc->searchstr, sizeof(mi->text));
|
||||||
|
mi->dummy = 1;
|
||||||
|
}
|
||||||
|
mi->abort = 0;
|
||||||
|
return (mi);
|
||||||
|
case CTL_WIPE:
|
||||||
|
mc->searchstr[0] = '\0';
|
||||||
|
mc->changed = 1;
|
||||||
|
break;
|
||||||
|
case CTL_ALL:
|
||||||
|
mc->list = !mc->list;
|
||||||
|
break;
|
||||||
|
case CTL_ABORT:
|
||||||
|
mi = xmalloc(sizeof *mi);
|
||||||
|
mi->text[0] = '\0';
|
||||||
|
mi->dummy = 1;
|
||||||
|
mi->abort = 1;
|
||||||
|
return (mi);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chr != '\0') {
|
||||||
|
char str[2];
|
||||||
|
|
||||||
|
str[0] = chr;
|
||||||
|
str[1] = '\0';
|
||||||
|
mc->changed = 1;
|
||||||
|
strlcat(mc->searchstr, str, sizeof(mc->searchstr));
|
||||||
|
}
|
||||||
|
|
||||||
|
mc->noresult = 0;
|
||||||
|
if (mc->changed && mc->searchstr[0] != '\0') {
|
||||||
|
(*mc->match)(menuq, resultq, mc->searchstr);
|
||||||
|
/* If menuq is empty, never show we've failed */
|
||||||
|
mc->noresult = TAILQ_EMPTY(resultq) && !TAILQ_EMPTY(menuq);
|
||||||
|
} else if (mc->changed)
|
||||||
|
TAILQ_INIT(resultq);
|
||||||
|
|
||||||
|
if (!mc->list && mc->listing && !mc->changed) {
|
||||||
|
TAILQ_INIT(resultq);
|
||||||
|
mc->listing = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
menu_draw(struct screen_ctx *sc, struct menu_ctx *mc, struct menu_q *menuq,
|
||||||
|
struct menu_q *resultq)
|
||||||
|
{
|
||||||
|
struct menu *mi;
|
||||||
|
int n, dy, xsave, ysave;
|
||||||
|
|
||||||
|
if (mc->list) {
|
||||||
|
if (TAILQ_EMPTY(resultq) && mc->list) {
|
||||||
|
/* Copy them all over. */
|
||||||
|
TAILQ_FOREACH(mi, menuq, entry)
|
||||||
|
TAILQ_INSERT_TAIL(resultq, mi,
|
||||||
|
resultentry);
|
||||||
|
|
||||||
|
mc->listing = 1;
|
||||||
|
} else if (mc->changed)
|
||||||
|
mc->listing = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
mc->num = 0;
|
||||||
|
mc->width = 0;
|
||||||
|
dy = 0;
|
||||||
|
if (mc->hasprompt) {
|
||||||
|
snprintf(mc->dispstr, sizeof(mc->dispstr), "%s%s%c",
|
||||||
|
mc->promptstr, mc->searchstr, PROMPT_ECHAR);
|
||||||
|
mc->width = font_width(sc, mc->dispstr, strlen(mc->dispstr));
|
||||||
|
dy = font_height(sc);
|
||||||
|
mc->num = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TAILQ_FOREACH(mi, resultq, resultentry) {
|
||||||
|
char *text;
|
||||||
|
|
||||||
|
if (mc->print != NULL) {
|
||||||
|
(*mc->print)(mi, mc->listing);
|
||||||
|
text = mi->print;
|
||||||
|
} else {
|
||||||
|
mi->print[0] = '\0';
|
||||||
|
text = mi->text;
|
||||||
|
}
|
||||||
|
|
||||||
|
mc->width = MAX(mc->width, font_width(sc, text,
|
||||||
|
MIN(strlen(text), MENU_MAXENTRY)));
|
||||||
|
dy += font_height(sc);
|
||||||
|
mc->num++;
|
||||||
|
}
|
||||||
|
|
||||||
|
xsave = mc->x;
|
||||||
|
ysave = mc->y;
|
||||||
|
if (mc->x < 0)
|
||||||
|
mc->x = 0;
|
||||||
|
else if (mc->x + mc->width >= sc->xmax)
|
||||||
|
mc->x = sc->xmax - mc->width;
|
||||||
|
|
||||||
|
if (mc->y + dy >= sc->ymax)
|
||||||
|
mc->y = sc->ymax - dy;
|
||||||
|
/* never hide the top of the menu */
|
||||||
|
if (mc->y < 0)
|
||||||
|
mc->y = 0;
|
||||||
|
|
||||||
|
if (mc->x != xsave || mc->y != ysave)
|
||||||
|
xu_ptr_setpos(sc->rootwin, mc->x, mc->y);
|
||||||
|
|
||||||
|
XClearWindow(X_Dpy, sc->menuwin);
|
||||||
|
XMoveResizeWindow(X_Dpy, sc->menuwin, mc->x, mc->y, mc->width, dy);
|
||||||
|
|
||||||
|
if (mc->hasprompt) {
|
||||||
|
font_draw(sc, mc->dispstr, strlen(mc->dispstr), sc->menuwin,
|
||||||
|
0, font_ascent(sc) + 1);
|
||||||
|
n = 1;
|
||||||
|
} else
|
||||||
|
n = 0;
|
||||||
|
|
||||||
|
TAILQ_FOREACH(mi, resultq, resultentry) {
|
||||||
|
char *text = mi->print[0] != '\0' ?
|
||||||
|
mi->print : mi->text;
|
||||||
|
|
||||||
|
font_draw(sc, text, MIN(strlen(text), MENU_MAXENTRY),
|
||||||
|
sc->menuwin, 0, n * font_height(sc) + font_ascent(sc) + 1);
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mc->hasprompt && n > 1)
|
||||||
|
XFillRectangle(X_Dpy, sc->menuwin, sc->gc,
|
||||||
|
0, font_height(sc), mc->width, font_height(sc));
|
||||||
|
|
||||||
|
if (mc->noresult)
|
||||||
|
XFillRectangle(X_Dpy, sc->menuwin, sc->gc,
|
||||||
|
0, 0, mc->width, font_height(sc));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
menu_handle_move(XEvent *e, struct menu_ctx *mc, struct screen_ctx *sc)
|
||||||
|
{
|
||||||
|
mc->prev = mc->entry;
|
||||||
|
mc->entry = menu_calc_entry(sc, mc, e->xbutton.x, e->xbutton.y);
|
||||||
|
|
||||||
|
if (mc->prev != -1)
|
||||||
|
XFillRectangle(X_Dpy, sc->menuwin, sc->gc, 0,
|
||||||
|
font_height(sc) * mc->prev, mc->width, font_height(sc));
|
||||||
|
if (mc->entry != -1) {
|
||||||
|
xu_ptr_regrab(MenuGrabMask, Cursor_select);
|
||||||
|
XFillRectangle(X_Dpy, sc->menuwin, sc->gc, 0,
|
||||||
|
font_height(sc) * mc->entry, mc->width, font_height(sc));
|
||||||
|
} else
|
||||||
|
xu_ptr_regrab(MenuGrabMask, Cursor_default);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct menu *
|
||||||
|
menu_handle_release(XEvent *e, struct menu_ctx *mc, struct screen_ctx *sc,
|
||||||
|
struct menu_q *resultq)
|
||||||
|
{
|
||||||
|
struct menu *mi;
|
||||||
|
int entry, i = 0;
|
||||||
|
|
||||||
|
entry = menu_calc_entry(sc, mc, e->xbutton.x, e->xbutton.y);
|
||||||
|
xu_ptr_ungrab();
|
||||||
|
|
||||||
|
if (mc->hasprompt)
|
||||||
|
i = 1;
|
||||||
|
|
||||||
|
TAILQ_FOREACH(mi, resultq, resultentry)
|
||||||
|
if (entry == i++)
|
||||||
|
break;
|
||||||
|
if (mi == NULL) {
|
||||||
|
mi = xmalloc(sizeof(*mi));
|
||||||
|
mi->text[0] = '\0';
|
||||||
|
mi->dummy = 1;
|
||||||
|
}
|
||||||
|
return (mi);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
menu_calc_entry(struct screen_ctx *sc, struct menu_ctx *mc, int x, int y)
|
||||||
|
{
|
||||||
|
int entry;
|
||||||
|
|
||||||
|
entry = y / font_height(sc);
|
||||||
|
|
||||||
|
/* in bounds? */
|
||||||
|
if (x <= 0 || x > mc->width || y <= 0 ||
|
||||||
|
y > font_height(sc) * mc->num || entry < 0 || entry >= mc->num)
|
||||||
|
entry = -1;
|
||||||
|
|
||||||
|
if (mc->hasprompt && entry == 0)
|
||||||
|
entry = -1;
|
||||||
|
|
||||||
|
return (entry);
|
||||||
|
}
|
279
mousefunc.c
Normal file
279
mousefunc.c
Normal file
@@ -0,0 +1,279 @@
|
|||||||
|
/*
|
||||||
|
* calmwm - the calm window manager
|
||||||
|
*
|
||||||
|
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
|
||||||
|
* Copyright (c) 2008 rivo nurges <rix@estpak.ee>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
|
|
||||||
|
#include <err.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "calmwm.h"
|
||||||
|
|
||||||
|
static int mousefunc_sweep_calc(struct client_ctx *, int, int, int, int);
|
||||||
|
static void mousefunc_sweep_draw(struct client_ctx *);
|
||||||
|
|
||||||
|
static int
|
||||||
|
mousefunc_sweep_calc(struct client_ctx *cc, int x, int y, int mx, int my)
|
||||||
|
{
|
||||||
|
int width = cc->geom.width, height = cc->geom.height;
|
||||||
|
|
||||||
|
cc->geom.width = abs(x - mx) - cc->bwidth;
|
||||||
|
cc->geom.height = abs(y - my) - cc->bwidth;
|
||||||
|
|
||||||
|
client_applysizehints(cc);
|
||||||
|
|
||||||
|
cc->geom.x = x <= mx ? x : x - cc->geom.width;
|
||||||
|
cc->geom.y = y <= my ? y : y - cc->geom.height;
|
||||||
|
|
||||||
|
return (width != cc->geom.width || height != cc->geom.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mousefunc_sweep_draw(struct client_ctx *cc)
|
||||||
|
{
|
||||||
|
struct screen_ctx *sc = cc->sc;
|
||||||
|
char asize[10]; /* fits "nnnnxnnnn\0" */
|
||||||
|
int width, height, width_size, width_name;
|
||||||
|
|
||||||
|
snprintf(asize, sizeof(asize), "%dx%d",
|
||||||
|
(cc->geom.width - cc->geom.basew) / cc->geom.incw,
|
||||||
|
(cc->geom.height - cc->geom.baseh) / cc->geom.inch);
|
||||||
|
width_size = font_width(sc, asize, strlen(asize)) + 4;
|
||||||
|
width_name = font_width(sc, cc->name, strlen(cc->name)) + 4;
|
||||||
|
width = MAX(width_size, width_name);
|
||||||
|
height = font_ascent(sc) + font_descent(sc) + 1;
|
||||||
|
|
||||||
|
XMoveResizeWindow(X_Dpy, sc->menuwin, cc->geom.x, cc->geom.y,
|
||||||
|
width, height * 2);
|
||||||
|
XMapWindow(X_Dpy, sc->menuwin);
|
||||||
|
XReparentWindow(X_Dpy, sc->menuwin, cc->win, 0, 0);
|
||||||
|
XClearWindow(X_Dpy, sc->menuwin);
|
||||||
|
font_draw(sc, cc->name, strlen(cc->name), sc->menuwin,
|
||||||
|
2, font_ascent(sc) + 1);
|
||||||
|
font_draw(sc, asize, strlen(asize), sc->menuwin,
|
||||||
|
width / 2 - width_size / 2, height + font_ascent(sc) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mousefunc_window_resize(struct client_ctx *cc, void *arg)
|
||||||
|
{
|
||||||
|
XEvent ev;
|
||||||
|
Time time = 0;
|
||||||
|
struct screen_ctx *sc = cc->sc;
|
||||||
|
int x = cc->geom.x, y = cc->geom.y;
|
||||||
|
|
||||||
|
client_raise(cc);
|
||||||
|
client_ptrsave(cc);
|
||||||
|
|
||||||
|
if (xu_ptr_grab(cc->win, MouseMask, Cursor_resize) < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
xu_ptr_setpos(cc->win, cc->geom.width, cc->geom.height);
|
||||||
|
mousefunc_sweep_draw(cc);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
XMaskEvent(X_Dpy, MouseMask|ExposureMask, &ev);
|
||||||
|
|
||||||
|
switch (ev.type) {
|
||||||
|
case Expose:
|
||||||
|
client_draw_border(cc);
|
||||||
|
break;
|
||||||
|
case MotionNotify:
|
||||||
|
if (mousefunc_sweep_calc(cc, x, y,
|
||||||
|
ev.xmotion.x_root, ev.xmotion.y_root))
|
||||||
|
/* Recompute window output */
|
||||||
|
mousefunc_sweep_draw(cc);
|
||||||
|
|
||||||
|
/* don't sync more than 60 times / second */
|
||||||
|
if ((ev.xmotion.time - time) > (1000 / 60)) {
|
||||||
|
time = ev.xmotion.time;
|
||||||
|
XSync(X_Dpy, False);
|
||||||
|
client_resize(cc);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ButtonRelease:
|
||||||
|
if (time) {
|
||||||
|
XSync(X_Dpy, False);
|
||||||
|
client_resize(cc);
|
||||||
|
}
|
||||||
|
XUnmapWindow(X_Dpy, sc->menuwin);
|
||||||
|
XReparentWindow(X_Dpy, sc->menuwin, sc->rootwin, 0, 0);
|
||||||
|
xu_ptr_ungrab();
|
||||||
|
|
||||||
|
/* Make sure the pointer stays within the window. */
|
||||||
|
if (cc->ptr.x > cc->geom.width)
|
||||||
|
cc->ptr.x = cc->geom.width - cc->bwidth;
|
||||||
|
if (cc->ptr.y > cc->geom.height)
|
||||||
|
cc->ptr.y = cc->geom.height - cc->bwidth;
|
||||||
|
client_ptrwarp(cc);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* NOTREACHED */
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mousefunc_window_move(struct client_ctx *cc, void *arg)
|
||||||
|
{
|
||||||
|
XEvent ev;
|
||||||
|
Time time = 0;
|
||||||
|
int px, py;
|
||||||
|
|
||||||
|
client_raise(cc);
|
||||||
|
|
||||||
|
if (xu_ptr_grab(cc->win, MouseMask, Cursor_move) < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
xu_ptr_getpos(cc->win, &px, &py);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
XMaskEvent(X_Dpy, MouseMask|ExposureMask, &ev);
|
||||||
|
|
||||||
|
switch (ev.type) {
|
||||||
|
case Expose:
|
||||||
|
client_draw_border(cc);
|
||||||
|
break;
|
||||||
|
case MotionNotify:
|
||||||
|
cc->geom.x = ev.xmotion.x_root - px;
|
||||||
|
cc->geom.y = ev.xmotion.y_root - py;
|
||||||
|
|
||||||
|
/* don't sync more than 60 times / second */
|
||||||
|
if ((ev.xmotion.time - time) > (1000 / 60)) {
|
||||||
|
time = ev.xmotion.time;
|
||||||
|
XSync(X_Dpy, False);
|
||||||
|
client_move(cc);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ButtonRelease:
|
||||||
|
if (time) {
|
||||||
|
XSync(X_Dpy, False);
|
||||||
|
client_move(cc);
|
||||||
|
}
|
||||||
|
xu_ptr_ungrab();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* NOTREACHED */
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mousefunc_window_grouptoggle(struct client_ctx *cc, void *arg)
|
||||||
|
{
|
||||||
|
group_sticky_toggle_enter(cc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mousefunc_window_lower(struct client_ctx *cc, void *arg)
|
||||||
|
{
|
||||||
|
client_ptrsave(cc);
|
||||||
|
client_lower(cc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mousefunc_window_hide(struct client_ctx *cc, void *arg)
|
||||||
|
{
|
||||||
|
client_hide(cc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mousefunc_menu_group(struct client_ctx *cc, void *arg)
|
||||||
|
{
|
||||||
|
group_menu(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mousefunc_menu_unhide(struct client_ctx *cc, void *arg)
|
||||||
|
{
|
||||||
|
struct screen_ctx *sc;
|
||||||
|
struct client_ctx *old_cc;
|
||||||
|
struct menu *mi;
|
||||||
|
struct menu_q menuq;
|
||||||
|
char *wname;
|
||||||
|
|
||||||
|
sc = cc->sc;
|
||||||
|
old_cc = client_current();
|
||||||
|
|
||||||
|
TAILQ_INIT(&menuq);
|
||||||
|
TAILQ_FOREACH(cc, &Clientq, entry)
|
||||||
|
if (cc->flags & CLIENT_HIDDEN) {
|
||||||
|
wname = (cc->label) ? cc->label : cc->name;
|
||||||
|
if (wname == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
mi = xcalloc(1, sizeof(*mi));
|
||||||
|
strlcpy(mi->text, wname, sizeof(mi->text));
|
||||||
|
mi->ctx = cc;
|
||||||
|
TAILQ_INSERT_TAIL(&menuq, mi, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TAILQ_EMPTY(&menuq))
|
||||||
|
return;
|
||||||
|
|
||||||
|
mi = menu_filter(sc, &menuq, NULL, NULL, 0, NULL, NULL);
|
||||||
|
if (mi != NULL) {
|
||||||
|
cc = (struct client_ctx *)mi->ctx;
|
||||||
|
client_unhide(cc);
|
||||||
|
|
||||||
|
if (old_cc != NULL)
|
||||||
|
client_ptrsave(old_cc);
|
||||||
|
client_ptrwarp(cc);
|
||||||
|
} else {
|
||||||
|
while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
|
||||||
|
TAILQ_REMOVE(&menuq, mi, entry);
|
||||||
|
xfree(mi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mousefunc_menu_cmd(struct client_ctx *cc, void *arg)
|
||||||
|
{
|
||||||
|
struct screen_ctx *sc;
|
||||||
|
struct menu *mi;
|
||||||
|
struct menu_q menuq;
|
||||||
|
struct cmd *cmd;
|
||||||
|
|
||||||
|
sc = cc->sc;
|
||||||
|
|
||||||
|
TAILQ_INIT(&menuq);
|
||||||
|
TAILQ_FOREACH(cmd, &Conf.cmdq, entry) {
|
||||||
|
mi = xcalloc(1, sizeof(*mi));
|
||||||
|
strlcpy(mi->text, cmd->label, sizeof(mi->text));
|
||||||
|
mi->ctx = cmd;
|
||||||
|
TAILQ_INSERT_TAIL(&menuq, mi, entry);
|
||||||
|
}
|
||||||
|
if (TAILQ_EMPTY(&menuq))
|
||||||
|
return;
|
||||||
|
|
||||||
|
mi = menu_filter(sc, &menuq, NULL, NULL, 0, NULL, NULL);
|
||||||
|
if (mi != NULL)
|
||||||
|
u_spawn(((struct cmd *)mi->ctx)->image);
|
||||||
|
else
|
||||||
|
while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
|
||||||
|
TAILQ_REMOVE(&menuq, mi, entry);
|
||||||
|
xfree(mi);
|
||||||
|
}
|
||||||
|
}
|
567
parse.y
Normal file
567
parse.y
Normal file
@@ -0,0 +1,567 @@
|
|||||||
|
/* $OpenBSD$ */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
|
||||||
|
* Copyright (c) 2001 Markus Friedl. All rights reserved.
|
||||||
|
* Copyright (c) 2001 Daniel Hartmeier. All rights reserved.
|
||||||
|
* Copyright (c) 2001 Theo de Raadt. All rights reserved.
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
%{
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <err.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "calmwm.h"
|
||||||
|
|
||||||
|
TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files);
|
||||||
|
static struct file {
|
||||||
|
TAILQ_ENTRY(file) entry;
|
||||||
|
FILE *stream;
|
||||||
|
char *name;
|
||||||
|
int lineno;
|
||||||
|
int errors;
|
||||||
|
} *file;
|
||||||
|
|
||||||
|
struct file *pushfile(const char *);
|
||||||
|
int popfile(void);
|
||||||
|
int yyparse(void);
|
||||||
|
int yylex(void);
|
||||||
|
int yyerror(const char *, ...);
|
||||||
|
int kw_cmp(const void *, const void *);
|
||||||
|
int lookup(char *);
|
||||||
|
int lgetc(int);
|
||||||
|
int lungetc(int);
|
||||||
|
int findeol(void);
|
||||||
|
|
||||||
|
static struct conf *conf;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
union {
|
||||||
|
int64_t number;
|
||||||
|
char *string;
|
||||||
|
} v;
|
||||||
|
int lineno;
|
||||||
|
} YYSTYPE;
|
||||||
|
|
||||||
|
%}
|
||||||
|
|
||||||
|
%token FONTNAME STICKY GAP MOUSEBIND
|
||||||
|
%token AUTOGROUP BIND COMMAND IGNORE
|
||||||
|
%token YES NO BORDERWIDTH MOVEAMOUNT
|
||||||
|
%token COLOR
|
||||||
|
%token ACTIVEBORDER INACTIVEBORDER
|
||||||
|
%token GROUPBORDER UNGROUPBORDER
|
||||||
|
%token ERROR
|
||||||
|
%token <v.string> STRING
|
||||||
|
%token <v.number> NUMBER
|
||||||
|
%type <v.number> yesno
|
||||||
|
%type <v.string> string
|
||||||
|
%%
|
||||||
|
|
||||||
|
grammar : /* empty */
|
||||||
|
| grammar '\n'
|
||||||
|
| grammar main '\n'
|
||||||
|
| grammar color '\n'
|
||||||
|
| grammar error '\n' { file->errors++; }
|
||||||
|
;
|
||||||
|
|
||||||
|
string : string STRING {
|
||||||
|
if (asprintf(&$$, "%s %s", $1, $2) == -1) {
|
||||||
|
free($1);
|
||||||
|
free($2);
|
||||||
|
yyerror("string: asprintf");
|
||||||
|
YYERROR;
|
||||||
|
}
|
||||||
|
free($1);
|
||||||
|
free($2);
|
||||||
|
}
|
||||||
|
| STRING
|
||||||
|
;
|
||||||
|
|
||||||
|
yesno : YES { $$ = 1; }
|
||||||
|
| NO { $$ = 0; }
|
||||||
|
;
|
||||||
|
|
||||||
|
main : FONTNAME STRING {
|
||||||
|
free(conf->DefaultFontName);
|
||||||
|
conf->DefaultFontName = $2;
|
||||||
|
}
|
||||||
|
| STICKY yesno {
|
||||||
|
if ($2 == 0)
|
||||||
|
conf->flags &= ~CONF_STICKY_GROUPS;
|
||||||
|
else
|
||||||
|
conf->flags |= CONF_STICKY_GROUPS;
|
||||||
|
}
|
||||||
|
| BORDERWIDTH NUMBER {
|
||||||
|
conf->bwidth = $2;
|
||||||
|
}
|
||||||
|
| MOVEAMOUNT NUMBER {
|
||||||
|
conf->mamount = $2;
|
||||||
|
}
|
||||||
|
| COMMAND STRING string {
|
||||||
|
conf_cmd_add(conf, $3, $2, 0);
|
||||||
|
free($2);
|
||||||
|
free($3);
|
||||||
|
}
|
||||||
|
| AUTOGROUP NUMBER STRING {
|
||||||
|
if ($2 < 0 || $2 > 9) {
|
||||||
|
free($3);
|
||||||
|
yyerror("autogroup number out of range: %d", $2);
|
||||||
|
YYERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
group_make_autogroup(conf, $3, $2);
|
||||||
|
free($3);
|
||||||
|
}
|
||||||
|
| IGNORE STRING {
|
||||||
|
struct winmatch *wm;
|
||||||
|
|
||||||
|
wm = xcalloc(1, sizeof(*wm));
|
||||||
|
strlcpy(wm->title, $2, sizeof(wm->title));
|
||||||
|
TAILQ_INSERT_TAIL(&conf->ignoreq, wm, entry);
|
||||||
|
|
||||||
|
free($2);
|
||||||
|
}
|
||||||
|
| BIND STRING string {
|
||||||
|
conf_bindname(conf, $2, $3);
|
||||||
|
free($2);
|
||||||
|
free($3);
|
||||||
|
}
|
||||||
|
| GAP NUMBER NUMBER NUMBER NUMBER {
|
||||||
|
conf->gap.top = $2;
|
||||||
|
conf->gap.bottom = $3;
|
||||||
|
conf->gap.left = $4;
|
||||||
|
conf->gap.right = $5;
|
||||||
|
}
|
||||||
|
| MOUSEBIND STRING string {
|
||||||
|
conf_mousebind(conf, $2, $3);
|
||||||
|
free($2);
|
||||||
|
free($3);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
color : COLOR colors
|
||||||
|
;
|
||||||
|
|
||||||
|
colors : ACTIVEBORDER STRING {
|
||||||
|
free(conf->color[CWM_COLOR_BORDOR_ACTIVE].name);
|
||||||
|
conf->color[CWM_COLOR_BORDOR_ACTIVE].name = $2;
|
||||||
|
}
|
||||||
|
| INACTIVEBORDER STRING {
|
||||||
|
free(conf->color[CWM_COLOR_BORDER_INACTIVE].name);
|
||||||
|
conf->color[CWM_COLOR_BORDER_INACTIVE].name = $2;
|
||||||
|
}
|
||||||
|
| GROUPBORDER STRING {
|
||||||
|
free(conf->color[CWM_COLOR_BORDER_GROUP].name);
|
||||||
|
conf->color[CWM_COLOR_BORDER_GROUP].name = $2;
|
||||||
|
}
|
||||||
|
| UNGROUPBORDER STRING {
|
||||||
|
free(conf->color[CWM_COLOR_BORDER_UNGROUP].name);
|
||||||
|
conf->color[CWM_COLOR_BORDER_UNGROUP].name = $2;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
%%
|
||||||
|
|
||||||
|
struct keywords {
|
||||||
|
const char *k_name;
|
||||||
|
int k_val;
|
||||||
|
};
|
||||||
|
|
||||||
|
int
|
||||||
|
yyerror(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
file->errors++;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
fprintf(stderr, "%s:%d: ", file->name, yylval.lineno);
|
||||||
|
vfprintf(stderr, fmt, ap);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
va_end(ap);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
kw_cmp(const void *k, const void *e)
|
||||||
|
{
|
||||||
|
return (strcmp(k, ((const struct keywords *)e)->k_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
lookup(char *s)
|
||||||
|
{
|
||||||
|
/* this has to be sorted always */
|
||||||
|
static const struct keywords keywords[] = {
|
||||||
|
{ "activeborder", ACTIVEBORDER},
|
||||||
|
{ "autogroup", AUTOGROUP},
|
||||||
|
{ "bind", BIND},
|
||||||
|
{ "borderwidth", BORDERWIDTH},
|
||||||
|
{ "color", COLOR},
|
||||||
|
{ "command", COMMAND},
|
||||||
|
{ "fontname", FONTNAME},
|
||||||
|
{ "gap", GAP},
|
||||||
|
{ "groupborder", GROUPBORDER},
|
||||||
|
{ "ignore", IGNORE},
|
||||||
|
{ "inactiveborder", INACTIVEBORDER},
|
||||||
|
{ "mousebind", MOUSEBIND},
|
||||||
|
{ "moveamount", MOVEAMOUNT},
|
||||||
|
{ "no", NO},
|
||||||
|
{ "sticky", STICKY},
|
||||||
|
{ "ungroupborder", UNGROUPBORDER},
|
||||||
|
{ "yes", YES}
|
||||||
|
};
|
||||||
|
const struct keywords *p;
|
||||||
|
|
||||||
|
p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
|
||||||
|
sizeof(keywords[0]), kw_cmp);
|
||||||
|
|
||||||
|
if (p)
|
||||||
|
return (p->k_val);
|
||||||
|
else
|
||||||
|
return (STRING);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MAXPUSHBACK 128
|
||||||
|
|
||||||
|
char *parsebuf;
|
||||||
|
int parseindex;
|
||||||
|
char pushback_buffer[MAXPUSHBACK];
|
||||||
|
int pushback_index = 0;
|
||||||
|
|
||||||
|
int
|
||||||
|
lgetc(int quotec)
|
||||||
|
{
|
||||||
|
int c, next;
|
||||||
|
|
||||||
|
if (parsebuf) {
|
||||||
|
/* Read character from the parsebuffer instead of input. */
|
||||||
|
if (parseindex >= 0) {
|
||||||
|
c = parsebuf[parseindex++];
|
||||||
|
if (c != '\0')
|
||||||
|
return (c);
|
||||||
|
parsebuf = NULL;
|
||||||
|
} else
|
||||||
|
parseindex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pushback_index)
|
||||||
|
return (pushback_buffer[--pushback_index]);
|
||||||
|
|
||||||
|
if (quotec) {
|
||||||
|
if ((c = getc(file->stream)) == EOF) {
|
||||||
|
yyerror("reached end of file while parsing quoted string");
|
||||||
|
if (popfile() == EOF)
|
||||||
|
return (EOF);
|
||||||
|
return (quotec);
|
||||||
|
}
|
||||||
|
return (c);
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((c = getc(file->stream)) == '\\') {
|
||||||
|
next = getc(file->stream);
|
||||||
|
if (next != '\n') {
|
||||||
|
c = next;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
yylval.lineno = file->lineno;
|
||||||
|
file->lineno++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (c == EOF) {
|
||||||
|
if (popfile() == EOF)
|
||||||
|
return (EOF);
|
||||||
|
c = getc(file->stream);
|
||||||
|
}
|
||||||
|
return (c);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
lungetc(int c)
|
||||||
|
{
|
||||||
|
if (c == EOF)
|
||||||
|
return (EOF);
|
||||||
|
if (parsebuf) {
|
||||||
|
parseindex--;
|
||||||
|
if (parseindex >= 0)
|
||||||
|
return (c);
|
||||||
|
}
|
||||||
|
if (pushback_index < MAXPUSHBACK-1)
|
||||||
|
return (pushback_buffer[pushback_index++] = c);
|
||||||
|
else
|
||||||
|
return (EOF);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
findeol(void)
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
|
||||||
|
parsebuf = NULL;
|
||||||
|
pushback_index = 0;
|
||||||
|
|
||||||
|
/* skip to either EOF or the first real EOL */
|
||||||
|
while (1) {
|
||||||
|
c = lgetc(0);
|
||||||
|
if (c == '\n') {
|
||||||
|
file->lineno++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (c == EOF)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return (ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
yylex(void)
|
||||||
|
{
|
||||||
|
char buf[8096];
|
||||||
|
char *p;
|
||||||
|
int quotec, next, c;
|
||||||
|
int token;
|
||||||
|
|
||||||
|
p = buf;
|
||||||
|
while ((c = lgetc(0)) == ' ' || c == '\t')
|
||||||
|
; /* nothing */
|
||||||
|
|
||||||
|
yylval.lineno = file->lineno;
|
||||||
|
if (c == '#')
|
||||||
|
while ((c = lgetc(0)) != '\n' && c != EOF)
|
||||||
|
; /* nothing */
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case '\'':
|
||||||
|
case '"':
|
||||||
|
quotec = c;
|
||||||
|
while (1) {
|
||||||
|
if ((c = lgetc(quotec)) == EOF)
|
||||||
|
return (0);
|
||||||
|
if (c == '\n') {
|
||||||
|
file->lineno++;
|
||||||
|
continue;
|
||||||
|
} else if (c == '\\') {
|
||||||
|
if ((next = lgetc(quotec)) == EOF)
|
||||||
|
return (0);
|
||||||
|
if (next == quotec || c == ' ' || c == '\t')
|
||||||
|
c = next;
|
||||||
|
else if (next == '\n') {
|
||||||
|
file->lineno++;
|
||||||
|
continue;
|
||||||
|
} else
|
||||||
|
lungetc(next);
|
||||||
|
} else if (c == quotec) {
|
||||||
|
*p = '\0';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (p + 1 >= buf + sizeof(buf) - 1) {
|
||||||
|
yyerror("string too long");
|
||||||
|
return (findeol());
|
||||||
|
}
|
||||||
|
*p++ = (char)c;
|
||||||
|
}
|
||||||
|
yylval.v.string = xstrdup(buf);
|
||||||
|
return (STRING);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define allowed_to_end_number(x) \
|
||||||
|
(isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
|
||||||
|
|
||||||
|
if (c == '-' || isdigit(c)) {
|
||||||
|
do {
|
||||||
|
*p++ = c;
|
||||||
|
if ((unsigned)(p-buf) >= sizeof(buf)) {
|
||||||
|
yyerror("string too long");
|
||||||
|
return (findeol());
|
||||||
|
}
|
||||||
|
} while ((c = lgetc(0)) != EOF && isdigit(c));
|
||||||
|
lungetc(c);
|
||||||
|
if (p == buf + 1 && buf[0] == '-')
|
||||||
|
goto nodigits;
|
||||||
|
if (c == EOF || allowed_to_end_number(c)) {
|
||||||
|
const char *errstr = NULL;
|
||||||
|
|
||||||
|
*p = '\0';
|
||||||
|
yylval.v.number = strtonum(buf, LLONG_MIN,
|
||||||
|
LLONG_MAX, &errstr);
|
||||||
|
if (errstr) {
|
||||||
|
yyerror("\"%s\" invalid number: %s",
|
||||||
|
buf, errstr);
|
||||||
|
return (findeol());
|
||||||
|
}
|
||||||
|
return (NUMBER);
|
||||||
|
} else {
|
||||||
|
nodigits:
|
||||||
|
while (p > buf + 1)
|
||||||
|
lungetc(*--p);
|
||||||
|
c = *--p;
|
||||||
|
if (c == '-')
|
||||||
|
return (c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define allowed_in_string(x) \
|
||||||
|
(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
|
||||||
|
x != '{' && x != '}' && x != '<' && x != '>' && \
|
||||||
|
x != '!' && x != '=' && x != '#' && x != ','))
|
||||||
|
|
||||||
|
if (isalnum(c) || c == ':' || c == '_' || c == '*' || c == '/') {
|
||||||
|
do {
|
||||||
|
*p++ = c;
|
||||||
|
if ((unsigned)(p-buf) >= sizeof(buf)) {
|
||||||
|
yyerror("string too long");
|
||||||
|
return (findeol());
|
||||||
|
}
|
||||||
|
} while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
|
||||||
|
lungetc(c);
|
||||||
|
*p = '\0';
|
||||||
|
if ((token = lookup(buf)) == STRING)
|
||||||
|
yylval.v.string = xstrdup(buf);
|
||||||
|
return (token);
|
||||||
|
}
|
||||||
|
if (c == '\n') {
|
||||||
|
yylval.lineno = file->lineno;
|
||||||
|
file->lineno++;
|
||||||
|
}
|
||||||
|
if (c == EOF)
|
||||||
|
return (0);
|
||||||
|
return (c);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct file *
|
||||||
|
pushfile(const char *name)
|
||||||
|
{
|
||||||
|
struct file *nfile;
|
||||||
|
|
||||||
|
nfile = xcalloc(1, sizeof(struct file));
|
||||||
|
nfile->name = xstrdup(name);
|
||||||
|
|
||||||
|
if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
|
||||||
|
if (errno != ENOENT)
|
||||||
|
warn("%s", nfile->name);
|
||||||
|
free(nfile->name);
|
||||||
|
free(nfile);
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
nfile->lineno = 1;
|
||||||
|
TAILQ_INSERT_TAIL(&files, nfile, entry);
|
||||||
|
return (nfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
popfile(void)
|
||||||
|
{
|
||||||
|
struct file *prev;
|
||||||
|
|
||||||
|
if ((prev = TAILQ_PREV(file, files, entry)) != NULL) {
|
||||||
|
prev->errors += file->errors;
|
||||||
|
TAILQ_REMOVE(&files, file, entry);
|
||||||
|
fclose(file->stream);
|
||||||
|
free(file->name);
|
||||||
|
free(file);
|
||||||
|
file = prev;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
return (EOF);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
parse_config(const char *filename, struct conf *xconf)
|
||||||
|
{
|
||||||
|
int errors = 0;
|
||||||
|
|
||||||
|
conf = xcalloc(1, sizeof(*conf));
|
||||||
|
|
||||||
|
if ((file = pushfile(filename)) == NULL) {
|
||||||
|
free(conf);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
strlcpy(conf->conf_path, filename, sizeof(conf->conf_path));
|
||||||
|
|
||||||
|
conf_init(conf);
|
||||||
|
|
||||||
|
yyparse();
|
||||||
|
errors = file->errors;
|
||||||
|
file->errors = 0;
|
||||||
|
popfile();
|
||||||
|
|
||||||
|
if (errors) {
|
||||||
|
conf_clear(conf);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
struct autogroupwin *ag;
|
||||||
|
struct keybinding *kb;
|
||||||
|
struct winmatch *wm;
|
||||||
|
struct cmd *cmd;
|
||||||
|
struct mousebinding *mb;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
conf_clear(xconf);
|
||||||
|
|
||||||
|
xconf->flags = conf->flags;
|
||||||
|
xconf->bwidth = conf->bwidth;
|
||||||
|
xconf->mamount = conf->mamount;
|
||||||
|
xconf->gap = conf->gap;
|
||||||
|
|
||||||
|
while ((cmd = TAILQ_FIRST(&conf->cmdq)) != NULL) {
|
||||||
|
TAILQ_REMOVE(&conf->cmdq, cmd, entry);
|
||||||
|
TAILQ_INSERT_TAIL(&xconf->cmdq, cmd, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((kb = TAILQ_FIRST(&conf->keybindingq)) != NULL) {
|
||||||
|
TAILQ_REMOVE(&conf->keybindingq, kb, entry);
|
||||||
|
TAILQ_INSERT_TAIL(&xconf->keybindingq, kb, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((ag = TAILQ_FIRST(&conf->autogroupq)) != NULL) {
|
||||||
|
TAILQ_REMOVE(&conf->autogroupq, ag, entry);
|
||||||
|
TAILQ_INSERT_TAIL(&xconf->autogroupq, ag, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((wm = TAILQ_FIRST(&conf->ignoreq)) != NULL) {
|
||||||
|
TAILQ_REMOVE(&conf->ignoreq, wm, entry);
|
||||||
|
TAILQ_INSERT_TAIL(&xconf->ignoreq, wm, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((mb = TAILQ_FIRST(&conf->mousebindingq)) != NULL) {
|
||||||
|
TAILQ_REMOVE(&conf->mousebindingq, mb, entry);
|
||||||
|
TAILQ_INSERT_TAIL(&xconf->mousebindingq, mb, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
strlcpy(xconf->termpath, conf->termpath,
|
||||||
|
sizeof(xconf->termpath));
|
||||||
|
strlcpy(xconf->lockpath, conf->lockpath,
|
||||||
|
sizeof(xconf->lockpath));
|
||||||
|
|
||||||
|
for (i = 0; i < CWM_COLOR_MAX; i++)
|
||||||
|
xconf->color[i].name = conf->color[i].name;
|
||||||
|
|
||||||
|
xconf->DefaultFontName = conf->DefaultFontName;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(conf);
|
||||||
|
|
||||||
|
return (errors ? -1 : 0);
|
||||||
|
}
|
109
screen.c
109
screen.c
@@ -18,19 +18,18 @@
|
|||||||
* $Id$
|
* $Id$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "headers.h"
|
#include <sys/param.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
|
|
||||||
|
#include <err.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "calmwm.h"
|
#include "calmwm.h"
|
||||||
|
|
||||||
extern struct screen_ctx_q Screenq;
|
|
||||||
extern struct screen_ctx *Curscreen;
|
|
||||||
|
|
||||||
static void
|
|
||||||
_clearwindow_cb(int sig)
|
|
||||||
{
|
|
||||||
struct screen_ctx *sc = screen_current();
|
|
||||||
XUnmapWindow(X_Dpy, sc->infowin);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct screen_ctx *
|
struct screen_ctx *
|
||||||
screen_fromroot(Window rootwin)
|
screen_fromroot(Window rootwin)
|
||||||
{
|
{
|
||||||
@@ -44,19 +43,12 @@ screen_fromroot(Window rootwin)
|
|||||||
return (TAILQ_FIRST(&Screenq));
|
return (TAILQ_FIRST(&Screenq));
|
||||||
}
|
}
|
||||||
|
|
||||||
struct screen_ctx *
|
|
||||||
screen_current(void)
|
|
||||||
{
|
|
||||||
return (Curscreen);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
screen_updatestackingorder(void)
|
screen_updatestackingorder(struct screen_ctx *sc)
|
||||||
{
|
{
|
||||||
Window *wins, w0, w1;
|
Window *wins, w0, w1;
|
||||||
struct screen_ctx *sc = screen_current();
|
|
||||||
u_int nwins, i, s;
|
|
||||||
struct client_ctx *cc;
|
struct client_ctx *cc;
|
||||||
|
u_int nwins, i, s;
|
||||||
|
|
||||||
if (!XQueryTree(X_Dpy, sc->rootwin, &w0, &w1, &wins, &nwins))
|
if (!XQueryTree(X_Dpy, sc->rootwin, &w0, &w1, &wins, &nwins))
|
||||||
return;
|
return;
|
||||||
@@ -74,41 +66,68 @@ screen_updatestackingorder(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
screen_init(void)
|
screen_init_xinerama(struct screen_ctx *sc)
|
||||||
{
|
{
|
||||||
|
XineramaScreenInfo *info;
|
||||||
|
int no;
|
||||||
|
|
||||||
struct screen_ctx *sc = screen_current();
|
if (HasXinerama == 0 || XineramaIsActive(X_Dpy) == 0) {
|
||||||
|
HasXinerama = 0;
|
||||||
|
sc->xinerama_no = 0;
|
||||||
|
}
|
||||||
|
|
||||||
sc->cycle_client = NULL;
|
info = XineramaQueryScreens(X_Dpy, &no);
|
||||||
|
if (info == NULL) {
|
||||||
|
/* Is xinerama actually off, instead of a malloc failure? */
|
||||||
|
if (sc->xinerama == NULL)
|
||||||
|
HasXinerama = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
sc->infowin = XCreateSimpleWindow(X_Dpy, sc->rootwin, 0, 0,
|
if (sc->xinerama != NULL)
|
||||||
1, 1, 1, sc->blackpixl, sc->whitepixl);
|
XFree(sc->xinerama);
|
||||||
|
sc->xinerama = info;
|
||||||
|
sc->xinerama_no = no;
|
||||||
|
}
|
||||||
|
|
||||||
/* XXX - marius. */
|
/*
|
||||||
if (signal(SIGALRM, _clearwindow_cb) == SIG_ERR)
|
* Find which xinerama screen the coordinates (x,y) is on.
|
||||||
err(1, "signal");
|
*/
|
||||||
|
XineramaScreenInfo *
|
||||||
|
screen_find_xinerama(struct screen_ctx *sc, int x, int y)
|
||||||
|
{
|
||||||
|
XineramaScreenInfo *info;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < sc->xinerama_no; i++) {
|
||||||
|
info = &sc->xinerama[i];
|
||||||
|
if (x > info->x_org && x < info->x_org + info->width &&
|
||||||
|
y > info->y_org && y < info->y_org + info->height)
|
||||||
|
return (info);
|
||||||
|
}
|
||||||
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
screen_infomsg(char *msg)
|
screen_update_geometry(struct screen_ctx *sc, int width, int height)
|
||||||
{
|
{
|
||||||
struct screen_ctx *sc = screen_current();
|
long geom[2], workareas[CALMWM_NGROUPS][4];
|
||||||
char buf[1024];
|
int i;
|
||||||
int dy, dx;
|
|
||||||
struct fontdesc *font = DefaultFont;
|
|
||||||
|
|
||||||
XUnmapWindow(X_Dpy, sc->infowin);
|
sc->xmax = geom[0] = width;
|
||||||
alarm(0);
|
sc->ymax = geom[1] = height;
|
||||||
|
XChangeProperty(X_Dpy, sc->rootwin, _NET_DESKTOP_GEOMETRY,
|
||||||
|
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)geom , 2);
|
||||||
|
|
||||||
snprintf(buf, sizeof(buf), ">%s", msg);
|
/* x, y, width, height. */
|
||||||
dy = font_ascent(font) + font_descent(font) + 1;
|
for (i = 0; i < CALMWM_NGROUPS; i++) {
|
||||||
dx = font_width(font, buf, strlen(buf));
|
workareas[i][0] = sc->gap.left;
|
||||||
|
workareas[i][1] = sc->gap.top;
|
||||||
|
workareas[i][2] = width - (sc->gap.left + sc->gap.right);
|
||||||
|
workareas[i][3] = height - (sc->gap.top + sc->gap.bottom);
|
||||||
|
}
|
||||||
|
|
||||||
XMoveResizeWindow(X_Dpy, sc->infowin, 0, 0, dx, dy);
|
XChangeProperty(X_Dpy, sc->rootwin, _NET_WORKAREA,
|
||||||
XMapRaised(X_Dpy, sc->infowin);
|
XA_CARDINAL, 32, PropModeReplace,
|
||||||
|
(unsigned char *)workareas, CALMWM_NGROUPS * 4);
|
||||||
font_draw(font, buf, strlen(buf), sc->infowin,
|
|
||||||
0, font_ascent(font) + 1);
|
|
||||||
|
|
||||||
alarm(1);
|
|
||||||
}
|
}
|
||||||
|
349
search.c
349
search.c
@@ -17,291 +17,21 @@
|
|||||||
* $Id$
|
* $Id$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "headers.h"
|
#include <sys/param.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <err.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fnmatch.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "calmwm.h"
|
#include "calmwm.h"
|
||||||
|
|
||||||
#define SearchMask (KeyPressMask|ExposureMask)
|
static int strsubmatch(char *, char *, int);
|
||||||
|
|
||||||
static int _strsubmatch(char *, char *, int);
|
|
||||||
|
|
||||||
void
|
|
||||||
search_init(struct screen_ctx *sc)
|
|
||||||
{
|
|
||||||
sc->searchwin = XCreateSimpleWindow(X_Dpy, sc->rootwin, 0, 0,
|
|
||||||
1, 1, 1, sc->blackpixl, sc->whitepixl);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* ranking. each rank type is assigned a weight. multiply this by
|
|
||||||
* the rank given. add them up. simple linear combination.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Input: list of items,
|
|
||||||
* Output: choose one
|
|
||||||
* so, exactly like menus
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct menu *
|
|
||||||
search_start(struct menu_q *menuq,
|
|
||||||
void (*match)(struct menu_q *, struct menu_q *, char *),
|
|
||||||
void (*rank)(struct menu_q *resultq, char *search),
|
|
||||||
void (*print)(struct menu *mi, int print),
|
|
||||||
char *prompt, int dummy)
|
|
||||||
{
|
|
||||||
struct screen_ctx *sc = screen_current();
|
|
||||||
int x, y, dx, dy, fontheight,
|
|
||||||
focusrevert, mutated, xmax, ymax, warp, added, beobnoxious = 0;
|
|
||||||
XEvent e;
|
|
||||||
char searchstr[MENU_MAXENTRY + 1];
|
|
||||||
char dispstr[MENU_MAXENTRY*2 + 1];
|
|
||||||
char promptstr[MENU_MAXENTRY + 1];
|
|
||||||
Window focuswin;
|
|
||||||
struct menu *mi = NULL, *dummy_mi = NULL;
|
|
||||||
struct menu_q resultq;
|
|
||||||
char chr;
|
|
||||||
enum ctltype ctl;
|
|
||||||
size_t len;
|
|
||||||
u_int n;
|
|
||||||
static int list = 0;
|
|
||||||
int listing = 0;
|
|
||||||
char endchar = '<EFBFBD>';
|
|
||||||
struct fontdesc *font = DefaultFont;
|
|
||||||
|
|
||||||
if (prompt == NULL)
|
|
||||||
prompt = "search";
|
|
||||||
|
|
||||||
TAILQ_INIT(&resultq);
|
|
||||||
|
|
||||||
xmax = DisplayWidth(X_Dpy, sc->which);
|
|
||||||
ymax = DisplayHeight(X_Dpy, sc->which);
|
|
||||||
|
|
||||||
xu_ptr_getpos(sc->rootwin, &x, &y);
|
|
||||||
|
|
||||||
searchstr[0] = '\0';
|
|
||||||
|
|
||||||
snprintf(promptstr, sizeof(promptstr), "%s <20>", prompt);
|
|
||||||
dy = fontheight = font_ascent(font) + font_descent(font) + 1;
|
|
||||||
snprintf(dispstr, sizeof(dispstr), "%s%c", promptstr, endchar);
|
|
||||||
dx = font_width(font, dispstr, strlen(dispstr));
|
|
||||||
|
|
||||||
XMoveResizeWindow(X_Dpy, sc->searchwin, x, y, dx, dy);
|
|
||||||
XSelectInput(X_Dpy, sc->searchwin, SearchMask);
|
|
||||||
XMapRaised(X_Dpy, sc->searchwin);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* TODO: eventually, the mouse should be able to select
|
|
||||||
* results as well. Right now we grab it only to set a fancy
|
|
||||||
* cursor.
|
|
||||||
*/
|
|
||||||
if (xu_ptr_grab(sc->searchwin, 0, Cursor_question) < 0) {
|
|
||||||
XUnmapWindow(X_Dpy, sc->searchwin);
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
XGetInputFocus(X_Dpy, &focuswin, &focusrevert);
|
|
||||||
XSetInputFocus(X_Dpy, sc->searchwin, RevertToPointerRoot, CurrentTime);
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
added = mutated = 0;
|
|
||||||
|
|
||||||
XMaskEvent(X_Dpy, SearchMask, &e);
|
|
||||||
|
|
||||||
switch (e.type) {
|
|
||||||
case KeyPress:
|
|
||||||
/*
|
|
||||||
* XXX - C-s & C-r for next and prev.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (input_keycodetrans(e.xkey.keycode, e.xkey.state,
|
|
||||||
&ctl, &chr, 1) < 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
switch (ctl) {
|
|
||||||
case CTL_ERASEONE:
|
|
||||||
if ((len = strlen(searchstr)) > 0) {
|
|
||||||
searchstr[len - 1] = '\0';
|
|
||||||
mutated = 1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CTL_UP:
|
|
||||||
mi = TAILQ_LAST(&resultq, menu_q);
|
|
||||||
if (mi == NULL)
|
|
||||||
break;
|
|
||||||
|
|
||||||
TAILQ_REMOVE(&resultq, mi, resultentry);
|
|
||||||
TAILQ_INSERT_HEAD(&resultq, mi, resultentry);
|
|
||||||
break;
|
|
||||||
case CTL_DOWN:
|
|
||||||
mi = TAILQ_FIRST(&resultq);
|
|
||||||
if (mi == NULL)
|
|
||||||
break;
|
|
||||||
|
|
||||||
TAILQ_REMOVE(&resultq, mi, resultentry);
|
|
||||||
TAILQ_INSERT_TAIL(&resultq, mi, resultentry);
|
|
||||||
break;
|
|
||||||
case CTL_RETURN:
|
|
||||||
/* This is just picking the match the
|
|
||||||
* cursor is over. */
|
|
||||||
if ((mi = TAILQ_FIRST(&resultq)) != NULL) {
|
|
||||||
goto found;
|
|
||||||
} else if (dummy) {
|
|
||||||
dummy_mi = xmalloc(sizeof *dummy_mi);
|
|
||||||
(void) strlcpy(dummy_mi->text,
|
|
||||||
searchstr, sizeof(dummy_mi->text));
|
|
||||||
dummy_mi->dummy = 1;
|
|
||||||
goto found;
|
|
||||||
}
|
|
||||||
goto out;
|
|
||||||
case CTL_WIPE:
|
|
||||||
searchstr[0] = '\0';
|
|
||||||
mutated = 1;
|
|
||||||
break;
|
|
||||||
case CTL_ALL:
|
|
||||||
list = !list;
|
|
||||||
break;
|
|
||||||
case CTL_ABORT:
|
|
||||||
goto out;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (chr != '\0') {
|
|
||||||
char str[2];
|
|
||||||
|
|
||||||
str[0] = chr;
|
|
||||||
str[1] = '\0';
|
|
||||||
mutated = 1;
|
|
||||||
added =
|
|
||||||
strlcat(searchstr, str, sizeof(searchstr));
|
|
||||||
}
|
|
||||||
|
|
||||||
beobnoxious = 0;
|
|
||||||
if (mutated && strlen(searchstr) > 0) {
|
|
||||||
(*match)(menuq, &resultq, searchstr);
|
|
||||||
beobnoxious = TAILQ_EMPTY(&resultq);
|
|
||||||
if (!beobnoxious && rank != NULL)
|
|
||||||
(*rank)(&resultq, searchstr);
|
|
||||||
} else if (mutated)
|
|
||||||
TAILQ_INIT(&resultq);
|
|
||||||
|
|
||||||
|
|
||||||
if (!list && listing && !mutated) {
|
|
||||||
TAILQ_INIT(&resultq);
|
|
||||||
listing = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
case Expose:
|
|
||||||
if (list) {
|
|
||||||
if (TAILQ_EMPTY(&resultq) && list) {
|
|
||||||
/* Copy them over and rank them. */
|
|
||||||
TAILQ_FOREACH(mi, menuq, entry)
|
|
||||||
TAILQ_INSERT_TAIL(&resultq, mi,
|
|
||||||
resultentry);
|
|
||||||
if (rank != NULL)
|
|
||||||
(*rank)(&resultq, searchstr);
|
|
||||||
|
|
||||||
listing = 1;
|
|
||||||
} else if (mutated)
|
|
||||||
listing = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
snprintf(dispstr, sizeof(dispstr), "%s%s%c",
|
|
||||||
promptstr, searchstr, endchar);
|
|
||||||
dx = font_width(font, dispstr, strlen(dispstr));
|
|
||||||
dy = fontheight;
|
|
||||||
|
|
||||||
TAILQ_FOREACH(mi, &resultq, resultentry) {
|
|
||||||
char *text;
|
|
||||||
|
|
||||||
if (print != NULL) {
|
|
||||||
(*print)(mi, listing);
|
|
||||||
text = mi->print;
|
|
||||||
} else {
|
|
||||||
mi->print[0] = '\0';
|
|
||||||
text = mi->text;
|
|
||||||
}
|
|
||||||
|
|
||||||
dx = MAX(dx, font_width(font, text,
|
|
||||||
MIN(strlen(text), MENU_MAXENTRY)));
|
|
||||||
dy += fontheight;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Calculate new geometry.
|
|
||||||
*
|
|
||||||
* XXX - put this into a util function -- it's
|
|
||||||
* used elsewhere, too.
|
|
||||||
*/
|
|
||||||
warp = 0;
|
|
||||||
if (x < 0) {
|
|
||||||
x = 0;
|
|
||||||
warp = 1;
|
|
||||||
}
|
|
||||||
if (x + dx >= xmax) {
|
|
||||||
x = xmax - dx;
|
|
||||||
warp = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (y < 0) {
|
|
||||||
y = 0;
|
|
||||||
warp = 1;
|
|
||||||
}
|
|
||||||
if (y + dy >= ymax) {
|
|
||||||
y = ymax - dy;
|
|
||||||
/* If the menu is too high, never hide the
|
|
||||||
* top of the menu.
|
|
||||||
*/
|
|
||||||
if (y < 0)
|
|
||||||
y = 0;
|
|
||||||
warp = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (warp)
|
|
||||||
xu_ptr_setpos(sc->rootwin, x, y);
|
|
||||||
|
|
||||||
XClearWindow(X_Dpy, sc->searchwin);
|
|
||||||
XMoveResizeWindow(X_Dpy, sc->searchwin, x, y, dx, dy);
|
|
||||||
|
|
||||||
font_draw(font, dispstr, strlen(dispstr), sc->searchwin,
|
|
||||||
0, font_ascent(font) + 1);
|
|
||||||
|
|
||||||
n = 1;
|
|
||||||
TAILQ_FOREACH(mi, &resultq, resultentry) {
|
|
||||||
char *text = mi->print[0] != '\0' ?
|
|
||||||
mi->print : mi->text;
|
|
||||||
|
|
||||||
font_draw(font, text,
|
|
||||||
MIN(strlen(text), MENU_MAXENTRY),
|
|
||||||
sc->searchwin,
|
|
||||||
0, n*fontheight + font_ascent(font) + 1);
|
|
||||||
n++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (n > 1)
|
|
||||||
XFillRectangle(X_Dpy, sc->searchwin, sc->gc,
|
|
||||||
0, fontheight, dx, fontheight);
|
|
||||||
|
|
||||||
if (beobnoxious)
|
|
||||||
XFillRectangle(X_Dpy, sc->searchwin, sc->gc,
|
|
||||||
0, 0, dx, fontheight);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
/* (if no match) */
|
|
||||||
xu_ptr_ungrab();
|
|
||||||
XSetInputFocus(X_Dpy, focuswin, focusrevert, CurrentTime);
|
|
||||||
|
|
||||||
found:
|
|
||||||
XUnmapWindow(X_Dpy, sc->searchwin);
|
|
||||||
|
|
||||||
if (dummy && dummy_mi != NULL)
|
|
||||||
return (dummy_mi);
|
|
||||||
return (mi);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Match: label, title, class.
|
* Match: label, title, class.
|
||||||
@@ -312,7 +42,9 @@ search_match_client(struct menu_q *menuq, struct menu_q *resultq, char *search)
|
|||||||
{
|
{
|
||||||
struct winname *wn;
|
struct winname *wn;
|
||||||
struct menu *mi, *tierp[4], *before = NULL;
|
struct menu *mi, *tierp[4], *before = NULL;
|
||||||
int ntiers = sizeof(tierp)/sizeof(tierp[0]);
|
int ntiers;
|
||||||
|
|
||||||
|
ntiers = sizeof(tierp) / sizeof(tierp[0]);
|
||||||
|
|
||||||
TAILQ_INIT(resultq);
|
TAILQ_INIT(resultq);
|
||||||
|
|
||||||
@@ -331,7 +63,7 @@ search_match_client(struct menu_q *menuq, struct menu_q *resultq, char *search)
|
|||||||
struct client_ctx *cc = mi->ctx;
|
struct client_ctx *cc = mi->ctx;
|
||||||
|
|
||||||
/* First, try to match on labels. */
|
/* 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;
|
cc->matchname = cc->label;
|
||||||
tier = 0;
|
tier = 0;
|
||||||
}
|
}
|
||||||
@@ -339,19 +71,15 @@ search_match_client(struct menu_q *menuq, struct menu_q *resultq, char *search)
|
|||||||
/* Then, on window names. */
|
/* Then, on window names. */
|
||||||
if (tier < 0) {
|
if (tier < 0) {
|
||||||
TAILQ_FOREACH_REVERSE(wn, &cc->nameq, winname_q, entry)
|
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;
|
cc->matchname = wn->name;
|
||||||
tier = 2;
|
tier = 2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* Then if there is a match on the window class name. */
|
||||||
* See if there is a match on the window class
|
if (tier < 0 && strsubmatch(search, cc->app_class, 0)) {
|
||||||
* name.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (tier < 0 && _strsubmatch(search, cc->app_class, 0)) {
|
|
||||||
cc->matchname = cc->app_class;
|
cc->matchname = cc->app_class;
|
||||||
tier = 3;
|
tier = 3;
|
||||||
}
|
}
|
||||||
@@ -367,9 +95,7 @@ search_match_client(struct menu_q *menuq, struct menu_q *resultq, char *search)
|
|||||||
if (cc == client_current() && tier < ntiers - 1)
|
if (cc == client_current() && tier < ntiers - 1)
|
||||||
tier++;
|
tier++;
|
||||||
|
|
||||||
/*
|
/* Clients that are hidden get ranked one up. */
|
||||||
* Clients that are hidden get ranked one up.
|
|
||||||
*/
|
|
||||||
if (cc->flags & CLIENT_HIDDEN && tier > 0)
|
if (cc->flags & CLIENT_HIDDEN && tier > 0)
|
||||||
tier--;
|
tier--;
|
||||||
|
|
||||||
@@ -382,7 +108,6 @@ search_match_client(struct menu_q *menuq, struct menu_q *resultq, char *search)
|
|||||||
* Always make your current tierp the newly inserted
|
* Always make your current tierp the newly inserted
|
||||||
* entry.
|
* entry.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for (t = tier; t >= 0 && ((before = tierp[t]) == NULL); t--)
|
for (t = tier; t >= 0 && ((before = tierp[t]) == NULL); t--)
|
||||||
;
|
;
|
||||||
|
|
||||||
@@ -398,24 +123,28 @@ search_match_client(struct menu_q *menuq, struct menu_q *resultq, char *search)
|
|||||||
void
|
void
|
||||||
search_print_client(struct menu *mi, int list)
|
search_print_client(struct menu *mi, int list)
|
||||||
{
|
{
|
||||||
struct client_ctx *cc = mi->ctx;
|
struct client_ctx *cc;
|
||||||
char flag = ' ';
|
char flag = ' ';
|
||||||
|
|
||||||
|
cc = mi->ctx;
|
||||||
|
|
||||||
if (cc == client_current())
|
if (cc == client_current())
|
||||||
flag = '!';
|
flag = '!';
|
||||||
else if (cc->flags & CLIENT_HIDDEN)
|
else if (cc->flags & CLIENT_HIDDEN)
|
||||||
flag = '&';
|
flag = '&';
|
||||||
|
|
||||||
if (list)
|
if (list)
|
||||||
cc->matchname = TAILQ_FIRST(&cc->nameq)->name;
|
cc->matchname = cc->name;
|
||||||
|
|
||||||
snprintf(mi->print, sizeof(mi->print), "%c%s", flag, cc->matchname);
|
snprintf(mi->print, sizeof(mi->print), "%c%s", flag, cc->matchname);
|
||||||
|
|
||||||
if (!list && cc->matchname != cc->name &&
|
if (!list && cc->matchname != cc->name &&
|
||||||
strlen(mi->print) < sizeof(mi->print) - 1) {
|
strlen(mi->print) < sizeof(mi->print) - 1) {
|
||||||
int diff = sizeof(mi->print) - 1 - strlen(mi->print);
|
|
||||||
const char *marker = "";
|
const char *marker = "";
|
||||||
char buf[MENU_MAXENTRY + 1];
|
char buf[MENU_MAXENTRY + 1];
|
||||||
|
int diff;
|
||||||
|
|
||||||
|
diff = sizeof(mi->print) - 1 - strlen(mi->print);
|
||||||
|
|
||||||
/* One for the ':' */
|
/* One for the ':' */
|
||||||
diff -= 1;
|
diff -= 1;
|
||||||
@@ -441,24 +170,35 @@ search_match_text(struct menu_q *menuq, struct menu_q *resultq, char *search)
|
|||||||
TAILQ_INIT(resultq);
|
TAILQ_INIT(resultq);
|
||||||
|
|
||||||
TAILQ_FOREACH(mi, menuq, entry)
|
TAILQ_FOREACH(mi, menuq, entry)
|
||||||
if (_strsubmatch(search, mi->text, 0))
|
if (strsubmatch(search, mi->text, 0))
|
||||||
TAILQ_INSERT_TAIL(resultq, mi, resultentry);
|
TAILQ_INSERT_TAIL(resultq, mi, resultentry);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
search_match_exec(struct menu_q *menuq, struct menu_q *resultq, char *search)
|
search_match_exec(struct menu_q *menuq, struct menu_q *resultq, char *search)
|
||||||
{
|
{
|
||||||
struct menu *mi;
|
struct menu *mi, *mj;
|
||||||
|
|
||||||
TAILQ_INIT(resultq);
|
TAILQ_INIT(resultq);
|
||||||
|
|
||||||
TAILQ_FOREACH(mi, menuq, entry)
|
TAILQ_FOREACH(mi, menuq, entry) {
|
||||||
if (_strsubmatch(search, mi->text, 1))
|
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);
|
TAILQ_INSERT_TAIL(resultq, mi, resultentry);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
_strsubmatch(char *sub, char *str, int zeroidx)
|
strsubmatch(char *sub, char *str, int zeroidx)
|
||||||
{
|
{
|
||||||
size_t len, sublen;
|
size_t len, sublen;
|
||||||
u_int n, flen;
|
u_int n, flen;
|
||||||
@@ -476,6 +216,7 @@ _strsubmatch(char *sub, char *str, int zeroidx)
|
|||||||
flen = len - sublen;
|
flen = len - sublen;
|
||||||
else
|
else
|
||||||
flen = 0;
|
flen = 0;
|
||||||
|
|
||||||
for (n = 0; n <= flen; n++)
|
for (n = 0; n <= flen; n++)
|
||||||
if (strncasecmp(sub, str + n, sublen) == 0)
|
if (strncasecmp(sub, str + n, sublen) == 0)
|
||||||
return (1);
|
return (1);
|
||||||
|
61
strlcat.c
Normal file
61
strlcat.c
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
/* $OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* OPENBSD ORIGINAL: lib/libc/string/strlcat.c */
|
||||||
|
|
||||||
|
#ifndef HAVE_STRLCAT
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Appends src to string dst of size siz (unlike strncat, siz is the
|
||||||
|
* full size of dst, not space left). At most siz-1 characters
|
||||||
|
* will be copied. Always NUL terminates (unless siz <= strlen(dst)).
|
||||||
|
* Returns strlen(src) + MIN(siz, strlen(initial dst)).
|
||||||
|
* If retval >= siz, truncation occurred.
|
||||||
|
*/
|
||||||
|
size_t
|
||||||
|
strlcat(char *dst, const char *src, size_t siz)
|
||||||
|
{
|
||||||
|
char *d = dst;
|
||||||
|
const char *s = src;
|
||||||
|
size_t n = siz;
|
||||||
|
size_t dlen;
|
||||||
|
|
||||||
|
/* Find the end of dst and adjust bytes left but don't go past end */
|
||||||
|
while (n-- != 0 && *d != '\0')
|
||||||
|
d++;
|
||||||
|
dlen = d - dst;
|
||||||
|
n = siz - dlen;
|
||||||
|
|
||||||
|
if (n == 0)
|
||||||
|
return(dlen + strlen(s));
|
||||||
|
while (*s != '\0') {
|
||||||
|
if (n != 1) {
|
||||||
|
*d++ = *s;
|
||||||
|
n--;
|
||||||
|
}
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
*d = '\0';
|
||||||
|
|
||||||
|
return(dlen + (s - src)); /* count does not include NUL */
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* !HAVE_STRLCAT */
|
57
strlcpy.c
Normal file
57
strlcpy.c
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
/* $OpenBSD: strlcpy.c,v 1.10 2005/08/08 08:05:37 espie Exp $ */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* OPENBSD ORIGINAL: lib/libc/string/strlcpy.c */
|
||||||
|
|
||||||
|
#ifndef HAVE_STRLCPY
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copy src to string dst of size siz. At most siz-1 characters
|
||||||
|
* will be copied. Always NUL terminates (unless siz == 0).
|
||||||
|
* Returns strlen(src); if retval >= siz, truncation occurred.
|
||||||
|
*/
|
||||||
|
size_t
|
||||||
|
strlcpy(char *dst, const char *src, size_t siz)
|
||||||
|
{
|
||||||
|
char *d = dst;
|
||||||
|
const char *s = src;
|
||||||
|
size_t n = siz;
|
||||||
|
|
||||||
|
/* Copy as many bytes as will fit */
|
||||||
|
if (n != 0 && --n != 0) {
|
||||||
|
do {
|
||||||
|
if ((*d++ = *s++) == 0)
|
||||||
|
break;
|
||||||
|
} while (--n != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Not enough room in dst, add NUL and traverse rest of src */
|
||||||
|
if (n == 0) {
|
||||||
|
if (siz != 0)
|
||||||
|
*d = '\0'; /* NUL-terminate dst */
|
||||||
|
while (*s++)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
return(s - src - 1); /* count does not include NUL */
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* !HAVE_STRLCPY */
|
70
strtonum.c
Normal file
70
strtonum.c
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
/* $OpenBSD: strtonum.c,v 1.6 2004/08/03 19:38:01 millert Exp $ */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2004 Ted Unangst and Todd Miller
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* OPENBSD ORIGINAL: lib/libc/stdlib/strtonum.c */
|
||||||
|
|
||||||
|
#ifndef HAVE_STRTONUM
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#define INVALID 1
|
||||||
|
#define TOOSMALL 2
|
||||||
|
#define TOOLARGE 3
|
||||||
|
|
||||||
|
long long
|
||||||
|
strtonum(const char *numstr, long long minval, long long maxval,
|
||||||
|
const char **errstrp)
|
||||||
|
{
|
||||||
|
long long ll = 0;
|
||||||
|
char *ep;
|
||||||
|
int error = 0;
|
||||||
|
struct errval {
|
||||||
|
const char *errstr;
|
||||||
|
int err;
|
||||||
|
} ev[4] = {
|
||||||
|
{ NULL, 0 },
|
||||||
|
{ "invalid", EINVAL },
|
||||||
|
{ "too small", ERANGE },
|
||||||
|
{ "too large", ERANGE },
|
||||||
|
};
|
||||||
|
|
||||||
|
ev[0].err = errno;
|
||||||
|
errno = 0;
|
||||||
|
if (minval > maxval)
|
||||||
|
error = INVALID;
|
||||||
|
else {
|
||||||
|
ll = strtoll(numstr, &ep, 10);
|
||||||
|
if (numstr == ep || *ep != '\0')
|
||||||
|
error = INVALID;
|
||||||
|
else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval)
|
||||||
|
error = TOOSMALL;
|
||||||
|
else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval)
|
||||||
|
error = TOOLARGE;
|
||||||
|
}
|
||||||
|
if (errstrp != NULL)
|
||||||
|
*errstrp = ev[error].errstr;
|
||||||
|
errno = ev[error].err;
|
||||||
|
if (error)
|
||||||
|
ll = 0;
|
||||||
|
|
||||||
|
return (ll);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* HAVE_STRTONUM */
|
76
util.c
76
util.c
@@ -18,7 +18,16 @@
|
|||||||
* $Id$
|
* $Id$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "headers.h"
|
#include <sys/param.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
|
|
||||||
|
#include <err.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "calmwm.h"
|
#include "calmwm.h"
|
||||||
|
|
||||||
#define MAXARGLEN 20
|
#define MAXARGLEN 20
|
||||||
@@ -26,19 +35,10 @@
|
|||||||
int
|
int
|
||||||
u_spawn(char *argstr)
|
u_spawn(char *argstr)
|
||||||
{
|
{
|
||||||
char *args[MAXARGLEN], **ap;
|
|
||||||
char **end = &args[MAXARGLEN - 1];
|
|
||||||
|
|
||||||
switch (fork()) {
|
switch (fork()) {
|
||||||
case 0:
|
case 0:
|
||||||
ap = args;
|
u_exec(argstr);
|
||||||
while (ap < end && (*ap = strsep(&argstr, " \t")) != NULL)
|
err(1, "%s", argstr);
|
||||||
ap++;
|
|
||||||
|
|
||||||
*ap = NULL;
|
|
||||||
setsid();
|
|
||||||
execvp(args[0], args);
|
|
||||||
err(1, args[0]);
|
|
||||||
break;
|
break;
|
||||||
case -1:
|
case -1:
|
||||||
warn("fork");
|
warn("fork");
|
||||||
@@ -51,42 +51,34 @@ u_spawn(char *argstr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
exec_wm(char *argstr)
|
u_exec(char *argstr)
|
||||||
{
|
{
|
||||||
char *args[MAXARGLEN], **ap = args;
|
char *args[MAXARGLEN], **ap = args;
|
||||||
char **end = &args[MAXARGLEN - 1];
|
char **end = &args[MAXARGLEN - 1], *tmp;
|
||||||
|
|
||||||
while (ap < end && (*ap = strsep(&argstr, " \t")) != NULL)
|
while (ap < end && (*ap = strsep(&argstr, " \t")) != NULL) {
|
||||||
|
if (**ap == '\0')
|
||||||
|
continue;
|
||||||
ap++;
|
ap++;
|
||||||
|
if (argstr != NULL) {
|
||||||
|
/* deal with quoted strings */
|
||||||
|
switch(argstr[0]) {
|
||||||
|
case '"':
|
||||||
|
case '\'':
|
||||||
|
if ((tmp = strchr(argstr + 1, argstr[0]))
|
||||||
|
!= NULL) {
|
||||||
|
*(tmp++) = '\0';
|
||||||
|
*(ap++) = ++argstr;
|
||||||
|
argstr = tmp;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
*ap = NULL;
|
*ap = NULL;
|
||||||
setsid();
|
setsid();
|
||||||
execvp(args[0], args);
|
execvp(args[0], args);
|
||||||
warn(args[0]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int dirent_isdir(char *filename) {
|
|
||||||
struct stat buffer;
|
|
||||||
int return_value;
|
|
||||||
|
|
||||||
return_value = stat(filename, &buffer);
|
|
||||||
|
|
||||||
if(return_value == -1)
|
|
||||||
return 0;
|
|
||||||
else
|
|
||||||
return S_ISDIR(buffer.st_mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
int dirent_islink(char *filename) {
|
|
||||||
struct stat buffer;
|
|
||||||
int return_value;
|
|
||||||
|
|
||||||
return_value = lstat(filename, &buffer);
|
|
||||||
|
|
||||||
if(return_value == -1)
|
|
||||||
return 0;
|
|
||||||
else
|
|
||||||
return S_ISLNK(buffer.st_mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
592
xevents.c
592
xevents.c
@@ -24,84 +24,116 @@
|
|||||||
* management of the xevent's.
|
* management of the xevent's.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "headers.h"
|
#include <sys/param.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
|
|
||||||
|
#include <err.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "calmwm.h"
|
#include "calmwm.h"
|
||||||
|
|
||||||
/*
|
static void xev_handle_maprequest(XEvent *);
|
||||||
* NOTE: in reality, many of these should move to client.c now that
|
static void xev_handle_unmapnotify(XEvent *);
|
||||||
* we've got this nice event layer.
|
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;
|
XMapRequestEvent *e = &ee->xmaprequest;
|
||||||
struct client_ctx *cc = NULL, *old_cc = client_current();
|
struct client_ctx *cc = NULL, *old_cc;
|
||||||
XWindowAttributes xattr;
|
XWindowAttributes xattr;
|
||||||
struct screen_ctx *sc;
|
struct winmatch *wm;
|
||||||
#ifdef notyet
|
|
||||||
int state;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (old_cc != NULL)
|
if ((old_cc = client_current()) != NULL)
|
||||||
client_ptrsave(old_cc);
|
client_ptrsave(old_cc);
|
||||||
|
|
||||||
if ((cc = client_find(e->window)) == NULL) {
|
if ((cc = client_find(e->window)) == NULL) {
|
||||||
XGetWindowAttributes(X_Dpy, e->window, &xattr);
|
XGetWindowAttributes(X_Dpy, e->window, &xattr);
|
||||||
cc = client_new(e->window, screen_fromroot(xattr.root), 1);
|
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
|
TAILQ_FOREACH(wm, &Conf.ignoreq, entry) {
|
||||||
* the window is withdrawn. */
|
if (strncasecmp(wm->title, cc->name, strlen(wm->title)) == 0)
|
||||||
if (xu_getstate(cc, &state) == 0 && state == WithdrawnState)
|
return;
|
||||||
warnx("WITHDRAWNSTATE for %s", cc->name);
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
client_ptrwarp(cc);
|
client_ptrwarp(cc);
|
||||||
xev_register(xev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
xev_handle_unmapnotify(struct xevent *xev, XEvent *ee)
|
xev_handle_unmapnotify(XEvent *ee)
|
||||||
{
|
{
|
||||||
XUnmapEvent *e = &ee->xunmap;
|
XUnmapEvent *e = &ee->xunmap;
|
||||||
|
XEvent ev;
|
||||||
struct client_ctx *cc;
|
struct client_ctx *cc;
|
||||||
struct screen_ctx *sc;
|
|
||||||
int wascurrent;
|
|
||||||
|
|
||||||
|
/* XXX, we need a recursive locking wrapper around grab server */
|
||||||
|
XGrabServer(X_Dpy);
|
||||||
if ((cc = client_find(e->window)) != NULL) {
|
if ((cc = client_find(e->window)) != NULL) {
|
||||||
sc = CCTOSC(cc);
|
/*
|
||||||
wascurrent = cc == client_current();
|
* If it's going to die anyway, nuke it.
|
||||||
client_delete(cc, e->send_event, 0);
|
*
|
||||||
|
* Else, if it's a synthetic event delete state, since they
|
||||||
#ifdef notyet
|
* want it to be withdrawn. ICCM recommends you withdraw on
|
||||||
/* XXX disable the ptrwarp until we handle it
|
* this even if we haven't alredy been told to iconify, to
|
||||||
* better. */
|
* deal with legacy clients.
|
||||||
if (!client_delete(cc, e->send_event, 0) && wascurrent)
|
*/
|
||||||
;/* client_ptrwarp(new_cc); */
|
if (XCheckTypedWindowEvent(X_Dpy, cc->win,
|
||||||
#endif
|
DestroyNotify, &ev) || e->send_event != 0) {
|
||||||
|
client_delete(cc);
|
||||||
|
} else
|
||||||
|
client_hide(cc);
|
||||||
}
|
}
|
||||||
|
XUngrabServer(X_Dpy);
|
||||||
xev_register(xev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
xev_handle_destroynotify(struct xevent *xev, XEvent *ee)
|
xev_handle_destroynotify(XEvent *ee)
|
||||||
{
|
{
|
||||||
XDestroyWindowEvent *e = &ee->xdestroywindow;
|
XDestroyWindowEvent *e = &ee->xdestroywindow;
|
||||||
struct client_ctx *cc;
|
struct client_ctx *cc;
|
||||||
|
|
||||||
if ((cc = client_find(e->window)) != NULL)
|
if ((cc = client_find(e->window)) != NULL)
|
||||||
client_delete(cc, 1, 1);
|
client_delete(cc);
|
||||||
|
|
||||||
xev_register(xev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
xev_handle_configurerequest(struct xevent *xev, XEvent *ee)
|
xev_handle_configurerequest(XEvent *ee)
|
||||||
{
|
{
|
||||||
XConfigureRequestEvent *e = &ee->xconfigurerequest;
|
XConfigureRequestEvent *e = &ee->xconfigurerequest;
|
||||||
struct client_ctx *cc;
|
struct client_ctx *cc;
|
||||||
@@ -109,9 +141,8 @@ xev_handle_configurerequest(struct xevent *xev, XEvent *ee)
|
|||||||
XWindowChanges wc;
|
XWindowChanges wc;
|
||||||
|
|
||||||
if ((cc = client_find(e->window)) != NULL) {
|
if ((cc = client_find(e->window)) != NULL) {
|
||||||
sc = CCTOSC(cc);
|
sc = cc->sc;
|
||||||
|
|
||||||
client_gravitate(cc, 0);
|
|
||||||
if (e->value_mask & CWWidth)
|
if (e->value_mask & CWWidth)
|
||||||
cc->geom.width = e->width;
|
cc->geom.width = e->width;
|
||||||
if (e->value_mask & CWHeight)
|
if (e->value_mask & CWHeight)
|
||||||
@@ -120,53 +151,48 @@ xev_handle_configurerequest(struct xevent *xev, XEvent *ee)
|
|||||||
cc->geom.x = e->x;
|
cc->geom.x = e->x;
|
||||||
if (e->value_mask & CWY)
|
if (e->value_mask & CWY)
|
||||||
cc->geom.y = e->y;
|
cc->geom.y = e->y;
|
||||||
|
if (e->value_mask & CWBorderWidth)
|
||||||
|
wc.border_width = e->border_width;
|
||||||
|
|
||||||
if (cc->geom.x == 0 &&
|
if (cc->geom.x == 0 && cc->geom.width >= sc->xmax)
|
||||||
cc->geom.width >= DisplayWidth(X_Dpy, sc->which))
|
|
||||||
cc->geom.x -= cc->bwidth;
|
cc->geom.x -= cc->bwidth;
|
||||||
|
|
||||||
if (cc->geom.y == 0 &&
|
if (cc->geom.y == 0 && cc->geom.height >= sc->ymax)
|
||||||
cc->geom.height >= DisplayHeight(X_Dpy, sc->which))
|
|
||||||
cc->geom.y -= cc->bwidth;
|
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;
|
XConfigureWindow(X_Dpy, cc->win, e->value_mask, &wc);
|
||||||
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);
|
|
||||||
xev_reconfig(cc);
|
xev_reconfig(cc);
|
||||||
}
|
} else {
|
||||||
|
/* let it do what it wants, it'll be ours when we map it. */
|
||||||
wc.x = cc != NULL ? 0 : e->x;
|
wc.x = e->x;
|
||||||
wc.y = cc != NULL ? 0 : e->y;
|
wc.y = e->y;
|
||||||
wc.width = e->width;
|
wc.width = e->width;
|
||||||
wc.height = e->height;
|
wc.height = e->height;
|
||||||
|
wc.border_width = e->border_width;
|
||||||
wc.stack_mode = Above;
|
wc.stack_mode = Above;
|
||||||
wc.border_width = 0;
|
|
||||||
e->value_mask &= ~CWStackMode;
|
e->value_mask &= ~CWStackMode;
|
||||||
e->value_mask |= CWBorderWidth;
|
|
||||||
|
|
||||||
XConfigureWindow(X_Dpy, e->window, e->value_mask, &wc);
|
XConfigureWindow(X_Dpy, e->window, e->value_mask, &wc);
|
||||||
|
}
|
||||||
xev_register(xev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
xev_handle_propertynotify(struct xevent *xev, XEvent *ee)
|
xev_handle_propertynotify(XEvent *ee)
|
||||||
{
|
{
|
||||||
XPropertyEvent *e = &ee->xproperty;
|
XPropertyEvent *e = &ee->xproperty;
|
||||||
|
struct screen_ctx *sc;
|
||||||
struct client_ctx *cc;
|
struct client_ctx *cc;
|
||||||
long tmp;
|
|
||||||
|
|
||||||
if ((cc = client_find(e->window)) != NULL) {
|
if ((cc = client_find(e->window)) != NULL) {
|
||||||
switch(e->atom) {
|
switch (e->atom) {
|
||||||
case XA_WM_NORMAL_HINTS:
|
case XA_WM_NORMAL_HINTS:
|
||||||
XGetWMNormalHints(X_Dpy, cc->win, cc->size, &tmp);
|
client_getsizehints(cc);
|
||||||
break;
|
break;
|
||||||
case XA_WM_NAME:
|
case XA_WM_NAME:
|
||||||
client_setname(cc);
|
client_setname(cc);
|
||||||
@@ -175,9 +201,17 @@ xev_handle_propertynotify(struct xevent *xev, XEvent *ee)
|
|||||||
/* do nothing */
|
/* do nothing */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
TAILQ_FOREACH(sc, &Screenq, entry)
|
||||||
|
if (sc->rootwin == e->window)
|
||||||
|
goto test;
|
||||||
|
return;
|
||||||
|
|
||||||
|
test:
|
||||||
|
if (e->atom == _NET_DESKTOP_NAMES)
|
||||||
|
group_update_names(sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
xev_register(xev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -192,186 +226,76 @@ xev_reconfig(struct client_ctx *cc)
|
|||||||
ce.y = cc->geom.y;
|
ce.y = cc->geom.y;
|
||||||
ce.width = cc->geom.width;
|
ce.width = cc->geom.width;
|
||||||
ce.height = cc->geom.height;
|
ce.height = cc->geom.height;
|
||||||
ce.border_width = 0;
|
ce.border_width = cc->bwidth;
|
||||||
ce.above = None;
|
ce.above = None;
|
||||||
ce.override_redirect = 0;
|
ce.override_redirect = 0;
|
||||||
|
|
||||||
XSendEvent(X_Dpy, cc->win, False, StructureNotifyMask, (XEvent *)&ce);
|
XSendEvent(X_Dpy, cc->win, False, StructureNotifyMask, (XEvent *)&ce);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
xev_handle_enternotify(struct xevent *xev, XEvent *ee)
|
xev_handle_enternotify(XEvent *ee)
|
||||||
{
|
{
|
||||||
XCrossingEvent *e = &ee->xcrossing;
|
XCrossingEvent *e = &ee->xcrossing;
|
||||||
struct client_ctx *cc;
|
struct client_ctx *cc;
|
||||||
|
|
||||||
if ((cc = client_find(e->window)) == NULL) {
|
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
|
|
||||||
client_setactive(cc, 1);
|
client_setactive(cc, 1);
|
||||||
|
|
||||||
xev_register(xev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
xev_handle_leavenotify(struct xevent *xev, XEvent *ee)
|
xev_handle_leavenotify(XEvent *ee)
|
||||||
{
|
{
|
||||||
client_leave(NULL);
|
client_leave(NULL);
|
||||||
|
|
||||||
xev_register(xev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We can split this into two event handlers. */
|
/* We can split this into two event handlers. */
|
||||||
void
|
static void
|
||||||
xev_handle_buttonpress(struct xevent *xev, XEvent *ee)
|
xev_handle_buttonpress(XEvent *ee)
|
||||||
{
|
{
|
||||||
XButtonEvent *e = &ee->xbutton;
|
XButtonEvent *e = &ee->xbutton;
|
||||||
struct client_ctx *cc, *old_cc = client_current();
|
struct client_ctx *cc, fakecc;
|
||||||
struct screen_ctx *sc = screen_fromroot(e->root);
|
struct screen_ctx *sc;
|
||||||
char *wname;
|
struct mousebinding *mb;
|
||||||
int altcontrol = e->state == (ControlMask|Mod1Mask);
|
|
||||||
|
|
||||||
|
sc = screen_fromroot(e->root);
|
||||||
cc = client_find(e->window);
|
cc = client_find(e->window);
|
||||||
|
|
||||||
if (sc->rootwin == e->window && !altcontrol) {
|
/* Ignore caps lock and numlock */
|
||||||
struct menu_q menuq;
|
e->state &= ~(Mod2Mask | LockMask);
|
||||||
struct menu *mi;
|
|
||||||
|
|
||||||
/* XXXSIGH!!!! */
|
TAILQ_FOREACH(mb, &Conf.mousebindingq, entry) {
|
||||||
if (e->button == Button2) {
|
if (e->button == mb->button && e->state == mb->modmask)
|
||||||
group_menu(e);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
TAILQ_INIT(&menuq);
|
|
||||||
|
|
||||||
switch (e->button) {
|
|
||||||
case Button1:
|
|
||||||
TAILQ_FOREACH(cc, &Clientq, entry) {
|
|
||||||
if (cc->flags & CLIENT_HIDDEN) {
|
|
||||||
if (cc->label != NULL)
|
|
||||||
wname = cc->label;
|
|
||||||
else
|
|
||||||
wname = cc->name;
|
|
||||||
|
|
||||||
if (wname == NULL)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
XCALLOC(mi, struct menu);
|
|
||||||
strlcpy(mi->text,
|
|
||||||
wname, sizeof(mi->text));
|
|
||||||
mi->ctx = cc;
|
|
||||||
TAILQ_INSERT_TAIL(&menuq, mi, entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Button3: {
|
|
||||||
struct cmd *cmd;
|
|
||||||
if (conf_cmd_changed(Conf.menu_path)) {
|
|
||||||
conf_cmd_clear(&Conf);
|
|
||||||
conf_cmd_populate(&Conf, Conf.menu_path);
|
|
||||||
}
|
|
||||||
TAILQ_FOREACH(cmd, &Conf.cmdq, entry) {
|
|
||||||
XCALLOC(mi, struct menu);
|
|
||||||
strlcpy(mi->text, cmd->label, sizeof(mi->text));
|
|
||||||
mi->ctx = cmd;
|
|
||||||
TAILQ_INSERT_TAIL(&menuq, mi, entry);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TAILQ_EMPTY(&menuq))
|
if (mb == NULL)
|
||||||
goto out;
|
return;
|
||||||
|
if (mb->context == MOUSEBIND_CTX_ROOT) {
|
||||||
|
if (e->window != sc->rootwin)
|
||||||
|
return;
|
||||||
|
cc = &fakecc;
|
||||||
|
cc->sc = screen_fromroot(e->window);
|
||||||
|
} else if (cc == NULL) /* (mb->context == MOUSEBIND_CTX_WIN */
|
||||||
|
return;
|
||||||
|
|
||||||
mi = (struct menu *)grab_menu(e, &menuq);
|
(*mb->callback)(cc, e);
|
||||||
if (mi == NULL)
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
switch (e->button) {
|
|
||||||
case Button1:
|
|
||||||
cc = (struct client_ctx *)mi->ctx;
|
|
||||||
client_unhide(cc);
|
|
||||||
|
|
||||||
if (old_cc != NULL)
|
|
||||||
client_ptrsave(old_cc);
|
|
||||||
client_ptrwarp(cc);
|
|
||||||
break;
|
|
||||||
case Button3:
|
|
||||||
u_spawn(((struct cmd *)mi->ctx)->image);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
|
|
||||||
TAILQ_REMOVE(&menuq, mi, entry);
|
|
||||||
xfree(mi);
|
|
||||||
}
|
|
||||||
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cc == NULL || e->state == 0)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
sc = CCTOSC(cc);
|
|
||||||
|
|
||||||
switch (e->button) {
|
|
||||||
case Button1:
|
|
||||||
if (altcontrol && !Groupmode)
|
|
||||||
group_sticky_toggle_enter(cc);
|
|
||||||
else {
|
|
||||||
grab_drag(cc);
|
|
||||||
client_move(cc);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Button2:
|
|
||||||
/* XXXSIGH!!! */
|
|
||||||
if (Groupmode)
|
|
||||||
group_click(cc);
|
|
||||||
else {
|
|
||||||
grab_sweep(cc);
|
|
||||||
client_resize(cc);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Button3:
|
|
||||||
client_ptrsave(cc);
|
|
||||||
client_lower(cc);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
out:
|
|
||||||
xev_register(xev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
xev_handle_buttonrelease(struct xevent *xev, XEvent *ee)
|
xev_handle_buttonrelease(XEvent *ee)
|
||||||
{
|
{
|
||||||
struct client_ctx *cc = client_current();
|
struct client_ctx *cc;
|
||||||
|
|
||||||
if (cc != NULL && !Groupmode)
|
if ((cc = client_current()) != NULL)
|
||||||
group_sticky_toggle_exit(cc);
|
group_sticky_toggle_exit(cc);
|
||||||
|
|
||||||
xev_register(xev);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
xev_handle_keypress(struct xevent *xev, XEvent *ee)
|
xev_handle_keypress(XEvent *ee)
|
||||||
{
|
{
|
||||||
XKeyEvent *e = &ee->xkey;
|
XKeyEvent *e = &ee->xkey;
|
||||||
struct client_ctx *cc = NULL; /* Make gcc happy. */
|
struct client_ctx *cc = NULL, fakecc;
|
||||||
struct keybinding *kb;
|
struct keybinding *kb;
|
||||||
KeySym keysym, skeysym;
|
KeySym keysym, skeysym;
|
||||||
int modshift;
|
int modshift;
|
||||||
@@ -379,6 +303,9 @@ xev_handle_keypress(struct xevent *xev, XEvent *ee)
|
|||||||
keysym = XKeycodeToKeysym(X_Dpy, e->keycode, 0);
|
keysym = XKeycodeToKeysym(X_Dpy, e->keycode, 0);
|
||||||
skeysym = XKeycodeToKeysym(X_Dpy, e->keycode, 1);
|
skeysym = XKeycodeToKeysym(X_Dpy, e->keycode, 1);
|
||||||
|
|
||||||
|
/* we don't care about caps lock and numlock here */
|
||||||
|
e->state &= ~(LockMask | Mod2Mask);
|
||||||
|
|
||||||
TAILQ_FOREACH(kb, &Conf.keybindingq, entry) {
|
TAILQ_FOREACH(kb, &Conf.keybindingq, entry) {
|
||||||
if (keysym != kb->keysym && skeysym == kb->keysym)
|
if (keysym != kb->keysym && skeysym == kb->keysym)
|
||||||
modshift = ShiftMask;
|
modshift = ShiftMask;
|
||||||
@@ -394,37 +321,37 @@ xev_handle_keypress(struct xevent *xev, XEvent *ee)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kb == NULL && e->window == screen_current()->groupwin)
|
|
||||||
group_display_keypress(e->keycode);
|
|
||||||
|
|
||||||
if (kb == NULL)
|
if (kb == NULL)
|
||||||
goto out;
|
return;
|
||||||
|
if (kb->flags & KBFLAG_NEEDCLIENT) {
|
||||||
if ((kb->flags & (KBFLAG_NEEDCLIENT|KBFLAG_FINDCLIENT)) &&
|
if (((cc = client_find(e->window)) == NULL) &&
|
||||||
(cc = client_find(e->window)) == NULL &&
|
|
||||||
(cc = client_current()) == NULL)
|
(cc = client_current()) == NULL)
|
||||||
if (kb->flags & KBFLAG_NEEDCLIENT)
|
return;
|
||||||
goto out;
|
} else {
|
||||||
|
cc = &fakecc;
|
||||||
|
cc->sc = screen_fromroot(e->window);
|
||||||
|
}
|
||||||
|
|
||||||
(*kb->callback)(cc, kb->argument);
|
(*kb->callback)(cc, &kb->argument);
|
||||||
|
|
||||||
out:
|
|
||||||
xev_register(xev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is only used for the alt suppression detection.
|
* This is only used for the alt suppression detection.
|
||||||
*/
|
*/
|
||||||
void
|
static void
|
||||||
xev_handle_keyrelease(struct xevent *xev, XEvent *ee)
|
xev_handle_keyrelease(XEvent *ee)
|
||||||
{
|
{
|
||||||
XKeyEvent *e = &ee->xkey;
|
XKeyEvent *e = &ee->xkey;
|
||||||
struct screen_ctx *sc = screen_fromroot(e->root);
|
struct screen_ctx *sc;
|
||||||
|
struct client_ctx *cc;
|
||||||
int keysym;
|
int keysym;
|
||||||
|
|
||||||
|
sc = screen_fromroot(e->root);
|
||||||
|
cc = client_current();
|
||||||
|
|
||||||
keysym = XKeycodeToKeysym(X_Dpy, e->keycode, 0);
|
keysym = XKeycodeToKeysym(X_Dpy, e->keycode, 0);
|
||||||
if (keysym != XK_Alt_L && keysym != XK_Alt_R)
|
if (keysym != XK_Alt_L && keysym != XK_Alt_R)
|
||||||
goto out;
|
return;
|
||||||
|
|
||||||
sc->altpersist = 0;
|
sc->altpersist = 0;
|
||||||
|
|
||||||
@@ -433,180 +360,89 @@ xev_handle_keyrelease(struct xevent *xev, XEvent *ee)
|
|||||||
* how/when to mtf.
|
* how/when to mtf.
|
||||||
*/
|
*/
|
||||||
client_mtf(NULL);
|
client_mtf(NULL);
|
||||||
client_altrelease();
|
|
||||||
|
|
||||||
out:
|
if (cc != NULL) {
|
||||||
xev_register(xev);
|
group_sticky_toggle_exit(cc);
|
||||||
|
XUngrabKeyboard(X_Dpy, CurrentTime);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
xev_handle_clientmessage(struct xevent *xev, XEvent *ee)
|
xev_handle_clientmessage(XEvent *ee)
|
||||||
{
|
{
|
||||||
XClientMessageEvent *e = &ee->xclient;
|
XClientMessageEvent *e = &ee->xclient;
|
||||||
struct client_ctx *cc = client_find(e->window);
|
Atom xa_wm_change_state;
|
||||||
Atom xa_wm_change_state = XInternAtom(X_Dpy, "WM_CHANGE_STATE", False);
|
struct client_ctx *cc;
|
||||||
|
|
||||||
if (cc == NULL)
|
xa_wm_change_state = XInternAtom(X_Dpy, "WM_CHANGE_STATE", False);
|
||||||
goto out;
|
|
||||||
|
if ((cc = client_find(e->window)) == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
if (e->message_type == xa_wm_change_state && e->format == 32 &&
|
if (e->message_type == xa_wm_change_state && e->format == 32 &&
|
||||||
e->data.l[0] == IconicState)
|
e->data.l[0] == IconicState)
|
||||||
client_hide(cc);
|
client_hide(cc);
|
||||||
out:
|
|
||||||
xev_register(xev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static void
|
||||||
* X Event handling
|
xev_handle_randr(XEvent *ee)
|
||||||
*/
|
|
||||||
|
|
||||||
static struct xevent_q _xevq, _xevq_putaway;
|
|
||||||
static short _xev_q_lock = 0;
|
|
||||||
|
|
||||||
void
|
|
||||||
xev_init(void)
|
|
||||||
{
|
{
|
||||||
TAILQ_INIT(&_xevq);
|
XRRScreenChangeNotifyEvent *rev = (XRRScreenChangeNotifyEvent *)ee;
|
||||||
TAILQ_INIT(&_xevq_putaway);
|
struct screen_ctx *sc;
|
||||||
}
|
int i;
|
||||||
|
|
||||||
struct xevent *
|
i = XRRRootToScreen(X_Dpy, rev->root);
|
||||||
xev_new(Window *win, Window *root,
|
TAILQ_FOREACH(sc, &Screenq, entry) {
|
||||||
int type, void (*cb)(struct xevent *, XEvent *), void *arg)
|
if (sc->which == (u_int)i) {
|
||||||
{
|
XRRUpdateConfiguration(ee);
|
||||||
struct xevent *xev;
|
screen_update_geometry(sc, rev->width, rev->height);
|
||||||
|
screen_init_xinerama(sc);
|
||||||
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)
|
* Called when the keymap has changed.
|
||||||
|
* Ungrab all keys, reload keymap and then regrab
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
xev_handle_mappingnotify(XEvent *ee)
|
||||||
{
|
{
|
||||||
XExposeEvent *e = &ee->xexpose;
|
XMappingEvent *e = &ee->xmapping;
|
||||||
struct screen_ctx *sc = screen_current();
|
struct keybinding *kb;
|
||||||
struct client_ctx *cc;
|
|
||||||
|
|
||||||
if ((cc = client_find(e->window)) != NULL)
|
TAILQ_FOREACH(kb, &Conf.keybindingq, entry)
|
||||||
client_draw_border(cc);
|
conf_ungrab(&Conf, kb);
|
||||||
|
|
||||||
if (sc->groupwin == e->window)
|
XRefreshKeyboardMapping(e);
|
||||||
group_display_draw(sc);
|
|
||||||
|
|
||||||
xev_register(xev);
|
TAILQ_FOREACH(kb, &Conf.keybindingq, entry)
|
||||||
|
conf_grab(&Conf, kb);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ASSIGN(xtype) do { \
|
static void
|
||||||
root = e. xtype .root; \
|
xev_handle_expose(XEvent *ee)
|
||||||
win = e. xtype .window; \
|
{
|
||||||
} while (0)
|
XExposeEvent *e = &ee->xexpose;
|
||||||
|
struct client_ctx *cc;
|
||||||
|
|
||||||
#define ASSIGN1(xtype) do { \
|
if ((cc = client_find(e->window)) != NULL && e->count == 0)
|
||||||
win = e. xtype .window; \
|
client_draw_border(cc);
|
||||||
} while (0)
|
}
|
||||||
|
|
||||||
|
|
||||||
|
volatile sig_atomic_t _xev_quit = 0;
|
||||||
|
|
||||||
void
|
void
|
||||||
xev_loop(void)
|
xev_loop(void)
|
||||||
{
|
{
|
||||||
Window win, root;
|
|
||||||
int type;
|
|
||||||
XEvent e;
|
XEvent e;
|
||||||
struct xevent *xev, *nextxev;
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
#ifdef DIAGNOSTIC
|
|
||||||
if (TAILQ_EMPTY(&_xevq))
|
|
||||||
errx(1, "X event queue empty");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
while (_xev_quit == 0) {
|
||||||
XNextEvent(X_Dpy, &e);
|
XNextEvent(X_Dpy, &e);
|
||||||
type = e.type;
|
if (e.type - Randr_ev == RRScreenChangeNotify)
|
||||||
|
xev_handle_randr(&e);
|
||||||
win = root = 0;
|
else if (e.type < LASTEvent && xev_handlers[e.type] != NULL)
|
||||||
|
(*xev_handlers[e.type])(&e);
|
||||||
switch (type) {
|
|
||||||
case MapRequest:
|
|
||||||
ASSIGN1(xmaprequest);
|
|
||||||
break;
|
|
||||||
case UnmapNotify:
|
|
||||||
ASSIGN1(xunmap);
|
|
||||||
break;
|
|
||||||
case ConfigureRequest:
|
|
||||||
ASSIGN1(xconfigurerequest);
|
|
||||||
break;
|
|
||||||
case PropertyNotify:
|
|
||||||
ASSIGN1(xproperty);
|
|
||||||
break;
|
|
||||||
case EnterNotify:
|
|
||||||
case LeaveNotify:
|
|
||||||
ASSIGN(xcrossing);
|
|
||||||
break;
|
|
||||||
case ButtonPress:
|
|
||||||
ASSIGN(xbutton);
|
|
||||||
break;
|
|
||||||
case ButtonRelease:
|
|
||||||
ASSIGN(xbutton);
|
|
||||||
break;
|
|
||||||
case KeyPress:
|
|
||||||
case KeyRelease:
|
|
||||||
ASSIGN(xkey);
|
|
||||||
break;
|
|
||||||
case DestroyNotify:
|
|
||||||
ASSIGN1(xdestroywindow);
|
|
||||||
break;
|
|
||||||
case ClientMessage:
|
|
||||||
ASSIGN1(xclient);
|
|
||||||
break;
|
|
||||||
default: /* XXX - still need shape event support. */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Now, search for matches, and call each of them.
|
|
||||||
*/
|
|
||||||
_xev_q_lock = 1;
|
|
||||||
for (xev = TAILQ_FIRST(&_xevq); xev != NULL; xev = nextxev) {
|
|
||||||
nextxev = TAILQ_NEXT(xev, entry);
|
|
||||||
|
|
||||||
if ((type != xev->xev_type && xev->xev_type != 0) ||
|
|
||||||
(xev->xev_win != NULL && win != *xev->xev_win) ||
|
|
||||||
(xev->xev_root != NULL && root != *xev->xev_root))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
TAILQ_REMOVE(&_xevq, xev, entry);
|
|
||||||
|
|
||||||
(*xev->xev_cb)(xev, &e);
|
|
||||||
}
|
|
||||||
_xev_q_lock = 0;
|
|
||||||
_xev_reincorporate();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef ASSIGN
|
|
||||||
#undef ASSIGN1
|
|
||||||
|
15
xmalloc.c
15
xmalloc.c
@@ -18,7 +18,16 @@
|
|||||||
* $Id$
|
* $Id$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "headers.h"
|
#include <sys/param.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
|
|
||||||
|
#include <err.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "calmwm.h"
|
#include "calmwm.h"
|
||||||
|
|
||||||
void *
|
void *
|
||||||
@@ -33,11 +42,11 @@ xmalloc(size_t siz)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void *
|
void *
|
||||||
xcalloc(size_t siz)
|
xcalloc(size_t no, size_t siz)
|
||||||
{
|
{
|
||||||
void *p;
|
void *p;
|
||||||
|
|
||||||
if ((p = calloc(1, siz)) == NULL)
|
if ((p = calloc(no, siz)) == NULL)
|
||||||
err(1, "calloc");
|
err(1, "calloc");
|
||||||
|
|
||||||
return (p);
|
return (p);
|
||||||
|
178
xutil.c
178
xutil.c
@@ -18,9 +18,20 @@
|
|||||||
* $Id$
|
* $Id$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "headers.h"
|
#include <sys/param.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
|
|
||||||
|
#include <err.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "calmwm.h"
|
#include "calmwm.h"
|
||||||
|
|
||||||
|
static unsigned int ign_mods[] = { 0, LockMask, Mod2Mask, Mod2Mask | LockMask };
|
||||||
|
|
||||||
int
|
int
|
||||||
xu_ptr_grab(Window win, int mask, Cursor curs)
|
xu_ptr_grab(Window win, int mask, Cursor curs)
|
||||||
{
|
{
|
||||||
@@ -42,26 +53,30 @@ xu_ptr_ungrab(void)
|
|||||||
XUngrabPointer(X_Dpy, CurrentTime);
|
XUngrabPointer(X_Dpy, CurrentTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
void
|
||||||
xu_btn_grab(Window win, int mask, u_int btn)
|
xu_btn_grab(Window win, int mask, u_int btn)
|
||||||
{
|
{
|
||||||
return (XGrabButton(X_Dpy, btn, mask, win,
|
int i;
|
||||||
|
for (i = 0; i < sizeof(ign_mods)/sizeof(*ign_mods); i++)
|
||||||
|
XGrabButton(X_Dpy, btn, (mask | ign_mods[i]), win,
|
||||||
False, ButtonMask, GrabModeAsync,
|
False, ButtonMask, GrabModeAsync,
|
||||||
GrabModeSync, None, None) == GrabSuccess ? 0 : -1);
|
GrabModeSync, None, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
xu_btn_ungrab(Window win, int mask, u_int btn)
|
xu_btn_ungrab(Window win, int mask, u_int btn)
|
||||||
{
|
{
|
||||||
XUngrabButton(X_Dpy, btn, mask, win);
|
int i;
|
||||||
|
for (i = 0; i < sizeof(ign_mods)/sizeof(*ign_mods); i++)
|
||||||
|
XUngrabButton(X_Dpy, btn, (mask | ign_mods[i]), win);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
xu_ptr_getpos(Window rootwin, int *x, int *y)
|
xu_ptr_getpos(Window rootwin, int *x, int *y)
|
||||||
{
|
{
|
||||||
|
Window w0, w1;
|
||||||
int tmp0, tmp1;
|
int tmp0, tmp1;
|
||||||
u_int tmp2;
|
u_int tmp2;
|
||||||
Window w0, w1;
|
|
||||||
|
|
||||||
XQueryPointer(X_Dpy, rootwin, &w0, &w1, &tmp0, &tmp1, x, y, &tmp2);
|
XQueryPointer(X_Dpy, rootwin, &w0, &w1, &tmp0, &tmp1, x, y, &tmp2);
|
||||||
}
|
}
|
||||||
@@ -76,40 +91,57 @@ void
|
|||||||
xu_key_grab(Window win, int mask, int keysym)
|
xu_key_grab(Window win, int mask, int keysym)
|
||||||
{
|
{
|
||||||
KeyCode code;
|
KeyCode code;
|
||||||
|
int i;
|
||||||
|
|
||||||
code = XKeysymToKeycode(X_Dpy, keysym);
|
code = XKeysymToKeycode(X_Dpy, keysym);
|
||||||
if ((XKeycodeToKeysym(X_Dpy, code, 0) != keysym) &&
|
if ((XKeycodeToKeysym(X_Dpy, code, 0) != keysym) &&
|
||||||
(XKeycodeToKeysym(X_Dpy, code, 1) == keysym))
|
(XKeycodeToKeysym(X_Dpy, code, 1) == keysym))
|
||||||
mask |= ShiftMask;
|
mask |= ShiftMask;
|
||||||
|
|
||||||
XGrabKey(X_Dpy, XKeysymToKeycode(X_Dpy, keysym), mask, win, True,
|
for (i = 0; i < sizeof(ign_mods)/sizeof(*ign_mods); i++)
|
||||||
GrabModeAsync, GrabModeAsync);
|
XGrabKey(X_Dpy, code, (mask | ign_mods[i]), win,
|
||||||
|
True, GrabModeAsync, GrabModeAsync);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
xu_sendmsg(struct client_ctx *cc, Atom atm, long val)
|
xu_key_ungrab(Window win, int mask, int keysym)
|
||||||
|
{
|
||||||
|
KeyCode code;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
code = XKeysymToKeycode(X_Dpy, keysym);
|
||||||
|
if ((XKeycodeToKeysym(X_Dpy, code, 0) != keysym) &&
|
||||||
|
(XKeycodeToKeysym(X_Dpy, code, 1) == keysym))
|
||||||
|
mask |= ShiftMask;
|
||||||
|
|
||||||
|
for (i = 0; i < sizeof(ign_mods)/sizeof(*ign_mods); i++)
|
||||||
|
XUngrabKey(X_Dpy, code, (mask | ign_mods[i]), win);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
xu_sendmsg(Window win, Atom atm, long val)
|
||||||
{
|
{
|
||||||
XEvent e;
|
XEvent e;
|
||||||
|
|
||||||
memset(&e, 0, sizeof(e));
|
memset(&e, 0, sizeof(e));
|
||||||
e.xclient.type = ClientMessage;
|
e.xclient.type = ClientMessage;
|
||||||
e.xclient.window = cc->win;
|
e.xclient.window = win;
|
||||||
e.xclient.message_type = atm;
|
e.xclient.message_type = atm;
|
||||||
e.xclient.format = 32;
|
e.xclient.format = 32;
|
||||||
e.xclient.data.l[0] = val;
|
e.xclient.data.l[0] = val;
|
||||||
e.xclient.data.l[1] = CurrentTime;
|
e.xclient.data.l[1] = CurrentTime;
|
||||||
|
|
||||||
XSendEvent(X_Dpy, cc->win, False, 0, &e);
|
XSendEvent(X_Dpy, win, False, 0, &e);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
xu_getprop(struct client_ctx *cc, Atom atm, Atom type, long len, u_char **p)
|
xu_getprop(Window win, Atom atm, Atom type, long len, u_char **p)
|
||||||
{
|
{
|
||||||
Atom realtype;
|
Atom realtype;
|
||||||
u_long n, extra;
|
u_long n, extra;
|
||||||
int format;
|
int format;
|
||||||
|
|
||||||
if (XGetWindowProperty(X_Dpy, cc->win, atm, 0L, len, False, type,
|
if (XGetWindowProperty(X_Dpy, win, atm, 0L, len, False, type,
|
||||||
&realtype, &format, &n, &extra, p) != Success || *p == NULL)
|
&realtype, &format, &n, &extra, p) != Success || *p == NULL)
|
||||||
return (-1);
|
return (-1);
|
||||||
|
|
||||||
@@ -119,13 +151,44 @@ xu_getprop(struct client_ctx *cc, Atom atm, Atom type, long len, u_char **p)
|
|||||||
return (n);
|
return (n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
xu_getstrprop(Window win, Atom atm, char **text) {
|
||||||
|
XTextProperty prop;
|
||||||
|
char **list;
|
||||||
|
int nitems = 0;
|
||||||
|
|
||||||
|
*text = NULL;
|
||||||
|
|
||||||
|
XGetTextProperty(X_Dpy, win, &prop, atm);
|
||||||
|
if (!prop.nitems)
|
||||||
|
return (0);
|
||||||
|
|
||||||
|
if (Xutf8TextPropertyToTextList(X_Dpy, &prop, &list,
|
||||||
|
&nitems) == Success && nitems > 0 && *list) {
|
||||||
|
if (nitems > 1) {
|
||||||
|
XTextProperty prop2;
|
||||||
|
if (Xutf8TextListToTextProperty(X_Dpy, list, nitems,
|
||||||
|
XUTF8StringStyle, &prop2) == Success) {
|
||||||
|
*text = xstrdup(prop2.value);
|
||||||
|
XFree(prop2.value);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
*text = xstrdup(*list);
|
||||||
|
}
|
||||||
|
XFreeStringList(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
XFree(prop.value);
|
||||||
|
|
||||||
|
return (nitems);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
xu_getstate(struct client_ctx *cc, int *state)
|
xu_getstate(struct client_ctx *cc, int *state)
|
||||||
{
|
{
|
||||||
Atom wm_state = XInternAtom(X_Dpy, "WM_STATE", False);
|
|
||||||
long *p = NULL;
|
long *p = NULL;
|
||||||
|
|
||||||
if (xu_getprop(cc, wm_state, wm_state, 2L, (u_char **)&p) <= 0)
|
if (xu_getprop(cc->win, WM_STATE, WM_STATE, 2L, (u_char **)&p) <= 0)
|
||||||
return (-1);
|
return (-1);
|
||||||
|
|
||||||
*state = (int)*p;
|
*state = (int)*p;
|
||||||
@@ -138,15 +201,86 @@ void
|
|||||||
xu_setstate(struct client_ctx *cc, int state)
|
xu_setstate(struct client_ctx *cc, int state)
|
||||||
{
|
{
|
||||||
long dat[2];
|
long dat[2];
|
||||||
Atom wm_state;
|
|
||||||
|
|
||||||
/* XXX cache */
|
dat[0] = state;
|
||||||
wm_state = XInternAtom(X_Dpy, "WM_STATE", False);
|
dat[1] = None;
|
||||||
|
|
||||||
dat[0] = (long)state;
|
|
||||||
dat[1] = (long)None;
|
|
||||||
|
|
||||||
cc->state = state;
|
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);
|
PropModeReplace, (unsigned char *)dat, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Atom cwm_atoms[CWM_NO_ATOMS];
|
||||||
|
char *atoms[CWM_NO_ATOMS] = {
|
||||||
|
"WM_STATE",
|
||||||
|
"WM_DELETE_WINDOW",
|
||||||
|
"WM_TAKE_FOCUS",
|
||||||
|
"WM_PROTOCOLS",
|
||||||
|
"_MOTIF_WM_HINTS",
|
||||||
|
"UTF8_STRING",
|
||||||
|
"_NET_SUPPORTED",
|
||||||
|
"_NET_SUPPORTING_WM_CHECK",
|
||||||
|
"_NET_WM_NAME",
|
||||||
|
"_NET_ACTIVE_WINDOW",
|
||||||
|
"_NET_CLIENT_LIST",
|
||||||
|
"_NET_NUMBER_OF_DESKTOPS",
|
||||||
|
"_NET_CURRENT_DESKTOP",
|
||||||
|
"_NET_DESKTOP_VIEWPORT",
|
||||||
|
"_NET_DESKTOP_GEOMETRY",
|
||||||
|
"_NET_VIRTUAL_ROOTS",
|
||||||
|
"_NET_SHOWING_DESKTOP",
|
||||||
|
"_NET_DESKTOP_NAMES",
|
||||||
|
"_NET_WM_DESKTOP",
|
||||||
|
"_NET_WORKAREA",
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
xu_getatoms(void)
|
||||||
|
{
|
||||||
|
XInternAtoms(X_Dpy, atoms, CWM_NO_ATOMS, False, cwm_atoms);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
xu_setwmname(struct screen_ctx *sc)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* set up the _NET_SUPPORTED hint with all netwm atoms that we
|
||||||
|
* know about.
|
||||||
|
*/
|
||||||
|
XChangeProperty(X_Dpy, sc->rootwin, _NET_SUPPORTED, XA_ATOM, 32,
|
||||||
|
PropModeReplace, (unsigned char *)&_NET_SUPPORTED,
|
||||||
|
CWM_NO_ATOMS - CWM_NETWM_START);
|
||||||
|
/*
|
||||||
|
* netwm spec says that to prove that the hint is not stale you must
|
||||||
|
* provide _NET_SUPPORTING_WM_CHECK containing a window (we use the
|
||||||
|
* menu window). The property must be set on the root window and the
|
||||||
|
* window itself, the window also must have _NET_WM_NAME set with the
|
||||||
|
* window manager name.
|
||||||
|
*/
|
||||||
|
XChangeProperty(X_Dpy, sc->rootwin, _NET_SUPPORTING_WM_CHECK,
|
||||||
|
XA_WINDOW, 32, PropModeReplace, (unsigned char *)&sc->menuwin, 1);
|
||||||
|
XChangeProperty(X_Dpy, sc->menuwin, _NET_SUPPORTING_WM_CHECK,
|
||||||
|
XA_WINDOW, 32, PropModeReplace, (unsigned char *)&sc->menuwin, 1);
|
||||||
|
XChangeProperty(X_Dpy, sc->menuwin, _NET_WM_NAME, UTF8_STRING,
|
||||||
|
8, PropModeReplace, WMNAME, strlen(WMNAME));
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long
|
||||||
|
xu_getcolor(struct screen_ctx *sc, char *name)
|
||||||
|
{
|
||||||
|
XColor color, tmp;
|
||||||
|
|
||||||
|
if (!XAllocNamedColor(X_Dpy, DefaultColormap(X_Dpy, sc->which),
|
||||||
|
name, &color, &tmp)) {
|
||||||
|
warnx("XAllocNamedColor error: '%s'", name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return color.pixel;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
xu_freecolor(struct screen_ctx *sc, unsigned long pixel)
|
||||||
|
{
|
||||||
|
XFreeColors(X_Dpy, DefaultColormap(X_Dpy, sc->which), &pixel, 1, 0L);
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user