/*
* BadWM - minimalistic window manager for the X Window System
* Copyright (C) Robert Annessi <robert@annessi.at>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "include/BadWM.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <X11/cursorfont.h>
#include <stdio.h>
#include "include/config.h"
Display *dpy;
int num_screens;
ScreenInfo *screens;
ScreenInfo *current_screen;
Client *current = NULL;
Window initialising = None;
XFontStruct *font;
Client *head_client;
Atom xa_wm_state;
Atom xa_wm_change_state;
Atom xa_wm_protos;
Atom xa_wm_delete;
Atom xa_wm_cmapwins;
Cursor arrow_curs;
Cursor move_curs;
Cursor resize_cursors[8];
const char *opt_display = "";
const char *opt_font = DEF_FONT;
const char **opt_term = NULL;
int opt_bw = DEF_BW;
int vdesk = KEY_TO_VDESK(XK_1);
int have_shape, shape_event;
int quitting = 0;
unsigned int numlockmask = 0;
static void *xmalloc(size_t size);
static void *xmalloc(size_t size) {
void *ptr = malloc(size);
if (!ptr) {
exit(1);
}
return ptr;
}
int main(int argc, char *argv[]) {
struct sigaction act;
XEvent ev;
int c;
int i;
initstr();
while(1)
{
#ifdef DEBUG
c = getopt(argc, argv, "d:vh");
#else
c = getopt(argc, argv, "vh");
#endif
if (c == -1)
break;
switch(c)
{
#ifdef DEBUG
case 'd':
config.global->debug = is_int(optarg);
break;
#endif
case 'v':
printf(PACKAGE_NAME" Version "VERSION"\n");
exit(0);
break;
case 'h':
printf("See the manpage. man 1 "PACKAGE_NAME"\n");
exit(0);
break;
default:
printf("-h for more info!\n");
exit(1);
break;
}
}
act.sa_handler = handle_signal;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGTERM, &act, NULL);
sigaction(SIGINT, &act, NULL);
sigaction(SIGHUP, &act, NULL);
setconf();
setup_display();
have_shape = XShapeQueryExtension(dpy, &shape_event, &i);
/* main event loop here */
for (;;) {
XNextEvent(dpy, &ev);
switch (ev.type) {
case KeyPress:
handle_key_event(&ev.xkey); break;
case ButtonPress:
handle_button_event(&ev.xbutton); break;
case ConfigureRequest:
handle_configure_request(&ev.xconfigurerequest); break;
case MapRequest:
handle_map_request(&ev.xmaprequest); break;
case ClientMessage:
handle_client_message(&ev.xclient); break;
case EnterNotify:
handle_enter_event(&ev.xcrossing); break;
case PropertyNotify:
handle_property_change(&ev.xproperty); break;
case UnmapNotify:
handle_unmap_event(&ev.xunmap); break;
default:
if (have_shape && ev.type == shape_event) {
handle_shape_event((XShapeEvent *)&ev);
}
break;
}
}
return 1;
}
void setup_display() {
XGCValues gv;
XSetWindowAttributes attr;
XColor dummy;
XModifierKeymap *modmap;
KeySym *keysym;
/* used in scanning windows (XQueryTree) */
unsigned int i, j, nwins;
Window dw1, dw2, *wins;
XWindowAttributes winattr;
dpy = XOpenDisplay(opt_display);
if (!dpy) {
fprintf(stderr, "can't open display %s\n", opt_display);
exit(2);
}
XSetErrorHandler(handle_xerror);
xa_wm_state = XInternAtom(dpy, "WM_STATE", False);
xa_wm_change_state = XInternAtom(dpy, "WM_CHANGE_STATE", False);
xa_wm_protos = XInternAtom(dpy, "WM_PROTOCOLS", False);
xa_wm_delete = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
font = XLoadQueryFont(dpy, opt_font);
if (!font) font = XLoadQueryFont(dpy, DEF_FONT);
arrow_curs = XCreateFontCursor(dpy, XC_top_left_arrow);
move_curs = XCreateFontCursor(dpy, XC_fleur);
resize_cursors[NorthWest] = XCreateFontCursor(dpy,XC_top_left_corner);
resize_cursors[North] = XCreateFontCursor(dpy,XC_top_side);
resize_cursors[NorthEast] = XCreateFontCursor(dpy,XC_top_right_corner);
resize_cursors[East] = XCreateFontCursor(dpy,XC_right_side);
resize_cursors[SouthEast] = XCreateFontCursor(dpy,XC_bottom_right_corner);
resize_cursors[South] = XCreateFontCursor(dpy,XC_bottom_side);
resize_cursors[SouthWest] = XCreateFontCursor(dpy,XC_bottom_left_corner);
resize_cursors[West] = XCreateFontCursor(dpy,XC_left_side);
/* find out which modifier is NumLock - we'll use this when grabbing
* every combination of modifiers we can think of */
modmap = XGetModifierMapping(dpy);
for (i = 0; i < 8; i++) {
for (j = 0; j < modmap->max_keypermod; j++) {
if (modmap->modifiermap[i*modmap->max_keypermod+j] == XKeysymToKeycode(dpy, XK_Num_Lock)) {
numlockmask = (1<<i);
#ifdef DEBUG
bad_debug(1,"setup_display() : XK_Num_Lock is (1<<0x%02x)\n", i);
#endif
}
}
}
XFreeModifiermap(modmap);
/* set up GC parameters - same for each screen */
gv.function = GXinvert;
gv.subwindow_mode = IncludeInferiors;
gv.line_width = opt_bw;
gv.font = font->fid;
/* set up root window attributes - same for each screen */
attr.event_mask = ChildMask | PropertyChangeMask | EnterWindowMask | LeaveWindowMask
| ButtonMask
;
/* now set up each screen in turn */
num_screens = ScreenCount(dpy);
screens = (ScreenInfo *)xmalloc(num_screens * sizeof(ScreenInfo));
for (i = 0; i < num_screens; i++) {
char *ds, *colon, *dot;
ds = DisplayString(dpy);
/* set up DISPLAY environment variable to use */
colon = rindex(ds, ':');
if (colon && num_screens > 1) {
screens[i].display = (char *)xmalloc(14 + strlen(ds));
strcpy(screens[i].display, "DISPLAY=");
strcat(screens[i].display, ds);
colon = rindex(screens[i].display, ':');
dot = index(colon, '.');
if (!dot)
dot = colon + strlen(colon);
snprintf(dot, 5, ".%d", i);
} else
screens[i].display = NULL;
screens[i].screen = i;
screens[i].root = RootWindow(dpy, i);
XAllocNamedColor(dpy, DefaultColormap(dpy, i), config.theme->fgcolor, &screens[i].fg, &dummy);
XAllocNamedColor(dpy, DefaultColormap(dpy, i), config.theme->bgcolor, &screens[i].bg, &dummy);
XAllocNamedColor(dpy, DefaultColormap(dpy, i), config.theme->fxcolor, &screens[i].fc, &dummy);
screens[i].invert_gc = XCreateGC(dpy, screens[i].root, GCFunction | GCSubwindowMode | GCLineWidth | GCFont, &gv);
XChangeWindowAttributes(dpy, screens[i].root, CWEventMask, &attr);
grab_keysym(screens[i].root, Mod1Mask, *keysym);
#ifdef DEBUG
/* scan all the windows on this screen */
bad_debug(1,"main:XQueryTree()\n");
#endif
XQueryTree(dpy, screens[i].root, &dw1, &dw2, &wins, &nwins);
#ifdef DEBUG
bad_debug(1,"%d windows\n", nwins);
#endif
for (j = 0; j < nwins; j++) {
XGetWindowAttributes(dpy, wins[j], &winattr);
if (!winattr.override_redirect && winattr.map_state == IsViewable)
make_new_client(wins[j], &screens[i]);
}
XFree(wins);
XDefineCursor(dpy,screens[i].root,arrow_curs);
}
current_screen = find_screen(DefaultScreen(dpy));
}
syntax highlighted by Code2HTML, v. 0.9.1