Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Added files

  • Loading branch information...
commit d03d3292ca49244004552ccc3ec0965caa413d09 1 parent 714ac37
moetunes authored

Showing 4 changed files with 1,240 additions and 0 deletions. Show diff stats Hide diff stats

  1. +52 0 ChangeLog
  2. +21 0 Makefile
  3. +127 0 config.h.def
  4. +1,040 0 dminiwm.c
52 ChangeLog
... ... @@ -0,0 +1,52 @@
  1 +28/11/11
  2 + Added last desktop function for switching back to the last opened desktop
  3 +
  4 +26/11/11
  5 + Added option to click on a window to focus it
  6 +
  7 +21/11/11
  8 + Fix for transient windows not being managed
  9 +
  10 +15/11/11
  11 + Fix for when trying to swap master with only one window
  12 +
  13 +23/10/11
  14 + Fine tuned the popup window management so notification windows aren't managed either
  15 +
  16 +15/10/11
  17 + Added having applications start on specified desktop
  18 +
  19 +13/10/11
  20 + Added ability to use grow_window/shrink_window in grid mode with 3 or 4 windows
  21 +
  22 +13/10/11
  23 + Popup windows now aren't managed/added to the stack
  24 +
  25 +10/10/11
  26 + Reapplied setting master_size relevant to default mode
  27 +
  28 +8/10/11
  29 + For only one window or fullscreen mode there is no border
  30 +
  31 +8/10/11
  32 + Fixed fullscreen mplayer
  33 +
  34 +8/10/11
  35 + Removed useless gaps when in grid mode
  36 +
  37 +16/9/11
  38 + Added back the option to have the panel at the top
  39 + Fine tuned the grid tiling mode
  40 +
  41 +13/9/11
  42 + Added back horizontal tiling, follow mouse and follow window
  43 +
  44 +12/9/11
  45 + Returned to catwm tiling methods - with the ability to resize the window at the top of the stack
  46 +
  47 +9/9/11
  48 + Fine tuned the next/prev desktop and the destroy notify functions
  49 +
  50 + 8/9/11
  51 + Have a proper destroy notify function now that removes destroyed windows from
  52 + the window manager stack for the desktop they were on.
21 Makefile
... ... @@ -0,0 +1,21 @@
  1 +CFLAGS+= -Wall
  2 +LDADD+= -lX11
  3 +LDFLAGS=
  4 +EXEC=dminiwm
  5 +
  6 +PREFIX?= /usr/local
  7 +BINDIR?= $(PREFIX)/bin
  8 +
  9 +CC=gcc
  10 +
  11 +all: $(EXEC)
  12 +
  13 +dminiwm: dminiwm.o
  14 + $(CC) $(LDFLAGS) -s -Os -o $@ $+ $(LDADD)
  15 +
  16 +install: all
  17 + install -Dm 755 dminiwm $(DESTDIR)$(BINDIR)/dminiwm
  18 +
  19 +clean:
  20 + rm -fv dminiwm *.o
  21 +
