wmii/cmd/wm/wm.c
2005-12-13 23:48:52 +02:00

809 lines
21 KiB
C

/*
* (C)opyright MMIV-MMV Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details.
*/
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <X11/cursorfont.h>
#include <X11/Xproto.h>
#include <X11/keysym.h>
#include <X11/Xatom.h>
#include <X11/Xproto.h>
#include "wm.h"
static XRectangle initial_rect;
static int other_wm_running;
static int (*x_error_handler) (Display *, XErrorEvent *);
static void new_page(void *obj, char *arg);
static void _select_page(void *obj, char *arg);
static void _destroy_page(void *obj, char *arg);
static void quit(void *obj, char *arg);
static void _attach_client(void *obj, char *arg);
static void _detach_client(void *obj, char *arg);
static void _close_client(void *obj, char *arg);
static void pager(void *obj, char *arg);
static void detached_clients(void *obj, char *arg);
static void reserve_area(void *obj, char *arg);
/* action table for /ctl namespace */
Action wm_acttbl[] = {
{"new", new_page},
{"destroy", _destroy_page},
{"select", _select_page},
{"attach", _attach_client},
{"detach", _detach_client},
{"close", _close_client},
{"quit", quit},
{"pager", pager},
{"detached_clients", detached_clients},
{"reserve_area", reserve_area},
{0, 0}
};
char *version[] = {
"wmiiwm - window manager improved 2 - " VERSION "\n"
" (C)opyright MMIV-MMV Anselm R. Garbe\n", 0
};
static void usage()
{
fprintf(stderr, "%s",
"usage: wmiiwm -s <socket file> [-c] [-v]\n"
" -s socket file\n"
" -c checks if another WM is already running\n"
" -v version info\n");
exit(1);
}
void run_action(File * f, void *obj, Action * acttbl)
{
int i;
size_t len;
if (!f->content)
return;
for (i = 0; acttbl[i].name; i++) {
len = strlen(acttbl[i].name);
if (!strncmp(acttbl[i].name, (char *) f->content, len)) {
if (f->size > len)
acttbl[i].func(obj, &((char *) f->content)[len + 1]);
else
acttbl[i].func(obj, 0);
return;
break;
}
}
fprintf(stderr, "wmiiwm: unknown action '%s'\n"
" or invalid ctl device\n", (char *) f->content);
}
static void quit(void *obj, char *arg)
{
ixps->runlevel = SHUTDOWN;
}
void invoke_wm_event(File * f)
{
if (!f->content)
return;
wmii_spawn(dpy, f->content);
}
static void
scale_rect(XRectangle * from_dim, XRectangle * to_dim,
XRectangle * src, XRectangle * tgt)
{
double wfact = (double) to_dim->width / (double) from_dim->width;
double hfact = (double) to_dim->height / (double) from_dim->height;
tgt->x = to_dim->x + (src->x * wfact);
tgt->y = to_dim->y + (src->y * hfact);
tgt->width = (src->width * wfact);
tgt->height = (src->height * hfact);
if (tgt->width < 1)
tgt->width = 1;
if (tgt->height < 1)
tgt->height = 1;
}
static void iter_draw_pager_frame(void *item, void *aux)
{
Draw *d = aux;
Frame *f = (Frame *)item;
if (f == get_sel_frame_of_area(f->area)) {
d->bg = blitz_loadcolor(dpy, screen_num, def[WM_SEL_BG_COLOR]->content);
d->fg = blitz_loadcolor(dpy, screen_num, def[WM_SEL_FG_COLOR]->content);
d->border = blitz_loadcolor(dpy, screen_num, def[WM_SEL_BORDER_COLOR]->content);
} else {
d->bg = blitz_loadcolor(dpy, screen_num, def[WM_NORM_BG_COLOR]->content);
d->fg = blitz_loadcolor(dpy, screen_num, def[WM_NORM_FG_COLOR]->content);
d->border = blitz_loadcolor(dpy, screen_num, def[WM_NORM_BORDER_COLOR]->content);
}
d->data = ((Client *)cext_stack_get_top_item(&f->clients))->file[C_NAME]->content;
scale_rect(&rect, &initial_rect, &f->rect, &d->rect);
blitz_drawlabel(dpy, d);
XSync(dpy, False); /* do not clear upwards */
}
static void draw_pager_area(void *item, void *aux)
{
Area *a = (Area *)item;
cext_stack_iterate_up(a->layout->get_frames(a), aux, iter_draw_pager_frame);
}
static void draw_pager_page(Page *p, Draw *d)
{
char name[4];
initial_rect = d->rect;
if (p == cext_stack_get_top_item(&pages)) {
d->bg = blitz_loadcolor(dpy, screen_num, def[WM_SEL_BG_COLOR]->content);
d->fg = blitz_loadcolor(dpy, screen_num, def[WM_SEL_FG_COLOR]->content);
d->border = blitz_loadcolor(dpy, screen_num, def[WM_SEL_BORDER_COLOR]->content);
} else {
d->bg = blitz_loadcolor(dpy, screen_num, def[WM_NORM_BG_COLOR]->content);
d->fg = blitz_loadcolor(dpy, screen_num, def[WM_NORM_FG_COLOR]->content);
d->border = blitz_loadcolor(dpy, screen_num, def[WM_NORM_BORDER_COLOR]->content);
}
snprintf(name, sizeof(name), "%d", cext_list_get_item_index(&pages, p));
d->data = name;
blitz_drawlabel(dpy, d);
XSync(dpy, False);
cext_stack_iterate_up(&p->areas, d, draw_pager_area);
}
static void draw_pager()
{
Draw d = { 0 };
unsigned int ic, ir, tw, th, rows, cols, size;
int i = 0;
int dx;
Page *p;
blitz_getbasegeometry(&pages, &size, &cols, &rows);
dx = (cols - 1) * GAP; /* GAPpx space */
tw = (rect.width - dx) / cols;
th = ((double) tw / rect.width) * rect.height;
d.drawable = transient;
d.gc = transient_gc;
d.font = font;
for (ir = 0; ir < rows; ir++) {
for (ic = 0; ic < cols; ic++) {
d.rect.x = ic * tw + (ic * GAP);
d.rect.width = tw;
if (rows == 1)
d.rect.y = 0;
else
d.rect.y = ir * (rect.height - th) / (rows - 1);
d.rect.height = th;
if (!(p = cext_list_get_item(&pages, i)))
return;
draw_pager_page(p, &d);
i++;
}
}
}
static Page *xy_to_pager_page(int x, int y)
{
unsigned int ic, ir, tw, th, rows, cols, size;
int i = 0;
int dx;
XRectangle r;
Page *p;
if (!cext_sizeof_container(&pages))
return nil;
blitz_getbasegeometry(&pages, &size, &cols, &rows);
dx = (cols - 1) * GAP; /* GAPpx space */
tw = (rect.width - dx) / cols;
th = ((double) tw / rect.width) * rect.height;
for (ir = 0; ir < rows; ir++) {
for (ic = 0; ic < cols; ic++) {
r.x = ic * tw + (ic * GAP);
r.width = tw;
if (rows == 1)
r.y = 0;
else
r.y = ir * (rect.height - th) / (rows - 1);
r.height = th;
if (!(p = cext_list_get_item(&pages, i)))
return nil;
if (blitz_ispointinrect(x, y, &r))
return p;
i++;
}
}
return nil;
}
static int handle_kpress(XKeyEvent * e)
{
KeySym ksym = XKeycodeToKeysym(dpy, e->keycode, 0);
if (ksym >= XK_0 && ksym <= XK_9)
return ksym - XK_0;
else if (ksym >= XK_a && ksym <= XK_z)
return 10 + ksym - XK_a;
return -1;
}
static void pager(void *obj, char *arg)
{
XEvent ev;
int i;
if (!cext_sizeof_container(&pages))
return;
XClearWindow(dpy, transient);
XMapRaised(dpy, transient);
draw_pager();
while (XGrabKeyboard(dpy, transient, True, GrabModeAsync, GrabModeAsync, CurrentTime) != GrabSuccess)
usleep(20000);
while (XGrabPointer(dpy, transient, False, ButtonPressMask, GrabModeAsync,
GrabModeAsync, None, normal_cursor, CurrentTime) != GrabSuccess)
usleep(20000);
for (;;) {
while (!XCheckWindowEvent(dpy, transient, ButtonPressMask | KeyPressMask, &ev)) {
usleep(20000);
continue;
}
switch (ev.type) {
case KeyPress:
XUnmapWindow(dpy, transient);
if ((i = handle_kpress(&ev.xkey)) != -1)
if (i < cext_sizeof_container(&pages))
sel_page(cext_list_get_item(&pages, i));
XUngrabKeyboard(dpy, CurrentTime);
XUngrabPointer(dpy, CurrentTime /* ev.xbutton.time */ );
return;
break;
case ButtonPress:
XUnmapWindow(dpy, transient);
if (ev.xbutton.button == Button1) {
Page *p = xy_to_pager_page(ev.xbutton.x, ev.xbutton.y);
if (p)
sel_page(p);
}
XUngrabKeyboard(dpy, CurrentTime);
XUngrabPointer(dpy, CurrentTime /* ev.xbutton.time */ );
return;
break;
}
}
}
static void draw_detached_clients()
{
unsigned int i, ic, ir, tw, th, rows, cols, size;
int dx, dy;
if (!cext_sizeof_container(&detached))
return;
blitz_getbasegeometry(&detached, &size, &cols, &rows);
dx = (cols - 1) * GAP; /* GAPpx space */
dy = (rows - 1) * GAP; /* GAPpx space */
tw = (rect.width - dx) / cols;
th = (rect.height - dy) / rows;
XClearWindow(dpy, transient);
XMapRaised(dpy, transient);
i = 0;
for (ir = 0; ir < rows; ir++) {
for (ic = 0; ic < cols; ic++) {
Client *c = cext_list_get_item(&detached, i++);
XRectangle cr;
if (!c)
return;
cr.x = ic * tw + (ic * GAP);
cr.y = ir * th + (ir * GAP);
cr.width = tw;
cr.height = th;
XMoveResizeWindow(dpy, c->win, cr.x, cr.y, cr.width,
cr.height);
configure_client(c);
show_client(c);
XRaiseWindow(dpy, c->win);
grab_client(c, AnyModifier, AnyButton);
XSync(dpy, False);
}
}
}
static void reserve_area(void *obj, char *arg)
{
if (arg && strrchr(arg, ',')) {
XRectangle r;
blitz_strtorect(&rect, &r, arg);
}
}
static void detached_clients(void *obj, char *arg)
{
XEvent ev;
int i, n;
size_t size = cext_sizeof_container(&detached);
Client *c;
if (!size)
return;
XClearWindow(dpy, transient);
XMapRaised(dpy, transient);
draw_detached_clients();
while (XGrabKeyboard(dpy, transient, True, GrabModeAsync, GrabModeAsync, CurrentTime) != GrabSuccess)
usleep(20000);
for (;;) {
while (!XCheckMaskEvent(dpy, ButtonPressMask | KeyPressMask, &ev)) {
usleep(20000);
continue;
}
switch (ev.type) {
case KeyPress:
XUnmapWindow(dpy, transient);
if ((n = handle_kpress(&ev.xkey)) != -1) {
for (i = 0; i < size; i++)
hide_client(cext_list_get_item(&detached, i));
if (n - 1 < i) {
c = cext_list_get_item(&detached, n);
cext_detach_item(&detached, c);
attach_client(c);
}
} else {
for (i = 0; i < size; i++)
hide_client(cext_list_get_item(&detached, i));
}
XUngrabKeyboard(dpy, CurrentTime);
return;
break;
case ButtonPress:
if (ev.xbutton.button == Button1) {
XUnmapWindow(dpy, transient);
for (i = 0; i < size; i++)
hide_client(cext_list_get_item(&detached, i));
if ((c = win_to_client(ev.xbutton.window))) {
cext_detach_item(&detached, c);
attach_client(c);
}
}
XUngrabKeyboard(dpy, CurrentTime);
return;
break;
}
}
}
static void _close_client(void *obj, char *arg)
{
Frame *f = get_sel_frame();
if (f)
close_client(cext_stack_get_top_item(&f->clients));
}
static void _attach_client(void *obj, char *arg)
{
if (cext_sizeof_container(&detached)) {
Client *c = cext_stack_get_top_item(&detached);
cext_detach_item(&detached, c);
attach_client(c);
}
}
static void _detach_client(void *obj, char *arg)
{
Client *c = get_sel_client();
if (c)
detach_client(c, False);
}
static void _select_page(void *obj, char *arg)
{
Page *p = get_sel_page();
if (!p || !arg)
return;
if (!strncmp(arg, "prev", 5))
p = cext_list_get_prev_item(&pages, p);
else if (!strncmp(arg, "next", 5))
p = cext_list_get_next_item(&pages, p);
else
p = cext_list_get_item(&pages, blitz_strtonum(arg, 0, cext_sizeof_container(&pages) - 1));
sel_page(p);
}
static void _destroy_page(void *obj, char *arg)
{
Page *p = get_sel_page();
if (p)
destroy_page(p);
}
static void new_page(void *obj, char *arg)
{
Page *p = get_sel_page();
if (p)
hide_page(p);
alloc_page();
}
static int comp_client_win(void *pattern, void *client)
{
Window w = *(Window *)pattern;
Client *c = client;
return c->win == w;
}
Client *win_to_client(Window w)
{
return cext_find_item(&clients, &w, comp_client_win);
}
void scan_wins()
{
int i;
unsigned int num;
Window *wins;
XWindowAttributes wa;
Window d1, d2;
Client *c;
if (XQueryTree(dpy, root, &d1, &d2, &wins, &num)) {
for (i = 0; i < num; i++) {
if (!XGetWindowAttributes(dpy, wins[i], &wa))
continue;
if (wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1))
continue;
if (wa.map_state == IsViewable) {
c = alloc_client(wins[i]);
init_client(c, &wa);
attach_client(c);
c->ignore_unmap++; /* was viewable already */
}
}
}
if (wins)
XFree(wins);
}
void *get_func(void *acttbl[][2], int rows, char *fname)
{
int i;
for (i = 0; i < rows; i++) {
if (!strncmp((char *) acttbl[i][0], fname, MAX_BUF)) {
return acttbl[i][1];
}
}
return 0;
}
int win_proto(Window w)
{
Atom *protocols;
long res;
int protos = 0;
int i;
res = wmii_property(dpy, w, wm_protocols, XA_ATOM, 20L, ((unsigned char **) &protocols));
if (res <= 0) {
return protos;
}
for (i = 0; i < res; i++) {
if (protocols[i] == wm_delete) {
protos |= PROTO_DEL;
}
}
free((char *) protocols);
return protos;
}
int win_state(Window w)
{
/* state hints */
XWMHints *hints = XGetWMHints(dpy, w);
int res;
long *prop = 0;
if (wmii_property(dpy, w, wm_state, wm_state, 2L, ((unsigned char **) &prop)) > 0) {
res = (int) *prop;
free((long *) prop);
} else {
res = hints ? hints->initial_state : NormalState;
}
if (hints) {
free(hints);
}
return res;
}
static void iter_update_area(void *area, void *aux)
{
Area *a = area;
a->layout->arrange(a);
}
static void iter_update_page(void *page, void *aux)
{
Page *p = page;
cext_list_iterate(&p->areas, nil, iter_update_area);
}
void handle_before_read(IXPServer *s, File *f)
{
char buf[64];
if (f == def[WM_AREA_GEOMETRY]) {
snprintf(buf, 64, "%d,%d,%d,%d", area_rect.x, area_rect.y, area_rect.width, area_rect.height);
if (f->content)
free(f->content);
f->content = cext_estrdup(buf);
f->size = strlen(buf);
}
}
void handle_after_write(IXPServer * s, File * f)
{
if (f == def[WM_CTL])
run_action(f, 0, wm_acttbl);
else if (f == def[WM_TRANS_COLOR]) {
unsigned long col[1];
col[0] = xorcolor.pixel;
XFreeColors(dpy, DefaultColormap(dpy, screen_num), col, 1, 0);
XAllocNamedColor(dpy, DefaultColormap(dpy, screen_num),
def[WM_TRANS_COLOR]->content,
&xorcolor, &xorcolor);
XSetForeground(dpy, xorgc, xorcolor.pixel);
}
else if (f == def[WM_FONT]) {
XFreeFont(dpy, font);
font = blitz_getfont(dpy, def[WM_FONT]->content);
}
else if (f == def[WM_AREA_GEOMETRY]) {
char *geom = def[WM_AREA_GEOMETRY]->content;
if (geom && strrchr(geom, ',')) {
area_rect = rect;
blitz_strtorect(&rect, &area_rect, geom);
cext_list_iterate(&pages, nil, iter_update_page);
}
}
check_event(0);
}
static void init_atoms()
{
wm_state = XInternAtom(dpy, "WM_STATE", False);
wm_change_state = XInternAtom(dpy, "WM_CHANGE_STATE", False);
wm_protocols = XInternAtom(dpy, "WM_PROTOCOLS", False);
wm_delete = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
motif_wm_hints = XInternAtom(dpy, "_MOTIF_WM_HINTS", False);
net_wm_desktop = XInternAtom(dpy, "_NET_WM_DESKTOP", False);
}
static void init_cursors()
{
normal_cursor = XCreateFontCursor(dpy, XC_left_ptr);
resize_cursor = XCreateFontCursor(dpy, XC_sizing);
move_cursor = XCreateFontCursor(dpy, XC_fleur);
drag_cursor = XCreateFontCursor(dpy, XC_cross);
w_cursor = XCreateFontCursor(dpy, XC_left_side);
e_cursor = XCreateFontCursor(dpy, XC_right_side);
n_cursor = XCreateFontCursor(dpy, XC_top_side);
s_cursor = XCreateFontCursor(dpy, XC_bottom_side);
nw_cursor = XCreateFontCursor(dpy, XC_top_left_corner);
ne_cursor = XCreateFontCursor(dpy, XC_top_right_corner);
sw_cursor = XCreateFontCursor(dpy, XC_bottom_left_corner);
se_cursor = XCreateFontCursor(dpy, XC_bottom_right_corner);
}
static void init_default()
{
def[WM_DETACHED_FRAME] = ixp_create(ixps, "/detached/frame");
def[WM_DETACHED_CLIENT] = ixp_create(ixps, "/detached/client");
def[WM_TRANS_COLOR] = wmii_create_ixpfile(ixps, "/default/transcolor", BLITZ_SEL_FG_COLOR);
def[WM_TRANS_COLOR]->after_write = handle_after_write;
def[WM_AREA_GEOMETRY] = wmii_create_ixpfile(ixps, "/default/area/geometry", BLITZ_SEL_FG_COLOR);
def[WM_AREA_GEOMETRY]->after_write = handle_after_write;
def[WM_AREA_GEOMETRY]->before_read = handle_before_read;
def[WM_SEL_BG_COLOR] = wmii_create_ixpfile(ixps, "/default/sstyle/bgcolor", BLITZ_SEL_BG_COLOR);
def[WM_SEL_FG_COLOR] = wmii_create_ixpfile(ixps, "/default/sstyle/fgcolor", BLITZ_SEL_FG_COLOR);
def[WM_SEL_BORDER_COLOR] = wmii_create_ixpfile(ixps, "/default/sstyle/bordercolor", BLITZ_SEL_BORDER_COLOR);
def[WM_NORM_BG_COLOR] = wmii_create_ixpfile(ixps, "/default/nstyle/bgcolor", BLITZ_NORM_BG_COLOR);
def[WM_NORM_FG_COLOR] = wmii_create_ixpfile(ixps, "/default/nstyle/fgcolor", BLITZ_NORM_FG_COLOR);
def[WM_NORM_BORDER_COLOR] = wmii_create_ixpfile(ixps, "/default/nstyle/bordercolor", BLITZ_NORM_BORDER_COLOR);
def[WM_FONT] = wmii_create_ixpfile(ixps, "/default/font", BLITZ_FONT);
def[WM_FONT]->after_write = handle_after_write;
def[WM_SNAP_VALUE] = wmii_create_ixpfile(ixps, "/default/snapvalue", "20"); /* 0..1000 */
def[WM_BORDER] = wmii_create_ixpfile(ixps, "/default/border", "1");
def[WM_TAB] = wmii_create_ixpfile(ixps, "/default/tab", "1");
def[WM_HANDLE_INC] = wmii_create_ixpfile(ixps, "/default/handleinc", "1");
def[WM_LOCKED] = wmii_create_ixpfile(ixps, "/default/locked", "1");
def[WM_LAYOUT] = wmii_create_ixpfile(ixps, "/default/layout", LAYOUT);
def[WM_SEL_PAGE] = ixp_create(ixps, "/sel");
def[WM_EVENT_PAGE_UPDATE] = ixp_create(ixps, "/event/pageupdate");
def[WM_EVENT_CLIENT_UPDATE] = ixp_create(ixps, "/event/clientupdate");
def[WM_EVENT_B1PRESS] = ixp_create(ixps, "/default/event/b1press");
def[WM_EVENT_B2PRESS] = ixp_create(ixps, "/default/event/b2press");
def[WM_EVENT_B3PRESS] = ixp_create(ixps, "/default/event/b3press");
def[WM_EVENT_B4PRESS] = ixp_create(ixps, "/default/event/b4press");
def[WM_EVENT_B5PRESS] = ixp_create(ixps, "/default/event/b5press");
}
static void init_screen()
{
XGCValues gcv;
XSetWindowAttributes wa;
XAllocNamedColor(dpy, DefaultColormap(dpy, screen_num),
def[WM_TRANS_COLOR]->content,
&xorcolor, &xorcolor);
gcv.subwindow_mode = IncludeInferiors;
gcv.function = GXxor;
gcv.foreground = xorcolor.pixel;
gcv.line_width = 4;
gcv.plane_mask = AllPlanes;
gcv.graphics_exposures = False;
xorgc = XCreateGC(dpy, root, GCForeground | GCGraphicsExposures
| GCFunction | GCSubwindowMode | GCLineWidth
| GCPlaneMask, &gcv);
rect.x = rect.y = 0;
rect.width = DisplayWidth(dpy, screen_num);
rect.height = DisplayHeight(dpy, screen_num);
area_rect = rect;
wa.override_redirect = 1;
wa.background_pixmap = ParentRelative;
wa.event_mask = ExposureMask | ButtonPressMask;
transient = XCreateWindow(dpy, root, 0, 0, rect.width, rect.height, 0, DefaultDepth(dpy, screen_num),
CopyFromParent, DefaultVisual(dpy, screen_num),
CWOverrideRedirect | CWBackPixmap | CWEventMask , &wa);
XSync(dpy, False);
transient_gc = XCreateGC(dpy, transient, 0, 0);
XDefineCursor(dpy, transient, normal_cursor);
XDefineCursor(dpy, root, normal_cursor);
}
/*
* There's no way to check accesses to destroyed windows, thus
* those cases are ignored (especially on UnmapNotify's).
* Other types of errors call Xlib's default error handler, which
* calls exit().
*/
static int wmii_error_handler(Display * dpy, XErrorEvent * error)
{
if (error->error_code == BadWindow
|| (error->request_code == X_SetInputFocus && error->error_code == BadMatch)
|| (error->request_code == X_PolyText8 && error->error_code == BadDrawable)
|| (error->request_code == X_PolyFillRectangle && error->error_code == BadDrawable)
|| (error->request_code == X_PolySegment && error->error_code == BadDrawable)
|| (error->request_code == X_ConfigureWindow && error->error_code == BadMatch))
return 0;
fprintf(stderr, "%s", "wmiiwm: fatal error");
return x_error_handler(dpy, error); /* calls exit() */
}
/*
* Startup Error handler to check if another window manager
* is already running.
*/
static int startup_error_handler(Display * dpy, XErrorEvent * error)
{
other_wm_running = 1;
return -1;
}
static void clean_client_up(void *item, void *aux)
{
detach_client(item, False);
}
static void cleanup()
{
cext_list_iterate(&clients, nil, clean_client_up);
XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
}
int main(int argc, char *argv[])
{
int i;
int checkwm = 0;
char *sockfile = 0;
/* command line args */
if (argc > 1) {
for (i = 1; (i < argc) && (argv[i][0] == '-'); i++) {
switch (argv[i][1]) {
case 'v':
fprintf(stdout, "%s", version[0]);
exit(0);
break;
case 'c':
checkwm = 1;
break;
case 's':
if (i + 1 < argc)
sockfile = argv[++i];
else
usage();
break;
default:
usage();
break;
}
}
}
dpy = XOpenDisplay(0);
if (!dpy) {
fprintf(stderr, "%s", "wmiiwm: cannot open display\n");
exit(1);
}
screen_num = DefaultScreen(dpy);
root = RootWindow(dpy, screen_num);
/* check if another WM is already running */
other_wm_running = 0;
XSetErrorHandler(startup_error_handler);
/* this causes an error if some other WM is running */
XSelectInput(dpy, root, ROOT_MASK);
XSync(dpy, False);
if (other_wm_running) {
fprintf(stderr,
"wmiiwm: another window manager is already running\n");
exit(1);
}
if (checkwm) {
XCloseDisplay(dpy);
exit(0);
}
XSetErrorHandler(0);
x_error_handler = XSetErrorHandler(wmii_error_handler);
ixps = wmii_setup_server(sockfile);
init_event_hander();
if (!(def[WM_CTL] = ixp_create(ixps, "/ctl"))) {
perror("wmiiwm: cannot connect IXP server");
exit(1);
}
def[WM_CTL]->after_write = handle_after_write;
detached.list = detached.stack = 0;
pages.list = pages.stack = 0;
areas.list = areas.stack = 0;
frames.list = frames.stack = 0;
clients.list = clients.stack = 0;
layouts.list = layouts.stack = 0;
init_atoms();
init_cursors();
init_default();
font = blitz_getfont(dpy, def[WM_FONT]->content);
wmii_init_lock_modifiers(dpy, &valid_mask, &num_lock_mask);
init_screen();
init_layouts();
scan_wins();
/* main event loop */
run_server_with_fd_support(ixps, ConnectionNumber(dpy), check_event, 0);
cleanup();
/* deinit_server(ixps);*/
XCloseDisplay(dpy);
return 0;
}