Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Added files

  • Loading branch information...
commit d03d3292ca49244004552ccc3ec0965caa413d09 1 parent 714ac37
@moetunes authored
Showing with 1,240 additions and 0 deletions.
  1. +52 −0 ChangeLog
  2. +21 −0 Makefile
  3. +127 −0 config.h.def
  4. +1,040 −0 dminiwm.c
View
52 ChangeLog
@@ -0,0 +1,52 @@
+28/11/11
+ Added last desktop function for switching back to the last opened desktop
+
+26/11/11
+ Added option to click on a window to focus it
+
+21/11/11
+ Fix for transient windows not being managed
+
+15/11/11
+ Fix for when trying to swap master with only one window
+
+23/10/11
+ Fine tuned the popup window management so notification windows aren't managed either
+
+15/10/11
+ Added having applications start on specified desktop
+
+13/10/11
+ Added ability to use grow_window/shrink_window in grid mode with 3 or 4 windows
+
+13/10/11
+ Popup windows now aren't managed/added to the stack
+
+10/10/11
+ Reapplied setting master_size relevant to default mode
+
+8/10/11
+ For only one window or fullscreen mode there is no border
+
+8/10/11
+ Fixed fullscreen mplayer
+
+8/10/11
+ Removed useless gaps when in grid mode
+
+16/9/11
+ Added back the option to have the panel at the top
+ Fine tuned the grid tiling mode
+
+13/9/11
+ Added back horizontal tiling, follow mouse and follow window
+
+12/9/11
+ Returned to catwm tiling methods - with the ability to resize the window at the top of the stack
+
+9/9/11
+ Fine tuned the next/prev desktop and the destroy notify functions
+
+ 8/9/11
+ Have a proper destroy notify function now that removes destroyed windows from
+ the window manager stack for the desktop they were on.
View
21 Makefile
@@ -0,0 +1,21 @@
+CFLAGS+= -Wall
+LDADD+= -lX11
+LDFLAGS=
+EXEC=dminiwm
+
+PREFIX?= /usr/local
+BINDIR?= $(PREFIX)/bin
+
+CC=gcc
+
+all: $(EXEC)
+
+dminiwm: dminiwm.o
+ $(CC) $(LDFLAGS) -s -Os -o $@ $+ $(LDADD)
+
+install: all
+ install -Dm 755 dminiwm $(DESTDIR)$(BINDIR)/dminiwm
+
+clean:
+ rm -fv dminiwm *.o
+
View
127 config.h.def
@@ -0,0 +1,127 @@
+ /* config.h for dminiwm.c [ 0.2.0 ]
+ *
+ * Started from catwm 31/12/10
+ * Bad window error checking and numlock checking used from
+ * 2wm at http://hg.suckless.org/2wm/
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef CONFIG_H
+#define CONFIG_H
+
+#define CLEANMASK(mask) (mask & ~(numlockmask | LockMask))
+
+/* Mod (Mod1 == alt) (Mod4 == Super/windows) */
+#define MOD1 Mod1Mask
+#define MOD4 Mod4Mask
+#define MASTER_SIZE 0.52
+#define TOP_PANEL 1 /* 1=Don't 0=Have the panel at the top instead of the bottom */
+#define PANEL_HEIGHT 18 /* 0 for no space for a panel */
+#define BORDER_WIDTH 2
+#define ATTACH_ASIDE 1 /* 0=TRUE, 1=New window is master */
+#define DEFAULT_MODE 0 /* 0=Vertical, 1=Fullscreen 2=Horizontal 3=grid*/
+#define FOLLOW_MOUSE 0 /* 1=Don't 0=Focus the window the mouse just entered */
+#define FOLLOW_WINDOW 0 /* 1=Don't 0=Follow the window when moved to a different desktop */
+#define CLICK_TO_FOCUS 1 /* 1=Don't 0=Focus an unfocused window when clicked */
+#define DESKTOPS 6 /* Must edit DESKTOPCHANGE keys to suit */
+
+// Colors
+#define FOCUS "#664422" // dkorange
+#define UNFOCUS "#004050" // blueish
+
+// Applications to a specific desktop
+static const Convenience convenience[] = { \
+ /* class desktop follow */
+ { "Thunar", 2, 1 },
+ //{ "Leafpad", 2, 1 },
+ { "Firefox", 3, 0 },
+ { "Links", 3, 1 },
+ { "MPlayer", 4, 1 },
+ { "Thunderbird", 5, 0 },
+ { "Pysol", 6, 1 },
+};
+
+const char* dmenucmd[] = {"dmenu_run","-i","-nb","#666622","-nf","white",NULL};
+const char* urxvtcmd[] = {"urxvtc",NULL};
+const char* terminalcmd[] = {"Terminal",NULL};
+const char* thunarcmd[] = {"thunar",NULL};
+const char* firefoxcmd[] = {"firefox",NULL};
+const char* webcmd[] = {"links","-g",NULL};
+const char* luakitcmd[] = {"/home/pnewm/.bin/launchbrowser",NULL};
+const char* mailcmd[] = {"thunderbird",NULL };
+const char* voldowncmd[] = {"/home/pnewm/.bin/voldown",NULL};
+const char* volupcmd[] = {"/home/pnewm/.bin/volup",NULL};
+const char* prevoldowncmd[] = {"/home/pnewm/.bin/prevoldown",NULL};
+const char* prevolupcmd[] = {"/home/pnewm/.bin/prevolup",NULL};
+const char* vols_what[] = {"/home/pnewm/.bin/volumes_what",NULL};
+// for reboot and shutdown
+const char* rebootcmd[] = {"sudo","reboot",NULL};
+const char* shutdowncmd[] = {"sudo","shutdown","-h","now",NULL};
+
+// Avoid multiple paste
+#define DESKTOPCHANGE(K,N) \
+ { MOD1, K, change_desktop, {.i = N}}, \
+ { MOD1|ShiftMask, K, client_to_desktop, {.i = N}},
+
+// Shortcuts
+static key keys[] = {
+ // MOD KEY FUNCTION ARGS
+ { MOD1, XK_h, resize_master, {.i = 10}},
+ { MOD1, XK_l, resize_master, {.i = -10}},
+ { MOD1, XK_c, kill_client, {NULL}},
+ { MOD1, XK_j, next_win, {NULL}},
+ { MOD1, XK_k, prev_win, {NULL}},
+ { MOD1, XK_v, spawn, {.com = dmenucmd}},
+ { MOD1, XK_p, resize_stack, {.i = 10}},
+ { MOD1, XK_o, resize_stack, {.i = -10}},
+ { MOD1, XK_Tab, toggle_desktop, {NULL}},
+ { MOD1, XK_Return, spawn, {.com = urxvtcmd}},
+ { MOD1, XK_Up, spawn, {.com = volupcmd}},
+ { MOD1, XK_Down, spawn, {.com = voldowncmd}},
+// alt + shift + shortcut
+ { MOD1|ShiftMask, XK_j, move_up, {NULL}},
+ { MOD1|ShiftMask, XK_k, move_down, {NULL}},
+ { MOD1|ShiftMask, XK_Return, swap_master, {NULL}},
+ { MOD1|ShiftMask, XK_g, switch_grid, {NULL}},
+ { MOD1|ShiftMask, XK_h, switch_horizontal, {NULL}},
+ { MOD1|ShiftMask, XK_m, switch_fullscreen, {NULL}},
+ { MOD1|ShiftMask, XK_v, switch_vertical, {NULL}},
+// Control + alt + shortcut
+ { MOD1|ControlMask, XK_q, quit, {NULL}},
+ { MOD1|ControlMask, XK_r, spawn, {.com = rebootcmd}},
+ { MOD1|ControlMask, XK_s, spawn, {.com = shutdowncmd}},
+// Window key + shortcut
+ { MOD4, XK_Right, next_desktop, {NULL}},
+ { MOD4, XK_Left, prev_desktop, {NULL}},
+ { MOD4, XK_e, spawn, {.com = mailcmd}},
+ { MOD4, XK_f, spawn, {.com = firefoxcmd}},
+ { MOD4, XK_w, spawn, {.com = webcmd}},
+ { MOD4, XK_l, spawn, {.com = luakitcmd}},
+ { MOD4, XK_h, spawn, {.com = thunarcmd}},
+ { MOD4, XK_t, spawn, {.com = terminalcmd}},
+ { MOD4, XK_v, spawn, {.com = vols_what}},
+ { MOD4, XK_Up, spawn, {.com = prevolupcmd}},
+ { MOD4, XK_Down, spawn, {.com = prevoldowncmd}},
+ DESKTOPCHANGE( XK_1, 0)
+ DESKTOPCHANGE( XK_2, 1)
+ DESKTOPCHANGE( XK_3, 2)
+ DESKTOPCHANGE( XK_4, 3)
+ DESKTOPCHANGE( XK_5, 4)
+ DESKTOPCHANGE( XK_6, 5)
+};
+
+#endif
+
View
1,040 dminiwm.c
@@ -0,0 +1,1040 @@
+/* dminiwm.c [ 0.2.0 ]
+*
+* I started this from catwm 31/12/10
+* Bad window error checking and numlock checking used from
+* 2wm at http://hg.suckless.org/2wm/
+*
+* 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 <http://www.gnu.org/licenses/>.
+*/
+
+#include <X11/Xlib.h>
+#include <X11/keysym.h>
+//#include <X11/XF86keysym.h>
+#include <X11/Xproto.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <string.h>
+
+#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;
+};
+
+typedef struct {
+ const char *class;
+ int preferredd;
+ int followwin;
+} Convenience;
+
+typedef enum {
+ ATOM_NET_WM_WINDOW_TYPE,
+ ATOM_NET_WM_WINDOW_TYPE_UTILITY,
+ ATOM_NET_WM_WINDOW_TYPE_DOCK,
+ ATOM_NET_WM_WINDOW_TYPE_SPLASH,
+ ATOM_NET_WM_WINDOW_TYPE_DIALOG,
+ ATOM_NET_WM_WINDOW_TYPE_NOTIFICATION,
+ ATOM_COUNT
+} AtomType;
+
+typedef struct {
+ Atom *atom;
+ const char *name;
+} AtomNode;
+
+Atom atoms[ATOM_COUNT];
+
+static const AtomNode atomList[] = {
+ { &atoms[ATOM_NET_WM_WINDOW_TYPE], "_NET_WM_WINDOW_TYPE" },
+ { &atoms[ATOM_NET_WM_WINDOW_TYPE_UTILITY], "_NET_WM_WINDOW_TYPE_UTILITY" },
+ { &atoms[ATOM_NET_WM_WINDOW_TYPE_DOCK], "_NET_WM_WINDOW_TYPE_DOCK" },
+ { &atoms[ATOM_NET_WM_WINDOW_TYPE_SPLASH], "_NET_WM_WINDOW_TYPE_SPLASH" },
+ { &atoms[ATOM_NET_WM_WINDOW_TYPE_DIALOG], "_NET_WM_WINDOW_TYPE_DIALOG" },
+ { &atoms[ATOM_NET_WM_WINDOW_TYPE_NOTIFICATION], "_NET_WM_WINDOW_TYPE_NOTIFICATION"},
+};
+
+// Functions
+static void add_window(Window w);
+static void buttonpressed(XEvent *e);
+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 destroynotify(XEvent *e);
+static void enternotify(XEvent *e);
+static void logger(const char* e);
+static unsigned long getcolor(const char* color);
+static void grabkeys();
+static void keypress(XEvent *e);
+static void kill_client();
+static void maprequest(XEvent *e);
+static void move_down();
+static void move_up();
+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 resize_master(const Arg arg);
+static void resize_stack(const Arg arg);
+static void save_desktop(int i);
+static void select_desktop(int i);
+static void send_kill_signal(Window w);
+static void setup();
+static void sigchld(int unused);
+static void spawn(const Arg arg);
+static void start();
+static void swap_master();
+static void tile();
+static void toggle_desktop();
+static void switch_fullscreen();
+static void switch_grid();
+static void switch_horizontal();
+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 previous_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,
+ [EnterNotify] = enternotify,
+ [ButtonPress] = buttonpressed,
+ [DestroyNotify] = destroynotify,
+ [ConfigureNotify] = configurenotify,
+ [ConfigureRequest] = configurerequest
+};
+
+// Desktop array
+static desktop desktops[DESKTOPS];
+
+/* ***************************** 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);
+ // for folow mouse
+ if(FOLLOW_MOUSE == 0)
+ XSelectInput(dis, c->win, EnterWindowMask);
+}
+
+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 move_down() {
+ Window tmp;
+ if(current == NULL || current->next == NULL || current->win == head->win || current->prev == NULL)
+ return;
+
+ tmp = current->win;
+ current->win = current->next->win;
+ current->next->win = tmp;
+ //keep the moved window activated
+ next_win();
+ save_desktop(current_desktop);
+ tile();
+}
+
+void move_up() {
+ Window tmp;
+ if(current == NULL || current->prev == head || current->win == head->win) {
+ return;
+ }
+ tmp = current->win;
+ current->win = current->prev->win;
+ current->prev->win = tmp;
+ prev_win();
+ save_desktop(current_desktop);
+ tile();
+}
+
+void swap_master() {
+ Window tmp;
+
+ if(head->next != 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();
+ }
+}
+
+/* **************************** Desktop Management ************************************* */
+void change_desktop(const Arg arg) {
+ client *c;
+
+ if(arg.i == current_desktop)
+ return;
+
+ // Save current "properties"
+ save_desktop(current_desktop);
+ previous_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 toggle_desktop() {
+ Arg a = {.i = previous_desktop};
+ change_desktop(a);
+}
+
+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();
+ if(FOLLOW_WINDOW == 0)
+ change_desktop(arg);
+}
+
+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;
+ int y = 0;
+
+ // For a top panel
+ if(TOP_PANEL == 0)
+ y = PANEL_HEIGHT;
+
+ // If only one window
+ if(head != NULL && head->next == NULL) {
+ XMoveResizeWindow(dis,head->win,0,y,sw+2*BORDER_WIDTH,sh+2*BORDER_WIDTH);
+ }
+ else if(head != NULL) {
+ switch(mode) {
+ case 0: /* Vertical */
+ // Master window
+ XMoveResizeWindow(dis,head->win,0,y,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,y,sw-master_size-(2*BORDER_WIDTH),(sh/n)+growth - BORDER_WIDTH);
+ y += (sh/n)+growth;
+ for(c=head->next->next;c;c=c->next) {
+ XMoveResizeWindow(dis,c->win,master_size + BORDER_WIDTH,y,sw-master_size-(2*BORDER_WIDTH),(sh/n)-(growth/(n-1)) - BORDER_WIDTH);
+ y += (sh/n)-(growth/(n-1));
+ }
+ break;
+ case 1: /* Fullscreen */
+ for(c=head;c;c=c->next) {
+ XMoveResizeWindow(dis,c->win,0,y,sw+2*BORDER_WIDTH,sh+2*BORDER_WIDTH);
+ }
+ break;
+ case 2: /* Horizontal */
+ // Master window
+ XMoveResizeWindow(dis,head->win,0,y,sw-BORDER_WIDTH,master_size - BORDER_WIDTH);
+
+ // Stack
+ for(c=head->next;c;c=c->next) ++n;
+ if(n == 1) growth = 0;
+ XMoveResizeWindow(dis,head->next->win,0,y+master_size + BORDER_WIDTH,(sw/n)+growth-BORDER_WIDTH,sh-master_size-(2*BORDER_WIDTH));
+ x = (sw/n)+growth;
+ for(c=head->next->next;c;c=c->next) {
+ XMoveResizeWindow(dis,c->win,x,y+master_size + BORDER_WIDTH,(sw/n)-(growth/(n-1)) - BORDER_WIDTH,sh-master_size-(2*BORDER_WIDTH));
+ x += (sw/n)-(growth/(n-1));
+ }
+ break;
+ case 3: { // Grid
+ int xpos = 0;
+ int wdt = 0;
+ int ht = 0;
+
+ for(c=head;c;c=c->next) ++x;
+
+ for(c=head;c;c=c->next) {
+ ++n;
+ if(x >= 7) {
+ wdt = (sw/3) - BORDER_WIDTH;
+ ht = (sh/3) - BORDER_WIDTH;
+ if((n == 1) || (n == 4) || (n == 7))
+ xpos = 0;
+ if((n == 2) || (n == 5) || (n == 8))
+ xpos = (sw/3) + BORDER_WIDTH;
+ if((n == 3) || (n == 6) || (n == 9))
+ xpos = (2*(sw/3)) + BORDER_WIDTH;
+ if((n == 4) || (n == 7))
+ y += (sh/3) + BORDER_WIDTH;
+ if((n == x) && (n == 7))
+ wdt = sw - BORDER_WIDTH;
+ if((n == x) && (n == 8))
+ wdt = 2*sw/3 - BORDER_WIDTH;
+ } else
+ if(x >= 5) {
+ wdt = (sw/3) - BORDER_WIDTH;
+ ht = (sh/2) - BORDER_WIDTH;
+ if((n == 1) || (n == 4))
+ xpos = 0;
+ if((n == 2) || (n == 5))
+ xpos = (sw/3) + BORDER_WIDTH;
+ if((n == 3) || (n == 6))
+ xpos = (2*(sw/3)) + BORDER_WIDTH;
+ if(n == 4)
+ y += (sh/2); // + BORDER_WIDTH;
+ if((n == x) && (n == 5))
+ wdt = 2*sw/3 - BORDER_WIDTH;
+
+ } else {
+ if(x > 2) {
+ if((n == 1) || (n == 2))
+ ht = (sh/2) + growth - BORDER_WIDTH;
+ if(n >= 3)
+ ht = (sh/2) - growth - 2*BORDER_WIDTH;
+ }
+ else
+ ht = sh - BORDER_WIDTH;
+ if((n == 1) || (n == 3)) {
+ xpos = 0;
+ wdt = master_size - BORDER_WIDTH;
+ }
+ if((n == 2) || (n == 4)) {
+ xpos = master_size+BORDER_WIDTH;
+ wdt = (sw - master_size) - 2*BORDER_WIDTH;
+ }
+ if(n == 3)
+ y += (sh/2) + growth + BORDER_WIDTH;
+ if((n == x) && (n == 3))
+ wdt = sw - BORDER_WIDTH;
+ }
+ XMoveResizeWindow(dis,c->win,xpos,y,wdt,ht);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void update_current() {
+ client *c;
+
+ for(c=head;c;c=c->next) {
+ if((head->next == NULL) || (mode == 1))
+ XSetWindowBorderWidth(dis,c->win,0);
+ else
+ XSetWindowBorderWidth(dis,c->win,BORDER_WIDTH);
+
+ if(current == c) {
+ // "Enable" current window
+ XSetWindowBorder(dis,c->win,win_focus);
+ XSetInputFocus(dis,c->win,RevertToParent,CurrentTime);
+ XRaiseWindow(dis,c->win);
+ if(CLICK_TO_FOCUS == 0)
+ XUngrabButton(dis, AnyButton, AnyModifier, c->win);
+ }
+ else {
+ XSetWindowBorder(dis,c->win,win_unfocus);
+ if(CLICK_TO_FOCUS == 0)
+ XGrabButton(dis, AnyButton, AnyModifier, c->win, True, ButtonPressMask|ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None);
+ }
+ }
+ XSync(dis, False);
+}
+
+void switch_vertical() {
+ if(mode != 0) {
+ mode = 0;
+ master_size = sw * MASTER_SIZE;
+ tile();
+ update_current();
+ }
+}
+
+void switch_fullscreen() {
+ if(mode != 1) {
+ mode = 1;
+ tile();
+ update_current();
+ }
+}
+
+void switch_horizontal() {
+ if(mode != 2) {
+ mode = 2;
+ master_size = sh * MASTER_SIZE;
+ tile();
+ update_current();
+ }
+}
+
+void switch_grid() {
+ if(mode != 3) {
+ mode = 3;
+ master_size = sw * MASTER_SIZE;
+ tile();
+ update_current();
+ }
+}
+
+void resize_master(const Arg arg) {
+ master_size += arg.i;
+ tile();
+}
+
+void resize_stack(const Arg arg) {
+ growth += arg.i;
+ tile();
+}
+
+/* ********************** Keyboard Management ********************** */
+void grabkeys() {
+ int i;
+ KeyCode code;
+
+ XUngrabKey(dis, AnyKey, AnyModifier, root);
+ // For each shortcuts
+ for(i=0;i<TABLENGTH(keys);++i) {
+ code = XKeysymToKeycode(dis,keys[i].keysym);
+ XGrabKey(dis, code, keys[i].mod, root, True, GrabModeAsync, GrabModeAsync);
+ XGrabKey(dis, code, keys[i].mod | LockMask, root, True, GrabModeAsync, GrabModeAsync);
+ XGrabKey(dis, code, keys[i].mod | numlockmask, root, True, GrabModeAsync, GrabModeAsync);
+ XGrabKey(dis, code, keys[i].mod | numlockmask | LockMask, root, True, GrabModeAsync, GrabModeAsync);
+ }
+}
+
+void keypress(XEvent *e) {
+ static unsigned int len = sizeof keys / sizeof keys[0];
+ unsigned int i;
+ KeySym keysym;
+ XKeyEvent *ev = &e->xkey;
+
+ 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;
+ if(ev->width < sw-BORDER_WIDTH)
+ wc.width = ev->width;
+ else
+ wc.width = sw-BORDER_WIDTH;
+ if(ev->height < sh-BORDER_WIDTH)
+ wc.height = ev->height;
+ else
+ wc.height = sh-BORDER_WIDTH;
+ 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,-BORDER_WIDTH,-BORDER_WIDTH,sw+BORDER_WIDTH,sh+BORDER_WIDTH);
+ return;
+ }
+
+ Window trans = None;
+ if (XGetTransientForHint(dis, ev->window, &trans) && trans != None) {
+ add_window(ev->window);
+ XMapWindow(dis, ev->window);
+ XSetInputFocus(dis,ev->window,RevertToParent,CurrentTime);
+ XRaiseWindow(dis,ev->window);
+ return;
+ }
+
+ unsigned long count, j, extra;
+ Atom realType;
+ int realFormat;
+ unsigned char *temp;
+ Atom *type;
+
+ if(XGetWindowProperty(dis, ev->window, atoms[ATOM_NET_WM_WINDOW_TYPE], 0, 32, False, XA_ATOM, &realType, &realFormat, &count, &extra, &temp) == Success) {
+ if(count > 0) {
+ type = (unsigned long*)temp;
+ for(j=0; j<count; j++) {
+ if((type[j] == atoms[ATOM_NET_WM_WINDOW_TYPE_UTILITY]) ||
+ (type[j] == atoms[ATOM_NET_WM_WINDOW_TYPE_NOTIFICATION]) ||
+ (type[j] == atoms[ATOM_NET_WM_WINDOW_TYPE_SPLASH]) ||
+ (type[j] == atoms[ATOM_NET_WM_WINDOW_TYPE_DIALOG]) ||
+ (type[j] == atoms[ATOM_NET_WM_WINDOW_TYPE_DOCK])) {
+ add_window(ev->window);
+ XMapWindow(dis, ev->window);
+ XSetInputFocus(dis,ev->window,RevertToParent,CurrentTime);
+ XRaiseWindow(dis,ev->window);
+ return;
+ }
+ }
+ }
+ if(temp)
+ XFree(temp);
+ }
+
+ XClassHint ch = {0};
+ static unsigned int len = sizeof convenience / sizeof convenience[0];
+ int i = 0;
+ int tmp = current_desktop;
+ if(XGetClassHint(dis, ev->window, &ch))
+ for(i=0;i<len;i++)
+ if(strcmp(ch.res_class, convenience[i].class) == 0) {
+ save_desktop(tmp);
+ select_desktop(convenience[i].preferredd-1);
+ add_window(ev->window);
+ if(tmp == convenience[i].preferredd-1) {
+ XMapWindow(dis, ev->window);
+ tile();
+ update_current();
+ } else {
+ select_desktop(tmp);
+ }
+ if(convenience[i].followwin != 0) {
+ Arg a = {.i = convenience[i].preferredd-1};
+ change_desktop(a);
+ }
+ if(ch.res_class)
+ XFree(ch.res_class);
+ if(ch.res_name)
+ XFree(ch.res_name);
+ 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;j<TABLENGTH(desktops);++j) {
+ select_desktop(j);
+ for(c=head;c;c=c->next)
+ if(ev->window == c->win)
+ i++;
+
+ if(i != 0) {
+ remove_window(ev->window);
+ select_desktop(tmp);
+ return;
+ }
+
+ i = 0;
+ }
+ select_desktop(tmp);
+}
+
+void enternotify(XEvent *e) {
+ client *c;
+ XCrossingEvent *ev = &e->xcrossing;
+
+ if(FOLLOW_MOUSE == 0) {
+ if((ev->mode != NotifyNormal || ev->detail == NotifyInferior) && ev->window != root)
+ return;
+ for(c=head;c;c=c->next)
+ if(ev->window == c->win) {
+ current = c;
+ update_current();
+ return;
+ }
+ }
+}
+
+void buttonpressed(XEvent *e) {
+ client *c;
+ XButtonPressedEvent *ev = &e->xbutton;
+
+ // change focus with LMB
+ if(CLICK_TO_FOCUS == 0 && ev->window != current->win && ev->button == Button1)
+ for(c=head;c;c=c->next)
+ if(ev->window == c->win) {
+ current = c;
+ update_current();
+ return;
+ }
+}
+
+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
+ if(mode == 2)
+ master_size = sh*MASTER_SIZE;
+ else
+ master_size = sw*MASTER_SIZE;
+
+ // Set up all desktop
+ int i;
+ for(i=0;i<TABLENGTH(desktops);++i) {
+ desktops[i].master_size = master_size;
+ desktops[i].mode = mode;
+ desktops[i].growth = growth;
+ desktops[i].head = head;
+ desktops[i].current = current;
+ }
+
+ // Select first dekstop by default
+ const Arg arg = {.i = 0};
+ current_desktop = arg.i;
+ change_desktop(arg);
+ // Set up atoms for dialog/notification windows
+ int x;
+ for(x = 0; x < ATOM_COUNT; x++)
+ *atomList[x].atom = XInternAtom(dis, atomList[x].name, False);
+ // To catch maprequest and destroynotify (if other wm running)
+ XSelectInput(dis,root,SubstructureNotifyMask|SubstructureRedirectMask);
+ XSetErrorHandler(xerror);
+ logger("\033[0;32mWe're up and running!");
+}
+
+void sigchld(int unused) {
+ // Again, thx to dwm ;)
+ if(signal(SIGCHLD, sigchld) == SIG_ERR) {
+ logger("\033[0;31mCan't install SIGCHLD handler");
+ exit(1);
+ }
+ while(0 < waitpid(-1, NULL, WNOHANG));
+}
+
+void spawn(const Arg arg) {
+ if(fork() == 0) {
+ if(fork() == 0) {
+ if(dis)
+ close(ConnectionNumber(dis));
+
+ setsid();
+ execvp((char*)arg.com[0],(char**)arg.com);
+ }
+ exit(0);
+ }
+}
+
+/* There's no way to check accesses to destroyed windows, thus those cases are ignored (especially on UnmapNotify's). Other types of errors call Xlibs default error handler, which may call exit. */
+int xerror(Display *dis, XErrorEvent *ee) {
+ if(ee->error_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;
+}
Please sign in to comment.
Something went wrong with that request. Please try again.