127 config.h.def
... ... @@ -0,0 +1,127 @@
  1 + /* config.h for dminiwm.c [ 0.2.0 ]
  2 + *
  3 + * Started from catwm 31/12/10
  4 + * Bad window error checking and numlock checking used from
  5 + * 2wm at http://hg.suckless.org/2wm/
  6 + *
  7 + * This program is free software: you can redistribute it and/or modify
  8 + * it under the terms of the GNU General Public License as published by
  9 + * the Free Software Foundation, either version 3 of the License, or
  10 + * (at your option) any later version.
  11 + *
  12 + * This program is distributed in the hope that it will be useful,
  13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15 + * GNU General Public License for more details.
  16 + *
  17 + * You should have received a copy of the GNU General Public License
  18 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
  19 + *
  20 + */
  21 +
  22 +#ifndef CONFIG_H
  23 +#define CONFIG_H
  24 +
  25 +#define CLEANMASK(mask) (mask & ~(numlockmask | LockMask))
  26 +
  27 +/* Mod (Mod1 == alt) (Mod4 == Super/windows) */
  28 +#define MOD1 Mod1Mask
  29 +#define MOD4 Mod4Mask
  30 +#define MASTER_SIZE 0.52
  31 +#define TOP_PANEL 1 /* 1=Don't 0=Have the panel at the top instead of the bottom */
  32 +#define PANEL_HEIGHT 18 /* 0 for no space for a panel */
  33 +#define BORDER_WIDTH 2
  34 +#define ATTACH_ASIDE 1 /* 0=TRUE, 1=New window is master */
  35 +#define DEFAULT_MODE 0 /* 0=Vertical, 1=Fullscreen 2=Horizontal 3=grid*/
  36 +#define FOLLOW_MOUSE 0 /* 1=Don't 0=Focus the window the mouse just entered */
  37 +#define FOLLOW_WINDOW 0 /* 1=Don't 0=Follow the window when moved to a different desktop */
  38 +#define CLICK_TO_FOCUS 1 /* 1=Don't 0=Focus an unfocused window when clicked */
  39 +#define DESKTOPS 6 /* Must edit DESKTOPCHANGE keys to suit */
  40 +
  41 +// Colors
  42 +#define FOCUS "#664422" // dkorange
  43 +#define UNFOCUS "#004050" // blueish
  44 +
  45 +// Applications to a specific desktop
  46 +static const Convenience convenience[] = { \
  47 + /* class desktop follow */
  48 + { "Thunar", 2, 1 },
  49 + //{ "Leafpad", 2, 1 },
  50 + { "Firefox", 3, 0 },
  51 + { "Links", 3, 1 },
  52 + { "MPlayer", 4, 1 },
  53 + { "Thunderbird", 5, 0 },
  54 + { "Pysol", 6, 1 },
  55 +};
  56 +
  57 +const char* dmenucmd[] = {"dmenu_run","-i","-nb","#666622","-nf","white",NULL};
  58 +const char* urxvtcmd[] = {"urxvtc",NULL};
  59 +const char* terminalcmd[] = {"Terminal",NULL};
  60 +const char* thunarcmd[] = {"thunar",NULL};
  61 +const char* firefoxcmd[] = {"firefox",NULL};
  62 +const char* webcmd[] = {"links","-g",NULL};
  63 +const char* luakitcmd[] = {"/home/pnewm/.bin/launchbrowser",NULL};
  64 +const char* mailcmd[] = {"thunderbird",NULL };
  65 +const char* voldowncmd[] = {"/home/pnewm/.bin/voldown",NULL};
  66 +const char* volupcmd[] = {"/home/pnewm/.bin/volup",NULL};
  67 +const char* prevoldowncmd[] = {"/home/pnewm/.bin/prevoldown",NULL};
  68 +const char* prevolupcmd[] = {"/home/pnewm/.bin/prevolup",NULL};
  69 +const char* vols_what[] = {"/home/pnewm/.bin/volumes_what",NULL};
  70 +// for reboot and shutdown
  71 +const char* rebootcmd[] = {"sudo","reboot",NULL};
  72 +const char* shutdowncmd[] = {"sudo","shutdown","-h","now",NULL};
  73 +
  74 +// Avoid multiple paste
  75 +#define DESKTOPCHANGE(K,N) \
  76 + { MOD1, K, change_desktop, {.i = N}}, \
  77 + { MOD1|ShiftMask, K, client_to_desktop, {.i = N}},
  78 +
  79 +// Shortcuts
  80 +static key keys[] = {
  81 + // MOD KEY FUNCTION ARGS
  82 + { MOD1, XK_h, resize_master, {.i = 10}},
  83 + { MOD1, XK_l, resize_master, {.i = -10}},
  84 + { MOD1, XK_c, kill_client, {NULL}},
  85 + { MOD1, XK_j, next_win, {NULL}},
  86 + { MOD1, XK_k, prev_win, {NULL}},
  87 + { MOD1, XK_v, spawn, {.com = dmenucmd}},
  88 + { MOD1, XK_p, resize_stack, {.i = 10}},
  89 + { MOD1, XK_o, resize_stack, {.i = -10}},
  90 + { MOD1, XK_Tab, toggle_desktop, {NULL}},
  91 + { MOD1, XK_Return, spawn, {.com = urxvtcmd}},
  92 + { MOD1, XK_Up, spawn, {.com = volupcmd}},
  93 + { MOD1, XK_Down, spawn, {.com = voldowncmd}},
  94 +// alt + shift + shortcut
  95 + { MOD1|ShiftMask, XK_j, move_up, {NULL}},
  96 + { MOD1|ShiftMask, XK_k, move_down, {NULL}},
  97 + { MOD1|ShiftMask, XK_Return, swap_master, {NULL}},
  98 + { MOD1|ShiftMask, XK_g, switch_grid, {NULL}},
  99 + { MOD1|ShiftMask, XK_h, switch_horizontal, {NULL}},
  100 + { MOD1|ShiftMask, XK_m, switch_fullscreen, {NULL}},
  101 + { MOD1|ShiftMask, XK_v, switch_vertical, {NULL}},
  102 +// Control + alt + shortcut
  103 + { MOD1|ControlMask, XK_q, quit, {NULL}},
  104 + { MOD1|ControlMask, XK_r, spawn, {.com = rebootcmd}},
  105 + { MOD1|ControlMask, XK_s, spawn, {.com = shutdowncmd}},
  106 +// Window key + shortcut
  107 + { MOD4, XK_Right, next_desktop, {NULL}},
  108 + { MOD4, XK_Left, prev_desktop, {NULL}},
  109 + { MOD4, XK_e, spawn, {.com = mailcmd}},
  110 + { MOD4, XK_f, spawn, {.com = firefoxcmd}},
  111 + { MOD4, XK_w, spawn, {.com = webcmd}},
  112 + { MOD4, XK_l, spawn, {.com = luakitcmd}},
  113 + { MOD4, XK_h, spawn, {.com = thunarcmd}},
  114 + { MOD4, XK_t, spawn, {.com = terminalcmd}},
  115 + { MOD4, XK_v, spawn, {.com = vols_what}},
  116 + { MOD4, XK_Up, spawn, {.com = prevolupcmd}},
  117 + { MOD4, XK_Down, spawn, {.com = prevoldowncmd}},
  118 + DESKTOPCHANGE( XK_1, 0)
  119 + DESKTOPCHANGE( XK_2, 1)
  120 + DESKTOPCHANGE( XK_3, 2)
  121 + DESKTOPCHANGE( XK_4, 3)
  122 + DESKTOPCHANGE( XK_5, 4)
  123 + DESKTOPCHANGE( XK_6, 5)
  124 +};
  125 +
  126 +#endif
  127 +
