/* evilwm - Minimalist Window Manager for X
* Copyright (C) 1999-2002 Ciaran Anscomb <evilwm@6809.org.uk>
* see README for license and other details. */
#include "evilwm.h"
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <X11/cursorfont.h>
#include <stdio.h>
#ifdef SHAPE
#include <X11/extensions/shape.h>
#endif
Display *dpy;
/*
int screen;
Window root;
GC invert_gc;
#ifdef VWM
XColor fg, bg, fc;
#else
XColor fg, bg;
#endif
*/
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 move_curs;
Cursor resize_curs;
char *opt_display = "";
char *opt_font = DEF_FONT;
char *opt_fg = DEF_FG;
char *opt_bg = DEF_BG;
char **opt_term = NULL;
char *opt_wm = "/usr/bin/fluxbox";
int opt_bw = DEF_BW;
#ifdef VWM
char *opt_fc = DEF_FC;
int vdesk = KEY_TO_VDESK(KEY_DESK1);
#endif
#ifdef SHAPE
int have_shape, shape_event;
#endif
int quitting = 0;
#ifdef MWM_HINTS
Atom mwm_hints;
#endif
unsigned int numlockmask = 0;
typedef char * c_star;
static c_star browser[3]={"/usr/bin/opera","/usr/bin/opera",NULL};
static c_star aim[3]={"/usr/local/bin/gaim","/usr/local/bin/gaim",NULL};
static c_star editor[3]={"/usr/bin/emacs","/usr/bin/emacs",NULL};
char opt_window_drag_with_alt=0;
char ** opt_browser = browser;
char ** opt_aim = aim;
char ** opt_editor = editor;
#define NUM_LIKABLE_CURSORS 5
static int likable_cursors [NUM_LIKABLE_CURSORS]= {XC_left_ptr,XC_top_left_arrow,XC_right_ptr,XC_draft_small,XC_draft_large};
int main(int argc, char *argv[]) {
struct sigaction act;
int i;
XEvent ev;
for (i = 1; i < argc; i++) {
if (!strcmp(argv[i], "-fn") && i+1<argc)
opt_font = argv[++i];
else if (!strcmp(argv[i], "-display") && i+1<argc) {
opt_display = argv[++i];
}
else if (!strcmp(argv[i], "-fg") && i+1<argc)
opt_fg = argv[++i];
else if (!strcmp(argv[i], "-bg") && i+1<argc)
opt_bg = argv[++i];
#ifdef VWM
else if (!strcmp(argv[i], "-fc") && i+1<argc)
opt_fc = argv[++i];
#endif
else if (!strcmp(argv[i], "-bw") && i+1<argc)
opt_bw = atoi(argv[++i]);
else if (!strcmp(argv[i], "-term") && i+1<argc) {
opt_term = (char **)malloc(3 * sizeof(char *));
opt_term[0] = argv[++i];
opt_term[1] = opt_term[0];
opt_term[2] = NULL;
#ifdef STDIO
} else if (!strcmp(argv[i], "-V")) {
printf("evilwm version " VERSION "\n");
exit(0);
#endif
} else if (!strcmp(argv[i],"-browser")) {
opt_browser[0]=argv[++i];
opt_browser[1]=opt_browser[0];
} else if (!strcmp(argv[i],"-aim")) {
opt_aim[0]=argv[++i];
opt_aim[1]=opt_aim[0];
} else if (!strcmp(argv[i],"-editor")) {
opt_editor[0]=argv[++i];
opt_editor[1]=opt_editor[0];
} else if (!strcmp(argv[i],"-alt")) {
opt_window_drag_with_alt=1;
} else if (!strcmp(argv[i],"-otherwm")) {
opt_wm=argv[++i];
} else {
#ifdef STDIO
printf("usage: evilwm [-display display] [-term termprog] [-fg foreground] [-alt] [-browser browsprog] [-aim chatprog] [-editor editprog]\n");
printf("\t[-bg background] [-bw borderwidth] [-V]\n");
#endif
exit(2);
}
}
if (!opt_term) {
opt_term = (char **)malloc(3 * sizeof(char *));
opt_term[0] = DEF_TERM;
opt_term[1] = opt_term[0];
opt_term[2] = NULL;
}
act.sa_handler = handle_signal;
sigemptyset(&act.sa_mask);
/* #ifdef SA_NOCLDSTOP */
/* act.sa_flags = SA_NOCLDSTOP; */ /* don't care about STOP, CONT */
/* #else */
act.sa_flags = 0;
/* #endif */
sigaction(SIGTERM, &act, NULL);
sigaction(SIGINT, &act, NULL);
sigaction(SIGHUP, &act, NULL);
/* sigaction(SIGCHLD, &act, NULL); */ /* handling this differently */
setup_display();
#ifdef SHAPE
have_shape = XShapeQueryExtension(dpy, &shape_event, &i);
#endif
/* main event loop here */
for (;;) {
//FILE * fp = fopen ("/tmp/log","a");
XNextEvent(dpy, &ev);
// fseel(fp,0,SEEK_END);
// fprintf (fp,"ev.type %d\n",ev.type);
// fclose(fp);
switch (ev.type) {
case KeyPress:
handle_key_event(&ev.xkey); break;
#ifdef MOUSE
case ButtonPress:
handle_button_event(&ev.xbutton); break;
#endif
case ConfigureRequest:
handle_configure_request(&ev.xconfigurerequest); break;
case MapRequest:
handle_map_request(&ev.xmaprequest); break;
#ifdef VDESK
case ClientMessage:
handle_client_message(&ev.xclient); break;
#endif
#ifdef COLOURMAP
case ColormapNotify:
handle_colormap_change(&ev.xcolormap); break;
#endif
case EnterNotify:
handle_enter_event(&ev.xcrossing); break;
case LeaveNotify:
handle_leave_event(&ev.xcrossing); break;
case PropertyNotify:
handle_property_change(&ev.xproperty); break;
case UnmapNotify:
handle_unmap_event(&ev.xunmap); break;
/* case Expose:
handle_expose_event(&ev.xexpose); break; */
default:
#ifdef SHAPE
if (have_shape && ev.type == shape_event) {
handle_shape_event((XShapeEvent *)&ev);
}
#endif
}
}
return 1;
}
void setup_display() {
XGCValues gv;
XSetWindowAttributes attr;
XColor dummy;
XModifierKeymap *modmap;
KeySym *keysym;
KeySym send_keys;
KeySym keys_to_grab[] = {
KEY_NEW, KEY_KILL,
KEY_TOPLEFT, KEY_TOPRIGHT, KEY_BOTTOMLEFT, KEY_BOTTOMRIGHT,
KEY_LEFT, KEY_RIGHT, KEY_DOWN, KEY_UP,
KEY_LOWER, KEY_ALTLOWER, KEY_INFO, KEY_MAXVERT, KEY_MAX,
#ifdef VWM
KEY_FIX, KEY_PREVDESK, KEY_NEXTDESK,XK_Tab,
KEY_DESK1, KEY_DESK2, KEY_DESK3, KEY_DESK4, KEY_DESK5, KEY_DESK6, KEY_DESK7,KEY_DESK8,
KEY_MINIMIZE,
#endif
KEY_GAIM,KEY_OPERA,KEY_EMACS,KEY_SHADE,
0
};
/* used in scanning windows (XQueryTree) */
unsigned int i, j, nwins;
Window dw1, dw2, *wins;
XWindowAttributes winattr;
dpy = XOpenDisplay(opt_display);
if (!dpy) {
#ifdef STDIO
fprintf(stderr, "can't open display %s\n", opt_display);
#endif
exit(1);
}
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);
#ifdef COLOURMAP
xa_wm_cmapwins = XInternAtom(dpy, "WM_COLORMAP_WINDOWS", False);
#endif
#ifdef MWM_HINTS
mwm_hints = XInternAtom(dpy, _XA_MWM_HINTS, False);
#endif
font = XLoadQueryFont(dpy, opt_font);
if (!font) font = XLoadQueryFont(dpy, DEF_FONT);
move_curs = XCreateFontCursor(dpy, XC_fleur);
resize_curs = XCreateFontCursor(dpy, XC_plus);
/* 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
fprintf(stderr, "setup_display() : XK_Num_Lock is (1<<0x%02x)\n", i);
#endif
}
}
}
XFree(modmap);
/* set up GC parameters - same for each screen */
gv.function = GXinvert;
gv.subwindow_mode = IncludeInferiors;
gv.line_width = 1; /* opt_bw */
gv.font = font->fid;
/* set up root window attributes - same for each screen */
attr.event_mask = ChildMask | PropertyChangeMask | EnterWindowMask | LeaveWindowMask
#ifdef COLOURMAP
| ColormapChangeMask
#endif
#ifdef MOUSE
| ButtonMask
#endif
;
/* now set up each screen in turn */
num_screens = ScreenCount(dpy);
screens = (ScreenInfo *)malloc(num_screens * sizeof(ScreenInfo));
for (i = 0; i < num_screens; i++) {
int default_curs;
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 *)malloc(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), opt_fg, &screens[i].fg, &dummy);
XAllocNamedColor(dpy, DefaultColormap(dpy, i), opt_bg, &screens[i].bg, &dummy);
#ifdef VWM
XAllocNamedColor(dpy, DefaultColormap(dpy, i), opt_fc, &screens[i].fc, &dummy);
#endif
screens[i].invert_gc = XCreateGC(dpy, screens[i].root, GCFunction | GCSubwindowMode | GCLineWidth | GCFont, &gv);
XChangeWindowAttributes(dpy, screens[i].root, CWEventMask, &attr);
/* Unfortunately grabbing AnyKey under Solaris seems not to work */
/* XGrabKey(dpy, AnyKey, ControlMask|Mod1Mask, root, True, GrabModeAsync, GrabModeAsync); */
/* So now I grab each and every one. */
for (keysym = keys_to_grab; *keysym; keysym++) {
grab_keysym(screens[i].root, /*ControlMask|Mod1Mask*/Mod4Mask, *keysym);
grab_keysym(screens[i].root, Mod1Mask, *keysym);
}
for (send_keys = KEY_DESK1;send_keys<=KEY_DESK8;send_keys++) {
grab_keysym (screens[i].root,Mod4Mask|ShiftMask,send_keys);
grab_keysym (screens[i].root,Mod1Mask|ShiftMask,send_keys);
}
grab_keysym (screens[i].root,Mod4Mask|ShiftMask,KEY_INFO) ;
grab_keysym(screens[i].root, Mod1Mask, XK_Tab);//add a mod 1 the mod4 is handled in for loop
default_curs = XCreateFontCursor(dpy, likable_cursors[i%NUM_LIKABLE_CURSORS]);
XDefineCursor(dpy,screens[i].root,default_curs);
/* scan all the windows on this screen */
#ifdef XDEBUG
fprintf(stderr, "main:XQueryTree(); ");
#endif
XQueryTree(dpy, screens[i].root, &dw1, &dw2, &wins, &nwins);
#ifdef XDEBUG
fprintf(stderr, "%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);
}
current_screen = find_screen(DefaultScreen(dpy));
}