6 Commits

Author SHA1 Message Date
a119fe5240 cvsimport 2010-09-25 21:58:18 +00:00
f2e8fad75c cvsimport 2010-09-25 22:21:23 +00:00
e0c9657773 cvsimport 2010-05-22 22:32:08 +00:00
oga
f769df540d cvsimport 2010-04-12 16:17:46 +00:00
d90ab51111 Add missing functions 2010-02-21 19:18:12 +01:00
50aff37f50 Import linux.patch
Patch largely based on cwmbuild.sh from http://tamentis.com/hacks/cwm/
written by Bertrand Janin, updated by Christian Neukirchen.
2010-02-21 19:15:27 +01:00
25 changed files with 3077 additions and 3132 deletions

14
LICENSE Normal file
View File

@ -0,0 +1,14 @@
Copyright (c) 2004,2005 Marius Aamodt Eriksen <marius@monkey.org>
Copyright (c) 2004 Andy Adamson <dros@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.

View File

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

219
calmwm.c
View File

@ -15,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $OpenBSD$
* $Id$
*/
#include <sys/param.h>
@ -25,50 +25,43 @@
#include <err.h>
#include <errno.h>
#include <getopt.h>
#include <locale.h>
#include <pwd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "calmwm.h"
Display *X_Dpy;
Time Last_Event_Time = CurrentTime;
Atom cwmh[CWMH_NITEMS];
Atom ewmh[EWMH_NITEMS];
Cursor Cursor_move;
Cursor Cursor_resize;
Cursor Cursor_select;
Cursor Cursor_default;
Cursor Cursor_question;
struct screen_ctx_q Screenq = TAILQ_HEAD_INITIALIZER(Screenq);
struct client_ctx_q Clientq = TAILQ_HEAD_INITIALIZER(Clientq);
int HasRandr, Randr_ev;
int HasXinerama, HasRandr, Randr_ev;
int Starting;
struct conf Conf;
const char *homedir;
volatile sig_atomic_t cwm_status;
static void sigchld_cb(int);
static void dpy_init(const char *);
static int x_errorhandler(Display *, XErrorEvent *);
static void x_init(const char *);
static void x_restart(char **);
static void x_setup(void);
static void x_setupscreen(struct screen_ctx *, u_int);
static void x_teardown(void);
static int x_wmerrorhandler(Display *, XErrorEvent *);
int
main(int argc, char **argv)
{
const char *conf_file = NULL;
char *conf_path, *display_name = NULL;
char **cwm_argv;
char *display_name = NULL;
int ch;
struct passwd *pw;
if (!setlocale(LC_CTYPE, "") || !XSupportsLocale())
warnx("no locale support");
mbtowc(NULL, NULL, MB_CUR_MAX);
cwm_argv = argv;
while ((ch = getopt(argc, argv, "c:d:")) != -1) {
switch (ch) {
case 'c':
@ -87,120 +80,159 @@ main(int argc, char **argv)
if (signal(SIGCHLD, sigchld_cb) == SIG_ERR)
err(1, "signal");
if ((homedir = getenv("HOME")) == NULL || *homedir == '\0') {
pw = getpwuid(getuid());
if (pw != NULL && pw->pw_dir != NULL && *pw->pw_dir != '\0')
homedir = pw->pw_dir;
else
homedir = "/";
}
Starting = 1;
dpy_init(display_name);
if (conf_file == NULL)
xasprintf(&conf_path, "%s/%s", homedir, CONFFILE);
else
conf_path = xstrdup(conf_file);
bzero(&Conf, sizeof(Conf));
conf_setup(&Conf, conf_file);
xu_getatoms();
x_setup();
Starting = 0;
if (access(conf_path, R_OK) != 0) {
if (conf_file != NULL)
warn("%s", conf_file);
free(conf_path);
conf_path = NULL;
}
xev_loop();
conf_init(&Conf);
if (conf_path && (parse_config(conf_path, &Conf) == -1))
warnx("config file %s has errors", conf_path);
free(conf_path);
x_init(display_name);
cwm_status = CWM_RUNNING;
while (cwm_status == CWM_RUNNING)
xev_process();
x_teardown();
if (cwm_status == CWM_RESTART)
x_restart(cwm_argv);
return (0);
}
static void
x_init(const char *dpyname)
dpy_init(const char *dpyname)
{
int i;
if ((X_Dpy = XOpenDisplay(dpyname)) == NULL)
errx(1, "unable to open display \"%s\"", XDisplayName(dpyname));
errx(1, "unable to open display \"%s\"",
XDisplayName(dpyname));
XSetErrorHandler(x_wmerrorhandler);
XSelectInput(X_Dpy, DefaultRootWindow(X_Dpy), SubstructureRedirectMask);
XSync(X_Dpy, False);
XSetErrorHandler(x_errorhandler);
HasRandr = XRRQueryExtension(X_Dpy, &Randr_ev, &i);
conf_atoms();
conf_cursor(&Conf);
for (i = 0; i < ScreenCount(X_Dpy); i++)
screen_init(i);
}
static void
x_restart(char **args)
x_setup(void)
{
(void)setsid();
(void)execvp(args[0], args);
struct screen_ctx *sc;
struct keybinding *kb;
int i;
for (i = 0; i < ScreenCount(X_Dpy); i++) {
sc = xcalloc(1, sizeof(*sc));
x_setupscreen(sc, i);
TAILQ_INSERT_TAIL(&Screenq, sc, entry);
}
/*
* XXX key grabs weren't done before, since Screenq was empty,
* do them here for now (this needs changing).
*/
TAILQ_FOREACH(kb, &Conf.keybindingq, entry)
conf_grab(&Conf, kb);
Cursor_move = XCreateFontCursor(X_Dpy, XC_fleur);
Cursor_resize = XCreateFontCursor(X_Dpy, XC_bottom_right_corner);
Cursor_select = XCreateFontCursor(X_Dpy, XC_hand1);
Cursor_default = XCreateFontCursor(X_Dpy, XC_X_cursor);
Cursor_question = XCreateFontCursor(X_Dpy, XC_question_arrow);
}
static void
x_teardown(void)
{
struct screen_ctx *sc;
unsigned int i;
conf_clear(&Conf);
TAILQ_FOREACH(sc, &Screenq, entry)
XFreeGC(X_Dpy, sc->gc);
TAILQ_FOREACH(sc, &Screenq, entry) {
for (i = 0; i < CWM_COLOR_NITEMS; i++)
XftColorFree(X_Dpy, DefaultVisual(X_Dpy, sc->which),
DefaultColormap(X_Dpy, sc->which),
&sc->xftcolor[i]);
XftDrawDestroy(sc->xftdraw);
XftFontClose(X_Dpy, sc->xftfont);
XUnmapWindow(X_Dpy, sc->menuwin);
XDestroyWindow(X_Dpy, sc->menuwin);
XUngrabKey(X_Dpy, AnyKey, AnyModifier, sc->rootwin);
}
XUngrabPointer(X_Dpy, CurrentTime);
XUngrabKeyboard(X_Dpy, CurrentTime);
for (i = 0; i < CF_NITEMS; i++)
XFreeCursor(X_Dpy, Conf.cursor[i]);
XSync(X_Dpy, False);
XSetInputFocus(X_Dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
XCloseDisplay(X_Dpy);
}
static int
x_wmerrorhandler(Display *dpy, XErrorEvent *e)
static void
x_setupscreen(struct screen_ctx *sc, u_int which)
{
errx(1, "root window unavailable - perhaps another wm is running?");
Window *wins, w0, w1;
XWindowAttributes winattr;
XSetWindowAttributes rootattr;
int fake;
u_int nwins, i;
sc->which = which;
sc->rootwin = RootWindow(X_Dpy, sc->which);
return (0);
conf_gap(&Conf, sc);
screen_update_geometry(sc, DisplayWidth(X_Dpy, sc->which),
DisplayHeight(X_Dpy, sc->which));
conf_color(&Conf, sc);
group_init(sc);
font_init(sc);
conf_font(&Conf, sc);
TAILQ_INIT(&sc->mruq);
/* Initialize menu window. */
menu_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. */
XQueryTree(X_Dpy, sc->rootwin, &w0, &w1, &wins, &nwins);
for (i = 0; i < nwins; i++) {
XGetWindowAttributes(X_Dpy, wins[i], &winattr);
if (winattr.override_redirect ||
winattr.map_state != IsViewable)
continue;
client_new(wins[i], sc, winattr.map_state != IsUnmapped);
}
XFree(wins);
screen_updatestackingorder(sc);
if (XineramaQueryExtension(X_Dpy, &fake, &fake) == 1 &&
((HasXinerama = XineramaIsActive(X_Dpy)) == 1))
HasXinerama = 1;
if (HasRandr)
XRRSelectInput(X_Dpy, sc->rootwin, RRScreenChangeNotifyMask);
/*
* initial setup of xinerama screens, if we're using RandR then we'll
* redo this whenever the screen changes since a CTRC may have been
* added or removed
*/
screen_init_xinerama(sc);
XSync(X_Dpy, False);
}
static int
x_errorhandler(Display *dpy, XErrorEvent *e)
{
#ifdef DEBUG
char msg[80], number[80], req[80];
{
char msg[80], number[80], req[80];
XGetErrorText(X_Dpy, e->error_code, msg, sizeof(msg));
(void)snprintf(number, sizeof(number), "%d", e->request_code);
XGetErrorDatabaseText(X_Dpy, "XRequest", number,
"<unknown>", req, sizeof(req));
XGetErrorText(X_Dpy, e->error_code, msg, sizeof(msg));
snprintf(number, sizeof(number), "%d", e->request_code);
XGetErrorDatabaseText(X_Dpy, "XRequest", number,
"<unknown>", req, sizeof(req));
warnx("%s(0x%x): %s", req, (unsigned int)e->resourceid, msg);
warnx("%s(0x%x): %s", req, (u_int)e->resourceid, msg);
}
#endif
if (Starting &&
e->error_code == BadAccess &&
e->request_code == X_GrabKey)
errx(1, "root window unavailable - perhaps another "
"wm is running?");
return (0);
}
@ -224,7 +256,6 @@ usage(void)
{
extern char *__progname;
(void)fprintf(stderr, "usage: %s [-c file] [-d display]\n",
__progname);
fprintf(stderr, "usage: %s [-c file] [-d display]\n", __progname);
exit(1);
}

887
calmwm.h
View File

@ -15,13 +15,16 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $OpenBSD$
* $Id$
*/
#ifndef _CALMWM_H_
#define _CALMWM_H_
#include <X11/XKBlib.h>
/* ugly stuff */
#define TAILQ_END(head) NULL
#define __dead
#include <X11/Xatom.h>
#include <X11/Xft/Xft.h>
#include <X11/Xlib.h>
@ -32,102 +35,40 @@
#include <X11/extensions/Xrandr.h>
#include <X11/keysym.h>
#define CALMWM_MAXNAMELEN 256
#undef MIN
#undef MAX
#define MIN(x, y) ((x) < (y) ? (x) : (y))
#define MAX(x, y) ((x) > (y) ? (x) : (y))
#ifndef nitems
#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
#endif
#define CONFFILE ".cwmrc"
#define WMNAME "CWM"
#define BUTTONMASK (ButtonPressMask|ButtonReleaseMask)
#define MOUSEMASK (BUTTONMASK|PointerMotionMask)
#define MENUMASK (MOUSEMASK|ButtonMotionMask|ExposureMask)
#define MENUGRABMASK (MOUSEMASK|ButtonMotionMask|StructureNotifyMask)
#define KEYMASK (KeyPressMask|ExposureMask)
#define IGNOREMODMASK (LockMask|Mod2Mask)
#define ChildMask (SubstructureRedirectMask|SubstructureNotifyMask)
#define ButtonMask (ButtonPressMask|ButtonReleaseMask)
#define MouseMask (ButtonMask|PointerMotionMask)
#define KeyMask (KeyPressMask|ExposureMask)
#define MenuMask (ButtonMask|ButtonMotionMask|ExposureMask| \
PointerMotionMask)
#define MenuGrabMask (ButtonMask|ButtonMotionMask|StructureNotifyMask|\
PointerMotionMask)
#define SearchMask (KeyPressMask|ExposureMask)
/* kb movement */
#define CWM_MOVE 0x0001
#define CWM_RESIZE 0x0002
#define CWM_PTRMOVE 0x0004
#define CWM_BIGMOVE 0x0008
#define CWM_UP 0x0010
#define CWM_DOWN 0x0020
#define CWM_LEFT 0x0040
#define CWM_RIGHT 0x0080
/* exec */
#define CWM_EXEC_PROGRAM 0x0001
#define CWM_EXEC_WM 0x0002
/* cycle */
#define CWM_CYCLE 0x0001
#define CWM_RCYCLE 0x0002
#define CWM_INGROUP 0x0004
/* menu */
#define CWM_MENU_DUMMY 0x0001
#define CWM_MENU_FILE 0x0002
#define ARG_CHAR 0x0001
#define ARG_INT 0x0002
#define CWM_TILE_HORIZ 0x0001
#define CWM_TILE_VERT 0x0002
#define CWM_GAP 0x0001
#define CWM_NOGAP 0x0002
#define CWM_WIN 0x0001
#define CWM_QUIT 0x0000
#define CWM_RUNNING 0x0001
#define CWM_RESTART 0x0002
union arg {
char *c;
int i;
};
union press {
KeySym keysym;
unsigned int button;
};
enum cursor_font {
CF_DEFAULT,
CF_MOVE,
CF_NORMAL,
CF_QUESTION,
CF_RESIZE,
CF_NITEMS
};
enum color {
CWM_COLOR_BORDER_ACTIVE,
enum cwmcolor {
CWM_COLOR_BORDOR_ACTIVE,
CWM_COLOR_BORDER_INACTIVE,
CWM_COLOR_BORDER_URGENCY,
CWM_COLOR_BORDER_GROUP,
CWM_COLOR_BORDER_UNGROUP,
CWM_COLOR_MENU_FG,
CWM_COLOR_MENU_BG,
CWM_COLOR_MENU_FONT,
CWM_COLOR_MENU_FONT_SEL,
CWM_COLOR_NITEMS
CWM_COLOR_FG_MENU,
CWM_COLOR_BG_MENU,
CWM_COLOR_MAX
};
struct geom {
int x;
int y;
int w;
int h;
struct color {
unsigned long pixel;
char *name;
};
struct gap {
int top;
int bottom;
@ -135,71 +76,13 @@ struct gap {
int right;
};
struct winname {
TAILQ_ENTRY(winname) entry;
char *name;
};
TAILQ_HEAD(winname_q, winname);
TAILQ_HEAD(ignore_q, winname);
struct client_ctx;
struct client_ctx {
TAILQ_ENTRY(client_ctx) entry;
TAILQ_ENTRY(client_ctx) group_entry;
TAILQ_ENTRY(client_ctx) mru_entry;
struct screen_ctx *sc;
Window win;
Colormap colormap;
unsigned int bwidth; /* border width */
struct geom geom, savegeom, fullgeom;
struct {
long flags; /* defined hints */
int basew; /* desired width */
int baseh; /* desired height */
int minw; /* minimum width */
int minh; /* minimum height */
int maxw; /* maximum width */
int maxh; /* maximum height */
int incw; /* width increment progression */
int inch; /* height increment progression */
float mina; /* minimum aspect ratio */
float maxa; /* maximum aspect ratio */
} hint;
struct {
int x; /* x position */
int y; /* y position */
} ptr;
#define CLIENT_HIDDEN 0x0001
#define CLIENT_IGNORE 0x0002
#define CLIENT_VMAXIMIZED 0x0004
#define CLIENT_HMAXIMIZED 0x0008
#define CLIENT_FREEZE 0x0010
#define CLIENT_GROUP 0x0020
#define CLIENT_UNGROUP 0x0040
#define CLIENT_INPUT 0x0080
#define CLIENT_WM_DELETE_WINDOW 0x0100
#define CLIENT_WM_TAKE_FOCUS 0x0200
#define CLIENT_URGENCY 0x0400
#define CLIENT_FULLSCREEN 0x0800
#define CLIENT_HIGHLIGHT (CLIENT_GROUP | CLIENT_UNGROUP)
#define CLIENT_MAXFLAGS (CLIENT_VMAXIMIZED | CLIENT_HMAXIMIZED)
#define CLIENT_MAXIMIZED (CLIENT_VMAXIMIZED | CLIENT_HMAXIMIZED)
int flags;
int active;
int stackingorder;
struct winname_q nameq;
#define CLIENT_MAXNAMEQLEN 5
int nameqlen;
char *name;
char *label;
char *matchname;
struct group_ctx *group;
XClassHint ch;
XWMHints *wmh;
};
TAILQ_HEAD(client_ctx_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 CALMWM_NGROUPS 9
struct group_ctx {
TAILQ_ENTRY(group_ctx) entry;
struct client_ctx_q clients;
@ -208,361 +91,481 @@ struct group_ctx {
int nhidden;
int highstack;
};
TAILQ_HEAD(group_ctx_q, group_ctx);
struct screen_ctx {
TAILQ_ENTRY(screen_ctx) entry;
u_int which;
Window rootwin;
Window menuwin;
struct color color[CWM_COLOR_MAX];
GC gc;
int altpersist;
int xmax;
int ymax;
struct gap gap;
struct cycle_entry_q mruq;
XftDraw *xftdraw;
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);
#define CLIENT_PROTO_DELETE 0x01
#define CLIENT_PROTO_TAKEFOCUS 0x02
#define CLIENT_MAXNAMEQLEN 5
#define CLIENT_HIDDEN 0x01
#define CLIENT_IGNORE 0x02
#define CLIENT_DOMAXIMIZE 0x04
#define CLIENT_MAXIMIZED 0x08
#define CLIENT_DOVMAXIMIZE 0x10
#define CLIENT_VMAXIMIZED 0x20
#define CLIENT_DOHMAXIMIZE 0x40
#define CLIENT_HMAXIMIZED 0x80
#define CLIENT_HIGHLIGHT_GROUP 1
#define CLIENT_HIGHLIGHT_UNGROUP 2
struct winname {
TAILQ_ENTRY(winname) entry;
char *name;
};
TAILQ_HEAD(winname_q, winname);
struct client_ctx {
TAILQ_ENTRY(client_ctx) entry;
TAILQ_ENTRY(client_ctx) searchentry;
TAILQ_ENTRY(client_ctx) group_entry;
TAILQ_ENTRY(client_ctx) mru_entry;
struct screen_ctx *sc;
Window win;
XSizeHints *size;
Colormap cmap;
u_int bwidth;
struct {
int x, y, width, height, basew, baseh,
minw, minh, maxw, maxh, incw, inch;
float mina, maxa;
} geom, savegeom;
struct {
int x,y;
} ptr;
int xproto;
int flags;
int state;
char *name;
struct winname_q nameq;
size_t nameqlen;
char *label;
int active;
int highlight;
char *matchname;
struct group_ctx *group;
int stackingorder;
char *app_class;
char *app_name;
char *app_cliarg;
};
extern const char *shortcut_to_name[];
/* Autogroups */
struct autogroupwin {
TAILQ_ENTRY(autogroupwin) entry;
char *class;
char *name;
int num;
};
TAILQ_HEAD(autogroupwin_q, autogroupwin);
struct region_ctx {
TAILQ_ENTRY(region_ctx) entry;
int num;
struct geom area;
};
TAILQ_HEAD(region_ctx_q, region_ctx);
#define CWM_MOVE 0x01
#define CWM_RESIZE 0x02
#define CWM_PTRMOVE 0x04
#define CWM_BIGMOVE 0x08
#define CWM_UP 0x10
#define CWM_DOWN 0x20
#define CWM_LEFT 0x40
#define CWM_RIGHT 0x80
struct screen_ctx {
TAILQ_ENTRY(screen_ctx) entry;
int which;
Window rootwin;
Window menuwin;
int cycling;
int snapdist;
struct geom view; /* viewable area */
struct geom work; /* workable area, gap-applied */
struct gap gap;
struct cycle_entry_q mruq;
struct region_ctx_q regionq;
XftColor xftcolor[CWM_COLOR_NITEMS];
XftDraw *xftdraw;
XftFont *xftfont;
#define CALMWM_NGROUPS 10
struct group_ctx groups[CALMWM_NGROUPS];
struct group_ctx_q groupq;
int group_hideall;
int group_nonames;
struct group_ctx *group_active;
char **group_names;
/*
* Match a window.
*/
#define CONF_MAX_WINTITLE 256
struct winmatch {
TAILQ_ENTRY(winmatch) entry;
char title[CONF_MAX_WINTITLE];
};
TAILQ_HEAD(screen_ctx_q, screen_ctx);
struct binding {
TAILQ_ENTRY(binding) entry;
TAILQ_HEAD(winmatch_q, winmatch);
/* for cwm_exec */
#define CWM_EXEC_PROGRAM 0x1
#define CWM_EXEC_WM 0x2
/* for alt-tab */
#define CWM_CYCLE 0x0
#define CWM_RCYCLE 0x1
/* for group cycle */
#define CWM_CYCLEGROUP 0x0
#define CWM_RCYCLEGROUP 0x1
#define KBFLAG_NEEDCLIENT 0x01
#define KBTOGROUP(X) ((X) - 1)
union arg {
char *c;
int i;
};
struct keybinding {
TAILQ_ENTRY(keybinding) entry;
void (*callback)(struct client_ctx *, union arg *);
union arg argument;
unsigned int modmask;
union press press;
int modmask;
int keysym;
int keycode;
int flags;
int argtype;
};
TAILQ_HEAD(keybinding_q, binding);
TAILQ_HEAD(mousebinding_q, binding);
struct cmd {
TAILQ_ENTRY(cmd) entry;
char *name;
char path[MAXPATHLEN];
TAILQ_ENTRY(cmd) entry;
int flags;
char image[MAXPATHLEN];
char label[256];
/* (argv) */
};
struct mousebinding {
int modmask;
int button;
int context;
void (*callback)(struct client_ctx *, void *);
TAILQ_ENTRY(mousebinding) entry;
};
#define MOUSEBIND_CTX_ROOT 1
#define MOUSEBIND_CTX_WIN 2
TAILQ_HEAD(keybinding_q, keybinding);
TAILQ_HEAD(cmd_q, cmd);
TAILQ_HEAD(mousebinding_q, mousebinding);
/* Global configuration */
struct conf {
struct keybinding_q keybindingq;
struct autogroupwin_q autogroupq;
struct winmatch_q ignoreq;
char conf_path[MAXPATHLEN];
struct cmd_q cmdq;
struct mousebinding_q mousebindingq;
#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 lockpath[MAXPATHLEN];
#define DEFAULTFONTNAME "sans-serif:pixelsize=14:bold"
char *DefaultFontName;
};
/* Menu stuff */
#define MENU_MAXENTRY 50
struct menu {
TAILQ_ENTRY(menu) entry;
TAILQ_ENTRY(menu) resultentry;
#define MENU_MAXENTRY 200
TAILQ_ENTRY(menu) entry;
TAILQ_ENTRY(menu) resultentry;
char text[MENU_MAXENTRY + 1];
char print[MENU_MAXENTRY + 1];
void *ctx;
short dummy;
short abort;
};
TAILQ_HEAD(menu_q, menu);
struct conf {
struct keybinding_q keybindingq;
struct mousebinding_q mousebindingq;
struct autogroupwin_q autogroupq;
struct ignore_q ignoreq;
struct cmd_q cmdq;
#define CONF_STICKY_GROUPS 0x0001
int flags;
#define CONF_BWIDTH 1
int bwidth;
#define CONF_MAMOUNT 1
int mamount;
#define CONF_SNAPDIST 0
int snapdist;
struct gap gap;
char *color[CWM_COLOR_NITEMS];
char termpath[MAXPATHLEN];
char lockpath[MAXPATHLEN];
char known_hosts[MAXPATHLEN];
#define CONF_FONT "sans-serif:pixelsize=14:bold"
char *font;
Cursor cursor[CF_NITEMS];
enum ctltype {
CTL_NONE = -1,
CTL_ERASEONE = 0, CTL_WIPE, CTL_UP, CTL_DOWN, CTL_RETURN,
CTL_ABORT, CTL_ALL
};
/* MWM hints */
struct mwm_hints {
unsigned long flags;
unsigned long functions;
unsigned long decorations;
u_long flags;
u_long functions;
u_long decorations;
};
#define MWM_NUMHINTS 3
#define MWM_NUMHINTS 3
#define PROP_MWM_HINTS_ELEMENTS 3
#define MWM_HINTS_DECORATIONS (1<<1)
#define MWM_DECOR_ALL (1<<0)
#define MWM_DECOR_BORDER (1<<1)
#define MWM_HINTS_DECORATIONS (1 << 1)
#define MWM_DECOR_ALL (1 << 0)
#define MWM_DECOR_BORDER (1 << 1)
extern Display *X_Dpy;
extern Time Last_Event_Time;
extern struct screen_ctx_q Screenq;
extern struct client_ctx_q Clientq;
extern struct conf Conf;
extern const char *homedir;
extern int HasRandr, Randr_ev;
enum {
WM_STATE,
WM_DELETE_WINDOW,
WM_TAKE_FOCUS,
WM_PROTOCOLS,
_MOTIF_WM_HINTS,
UTF8_STRING,
WM_CHANGE_STATE,
CWMH_NITEMS
};
enum {
_NET_SUPPORTED,
_NET_SUPPORTING_WM_CHECK,
_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_WORKAREA,
_NET_WM_NAME,
_NET_WM_DESKTOP,
_NET_CLOSE_WINDOW,
_NET_WM_STATE,
#define _NET_WM_STATES_NITEMS 4
_NET_WM_STATE_MAXIMIZED_VERT,
_NET_WM_STATE_MAXIMIZED_HORZ,
_NET_WM_STATE_FULLSCREEN,
_NET_WM_STATE_DEMANDS_ATTENTION,
EWMH_NITEMS
};
enum {
_NET_WM_STATE_REMOVE,
_NET_WM_STATE_ADD,
_NET_WM_STATE_TOGGLE
};
extern Atom cwmh[CWMH_NITEMS];
extern Atom ewmh[EWMH_NITEMS];
int input_keycodetrans(KeyCode, u_int, enum ctltype *,
char *);
__dead void usage(void);
void client_applysizehints(struct client_ctx *);
void client_config(struct client_ctx *);
struct client_ctx *client_current(void);
void client_cycle(struct screen_ctx *, int);
void client_cycle_leave(struct screen_ctx *);
void client_delete(struct client_ctx *);
void client_draw_border(struct client_ctx *);
struct client_ctx *client_find(Window);
void client_freeze(struct client_ctx *);
void client_fullscreen(struct client_ctx *);
long client_get_wm_state(struct client_ctx *);
void client_getsizehints(struct client_ctx *);
void client_hide(struct client_ctx *);
void client_hmaximize(struct client_ctx *);
void client_htile(struct client_ctx *);
struct client_ctx *client_new(Window, struct screen_ctx *, int);
int client_delete(struct client_ctx *);
void client_setactive(struct client_ctx *, int);
void client_resize(struct client_ctx *);
void client_lower(struct client_ctx *);
void client_map(struct client_ctx *);
void client_maximize(struct client_ctx *);
void client_msg(struct client_ctx *, Atom, Time);
void client_move(struct client_ctx *);
struct client_ctx *client_init(Window, struct screen_ctx *);
void client_ptrsave(struct client_ctx *);
void client_ptrwarp(struct client_ctx *);
void client_raise(struct client_ctx *);
void client_resize(struct client_ctx *, int);
void client_move(struct client_ctx *);
void client_leave(struct client_ctx *);
void client_send_delete(struct client_ctx *);
void client_set_wm_state(struct client_ctx *, long);
void client_setactive(struct client_ctx *);
void client_setname(struct client_ctx *);
int client_snapcalc(int, int, int, int, int);
void client_transient(struct client_ctx *);
struct client_ctx *client_current(void);
void client_hide(struct client_ctx *);
void client_unhide(struct client_ctx *);
void client_urgency(struct client_ctx *);
void client_vmaximize(struct client_ctx *);
void client_vtile(struct client_ctx *);
void client_setname(struct client_ctx *);
void client_warp(struct client_ctx *);
void client_wm_hints(struct client_ctx *);
void group_alltoggle(struct screen_ctx *);
void group_autogroup(struct client_ctx *);
void group_cycle(struct screen_ctx *, int);
void group_hidetoggle(struct screen_ctx *, int);
void group_init(struct screen_ctx *);
void group_menu(struct screen_ctx *);
void group_movetogroup(struct client_ctx *, int);
void group_only(struct screen_ctx *, int);
void group_set_state(struct screen_ctx *);
void group_sticky(struct client_ctx *);
void group_sticky_toggle_enter(struct client_ctx *);
void group_sticky_toggle_exit(struct client_ctx *);
void group_update_names(struct screen_ctx *);
void search_match_client(struct menu_q *, struct menu_q *,
char *);
void search_match_exec(struct menu_q *, struct menu_q *,
char *);
void search_match_exec_path(struct menu_q *,
struct menu_q *, char *);
void search_match_path_any(struct menu_q *, struct menu_q *,
char *);
void search_match_text(struct menu_q *, struct menu_q *,
char *);
void search_print_client(struct menu *, int);
struct geom screen_find_xinerama(struct screen_ctx *,
int, int, int);
struct screen_ctx *screen_fromroot(Window);
void screen_init(int);
void screen_update_geometry(struct screen_ctx *);
void screen_updatestackingorder(struct screen_ctx *);
void kbfunc_client_cycle(struct client_ctx *, union arg *);
void kbfunc_client_cyclegroup(struct client_ctx *,
union arg *);
void kbfunc_client_delete(struct client_ctx *, union arg *);
void kbfunc_client_freeze(struct client_ctx *, union arg *);
void kbfunc_client_fullscreen(struct client_ctx *,
union arg *);
void kbfunc_client_group(struct client_ctx *, union arg *);
void kbfunc_client_grouponly(struct client_ctx *,
union arg *);
void kbfunc_client_grouptoggle(struct client_ctx *,
union arg *);
void kbfunc_client_hide(struct client_ctx *, union arg *);
void kbfunc_client_hmaximize(struct client_ctx *,
union arg *);
void kbfunc_client_label(struct client_ctx *, union arg *);
void kbfunc_client_lower(struct client_ctx *, union arg *);
void kbfunc_client_maximize(struct client_ctx *,
union arg *);
void kbfunc_client_moveresize(struct client_ctx *,
union arg *);
void kbfunc_client_movetogroup(struct client_ctx *,
union arg *);
void kbfunc_client_nogroup(struct client_ctx *,
union arg *);
void kbfunc_client_raise(struct client_ctx *, union arg *);
void kbfunc_client_rcycle(struct client_ctx *, union arg *);
void kbfunc_client_search(struct client_ctx *, union arg *);
void kbfunc_client_vmaximize(struct client_ctx *,
union arg *);
void kbfunc_cmdexec(struct client_ctx *, union arg *);
void kbfunc_cwm_status(struct client_ctx *, union arg *);
void kbfunc_exec(struct client_ctx *, union arg *);
void kbfunc_lock(struct client_ctx *, union arg *);
void kbfunc_menu_cmd(struct client_ctx *, union arg *);
void kbfunc_ssh(struct client_ctx *, union arg *);
void kbfunc_term(struct client_ctx *, union arg *);
void kbfunc_tile(struct client_ctx *, union arg *);
void mousefunc_client_grouptoggle(struct client_ctx *,
union arg *);
void mousefunc_client_move(struct client_ctx *,
union arg *);
void mousefunc_client_resize(struct client_ctx *,
union arg *);
void mousefunc_menu_cmd(struct client_ctx *, union arg *);
void mousefunc_menu_group(struct client_ctx *, union arg *);
void mousefunc_menu_unhide(struct client_ctx *,
union arg *);
void client_ptrwarp(struct client_ctx *);
void client_ptrsave(struct client_ctx *);
void client_draw_border(struct client_ctx *);
void client_maximize(struct client_ctx *);
void client_vertmaximize(struct client_ctx *);
void client_horizmaximize(struct client_ctx *);
void client_map(struct client_ctx *);
void client_mtf(struct client_ctx *);
struct client_ctx *client_cycle(struct screen_ctx *, int);
void client_getsizehints(struct client_ctx *);
void client_applysizehints(struct client_ctx *);
struct menu *menu_filter(struct screen_ctx *, struct menu_q *,
const char *, const char *, int,
char *, char *, int,
void (*)(struct menu_q *, struct menu_q *, char *),
void (*)(struct menu *, int));
void menuq_add(struct menu_q *, void *, const char *, ...);
void menuq_clear(struct menu_q *);
void menu_init(struct screen_ctx *);
/* XXX should be xu_ */
void xev_reconfig(struct client_ctx *);
void xev_loop(void);
void xu_getatoms(void);
int xu_ptr_grab(Window, int, Cursor);
void xu_btn_grab(Window, int, u_int);
int xu_ptr_regrab(int, Cursor);
void xu_btn_ungrab(Window, int, u_int);
void xu_ptr_ungrab(void);
void xu_ptr_setpos(Window, int, int);
void xu_ptr_getpos(Window, int *, int *);
void xu_key_grab(Window, int, int);
void xu_key_ungrab(Window, int, int);
void xu_sendmsg(Window, Atom, long);
int xu_getprop(Window, Atom, Atom, long, u_char **);
int xu_getstrprop(Window, Atom, char **);
void xu_setstate(struct client_ctx *, int);
int xu_getstate(struct client_ctx *, int *);
unsigned long xu_getcolor(struct screen_ctx *, char *);
void xu_freecolor(struct screen_ctx *, unsigned long);
void xu_setwmname(struct screen_ctx *);
int u_spawn(char *);
void u_exec(char *);
void xfree(void *);
void *xmalloc(size_t);
void *xcalloc(size_t, size_t);
char *xstrdup(const char *);
struct screen_ctx *screen_fromroot(Window);
void screen_updatestackingorder(struct screen_ctx *);
void screen_update_geometry(struct screen_ctx *, int, int);
void screen_init_xinerama(struct screen_ctx *);
XineramaScreenInfo *screen_find_xinerama(struct screen_ctx *, int, int);
void conf_setup(struct conf *, const char *);
void conf_client(struct client_ctx *);
void conf_grab(struct conf *, struct keybinding *);
void conf_ungrab(struct conf *, struct keybinding *);
void conf_bindname(struct conf *, char *, char *);
void conf_mousebind(struct conf *, char *, char *);
void conf_grab_mouse(struct client_ctx *);
void conf_reload(struct conf *);
void conf_gap(struct conf *, struct screen_ctx *);
void conf_font(struct conf *, struct screen_ctx *);
void conf_color(struct conf *, struct screen_ctx *);
void conf_init(struct conf *);
void conf_clear(struct conf *);
void conf_cmd_add(struct conf *, char *, char *, int);
int parse_config(const char *, struct conf *);
void conf_atoms(void);
void conf_autogroup(struct conf *, int, const char *);
int conf_bind_kbd(struct conf *, const char *,
const char *);
int conf_bind_mouse(struct conf *, const char *,
const char *);
void conf_clear(struct conf *);
void conf_client(struct client_ctx *);
int conf_cmd_add(struct conf *, const char *,
const char *);
void conf_cursor(struct conf *);
void conf_grab_kbd(Window);
void conf_grab_mouse(Window);
void conf_init(struct conf *);
void conf_ignore(struct conf *, const char *);
void conf_screen(struct screen_ctx *);
void kbfunc_client_lower(struct client_ctx *, union arg *);
void kbfunc_client_raise(struct client_ctx *, union arg *);
void kbfunc_client_search(struct client_ctx *, union arg *);
void kbfunc_client_hide(struct client_ctx *, union arg *);
void kbfunc_client_cycle(struct client_ctx *, union arg *);
void kbfunc_client_rcycle(struct client_ctx *, union arg *);
void kbfunc_cmdexec(struct client_ctx *, union arg *);
void kbfunc_client_label(struct client_ctx *, union arg *);
void kbfunc_client_delete(struct client_ctx *, union arg *);
void kbfunc_client_group(struct client_ctx *, union arg *);
void kbfunc_client_grouponly(struct client_ctx *,
union arg *);
void kbfunc_client_cyclegroup(struct client_ctx *,
union arg *);
void kbfunc_client_nogroup(struct client_ctx *,
union arg *);
void kbfunc_client_grouptoggle(struct client_ctx *,
union arg *);
void kbfunc_client_movetogroup(struct client_ctx *,
union arg *);
void kbfunc_client_maximize(struct client_ctx *,
union arg *);
void kbfunc_client_vmaximize(struct client_ctx *,
union arg *);
void kbfunc_client_hmaximize(struct client_ctx *,
union arg *);
void kbfunc_reload(struct client_ctx *, union arg *);
void kbfunc_quit_wm(struct client_ctx *, union arg *);
void kbfunc_moveresize(struct client_ctx *, union arg *);
void kbfunc_menu_search(struct client_ctx *, union arg *);
void kbfunc_exec(struct client_ctx *, union arg *);
void kbfunc_ssh(struct client_ctx *, union arg *);
void kbfunc_term(struct client_ctx *, union arg *);
void kbfunc_lock(struct client_ctx *, union arg *);
void xev_process(void);
void mousefunc_window_resize(struct client_ctx *, void *);
void mousefunc_window_move(struct client_ctx *, void *);
void mousefunc_window_grouptoggle(struct client_ctx *,
void *);
void mousefunc_window_lower(struct client_ctx *, void *);
void mousefunc_window_hide(struct client_ctx *, void *);
void mousefunc_menu_group(struct client_ctx *, void *);
void mousefunc_menu_unhide(struct client_ctx *, void *);
void mousefunc_menu_cmd(struct client_ctx *, void *);
void xu_btn_grab(Window, int, unsigned int);
void xu_btn_ungrab(Window);
int xu_getprop(Window, Atom, Atom, long, unsigned char **);
int xu_getstrprop(Window, Atom, char **);
void xu_key_grab(Window, unsigned int, KeySym);
void xu_key_ungrab(Window);
void xu_ptr_getpos(Window, int *, int *);
int xu_ptr_grab(Window, unsigned int, Cursor);
int xu_ptr_regrab(unsigned int, Cursor);
void xu_ptr_setpos(Window, int, int);
void xu_ptr_ungrab(void);
void xu_xft_draw(struct screen_ctx *, const char *,
int, int, int);
int xu_xft_width(XftFont *, const char *, int);
void xu_xorcolor(XftColor, XftColor, XftColor *);
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 xu_ewmh_net_supported(struct screen_ctx *);
void xu_ewmh_net_supported_wm_check(struct screen_ctx *);
void xu_ewmh_net_desktop_geometry(struct screen_ctx *);
void xu_ewmh_net_workarea(struct screen_ctx *);
void xu_ewmh_net_client_list(struct screen_ctx *);
void xu_ewmh_net_active_window(struct screen_ctx *, Window);
void xu_ewmh_net_wm_desktop_viewport(struct screen_ctx *);
void xu_ewmh_net_wm_number_of_desktops(struct screen_ctx *);
void xu_ewmh_net_showing_desktop(struct screen_ctx *);
void xu_ewmh_net_virtual_roots(struct screen_ctx *);
void xu_ewmh_net_current_desktop(struct screen_ctx *, long);
void xu_ewmh_net_desktop_names(struct screen_ctx *, char *,
int);
void group_init(struct screen_ctx *);
void group_make_autogroup(struct conf *, char *, int);
void group_update_names(struct screen_ctx *);
void group_hidetoggle(struct screen_ctx *, int);
void group_only(struct screen_ctx *, int);
void group_cycle(struct screen_ctx *, int);
void group_sticky(struct client_ctx *);
void group_client_delete(struct client_ctx *);
void group_menu(XButtonEvent *);
void group_alltoggle(struct screen_ctx *);
void group_sticky_toggle_enter(struct client_ctx *);
void group_sticky_toggle_exit(struct client_ctx *);
void group_autogroup(struct client_ctx *);
void group_movetogroup(struct client_ctx *, int);
void xu_ewmh_net_wm_desktop(struct client_ctx *);
Atom *xu_ewmh_get_net_wm_state(struct client_ctx *, int *);
void xu_ewmh_handle_net_wm_state_msg(struct client_ctx *,
int, Atom , Atom);
void xu_ewmh_set_net_wm_state(struct client_ctx *);
void xu_ewmh_restore_net_wm_state(struct client_ctx *);
int font_ascent(struct screen_ctx *);
int font_descent(struct screen_ctx *);
u_int font_height(struct screen_ctx *);
void font_init(struct screen_ctx *);
int font_width(struct screen_ctx *, const char *, int);
void font_draw(struct screen_ctx *, const char *, int,
Drawable, int, int);
XftFont *font_make(struct screen_ctx *, const char *);
void u_exec(char *);
void u_spawn(char *);
/* Externs */
void *xcalloc(size_t, size_t);
void *xmalloc(size_t);
char *xstrdup(const char *);
int xasprintf(char **, const char *, ...)
__attribute__((__format__ (printf, 2, 3)))
__attribute__((__nonnull__ (2)));
extern Display *X_Dpy;
extern Cursor Cursor_move;
extern Cursor Cursor_resize;
extern Cursor Cursor_select;
extern Cursor Cursor_default;
extern Cursor Cursor_question;
extern struct screen_ctx_q Screenq;
extern struct screen_ctx *curscreen;
extern struct client_ctx_q Clientq;
extern int HasXinerama, HasRandr, Randr_ev;
extern struct conf Conf;
#define WM_STATE cwm_atoms[0]
#define WM_DELETE_WINDOW cwm_atoms[1]
#define WM_TAKE_FOCUS cwm_atoms[2]
#define WM_PROTOCOLS cwm_atoms[3]
#define _MOTIF_WM_HINTS cwm_atoms[4]
#define 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_ */

1030
client.c

File diff suppressed because it is too large Load Diff

783
conf.c
View File

@ -15,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $OpenBSD$
* $Id$
*/
#include <sys/param.h>
@ -24,157 +24,90 @@
#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "calmwm.h"
static const char *conf_bind_getmask(const char *, unsigned int *);
static void conf_cmd_remove(struct conf *, const char *);
static void conf_unbind_kbd(struct conf *, struct binding *);
static void conf_unbind_mouse(struct conf *, struct binding *);
#ifndef timespeccmp
#define timespeccmp(tsp, usp, cmp) \
(((tsp)->tv_sec == (usp)->tv_sec) ? \
((tsp)->tv_nsec cmp (usp)->tv_nsec) : \
((tsp)->tv_sec cmp (usp)->tv_sec))
#endif
int
conf_cmd_add(struct conf *c, const char *name, const char *path)
static void conf_mouseunbind(struct conf *, struct mousebinding *);
static void conf_unbind(struct conf *, struct keybinding *);
/* Add an command menu entry to the end of the menu */
void
conf_cmd_add(struct conf *c, char *image, char *label, int flags)
{
struct cmd *cmd;
/* "term" and "lock" have special meanings. */
if (strcmp(name, "term") == 0) {
if (strlcpy(c->termpath, path, sizeof(c->termpath)) >=
sizeof(c->termpath))
return (0);
} else if (strcmp(name, "lock") == 0) {
if (strlcpy(c->lockpath, path, sizeof(c->lockpath)) >=
sizeof(c->lockpath))
return (0);
} else {
conf_cmd_remove(c, name);
cmd = xmalloc(sizeof(*cmd));
cmd->name = xstrdup(name);
if (strlcpy(cmd->path, path, sizeof(cmd->path)) >=
sizeof(cmd->path))
return (0);
if (strcmp(label, "term") == 0)
strlcpy(c->termpath, image, sizeof(c->termpath));
else if (strcmp(label, "lock") == 0)
strlcpy(c->lockpath, image, sizeof(c->lockpath));
else {
struct cmd *cmd = xmalloc(sizeof(*cmd));
cmd->flags = flags;
strlcpy(cmd->image, image, sizeof(cmd->image));
strlcpy(cmd->label, label, sizeof(cmd->label));
TAILQ_INSERT_TAIL(&c->cmdq, cmd, entry);
}
return (1);
}
static void
conf_cmd_remove(struct conf *c, const char *name)
{
struct cmd *cmd = NULL, *cmdnxt;
TAILQ_FOREACH_SAFE(cmd, &c->cmdq, entry, cmdnxt) {
if (strcmp(cmd->name, name) == 0) {
TAILQ_REMOVE(&c->cmdq, cmd, entry);
free(cmd->name);
free(cmd);
}
}
}
void
conf_autogroup(struct conf *c, int no, const char *val)
{
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(&c->autogroupq, aw, entry);
}
void
conf_ignore(struct conf *c, const char *name)
conf_gap(struct conf *c, struct screen_ctx *sc)
{
struct winname *wn;
wn = xcalloc(1, sizeof(*wn));
wn->name = xstrdup(name);
TAILQ_INSERT_TAIL(&c->ignoreq, wn, entry);
sc->gap = c->gap;
}
static const char *color_binds[] = {
"#CCCCCC", /* CWM_COLOR_BORDER_ACTIVE */
"#666666", /* CWM_COLOR_BORDER_INACTIVE */
"#FC8814", /* CWM_COLOR_BORDER_URGENCY */
"blue", /* CWM_COLOR_BORDER_GROUP */
"red", /* CWM_COLOR_BORDER_UNGROUP */
"black", /* CWM_COLOR_MENU_FG */
"white", /* CWM_COLOR_MENU_BG */
"black", /* CWM_COLOR_MENU_FONT */
"", /* CWM_COLOR_MENU_FONT_SEL */
};
void
conf_screen(struct screen_ctx *sc)
conf_font(struct conf *c, struct screen_ctx *sc)
{
unsigned int i;
XftColor xc;
Colormap colormap = DefaultColormap(X_Dpy, sc->which);
Visual *visual = DefaultVisual(X_Dpy, sc->which);
sc->gap = Conf.gap;
sc->snapdist = Conf.snapdist;
sc->xftfont = XftFontOpenXlfd(X_Dpy, sc->which, Conf.font);
if (sc->xftfont == NULL) {
sc->xftfont = XftFontOpenName(X_Dpy, sc->which, Conf.font);
if (sc->xftfont == NULL)
errx(1, "XftFontOpenName");
}
for (i = 0; i < nitems(color_binds); i++) {
if (i == CWM_COLOR_MENU_FONT_SEL && *Conf.color[i] == '\0') {
xu_xorcolor(sc->xftcolor[CWM_COLOR_MENU_BG],
sc->xftcolor[CWM_COLOR_MENU_FG], &xc);
xu_xorcolor(sc->xftcolor[CWM_COLOR_MENU_FONT], xc, &xc);
if (!XftColorAllocValue(X_Dpy, visual, colormap,
&xc.color, &sc->xftcolor[CWM_COLOR_MENU_FONT_SEL]))
warnx("XftColorAllocValue: %s", Conf.color[i]);
break;
}
if (XftColorAllocName(X_Dpy, visual, colormap,
Conf.color[i], &xc)) {
sc->xftcolor[i] = xc;
XftColorFree(X_Dpy, visual, colormap, &xc);
} else {
warnx("XftColorAllocName: %s", Conf.color[i]);
XftColorAllocName(X_Dpy, visual, colormap,
color_binds[i], &sc->xftcolor[i]);
}
}
sc->menuwin = XCreateSimpleWindow(X_Dpy, sc->rootwin, 0, 0, 1, 1,
Conf.bwidth,
sc->xftcolor[CWM_COLOR_MENU_FG].pixel,
sc->xftcolor[CWM_COLOR_MENU_BG].pixel);
sc->xftdraw = XftDrawCreate(X_Dpy, sc->menuwin, visual, colormap);
if (sc->xftdraw == NULL)
errx(1, "XftDrawCreate");
conf_grab_kbd(sc->rootwin);
sc->font = font_make(sc, c->DefaultFontName);
sc->fontheight = font_ascent(sc) + font_descent(sc) + 1;
}
static const struct {
const char *key;
const char *func;
} kbd_binds[] = {
void
conf_color(struct conf *c, struct screen_ctx *sc)
{
int i;
for (i = 0; i < CWM_COLOR_MAX; i++) {
xu_freecolor(sc, sc->color[i].pixel);
sc->color[i].pixel = xu_getcolor(sc, c->color[i].name);
}
}
void
conf_reload(struct conf *c)
{
struct screen_ctx *sc;
struct client_ctx *cc;
if (parse_config(c->conf_path, c) == -1) {
warnx("config file %s has errors, not reloading", c->conf_path);
return;
}
TAILQ_FOREACH(cc, &Clientq, entry)
client_draw_border(cc);
TAILQ_FOREACH(sc, &Screenq, entry) {
conf_gap(c, sc);
conf_color(c, sc);
conf_font(c, sc);
}
}
static struct {
char *key;
char *func;
} kb_binds[] = {
{ "CM-Return", "terminal" },
{ "CM-Delete", "lock" },
{ "M-question", "exec" },
@ -202,12 +135,10 @@ static const struct {
{ "M-Right", "cyclegroup" },
{ "M-Left", "rcyclegroup" },
{ "CM-g", "grouptoggle" },
{ "CM-f", "fullscreen" },
{ "CM-m", "maximize" },
{ "CM-f", "maximize" },
{ "CM-equal", "vmaximize" },
{ "CMS-equal", "hmaximize" },
{ "CMS-f", "freeze" },
{ "CMS-r", "restart" },
{ "CMS-r", "reload" },
{ "CMS-q", "quit" },
{ "M-h", "moveleft" },
{ "M-j", "movedown" },
@ -234,7 +165,7 @@ static const struct {
{ "CS-Up", "bigptrmoveup" },
{ "CS-Right", "bigptrmoveright" },
},
mouse_binds[] = {
m_binds[] = {
{ "1", "menu_unhide" },
{ "2", "menu_group" },
{ "3", "menu_cmd" },
@ -248,13 +179,11 @@ mouse_binds[] = {
void
conf_init(struct conf *c)
{
unsigned int i;
(void)memset(c, 0, sizeof(*c));
int i;
c->flags = 0;
c->bwidth = CONF_BWIDTH;
c->mamount = CONF_MAMOUNT;
c->snapdist = CONF_SNAPDIST;
TAILQ_INIT(&c->ignoreq);
TAILQ_INIT(&c->cmdq);
@ -262,75 +191,109 @@ conf_init(struct conf *c)
TAILQ_INIT(&c->autogroupq);
TAILQ_INIT(&c->mousebindingq);
for (i = 0; i < nitems(kbd_binds); i++)
conf_bind_kbd(c, kbd_binds[i].key, kbd_binds[i].func);
for (i = 0; i < sizeof(kb_binds) / sizeof(kb_binds[0]); i++)
conf_bindname(c, kb_binds[i].key, kb_binds[i].func);
for (i = 0; i < nitems(mouse_binds); i++)
conf_bind_mouse(c, mouse_binds[i].key, mouse_binds[i].func);
for (i = 0; i < sizeof(m_binds) / sizeof(m_binds[0]); i++)
conf_mousebind(c, m_binds[i].key, m_binds[i].func);
for (i = 0; i < nitems(color_binds); i++)
c->color[i] = xstrdup(color_binds[i]);
/* Default term/lock */
strlcpy(c->termpath, "xterm", sizeof(c->termpath));
strlcpy(c->lockpath, "xlock", sizeof(c->lockpath));
conf_cmd_add(c, "lock", "xlock");
conf_cmd_add(c, "term", "xterm");
c->color[CWM_COLOR_BORDOR_ACTIVE].name =
xstrdup(CONF_COLOR_ACTIVEBORDER);
c->color[CWM_COLOR_BORDER_INACTIVE].name =
xstrdup(CONF_COLOR_INACTIVEBORDER);
c->color[CWM_COLOR_BORDER_GROUP].name =
xstrdup(CONF_COLOR_GROUPBORDER);
c->color[CWM_COLOR_BORDER_UNGROUP].name =
xstrdup(CONF_COLOR_UNGROUPBORDER);
c->color[CWM_COLOR_FG_MENU].name =
xstrdup(CONF_COLOR_MENUFG);
c->color[CWM_COLOR_BG_MENU].name =
xstrdup(CONF_COLOR_MENUBG);
(void)snprintf(c->known_hosts, sizeof(c->known_hosts), "%s/%s",
homedir, ".ssh/known_hosts");
c->font = xstrdup(CONF_FONT);
c->DefaultFontName = xstrdup(DEFAULTFONTNAME);
}
void
conf_clear(struct conf *c)
{
struct autogroupwin *aw;
struct binding *kb, *mb;
struct winname *wn;
struct autogroupwin *ag;
struct keybinding *kb;
struct winmatch *wm;
struct cmd *cmd;
struct mousebinding *mb;
int i;
while ((cmd = TAILQ_FIRST(&c->cmdq)) != NULL) {
TAILQ_REMOVE(&c->cmdq, cmd, entry);
free(cmd->name);
free(cmd);
xfree(cmd);
}
while ((kb = TAILQ_FIRST(&c->keybindingq)) != NULL) {
TAILQ_REMOVE(&c->keybindingq, kb, entry);
free(kb);
xfree(kb);
}
while ((aw = TAILQ_FIRST(&c->autogroupq)) != NULL) {
TAILQ_REMOVE(&c->autogroupq, aw, entry);
free(aw->class);
free(aw->name);
free(aw);
while ((ag = TAILQ_FIRST(&c->autogroupq)) != NULL) {
TAILQ_REMOVE(&c->autogroupq, ag, entry);
xfree(ag->class);
if (ag->name)
xfree(ag->name);
xfree(ag);
}
while ((wn = TAILQ_FIRST(&c->ignoreq)) != NULL) {
TAILQ_REMOVE(&c->ignoreq, wn, entry);
free(wn);
while ((wm = TAILQ_FIRST(&c->ignoreq)) != NULL) {
TAILQ_REMOVE(&c->ignoreq, wm, entry);
xfree(wm);
}
while ((mb = TAILQ_FIRST(&c->mousebindingq)) != NULL) {
TAILQ_REMOVE(&c->mousebindingq, mb, entry);
free(mb);
xfree(mb);
}
for (i = 0; i < CWM_COLOR_NITEMS; i++)
free(c->color[i]);
for (i = 0; i < CWM_COLOR_MAX; i++)
xfree(c->color[i].name);
free(c->font);
xfree(c->DefaultFontName);
}
void
conf_setup(struct conf *c, const char *conf_file)
{
struct stat sb;
if (conf_file == NULL) {
char *home = getenv("HOME");
if (home == NULL)
errx(1, "No HOME directory.");
snprintf(c->conf_path, sizeof(c->conf_path), "%s/%s", home,
CONFFILE);
} else
if (stat(conf_file, &sb) == -1 || !(sb.st_mode & S_IFREG))
errx(1, "%s: %s", conf_file, strerror(errno));
else
strlcpy(c->conf_path, conf_file, sizeof(c->conf_path));
conf_init(c);
(void)parse_config(c->conf_path, c);
}
void
conf_client(struct client_ctx *cc)
{
struct winname *wn;
struct winmatch *wm;
char *wname = cc->name;
int ignore = 0;
TAILQ_FOREACH(wn, &Conf.ignoreq, entry) {
if (strncasecmp(wn->name, cc->name, strlen(wn->name)) == 0) {
TAILQ_FOREACH(wm, &Conf.ignoreq, entry) {
if (strncasecmp(wm->title, wname, strlen(wm->title)) == 0) {
ignore = 1;
break;
}
@ -340,21 +303,21 @@ conf_client(struct client_ctx *cc)
cc->flags |= ignore ? CLIENT_IGNORE : 0;
}
static const struct {
const char *tag;
static struct {
char *tag;
void (*handler)(struct client_ctx *, union arg *);
int flags;
union arg argument;
} name_to_kbfunc[] = {
{ "lower", kbfunc_client_lower, CWM_WIN, {0} },
{ "raise", kbfunc_client_raise, CWM_WIN, {0} },
{ "lower", kbfunc_client_lower, KBFLAG_NEEDCLIENT, {0} },
{ "raise", kbfunc_client_raise, KBFLAG_NEEDCLIENT, {0} },
{ "search", kbfunc_client_search, 0, {0} },
{ "menusearch", kbfunc_menu_cmd, 0, {0} },
{ "hide", kbfunc_client_hide, CWM_WIN, {0} },
{ "menusearch", kbfunc_menu_search, 0, {0} },
{ "hide", kbfunc_client_hide, KBFLAG_NEEDCLIENT, {0} },
{ "cycle", kbfunc_client_cycle, 0, {.i = CWM_CYCLE} },
{ "rcycle", kbfunc_client_cycle, 0, {.i = CWM_RCYCLE} },
{ "label", kbfunc_client_label, CWM_WIN, {0} },
{ "delete", kbfunc_client_delete, CWM_WIN, {0} },
{ "label", kbfunc_client_label, KBFLAG_NEEDCLIENT, {0} },
{ "delete", kbfunc_client_delete, KBFLAG_NEEDCLIENT, {0} },
{ "group1", kbfunc_client_group, 0, {.i = 1} },
{ "group2", kbfunc_client_group, 0, {.i = 2} },
{ "group3", kbfunc_client_group, 0, {.i = 3} },
@ -373,90 +336,120 @@ static const struct {
{ "grouponly7", kbfunc_client_grouponly, 0, {.i = 7} },
{ "grouponly8", kbfunc_client_grouponly, 0, {.i = 8} },
{ "grouponly9", kbfunc_client_grouponly, 0, {.i = 9} },
{ "movetogroup1", kbfunc_client_movetogroup, CWM_WIN, {.i = 1} },
{ "movetogroup2", kbfunc_client_movetogroup, CWM_WIN, {.i = 2} },
{ "movetogroup3", kbfunc_client_movetogroup, CWM_WIN, {.i = 3} },
{ "movetogroup4", kbfunc_client_movetogroup, CWM_WIN, {.i = 4} },
{ "movetogroup5", kbfunc_client_movetogroup, CWM_WIN, {.i = 5} },
{ "movetogroup6", kbfunc_client_movetogroup, CWM_WIN, {.i = 6} },
{ "movetogroup7", kbfunc_client_movetogroup, CWM_WIN, {.i = 7} },
{ "movetogroup8", kbfunc_client_movetogroup, CWM_WIN, {.i = 8} },
{ "movetogroup9", kbfunc_client_movetogroup, CWM_WIN, {.i = 9} },
{ "movetogroup1", kbfunc_client_movetogroup, KBFLAG_NEEDCLIENT,
{.i = 1} },
{ "movetogroup2", kbfunc_client_movetogroup, KBFLAG_NEEDCLIENT,
{.i = 2} },
{ "movetogroup3", kbfunc_client_movetogroup, KBFLAG_NEEDCLIENT,
{.i = 3} },
{ "movetogroup4", kbfunc_client_movetogroup, KBFLAG_NEEDCLIENT,
{.i = 4} },
{ "movetogroup5", kbfunc_client_movetogroup, KBFLAG_NEEDCLIENT,
{.i = 5} },
{ "movetogroup6", kbfunc_client_movetogroup, KBFLAG_NEEDCLIENT,
{.i = 6} },
{ "movetogroup7", kbfunc_client_movetogroup, KBFLAG_NEEDCLIENT,
{.i = 7} },
{ "movetogroup8", kbfunc_client_movetogroup, KBFLAG_NEEDCLIENT,
{.i = 8} },
{ "movetogroup9", kbfunc_client_movetogroup, KBFLAG_NEEDCLIENT,
{.i = 9} },
{ "nogroup", kbfunc_client_nogroup, 0, {0} },
{ "cyclegroup", kbfunc_client_cyclegroup, 0, {.i = CWM_CYCLE} },
{ "rcyclegroup", kbfunc_client_cyclegroup, 0, {.i = CWM_RCYCLE} },
{ "cycleingroup", kbfunc_client_cycle, CWM_WIN,
{.i = CWM_CYCLE|CWM_INGROUP} },
{ "rcycleingroup", kbfunc_client_cycle, CWM_WIN,
{.i = CWM_RCYCLE|CWM_INGROUP} },
{ "grouptoggle", kbfunc_client_grouptoggle, CWM_WIN, {0}},
{ "fullscreen", kbfunc_client_fullscreen, CWM_WIN, {0} },
{ "maximize", kbfunc_client_maximize, CWM_WIN, {0} },
{ "vmaximize", kbfunc_client_vmaximize, CWM_WIN, {0} },
{ "hmaximize", kbfunc_client_hmaximize, CWM_WIN, {0} },
{ "freeze", kbfunc_client_freeze, CWM_WIN, {0} },
{ "restart", kbfunc_cwm_status, 0, {.i = CWM_RESTART} },
{ "quit", kbfunc_cwm_status, 0, {.i = CWM_QUIT} },
{ "cyclegroup", kbfunc_client_cyclegroup, 0, {.i = CWM_CYCLEGROUP} },
{ "rcyclegroup", kbfunc_client_cyclegroup, 0, {.i = CWM_RCYCLEGROUP} },
{ "grouptoggle", kbfunc_client_grouptoggle, KBFLAG_NEEDCLIENT, {0}},
{ "maximize", kbfunc_client_maximize, KBFLAG_NEEDCLIENT, {0} },
{ "vmaximize", kbfunc_client_vmaximize, KBFLAG_NEEDCLIENT, {0} },
{ "hmaximize", kbfunc_client_hmaximize, KBFLAG_NEEDCLIENT, {0} },
{ "reload", kbfunc_reload, 0, {0} },
{ "quit", kbfunc_quit_wm, 0, {0} },
{ "exec", kbfunc_exec, 0, {.i = CWM_EXEC_PROGRAM} },
{ "exec_wm", kbfunc_exec, 0, {.i = CWM_EXEC_WM} },
{ "ssh", kbfunc_ssh, 0, {0} },
{ "terminal", kbfunc_term, 0, {0} },
{ "lock", kbfunc_lock, 0, {0} },
{ "moveup", kbfunc_client_moveresize, CWM_WIN,
{ "moveup", kbfunc_moveresize, KBFLAG_NEEDCLIENT,
{.i = (CWM_UP|CWM_MOVE)} },
{ "movedown", kbfunc_client_moveresize, CWM_WIN,
{ "movedown", kbfunc_moveresize, KBFLAG_NEEDCLIENT,
{.i = (CWM_DOWN|CWM_MOVE)} },
{ "moveright", kbfunc_client_moveresize, CWM_WIN,
{ "moveright", kbfunc_moveresize, KBFLAG_NEEDCLIENT,
{.i = (CWM_RIGHT|CWM_MOVE)} },
{ "moveleft", kbfunc_client_moveresize, CWM_WIN,
{ "moveleft", kbfunc_moveresize, KBFLAG_NEEDCLIENT,
{.i = (CWM_LEFT|CWM_MOVE)} },
{ "bigmoveup", kbfunc_client_moveresize, CWM_WIN,
{ "bigmoveup", kbfunc_moveresize, KBFLAG_NEEDCLIENT,
{.i = (CWM_UP|CWM_MOVE|CWM_BIGMOVE)} },
{ "bigmovedown", kbfunc_client_moveresize, CWM_WIN,
{ "bigmovedown", kbfunc_moveresize, KBFLAG_NEEDCLIENT,
{.i = (CWM_DOWN|CWM_MOVE|CWM_BIGMOVE)} },
{ "bigmoveright", kbfunc_client_moveresize, CWM_WIN,
{ "bigmoveright", kbfunc_moveresize, KBFLAG_NEEDCLIENT,
{.i = (CWM_RIGHT|CWM_MOVE|CWM_BIGMOVE)} },
{ "bigmoveleft", kbfunc_client_moveresize, CWM_WIN,
{ "bigmoveleft", kbfunc_moveresize, KBFLAG_NEEDCLIENT,
{.i = (CWM_LEFT|CWM_MOVE|CWM_BIGMOVE)} },
{ "resizeup", kbfunc_client_moveresize, CWM_WIN,
{ "resizeup", kbfunc_moveresize, KBFLAG_NEEDCLIENT,
{.i = (CWM_UP|CWM_RESIZE)} },
{ "resizedown", kbfunc_client_moveresize, CWM_WIN,
{ "resizedown", kbfunc_moveresize, KBFLAG_NEEDCLIENT,
{.i = (CWM_DOWN|CWM_RESIZE)} },
{ "resizeright", kbfunc_client_moveresize, CWM_WIN,
{ "resizeright", kbfunc_moveresize, KBFLAG_NEEDCLIENT,
{.i = (CWM_RIGHT|CWM_RESIZE)} },
{ "resizeleft", kbfunc_client_moveresize, CWM_WIN,
{ "resizeleft", kbfunc_moveresize, KBFLAG_NEEDCLIENT,
{.i = (CWM_LEFT|CWM_RESIZE)} },
{ "bigresizeup", kbfunc_client_moveresize, CWM_WIN,
{ "bigresizeup", kbfunc_moveresize, KBFLAG_NEEDCLIENT,
{.i = (CWM_UP|CWM_RESIZE|CWM_BIGMOVE)} },
{ "bigresizedown", kbfunc_client_moveresize, CWM_WIN,
{ "bigresizedown", kbfunc_moveresize, KBFLAG_NEEDCLIENT,
{.i = (CWM_DOWN|CWM_RESIZE|CWM_BIGMOVE)} },
{ "bigresizeright", kbfunc_client_moveresize, CWM_WIN,
{ "bigresizeright", kbfunc_moveresize, KBFLAG_NEEDCLIENT,
{.i = (CWM_RIGHT|CWM_RESIZE|CWM_BIGMOVE)} },
{ "bigresizeleft", kbfunc_client_moveresize, CWM_WIN,
{ "bigresizeleft", kbfunc_moveresize, KBFLAG_NEEDCLIENT,
{.i = (CWM_LEFT|CWM_RESIZE|CWM_BIGMOVE)} },
{ "ptrmoveup", kbfunc_client_moveresize, 0,
{.i = (CWM_UP|CWM_PTRMOVE)} },
{ "ptrmovedown", kbfunc_client_moveresize, 0,
{.i = (CWM_DOWN|CWM_PTRMOVE)} },
{ "ptrmoveleft", kbfunc_client_moveresize, 0,
{.i = (CWM_LEFT|CWM_PTRMOVE)} },
{ "ptrmoveright", kbfunc_client_moveresize, 0,
{ "ptrmoveup", kbfunc_moveresize, 0, {.i = (CWM_UP|CWM_PTRMOVE)} },
{ "ptrmovedown", kbfunc_moveresize, 0, {.i = (CWM_DOWN|CWM_PTRMOVE)} },
{ "ptrmoveleft", kbfunc_moveresize, 0, {.i = (CWM_LEFT|CWM_PTRMOVE)} },
{ "ptrmoveright", kbfunc_moveresize, 0,
{.i = (CWM_RIGHT|CWM_PTRMOVE)} },
{ "bigptrmoveup", kbfunc_client_moveresize, 0,
{ "bigptrmoveup", kbfunc_moveresize, 0,
{.i = (CWM_UP|CWM_PTRMOVE|CWM_BIGMOVE)} },
{ "bigptrmovedown", kbfunc_client_moveresize, 0,
{ "bigptrmovedown", kbfunc_moveresize, 0,
{.i = (CWM_DOWN|CWM_PTRMOVE|CWM_BIGMOVE)} },
{ "bigptrmoveleft", kbfunc_client_moveresize, 0,
{ "bigptrmoveleft", kbfunc_moveresize, 0,
{.i = (CWM_LEFT|CWM_PTRMOVE|CWM_BIGMOVE)} },
{ "bigptrmoveright", kbfunc_client_moveresize, 0,
{ "bigptrmoveright", kbfunc_moveresize, 0,
{.i = (CWM_RIGHT|CWM_PTRMOVE|CWM_BIGMOVE)} },
{ "htile", kbfunc_tile, CWM_WIN, {.i = CWM_TILE_HORIZ} },
{ "vtile", kbfunc_tile, CWM_WIN, {.i = CWM_TILE_VERT} },
{ NULL, NULL, 0, {0}},
};
static const struct {
const char ch;
int mask;
/*
* The following two functions are used when grabbing and ungrabbing keys for
* bindings
*/
/*
* Grab key combination on all screens and add to the global queue
*/
void
conf_grab(struct conf *c, struct keybinding *kb)
{
extern struct screen_ctx_q Screenq;
struct screen_ctx *sc;
TAILQ_FOREACH(sc, &Screenq, entry)
xu_key_grab(sc->rootwin, kb->modmask, kb->keysym);
}
/*
* Ungrab key combination from all screens and remove from global queue
*/
void
conf_ungrab(struct conf *c, struct keybinding *kb)
{
extern struct screen_ctx_q Screenq;
struct screen_ctx *sc;
TAILQ_FOREACH(sc, &Screenq, entry)
xu_key_ungrab(sc->rootwin, kb->modmask, kb->keysym);
}
static struct {
char chr;
int mask;
} bind_mods[] = {
{ 'C', ControlMask },
{ 'M', Mod1Mask },
@ -464,240 +457,202 @@ static const struct {
{ 'S', ShiftMask },
};
static const char *
conf_bind_getmask(const char *name, unsigned int *mask)
void
conf_bindname(struct conf *c, char *name, char *binding)
{
char *dash;
const char *ch;
unsigned int i;
struct keybinding *current_binding;
char *substring, *tmp;
int iter;
*mask = 0;
if ((dash = strchr(name, '-')) == NULL)
return (name);
for (i = 0; i < nitems(bind_mods); i++) {
if ((ch = strchr(name, bind_mods[i].ch)) != NULL && ch < dash)
*mask |= bind_mods[i].mask;
current_binding = xcalloc(1, sizeof(*current_binding));
if ((substring = strchr(name, '-')) != NULL) {
for (iter = 0; iter < (sizeof(bind_mods) /
sizeof(bind_mods[0])); iter++) {
if ((tmp = strchr(name, bind_mods[iter].chr)) !=
NULL && tmp < substring) {
current_binding->modmask |=
bind_mods[iter].mask;
}
}
/* skip past the modifiers */
substring++;
} else {
substring = name;
}
/* Skip past modifiers. */
return (dash + 1);
}
if (substring[0] == '[' &&
substring[strlen(substring)-1] == ']') {
sscanf(substring, "[%d]", &current_binding->keycode);
current_binding->keysym = NoSymbol;
} else {
current_binding->keycode = 0;
current_binding->keysym = XStringToKeysym(substring);
}
int
conf_bind_kbd(struct conf *c, const char *bind, const char *cmd)
{
struct binding *kb;
const char *key;
unsigned int i, mask;
kb = xcalloc(1, sizeof(*kb));
key = conf_bind_getmask(bind, &mask);
kb->modmask |= mask;
kb->press.keysym = XStringToKeysym(key);
if (kb->press.keysym == NoSymbol) {
warnx("unknown symbol: %s", key);
free(kb);
return (0);
if (current_binding->keysym == NoSymbol &&
current_binding->keycode == 0) {
xfree(current_binding);
return;
}
/* We now have the correct binding, remove duplicates. */
conf_unbind_kbd(c, kb);
conf_unbind(c, current_binding);
if (strcmp("unmap", cmd) == 0) {
free(kb);
return (1);
}
if (strcmp("unmap", binding) == 0)
return;
for (i = 0; i < nitems(name_to_kbfunc); i++) {
if (strcmp(name_to_kbfunc[i].tag, cmd) != 0)
for (iter = 0; name_to_kbfunc[iter].tag != NULL; iter++) {
if (strcmp(name_to_kbfunc[iter].tag, binding) != 0)
continue;
kb->callback = name_to_kbfunc[i].handler;
kb->flags = name_to_kbfunc[i].flags;
kb->argument = name_to_kbfunc[i].argument;
kb->argtype |= ARG_INT;
TAILQ_INSERT_TAIL(&c->keybindingq, kb, entry);
return (1);
current_binding->callback = name_to_kbfunc[iter].handler;
current_binding->flags = name_to_kbfunc[iter].flags;
current_binding->argument = name_to_kbfunc[iter].argument;
conf_grab(c, current_binding);
TAILQ_INSERT_TAIL(&c->keybindingq, current_binding, entry);
return;
}
kb->callback = kbfunc_cmdexec;
kb->flags = 0;
kb->argument.c = xstrdup(cmd);
kb->argtype |= ARG_CHAR;
TAILQ_INSERT_TAIL(&c->keybindingq, kb, entry);
return (1);
current_binding->callback = kbfunc_cmdexec;
current_binding->argument.c = xstrdup(binding);
current_binding->flags = 0;
conf_grab(c, current_binding);
TAILQ_INSERT_TAIL(&c->keybindingq, current_binding, entry);
return;
}
static void
conf_unbind_kbd(struct conf *c, struct binding *unbind)
conf_unbind(struct conf *c, struct keybinding *unbind)
{
struct binding *key = NULL, *keynxt;
struct keybinding *key = NULL, *keynxt;
for (key = TAILQ_FIRST(&c->keybindingq);
key != TAILQ_END(&c->keybindingq); key = keynxt) {
keynxt = TAILQ_NEXT(key, entry);
TAILQ_FOREACH_SAFE(key, &c->keybindingq, entry, keynxt) {
if (key->modmask != unbind->modmask)
continue;
if (key->press.keysym == unbind->press.keysym) {
if ((key->keycode != 0 && key->keysym == NoSymbol &&
key->keycode == unbind->keycode) ||
key->keysym == unbind->keysym) {
conf_ungrab(c, key);
TAILQ_REMOVE(&c->keybindingq, key, entry);
if (key->argtype & ARG_CHAR)
free(key->argument.c);
free(key);
xfree(key);
}
}
}
static const struct {
const char *tag;
void (*handler)(struct client_ctx *, union arg *);
int flags;
union arg argument;
static struct {
char *tag;
void (*handler)(struct client_ctx *, void *);
int context;
} name_to_mousefunc[] = {
{ "window_lower", kbfunc_client_lower, CWM_WIN, {0} },
{ "window_raise", kbfunc_client_raise, CWM_WIN, {0} },
{ "window_hide", kbfunc_client_hide, CWM_WIN, {0} },
{ "cyclegroup", kbfunc_client_cyclegroup, 0, {.i = CWM_CYCLE} },
{ "rcyclegroup", kbfunc_client_cyclegroup, 0, {.i = CWM_RCYCLE} },
{ "window_move", mousefunc_client_move, CWM_WIN, {0} },
{ "window_resize", mousefunc_client_resize, CWM_WIN, {0} },
{ "window_grouptoggle", mousefunc_client_grouptoggle, CWM_WIN, {0} },
{ "menu_group", mousefunc_menu_group, 0, {0} },
{ "menu_unhide", mousefunc_menu_unhide, 0, {0} },
{ "menu_cmd", mousefunc_menu_cmd, 0, {0} },
{ "window_move", mousefunc_window_move, MOUSEBIND_CTX_WIN },
{ "window_resize", mousefunc_window_resize, MOUSEBIND_CTX_WIN },
{ "window_grouptoggle", mousefunc_window_grouptoggle,
MOUSEBIND_CTX_WIN },
{ "window_lower", mousefunc_window_lower, MOUSEBIND_CTX_WIN },
{ "window_hide", mousefunc_window_hide, MOUSEBIND_CTX_WIN },
{ "menu_group", mousefunc_menu_group, MOUSEBIND_CTX_ROOT },
{ "menu_unhide", mousefunc_menu_unhide, MOUSEBIND_CTX_ROOT },
{ "menu_cmd", mousefunc_menu_cmd, MOUSEBIND_CTX_ROOT },
{ NULL, NULL, 0 },
};
int
conf_bind_mouse(struct conf *c, const char *bind, const char *cmd)
void
conf_mousebind(struct conf *c, char *name, char *binding)
{
struct binding *mb;
const char *button, *errstr;
unsigned int i, mask;
struct mousebinding *current_binding;
char *substring, *tmp;
const char *errstr;
int iter;
mb = xcalloc(1, sizeof(*mb));
button = conf_bind_getmask(bind, &mask);
mb->modmask |= mask;
current_binding = xcalloc(1, sizeof(*current_binding));
mb->press.button = strtonum(button, Button1, Button5, &errstr);
if (errstr) {
warnx("button number is %s: %s", errstr, button);
free(mb);
return (0);
}
if ((substring = strchr(name, '-')) != NULL) {
for (iter = 0; iter < (sizeof(bind_mods) /
sizeof(bind_mods[0])); iter++) {
if ((tmp = strchr(name, bind_mods[iter].chr)) !=
NULL && tmp < substring) {
current_binding->modmask |=
bind_mods[iter].mask;
}
}
/* We now have the correct binding, remove duplicates. */
conf_unbind_mouse(c, mb);
/* skip past the modifiers */
substring++;
} else
substring = name;
if (strcmp("unmap", cmd) == 0) {
free(mb);
return (1);
}
current_binding->button = strtonum(substring, 1, 3, &errstr);
if (errstr)
warnx("number of buttons is %s: %s", errstr, substring);
for (i = 0; i < nitems(name_to_mousefunc); i++) {
if (strcmp(name_to_mousefunc[i].tag, cmd) != 0)
conf_mouseunbind(c, current_binding);
if (strcmp("unmap", binding) == 0)
return;
for (iter = 0; name_to_mousefunc[iter].tag != NULL; iter++) {
if (strcmp(name_to_mousefunc[iter].tag, binding) != 0)
continue;
mb->callback = name_to_mousefunc[i].handler;
mb->flags = name_to_mousefunc[i].flags;
mb->argument = name_to_mousefunc[i].argument;
TAILQ_INSERT_TAIL(&c->mousebindingq, mb, entry);
return (1);
current_binding->context = name_to_mousefunc[iter].context;
current_binding->callback = name_to_mousefunc[iter].handler;
TAILQ_INSERT_TAIL(&c->mousebindingq, current_binding, entry);
return;
}
return (0);
}
static void
conf_unbind_mouse(struct conf *c, struct binding *unbind)
conf_mouseunbind(struct conf *c, struct mousebinding *unbind)
{
struct binding *mb = NULL, *mbnxt;
struct mousebinding *mb = NULL, *mbnxt;
for (mb = TAILQ_FIRST(&c->mousebindingq);
mb != TAILQ_END(&c->mousebindingq); mb = mbnxt) {
mbnxt = TAILQ_NEXT(mb, entry);
TAILQ_FOREACH_SAFE(mb, &c->mousebindingq, entry, mbnxt) {
if (mb->modmask != unbind->modmask)
continue;
if (mb->press.button == unbind->press.button) {
if (mb->button == unbind->button) {
TAILQ_REMOVE(&c->mousebindingq, mb, entry);
free(mb);
xfree(mb);
}
}
}
static int cursor_binds[] = {
XC_X_cursor, /* CF_DEFAULT */
XC_fleur, /* CF_MOVE */
XC_left_ptr, /* CF_NORMAL */
XC_question_arrow, /* CF_QUESTION */
XC_bottom_right_corner, /* CF_RESIZE */
};
/*
* Grab the mouse buttons that we need for bindings for this client
*/
void
conf_cursor(struct conf *c)
conf_grab_mouse(struct client_ctx *cc)
{
unsigned int i;
for (i = 0; i < nitems(cursor_binds); i++)
c->cursor[i] = XCreateFontCursor(X_Dpy, cursor_binds[i]);
}
void
conf_grab_mouse(Window win)
{
struct binding *mb;
xu_btn_ungrab(win);
struct mousebinding *mb;
int button;
TAILQ_FOREACH(mb, &Conf.mousebindingq, entry) {
if (mb->flags & CWM_WIN)
xu_btn_grab(win, mb->modmask, mb->press.button);
if (mb->context != MOUSEBIND_CTX_WIN)
continue;
switch(mb->button) {
case 1:
button = Button1;
break;
case 2:
button = Button2;
break;
case 3:
button = Button3;
break;
default:
warnx("strange button in mousebinding\n");
continue;
}
xu_btn_grab(cc->win, mb->modmask, button);
}
}
void
conf_grab_kbd(Window win)
{
struct binding *kb;
xu_key_ungrab(win);
TAILQ_FOREACH(kb, &Conf.keybindingq, entry)
xu_key_grab(win, kb->modmask, kb->press.keysym);
}
static char *cwmhints[] = {
"WM_STATE",
"WM_DELETE_WINDOW",
"WM_TAKE_FOCUS",
"WM_PROTOCOLS",
"_MOTIF_WM_HINTS",
"UTF8_STRING",
"WM_CHANGE_STATE",
};
static char *ewmhints[] = {
"_NET_SUPPORTED",
"_NET_SUPPORTING_WM_CHECK",
"_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_WORKAREA",
"_NET_WM_NAME",
"_NET_WM_DESKTOP",
"_NET_CLOSE_WINDOW",
"_NET_WM_STATE",
"_NET_WM_STATE_MAXIMIZED_VERT",
"_NET_WM_STATE_MAXIMIZED_HORZ",
"_NET_WM_STATE_FULLSCREEN",
"_NET_WM_STATE_DEMANDS_ATTENTION",
};
void
conf_atoms(void)
{
XInternAtoms(X_Dpy, cwmhints, nitems(cwmhints), False, cwmh);
XInternAtoms(X_Dpy, ewmhints, nitems(ewmhints), False, ewmh);
}

51
cwm.1
View File

@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: December 16 2013 $
.Dd $Mdocdate: August 24 2009 $
.Dt CWM 1
.Os
.Sh NAME
@ -52,7 +52,7 @@ Right mouse button.
.Nm
is very simple in its use.
Most of the actions are initiated via key bindings.
The default key bindings are described below;
The current key bindings are described below;
their functionality is described in more detail later.
.Pp
.Bl -tag -width "CM-EscapeXXXXX" -offset indent -compact
@ -88,12 +88,8 @@ Toggle group membership of current window.
Cycle through active groups.
.It Ic M-Left
Reverse cycle through active groups.
.It Ic CMS-f
Toggle freezing geometry of current window.
.It Ic CM-f
Toggle full-screen mode of current window.
.It Ic CM-m
Toggle maximization of current window.
Toggle full-screen size of current window.
.It Ic CM-=
Toggle vertical maximization of current window.
.It Ic CMS-=
@ -118,14 +114,13 @@ dialog; allows you to switch from
.Nm
to another window manager without restarting the X server.
.It Ic CMS-r
Restart the running
.Xr cwm 1 .
Reload configuration.
.It Ic CMS-q
Quit
.Nm .
.El
.Pp
The default mouse bindings are:
The mouse bindings are also important, they are:
.Pp
.Bl -tag -width Ds -offset indent -compact
.It Ic M-M1
@ -145,17 +140,8 @@ The options for
are as follows:
.Bl -tag -width Ds
.It Fl c Ar file
Specify an alternative configuration file.
By default,
.Nm
loads
.Pa ~/.cwmrc ,
if present.
Any error messages from lines in the configuration file will be sent to
.Em stderr ;
however,
.Nm
will continue to process the rest of the configuration file.
Specify the config file to use. Defaults to
.Pa ~/.cwmrc .
.It Fl d Ar display
Specify the display to use.
.El
@ -270,6 +256,18 @@ option is given.
.El
.Sh SEE ALSO
.Xr cwmrc 5
.Sh AUTHORS
.An -nosplit
.Pp
.Nm
was developed by
.An Marius Aamodt Eriksen Aq marius@monkey.org
with contributions from
.An Andy Adamson Aq dros@monkey.org ,
.An Niels Provos Aq provos@monkey.org ,
and
.An Antti Nyk\(:anen Aq aon@iki.fi .
Ideas, discussion with many others.
.Sh HISTORY
.Nm
was originally inspired by evilwm, but was rewritten from scratch
@ -280,14 +278,3 @@ has since been removed or rewritten.
.Nm
first appeared in
.Ox 4.2 .
.Sh AUTHORS
.An -nosplit
.Nm
was developed by
.An Marius Aamodt Eriksen Aq marius@monkey.org
with contributions from
.An Andy Adamson Aq dros@monkey.org ,
.An Niels Provos Aq provos@monkey.org ,
and
.An Antti Nyk\(:anen Aq aon@iki.fi .
Ideas, discussion with many others.

118
cwmrc.5
View File

@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: December 16 2013 $
.Dd $Mdocdate: September 25 2010 $
.Dt CWMRC 5
.Os
.Sh NAME
@ -24,48 +24,26 @@
This manual page describes the
.Xr cwm 1
configuration file.
.Pp
The current line can be extended over multiple lines using a backslash
.Pq Sq \e .
Comments can be put anywhere in the file using a hash mark
.Pq Sq # ,
and extend to the end of the current line.
Care should be taken when commenting out multi-line text:
the comment is effective until the end of the entire block.
.Pp
Arguments containing whitespace should be surrounded by double quotes
.Pq \&" .
.Pp
The following options are accepted:
The following options are accepted in the configuration file:
.Pp
.Bl -tag -width Ds -compact
.It Ic autogroup Ar group windowclass
.It Ic autogroup Ar group windowname
.It Ic autogroup Ar group windowname,windowclass
Automatically add new windows to
.Ar group
if their class property matches
.Ar windowclass ,
or if their name and class properties match
.Ar windowname
and
.Ar windowclass ,
respectively.
The more specific last match wins.
Control automatic window grouping, based on the name and/or class
properties, where
.Ar group
is a number between 0 and 9.
If
.Ar group
is 0, matching windows will not be added to any group; this may be
used to override
.Dq sticky group mode .
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 values, respectively, for existing windows
are both set in the WM_CLASS property and may be obtained using
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 key binding, or replacement of a default
key binding.
Cause the creation of a keybinding, or replacement of a default
keybinding.
The modifier keys come first, followed by a
.Sq - .
.Pp
@ -84,8 +62,10 @@ The Mod4 key (normally the windows key).
.Pp
The
.Sq -
should be followed by a keysym name, taken from
.Pa /usr/X11R6/include/X11/keysymdef.h .
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
@ -96,7 +76,7 @@ A special
.Ar command
keyword
.Dq unmap
can be used to remove the named key binding.
can be used to remove the named keybinding.
This can be used to remove a binding which conflicts with an
application.
.Pp
@ -107,27 +87,12 @@ Set the window border width to
.It Ic color activeborder Ar color
Set the color of the active border.
.Pp
.It Ic color font Ar color
Set menu font color.
.Pp
.It Ic color selfont Ar color
Set font color for selected menu item.
.Pp
.It Ic color groupborder Ar color
Set the color of the border while grouping a window.
.Pp
.It Ic color inactiveborder Ar color
Set the color of the inactive border.
.Pp
.It Ic color menubg Ar color
Set menu background color.
.Pp
.It Ic color menufg Ar color
Set menu foreground color.
.Pp
.It Ic color urgencyborder Ar color
Set the color of the border of a window indicating urgency.
.Pp
.It Ic color ungroupborder Ar color
Set the color of the border while ungrouping a window.
.Pp
@ -148,7 +113,7 @@ and
.Nm lock
have a special meaning.
They point to the terminal and screen locking programs specified by
key bindings.
keybindings.
The defaults are
.Xr xterm 1
and
@ -207,10 +172,6 @@ Left mouse button.
Middle mouse button.
.It 3
Right mouse button.
.It 4
Scroll up mouse button.
.It 5
Scroll down mouse button.
.El
.Pp
The
@ -224,10 +185,6 @@ Set a default size for the keyboard movement bindings,
in pixels.
The default is 1.
.Pp
.It Ic snapdist Ar pixels
Minimum distance to snap-to adjacent edge, in pixels.
The default is 0.
.Pp
.It Ic sticky Ic yes Ns \&| Ns Ic no
Toggle sticky group mode.
The default behavior for new windows is to not assign any group.
@ -258,14 +215,10 @@ ignore xwi
ignore xapm
ignore xclock
# Key bindings
# Keybindings
bind CM-r label
bind CS-Return "xterm -e top"
bind 4-o unmap
bind CM-equal unmap
bind CMS-equal unmap
bind C4-equal vmaximize
bind C4S-equal hmaximize
bind M-1 grouponly1
bind M-2 grouponly2
bind M-3 grouponly3
@ -273,15 +226,14 @@ bind MS-1 movetogroup1
bind MS-2 movetogroup2
bind MS-3 movetogroup3
# Mouse bindings
# Mousebindings
mousebind M-2 window_lower
mousebind M-3 window_resize
.Ed
.Sh BIND COMMAND LIST
.Bl -tag -width 18n -compact
.It restart
Restart the running
.Xr cwm 1 .
.It reload
Reload configuration.
.It quit
Quit
.Xr cwm 1 .
@ -325,10 +277,6 @@ Reverse cycle through groups.
Forward cycle through windows.
.It rcycle
Reverse cycle through windows.
.It cycleingroup
Forward cycle through windows in current group.
.It rcycleingroup
Reverse cycle through windows in current group.
.It delete
Delete current window.
.It hide
@ -339,16 +287,12 @@ Lower current window.
Raise current window.
.It label
Label current window.
.It freeze
Freeze current window geometry.
.It fullscreen
Full-screen current window (gap + border removed).
.It maximize
Maximize current window (gap + border honored).
Maximize current window full-screen.
.It vmaximize
Vertically maximize current window (gap + border honored).
Maximize current window vertically.
.It hmaximize
Horizontally maximize current window (gap + border honored).
Maximize current window horizontally.
.It moveup
Move window
.Ar moveamount
@ -445,12 +389,6 @@ pixels right.
Move pointer 10 times
.Ar moveamount
pixels left.
.It htile
Current window is placed at the top of the screen and maximized
horizontally, other windows in its group share remaining screen space.
.It vtile
Current window is placed on the left of the screen and maximized
vertically, other windows in its group share remaining screen space.
.El
.Sh MOUSEBIND COMMAND LIST
.Bl -tag -width 18n -compact
@ -460,16 +398,10 @@ Move current window.
Resize current window.
.It window_lower
Lower current window.
.It window_raise
Raise current window.
.It window_hide
Hide current window.
.It window_grouptoggle
Toggle group membership of current window.
.It cyclegroup
Forward cycle through groups.
.It rcyclegroup
Reverse cycle through groups.
.It menu_group
Launch group list.
.It menu_unhide

106
fgetln.c Normal file
View File

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

99
font.c Normal file
View File

@ -0,0 +1,99 @@
/*
* font.c - cwm font abstraction
*
* 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.
*/
#include <sys/param.h>
#include <sys/queue.h>
#include <err.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "calmwm.h"
int
font_ascent(struct screen_ctx *sc)
{
return (sc->font->ascent);
}
int
font_descent(struct screen_ctx *sc)
{
return (sc->font->descent);
}
u_int
font_height(struct screen_ctx *sc)
{
return (sc->fontheight);
}
void
font_init(struct screen_ctx *sc)
{
sc->xftdraw = XftDrawCreate(X_Dpy, sc->rootwin,
DefaultVisual(X_Dpy, sc->which), DefaultColormap(X_Dpy, sc->which));
if (sc->xftdraw == NULL)
errx(1, "XftDrawCreate");
if (!XftColorAllocName(X_Dpy, DefaultVisual(X_Dpy, sc->which),
DefaultColormap(X_Dpy, sc->which), "black", &sc->xftcolor))
errx(1, "XftColorAllocName");
}
int
font_width(struct screen_ctx *sc, const char *text, int len)
{
XGlyphInfo extents;
XftTextExtents8(X_Dpy, sc->font, (const XftChar8*)text,
len, &extents);
return (extents.xOff);
}
void
font_draw(struct screen_ctx *sc, const char *text, int len,
Drawable d, int x, int y)
{
XftDrawChange(sc->xftdraw, d);
/* Really needs to be UTF8'd. */
XftDrawString8(sc->xftdraw, &sc->xftcolor, sc->font, x, y,
(const FcChar8*)text, len);
}
XftFont *
font_make(struct screen_ctx *sc, const char *name)
{
XftFont *fn = NULL;
FcPattern *pat, *patx;
XftResult res;
if ((pat = FcNameParse((const FcChar8*)name)) == NULL)
return (NULL);
if ((patx = XftFontMatch(X_Dpy, sc->which, pat, &res)) != NULL)
fn = XftFontOpenPattern(X_Dpy, patx);
FcPatternDestroy(pat);
return (fn);
}

288
group.c
View File

@ -16,7 +16,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $OpenBSD$
* $Id$
*/
#include <sys/param.h>
@ -25,14 +25,15 @@
#include <assert.h>
#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "calmwm.h"
static void group_assign(struct group_ctx *, struct client_ctx *);
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 *);
@ -45,20 +46,40 @@ const char *shortcut_to_name[] = {
};
static void
group_assign(struct group_ctx *gc, struct client_ctx *cc)
group_add(struct group_ctx *gc, struct client_ctx *cc)
{
if (gc == NULL)
gc = TAILQ_FIRST(&cc->sc->groupq);
long no;
if (cc == NULL || gc == NULL)
errx(1, "group_add: a ctx is NULL");
no = gc->shortcut - 1;
if (cc->group == gc)
return;
if (cc->group != NULL)
TAILQ_REMOVE(&cc->group->clients, cc, group_entry);
XChangeProperty(X_Dpy, cc->win, _NET_WM_DESKTOP, XA_CARDINAL,
32, PropModeReplace, (unsigned char *)&no, 1);
TAILQ_INSERT_TAIL(&gc->clients, cc, group_entry);
cc->group = gc;
}
xu_ewmh_net_wm_desktop(cc);
static void
group_remove(struct client_ctx *cc)
{
long no = 0xffffffff;
if (cc == NULL || cc->group == NULL)
errx(1, "group_remove: a ctx is NULL");
XChangeProperty(X_Dpy, cc->win, _NET_WM_DESKTOP, XA_CARDINAL,
32, PropModeReplace, (unsigned char *)&no, 1);
TAILQ_REMOVE(&cc->group->clients, cc, group_entry);
cc->group = NULL;
}
static void
@ -84,14 +105,10 @@ group_show(struct screen_ctx *sc, struct group_ctx *gc)
{
struct client_ctx *cc;
Window *winlist;
int i, lastempty = -1;
u_int i;
int lastempty = -1;
gc->highstack = 0;
TAILQ_FOREACH(cc, &gc->clients, group_entry) {
if (cc->stackingorder > gc->highstack)
gc->highstack = cc->stackingorder;
}
winlist = xcalloc((gc->highstack + 1), sizeof(*winlist));
winlist = (Window *) xcalloc(sizeof(*winlist), (gc->highstack + 1));
/*
* Invert the stacking order as XRestackWindows() expects them
@ -114,74 +131,93 @@ group_show(struct screen_ctx *sc, struct group_ctx *gc)
}
XRestackWindows(X_Dpy, winlist, gc->nhidden);
free(winlist);
xfree(winlist);
gc->hidden = 0;
group_setactive(sc, gc->shortcut);
group_setactive(sc, gc->shortcut - 1);
}
void
group_init(struct screen_ctx *sc)
{
int i;
long viewports[2] = {0, 0};
long ndesks = CALMWM_NGROUPS, zero = 0;
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.
/* see if any group names have already been set and update the property
* with ours if they'll have changed.
*/
group_update_names(sc);
for (i = 0; i < CALMWM_NGROUPS; i++) {
TAILQ_INIT(&sc->groups[i].clients);
sc->groups[i].hidden = 0;
sc->groups[i].shortcut = i;
sc->groups[i].shortcut = i + 1;
TAILQ_INSERT_TAIL(&sc->groupq, &sc->groups[i], entry);
}
xu_ewmh_net_wm_desktop_viewport(sc);
xu_ewmh_net_wm_number_of_desktops(sc);
xu_ewmh_net_showing_desktop(sc);
xu_ewmh_net_virtual_roots(sc);
group_setactive(sc, 1);
/* 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_set_state(struct screen_ctx *sc)
group_make_autogroup(struct conf *conf, char *val, int no)
{
struct group_ctx *gc;
struct autogroupwin *aw;
char *p;
TAILQ_FOREACH(gc, &sc->groupq, entry)
group_fix_hidden_state(gc);
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];
xu_ewmh_net_current_desktop(sc, idx);
XChangeProperty(X_Dpy, sc->rootwin, _NET_CURRENT_DESKTOP,
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&idx, 1);
}
void
group_movetogroup(struct client_ctx *cc, int idx)
{
struct screen_ctx *sc = cc->sc;
struct group_ctx *gc;
if (idx < 0 || idx >= CALMWM_NGROUPS)
errx(1, "group_movetogroup: index out of range (%d)", idx);
err(1, "group_movetogroup: index out of range (%d)", idx);
gc = &sc->groups[idx];
if (cc->group == gc)
return;
if (gc->hidden) {
if(sc->group_active != &sc->groups[idx])
client_hide(cc);
gc->nhidden++;
}
group_assign(gc, cc);
group_add(&sc->groups[idx], cc);
}
/*
@ -191,14 +227,16 @@ void
group_sticky_toggle_enter(struct client_ctx *cc)
{
struct screen_ctx *sc = cc->sc;
struct group_ctx *gc = sc->group_active;
struct group_ctx *gc;
gc = sc->group_active;
if (gc == cc->group) {
group_assign(NULL, cc);
cc->flags |= CLIENT_UNGROUP;
group_remove(cc);
cc->highlight = CLIENT_HIGHLIGHT_UNGROUP;
} else {
group_assign(gc, cc);
cc->flags |= CLIENT_GROUP;
group_add(gc, cc);
cc->highlight = CLIENT_HIGHLIGHT_GROUP;
}
client_draw_border(cc);
@ -207,7 +245,7 @@ group_sticky_toggle_enter(struct client_ctx *cc)
void
group_sticky_toggle_exit(struct client_ctx *cc)
{
cc->flags &= ~CLIENT_HIGHLIGHT;
cc->highlight = 0;
client_draw_border(cc);
}
@ -235,7 +273,7 @@ group_hidetoggle(struct screen_ctx *sc, int idx)
struct group_ctx *gc;
if (idx < 0 || idx >= CALMWM_NGROUPS)
errx(1, "group_hidetoggle: index out of range (%d)", idx);
err(1, "group_hidetoggle: index out of range (%d)", idx);
gc = &sc->groups[idx];
group_fix_hidden_state(gc);
@ -244,7 +282,7 @@ group_hidetoggle(struct screen_ctx *sc, int idx)
group_show(sc, gc);
else {
group_hide(sc, gc);
/* make clients stick to empty group */
/* XXX wtf? */
if (TAILQ_EMPTY(&gc->clients))
group_setactive(sc, idx);
}
@ -253,16 +291,16 @@ group_hidetoggle(struct screen_ctx *sc, int idx)
void
group_only(struct screen_ctx *sc, int idx)
{
struct group_ctx *gc;
int i;
if (idx < 0 || idx >= CALMWM_NGROUPS)
errx(1, "group_only: index out of range (%d)", idx);
err(1, "group_only: index out of range (%d)", idx);
TAILQ_FOREACH(gc, &sc->groupq, entry) {
if (gc->shortcut == idx)
group_show(sc, gc);
for (i = 0; i < CALMWM_NGROUPS; i++) {
if (i == idx)
group_show(sc, &sc->groups[i]);
else
group_hide(sc, gc);
group_hide(sc, &sc->groups[i]);
}
}
@ -270,7 +308,7 @@ group_only(struct screen_ctx *sc, int idx)
* Cycle through active groups. If none exist, then just stay put.
*/
void
group_cycle(struct screen_ctx *sc, int flags)
group_cycle(struct screen_ctx *sc, int reverse)
{
struct group_ctx *gc, *showgroup = NULL;
@ -278,11 +316,11 @@ group_cycle(struct screen_ctx *sc, int flags)
gc = sc->group_active;
for (;;) {
gc = (flags & CWM_RCYCLE) ? TAILQ_PREV(gc, group_ctx_q,
entry) : TAILQ_NEXT(gc, entry);
gc = reverse ? TAILQ_PREV(gc, group_ctx_q, entry) :
TAILQ_NEXT(gc, entry);
if (gc == NULL)
gc = (flags & CWM_RCYCLE) ? TAILQ_LAST(&sc->groupq,
group_ctx_q) : TAILQ_FIRST(&sc->groupq);
gc = reverse ? TAILQ_LAST(&sc->groupq, group_ctx_q) :
TAILQ_FIRST(&sc->groupq);
if (gc == sc->group_active)
break;
@ -300,50 +338,81 @@ group_cycle(struct screen_ctx *sc, int flags)
if (showgroup->hidden)
group_show(sc, showgroup);
else
group_setactive(sc, showgroup->shortcut);
group_setactive(sc, showgroup->shortcut - 1);
}
/* called when a client is deleted */
void
group_client_delete(struct client_ctx *cc)
{
if (cc->group == NULL)
return;
TAILQ_REMOVE(&cc->group->clients, cc, group_entry);
cc->group = NULL; /* he he */
}
void
group_menu(struct screen_ctx *sc)
group_menu(XButtonEvent *e)
{
struct screen_ctx *sc;
struct group_ctx *gc;
struct menu *mi;
struct menu_q menuq;
int i;
sc = screen_fromroot(e->root);
TAILQ_INIT(&menuq);
TAILQ_FOREACH(gc, &sc->groupq, entry) {
for (i = 0; i < CALMWM_NGROUPS; i++) {
gc = &sc->groups[i];
if (TAILQ_EMPTY(&gc->clients))
continue;
menuq_add(&menuq, gc, gc->hidden ? "%d: [%s]" : "%d: %s",
gc->shortcut, sc->group_names[gc->shortcut]);
mi = xcalloc(1, sizeof(*mi));
if (gc->hidden)
snprintf(mi->text, sizeof(mi->text), "%d: [%s]",
gc->shortcut, sc->group_names[i]);
else
snprintf(mi->text, sizeof(mi->text), "%d: %s",
gc->shortcut, sc->group_names[i]);
mi->ctx = gc;
TAILQ_INSERT_TAIL(&menuq, mi, entry);
}
if (TAILQ_EMPTY(&menuq))
return;
mi = menu_filter(sc, &menuq, NULL, NULL, 0, NULL, NULL);
if (mi != NULL && mi->ctx != NULL) {
gc = (struct group_ctx *)mi->ctx;
(gc->hidden) ? group_show(sc, gc) : group_hide(sc, gc);
}
menuq_clear(&menuq);
if (mi == NULL || mi->ctx == NULL)
goto cleanup;
gc = (struct group_ctx *)mi->ctx;
(gc->hidden) ? group_show(sc, gc) : group_hide(sc, gc);
cleanup:
while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
TAILQ_REMOVE(&menuq, mi, entry);
xfree(mi);
}
}
void
group_alltoggle(struct screen_ctx *sc)
{
struct group_ctx *gc;
int i;
TAILQ_FOREACH(gc, &sc->groupq, entry) {
for (i = 0; i < CALMWM_NGROUPS; i++) {
if (sc->group_hideall)
group_show(sc, gc);
group_show(sc, &sc->groups[i]);
else
group_hide(sc, gc);
group_hide(sc, &sc->groups[i]);
}
sc->group_hideall = !sc->group_hideall;
sc->group_hideall = (!sc->group_hideall);
}
void
@ -352,45 +421,45 @@ group_autogroup(struct client_ctx *cc)
struct screen_ctx *sc = cc->sc;
struct autogroupwin *aw;
struct group_ctx *gc;
int no = -1, both_match = 0;
int no = -1;
long *grpno;
if (cc->ch.res_class == NULL || cc->ch.res_name == NULL)
if (cc->app_class == NULL || cc->app_name == NULL)
return;
if (xu_getprop(cc->win, ewmh[_NET_WM_DESKTOP],
XA_CARDINAL, 1, (unsigned char **)&grpno) > 0) {
if (*grpno == -1)
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;
no = *grpno + 1;
XFree(grpno);
} else {
TAILQ_FOREACH(aw, &Conf.autogroupq, entry) {
if (strcmp(aw->class, cc->ch.res_class) == 0) {
if ((aw->name != NULL) &&
(strcmp(aw->name, cc->ch.res_name) == 0)) {
no = aw->num;
both_match = 1;
} else if (aw->name == NULL && !both_match)
no = aw->num;
if (strcmp(aw->class, cc->app_class) == 0 &&
(aw->name == NULL ||
strcmp(aw->name, cc->app_name) == 0)) {
no = aw->num;
break;
}
}
}
/* no group please */
if (no == 0)
return;
TAILQ_FOREACH(gc, &sc->groupq, entry) {
if (gc->shortcut == no) {
group_assign(gc, cc);
group_add(gc, cc);
return;
}
}
if (Conf.flags & CONF_STICKY_GROUPS)
group_assign(sc->group_active, cc);
else
group_assign(NULL, cc);
group_add(sc->group_active, cc);
}
void
@ -398,21 +467,27 @@ group_update_names(struct screen_ctx *sc)
{
char **strings, *p;
unsigned char *prop_ret;
int i = 0, j = 0, nstrings = 0, n = 0, setnames = 0;
if ((j = xu_getprop(sc->rootwin, ewmh[_NET_DESKTOP_NAMES],
cwmh[UTF8_STRING], 0xffffff, (unsigned char **)&prop_ret)) > 0) {
prop_ret[j - 1] = '\0'; /* paranoia */
while (i < j) {
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 = xcalloc((nstrings < CALMWM_NGROUPS ? CALMWM_NGROUPS :
nstrings), sizeof(*strings));
strings = xmalloc((nstrings < CALMWM_NGROUPS ? CALMWM_NGROUPS :
nstrings) * sizeof(*strings));
p = (char *)prop_ret;
i = n = 0;
p = prop_ret;
while (n < nstrings) {
strings[n++] = xstrdup(p);
p += strlen(p) + 1;
@ -423,7 +498,7 @@ group_update_names(struct screen_ctx *sc)
*/
if (n < CALMWM_NGROUPS) {
setnames = 1;
i = 0;
i = 1;
while (n < CALMWM_NGROUPS)
strings[n++] = xstrdup(shortcut_to_name[i++]);
}
@ -442,7 +517,7 @@ group_update_names(struct screen_ctx *sc)
static void
group_set_names(struct screen_ctx *sc)
{
char *p, *q;
unsigned char *p, *q;
size_t len = 0, tlen, slen;
int i;
@ -453,10 +528,11 @@ group_set_names(struct screen_ctx *sc)
tlen = len;
for (i = 0; i < sc->group_nonames; i++) {
slen = strlen(sc->group_names[i]) + 1;
(void)strlcpy(q, sc->group_names[i], tlen);
strlcpy(q, sc->group_names[i], tlen);
tlen -= slen;
q += slen;
}
xu_ewmh_net_desktop_names(sc, p, len);
XChangeProperty(X_Dpy, sc->rootwin, _NET_DESKTOP_NAMES,
UTF8_STRING, 8, PropModeReplace, p, len);
}

117
input.c Normal file
View File

@ -0,0 +1,117 @@
/*
* 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 <sys/param.h>
#include <sys/queue.h>
#include <err.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "calmwm.h"
int
input_keycodetrans(KeyCode kc, u_int state, enum ctltype *ctl, char *chr)
{
int ks;
*ctl = CTL_NONE;
*chr = '\0';
ks = XKeycodeToKeysym(X_Dpy, kc, (state & ShiftMask) ? 1 : 0);
/* Look for control characters. */
switch (ks) {
case XK_BackSpace:
*ctl = CTL_ERASEONE;
break;
case XK_Return:
*ctl = CTL_RETURN;
break;
case XK_Up:
*ctl = CTL_UP;
break;
case XK_Down:
*ctl = CTL_DOWN;
break;
case XK_Escape:
*ctl = CTL_ABORT;
break;
}
if (*ctl == CTL_NONE && (state & ControlMask)) {
switch (ks) {
case XK_s:
case XK_S:
/* Emacs "next" */
*ctl = CTL_DOWN;
break;
case XK_r:
case XK_R:
/* Emacs "previous" */
*ctl = CTL_UP;
break;
case XK_u:
case XK_U:
*ctl = CTL_WIPE;
break;
case XK_h:
case XK_H:
*ctl = CTL_ERASEONE;
break;
case XK_a:
case XK_A:
*ctl = CTL_ALL;
break;
}
}
if (*ctl == CTL_NONE && (state & Mod1Mask)) {
switch (ks) {
case XK_j:
case XK_J:
/* Vi "down" */
*ctl = CTL_DOWN;
break;
case XK_k:
case XK_K:
/* Vi "up" */
*ctl = CTL_UP;
break;
}
}
if (*ctl != CTL_NONE)
return (0);
/*
* For regular characters, only (part of, actually) Latin 1
* for now.
*/
if (ks < 0x20 || ks > 0x07e)
return (-1);
*chr = (char)ks;
return (0);
}

286
kbfunc.c
View File

@ -1,7 +1,7 @@
/*
* calmwm - the calm window manager
* calmwm - the calm window manager
*
* Copyright (c) 2004 Martin Murray <mmurray@monkey.org>
* Copyright (c) 2004 Martin Murray <mmurray@monkey.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -15,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $OpenBSD$
* $Id$
*/
#include <sys/param.h>
@ -25,22 +25,21 @@
#include <err.h>
#include <errno.h>
#include <paths.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "calmwm.h"
#define KNOWN_HOSTS ".ssh/known_hosts"
#define HASH_MARKER "|1|"
extern sig_atomic_t cwm_status;
extern int _xev_quit;
void
kbfunc_client_lower(struct client_ctx *cc, union arg *arg)
{
client_ptrsave(cc);
client_lower(cc);
}
@ -50,19 +49,16 @@ kbfunc_client_raise(struct client_ctx *cc, union arg *arg)
client_raise(cc);
}
#define TYPEMASK (CWM_MOVE | CWM_RESIZE | CWM_PTRMOVE)
#define MOVEMASK (CWM_UP | CWM_DOWN | CWM_LEFT | CWM_RIGHT)
#define typemask (CWM_MOVE | CWM_RESIZE | CWM_PTRMOVE)
#define movemask (CWM_UP | CWM_DOWN | CWM_LEFT | CWM_RIGHT)
void
kbfunc_client_moveresize(struct client_ctx *cc, union arg *arg)
kbfunc_moveresize(struct client_ctx *cc, union arg *arg)
{
struct screen_ctx *sc = cc->sc;
struct geom xine;
struct screen_ctx *sc;
int x, y, flags, amt;
unsigned int mx, my;
if (cc->flags & CLIENT_FREEZE)
return;
u_int mx, my;
sc = cc->sc;
mx = my = 0;
flags = arg->i;
@ -73,7 +69,7 @@ kbfunc_client_moveresize(struct client_ctx *cc, union arg *arg)
amt = amt * 10;
}
switch (flags & MOVEMASK) {
switch (flags & movemask) {
case CWM_UP:
my -= amt;
break;
@ -87,53 +83,49 @@ kbfunc_client_moveresize(struct client_ctx *cc, union arg *arg)
mx -= amt;
break;
}
switch (flags & TYPEMASK) {
switch (flags & typemask) {
case CWM_MOVE:
cc->geom.x += mx;
if (cc->geom.x + cc->geom.w < 0)
cc->geom.x = -cc->geom.w;
if (cc->geom.x > sc->view.w - 1)
cc->geom.x = sc->view.w - 1;
cc->geom.y += my;
if (cc->geom.y + cc->geom.h < 0)
cc->geom.y = -cc->geom.h;
if (cc->geom.y > sc->view.h - 1)
cc->geom.y = sc->view.h - 1;
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;
xine = screen_find_xinerama(sc,
cc->geom.x + cc->geom.w / 2,
cc->geom.y + cc->geom.h / 2, CWM_GAP);
cc->geom.x += client_snapcalc(cc->geom.x,
cc->geom.x + cc->geom.w + (cc->bwidth * 2),
xine.x, xine.x + xine.w, sc->snapdist);
cc->geom.y += client_snapcalc(cc->geom.y,
cc->geom.y + cc->geom.h + (cc->bwidth * 2),
xine.y, xine.y + xine.h, sc->snapdist);
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.x = x + mx;
cc->ptr.y = y + my;
cc->ptr.x = x + mx;
client_ptrwarp(cc);
break;
case CWM_RESIZE:
if ((cc->geom.w += mx) < 1)
cc->geom.w = 1;
if ((cc->geom.h += my) < 1)
cc->geom.h = 1;
client_resize(cc, 1);
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.w)
cc->ptr.x = cc->geom.w - cc->bwidth;
if (cc->ptr.y > cc->geom.h)
cc->ptr.y = cc->geom.h - cc->bwidth;
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:
xu_ptr_getpos(sc->rootwin, &x, &y);
xu_ptr_setpos(sc->rootwin, x + mx, y + my);
if (cc) {
xu_ptr_getpos(cc->win, &x, &y);
xu_ptr_setpos(cc->win, x + mx, y + my);
} else {
xu_ptr_getpos(sc->rootwin, &x, &y);
xu_ptr_setpos(sc->rootwin, x + mx, y + my);
}
break;
default:
warnx("invalid flags passed to kbfunc_client_moveresize");
@ -143,16 +135,22 @@ kbfunc_client_moveresize(struct client_ctx *cc, union arg *arg)
void
kbfunc_client_search(struct client_ctx *cc, union arg *arg)
{
struct screen_ctx *sc = cc->sc;
struct screen_ctx *sc;
struct client_ctx *old_cc;
struct menu *mi;
struct menu_q menuq;
sc = cc->sc;
old_cc = client_current();
TAILQ_INIT(&menuq);
TAILQ_FOREACH(cc, &Clientq, entry)
menuq_add(&menuq, cc, "%s", cc->name);
TAILQ_FOREACH(cc, &Clientq, entry) {
mi = xcalloc(1, sizeof(*mi));
strlcpy(mi->text, cc->name, sizeof(mi->text));
mi->ctx = cc;
TAILQ_INSERT_TAIL(&menuq, mi, entry);
}
if ((mi = menu_filter(sc, &menuq, "window", NULL, 0,
search_match_client, search_print_client)) != NULL) {
@ -165,32 +163,46 @@ kbfunc_client_search(struct client_ctx *cc, union arg *arg)
client_ptrwarp(cc);
}
menuq_clear(&menuq);
while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
TAILQ_REMOVE(&menuq, mi, entry);
xfree(mi);
}
}
void
kbfunc_menu_cmd(struct client_ctx *cc, union arg *arg)
kbfunc_menu_search(struct client_ctx *cc, union arg *arg)
{
struct screen_ctx *sc = cc->sc;
struct screen_ctx *sc;
struct cmd *cmd;
struct menu *mi;
struct menu_q menuq;
sc = cc->sc;
TAILQ_INIT(&menuq);
TAILQ_FOREACH(cmd, &Conf.cmdq, entry)
menuq_add(&menuq, cmd, "%s", cmd->name);
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 ((mi = menu_filter(sc, &menuq, "application", NULL, 0,
search_match_text, NULL)) != NULL)
u_spawn(((struct cmd *)mi->ctx)->path);
u_spawn(((struct cmd *)mi->ctx)->image);
menuq_clear(&menuq);
while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
TAILQ_REMOVE(&menuq, mi, entry);
xfree(mi);
}
}
void
kbfunc_client_cycle(struct client_ctx *cc, union arg *arg)
{
struct screen_ctx *sc = cc->sc;
struct screen_ctx *sc;
sc = cc->sc;
/* XXX for X apps that ignore events */
XGrabKeyboard(X_Dpy, sc->rootwin, True,
@ -227,26 +239,26 @@ void
kbfunc_exec(struct client_ctx *cc, union arg *arg)
{
#define NPATHS 256
struct screen_ctx *sc = cc->sc;
char **ap, *paths[NPATHS], *path, *pathcpy;
struct screen_ctx *sc;
char **ap, *paths[NPATHS], *path, *pathcpy, *label;
char tpath[MAXPATHLEN];
const char *label;
DIR *dirp;
struct dirent *dp;
struct menu *mi;
struct menu_q menuq;
int l, i, cmd = arg->i;
sc = cc->sc;
switch (cmd) {
case CWM_EXEC_PROGRAM:
label = "exec";
break;
case CWM_EXEC_WM:
label = "wm";
break;
default:
errx(1, "kbfunc_exec: invalid cmd %d", cmd);
/*NOTREACHED*/
case CWM_EXEC_PROGRAM:
label = "exec";
break;
case CWM_EXEC_WM:
label = "wm";
break;
default:
err(1, "kbfunc_exec: invalid cmd %d", cmd);
/*NOTREACHED*/
}
TAILQ_INIT(&menuq);
@ -269,63 +281,74 @@ kbfunc_exec(struct client_ctx *cc, union arg *arg)
/* skip everything but regular files and symlinks */
if (dp->d_type != DT_REG && dp->d_type != DT_LNK)
continue;
(void)memset(tpath, '\0', sizeof(tpath));
memset(tpath, '\0', sizeof(tpath));
l = snprintf(tpath, sizeof(tpath), "%s/%s", paths[i],
dp->d_name);
/* check for truncation etc */
if (l == -1 || l >= (int)sizeof(tpath))
continue;
if (access(tpath, X_OK) == 0)
menuq_add(&menuq, NULL, "%s", dp->d_name);
if (access(tpath, X_OK) == 0) {
mi = xcalloc(1, sizeof(*mi));
strlcpy(mi->text, dp->d_name, sizeof(mi->text));
TAILQ_INSERT_TAIL(&menuq, mi, entry);
}
}
(void)closedir(dirp);
}
free(path);
xfree(path);
if ((mi = menu_filter(sc, &menuq, label, NULL,
CWM_MENU_DUMMY | CWM_MENU_FILE,
search_match_exec_path, NULL)) != NULL) {
if ((mi = menu_filter(sc, &menuq, label, NULL, 1,
search_match_exec, NULL)) != NULL) {
if (mi->text[0] == '\0')
goto out;
switch (cmd) {
case CWM_EXEC_PROGRAM:
u_spawn(mi->text);
break;
case CWM_EXEC_WM:
u_exec(mi->text);
warn("%s", mi->text);
break;
default:
errx(1, "kb_func: egad, cmd changed value!");
break;
case CWM_EXEC_PROGRAM:
u_spawn(mi->text);
break;
case CWM_EXEC_WM:
u_exec(mi->text);
warn("%s", mi->text);
break;
default:
err(1, "kb_func: egad, cmd changed value!");
break;
}
}
out:
if (mi != NULL && mi->dummy)
free(mi);
menuq_clear(&menuq);
xfree(mi);
while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
TAILQ_REMOVE(&menuq, mi, entry);
xfree(mi);
}
}
void
kbfunc_ssh(struct client_ctx *cc, union arg *arg)
{
struct screen_ctx *sc = cc->sc;
struct screen_ctx *sc;
struct menu *mi;
struct menu_q menuq;
FILE *fp;
char *buf, *lbuf, *p;
char hostbuf[MAXHOSTNAMELEN];
char *buf, *lbuf, *p, *home;
char hostbuf[MAXHOSTNAMELEN], filename[MAXPATHLEN];
char cmd[256];
int l;
size_t len;
if ((fp = fopen(Conf.known_hosts, "r")) == NULL) {
warn("kbfunc_ssh: %s", Conf.known_hosts);
sc = cc->sc;
if ((home = getenv("HOME")) == NULL)
return;
l = snprintf(filename, sizeof(filename), "%s/%s", home, KNOWN_HOSTS);
if (l == -1 || l >= sizeof(filename))
return;
if ((fp = fopen(filename, "r")) == NULL)
return;
}
TAILQ_INIT(&menuq);
lbuf = NULL;
while ((buf = fgetln(fp, &len))) {
if (buf[len - 1] == '\n')
@ -333,7 +356,7 @@ kbfunc_ssh(struct client_ctx *cc, union arg *arg)
else {
/* EOF without EOL, copy and add the NUL */
lbuf = xmalloc(len + 1);
(void)memcpy(lbuf, buf, len);
memcpy(lbuf, buf, len);
lbuf[len] = '\0';
buf = lbuf;
}
@ -346,25 +369,30 @@ kbfunc_ssh(struct client_ctx *cc, union arg *arg)
/* ignore badness */
if (p - buf + 1 > sizeof(hostbuf))
continue;
(void)strlcpy(hostbuf, buf, p - buf + 1);
menuq_add(&menuq, NULL, hostbuf);
(void) strlcpy(hostbuf, buf, p - buf + 1);
mi = xcalloc(1, sizeof(*mi));
(void) strlcpy(mi->text, hostbuf, sizeof(mi->text));
TAILQ_INSERT_TAIL(&menuq, mi, entry);
}
free(lbuf);
(void)fclose(fp);
xfree(lbuf);
fclose(fp);
if ((mi = menu_filter(sc, &menuq, "ssh", NULL, CWM_MENU_DUMMY,
if ((mi = menu_filter(sc, &menuq, "ssh", NULL, 1,
search_match_exec, NULL)) != NULL) {
if (mi->text[0] == '\0')
goto out;
l = snprintf(cmd, sizeof(cmd), "%s -T '[ssh] %s' -e ssh %s",
Conf.termpath, mi->text, mi->text);
l = snprintf(cmd, sizeof(cmd), "%s -e ssh %s", Conf.termpath,
mi->text);
if (l != -1 && l < sizeof(cmd))
u_spawn(cmd);
}
out:
if (mi != NULL && mi->dummy)
free(mi);
menuq_clear(&menuq);
xfree(mi);
while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
TAILQ_REMOVE(&menuq, mi, entry);
xfree(mi);
}
}
void
@ -376,14 +404,15 @@ kbfunc_client_label(struct client_ctx *cc, union arg *arg)
TAILQ_INIT(&menuq);
/* dummy is set, so this will always return */
mi = menu_filter(cc->sc, &menuq, "label", cc->label, CWM_MENU_DUMMY,
mi = menu_filter(cc->sc, &menuq, "label", cc->label, 1,
search_match_text, NULL);
if (!mi->abort) {
free(cc->label);
if (cc->label != NULL)
xfree(cc->label);
cc->label = xstrdup(mi->text);
}
free(mi);
xfree(mi);
}
void
@ -395,13 +424,13 @@ kbfunc_client_delete(struct client_ctx *cc, union arg *arg)
void
kbfunc_client_group(struct client_ctx *cc, union arg *arg)
{
group_hidetoggle(cc->sc, arg->i);
group_hidetoggle(cc->sc, KBTOGROUP(arg->i));
}
void
kbfunc_client_grouponly(struct client_ctx *cc, union arg *arg)
{
group_only(cc->sc, arg->i);
group_only(cc->sc, KBTOGROUP(arg->i));
}
void
@ -429,13 +458,7 @@ kbfunc_client_grouptoggle(struct client_ctx *cc, union arg *arg)
void
kbfunc_client_movetogroup(struct client_ctx *cc, union arg *arg)
{
group_movetogroup(cc, arg->i);
}
void
kbfunc_client_fullscreen(struct client_ctx *cc, union arg *arg)
{
client_fullscreen(cc);
group_movetogroup(cc, KBTOGROUP(arg->i));
}
void
@ -447,36 +470,23 @@ kbfunc_client_maximize(struct client_ctx *cc, union arg *arg)
void
kbfunc_client_vmaximize(struct client_ctx *cc, union arg *arg)
{
client_vmaximize(cc);
client_vertmaximize(cc);
}
void
kbfunc_client_hmaximize(struct client_ctx *cc, union arg *arg)
{
client_hmaximize(cc);
client_horizmaximize(cc);
}
void
kbfunc_client_freeze(struct client_ctx *cc, union arg *arg)
kbfunc_quit_wm(struct client_ctx *cc, union arg *arg)
{
client_freeze(cc);
_xev_quit = 1;
}
void
kbfunc_cwm_status(struct client_ctx *cc, union arg *arg)
kbfunc_reload(struct client_ctx *cc, union arg *arg)
{
cwm_status = arg->i;
}
void
kbfunc_tile(struct client_ctx *cc, union arg *arg)
{
switch (arg->i) {
case CWM_TILE_HORIZ:
client_htile(cc);
break;
case CWM_TILE_VERT:
client_vtile(cc);
break;
}
conf_reload(&Conf);
}

447
menu.c
View File

@ -1,6 +1,4 @@
/*
* calmwm - the calm window manager
*
* Copyright (c) 2008 Owain G. Ainsworth <oga@openbsd.org>
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
*
@ -15,35 +13,24 @@
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $OpenBSD$
*/
#include <sys/param.h>
#include <sys/queue.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "calmwm.h"
#define PROMPT_SCHAR "\xc2\xbb"
#define PROMPT_ECHAR "\xc2\xab"
enum ctltype {
CTL_NONE = -1,
CTL_ERASEONE = 0, CTL_WIPE, CTL_UP, CTL_DOWN, CTL_RETURN,
CTL_TAB, CTL_ABORT, CTL_ALL
};
#define PROMPT_SCHAR '<27>'
#define PROMPT_ECHAR '<27>'
struct menu_ctx {
struct screen_ctx *sc;
char searchstr[MENU_MAXENTRY + 1];
char dispstr[MENU_MAXENTRY*2 + 1];
char promptstr[MENU_MAXENTRY + 1];
@ -54,32 +41,45 @@ struct menu_ctx {
int noresult;
int prev;
int entry;
int height;
int width;
int num;
int flags;
int x;
int y;
void (*match)(struct menu_q *, struct menu_q *, char *);
void (*print)(struct menu *, int);
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 menu_q *);
struct screen_ctx *);
static struct menu *menu_handle_release(XEvent *, struct menu_ctx *,
struct menu_q *);
static void menu_draw(struct menu_ctx *, struct menu_q *,
struct menu_q *);
static void menu_draw_entry(struct menu_ctx *, struct menu_q *,
struct screen_ctx *, struct menu_q *);
static void menu_draw(struct screen_ctx *, struct menu_ctx *,
struct menu_q *, struct menu_q *);
static int menu_calc_entry(struct screen_ctx *, struct menu_ctx *,
int, int);
static int menu_calc_entry(struct menu_ctx *, int, int);
static struct menu *menu_complete_path(struct menu_ctx *);
static int menu_keycode(XKeyEvent *, enum ctltype *, char *);
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, const char *prompt,
const char *initial, int flags,
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))
{
@ -89,30 +89,29 @@ menu_filter(struct screen_ctx *sc, struct menu_q *menuq, const char *prompt,
XEvent e;
Window focuswin;
int evmask, focusrevert;
int xsave, ysave, xcur, ycur;
TAILQ_INIT(&resultq);
(void)memset(&mc, 0, sizeof(mc));
bzero(&mc, sizeof(mc));
xu_ptr_getpos(sc->rootwin, &mc.x, &mc.y);
xsave = mc.x;
ysave = mc.y;
mc.sc = sc;
mc.flags = flags;
if (prompt != NULL) {
evmask = MENUMASK | KEYMASK; /* accept keys as well */
(void)strlcpy(mc.promptstr, prompt, sizeof(mc.promptstr));
mc.hasprompt = 1;
} else {
evmask = MENUMASK;
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)
(void)strlcpy(mc.searchstr, initial, sizeof(mc.searchstr));
strlcpy(mc.searchstr, initial, sizeof(mc.searchstr));
else
mc.searchstr[0] = '\0';
@ -120,11 +119,12 @@ menu_filter(struct screen_ctx *sc, struct menu_q *menuq, const char *prompt,
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,
Conf.cursor[CF_QUESTION]) < 0) {
if (xu_ptr_grab(sc->menuwin, MenuGrabMask, Cursor_question) < 0) {
XUnmapWindow(X_Dpy, sc->menuwin);
return (NULL);
}
@ -142,99 +142,57 @@ menu_filter(struct screen_ctx *sc, struct menu_q *menuq, const char *prompt,
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(&mc, menuq, &resultq);
menu_draw(sc, &mc, menuq, &resultq);
break;
case MotionNotify:
menu_handle_move(&e, &mc, &resultq);
menu_handle_move(&e, &mc, sc);
break;
case ButtonRelease:
if ((mi = menu_handle_release(&e, &mc, &resultq))
if ((mi = menu_handle_release(&e, &mc, sc, &resultq))
!= NULL)
goto out;
break;
default:
break;
}
}
out:
if ((mc.flags & CWM_MENU_DUMMY) == 0 && mi->dummy) {
/* no mouse based match */
free(mi);
if (dummy == 0 && mi->dummy) { /* no match */
xfree (mi);
mi = NULL;
xu_ptr_ungrab();
XSetInputFocus(X_Dpy, focuswin, focusrevert, CurrentTime);
}
XSetInputFocus(X_Dpy, focuswin, focusrevert, CurrentTime);
/* restore if user didn't move */
xu_ptr_getpos(sc->rootwin, &xcur, &ycur);
if (xcur == mc.x && ycur == mc.y)
xu_ptr_setpos(sc->rootwin, xsave, ysave);
xu_ptr_ungrab();
XMoveResizeWindow(X_Dpy, sc->menuwin, 0, 0, 1, 1);
XUnmapWindow(X_Dpy, sc->menuwin);
XUngrabKeyboard(X_Dpy, CurrentTime);
return (mi);
}
static struct menu *
menu_complete_path(struct menu_ctx *mc)
{
struct menu *mi, *mr;
struct menu_q menuq;
char *path = NULL;
path = xcalloc(1, sizeof(mr->text));
mr = xcalloc(1, sizeof(*mr));
TAILQ_INIT(&menuq);
if ((mi = menu_filter(mc->sc, &menuq, mc->searchstr, NULL,
CWM_MENU_DUMMY, search_match_path_any, NULL)) != NULL) {
mr->abort = mi->abort;
mr->dummy = mi->dummy;
strlcpy(path, mi->text, sizeof(mi->text));
}
menuq_clear(&menuq);
if (path[0] != '\0')
snprintf(mr->text, sizeof(mr->text), "%s \"%s\"",
mc->searchstr, path);
else if (!mr->abort)
strlcpy(mr->text, mc->searchstr, sizeof(mr->text));
free(path);
return (mr);
}
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[32];
char chr;
size_t len;
int clen, i;
wchar_t wc;
if (menu_keycode(&e->xkey, &ctl, chr) < 0)
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) {
clen = 1;
while (mbtowc(&wc, &mc->searchstr[len-clen], MB_CUR_MAX) == -1)
clen++;
for (i = 1; i <= clen; i++)
mc->searchstr[len - i] = '\0';
mc->searchstr[len - 1] = '\0';
mc->changed = 1;
}
break;
@ -271,33 +229,6 @@ menu_handle_key(XEvent *e, struct menu_ctx *mc, struct menu_q *menuq,
mc->searchstr[0] = '\0';
mc->changed = 1;
break;
case CTL_TAB:
if ((mi = TAILQ_FIRST(resultq)) != NULL) {
/*
* - We are in exec_path menu mode
* - It is equal to the input
* We got a command, launch the file menu
*/
if ((mc->flags & CWM_MENU_FILE) &&
(strncmp(mc->searchstr, mi->text,
strlen(mi->text))) == 0)
return (menu_complete_path(mc));
/*
* Put common prefix of the results into searchstr
*/
(void)strlcpy(mc->searchstr,
mi->text, sizeof(mc->searchstr));
while ((mi = TAILQ_NEXT(mi, resultentry)) != NULL) {
i = 0;
while (tolower(mc->searchstr[i]) ==
tolower(mi->text[i]))
i++;
mc->searchstr[i] = '\0';
}
mc->changed = 1;
}
break;
case CTL_ALL:
mc->list = !mc->list;
break;
@ -311,9 +242,13 @@ menu_handle_key(XEvent *e, struct menu_ctx *mc, struct menu_q *menuq,
break;
}
if (chr[0] != '\0') {
if (chr != '\0') {
char str[2];
str[0] = chr;
str[1] = '\0';
mc->changed = 1;
(void)strlcat(mc->searchstr, chr, sizeof(mc->searchstr));
strlcat(mc->searchstr, str, sizeof(mc->searchstr));
}
mc->noresult = 0;
@ -333,12 +268,11 @@ menu_handle_key(XEvent *e, struct menu_ctx *mc, struct menu_q *menuq,
}
static void
menu_draw(struct menu_ctx *mc, struct menu_q *menuq, struct menu_q *resultq)
menu_draw(struct screen_ctx *sc, struct menu_ctx *mc, struct menu_q *menuq,
struct menu_q *resultq)
{
struct screen_ctx *sc = mc->sc;
struct menu *mi;
struct geom xine;
int n, xsave, ysave;
struct menu *mi;
int n, dy, xsave, ysave;
if (mc->list) {
if (TAILQ_EMPTY(resultq) && mc->list) {
@ -354,13 +288,12 @@ menu_draw(struct menu_ctx *mc, struct menu_q *menuq, struct menu_q *resultq)
mc->num = 0;
mc->width = 0;
mc->height = 0;
dy = 0;
if (mc->hasprompt) {
(void)snprintf(mc->dispstr, sizeof(mc->dispstr), "%s%s%s%s",
mc->promptstr, PROMPT_SCHAR, mc->searchstr, PROMPT_ECHAR);
mc->width = xu_xft_width(sc->xftfont, mc->dispstr,
strlen(mc->dispstr));
mc->height = sc->xftfont->height + 1;
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;
}
@ -375,43 +308,34 @@ menu_draw(struct menu_ctx *mc, struct menu_q *menuq, struct menu_q *resultq)
text = mi->text;
}
mc->width = MAX(mc->width, xu_xft_width(sc->xftfont, text,
mc->width = MAX(mc->width, font_width(sc, text,
MIN(strlen(text), MENU_MAXENTRY)));
mc->height += sc->xftfont->height + 1;
dy += font_height(sc);
mc->num++;
}
xine = screen_find_xinerama(sc, mc->x, mc->y, CWM_GAP);
xine.w += xine.x - Conf.bwidth * 2;
xine.h += xine.y - Conf.bwidth * 2;
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;
/* Never hide the top, or left side, of the menu. */
if (mc->x + mc->width >= xine.w)
mc->x = xine.w - mc->width;
if (mc->x < xine.x) {
mc->x = xine.x;
mc->width = MIN(mc->width, (xine.w - xine.x));
}
if (mc->y + mc->height >= xine.h)
mc->y = xine.h - mc->height;
if (mc->y < xine.y) {
mc->y = xine.y;
mc->height = MIN(mc->height, (xine.h - xine.y));
}
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, mc->height);
XMoveResizeWindow(X_Dpy, sc->menuwin, mc->x, mc->y, mc->width, dy);
if (mc->hasprompt) {
xu_xft_draw(sc, mc->dispstr, CWM_COLOR_MENU_FONT,
0, sc->xftfont->ascent);
font_draw(sc, mc->dispstr, strlen(mc->dispstr), sc->menuwin,
0, font_ascent(sc) + 1);
n = 1;
} else
n = 0;
@ -419,72 +343,47 @@ menu_draw(struct menu_ctx *mc, struct menu_q *menuq, struct menu_q *resultq)
TAILQ_FOREACH(mi, resultq, resultentry) {
char *text = mi->print[0] != '\0' ?
mi->print : mi->text;
int y = n * (sc->xftfont->height + 1) + sc->xftfont->ascent + 1;
/* Stop drawing when menu doesn't fit inside the screen. */
if (mc->y + y > xine.h)
break;
xu_xft_draw(sc, text, CWM_COLOR_MENU_FONT, 0, y);
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)
menu_draw_entry(mc, resultq, 1, 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_draw_entry(struct menu_ctx *mc, struct menu_q *resultq,
int entry, int active)
{
struct screen_ctx *sc = mc->sc;
struct menu *mi;
char *text;
int color, i = 0;
if (mc->hasprompt)
i = 1;
TAILQ_FOREACH(mi, resultq, resultentry)
if (entry == i++)
break;
if (mi == NULL)
return;
color = active ? CWM_COLOR_MENU_FG : CWM_COLOR_MENU_BG;
text = mi->print[0] != '\0' ? mi->print : mi->text;
XftDrawRect(sc->xftdraw, &sc->xftcolor[color], 0,
(sc->xftfont->height + 1) * entry, mc->width,
(sc->xftfont->height + 1) + sc->xftfont->descent);
color = active ? CWM_COLOR_MENU_FONT_SEL : CWM_COLOR_MENU_FONT;
xu_xft_draw(sc, text, color,
0, (sc->xftfont->height + 1) * entry + sc->xftfont->ascent + 1);
}
static void
menu_handle_move(XEvent *e, struct menu_ctx *mc, struct menu_q *resultq)
menu_handle_move(XEvent *e, struct menu_ctx *mc, struct screen_ctx *sc)
{
mc->prev = mc->entry;
mc->entry = menu_calc_entry(mc, e->xbutton.x, e->xbutton.y);
if (mc->prev == mc->entry)
return;
mc->entry = menu_calc_entry(sc, mc, e->xbutton.x, e->xbutton.y);
if (mc->prev != -1)
menu_draw_entry(mc, resultq, mc->prev, 0);
XFillRectangle(X_Dpy, sc->menuwin, sc->gc, 0,
font_height(sc) * mc->prev, mc->width, font_height(sc));
if (mc->entry != -1) {
(void)xu_ptr_regrab(MENUGRABMASK, Conf.cursor[CF_NORMAL]);
menu_draw_entry(mc, resultq, 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
(void)xu_ptr_regrab(MENUGRABMASK, Conf.cursor[CF_DEFAULT]);
xu_ptr_regrab(MenuGrabMask, Cursor_default);
}
static struct menu *
menu_handle_release(XEvent *e, struct menu_ctx *mc, struct menu_q *resultq)
menu_handle_release(XEvent *e, struct menu_ctx *mc, struct screen_ctx *sc,
struct menu_q *resultq)
{
struct menu *mi;
int entry, i = 0;
struct menu *mi;
int entry, i = 0;
entry = menu_calc_entry(mc, e->xbutton.x, e->xbutton.y);
entry = menu_calc_entry(sc, mc, e->xbutton.x, e->xbutton.y);
xu_ptr_ungrab();
if (mc->hasprompt)
i = 1;
@ -501,17 +400,15 @@ menu_handle_release(XEvent *e, struct menu_ctx *mc, struct menu_q *resultq)
}
static int
menu_calc_entry(struct menu_ctx *mc, int x, int y)
menu_calc_entry(struct screen_ctx *sc, struct menu_ctx *mc, int x, int y)
{
struct screen_ctx *sc = mc->sc;
int entry;
int entry;
entry = y / (sc->xftfont->height + 1);
entry = y / font_height(sc);
/* in bounds? */
if (x < 0 || x > mc->width || y < 0 ||
y > (sc->xftfont->height + 1) * mc->num ||
entry < 0 || entry >= mc->num)
if (x <= 0 || x > mc->width || y <= 0 ||
y > font_height(sc) * mc->num || entry < 0 || entry >= mc->num)
entry = -1;
if (mc->hasprompt && entry == 0)
@ -519,115 +416,3 @@ menu_calc_entry(struct menu_ctx *mc, int x, int y)
return (entry);
}
static int
menu_keycode(XKeyEvent *ev, enum ctltype *ctl, char *chr)
{
KeySym ks;
unsigned int state = ev->state;
*ctl = CTL_NONE;
chr[0] = '\0';
ks = XkbKeycodeToKeysym(X_Dpy, ev->keycode, 0,
(state & ShiftMask) ? 1 : 0);
/* Look for control characters. */
switch (ks) {
case XK_BackSpace:
*ctl = CTL_ERASEONE;
break;
case XK_Return:
*ctl = CTL_RETURN;
break;
case XK_Tab:
*ctl = CTL_TAB;
break;
case XK_Up:
*ctl = CTL_UP;
break;
case XK_Down:
*ctl = CTL_DOWN;
break;
case XK_Escape:
*ctl = CTL_ABORT;
break;
}
if (*ctl == CTL_NONE && (state & ControlMask)) {
switch (ks) {
case XK_s:
case XK_S:
/* Emacs "next" */
*ctl = CTL_DOWN;
break;
case XK_r:
case XK_R:
/* Emacs "previous" */
*ctl = CTL_UP;
break;
case XK_u:
case XK_U:
*ctl = CTL_WIPE;
break;
case XK_h:
case XK_H:
*ctl = CTL_ERASEONE;
break;
case XK_a:
case XK_A:
*ctl = CTL_ALL;
break;
}
}
if (*ctl == CTL_NONE && (state & Mod1Mask)) {
switch (ks) {
case XK_j:
case XK_J:
/* Vi "down" */
*ctl = CTL_DOWN;
break;
case XK_k:
case XK_K:
/* Vi "up" */
*ctl = CTL_UP;
break;
}
}
if (*ctl != CTL_NONE)
return (0);
if (XLookupString(ev, chr, 32, &ks, NULL) < 0)
return (-1);
return (0);
}
void
menuq_add(struct menu_q *mq, void *ctx, const char *fmt, ...)
{
va_list ap;
struct menu *mi;
mi = xcalloc(1, sizeof(*mi));
mi->ctx = ctx;
va_start(ap, fmt);
(void)vsnprintf(mi->text, sizeof(mi->text), fmt, ap);
va_end(ap);
TAILQ_INSERT_TAIL(mq, mi, entry);
}
void
menuq_clear(struct menu_q *mq)
{
struct menu *mi;
while ((mi = TAILQ_FIRST(mq)) != NULL) {
TAILQ_REMOVE(mq, mi, entry);
free(mi);
}
}

View File

@ -1,8 +1,8 @@
/*
* calmwm - the calm window manager
* calmwm - the calm window manager
*
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
* Copyright (c) 2008 rivo nurges <rix@estpak.ee>
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
* Copyright (c) 2008 rivo nurges <rix@estpak.ee>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -16,7 +16,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $OpenBSD$
* $Id$
*/
#include <sys/param.h>
@ -24,95 +24,111 @@
#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "calmwm.h"
static void mousefunc_sweep_calc(struct client_ctx *, int, int, int, int);
static int mousefunc_sweep_calc(struct client_ctx *, int, int, int, int);
static void mousefunc_sweep_draw(struct client_ctx *);
static void
static int
mousefunc_sweep_calc(struct client_ctx *cc, int x, int y, int mx, int my)
{
cc->geom.w = abs(x - mx) - cc->bwidth;
cc->geom.h = abs(y - my) - cc->bwidth;
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.w;
cc->geom.y = y <= my ? y : y - cc->geom.h;
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 s[14]; /* fits " nnnn x nnnn \0" */
char asize[10]; /* fits "nnnnxnnnn\0" */
int width, height, width_size, width_name;
(void)snprintf(s, sizeof(s), " %4d x %-4d ",
(cc->geom.w - cc->hint.basew) / cc->hint.incw,
(cc->geom.h - cc->hint.baseh) / cc->hint.inch);
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;
XReparentWindow(X_Dpy, sc->menuwin, cc->win, 0, 0);
XMoveResizeWindow(X_Dpy, sc->menuwin, 0, 0,
xu_xft_width(sc->xftfont, s, strlen(s)), sc->xftfont->height);
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);
xu_xft_draw(sc, s, CWM_COLOR_MENU_FONT, 0, sc->xftfont->ascent + 1);
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_client_resize(struct client_ctx *cc, union arg *arg)
mousefunc_window_resize(struct client_ctx *cc, void *arg)
{
XEvent ev;
Time ltime = 0;
Time time = 0;
struct screen_ctx *sc = cc->sc;
int x = cc->geom.x, y = cc->geom.y;
if (cc->flags & CLIENT_FREEZE)
return;
client_raise(cc);
client_ptrsave(cc);
if (xu_ptr_grab(cc->win, MOUSEMASK, Conf.cursor[CF_RESIZE]) < 0)
if (xu_ptr_grab(cc->win, MouseMask, Cursor_resize) < 0)
return;
xu_ptr_setpos(cc->win, cc->geom.w, cc->geom.h);
xu_ptr_setpos(cc->win, cc->geom.width, cc->geom.height);
mousefunc_sweep_draw(cc);
for (;;) {
XMaskEvent(X_Dpy, MOUSEMASK, &ev);
XMaskEvent(X_Dpy, MouseMask|ExposureMask, &ev);
switch (ev.type) {
case Expose:
client_draw_border(cc);
break;
case MotionNotify:
mousefunc_sweep_calc(cc, x, y,
ev.xmotion.x_root, ev.xmotion.y_root);
/* don't resize more than 60 times / second */
if ((ev.xmotion.time - ltime) > (1000 / 60)) {
ltime = ev.xmotion.time;
client_resize(cc, 1);
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 (ltime)
client_resize(cc, 1);
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.w)
cc->ptr.x = cc->geom.w - cc->bwidth;
if (cc->ptr.y > cc->geom.h)
cc->ptr.y = cc->geom.h - cc->bwidth;
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;
}
}
@ -120,51 +136,42 @@ mousefunc_client_resize(struct client_ctx *cc, union arg *arg)
}
void
mousefunc_client_move(struct client_ctx *cc, union arg *arg)
mousefunc_window_move(struct client_ctx *cc, void *arg)
{
XEvent ev;
Time ltime = 0;
struct screen_ctx *sc = cc->sc;
struct geom xine;
Time time = 0;
int px, py;
client_raise(cc);
if (cc->flags & CLIENT_FREEZE)
return;
if (xu_ptr_grab(cc->win, MOUSEMASK, Conf.cursor[CF_MOVE]) < 0)
if (xu_ptr_grab(cc->win, MouseMask, Cursor_move) < 0)
return;
xu_ptr_getpos(cc->win, &px, &py);
for (;;) {
XMaskEvent(X_Dpy, MOUSEMASK, &ev);
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->bwidth;
cc->geom.y = ev.xmotion.y_root - py - cc->bwidth;
cc->geom.x = ev.xmotion.x_root - px;
cc->geom.y = ev.xmotion.y_root - py;
xine = screen_find_xinerama(sc,
cc->geom.x + cc->geom.w / 2,
cc->geom.y + cc->geom.h / 2, CWM_GAP);
cc->geom.x += client_snapcalc(cc->geom.x,
cc->geom.x + cc->geom.w + (cc->bwidth * 2),
xine.x, xine.x + xine.w, sc->snapdist);
cc->geom.y += client_snapcalc(cc->geom.y,
cc->geom.y + cc->geom.h + (cc->bwidth * 2),
xine.y, xine.y + xine.h, sc->snapdist);
/* don't move more than 60 times / second */
if ((ev.xmotion.time - ltime) > (1000 / 60)) {
ltime = ev.xmotion.time;
/* 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 (ltime)
if (time) {
XSync(X_Dpy, False);
client_move(cc);
}
xu_ptr_ungrab();
return;
}
@ -173,26 +180,40 @@ mousefunc_client_move(struct client_ctx *cc, union arg *arg)
}
void
mousefunc_client_grouptoggle(struct client_ctx *cc, union arg *arg)
mousefunc_window_grouptoggle(struct client_ctx *cc, void *arg)
{
group_sticky_toggle_enter(cc);
}
void
mousefunc_menu_group(struct client_ctx *cc, union arg *arg)
mousefunc_window_lower(struct client_ctx *cc, void *arg)
{
group_menu(cc->sc);
client_ptrsave(cc);
client_lower(cc);
}
void
mousefunc_menu_unhide(struct client_ctx *cc, union arg *arg)
mousefunc_window_hide(struct client_ctx *cc, void *arg)
{
struct screen_ctx *sc = cc->sc;
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);
@ -202,44 +223,57 @@ mousefunc_menu_unhide(struct client_ctx *cc, union arg *arg)
if (wname == NULL)
continue;
menuq_add(&menuq, cc, "(%d) %s",
cc->group->shortcut, wname);
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;
if ((mi = menu_filter(sc, &menuq, NULL, NULL, 0,
NULL, NULL)) != NULL) {
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);
}
}
menuq_clear(&menuq);
}
void
mousefunc_menu_cmd(struct client_ctx *cc, union arg *arg)
mousefunc_menu_cmd(struct client_ctx *cc, void *arg)
{
struct screen_ctx *sc = cc->sc;
struct cmd *cmd;
struct screen_ctx *sc;
struct menu *mi;
struct menu_q menuq;
struct cmd *cmd;
sc = cc->sc;
TAILQ_INIT(&menuq);
TAILQ_FOREACH(cmd, &Conf.cmdq, entry)
menuq_add(&menuq, cmd, "%s", cmd->name);
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;
if ((mi = menu_filter(sc, &menuq, NULL, NULL, 0,
NULL, NULL)) != NULL)
u_spawn(((struct cmd *)mi->ctx)->path);
menuq_clear(&menuq);
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);
}
}

244
parse.y
View File

@ -42,17 +42,18 @@ static struct file {
char *name;
int lineno;
int errors;
} *file, *topfile;
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);
} *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;
@ -69,11 +70,9 @@ typedef struct {
%token FONTNAME STICKY GAP MOUSEBIND
%token AUTOGROUP BIND COMMAND IGNORE
%token YES NO BORDERWIDTH MOVEAMOUNT
%token COLOR SNAPDIST
%token ACTIVEBORDER INACTIVEBORDER URGENCYBORDER
%token COLOR
%token ACTIVEBORDER INACTIVEBORDER
%token GROUPBORDER UNGROUPBORDER
%token MENUBG MENUFG
%token FONTCOLOR FONTSELCOLOR
%token ERROR
%token <v.string> STRING
%token <v.number> NUMBER
@ -106,8 +105,8 @@ yesno : YES { $$ = 1; }
;
main : FONTNAME STRING {
free(conf->font);
conf->font = $2;
free(conf->DefaultFontName);
conf->DefaultFontName = $2;
}
| STICKY yesno {
if ($2 == 0)
@ -116,80 +115,48 @@ main : FONTNAME STRING {
conf->flags |= CONF_STICKY_GROUPS;
}
| BORDERWIDTH NUMBER {
if ($2 < 0 || $2 > UINT_MAX) {
yyerror("invalid borderwidth: %d", $2);
YYERROR;
}
conf->bwidth = $2;
}
| MOVEAMOUNT NUMBER {
if ($2 < 0 || $2 > INT_MAX) {
yyerror("invalid movemount: %d", $2);
YYERROR;
}
conf->mamount = $2;
}
| SNAPDIST NUMBER {
if ($2 < 0 || $2 > INT_MAX) {
yyerror("invalid snapdist: %d", $2);
YYERROR;
}
conf->snapdist = $2;
}
| COMMAND STRING string {
if (!conf_cmd_add(conf, $2, $3)) {
yyerror("command name/path too long");
free($2);
free($3);
YYERROR;
}
conf_cmd_add(conf, $3, $2, 0);
free($2);
free($3);
}
| AUTOGROUP NUMBER STRING {
if ($2 < 0 || $2 > 9) {
free($3);
yyerror("invalid autogroup: %d", $2);
yyerror("autogroup number out of range: %d", $2);
YYERROR;
}
conf_autogroup(conf, $2, $3);
group_make_autogroup(conf, $3, $2);
free($3);
}
| IGNORE STRING {
conf_ignore(conf, $2);
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 {
if (!conf_bind_kbd(conf, $2, $3)) {
yyerror("invalid bind: %s %s", $2, $3);
free($2);
free($3);
YYERROR;
}
conf_bindname(conf, $2, $3);
free($2);
free($3);
}
| GAP NUMBER NUMBER NUMBER NUMBER {
if ($2 < 0 || $2 > INT_MAX ||
$3 < 0 || $3 > INT_MAX ||
$4 < 0 || $4 > INT_MAX ||
$5 < 0 || $5 > INT_MAX) {
yyerror("invalid gap: %d %d %d %d",
$2, $3, $4, $5);
YYERROR;
}
conf->gap.top = $2;
conf->gap.bottom = $3;
conf->gap.left = $4;
conf->gap.right = $5;
}
| MOUSEBIND STRING string {
if (!conf_bind_mouse(conf, $2, $3)) {
yyerror("invalid mousebind: %s %s", $2, $3);
free($2);
free($3);
YYERROR;
}
conf_mousebind(conf, $2, $3);
free($2);
free($3);
}
@ -199,40 +166,20 @@ color : COLOR colors
;
colors : ACTIVEBORDER STRING {
free(conf->color[CWM_COLOR_BORDER_ACTIVE]);
conf->color[CWM_COLOR_BORDER_ACTIVE] = $2;
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]);
conf->color[CWM_COLOR_BORDER_INACTIVE] = $2;
}
| URGENCYBORDER STRING {
free(conf->color[CWM_COLOR_BORDER_URGENCY]);
conf->color[CWM_COLOR_BORDER_URGENCY] = $2;
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]);
conf->color[CWM_COLOR_BORDER_GROUP] = $2;
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]);
conf->color[CWM_COLOR_BORDER_UNGROUP] = $2;
}
| MENUBG STRING {
free(conf->color[CWM_COLOR_MENU_BG]);
conf->color[CWM_COLOR_MENU_BG] = $2;
}
| MENUFG STRING {
free(conf->color[CWM_COLOR_MENU_FG]);
conf->color[CWM_COLOR_MENU_FG] = $2;
}
| FONTCOLOR STRING {
free(conf->color[CWM_COLOR_MENU_FONT]);
conf->color[CWM_COLOR_MENU_FONT] = $2;
}
| FONTSELCOLOR STRING {
free(conf->color[CWM_COLOR_MENU_FONT_SEL]);
conf->color[CWM_COLOR_MENU_FONT_SEL] = $2;
free(conf->color[CWM_COLOR_BORDER_UNGROUP].name);
conf->color[CWM_COLOR_BORDER_UNGROUP].name = $2;
}
;
%%
@ -245,7 +192,7 @@ struct keywords {
int
yyerror(const char *fmt, ...)
{
va_list ap;
va_list ap;
file->errors++;
va_start(ap, fmt);
@ -273,22 +220,16 @@ lookup(char *s)
{ "borderwidth", BORDERWIDTH},
{ "color", COLOR},
{ "command", COMMAND},
{ "font", FONTCOLOR},
{ "fontname", FONTNAME},
{ "gap", GAP},
{ "groupborder", GROUPBORDER},
{ "ignore", IGNORE},
{ "inactiveborder", INACTIVEBORDER},
{ "menubg", MENUBG},
{ "menufg", MENUFG},
{ "mousebind", MOUSEBIND},
{ "moveamount", MOVEAMOUNT},
{ "no", NO},
{ "selfont", FONTSELCOLOR},
{ "snapdist", SNAPDIST},
{ "sticky", STICKY},
{ "ungroupborder", UNGROUPBORDER},
{ "urgencyborder", URGENCYBORDER},
{ "yes", YES}
};
const struct keywords *p;
@ -304,9 +245,9 @@ lookup(char *s)
#define MAXPUSHBACK 128
u_char *parsebuf;
char *parsebuf;
int parseindex;
u_char pushback_buffer[MAXPUSHBACK];
char pushback_buffer[MAXPUSHBACK];
int pushback_index = 0;
int
@ -330,9 +271,8 @@ lgetc(int quotec)
if (quotec) {
if ((c = getc(file->stream)) == EOF) {
yyerror("reached end of file while parsing "
"quoted string");
if (file == topfile || popfile() == EOF)
yyerror("reached end of file while parsing quoted string");
if (popfile() == EOF)
return (EOF);
return (quotec);
}
@ -350,7 +290,7 @@ lgetc(int quotec)
}
while (c == EOF) {
if (file == topfile || popfile() == EOF)
if (popfile() == EOF)
return (EOF);
c = getc(file->stream);
}
@ -379,13 +319,11 @@ findeol(void)
int c;
parsebuf = NULL;
pushback_index = 0;
/* skip to either EOF or the first real EOL */
while (1) {
if (pushback_index)
c = pushback_buffer[--pushback_index];
else
c = lgetc(0);
c = lgetc(0);
if (c == '\n') {
file->lineno++;
break;
@ -399,8 +337,8 @@ findeol(void)
int
yylex(void)
{
u_char buf[8096];
u_char *p;
char buf[8096];
char *p;
int quotec, next, c;
int token;
@ -441,7 +379,7 @@ yylex(void)
yyerror("string too long");
return (findeol());
}
*p++ = c;
*p++ = (char)c;
}
yylval.v.string = xstrdup(buf);
return (STRING);
@ -483,7 +421,6 @@ nodigits:
}
}
/* Similar to other parse.y copies, but also allows '/' in strings */
#define allowed_in_string(x) \
(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
x != '{' && x != '}' && x != '<' && x != '>' && \
@ -521,7 +458,8 @@ pushfile(const char *name)
nfile->name = xstrdup(name);
if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
warn("%s", nfile->name);
if (errno != ENOENT)
warn("%s", nfile->name);
free(nfile->name);
free(nfile);
return (NULL);
@ -536,32 +474,94 @@ popfile(void)
{
struct file *prev;
if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
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 (file ? 0 : EOF);
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;
int errors = 0;
conf = xconf;
conf = xcalloc(1, sizeof(*conf));
if ((file = pushfile(filename)) == NULL) {
free(conf);
return (-1);
}
topfile = file;
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);
}

178
screen.c
View File

@ -15,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $OpenBSD$
* $Id$
*/
#include <sys/param.h>
@ -23,62 +23,13 @@
#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "calmwm.h"
void
screen_init(int which)
{
struct screen_ctx *sc;
Window *wins, w0, w1;
XSetWindowAttributes rootattr;
unsigned int nwins, i;
sc = xcalloc(1, sizeof(*sc));
TAILQ_INIT(&sc->mruq);
TAILQ_INIT(&sc->regionq);
sc->which = which;
sc->rootwin = RootWindow(X_Dpy, sc->which);
conf_screen(sc);
xu_ewmh_net_supported(sc);
xu_ewmh_net_supported_wm_check(sc);
screen_update_geometry(sc);
group_init(sc);
rootattr.cursor = Conf.cursor[CF_NORMAL];
rootattr.event_mask = SubstructureRedirectMask|SubstructureNotifyMask|
PropertyChangeMask|EnterWindowMask|LeaveWindowMask|
ColormapChangeMask|BUTTONMASK;
XChangeWindowAttributes(X_Dpy, sc->rootwin,
CWEventMask|CWCursor, &rootattr);
/* Deal with existing clients. */
if (XQueryTree(X_Dpy, sc->rootwin, &w0, &w1, &wins, &nwins)) {
for (i = 0; i < nwins; i++)
(void)client_init(wins[i], sc);
XFree(wins);
}
screen_updatestackingorder(sc);
group_set_state(sc);
if (HasRandr)
XRRSelectInput(X_Dpy, sc->rootwin, RRScreenChangeNotifyMask);
TAILQ_INSERT_TAIL(&Screenq, sc, entry);
XSync(X_Dpy, False);
}
struct screen_ctx *
screen_fromroot(Window rootwin)
{
@ -97,83 +48,86 @@ screen_updatestackingorder(struct screen_ctx *sc)
{
Window *wins, w0, w1;
struct client_ctx *cc;
unsigned int nwins, i, s;
u_int nwins, i, s;
if (XQueryTree(X_Dpy, sc->rootwin, &w0, &w1, &wins, &nwins)) {
for (s = 0, i = 0; i < nwins; i++) {
/* Skip hidden windows */
if ((cc = client_find(wins[i])) == NULL ||
cc->flags & CLIENT_HIDDEN)
continue;
cc->stackingorder = s++;
}
XFree(wins);
if (!XQueryTree(X_Dpy, sc->rootwin, &w0, &w1, &wins, &nwins))
return;
for (s = 0, i = 0; i < nwins; i++) {
/* Skip hidden windows */
if ((cc = client_find(wins[i])) == NULL ||
cc->flags & CLIENT_HIDDEN)
continue;
cc->stackingorder = s++;
}
XFree(wins);
}
void
screen_init_xinerama(struct screen_ctx *sc)
{
XineramaScreenInfo *info;
int no;
if (HasXinerama == 0 || XineramaIsActive(X_Dpy) == 0) {
HasXinerama = 0;
sc->xinerama_no = 0;
}
info = XineramaQueryScreens(X_Dpy, &no);
if (info == NULL) {
/* Is xinerama actually off, instead of a malloc failure? */
if (sc->xinerama == NULL)
HasXinerama = 0;
return;
}
if (sc->xinerama != NULL)
XFree(sc->xinerama);
sc->xinerama = info;
sc->xinerama_no = no;
}
/*
* Find which xinerama screen the coordinates (x,y) is on.
*/
struct geom
screen_find_xinerama(struct screen_ctx *sc, int x, int y, int flags)
XineramaScreenInfo *
screen_find_xinerama(struct screen_ctx *sc, int x, int y)
{
struct region_ctx *region;
struct geom geom = sc->work;
XineramaScreenInfo *info;
int i;
TAILQ_FOREACH(region, &sc->regionq, entry) {
if (x >= region->area.x && x < region->area.x+region->area.w &&
y >= region->area.y && y < region->area.y+region->area.h) {
geom = region->area;
break;
}
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);
}
if (flags & CWM_GAP) {
geom.x += sc->gap.left;
geom.y += sc->gap.top;
geom.w -= (sc->gap.left + sc->gap.right);
geom.h -= (sc->gap.top + sc->gap.bottom);
}
return (geom);
return (NULL);
}
void
screen_update_geometry(struct screen_ctx *sc)
screen_update_geometry(struct screen_ctx *sc, int width, int height)
{
XineramaScreenInfo *info = NULL;
struct region_ctx *region;
int info_no = 0, i;
long geom[2], workareas[CALMWM_NGROUPS][4];
int i;
sc->view.x = 0;
sc->view.y = 0;
sc->view.w = DisplayWidth(X_Dpy, sc->which);
sc->view.h = DisplayHeight(X_Dpy, sc->which);
sc->xmax = geom[0] = width;
sc->ymax = geom[1] = height;
XChangeProperty(X_Dpy, sc->rootwin, _NET_DESKTOP_GEOMETRY,
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)geom , 2);
sc->work.x = sc->view.x + sc->gap.left;
sc->work.y = sc->view.y + sc->gap.top;
sc->work.w = sc->view.w - (sc->gap.left + sc->gap.right);
sc->work.h = sc->view.h - (sc->gap.top + sc->gap.bottom);
/* RandR event may have a CTRC added or removed. */
if (XineramaIsActive(X_Dpy))
info = XineramaQueryScreens(X_Dpy, &info_no);
while ((region = TAILQ_FIRST(&sc->regionq)) != NULL) {
TAILQ_REMOVE(&sc->regionq, region, entry);
free(region);
/* x, y, width, height. */
for (i = 0; i < CALMWM_NGROUPS; i++) {
workareas[i][0] = sc->gap.left;
workareas[i][1] = sc->gap.top;
workareas[i][2] = width - (sc->gap.left + sc->gap.right);
workareas[i][3] = height - (sc->gap.top + sc->gap.bottom);
}
for (i = 0; i < info_no; i++) {
region = xmalloc(sizeof(*region));
region->num = i;
region->area.x = info[i].x_org;
region->area.y = info[i].y_org;
region->area.w = info[i].width;
region->area.h = info[i].height;
TAILQ_INSERT_TAIL(&sc->regionq, region, entry);
}
if (info)
XFree(info);
xu_ewmh_net_desktop_geometry(sc);
xu_ewmh_net_workarea(sc);
XChangeProperty(X_Dpy, sc->rootwin, _NET_WORKAREA,
XA_CARDINAL, 32, PropModeReplace,
(unsigned char *)workareas, CALMWM_NGROUPS * 4);
}

View File

@ -2,7 +2,6 @@
* 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.
@ -15,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $OpenBSD$
* $Id$
*/
#include <sys/param.h>
@ -25,21 +24,13 @@
#include <err.h>
#include <errno.h>
#include <fnmatch.h>
#include <glob.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "calmwm.h"
#define PATH_ANY 0x0001
#define PATH_EXEC 0x0002
static void search_match_path(struct menu_q *, struct menu_q *,
char *, int);
static void search_match_path_exec(struct menu_q *, struct menu_q *,
char *);
static int strsubmatch(char *, char *, int);
/*
@ -51,10 +42,13 @@ search_match_client(struct menu_q *menuq, struct menu_q *resultq, char *search)
{
struct winname *wn;
struct menu *mi, *tierp[4], *before = NULL;
int ntiers;
ntiers = sizeof(tierp) / sizeof(tierp[0]);
TAILQ_INIT(resultq);
(void)memset(tierp, 0, sizeof(tierp));
memset(tierp, 0, sizeof(tierp));
/*
* In order of rank:
@ -85,8 +79,8 @@ search_match_client(struct menu_q *menuq, struct menu_q *resultq, char *search)
}
/* Then if there is a match on the window class name. */
if (tier < 0 && strsubmatch(search, cc->ch.res_class, 0)) {
cc->matchname = cc->ch.res_class;
if (tier < 0 && strsubmatch(search, cc->app_class, 0)) {
cc->matchname = cc->app_class;
tier = 3;
}
@ -98,14 +92,14 @@ search_match_client(struct menu_q *menuq, struct menu_q *resultq, char *search)
* window. Furthermore, this is denoted by a "!" when
* printing the window name in the search menu.
*/
if (cc == client_current() && tier < nitems(tierp) - 1)
if (cc == client_current() && tier < ntiers - 1)
tier++;
/* Clients that are hidden get ranked one up. */
if (cc->flags & CLIENT_HIDDEN && tier > 0)
tier--;
assert(tier < nitems(tierp));
assert(tier < ntiers);
/*
* If you have a tierp, insert after it, and make it
@ -142,8 +136,7 @@ search_print_client(struct menu *mi, int list)
if (list)
cc->matchname = cc->name;
(void)snprintf(mi->print, sizeof(mi->print), "(%d) %c%s",
cc->group->shortcut, flag, cc->matchname);
snprintf(mi->print, sizeof(mi->print), "%c%s", flag, cc->matchname);
if (!list && cc->matchname != cc->name &&
strlen(mi->print) < sizeof(mi->print) - 1) {
@ -163,46 +156,12 @@ search_print_client(struct menu *mi, int list)
diff = strlen(cc->name);
}
(void)strlcpy(buf, mi->print, sizeof(buf));
(void)snprintf(mi->print, sizeof(mi->print),
strlcpy(buf, mi->print, sizeof(buf));
snprintf(mi->print, sizeof(mi->print),
"%s:%.*s%s", buf, diff, cc->name, marker);
}
}
static void
search_match_path(struct menu_q *menuq, struct menu_q *resultq, char *search, int flag)
{
char pattern[MAXPATHLEN];
glob_t g;
int i;
TAILQ_INIT(resultq);
(void)strlcpy(pattern, search, sizeof(pattern));
(void)strlcat(pattern, "*", sizeof(pattern));
if (glob(pattern, GLOB_MARK, NULL, &g) != 0)
return;
for (i = 0; i < g.gl_pathc; i++) {
if ((flag & PATH_EXEC) && access(g.gl_pathv[i], X_OK))
continue;
menuq_add(resultq, NULL, "%s", g.gl_pathv[i]);
}
globfree(&g);
}
static void
search_match_path_exec(struct menu_q *menuq, struct menu_q *resultq, char *search)
{
return (search_match_path(menuq, resultq, search, PATH_EXEC));
}
void
search_match_path_any(struct menu_q *menuq, struct menu_q *resultq, char *search)
{
return (search_match_path(menuq, resultq, search, PATH_ANY));
}
void
search_match_text(struct menu_q *menuq, struct menu_q *resultq, char *search)
{
@ -219,39 +178,30 @@ void
search_match_exec(struct menu_q *menuq, struct menu_q *resultq, char *search)
{
struct menu *mi, *mj;
int r;
TAILQ_INIT(resultq);
TAILQ_FOREACH(mi, menuq, entry) {
if (strsubmatch(search, mi->text, 1) == 0 &&
fnmatch(search, mi->text, 0) == FNM_NOMATCH)
continue;
TAILQ_FOREACH(mj, resultq, resultentry) {
r = strcasecmp(mi->text, mj->text);
if (r < 0)
continue;
for (mj = TAILQ_FIRST(resultq); mj != NULL;
mj = TAILQ_NEXT(mj, resultentry)) {
if (strcasecmp(mi->text, mj->text) < 0) {
TAILQ_INSERT_BEFORE(mj, mi, resultentry);
if (r <= 0)
break;
}
}
if (mj == NULL)
TAILQ_INSERT_TAIL(resultq, mi, resultentry);
}
}
void
search_match_exec_path(struct menu_q *menuq, struct menu_q *resultq, char *search)
{
search_match_exec(menuq, resultq, search);
if (TAILQ_EMPTY(resultq))
search_match_path_exec(menuq, resultq, search);
}
static int
strsubmatch(char *sub, char *str, int zeroidx)
{
size_t len, sublen;
unsigned int n, flen;
size_t len, sublen;
u_int n, flen;
if (sub == NULL || str == NULL)
return (0);

61
strlcat.c Normal file
View File

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

57
strlcpy.c Normal file
View File

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

70
strtonum.c Normal file
View File

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

13
util.c
View File

@ -15,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $OpenBSD$
* $Id$
*/
#include <sys/param.h>
@ -23,16 +23,16 @@
#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "calmwm.h"
#define MAXARGLEN 20
void
int
u_spawn(char *argstr)
{
switch (fork()) {
@ -42,9 +42,12 @@ u_spawn(char *argstr)
break;
case -1:
warn("fork");
return (-1);
default:
break;
}
return (0);
}
void
@ -76,6 +79,6 @@ u_exec(char *argstr)
}
*ap = NULL;
(void)setsid();
(void)execvp(args[0], args);
setsid();
execvp(args[0], args);
}

274
xevents.c
View File

@ -15,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $OpenBSD$
* $Id$
*/
/*
@ -29,9 +29,10 @@
#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "calmwm.h"
@ -42,64 +43,83 @@ 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 *);
static void xev_handle_expose(XEvent *);
void (*xev_handlers[LASTEvent])(XEvent *) = {
[MapRequest] = xev_handle_maprequest,
[UnmapNotify] = xev_handle_unmapnotify,
[DestroyNotify] = xev_handle_destroynotify,
[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,
[Expose] = xev_handle_expose,
};
static KeySym modkeys[] = { XK_Alt_L, XK_Alt_R, XK_Super_L, XK_Super_R,
XK_Control_L, XK_Control_R };
static void
xev_handle_maprequest(XEvent *ee)
{
XMapRequestEvent *e = &ee->xmaprequest;
struct client_ctx *cc = NULL, *old_cc;
XWindowAttributes xattr;
struct winmatch *wm;
if ((old_cc = client_current()))
if ((old_cc = client_current()) != NULL)
client_ptrsave(old_cc);
if ((cc = client_find(e->window)) == NULL)
cc = client_init(e->window, NULL);
if ((cc = client_find(e->window)) == NULL) {
XGetWindowAttributes(X_Dpy, e->window, &xattr);
cc = client_new(e->window, screen_fromroot(xattr.root), 1);
}
if ((cc != NULL) && ((cc->flags & CLIENT_IGNORE) == 0))
client_ptrwarp(cc);
TAILQ_FOREACH(wm, &Conf.ignoreq, entry) {
if (strncasecmp(wm->title, cc->name, strlen(wm->title)) == 0)
return;
}
client_ptrwarp(cc);
}
static void
xev_handle_unmapnotify(XEvent *ee)
{
XUnmapEvent *e = &ee->xunmap;
XEvent ev;
struct client_ctx *cc;
/* XXX, we need a recursive locking wrapper around grab server */
XGrabServer(X_Dpy);
if ((cc = client_find(e->window)) != NULL) {
if (e->send_event) {
client_set_wm_state(cc, WithdrawnState);
} else {
if (!(cc->flags & CLIENT_HIDDEN))
client_delete(cc);
}
/*
* If it's going to die anyway, nuke it.
*
* Else, if it's a synthetic event delete state, since they
* want it to be withdrawn. ICCM recommends you withdraw on
* this even if we haven't alredy been told to iconify, to
* deal with legacy clients.
*/
if (XCheckTypedWindowEvent(X_Dpy, cc->win,
DestroyNotify, &ev) || e->send_event != 0) {
client_delete(cc);
} else
client_hide(cc);
}
XUngrabServer(X_Dpy);
}
static void
@ -124,34 +144,30 @@ xev_handle_configurerequest(XEvent *ee)
sc = cc->sc;
if (e->value_mask & CWWidth)
cc->geom.w = e->width;
cc->geom.width = e->width;
if (e->value_mask & CWHeight)
cc->geom.h = e->height;
cc->geom.height = e->height;
if (e->value_mask & CWX)
cc->geom.x = e->x;
if (e->value_mask & CWY)
cc->geom.y = e->y;
if (e->value_mask & CWBorderWidth)
cc->bwidth = e->border_width;
if (e->value_mask & CWSibling)
wc.sibling = e->above;
if (e->value_mask & CWStackMode)
wc.stack_mode = e->detail;
wc.border_width = e->border_width;
if (cc->geom.x == 0 && cc->geom.w >= sc->view.w)
if (cc->geom.x == 0 && cc->geom.width >= sc->xmax)
cc->geom.x -= cc->bwidth;
if (cc->geom.y == 0 && cc->geom.h >= sc->view.h)
if (cc->geom.y == 0 && cc->geom.height >= sc->ymax)
cc->geom.y -= cc->bwidth;
wc.x = cc->geom.x;
wc.y = cc->geom.y;
wc.width = cc->geom.w;
wc.height = cc->geom.h;
wc.width = cc->geom.width;
wc.height = cc->geom.height;
wc.border_width = cc->bwidth;
XConfigureWindow(X_Dpy, cc->win, e->value_mask, &wc);
client_config(cc);
xev_reconfig(cc);
} else {
/* let it do what it wants, it'll be ours when we map it. */
wc.x = e->x;
@ -181,25 +197,40 @@ xev_handle_propertynotify(XEvent *ee)
case XA_WM_NAME:
client_setname(cc);
break;
case XA_WM_HINTS:
client_wm_hints(cc);
client_draw_border(cc);
break;
case XA_WM_TRANSIENT_FOR:
client_transient(cc);
break;
default:
/* do nothing */
break;
}
} else {
TAILQ_FOREACH(sc, &Screenq, entry) {
if (sc->rootwin == e->window) {
if (e->atom == ewmh[_NET_DESKTOP_NAMES])
group_update_names(sc);
}
}
TAILQ_FOREACH(sc, &Screenq, entry)
if (sc->rootwin == e->window)
goto test;
return;
test:
if (e->atom == _NET_DESKTOP_NAMES)
group_update_names(sc);
}
}
void
xev_reconfig(struct client_ctx *cc)
{
XConfigureEvent ce;
ce.type = ConfigureNotify;
ce.event = cc->win;
ce.window = cc->win;
ce.x = cc->geom.x;
ce.y = cc->geom.y;
ce.width = cc->geom.width;
ce.height = cc->geom.height;
ce.border_width = cc->bwidth;
ce.above = None;
ce.override_redirect = 0;
XSendEvent(X_Dpy, cc->win, False, StructureNotifyMask, (XEvent *)&ce);
}
static void
@ -208,10 +239,14 @@ xev_handle_enternotify(XEvent *ee)
XCrossingEvent *e = &ee->xcrossing;
struct client_ctx *cc;
Last_Event_Time = e->time;
if ((cc = client_find(e->window)) != NULL)
client_setactive(cc);
client_setactive(cc, 1);
}
static void
xev_handle_leavenotify(XEvent *ee)
{
client_leave(NULL);
}
/* We can split this into two event handlers. */
@ -220,29 +255,31 @@ xev_handle_buttonpress(XEvent *ee)
{
XButtonEvent *e = &ee->xbutton;
struct client_ctx *cc, fakecc;
struct binding *mb;
struct screen_ctx *sc;
struct mousebinding *mb;
e->state &= ~IGNOREMODMASK;
sc = screen_fromroot(e->root);
cc = client_find(e->window);
/* Ignore caps lock and numlock */
e->state &= ~(Mod2Mask | LockMask);
TAILQ_FOREACH(mb, &Conf.mousebindingq, entry) {
if (e->button == mb->press.button && e->state == mb->modmask)
if (e->button == mb->button && e->state == mb->modmask)
break;
}
if (mb == NULL)
return;
if (mb->flags & CWM_WIN) {
if (((cc = client_find(e->window)) == NULL) &&
(cc = client_current()) == NULL)
return;
} else {
if (e->window != e->root)
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;
(*mb->callback)(cc, &mb->argument);
(*mb->callback)(cc, e);
}
static void
@ -250,7 +287,7 @@ xev_handle_buttonrelease(XEvent *ee)
{
struct client_ctx *cc;
if ((cc = client_current()))
if ((cc = client_current()) != NULL)
group_sticky_toggle_exit(cc);
}
@ -259,17 +296,18 @@ xev_handle_keypress(XEvent *ee)
{
XKeyEvent *e = &ee->xkey;
struct client_ctx *cc = NULL, fakecc;
struct binding *kb;
struct keybinding *kb;
KeySym keysym, skeysym;
unsigned int modshift;
int modshift;
keysym = XkbKeycodeToKeysym(X_Dpy, e->keycode, 0, 0);
skeysym = XkbKeycodeToKeysym(X_Dpy, e->keycode, 0, 1);
keysym = XKeycodeToKeysym(X_Dpy, e->keycode, 0);
skeysym = XKeycodeToKeysym(X_Dpy, e->keycode, 1);
e->state &= ~IGNOREMODMASK;
/* we don't care about caps lock and numlock here */
e->state &= ~(LockMask | Mod2Mask);
TAILQ_FOREACH(kb, &Conf.keybindingq, entry) {
if (keysym != kb->press.keysym && skeysym == kb->press.keysym)
if (keysym != kb->keysym && skeysym == kb->keysym)
modshift = ShiftMask;
else
modshift = 0;
@ -277,13 +315,15 @@ xev_handle_keypress(XEvent *ee)
if ((kb->modmask | modshift) != e->state)
continue;
if (kb->press.keysym == (modshift == 0 ? keysym : skeysym))
if ((kb->keycode != 0 && kb->keysym == NoSymbol &&
kb->keycode == e->keycode) || kb->keysym ==
(modshift == 0 ? keysym : skeysym))
break;
}
if (kb == NULL)
return;
if (kb->flags & CWM_WIN) {
if (kb->flags & KBFLAG_NEEDCLIENT) {
if (((cc = client_find(e->window)) == NULL) &&
(cc = client_current()) == NULL)
return;
@ -296,24 +336,34 @@ xev_handle_keypress(XEvent *ee)
}
/*
* This is only used for the modifier suppression detection.
* This is only used for the alt suppression detection.
*/
static void
xev_handle_keyrelease(XEvent *ee)
{
XKeyEvent *e = &ee->xkey;
struct screen_ctx *sc;
KeySym keysym;
unsigned int i;
struct client_ctx *cc;
int keysym;
sc = screen_fromroot(e->root);
cc = client_current();
keysym = XkbKeycodeToKeysym(X_Dpy, e->keycode, 0, 0);
for (i = 0; i < nitems(modkeys); i++) {
if (keysym == modkeys[i]) {
client_cycle_leave(sc);
break;
}
keysym = XKeycodeToKeysym(X_Dpy, e->keycode, 0);
if (keysym != XK_Alt_L && keysym != XK_Alt_R)
return;
sc->altpersist = 0;
/*
* XXX - better interface... xevents should not know about
* how/when to mtf.
*/
client_mtf(NULL);
if (cc != NULL) {
group_sticky_toggle_exit(cc);
XUngrabKeyboard(X_Dpy, CurrentTime);
}
}
@ -321,45 +371,17 @@ static void
xev_handle_clientmessage(XEvent *ee)
{
XClientMessageEvent *e = &ee->xclient;
struct client_ctx *cc, *old_cc;
struct screen_ctx *sc;
Atom xa_wm_change_state;
struct client_ctx *cc;
sc = screen_fromroot(e->window);
xa_wm_change_state = XInternAtom(X_Dpy, "WM_CHANGE_STATE", False);
if ((cc = client_find(e->window)) == NULL && e->window != sc->rootwin)
if ((cc = client_find(e->window)) == NULL)
return;
if (e->message_type == cwmh[WM_CHANGE_STATE] && e->format == 32 &&
if (e->message_type == xa_wm_change_state && e->format == 32 &&
e->data.l[0] == IconicState)
client_hide(cc);
if (e->message_type == ewmh[_NET_CLOSE_WINDOW])
client_send_delete(cc);
if (e->message_type == ewmh[_NET_ACTIVE_WINDOW] && e->format == 32) {
if ((old_cc = client_current()))
client_ptrsave(old_cc);
client_ptrwarp(cc);
}
if (e->message_type == ewmh[_NET_WM_DESKTOP] && e->format == 32) {
/*
* The EWMH spec states that if the cardinal returned is
* 0xFFFFFFFF (-1) then the window should appear on all
* desktops, which in our case is assigned to group 0.
*/
if (e->data.l[0] == (unsigned long)-1)
group_movetogroup(cc, 0);
else
group_movetogroup(cc, e->data.l[0]);
}
if (e->message_type == ewmh[_NET_WM_STATE] && e->format == 32)
xu_ewmh_handle_net_wm_state_msg(cc,
e->data.l[0], e->data.l[1], e->data.l[2]);
if (e->message_type == ewmh[_NET_CURRENT_DESKTOP] && e->format == 32)
group_only(sc, e->data.l[0]);
}
static void
@ -371,9 +393,10 @@ xev_handle_randr(XEvent *ee)
i = XRRRootToScreen(X_Dpy, rev->root);
TAILQ_FOREACH(sc, &Screenq, entry) {
if (sc->which == i) {
if (sc->which == (u_int)i) {
XRRUpdateConfiguration(ee);
screen_update_geometry(sc);
screen_update_geometry(sc, rev->width, rev->height);
screen_init_xinerama(sc);
}
}
}
@ -386,13 +409,15 @@ static void
xev_handle_mappingnotify(XEvent *ee)
{
XMappingEvent *e = &ee->xmapping;
struct screen_ctx *sc;
struct keybinding *kb;
TAILQ_FOREACH(kb, &Conf.keybindingq, entry)
conf_ungrab(&Conf, kb);
XRefreshKeyboardMapping(e);
if (e->request == MappingKeyboard) {
TAILQ_FOREACH(sc, &Screenq, entry)
conf_grab_kbd(sc->rootwin);
}
TAILQ_FOREACH(kb, &Conf.keybindingq, entry)
conf_grab(&Conf, kb);
}
static void
@ -405,14 +430,19 @@ xev_handle_expose(XEvent *ee)
client_draw_border(cc);
}
volatile sig_atomic_t _xev_quit = 0;
void
xev_process(void)
xev_loop(void)
{
XEvent e;
XNextEvent(X_Dpy, &e);
if (e.type - Randr_ev == RRScreenChangeNotify)
xev_handle_randr(&e);
else if (e.type < LASTEvent && xev_handlers[e.type] != NULL)
(*xev_handlers[e.type])(&e);
while (_xev_quit == 0) {
XNextEvent(X_Dpy, &e);
if (e.type - Randr_ev == RRScreenChangeNotify)
xev_handle_randr(&e);
else if (e.type < LASTEvent && xev_handlers[e.type] != NULL)
(*xev_handlers[e.type])(&e);
}
}

View File

@ -15,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $OpenBSD$
* $Id$
*/
#include <sys/param.h>
@ -23,11 +23,9 @@
#include <err.h>
#include <errno.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "calmwm.h"
@ -37,8 +35,6 @@ xmalloc(size_t siz)
{
void *p;
if (siz == 0)
errx(1, "xmalloc: zero size");
if ((p = malloc(siz)) == NULL)
err(1, "malloc");
@ -50,16 +46,18 @@ xcalloc(size_t no, size_t siz)
{
void *p;
if (siz == 0 || no == 0)
errx(1, "xcalloc: zero size");
if (SIZE_MAX / no < siz)
errx(1, "xcalloc: no * siz > SIZE_MAX");
if ((p = calloc(no, siz)) == NULL)
err(1, "calloc");
return (p);
}
void
xfree(void *p)
{
free(p);
}
char *
xstrdup(const char *str)
{
@ -70,19 +68,3 @@ xstrdup(const char *str)
return (p);
}
int
xasprintf(char **ret, const char *fmt, ...)
{
va_list ap;
int i;
va_start(ap, fmt);
i = vasprintf(ret, fmt, ap);
va_end(ap);
if (i < 0 || *ret == NULL)
err(1, "asprintf");
return (i);
}

483
xutil.c
View File

@ -15,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $OpenBSD$
* $Id$
*/
#include <sys/param.h>
@ -23,56 +23,17 @@
#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "calmwm.h"
static unsigned int ign_mods[] = { 0, LockMask, Mod2Mask, Mod2Mask | LockMask };
void
xu_btn_grab(Window win, int mask, unsigned int btn)
{
unsigned int i;
for (i = 0; i < nitems(ign_mods); i++)
XGrabButton(X_Dpy, btn, (mask | ign_mods[i]), win,
False, BUTTONMASK, GrabModeAsync,
GrabModeSync, None, None);
}
void
xu_btn_ungrab(Window win)
{
XUngrabButton(X_Dpy, AnyButton, AnyModifier, win);
}
void
xu_key_grab(Window win, unsigned int mask, KeySym keysym)
{
KeyCode code;
unsigned int i;
code = XKeysymToKeycode(X_Dpy, keysym);
if ((XkbKeycodeToKeysym(X_Dpy, code, 0, 0) != keysym) &&
(XkbKeycodeToKeysym(X_Dpy, code, 0, 1) == keysym))
mask |= ShiftMask;
for (i = 0; i < nitems(ign_mods); i++)
XGrabKey(X_Dpy, code, (mask | ign_mods[i]), win,
True, GrabModeAsync, GrabModeAsync);
}
void
xu_key_ungrab(Window win)
{
XUngrabKey(X_Dpy, AnyKey, AnyModifier, win);
}
int
xu_ptr_grab(Window win, unsigned int mask, Cursor curs)
xu_ptr_grab(Window win, int mask, Cursor curs)
{
return (XGrabPointer(X_Dpy, win, False, mask,
GrabModeAsync, GrabModeAsync,
@ -80,7 +41,7 @@ xu_ptr_grab(Window win, unsigned int mask, Cursor curs)
}
int
xu_ptr_regrab(unsigned int mask, Cursor curs)
xu_ptr_regrab(int mask, Cursor curs)
{
return (XChangeActivePointerGrab(X_Dpy, mask,
curs, CurrentTime) == GrabSuccess ? 0 : -1);
@ -93,13 +54,31 @@ xu_ptr_ungrab(void)
}
void
xu_ptr_getpos(Window win, int *x, int *y)
xu_btn_grab(Window win, int mask, u_int btn)
{
Window w0, w1;
int tmp0, tmp1;
unsigned int tmp2;
int i;
for (i = 0; i < sizeof(ign_mods)/sizeof(*ign_mods); i++)
XGrabButton(X_Dpy, btn, (mask | ign_mods[i]), win,
False, ButtonMask, GrabModeAsync,
GrabModeSync, None, None);
}
XQueryPointer(X_Dpy, win, &w0, &w1, &tmp0, &tmp1, x, y, &tmp2);
void
xu_btn_ungrab(Window win, int mask, u_int btn)
{
int i;
for (i = 0; i < sizeof(ign_mods)/sizeof(*ign_mods); i++)
XUngrabButton(X_Dpy, btn, (mask | ign_mods[i]), win);
}
void
xu_ptr_getpos(Window rootwin, int *x, int *y)
{
Window w0, w1;
int tmp0, tmp1;
u_int tmp2;
XQueryPointer(X_Dpy, rootwin, &w0, &w1, &tmp0, &tmp1, x, y, &tmp2);
}
void
@ -108,12 +87,59 @@ xu_ptr_setpos(Window win, int x, int y)
XWarpPointer(X_Dpy, None, win, 0, 0, 0, 0, x, y);
}
int
xu_getprop(Window win, Atom atm, Atom type, long len, unsigned char **p)
void
xu_key_grab(Window win, int mask, int keysym)
{
Atom realtype;
unsigned long n, extra;
int format;
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++)
XGrabKey(X_Dpy, code, (mask | ign_mods[i]), win,
True, GrabModeAsync, GrabModeAsync);
}
void
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;
memset(&e, 0, sizeof(e));
e.xclient.type = ClientMessage;
e.xclient.window = win;
e.xclient.message_type = atm;
e.xclient.format = 32;
e.xclient.data.l[0] = val;
e.xclient.data.l[1] = CurrentTime;
XSendEvent(X_Dpy, win, False, 0, &e);
}
int
xu_getprop(Window win, Atom atm, Atom type, long len, u_char **p)
{
Atom realtype;
u_long n, extra;
int format;
if (XGetWindowProperty(X_Dpy, win, atm, 0L, len, False, type,
&realtype, &format, &n, &extra, p) != Success || *p == NULL)
@ -143,7 +169,7 @@ xu_getstrprop(Window win, Atom atm, char **text) {
XTextProperty prop2;
if (Xutf8TextListToTextProperty(X_Dpy, list, nitems,
XUTF8StringStyle, &prop2) == Success) {
*text = xstrdup((const char *)prop2.value);
*text = xstrdup(prop2.value);
XFree(prop2.value);
}
} else {
@ -157,283 +183,104 @@ xu_getstrprop(Window win, Atom atm, char **text) {
return (nitems);
}
/* Root Window Properties */
void
xu_ewmh_net_supported(struct screen_ctx *sc)
int
xu_getstate(struct client_ctx *cc, int *state)
{
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_SUPPORTED],
XA_ATOM, 32, PropModeReplace, (unsigned char *)ewmh, EWMH_NITEMS);
}
long *p = NULL;
void
xu_ewmh_net_supported_wm_check(struct screen_ctx *sc)
{
Window w;
if (xu_getprop(cc->win, WM_STATE, WM_STATE, 2L, (u_char **)&p) <= 0)
return (-1);
w = XCreateSimpleWindow(X_Dpy, sc->rootwin, -1, -1, 1, 1, 0, 0, 0);
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_SUPPORTING_WM_CHECK],
XA_WINDOW, 32, PropModeReplace, (unsigned char *)&w, 1);
XChangeProperty(X_Dpy, w, ewmh[_NET_SUPPORTING_WM_CHECK],
XA_WINDOW, 32, PropModeReplace, (unsigned char *)&w, 1);
XChangeProperty(X_Dpy, w, ewmh[_NET_WM_NAME],
cwmh[UTF8_STRING], 8, PropModeReplace, (unsigned char *)WMNAME,
strlen(WMNAME));
}
void
xu_ewmh_net_desktop_geometry(struct screen_ctx *sc)
{
long geom[2] = { sc->view.w, sc->view.h };
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_DESKTOP_GEOMETRY],
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)geom , 2);
}
void
xu_ewmh_net_workarea(struct screen_ctx *sc)
{
long workareas[CALMWM_NGROUPS][4];
int i;
for (i = 0; i < CALMWM_NGROUPS; i++) {
workareas[i][0] = sc->work.x;
workareas[i][1] = sc->work.y;
workareas[i][2] = sc->work.w;
workareas[i][3] = sc->work.h;
}
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_WORKAREA],
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)workareas,
CALMWM_NGROUPS * 4);
}
void
xu_ewmh_net_client_list(struct screen_ctx *sc)
{
struct client_ctx *cc;
Window *winlist;
int i = 0, j = 0;
TAILQ_FOREACH(cc, &Clientq, entry)
i++;
if (i == 0)
return;
winlist = xcalloc(i, sizeof(*winlist));
TAILQ_FOREACH(cc, &Clientq, entry)
winlist[j++] = cc->win;
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_CLIENT_LIST],
XA_WINDOW, 32, PropModeReplace, (unsigned char *)winlist, i);
free(winlist);
}
void
xu_ewmh_net_active_window(struct screen_ctx *sc, Window w)
{
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_ACTIVE_WINDOW],
XA_WINDOW, 32, PropModeReplace, (unsigned char *)&w, 1);
}
void
xu_ewmh_net_wm_desktop_viewport(struct screen_ctx *sc)
{
long viewports[2] = {0, 0};
/* We don't support large desktops, so this is (0, 0). */
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_DESKTOP_VIEWPORT],
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)viewports, 2);
}
void
xu_ewmh_net_wm_number_of_desktops(struct screen_ctx *sc)
{
long ndesks = CALMWM_NGROUPS;
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_NUMBER_OF_DESKTOPS],
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&ndesks, 1);
}
void
xu_ewmh_net_showing_desktop(struct screen_ctx *sc)
{
long zero = 0;
/* We don't support `showing desktop' mode, so this is zero.
* 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, ewmh[_NET_SHOWING_DESKTOP],
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&zero, 1);
}
void
xu_ewmh_net_virtual_roots(struct screen_ctx *sc)
{
/* We don't support virtual roots, so delete if set by previous wm. */
XDeleteProperty(X_Dpy, sc->rootwin, ewmh[_NET_VIRTUAL_ROOTS]);
}
void
xu_ewmh_net_current_desktop(struct screen_ctx *sc, long idx)
{
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_CURRENT_DESKTOP],
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&idx, 1);
}
void
xu_ewmh_net_desktop_names(struct screen_ctx *sc, char *data, int n)
{
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_DESKTOP_NAMES],
cwmh[UTF8_STRING], 8, PropModeReplace, (unsigned char *)data, n);
}
/* Application Window Properties */
void
xu_ewmh_net_wm_desktop(struct client_ctx *cc)
{
long no = cc->group->shortcut;
XChangeProperty(X_Dpy, cc->win, ewmh[_NET_WM_DESKTOP],
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&no, 1);
}
Atom *
xu_ewmh_get_net_wm_state(struct client_ctx *cc, int *n)
{
Atom *state, *p = NULL;
if ((*n = xu_getprop(cc->win, ewmh[_NET_WM_STATE], XA_ATOM, 64L,
(unsigned char **)&p)) <= 0)
return (NULL);
state = xcalloc(*n, sizeof(Atom));
(void)memcpy(state, p, *n * sizeof(Atom));
*state = (int)*p;
XFree((char *)p);
return (state);
return (0);
}
void
xu_ewmh_handle_net_wm_state_msg(struct client_ctx *cc, int action,
Atom first, Atom second)
xu_setstate(struct client_ctx *cc, int state)
{
unsigned int i;
static struct handlers {
int atom;
int property;
void (*toggle)(struct client_ctx *);
} handlers[] = {
{ _NET_WM_STATE_MAXIMIZED_VERT,
CLIENT_VMAXIMIZED,
client_vmaximize },
{ _NET_WM_STATE_MAXIMIZED_HORZ,
CLIENT_HMAXIMIZED,
client_hmaximize },
{ _NET_WM_STATE_FULLSCREEN,
CLIENT_FULLSCREEN,
client_fullscreen },
{ _NET_WM_STATE_DEMANDS_ATTENTION,
CLIENT_URGENCY,
client_urgency },
};
long dat[2];
for (i = 0; i < nitems(handlers); i++) {
if (first != ewmh[handlers[i].atom] &&
second != ewmh[handlers[i].atom])
continue;
switch (action) {
case _NET_WM_STATE_ADD:
if ((cc->flags & handlers[i].property) == 0)
handlers[i].toggle(cc);
break;
case _NET_WM_STATE_REMOVE:
if (cc->flags & handlers[i].property)
handlers[i].toggle(cc);
break;
case _NET_WM_STATE_TOGGLE:
handlers[i].toggle(cc);
}
dat[0] = state;
dat[1] = None;
cc->state = state;
XChangeProperty(X_Dpy, cc->win, WM_STATE, WM_STATE, 32,
PropModeReplace, (unsigned char *)dat, 2);
}
Atom cwm_atoms[CWM_NO_ATOMS];
char *atoms[CWM_NO_ATOMS] = {
"WM_STATE",
"WM_DELETE_WINDOW",
"WM_TAKE_FOCUS",
"WM_PROTOCOLS",
"_MOTIF_WM_HINTS",
"UTF8_STRING",
"_NET_SUPPORTED",
"_NET_SUPPORTING_WM_CHECK",
"_NET_WM_NAME",
"_NET_ACTIVE_WINDOW",
"_NET_CLIENT_LIST",
"_NET_NUMBER_OF_DESKTOPS",
"_NET_CURRENT_DESKTOP",
"_NET_DESKTOP_VIEWPORT",
"_NET_DESKTOP_GEOMETRY",
"_NET_VIRTUAL_ROOTS",
"_NET_SHOWING_DESKTOP",
"_NET_DESKTOP_NAMES",
"_NET_WM_DESKTOP",
"_NET_WORKAREA",
};
void
xu_getatoms(void)
{
XInternAtoms(X_Dpy, atoms, CWM_NO_ATOMS, False, cwm_atoms);
}
void
xu_setwmname(struct screen_ctx *sc)
{
/*
* set up the _NET_SUPPORTED hint with all netwm atoms that we
* know about.
*/
XChangeProperty(X_Dpy, sc->rootwin, _NET_SUPPORTED, XA_ATOM, 32,
PropModeReplace, (unsigned char *)&_NET_SUPPORTED,
CWM_NO_ATOMS - CWM_NETWM_START);
/*
* netwm spec says that to prove that the hint is not stale you must
* provide _NET_SUPPORTING_WM_CHECK containing a window (we use the
* menu window). The property must be set on the root window and the
* window itself, the window also must have _NET_WM_NAME set with the
* window manager name.
*/
XChangeProperty(X_Dpy, sc->rootwin, _NET_SUPPORTING_WM_CHECK,
XA_WINDOW, 32, PropModeReplace, (unsigned char *)&sc->menuwin, 1);
XChangeProperty(X_Dpy, sc->menuwin, _NET_SUPPORTING_WM_CHECK,
XA_WINDOW, 32, PropModeReplace, (unsigned char *)&sc->menuwin, 1);
XChangeProperty(X_Dpy, sc->menuwin, _NET_WM_NAME, UTF8_STRING,
8, PropModeReplace, WMNAME, strlen(WMNAME));
}
unsigned long
xu_getcolor(struct screen_ctx *sc, char *name)
{
XColor color, tmp;
if (!XAllocNamedColor(X_Dpy, DefaultColormap(X_Dpy, sc->which),
name, &color, &tmp)) {
warnx("XAllocNamedColor error: '%s'", name);
return 0;
}
return color.pixel;
}
void
xu_ewmh_restore_net_wm_state(struct client_ctx *cc)
xu_freecolor(struct screen_ctx *sc, unsigned long pixel)
{
Atom *atoms;
int i, n;
atoms = xu_ewmh_get_net_wm_state(cc, &n);
for (i = 0; i < n; i++) {
if (atoms[i] == ewmh[_NET_WM_STATE_MAXIMIZED_HORZ])
client_hmaximize(cc);
if (atoms[i] == ewmh[_NET_WM_STATE_MAXIMIZED_VERT])
client_vmaximize(cc);
if (atoms[i] == ewmh[_NET_WM_STATE_FULLSCREEN])
client_fullscreen(cc);
if (atoms[i] == ewmh[_NET_WM_STATE_DEMANDS_ATTENTION])
client_urgency(cc);
}
free(atoms);
}
void
xu_ewmh_set_net_wm_state(struct client_ctx *cc)
{
Atom *atoms, *oatoms;
int n, i, j;
oatoms = xu_ewmh_get_net_wm_state(cc, &n);
atoms = xcalloc((n + _NET_WM_STATES_NITEMS), sizeof(Atom));
for (i = j = 0; i < n; i++) {
if (oatoms[i] != ewmh[_NET_WM_STATE_MAXIMIZED_HORZ] &&
oatoms[i] != ewmh[_NET_WM_STATE_MAXIMIZED_VERT] &&
oatoms[i] != ewmh[_NET_WM_STATE_FULLSCREEN] &&
oatoms[i] != ewmh[_NET_WM_STATE_DEMANDS_ATTENTION])
atoms[j++] = oatoms[i];
}
free(oatoms);
if (cc->flags & CLIENT_FULLSCREEN)
atoms[j++] = ewmh[_NET_WM_STATE_FULLSCREEN];
else {
if (cc->flags & CLIENT_HMAXIMIZED)
atoms[j++] = ewmh[_NET_WM_STATE_MAXIMIZED_HORZ];
if (cc->flags & CLIENT_VMAXIMIZED)
atoms[j++] = ewmh[_NET_WM_STATE_MAXIMIZED_VERT];
}
if (cc->flags & CLIENT_URGENCY)
atoms[j++] = ewmh[_NET_WM_STATE_DEMANDS_ATTENTION];
if (j > 0)
XChangeProperty(X_Dpy, cc->win, ewmh[_NET_WM_STATE],
XA_ATOM, 32, PropModeReplace, (unsigned char *)atoms, j);
else
XDeleteProperty(X_Dpy, cc->win, ewmh[_NET_WM_STATE]);
free(atoms);
}
void
xu_xorcolor(XftColor a, XftColor b, XftColor *r)
{
r->pixel = a.pixel ^ b.pixel;
r->color.red = a.color.red ^ b.color.red;
r->color.green = a.color.green ^ b.color.green;
r->color.blue = a.color.blue ^ b.color.blue;
r->color.alpha = 0xffff;
}
int
xu_xft_width(XftFont *xftfont, const char *text, int len)
{
XGlyphInfo extents;
XftTextExtentsUtf8(X_Dpy, xftfont, (const FcChar8*)text,
len, &extents);
return (extents.xOff);
}
void
xu_xft_draw(struct screen_ctx *sc, const char *text, int color, int x, int y)
{
XftDrawStringUtf8(sc->xftdraw, &sc->xftcolor[color], sc->xftfont,
x, y, (const FcChar8*)text, strlen(text));
XFreeColors(X_Dpy, DefaultColormap(X_Dpy, sc->which), &pixel, 1, 0L);
}