1,040 dminiwm.c
... ... @@ -0,0 +1,1040 @@
  1 +/* dminiwm.c [ 0.2.0 ]
  2 +*
  3 +* I started this from catwm 31/12/10
  4 +* Bad window error checking and numlock checking used from
  5 +* 2wm at http://hg.suckless.org/2wm/
  6 +*
  7 +* This program is free software: you can redistribute it and/or modify
  8 +* it under the terms of the GNU General Public License as published by
  9 +* the Free Software Foundation, either version 3 of the License, or
  10 +* (at your option) any later version.
  11 +* This program is distributed in the hope that it will be useful,
  12 +* but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14 +* GNU General Public License for more details.
  15 +* You should have received a copy of the GNU General Public License
  16 +* along with this program. If not, see <http://www.gnu.org/licenses/>.
  17 +*/
  18 +
  19 +#include <X11/Xlib.h>
  20 +#include <X11/keysym.h>
  21 +//#include <X11/XF86keysym.h>
  22 +#include <X11/Xproto.h>
  23 +#include <X11/Xutil.h>
  24 +#include <X11/Xatom.h>
  25 +#include <stdio.h>
  26 +#include <unistd.h>
  27 +#include <stdlib.h>
  28 +#include <signal.h>
  29 +#include <sys/wait.h>
  30 +#include <string.h>
  31 +
  32 +#define TABLENGTH(X) (sizeof(X)/sizeof(*X))
  33 +
  34 +typedef union {
  35 + const char** com;
  36 + const int i;
  37 +} Arg;
  38 +
  39 +// Structs
  40 +typedef struct {
  41 + unsigned int mod;
  42 + KeySym keysym;
  43 + void (*function)(const Arg arg);
  44 + const Arg arg;
  45 +} key;
  46 +
  47 +typedef struct client client;
  48 +struct client{
  49 + // Prev and next client
  50 + client *next;
  51 + client *prev;
  52 +
  53 + // The window
  54 + Window win;
  55 +};
  56 +
  57 +typedef struct desktop desktop;
  58 +struct desktop{
  59 + int master_size;
  60 + int mode;
  61 + int growth;
  62 + client *head;
  63 + client *current;
  64 +};
  65 +
  66 +typedef struct {
  67 + const char *class;
  68 + int preferredd;
  69 + int followwin;
  70 +} Convenience;
  71 +
  72 +typedef enum {
  73 + ATOM_NET_WM_WINDOW_TYPE,
  74 + ATOM_NET_WM_WINDOW_TYPE_UTILITY,
  75 + ATOM_NET_WM_WINDOW_TYPE_DOCK,
  76 + ATOM_NET_WM_WINDOW_TYPE_SPLASH,
  77 + ATOM_NET_WM_WINDOW_TYPE_DIALOG,
  78 + ATOM_NET_WM_WINDOW_TYPE_NOTIFICATION,
  79 + ATOM_COUNT
  80 +} AtomType;
  81 +
  82 +typedef struct {
  83 + Atom *atom;
  84 + const char *name;
  85 +} AtomNode;
  86 +
  87 +Atom atoms[ATOM_COUNT];
  88 +
  89 +static const AtomNode atomList[] = {
  90 + { &atoms[ATOM_NET_WM_WINDOW_TYPE], "_NET_WM_WINDOW_TYPE" },
  91 + { &atoms[ATOM_NET_WM_WINDOW_TYPE_UTILITY], "_NET_WM_WINDOW_TYPE_UTILITY" },
  92 + { &atoms[ATOM_NET_WM_WINDOW_TYPE_DOCK], "_NET_WM_WINDOW_TYPE_DOCK" },
  93 + { &atoms[ATOM_NET_WM_WINDOW_TYPE_SPLASH], "_NET_WM_WINDOW_TYPE_SPLASH" },
  94 + { &atoms[ATOM_NET_WM_WINDOW_TYPE_DIALOG], "_NET_WM_WINDOW_TYPE_DIALOG" },
  95 + { &atoms[ATOM_NET_WM_WINDOW_TYPE_NOTIFICATION], "_NET_WM_WINDOW_TYPE_NOTIFICATION"},
  96 +};
  97 +
  98 +// Functions
  99 +static void add_window(Window w);
  100 +static void buttonpressed(XEvent *e);
  101 +static void change_desktop(const Arg arg);
  102 +static void client_to_desktop(const Arg arg);
  103 +static void configurenotify(XEvent *e);
  104 +static void configurerequest(XEvent *e);
  105 +static void destroynotify(XEvent *e);
  106 +static void enternotify(XEvent *e);
  107 +static void logger(const char* e);
  108 +static unsigned long getcolor(const char* color);
  109 +static void grabkeys();
  110 +static void keypress(XEvent *e);
  111 +static void kill_client();
  112 +static void maprequest(XEvent *e);
  113 +static void move_down();
  114 +static void move_up();
  115 +static void next_desktop();
  116 +static void next_win();
  117 +static void prev_desktop();
  118 +static void prev_win();
  119 +static void quit();
  120 +static void remove_window(Window w);
  121 +static void resize_master(const Arg arg);
  122 +static void resize_stack(const Arg arg);
  123 +static void save_desktop(int i);
  124 +static void select_desktop(int i);
  125 +static void send_kill_signal(Window w);
  126 +static void setup();
  127 +static void sigchld(int unused);
  128 +static void spawn(const Arg arg);
  129 +static void start();
  130 +static void swap_master();
  131 +static void tile();
  132 +static void toggle_desktop();
  133 +static void switch_fullscreen();
  134 +static void switch_grid();
  135 +static void switch_horizontal();
  136 +static void switch_vertical();
  137 +static void update_current();
  138 +
  139 +// Include configuration file (need struct key)
  140 +#include "config.h"
  141 +
  142 +// Variable
  143 +static Display *dis;
  144 +static int bool_quit;
  145 +static int current_desktop;
  146 +static int previous_desktop;
  147 +static int growth;
  148 +static int master_size;
  149 +static int mode;
  150 +static int sh;
  151 +static int sw;
  152 +static int screen;
  153 +static int xerror(Display *dis, XErrorEvent *ee);
  154 +static int (*xerrorxlib)(Display *, XErrorEvent *);
  155 +static unsigned int win_focus;
  156 +static unsigned int win_unfocus;
  157 +unsigned int numlockmask; /* dynamic key lock mask */
  158 +static Window root;
  159 +static client *head;
  160 +static client *current;
  161 +
  162 +// Events array
  163 +static void (*events[LASTEvent])(XEvent *e) = {
  164 + [KeyPress] = keypress,
  165 + [MapRequest] = maprequest,
  166 + [EnterNotify] = enternotify,
  167 + [ButtonPress] = buttonpressed,
  168 + [DestroyNotify] = destroynotify,
  169 + [ConfigureNotify] = configurenotify,
  170 + [ConfigureRequest] = configurerequest
  171 +};
  172 +
  173 +// Desktop array
  174 +static desktop desktops[DESKTOPS];
  175 +
  176 +/* ***************************** Window Management ******************************* */
  177 +void add_window(Window w) {
  178 + client *c,*t;
  179 +
  180 + if(!(c = (client *)calloc(1,sizeof(client)))) {
  181 + logger("\033[0;31mError calloc!");
  182 + exit(1);
  183 + }
  184 +
  185 + if(head == NULL) {
  186 + c->next = NULL;
  187 + c->prev = NULL;
  188 + c->win = w;
  189 + head = c;
  190 + }
  191 + else {
  192 + if(ATTACH_ASIDE == 0) {
  193 + for(t=head;t->next;t=t->next);
  194 +
  195 + c->next = NULL;
  196 + c->prev = t;
  197 + c->win = w;
  198 +
  199 + t->next = c;
  200 + }
  201 + else {
  202 + for(t=head;t->prev;t=t->prev);
  203 +
  204 + c->prev = NULL;
  205 + c->next = t;
  206 + c->win = w;
  207 +
  208 + t->prev = c;
  209 +
  210 + head = c;
  211 + }
  212 + }
  213 +
  214 + current = c;
  215 + save_desktop(current_desktop);
  216 + // for folow mouse
  217 + if(FOLLOW_MOUSE == 0)
  218 + XSelectInput(dis, c->win, EnterWindowMask);
  219 +}
  220 +
  221 +void remove_window(Window w) {
  222 + client *c;
  223 +
  224 + // CHANGE THIS UGLY CODE
  225 + for(c=head;c;c=c->next) {
  226 +
  227 + if(c->win == w) {
  228 + if(c->prev == NULL && c->next == NULL) {
  229 + free(head);
  230 + head = NULL;
  231 + current = NULL;
  232 + save_desktop(current_desktop);
  233 + return;
  234 + }
  235 +
  236 + if(c->prev == NULL) {
  237 + head = c->next;
  238 + c->next->prev = NULL;
  239 + current = c->next;
  240 + }
  241 + else if(c->next == NULL) {
  242 + c->prev->next = NULL;
  243 + current = c->prev;
  244 + }
  245 + else {
  246 + c->prev->next = c->next;
  247 + c->next->prev = c->prev;
  248 + current = c->prev;
  249 + }
  250 +
  251 + free(c);
  252 + save_desktop(current_desktop);
  253 + tile();
  254 + update_current();
  255 + return;
  256 + }
  257 + }
  258 +}
  259 +
  260 +void kill_client() {
  261 + if(current != NULL) {
  262 + //send delete signal to window
  263 + XEvent ke;
  264 + ke.type = ClientMessage;
  265 + ke.xclient.window = current->win;
  266 + ke.xclient.message_type = XInternAtom(dis, "WM_PROTOCOLS", True);
  267 + ke.xclient.format = 32;
  268 + ke.xclient.data.l[0] = XInternAtom(dis, "WM_DELETE_WINDOW", True);
  269 + ke.xclient.data.l[1] = CurrentTime;
  270 + XSendEvent(dis, current->win, False, NoEventMask, &ke);
  271 + send_kill_signal(current->win);
  272 + remove_window(current->win);
  273 + }
  274 +}
  275 +
  276 +void next_win() {
  277 + client *c;
  278 +
  279 + if(current != NULL && head != NULL) {
  280 + if(current->next == NULL)
  281 + c = head;
  282 + else
  283 + c = current->next;
  284 +
  285 + current = c;
  286 + if(mode == 1)
  287 + tile();
  288 + update_current();
  289 + }
  290 +}
  291 +
  292 +void prev_win() {
  293 + client *c;
  294 +
  295 + if(current != NULL && head != NULL) {
  296 + if(current->prev == NULL)
  297 + for(c=head;c->next;c=c->next);
  298 + else
  299 + c = current->prev;
  300 +
  301 + current = c;
  302 + if(mode == 1)
  303 + tile();
  304 + update_current();
  305 + }
  306 +}
  307 +
  308 +void move_down() {
  309 + Window tmp;
  310 + if(current == NULL || current->next == NULL || current->win == head->win || current->prev == NULL)
  311 + return;
  312 +
  313 + tmp = current->win;
  314 + current->win = current->next->win;
  315 + current->next->win = tmp;
  316 + //keep the moved window activated
  317 + next_win();
  318 + save_desktop(current_desktop);
  319 + tile();
  320 +}
  321 +
  322 +void move_up() {
  323 + Window tmp;
  324 + if(current == NULL || current->prev == head || current->win == head->win) {
  325 + return;
  326 + }
  327 + tmp = current->win;
  328 + current->win = current->prev->win;
  329 + current->prev->win = tmp;
  330 + prev_win();
  331 + save_desktop(current_desktop);
  332 + tile();
  333 +}
  334 +
  335 +void swap_master() {
  336 + Window tmp;
  337 +
  338 + if(head->next != NULL && current != NULL && mode != 1) {
  339 + if(current == head) {
  340 + tmp = head->next->win;
  341 + head->next->win = head->win;
  342 + head->win = tmp;
  343 + } else {
  344 + tmp = head->win;
  345 + head->win = current->win;
  346 + current->win = tmp;
  347 + current = head;
  348 + }
  349 + save_desktop(current_desktop);
  350 + tile();
  351 + update_current();
  352 + }
  353 +}
  354 +
  355 +/* **************************** Desktop Management ************************************* */
  356 +void change_desktop(const Arg arg) {
  357 + client *c;
  358 +
  359 + if(arg.i == current_desktop)
  360 + return;
  361 +
  362 + // Save current "properties"
  363 + save_desktop(current_desktop);
  364 + previous_desktop = current_desktop;
  365 +
  366 + // Unmap all window
  367 + if(head != NULL)
  368 + for(c=head;c;c=c->next)
  369 + XUnmapWindow(dis,c->win);
  370 +
  371 + // Take "properties" from the new desktop
  372 + select_desktop(arg.i);
  373 +
  374 + // Map all windows
  375 + if(head != NULL)
  376 + for(c=head;c;c=c->next)
  377 + XMapWindow(dis,c->win);
  378 +
  379 + tile();
  380 + update_current();
  381 +}
  382 +
  383 +void toggle_desktop() {
  384 + Arg a = {.i = previous_desktop};
  385 + change_desktop(a);
  386 +}
  387 +
  388 +void next_desktop() {
  389 + int tmp = current_desktop;
  390 + if(tmp == TABLENGTH(desktops)-1)
  391 + tmp = 0;
  392 + else
  393 + tmp++;
  394 +
  395 + Arg a = {.i = tmp};
  396 + change_desktop(a);
  397 +}
  398 +
  399 +void prev_desktop() {
  400 + int tmp = current_desktop;
  401 + if(tmp == 0)
  402 + tmp = TABLENGTH(desktops)-1;
  403 + else
  404 + tmp--;
  405 +
  406 + Arg a = {.i = tmp};
  407 + change_desktop(a);
  408 +}
  409 +
  410 +void client_to_desktop(const Arg arg) {
  411 + client *tmp = current;
  412 + int tmp2 = current_desktop;
  413 +
  414 + if(arg.i == current_desktop || current == NULL)
  415 + return;
  416 +
  417 + // Add client to desktop
  418 + select_desktop(arg.i);
  419 + add_window(tmp->win);
  420 + save_desktop(arg.i);
  421 +
  422 + // Remove client from current desktop
  423 + select_desktop(tmp2);
  424 + XUnmapWindow(dis,tmp->win);
  425 + remove_window(tmp->win);
  426 + save_desktop(tmp2);
  427 + tile();
  428 + update_current();
  429 + if(FOLLOW_WINDOW == 0)
  430 + change_desktop(arg);
  431 +}
  432 +
  433 +void save_desktop(int i) {
  434 + desktops[i].master_size = master_size;
  435 + desktops[i].mode = mode;
  436 + desktops[i].growth = growth;
  437 + desktops[i].head = head;
  438 + desktops[i].current = current;
  439 +}
  440 +
  441 +void select_desktop(int i) {
  442 + master_size = desktops[i].master_size;
  443 + mode = desktops[i].mode;
  444 + growth = desktops[i].growth;
  445 + head = desktops[i].head;
  446 + current = desktops[i].current;
  447 + current_desktop = i;
  448 +}
  449 +
  450 +void tile() {
  451 + client *c;
  452 + int n = 0;
  453 + int x = 0;
  454 + int y = 0;
  455 +
  456 + // For a top panel
  457 + if(TOP_PANEL == 0)
  458 + y = PANEL_HEIGHT;
  459 +
  460 + // If only one window
  461 + if(head != NULL && head->next == NULL) {
  462 + XMoveResizeWindow(dis,head->win,0,y,sw+2*BORDER_WIDTH,sh+2*BORDER_WIDTH);
  463 + }
  464 + else if(head != NULL) {
  465 + switch(mode) {
  466 + case 0: /* Vertical */
  467 + // Master window
  468 + XMoveResizeWindow(dis,head->win,0,y,master_size - BORDER_WIDTH,sh - BORDER_WIDTH);
  469 +
  470 + // Stack
  471 + for(c=head->next;c;c=c->next) ++n;
  472 + if(n == 1) growth = 0;
  473 + XMoveResizeWindow(dis,head->next->win,master_size + BORDER_WIDTH,y,sw-master_size-(2*BORDER_WIDTH),(sh/n)+growth - BORDER_WIDTH);
  474 + y += (sh/n)+growth;
  475 + for(c=head->next->next;c;c=c->next) {
  476 + XMoveResizeWindow(dis,c->win,master_size + BORDER_WIDTH,y,sw-master_size-(2*BORDER_WIDTH),(sh/n)-(growth/(n-1)) - BORDER_WIDTH);
  477 + y += (sh/n)-(growth/(n-1));
  478 + }
  479 + break;
  480 + case 1: /* Fullscreen */
  481 + for(c=head;c;c=c->next) {
  482 + XMoveResizeWindow(dis,c->win,0,y,sw+2*BORDER_WIDTH,sh+2*BORDER_WIDTH);
  483 + }
  484 + break;
  485 + case 2: /* Horizontal */
  486 + // Master window
  487 + XMoveResizeWindow(dis,head->win,0,y,sw-BORDER_WIDTH,master_size - BORDER_WIDTH);
  488 +
  489 + // Stack
  490 + for(c=head->next;c;c=c->next) ++n;
  491 + if(n == 1) growth = 0;
  492 + XMoveResizeWindow(dis,head->next->win,0,y+master_size + BORDER_WIDTH,(sw/n)+growth-BORDER_WIDTH,sh-master_size-(2*BORDER_WIDTH));
  493 + x = (sw/n)+growth;
  494 + for(c=head->next->next;c;c=c->next) {
  495 + XMoveResizeWindow(dis,c->win,x,y+master_size + BORDER_WIDTH,(sw/n)-(growth/(n-1)) - BORDER_WIDTH,sh-master_size-(2*BORDER_WIDTH));
  496 + x += (sw/n)-(growth/(n-1));
  497 + }
  498 + break;
  499 + case 3: { // Grid
  500 + int xpos = 0;
  501 + int wdt = 0;
  502 + int ht = 0;
  503 +
  504 + for(c=head;c;c=c->next) ++x;
  505 +
  506 + for(c=head;c;c=c->next) {
  507 + ++n;
  508 + if(x >= 7) {
  509 + wdt = (sw/3) - BORDER_WIDTH;
  510 + ht = (sh/3) - BORDER_WIDTH;
  511 + if((n == 1) || (n == 4) || (n == 7))
  512 + xpos = 0;
  513 + if((n == 2) || (n == 5) || (n == 8))
  514 + xpos = (sw/3) + BORDER_WIDTH;
  515 + if((n == 3) || (n == 6) || (n == 9))
  516 + xpos = (2*(sw/3)) + BORDER_WIDTH;
  517 + if((n == 4) || (n == 7))
  518 + y += (sh/3) + BORDER_WIDTH;
  519 + if((n == x) && (n == 7))
  520 + wdt = sw - BORDER_WIDTH;
  521 + if((n == x) && (n == 8))
  522 + wdt = 2*sw/3 - BORDER_WIDTH;
  523 + } else
  524 + if(x >= 5) {
  525 + wdt = (sw/3) - BORDER_WIDTH;
  526 + ht = (sh/2) - BORDER_WIDTH;
  527 + if((n == 1) || (n == 4))
  528 + xpos = 0;
  529 + if((n == 2) || (n == 5))
  530 + xpos = (sw/3) + BORDER_WIDTH;
  531 + if((n == 3) || (n == 6))
  532 + xpos = (2*(sw/3)) + BORDER_WIDTH;
  533 + if(n == 4)
  534 + y += (sh/2); // + BORDER_WIDTH;
  535 + if((n == x) && (n == 5))
  536 + wdt = 2*sw/3 - BORDER_WIDTH;
  537 +
  538 + } else {
  539 + if(x > 2) {
  540 + if((n == 1) || (n == 2))
  541 + ht = (sh/2) + growth - BORDER_WIDTH;
  542 + if(n >= 3)
  543 + ht = (sh/2) - growth - 2*BORDER_WIDTH;
  544 + }
  545 + else
  546 + ht = sh - BORDER_WIDTH;
  547 + if((n == 1) || (n == 3)) {
  548 + xpos = 0;
  549 + wdt = master_size - BORDER_WIDTH;
  550 + }
  551 + if((n == 2) || (n == 4)) {
  552 + xpos = master_size+BORDER_WIDTH;
  553 + wdt = (sw - master_size) - 2*BORDER_WIDTH;
  554 + }
  555 + if(n == 3)
  556 + y += (sh/2) + growth + BORDER_WIDTH;
  557 + if((n == x) && (n == 3))
  558 + wdt = sw - BORDER_WIDTH;
  559 + }
  560 + XMoveResizeWindow(dis,c->win,xpos,y,wdt,ht);
  561 + }
  562 + }
  563 + break;
  564 + default:
  565 + break;
  566 + }
  567 + }
  568 +}
  569 +
  570 +void update_current() {
  571 + client *c;
  572 +
  573 + for(c=head;c;c=c->next) {
  574 + if((head->next == NULL) || (mode == 1))
  575 + XSetWindowBorderWidth(dis,c->win,0);
  576 + else
  577 + XSetWindowBorderWidth(dis,c->win,BORDER_WIDTH);
  578 +
  579 + if(current == c) {
  580 + // "Enable" current window
  581 + XSetWindowBorder(dis,c->win,win_focus);
  582 + XSetInputFocus(dis,c->win,RevertToParent,CurrentTime);
  583 + XRaiseWindow(dis,c->win);
  584 + if(CLICK_TO_FOCUS == 0)
  585 + XUngrabButton(dis, AnyButton, AnyModifier, c->win);
  586 + }
  587 + else {
  588 + XSetWindowBorder(dis,c->win,win_unfocus);
  589 + if(CLICK_TO_FOCUS == 0)
  590 + XGrabButton(dis, AnyButton, AnyModifier, c->win, True, ButtonPressMask|ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None);
  591 + }
  592 + }
  593 + XSync(dis, False);
  594 +}
  595 +
  596 +void switch_vertical() {
  597 + if(mode != 0) {
  598 + mode = 0;
  599 + master_size = sw * MASTER_SIZE;
  600 + tile();
  601 + update_current();
  602 + }
  603 +}
  604 +
  605 +void switch_fullscreen() {
  606 + if(mode != 1) {
  607 + mode = 1;
  608 + tile();
  609 + update_current();
  610 + }
  611 +}
  612 +
  613 +void switch_horizontal() {
  614 + if(mode != 2) {
  615 + mode = 2;
  616 + master_size = sh * MASTER_SIZE;
  617 + tile();
  618 + update_current();
  619 + }
  620 +}
  621 +
  622 +void switch_grid() {
  623 + if(mode != 3) {
  624 + mode = 3;
  625 + master_size = sw * MASTER_SIZE;
  626 + tile();
  627 + update_current();
  628 + }
  629 +}
  630 +
  631 +void resize_master(const Arg arg) {
  632 + master_size += arg.i;
  633 + tile();
  634 +}
  635 +
  636 +void resize_stack(const Arg arg) {
  637 + growth += arg.i;
  638 + tile();
  639 +}
  640 +
  641 +/* ********************** Keyboard Management ********************** */
  642 +void grabkeys() {
  643 + int i;
  644 + KeyCode code;
  645 +
  646 + XUngrabKey(dis, AnyKey, AnyModifier, root);
  647 + // For each shortcuts
  648 + for(i=0;i<TABLENGTH(keys);++i) {
  649 + code = XKeysymToKeycode(dis,keys[i].keysym);
  650 + XGrabKey(dis, code, keys[i].mod, root, True, GrabModeAsync, GrabModeAsync);
  651 + XGrabKey(dis, code, keys[i].mod | LockMask, root, True, GrabModeAsync, GrabModeAsync);
  652 + XGrabKey(dis, code, keys[i].mod | numlockmask, root, True, GrabModeAsync, GrabModeAsync);
  653 + XGrabKey(dis, code, keys[i].mod | numlockmask | LockMask, root, True, GrabModeAsync, GrabModeAsync);
  654 + }
  655 +}
  656 +
  657 +void keypress(XEvent *e) {
  658 + static unsigned int len = sizeof keys / sizeof keys[0];
  659 + unsigned int i;
  660 + KeySym keysym;
  661 + XKeyEvent *ev = &e->xkey;
  662 +
  663 + keysym = XKeycodeToKeysym(dis, (KeyCode)ev->keycode, 0);
  664 + for(i = 0; i < len; i++) {
  665 + if(keysym == keys[i].keysym && CLEANMASK(keys[i].mod) == CLEANMASK(ev->state)) {
  666 + if(keys[i].function)
  667 + keys[i].function(keys[i].arg);
  668 + }
  669 + }
  670 +}
  671 +
  672 +void configurenotify(XEvent *e) {
  673 + // Do nothing for the moment
  674 +}
  675 +
  676 +/* ********************** Signal Management ************************** */
  677 +void configurerequest(XEvent *e) {
  678 + // Paste from DWM, thx again \o/
  679 + XConfigureRequestEvent *ev = &e->xconfigurerequest;
  680 + XWindowChanges wc;
  681 +
  682 + wc.x = ev->x;
  683 + wc.y = ev->y;
  684 + if(ev->width < sw-BORDER_WIDTH)
  685 + wc.width = ev->width;
  686 + else
  687 + wc.width = sw-BORDER_WIDTH;
  688 + if(ev->height < sh-BORDER_WIDTH)
  689 + wc.height = ev->height;
  690 + else
  691 + wc.height = sh-BORDER_WIDTH;
  692 + wc.border_width = ev->border_width;
  693 + wc.sibling = ev->above;
  694 + wc.stack_mode = ev->detail;
  695 + XConfigureWindow(dis, ev->window, ev->value_mask, &wc);
  696 + XSync(dis, False);
  697 +}
  698 +
  699 +void maprequest(XEvent *e) {
  700 + XMapRequestEvent *ev = &e->xmaprequest;
  701 +
  702 + // For fullscreen mplayer (and maybe some other program)
  703 + client *c;
  704 +
  705 + for(c=head;c;c=c->next)
  706 + if(ev->window == c->win) {
  707 + XMapWindow(dis,ev->window);
  708 + XMoveResizeWindow(dis,c->win,-BORDER_WIDTH,-BORDER_WIDTH,sw+BORDER_WIDTH,sh+BORDER_WIDTH);
  709 + return;
  710 + }
  711 +
  712 + Window trans = None;
  713 + if (XGetTransientForHint(dis, ev->window, &trans) && trans != None) {
  714 + add_window(ev->window);
  715 + XMapWindow(dis, ev->window);
  716 + XSetInputFocus(dis,ev->window,RevertToParent,CurrentTime);
  717 + XRaiseWindow(dis,ev->window);
  718 + return;
  719 + }
  720 +
  721 + unsigned long count, j, extra;
  722 + Atom realType;
  723 + int realFormat;
  724 + unsigned char *temp;
  725 + Atom *type;
  726 +
  727 + if(XGetWindowProperty(dis, ev->window, atoms[ATOM_NET_WM_WINDOW_TYPE], 0, 32, False, XA_ATOM, &realType, &realFormat, &count, &extra, &temp) == Success) {
  728 + if(count > 0) {
  729 + type = (unsigned long*)temp;
  730 + for(j=0; j<count; j++) {
  731 + if((type[j] == atoms[ATOM_NET_WM_WINDOW_TYPE_UTILITY]) ||
  732 + (type[j] == atoms[ATOM_NET_WM_WINDOW_TYPE_NOTIFICATION]) ||
  733 + (type[j] == atoms[ATOM_NET_WM_WINDOW_TYPE_SPLASH]) ||
  734 + (type[j] == atoms[ATOM_NET_WM_WINDOW_TYPE_DIALOG]) ||
  735 + (type[j] == atoms[ATOM_NET_WM_WINDOW_TYPE_DOCK])) {
  736 + add_window(ev->window);
  737 + XMapWindow(dis, ev->window);
  738 + XSetInputFocus(dis,ev->window,RevertToParent,CurrentTime);
  739 + XRaiseWindow(dis,ev->window);
  740 + return;
  741 + }
  742 + }
  743 + }
  744 + if(temp)
  745 + XFree(temp);
  746 + }
  747 +
  748 + XClassHint ch = {0};
  749 + static unsigned int len = sizeof convenience / sizeof convenience[0];
  750 + int i = 0;
  751 + int tmp = current_desktop;
  752 + if(XGetClassHint(dis, ev->window, &ch))
  753 + for(i=0;i<len;i++)
  754 + if(strcmp(ch.res_class, convenience[i].class) == 0) {
  755 + save_desktop(tmp);
  756 + select_desktop(convenience[i].preferredd-1);
  757 + add_window(ev->window);
  758 + if(tmp == convenience[i].preferredd-1) {
  759 + XMapWindow(dis, ev->window);
  760 + tile();
  761 + update_current();
  762 + } else {
  763 + select_desktop(tmp);
  764 + }
  765 + if(convenience[i].followwin != 0) {
  766 + Arg a = {.i = convenience[i].preferredd-1};
  767 + change_desktop(a);
  768 + }
  769 + if(ch.res_class)
  770 + XFree(ch.res_class);
  771 + if(ch.res_name)
  772 + XFree(ch.res_name);
  773 + return;
  774 + }
  775 +
  776 + add_window(ev->window);
  777 + XMapWindow(dis,ev->window);
  778 + tile();
  779 + update_current();
  780 +}
  781 +
  782 +void destroynotify(XEvent *e) {
  783 + int i = 0;
  784 + int j = 0;
  785 + int tmp = current_desktop;
  786 + client *c;
  787 + XDestroyWindowEvent *ev = &e->xdestroywindow;
  788 +
  789 + save_desktop(tmp);
  790 + for(j=0;j<TABLENGTH(desktops);++j) {
  791 + select_desktop(j);
  792 + for(c=head;c;c=c->next)
  793 + if(ev->window == c->win)
  794 + i++;
  795 +
  796 + if(i != 0) {
  797 + remove_window(ev->window);
  798 + select_desktop(tmp);
  799 + return;
  800 + }
  801 +
  802 + i = 0;
  803 + }
  804 + select_desktop(tmp);
  805 +}
  806 +
  807 +void enternotify(XEvent *e) {
  808 + client *c;
  809 + XCrossingEvent *ev = &e->xcrossing;
  810 +
  811 + if(FOLLOW_MOUSE == 0) {
  812 + if((ev->mode != NotifyNormal || ev->detail == NotifyInferior) && ev->window != root)
  813 + return;
  814 + for(c=head;c;c=c->next)
  815 + if(ev->window == c->win) {
  816 + current = c;
  817 + update_current();
  818 + return;
  819 + }
  820 + }
  821 +}
  822 +
  823 +void buttonpressed(XEvent *e) {
  824 + client *c;
  825 + XButtonPressedEvent *ev = &e->xbutton;
  826 +
  827 + // change focus with LMB
  828 + if(CLICK_TO_FOCUS == 0 && ev->window != current->win && ev->button == Button1)
  829 + for(c=head;c;c=c->next)
  830 + if(ev->window == c->win) {
  831 + current = c;
  832 + update_current();
  833 + return;
  834 + }
  835 +}
  836 +
  837 +void send_kill_signal(Window w) {
  838 + XEvent ke;
  839 + ke.type = ClientMessage;
  840 + ke.xclient.window = w;
  841 + ke.xclient.message_type = XInternAtom(dis, "WM_PROTOCOLS", True);
  842 + ke.xclient.format = 32;
  843 + ke.xclient.data.l[0] = XInternAtom(dis, "WM_DELETE_WINDOW", True);
  844 + ke.xclient.data.l[1] = CurrentTime;
  845 + XSendEvent(dis, w, False, NoEventMask, &ke);
  846 +}
  847 +
  848 +unsigned long getcolor(const char* color) {
  849 + XColor c;
  850 + Colormap map = DefaultColormap(dis,screen);
  851 +
  852 + if(!XAllocNamedColor(dis,map,color,&c,&c)) {
  853 + logger("\033[0;31mError parsing color!");
  854 + exit(1);
  855 + }
  856 + return c.pixel;
  857 +}
  858 +
  859 +void quit() {
  860 + Window root_return, parent;
  861 + Window *children;
  862 + int i;
  863 + unsigned int nchildren;
  864 + XEvent ev;
  865 +
  866 + /*
  867 + * if a client refuses to terminate itself,
  868 + * we kill every window remaining the brutal way.
  869 + * Since we're stuck in the while(nchildren > 0) { ... } loop
  870 + * we can't exit through the main method.
  871 + * This all happens if MOD+q is pushed a second time.
  872 + */
  873 + if(bool_quit == 1) {
  874 + XUngrabKey(dis, AnyKey, AnyModifier, root);
  875 + XDestroySubwindows(dis, root);
  876 + logger(" \033[0;33mThanks for using!");
  877 + XCloseDisplay(dis);
  878 + logger("\033[0;31mforced shutdown");
  879 + }
  880 +
  881 + bool_quit = 1;
  882 + XQueryTree(dis, root, &root_return, &parent, &children, &nchildren);
  883 + for(i = 0; i < nchildren; i++) {
  884 + send_kill_signal(children[i]);
  885 + }
  886 + //keep alive until all windows are killed
  887 + while(nchildren > 0) {
  888 + XQueryTree(dis, root, &root_return, &parent, &children, &nchildren);
  889 + XNextEvent(dis,&ev);
  890 + if(events[ev.type])
  891 + events[ev.type](&ev);
  892 + }
  893 +
  894 + XUngrabKey(dis,AnyKey,AnyModifier,root);
  895 + logger("\033[0;34mYou Quit : Thanks for using!");
  896 +}
  897 +
  898 +void logger(const char* e) {
  899 + fprintf(stdout,"\n\033[0;34m:: dminiwm : %s \033[0;m\n", e);
  900 +}
  901 +
  902 +void setup() {
  903 + // Install a signal
  904 + sigchld(0);
  905 +
  906 + // Screen and root window
  907 + screen = DefaultScreen(dis);
  908 + root = RootWindow(dis,screen);
  909 +
  910 + // Screen width and height
  911 + sw = XDisplayWidth(dis,screen) - BORDER_WIDTH;
  912 + sh = (XDisplayHeight(dis,screen) - PANEL_HEIGHT) - BORDER_WIDTH;
  913 +
  914 + // Colors
  915 + win_focus = getcolor(FOCUS);
  916 + win_unfocus = getcolor(UNFOCUS);
  917 +
  918 + // numlock workaround
  919 + int j, k;
  920 + XModifierKeymap *modmap;
  921 + numlockmask = 0;
  922 + modmap = XGetModifierMapping(dis);
  923 + for (k = 0; k < 8; k++) {
  924 + for (j = 0; j < modmap->max_keypermod; j++) {
  925 + if(modmap->modifiermap[k * modmap->max_keypermod + j] == XKeysymToKeycode(dis, XK_Num_Lock))
  926 + numlockmask = (1 << k);
  927 + }
  928 + }
  929 + XFreeModifiermap(modmap);
  930 +
  931 + // Shortcuts
  932 + grabkeys();
  933 +
  934 + // Default stack
  935 + mode = DEFAULT_MODE;
  936 + growth = 0;
  937 +
  938 + // For exiting
  939 + bool_quit = 0;
  940 +
  941 + // List of client
  942 + head = NULL;
  943 + current = NULL;
  944 +
  945 + // Master size
  946 + if(mode == 2)
  947 + master_size = sh*MASTER_SIZE;
  948 + else
  949 + master_size = sw*MASTER_SIZE;
  950 +
  951 + // Set up all desktop
  952 + int i;
  953 + for(i=0;i<TABLENGTH(desktops);++i) {
  954 + desktops[i].master_size = master_size;
  955 + desktops[i].mode = mode;
  956 + desktops[i].growth = growth;
  957 + desktops[i].head = head;
  958 + desktops[i].current = current;
  959 + }
  960 +
  961 + // Select first dekstop by default
  962 + const Arg arg = {.i = 0};
  963 + current_desktop = arg.i;
  964 + change_desktop(arg);
  965 + // Set up atoms for dialog/notification windows
  966 + int x;
  967 + for(x = 0; x < ATOM_COUNT; x++)
  968 + *atomList[x].atom = XInternAtom(dis, atomList[x].name, False);
  969 + // To catch maprequest and destroynotify (if other wm running)
  970 + XSelectInput(dis,root,SubstructureNotifyMask|SubstructureRedirectMask);
  971 + XSetErrorHandler(xerror);
  972 + logger("\033[0;32mWe're up and running!");
  973 +}
  974 +
  975 +void sigchld(int unused) {
  976 + // Again, thx to dwm ;)
  977 + if(signal(SIGCHLD, sigchld) == SIG_ERR) {
  978 + logger("\033[0;31mCan't install SIGCHLD handler");
  979 + exit(1);
  980 + }
  981 + while(0 < waitpid(-1, NULL, WNOHANG));
  982 +}
  983 +
  984 +void spawn(const Arg arg) {
  985 + if(fork() == 0) {
  986 + if(fork() == 0) {
  987 + if(dis)
  988 + close(ConnectionNumber(dis));
  989 +
  990 + setsid();
  991 + execvp((char*)arg.com[0],(char**)arg.com);
  992 + }
  993 + exit(0);
  994 + }
  995 +}
  996 +
  997 +/* 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. */
  998 +int xerror(Display *dis, XErrorEvent *ee) {
  999 + if(ee->error_code == BadWindow
  1000 + || (ee->request_code == X_SetInputFocus && ee->error_code == BadMatch)
  1001 + || (ee->request_code == X_PolyText8 && ee->error_code == BadDrawable)
  1002 + || (ee->request_code == X_PolyFillRectangle && ee->error_code == BadDrawable)
  1003 + || (ee->request_code == X_PolySegment && ee->error_code == BadDrawable)
  1004 + || (ee->request_code == X_ConfigureWindow && ee->error_code == BadMatch)
  1005 + || (ee->request_code == X_GrabKey && ee->error_code == BadAccess)
  1006 + || (ee->request_code == X_CopyArea && ee->error_code == BadDrawable))
  1007 + return 0;
  1008 + logger("\033[0;31mBad Window Error!");
  1009 + return xerrorxlib(dis, ee); /* may call exit */
  1010 +}
  1011 +
  1012 +void start() {
  1013 + XEvent ev;
  1014 +
  1015 + // Main loop, just dispatch events (thx to dwm ;)
  1016 + while(!bool_quit && !XNextEvent(dis,&ev)) {
  1017 + if(events[ev.type])
  1018 + events[ev.type](&ev);
  1019 + }
  1020 +}
  1021 +
  1022 +
  1023 +int main(int argc, char **argv) {
  1024 + // Open display
  1025 + if(!(dis = XOpenDisplay(NULL))) {
  1026 + logger("\033[0;31mCannot open display!");
  1027 + exit(1);
  1028 + }
  1029 +
  1030 + // Setup env
  1031 + setup();
  1032 +
  1033 + // Start wm
  1034 + start();
  1035 +
  1036 + // Close display
  1037 + XCloseDisplay(dis);
  1038 +
  1039 + return 0;
  1040 +}

0 comments on commit d03d329

Please sign in to comment.
Something went wrong with that request. Please try again.