/*-
* Copyright (c) 2001 Jordan DeLong
* All rights reserved.
*
* 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.
* 3. Neither the name of the author nor the names of contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*/
#include "wm.h"
/* list of screen structures, and count of screens */
int screen_count = 0;
screenlist_t screen_list = TAILQ_HEAD_INITIALIZER(screen_list);
/*
* error handler to use while we're trying to init; if errors
* happen here it's probably because someone else (another window
* manager, presumably) selected for SubstructureRedirectMask
* on the root window.
*/
static int init_handler(Display *d, XErrorEvent *e) {
errx(1, "another window manager may be "
"running; exiting now.");
}
/*
* error handler used during normal window manager
* operation. it is expected that we get some BadWindows,
* BadDrawables and such when windows exit; nonexpected
* stuff is logged to stderr.
*/
static int error_handler(Display *d, XErrorEvent *event) {
if (event->error_code != BadWindow
&& event->error_code != BadMatch
&& event->request_code != X_GetGeometry
&& event->error_code != BadDrawable)
trace("unexpected Xlib error; error code %d,"
"request code %d, minor %d",
event->error_code, event->request_code,
event->minor_code);
return 0;
}
/* this starts us up managing windows that already exist when we start */
static void manage_existing_windows(screen_t *screen) {
XWindowAttributes attr;
Window wroot, wparent, *children;
int nchilds, i;
client_t *client;
XGrabServer(display);
XQueryTree(display, screen->root, &wroot, &wparent, &children, &nchilds);
for (i = 0; i < nchilds; i++) {
XGetWindowAttributes(display, children[i], &attr);
if (attr.override_redirect || attr.map_state != IsViewable)
continue;
client = client_add(screen, children[i], NULL, NULL);
if (!client)
continue;
client->flags.unmap_from_reparent = 1;
}
XUngrabServer(display);
}
/* manage a screen */
static screen_t *screen_manage(int num) {
XSetWindowAttributes wattr;
XGCValues gcvalues;
XColor clr;
screen_t *screen;
Window dumroot;
int dumx, dumy, dumbord, dumdepth;
int events;
screen = calloc(1, sizeof(screen_t));
screen->num = num;
screen->root = RootWindow(display, screen->num);
/* get root window dimensions */
XGetGeometry(display, screen->root, &dumroot, &dumx, &dumy, &screen->width, &screen->height,
&dumbord, &dumdepth);
/* we sync after this so we don't accidently change the root window cursor if a manager is running */
events = SubstructureNotifyMask | SubstructureRedirectMask | ButtonPressMask | ButtonReleaseMask;
XSelectInput(display, screen->root, events);
XSync(display, 0);
XDefineCursor(display, screen->root, cursor_default);
XSaveContext(display, screen->root, root_context, (XPointer) screen);
/* get a window to focus if none of the clients can get it */
wattr.override_redirect = 1;
screen->nofocus = XCreateWindow(display, screen->root, -10, -10, 4, 4, 0, 0,
InputOnly, CopyFromParent, CWOverrideRedirect, &wattr);
XMapWindow(display, screen->nofocus);
/* get colors for the screen */
if (!options.linefgclr || !XParseColor(display, DefaultColormap(display, screen->num), options.linefgclr, &clr)) {
screen->linefg = (1 << DefaultDepth(display, screen->num)) - 1;
} else {
XAllocColor(display, DefaultColormap(display, screen->num), &clr);
screen->linefg = clr.pixel;
}
if (!options.titleclr || !XParseColor(display, DefaultColormap(display, screen->num), options.titleclr, &clr))
clr.pixel = BlackPixel(display, screen->num);
else
XAllocColor(display, DefaultColormap(display, screen->num), &clr);
/* get graphics contexts */
gcvalues.function = GXxor;
gcvalues.foreground = screen->linefg;
gcvalues.background = BlackPixel(display, screen->num);
gcvalues.subwindow_mode = IncludeInferiors;
gcvalues.line_width = options.linewidth;
screen->xorgc = XCreateGC(display, screen->root, GCForeground | GCBackground
| GCSubwindowMode | GCFunction | GCLineWidth, &gcvalues);
gcvalues.function = GXcopy;
gcvalues.foreground = clr.pixel;
gcvalues.background = WhitePixel(display, screen->num);
#ifdef I18N
screen->titlegc = XCreateGC(display, screen->root, GCForeground | GCBackground
| GCFunction, &gcvalues);
#else
gcvalues.font = titlefont->fid;
screen->titlegc = XCreateGC(display, screen->root, GCForeground | GCBackground
| GCFont | GCFunction, &gcvalues);
#endif
return screen;
}
/* the main initialization routine */
void screen_init() {
screen_t *screen;
int dum, i;
screen_count = ScreenCount(display);
XSetErrorHandler(init_handler);
/*
* get cursors, unique contexts and intern all
* the global atoms.
*/
cursor_default = XCreateFontCursor(display, XC_left_ptr);
cursor_move = XCreateFontCursor(display, XC_fleur);
cursor_place = XCreateFontCursor(display, XC_bottom_right_corner);
client_context = XUniqueContext();
root_context = XUniqueContext();
decor_context = XUniqueContext();
plugin_context = XUniqueContext();
XInternAtoms(display, atom_names, NUM_ATOMS, 0, atoms);
/* we need this before screen_manage calls */
decor_init();
/* manage all screens */
for (i = 0; i < screen_count; i++) {
screen = screen_manage(i);
TAILQ_INSERT_HEAD(&screen_list, screen, s_list);
}
/*
* make sure no errors have happened yet, and
* switch to the real error handler used during
* normal program operation.
*/
XSync(display, 0);
XSetErrorHandler(error_handler);
XSync(display, 0);
if (pixmap_getpixmaps() != 0)
errx(1, "unable to get pixmaps");
dgroup_learn_space();
/*
* create desktops and grab keys for all
* the managed screens
*/
TAILQ_FOREACH_REVERSE(screen, &screen_list, screenlist, s_list) {
TAILQ_INIT(&screen->s_desklist);
if (desktop_create(screen, options.desktop_width, options.desktop_height,
options.desktop_count) == -1)
errx(1, "unable to add requested number of "
"desktops to screen %d", screen->num);
screen->desktop = TAILQ_FIRST(&screen->s_desklist);
keys_grab(screen);
}
/* see if we have the shape extension */
if (XShapeQueryExtension(display, &shape_base, &dum) == 0)
errx(1, "shape extension not found; shape is "
"required to run this windowmanager");
}
/* manage clients that already exist */
void screen_manage_existing() {
screen_t *screen;
TAILQ_FOREACH(screen, &screen_list, s_list)
manage_existing_windows(screen);
}
/* shutdown routine */
void screen_shutdown() {
screen_t *screen, *next;
/* kill all screens */
screen = TAILQ_FIRST(&screen_list);
while (screen) {
/* remove screen data */
XDestroyWindow(display, screen->nofocus);
XFreeGC(display, screen->xorgc);
XFreeGC(display, screen->titlegc);
/* get rid of all desktops */
desktop_remove(screen);
/* free the screen_t */
next = TAILQ_NEXT(screen, s_list);
free(screen);
screen = next;
}
TAILQ_INIT(&screen_list);
/*
* make sure input focus is on the root
* window before we leave.
*/
XSetInputFocus(display, PointerRoot, RevertToPointerRoot,
CurrentTime);
XSync(display, 0);
}
syntax highlighted by Code2HTML, v. 0.9.1