cwm/calmwm.c

328 lines
8.1 KiB
C
Raw Normal View History

2007-04-27 21:58:48 +04:00
/*
* 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.
2007-04-27 21:58:48 +04:00
*
* $Id$
*/
#include "headers.h"
#include "calmwm.h"
Display *X_Dpy;
2007-04-27 21:58:48 +04:00
Cursor Cursor_move;
Cursor Cursor_resize;
Cursor Cursor_select;
Cursor Cursor_default;
Cursor Cursor_question;
2007-04-27 21:58:48 +04:00
struct screen_ctx_q Screenq;
struct screen_ctx *Curscreen;
u_int Nscreens;
2007-04-27 21:58:48 +04:00
struct client_ctx_q Clientq;
2007-04-27 21:58:48 +04:00
int Doshape, Shape_ev;
int Starting;
struct conf Conf;
2007-04-27 21:58:48 +04:00
/* From TWM */
#define gray_width 2
#define gray_height 2
static char gray_bits[] = {0x02, 0x01};
2008-04-16 00:24:41 +04:00
static void _sigchld_cb(int);
static void dpy_init(const char *);
2007-04-27 21:58:48 +04:00
int
main(int argc, char **argv)
{
const char *conf_file = NULL;
char *display_name = NULL;
int ch;
while ((ch = getopt(argc, argv, "c:d:")) != -1) {
2007-04-27 21:58:48 +04:00
switch (ch) {
case 'c':
2008-05-19 22:53:09 +04:00
conf_file = optarg;
break;
case 'd':
display_name = optarg;
break;
2007-04-27 21:58:48 +04:00
default:
usage();
2007-04-27 21:58:48 +04:00
}
}
argc -= optind;
2007-05-21 11:53:11 +04:00
argv += optind;
2007-04-27 21:58:48 +04:00
/* Ignore a few signals. */
2008-04-16 00:24:41 +04:00
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
err(1, "signal");
2007-04-27 21:58:48 +04:00
2008-04-16 00:24:41 +04:00
if (signal(SIGCHLD, _sigchld_cb) == SIG_ERR)
err(1, "signal");
2007-04-27 21:58:48 +04:00
group_init();
Starting = 1;
dpy_init(display_name);
bzero(&Conf, sizeof(Conf));
2008-05-19 22:53:09 +04:00
conf_setup(&Conf, conf_file);
2007-04-27 21:58:48 +04:00
client_setup();
x_setup();
Starting = 0;
2007-04-27 21:58:48 +04:00
xev_init();
XEV_QUICK(NULL, NULL, MapRequest, xev_handle_maprequest, NULL);
XEV_QUICK(NULL, NULL, UnmapNotify, xev_handle_unmapnotify, NULL);
XEV_QUICK(NULL, NULL, ConfigureRequest,
xev_handle_configurerequest, NULL);
XEV_QUICK(NULL, NULL, PropertyNotify, xev_handle_propertynotify, NULL);
XEV_QUICK(NULL, NULL, EnterNotify, xev_handle_enternotify, NULL);
XEV_QUICK(NULL, NULL, LeaveNotify, xev_handle_leavenotify, NULL);
XEV_QUICK(NULL, NULL, ButtonPress, xev_handle_buttonpress, NULL);
XEV_QUICK(NULL, NULL, ButtonRelease, xev_handle_buttonrelease, NULL);
XEV_QUICK(NULL, NULL, KeyPress, xev_handle_keypress, NULL);
XEV_QUICK(NULL, NULL, KeyRelease, xev_handle_keyrelease, NULL);
XEV_QUICK(NULL, NULL, Expose, xev_handle_expose, NULL);
XEV_QUICK(NULL, NULL, DestroyNotify, xev_handle_destroynotify, NULL);
XEV_QUICK(NULL, NULL, ClientMessage, xev_handle_clientmessage, NULL);
XEV_QUICK(NULL, NULL, MappingNotify, xev_handle_mapping, NULL);
2007-04-27 21:58:48 +04:00
xev_loop();
return (0);
}
void
dpy_init(const char *dpyname)
2007-04-27 21:58:48 +04:00
{
int i;
2007-04-27 21:58:48 +04:00
if ((X_Dpy = XOpenDisplay(dpyname)) == NULL)
errx(1, "unable to open display \"%s\"",
XDisplayName(dpyname));
2007-04-27 21:58:48 +04:00
XSetErrorHandler(x_errorhandler);
Doshape = XShapeQueryExtension(X_Dpy, &Shape_ev, &i);
2007-04-27 21:58:48 +04:00
TAILQ_INIT(&Screenq);
}
void
x_setup(void)
{
struct screen_ctx *sc;
struct keybinding *kb;
int i;
Nscreens = ScreenCount(X_Dpy);
for (i = 0; i < (int)Nscreens; i++) {
2007-04-27 21:58:48 +04:00
XMALLOC(sc, struct screen_ctx);
x_setupscreen(sc, i);
TAILQ_INSERT_TAIL(&Screenq, sc, entry);
2007-04-27 21:58:48 +04:00
}
/*
* 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);
2007-04-27 21:58:48 +04:00
}
void
2007-04-27 21:58:48 +04:00
x_setupscreen(struct screen_ctx *sc, u_int which)
{
XColor tmp;
XGCValues gv;
Window *wins, w0, w1;
XWindowAttributes winattr;
XSetWindowAttributes rootattr;
u_int nwins, i;
2007-04-27 21:58:48 +04:00
Curscreen = sc;
2007-04-27 21:58:48 +04:00
sc->display = x_screenname(which);
sc->which = which;
sc->rootwin = RootWindow(X_Dpy, which);
sc->xmax = DisplayWidth(X_Dpy, sc->which);
sc->ymax = DisplayHeight(X_Dpy, sc->which);
XAllocNamedColor(X_Dpy, DefaultColormap(X_Dpy, which),
2007-04-27 21:58:48 +04:00
"black", &sc->fgcolor, &tmp);
XAllocNamedColor(X_Dpy, DefaultColormap(X_Dpy, which),
2007-04-27 21:58:48 +04:00
"#00cc00", &sc->bgcolor, &tmp);
XAllocNamedColor(X_Dpy,DefaultColormap(X_Dpy, which),
2007-04-27 21:58:48 +04:00
"blue", &sc->fccolor, &tmp);
XAllocNamedColor(X_Dpy, DefaultColormap(X_Dpy, which),
2007-04-27 21:58:48 +04:00
"red", &sc->redcolor, &tmp);
XAllocNamedColor(X_Dpy, DefaultColormap(X_Dpy, which),
2007-04-27 21:58:48 +04:00
"#00ccc8", &sc->cyancolor, &tmp);
XAllocNamedColor(X_Dpy, DefaultColormap(X_Dpy, which),
2007-04-27 21:58:48 +04:00
"white", &sc->whitecolor, &tmp);
XAllocNamedColor(X_Dpy, DefaultColormap(X_Dpy, which),
2007-04-27 21:58:48 +04:00
"black", &sc->blackcolor, &tmp);
sc->blackpixl = BlackPixel(X_Dpy, sc->which);
sc->whitepixl = WhitePixel(X_Dpy, sc->which);
2007-04-27 21:58:48 +04:00
sc->bluepixl = sc->fccolor.pixel;
sc->redpixl = sc->redcolor.pixel;
sc->cyanpixl = sc->cyancolor.pixel;
2008-04-16 00:24:41 +04:00
sc->gray = XCreatePixmapFromBitmapData(X_Dpy, sc->rootwin,
gray_bits, gray_width, gray_height,
sc->blackpixl, sc->whitepixl, DefaultDepth(X_Dpy, sc->which));
2007-04-27 21:58:48 +04:00
2008-04-16 00:24:41 +04:00
sc->blue = XCreatePixmapFromBitmapData(X_Dpy, sc->rootwin,
gray_bits, gray_width, gray_height,
sc->bluepixl, sc->whitepixl, DefaultDepth(X_Dpy, sc->which));
2007-04-27 21:58:48 +04:00
2008-04-16 00:24:41 +04:00
sc->red = XCreatePixmapFromBitmapData(X_Dpy, sc->rootwin,
gray_bits, gray_width, gray_height,
sc->redpixl, sc->whitepixl, DefaultDepth(X_Dpy, sc->which));
2007-04-27 21:58:48 +04:00
gv.foreground = sc->blackpixl^sc->whitepixl;
gv.background = sc->whitepixl;
gv.function = GXxor;
gv.line_width = 1;
gv.subwindow_mode = IncludeInferiors;
sc->gc = XCreateGC(X_Dpy, sc->rootwin,
2007-04-27 21:58:48 +04:00
GCForeground|GCBackground|GCFunction|
GCLineWidth|GCSubwindowMode, &gv);
2007-04-27 21:58:48 +04:00
font_init(sc);
conf_font(&Conf);
2007-04-27 21:58:48 +04:00
TAILQ_INIT(&sc->mruq);
/* Initialize menu window. */
menu_init(sc);
2007-04-27 21:58:48 +04:00
/* Deal with existing clients. */
2008-04-16 00:24:41 +04:00
XQueryTree(X_Dpy, sc->rootwin, &w0, &w1, &wins, &nwins);
2007-04-27 21:58:48 +04:00
for (i = 0; i < nwins; i++) {
XGetWindowAttributes(X_Dpy, wins[i], &winattr);
2007-04-27 21:58:48 +04:00
if (winattr.override_redirect ||
winattr.map_state != IsViewable) {
char *name;
XFetchName(X_Dpy, wins[i], &name);
2007-04-27 21:58:48 +04:00
continue;
}
client_new(wins[i], sc, winattr.map_state != IsUnmapped);
}
XFree(wins);
screen_updatestackingorder();
rootattr.event_mask = ChildMask|PropertyChangeMask|EnterWindowMask|
LeaveWindowMask|ColormapChangeMask|ButtonMask;
XChangeWindowAttributes(X_Dpy, sc->rootwin,
2008-05-19 22:53:09 +04:00
CWEventMask, &rootattr);
2007-04-27 21:58:48 +04:00
XSync(X_Dpy, False);
2007-04-27 21:58:48 +04:00
return;
2007-04-27 21:58:48 +04:00
}
char *
x_screenname(int which)
{
char *cp, *dstr, *sn;
size_t snlen;
2007-04-27 21:58:48 +04:00
if (which > 9)
errx(1, "Can't handle more than 9 screens. If you need it, "
"tell <marius@monkey.org>. It's a trivial fix.");
dstr = xstrdup(DisplayString(X_Dpy));
2007-04-27 21:58:48 +04:00
2008-05-19 22:53:09 +04:00
if ((cp = strrchr(dstr, ':')) == NULL)
2007-04-27 21:58:48 +04:00
return (NULL);
2008-05-19 22:53:09 +04:00
if ((cp = strchr(cp, '.')) != NULL)
2007-04-27 21:58:48 +04:00
*cp = '\0';
snlen = strlen(dstr) + 3; /* string, dot, number, null */
sn = (char *)xmalloc(snlen);
snprintf(sn, snlen, "%s.%d", dstr, which);
free(dstr);
return (sn);
}
int
x_errorhandler(Display *dpy, XErrorEvent *e)
{
#ifdef DEBUG
{
char msg[80], number[80], req[80];
XGetErrorText(X_Dpy, e->error_code, msg, sizeof(msg));
2007-04-27 21:58:48 +04:00
snprintf(number, sizeof(number), "%d", e->request_code);
XGetErrorDatabaseText(X_Dpy, "XRequest", number,
2007-04-27 21:58:48 +04:00
"<unknown>", req, sizeof(req));
warnx("%s(0x%x): %s", req, (u_int)e->resourceid, msg);
}
#endif
2008-04-16 00:24:41 +04:00
if (Starting &&
e->error_code == BadAccess &&
e->request_code == X_GrabKey)
2007-04-27 21:58:48 +04:00
errx(1, "root window unavailable - perhaps another "
2008-04-16 00:24:41 +04:00
"wm is running?");
2007-04-27 21:58:48 +04:00
return (0);
}
static void
_sigchld_cb(int which)
{
pid_t pid;
int save_errno = errno;
int status;
2007-04-27 21:58:48 +04:00
2008-04-16 00:24:41 +04:00
/* Collect dead children. */
while ((pid = waitpid(-1, &status, WNOHANG)) > 0 ||
(pid < 0 && errno == EINTR))
2007-04-27 21:58:48 +04:00
;
errno = save_errno;
2007-04-27 21:58:48 +04:00
}
__dead void
usage(void)
{
extern char *__progname;
fprintf(stderr, "usage: %s [-c file] [-d display]\n", __progname);
exit(1);
}