From 4c39a9c3aa4547c1d7ca593b69f03ca3cdb2e805 Mon Sep 17 00:00:00 2001 From: moetunes Date: Mon, 12 Sep 2011 19:47:12 +1000 Subject: first commit --- src/dminiwm.c | 748 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 748 insertions(+) create mode 100755 src/dminiwm.c (limited to 'src/dminiwm.c') diff --git a/src/dminiwm.c b/src/dminiwm.c new file mode 100755 index 0000000..4ee82e8 --- /dev/null +++ b/src/dminiwm.c @@ -0,0 +1,748 @@ +/* dminiwm.c [ 0.0.1 ] +* +* I started this from catwm 31/12/10 with many thanks! +* Bad window error checking and numlock checking used from +* 2wm at http://hg.suckless.org/2wm/ with many thanks ! +* +* 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 3 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, see . +*/ + +#include +#include +//#include +#include +#include +#include +#include +#include +#include + +#define TABLENGTH(X) (sizeof(X)/sizeof(*X)) + +typedef union { + const char** com; + const int i; +} Arg; + +// Structs +typedef struct { + unsigned int mod; + KeySym keysym; + void (*function)(const Arg arg); + const Arg arg; +} key; + +typedef struct client client; +struct client{ + // Prev and next client + client *next; + client *prev; + + // The window + Window win; +}; + +typedef struct desktop desktop; +struct desktop{ + int master_size; + int mode; + int growth; + client *head; + client *current; +}; + +// Functions +static void add_window(Window w); +static void change_desktop(const Arg arg); +static void client_to_desktop(const Arg arg); +static void configurenotify(XEvent *e); +static void configurerequest(XEvent *e); +static void decrease(); +static void destroynotify(XEvent *e); +static void logger(const char* e); +static unsigned long getcolor(const char* color); +static void grabkeys(); +static void grow_window(); +static void increase(); +static void keypress(XEvent *e); +static void kill_client(); +static void maprequest(XEvent *e); +static void next_desktop(); +static void next_win(); +static void prev_desktop(); +static void prev_win(); +static void quit(); +static void remove_window(Window w); +static void save_desktop(int i); +static void select_desktop(int i); +static void send_kill_signal(Window w); +static void setup(); +static void shrink_window(); +static void sigchld(int unused); +static void spawn(const Arg arg); +static void start(); +static void swap_master(); +static void tile(); +static void switch_fullscreen(); +static void switch_vertical(); +static void update_current(); + +// Include configuration file (need struct key) +#include "config.h" + +// Variable +static Display *dis; +static int bool_quit; +static int current_desktop; +static int growth; +static int master_size; +static int mode; +static int sh; +static int sw; +static int screen; +static int xerror(Display *dis, XErrorEvent *ee); +static int (*xerrorxlib)(Display *, XErrorEvent *); +static unsigned int win_focus; +static unsigned int win_unfocus; +unsigned int numlockmask; /* dynamic key lock mask */ +static Window root; +static client *head; +static client *current; + +// Events array +static void (*events[LASTEvent])(XEvent *e) = { + [KeyPress] = keypress, + [MapRequest] = maprequest, + [DestroyNotify] = destroynotify, + [ConfigureNotify] = configurenotify, + [ConfigureRequest] = configurerequest +}; + +// Desktop array +static desktop desktops[6]; + +/* ***************************** Window Management ******************************* */ +void add_window(Window w) { + client *c,*t; + + if(!(c = (client *)calloc(1,sizeof(client)))) { + logger("\033[0;31mError calloc!"); + exit(1); + } + + if(head == NULL) { + c->next = NULL; + c->prev = NULL; + c->win = w; + head = c; + } + else { + if(ATTACH_ASIDE == 0) { + for(t=head;t->next;t=t->next); + + c->next = NULL; + c->prev = t; + c->win = w; + + t->next = c; + } + else { + for(t=head;t->prev;t=t->prev); + + c->prev = NULL; + c->next = t; + c->win = w; + + t->prev = c; + + head = c; + } + } + + current = c; + save_desktop(current_desktop); +} + +void remove_window(Window w) { + client *c; + + // CHANGE THIS UGLY CODE + for(c=head;c;c=c->next) { + + if(c->win == w) { + if(c->prev == NULL && c->next == NULL) { + free(head); + head = NULL; + current = NULL; + save_desktop(current_desktop); + return; + } + + if(c->prev == NULL) { + head = c->next; + c->next->prev = NULL; + current = c->next; + } + else if(c->next == NULL) { + c->prev->next = NULL; + current = c->prev; + } + else { + c->prev->next = c->next; + c->next->prev = c->prev; + current = c->prev; + } + + free(c); + save_desktop(current_desktop); + tile(); + update_current(); + return; + } + } +} + +void kill_client() { + if(current != NULL) { + //send delete signal to window + XEvent ke; + ke.type = ClientMessage; + ke.xclient.window = current->win; + ke.xclient.message_type = XInternAtom(dis, "WM_PROTOCOLS", True); + ke.xclient.format = 32; + ke.xclient.data.l[0] = XInternAtom(dis, "WM_DELETE_WINDOW", True); + ke.xclient.data.l[1] = CurrentTime; + XSendEvent(dis, current->win, False, NoEventMask, &ke); + send_kill_signal(current->win); + remove_window(current->win); + } +} + +void next_win() { + client *c; + + if(current != NULL && head != NULL) { + if(current->next == NULL) + c = head; + else + c = current->next; + + current = c; + if(mode == 1) + tile(); + update_current(); + } +} + +void prev_win() { + client *c; + + if(current != NULL && head != NULL) { + if(current->prev == NULL) + for(c=head;c->next;c=c->next); + else + c = current->prev; + + current = c; + if(mode == 1) + tile(); + update_current(); + } +} + +void swap_master() { + Window tmp; + + if(head != NULL && current != NULL && mode != 1) { + if(current == head) { + tmp = head->next->win; + head->next->win = head->win; + head->win = tmp; + } else { + tmp = head->win; + head->win = current->win; + current->win = tmp; + current = head; + } + save_desktop(current_desktop); + tile(); + update_current(); + } +} + +void decrease() { + master_size -= 10; + tile(); +} + +void increase() { + master_size += 10; + tile(); +} + +/* **************************** Desktop Management ************************************* */ +void change_desktop(const Arg arg) { + client *c; + + if(arg.i == current_desktop) + return; + + // Save current "properties" + save_desktop(current_desktop); + + // Unmap all window + if(head != NULL) + for(c=head;c;c=c->next) + XUnmapWindow(dis,c->win); + + // Take "properties" from the new desktop + select_desktop(arg.i); + + // Map all windows + if(head != NULL) + for(c=head;c;c=c->next) + XMapWindow(dis,c->win); + + tile(); + update_current(); + +} + +void next_desktop() { + int tmp = current_desktop; + if(tmp == TABLENGTH(desktops)-1) + tmp = 0; + else + tmp++; + + Arg a = {.i = tmp}; + change_desktop(a); +} + +void prev_desktop() { + int tmp = current_desktop; + if(tmp == 0) + tmp = TABLENGTH(desktops)-1; + else + tmp--; + + Arg a = {.i = tmp}; + change_desktop(a); +} + +void client_to_desktop(const Arg arg) { + client *tmp = current; + int tmp2 = current_desktop; + + if(arg.i == current_desktop || current == NULL) + return; + + // Add client to desktop + select_desktop(arg.i); + add_window(tmp->win); + save_desktop(arg.i); + + // Remove client from current desktop + select_desktop(tmp2); + XUnmapWindow(dis,tmp->win); + remove_window(tmp->win); + save_desktop(tmp2); + tile(); + update_current(); +} + +void save_desktop(int i) { + desktops[i].master_size = master_size; + desktops[i].mode = mode; + desktops[i].growth = growth; + desktops[i].head = head; + desktops[i].current = current; +} + +void select_desktop(int i) { + master_size = desktops[i].master_size; + mode = desktops[i].mode; + growth = desktops[i].growth; + head = desktops[i].head; + current = desktops[i].current; + current_desktop = i; +} + +void tile() { + client *c; + int n = 0; + int x = 0; + + // If only one window + if(head != NULL && head->next == NULL) { + XMoveResizeWindow(dis,head->win,0,0,sw-BORDER_WIDTH,sh-BORDER_WIDTH); + } + else if(head != NULL) { + switch(mode) { + case 0: /* Vertical */ + // Master window + XMoveResizeWindow(dis,head->win,0,0,master_size - BORDER_WIDTH,sh - BORDER_WIDTH); + + // Stack + for(c=head->next;c;c=c->next) ++n; + if(n == 1) growth = 0; + XMoveResizeWindow(dis,head->next->win,master_size + BORDER_WIDTH,0,sw-master_size-(2*BORDER_WIDTH),(sh/n)+growth - BORDER_WIDTH); + x = (sh/n)+growth; + for(c=head->next->next;c;c=c->next) { + XMoveResizeWindow(dis,c->win,master_size + BORDER_WIDTH,x,sw-master_size-(2*BORDER_WIDTH),(sh/n)-(growth/(n-1)) - BORDER_WIDTH); + x += (sh/n)-(growth/(n-1)); + } + break; + case 1: /* Fullscreen */ + for(c=head;c;c=c->next) { + XMoveResizeWindow(dis,c->win,0,0,sw-BORDER_WIDTH,sh-BORDER_WIDTH); + } + break; + } + } +} + +void update_current() { + client *c; + + for(c=head;c;c=c->next) + if(current == c) { + // "Enable" current window + XSetWindowBorderWidth(dis,c->win,BORDER_WIDTH); + XSetWindowBorder(dis,c->win,win_focus); + XSetInputFocus(dis,c->win,RevertToParent,CurrentTime); + XRaiseWindow(dis,c->win); + } + else + XSetWindowBorder(dis,c->win,win_unfocus); + + XSync(dis, False); +} + +void switch_fullscreen() { + if(mode != 1) { + mode = 1; + tile(); + update_current(); + } +} + +void switch_vertical() { + if(mode != 0) { + mode = 0; + tile(); + update_current(); + } +} + +void grow_window() { + growth += 10; + tile(); +} + +void shrink_window() { + growth -= 10; + tile(); +} + +/* ********************** Keyboard Management ********************** */ +void grabkeys() { + int i; + KeyCode code; + + XUngrabKey(dis, AnyKey, AnyModifier, root); + // For each shortcuts + for(i=0;ixkey; + + keysym = XKeycodeToKeysym(dis, (KeyCode)ev->keycode, 0); + for(i = 0; i < len; i++) { + if(keysym == keys[i].keysym && CLEANMASK(keys[i].mod) == CLEANMASK(ev->state)) { + if(keys[i].function) + keys[i].function(keys[i].arg); + } + } +} + +void configurenotify(XEvent *e) { + // Do nothing for the moment +} + +/* ********************** Signal Management ************************** */ +void configurerequest(XEvent *e) { + // Paste from DWM, thx again \o/ + XConfigureRequestEvent *ev = &e->xconfigurerequest; + XWindowChanges wc; + wc.x = ev->x; + wc.y = ev->y; + wc.width = ev->width; + wc.height = ev->height; + wc.border_width = ev->border_width; + wc.sibling = ev->above; + wc.stack_mode = ev->detail; + XConfigureWindow(dis, ev->window, ev->value_mask, &wc); + XSync(dis, False); +} + +void maprequest(XEvent *e) { + XMapRequestEvent *ev = &e->xmaprequest; + + // For fullscreen mplayer (and maybe some other program) + client *c; + + for(c=head;c;c=c->next) + if(ev->window == c->win) { + XMapWindow(dis,ev->window); + XMoveResizeWindow(dis,c->win,0,0,sw-BORDER_WIDTH,sh-BORDER_WIDTH); + return; + } + + add_window(ev->window); + XMapWindow(dis,ev->window); + tile(); + update_current(); +} + +void destroynotify(XEvent *e) { + int i=0; + int j = 0; + int tmp = current_desktop; + client *c; + XDestroyWindowEvent *ev = &e->xdestroywindow; + + save_desktop(tmp); + for(j=0;jnext) + if(ev->window == c->win) + i++; + + if(i != 0) { + remove_window(ev->window); + select_desktop(tmp); + return; + } + + i = 0; + } + select_desktop(tmp); +} + +void send_kill_signal(Window w) { + XEvent ke; + ke.type = ClientMessage; + ke.xclient.window = w; + ke.xclient.message_type = XInternAtom(dis, "WM_PROTOCOLS", True); + ke.xclient.format = 32; + ke.xclient.data.l[0] = XInternAtom(dis, "WM_DELETE_WINDOW", True); + ke.xclient.data.l[1] = CurrentTime; + XSendEvent(dis, w, False, NoEventMask, &ke); +} + +unsigned long getcolor(const char* color) { + XColor c; + Colormap map = DefaultColormap(dis,screen); + + if(!XAllocNamedColor(dis,map,color,&c,&c)) { + logger("\033[0;31mError parsing color!"); + exit(1); + } + return c.pixel; +} + +void quit() { + Window root_return, parent; + Window *children; + int i; + unsigned int nchildren; + XEvent ev; + + /* + * if a client refuses to terminate itself, + * we kill every window remaining the brutal way. + * Since we're stuck in the while(nchildren > 0) { ... } loop + * we can't exit through the main method. + * This all happens if MOD+q is pushed a second time. + */ + if(bool_quit == 1) { + XUngrabKey(dis, AnyKey, AnyModifier, root); + XDestroySubwindows(dis, root); + logger(" \033[0;33mThanks for using!"); + XCloseDisplay(dis); + logger("\033[0;31mforced shutdown"); + } + + bool_quit = 1; + XQueryTree(dis, root, &root_return, &parent, &children, &nchildren); + for(i = 0; i < nchildren; i++) { + send_kill_signal(children[i]); + } + //keep alive until all windows are killed + while(nchildren > 0) { + XQueryTree(dis, root, &root_return, &parent, &children, &nchildren); + XNextEvent(dis,&ev); + if(events[ev.type]) + events[ev.type](&ev); + } + + XUngrabKey(dis,AnyKey,AnyModifier,root); + logger("\033[0;34mYou Quit : Thanks for using!"); +} + +void logger(const char* e) { + fprintf(stdout,"\n\033[0;34m:: dminiwm : %s \033[0;m\n", e); +} + +void setup() { + // Install a signal + sigchld(0); + + // Screen and root window + screen = DefaultScreen(dis); + root = RootWindow(dis,screen); + + // Screen width and height + sw = XDisplayWidth(dis,screen) - BORDER_WIDTH; + sh = (XDisplayHeight(dis,screen) - PANEL_HEIGHT) - BORDER_WIDTH; + + // Colors + win_focus = getcolor(FOCUS); + win_unfocus = getcolor(UNFOCUS); + + // numlock workaround + int j, k; + XModifierKeymap *modmap; + numlockmask = 0; + modmap = XGetModifierMapping(dis); + for (k = 0; k < 8; k++) { + for (j = 0; j < modmap->max_keypermod; j++) { + if(modmap->modifiermap[k * modmap->max_keypermod + j] == XKeysymToKeycode(dis, XK_Num_Lock)) + numlockmask = (1 << k); + } + } + XFreeModifiermap(modmap); + + // Shortcuts + grabkeys(); + + // Default stack + mode = DEFAULT_MODE; + growth = 0; + + // For exiting + bool_quit = 0; + + // List of client + head = NULL; + current = NULL; + + // Master size + master_size = sw*MASTER_SIZE; + + // Set up all desktop + int i; + for(i=0;ierror_code == BadWindow + || (ee->request_code == X_SetInputFocus && ee->error_code == BadMatch) + || (ee->request_code == X_PolyText8 && ee->error_code == BadDrawable) + || (ee->request_code == X_PolyFillRectangle && ee->error_code == BadDrawable) + || (ee->request_code == X_PolySegment && ee->error_code == BadDrawable) + || (ee->request_code == X_ConfigureWindow && ee->error_code == BadMatch) + || (ee->request_code == X_GrabKey && ee->error_code == BadAccess) + || (ee->request_code == X_CopyArea && ee->error_code == BadDrawable)) + return 0; + logger("\033[0;31mBad Window Error!"); + return xerrorxlib(dis, ee); /* may call exit */ +} + +void start() { + XEvent ev; + + // Main loop, just dispatch events (thx to dwm ;) + while(!bool_quit && !XNextEvent(dis,&ev)) { + if(events[ev.type]) + events[ev.type](&ev); + } +} + + +int main(int argc, char **argv) { + // Open display + if(!(dis = XOpenDisplay(NULL))) { + logger("\033[0;31mCannot open display!"); + exit(1); + } + + // Setup env + setup(); + + // Start wm + start(); + + // Close display + XCloseDisplay(dis); + + return 0; +} -- cgit v1.3.1