docs: update

This commit is contained in:
Dylan Araps 2019-10-11 14:48:34 +03:00
commit 95b696bdc2
5 changed files with 831 additions and 0 deletions

32
LICENCE_DWM Normal file
View File

@ -0,0 +1,32 @@
MIT/X Consortium License
© 2006-2011 Anselm R Garbe <anselm@garbe.us>
© 2007-2011 Peter Hartlich <sgkkr at hartlich dot com>
© 2010-2011 Connor Lane Smith <cls@lubutu.com>
© 2006-2009 Jukka Salmi <jukka at salmi dot ch>
© 2007-2009 Premysl Hruby <dfenze at gmail dot com>
© 2007-2009 Szabolcs Nagy <nszabolcs at gmail dot com>
© 2007-2009 Christof Musik <christof at sendfax dot de>
© 2009 Mate Nagy <mnagy at port70 dot net>
© 2007-2008 Enno Gottox Boland <gottox at s01 dot de>
© 2008 Martin Hurton <martin dot hurton at gmail dot com>
© 2008 Neale Pickett <neale dot woozle dot org>
© 2006-2007 Sander van Dijk <a dot h dot vandijk at gmail dot com>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

20
Makefile Executable file
View File

@ -0,0 +1,20 @@
CFLAGS+= -Wall
LDADD+= -lX11
LDFLAGS=
EXEC=catwm
PREFIX?= /usr
BINDIR?= $(PREFIX)/bin
CC=gcc
all: $(EXEC)
catwm: catwm.o
$(CC) $(LDFLAGS) -Os -o $@ $+ $(LDADD)
install: all
install -Dm 755 catwm $(DESTDIR)$(BINDIR)/catwm
clean:
rm -f catwm *.o

11
README.md Executable file
View File

@ -0,0 +1,11 @@
# catwm
```
/\___/\
( o o ) Made by cat...
( =^= )
( ) ... for cat!
( )
( ))))))________________ Cute And Tiny Window Manager
```

674
catwm.c Executable file
View File

@ -0,0 +1,674 @@
/*
* /\___/\
* ( o o ) Made by cat...
* ( =^= )
* ( ) ... for cat!
* ( )
* ( ))))))________________ Cute And Tiny Window Manager
* ______________________________________________________________________________
*
* Copyright (c) 2010, Rinaldini Julien, julien.rinaldini@heig-vd.ch
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
#include <X11/Xlib.h>
#include <X11/keysym.h>
#include <X11/XF86keysym.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/wait.h>
#define TABLENGTH(X) (sizeof(X)/sizeof(*X))
typedef union {
const char** com;
const int i;
} Arg;
// Structs
struct key {
unsigned int mod;
KeySym keysym;
void (*function)(const Arg arg);
const Arg arg;
};
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;
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 die(const char* e);
static unsigned long getcolor(const char* color);
static void grabkeys();
static void increase();
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 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();
static void swap_master();
static void switch_mode();
static void tile();
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 master_size;
static int mode;
static int sh;
static int sw;
static int screen;
static unsigned int win_focus;
static unsigned int win_unfocus;
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[10];
void add_window(Window w) {
client *c,*t;
if(!(c = (client *)calloc(1,sizeof(client))))
die("Error calloc!");
if(head == NULL) {
c->next = NULL;
c->prev = NULL;
c->win = w;
head = c;
}
else {
for(t=head;t->next;t=t->next);
c->next = NULL;
c->prev = t;
c->win = w;
t->next = c;
}
current = c;
}
void change_desktop(const Arg arg) {
client *c;
if(arg.i == current_desktop)
return;
// Unmap all window
if(head != NULL)
for(c=head;c;c=c->next)
XUnmapWindow(dis,c->win);
// Save current "properties"
save_desktop(current_desktop);
// 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 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);
remove_window(current->win);
tile();
update_current();
}
void configurenotify(XEvent *e) {
// Do nothing for the moment
}
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);
}
void decrease() {
if(master_size > 50) {
master_size -= 10;
tile();
}
}
void destroynotify(XEvent *e) {
int i=0;
client *c;
XDestroyWindowEvent *ev = &e->xdestroywindow;
// Uber (and ugly) hack ;)
for(c=head;c;c=c->next)
if(ev->window == c->win)
i++;
// End of the hack
if(i == 0)
return;
remove_window(ev->window);
tile();
update_current();
}
void die(const char* e) {
fprintf(stdout,"catwm: %s\n",e);
exit(1);
}
unsigned long getcolor(const char* color) {
XColor c;
Colormap map = DefaultColormap(dis,screen);
if(!XAllocNamedColor(dis,map,color,&c,&c))
die("Error parsing color!");
return c.pixel;
}
void grabkeys() {
int i;
KeyCode code;
// For each shortcuts
for(i=0;i<TABLENGTH(keys);++i) {
if((code = XKeysymToKeycode(dis,keys[i].keysym))) {
XGrabKey(dis,code,keys[i].mod,root,True,GrabModeAsync,GrabModeAsync);
}
}
}
void increase() {
if(master_size < sw-50) {
master_size += 10;
tile();
}
}
void keypress(XEvent *e) {
int i;
XKeyEvent ke = e->xkey;
KeySym keysym = XKeycodeToKeysym(dis,ke.keycode,0);
for(i=0;i<TABLENGTH(keys);++i) {
if(keys[i].keysym == keysym && keys[i].mod == ke.state) {
keys[i].function(keys[i].arg);
}
}
}
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);
}
}
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);
return;
}
add_window(ev->window);
XMapWindow(dis,ev->window);
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();
tile();
update_current();
}
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();
tile();
update_current();
}
void next_desktop() {
int tmp = current_desktop;
if(tmp== 9)
tmp = 0;
else
tmp++;
Arg a = {.i = tmp};
change_desktop(a);
}
void next_win() {
client *c;
if(current != NULL && head != NULL) {
if(current->next == NULL)
c = head;
else
c = current->next;
current = c;
update_current();
}
}
void prev_desktop() {
int tmp = current_desktop;
if(tmp == 0)
tmp = 9;
else
tmp--;
Arg a = {.i = tmp};
change_desktop(a);
}
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;
update_current();
}
}
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);
fprintf(stdout, "catwm: Thanks for using!\n");
XCloseDisplay(dis);
die("forced 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);
fprintf(stdout,"catwm: Thanks for using!\n");
}
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;
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);
return;
}
}
}
void save_desktop(int i) {
desktops[i].master_size = master_size;
desktops[i].mode = mode;
desktops[i].head = head;
desktops[i].current = current;
}
void select_desktop(int i) {
head = desktops[i].head;
current = desktops[i].current;
master_size = desktops[i].master_size;
mode = desktops[i].mode;
current_desktop = i;
}
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);
}
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);
sh = XDisplayHeight(dis,screen);
// Colors
win_focus = getcolor(FOCUS);
win_unfocus = getcolor(UNFOCUS);
// Shortcuts
grabkeys();
// Vertical stack
mode = 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;i<TABLENGTH(desktops);++i) {
desktops[i].master_size = master_size;
desktops[i].mode = mode;
desktops[i].head = head;
desktops[i].current = current;
}
// Select first dekstop by default
const Arg arg = {.i = 1};
current_desktop = arg.i;
change_desktop(arg);
// To catch maprequest and destroynotify (if other wm running)
XSelectInput(dis,root,SubstructureNotifyMask|SubstructureRedirectMask);
}
void sigchld(int unused) {
// Again, thx to dwm ;)
if(signal(SIGCHLD, sigchld) == SIG_ERR)
die("Can't install SIGCHLD handler");
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);
}
}
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);
}
}
void swap_master() {
Window tmp;
if(head != NULL && current != NULL && current != head && mode == 0) {
tmp = head->win;
head->win = current->win;
current->win = tmp;
current = head;
tile();
update_current();
}
}
void switch_mode() {
mode = (mode == 0) ? 1:0;
tile();
update_current();
}
void tile() {
client *c;
int n = 0;
int y = 0;
// If only one window
if(head != NULL && head->next == NULL) {
XMoveResizeWindow(dis,head->win,0,0,sw-2,sh-2);
}
else if(head != NULL) {
switch(mode) {
case 0:
// Master window
XMoveResizeWindow(dis,head->win,0,0,master_size-2,sh-2);
// Stack
for(c=head->next;c;c=c->next) ++n;
for(c=head->next;c;c=c->next) {
XMoveResizeWindow(dis,c->win,master_size,y,sw-master_size-2,(sh/n)-2);
y += sh/n;
}
break;
case 1:
for(c=head;c;c=c->next) {
XMoveResizeWindow(dis,c->win,0,0,sw,sh);
}
break;
default:
break;
}
}
}
void update_current() {
client *c;
for(c=head;c;c=c->next)
if(current == c) {
// "Enable" current window
XSetWindowBorderWidth(dis,c->win,1);
XSetWindowBorder(dis,c->win,win_focus);
XSetInputFocus(dis,c->win,RevertToParent,CurrentTime);
XRaiseWindow(dis,c->win);
}
else
XSetWindowBorder(dis,c->win,win_unfocus);
}
int main(int argc, char **argv) {
// Open display
if(!(dis = XOpenDisplay(NULL)))
die("Cannot open display!");
// Setup env
setup();
// Start wm
start();
// Close display
XCloseDisplay(dis);
return 0;
}

94
config.h Executable file
View File

@ -0,0 +1,94 @@
/*
* /\___/\
* ( o o ) Made by cat...
* ( =^= )
* ( ) ... for cat!
* ( )
* ( ))))))________________ Cute And Tiny Window Manager
* ______________________________________________________________________________
*
* Copyright (c) 2010, Rinaldini Julien, julien.rinaldini@heig-vd.ch
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
#ifndef CONFIG_H
#define CONFIG_H
// Mod (Mod1 == alt) and master size
#define MOD Mod1Mask
#define MASTER_SIZE 0.6
// Colors
#define FOCUS "rgb:bc/57/66"
#define UNFOCUS "rgb:88/88/88"
const char* dmenucmd[] = {"dmenu_run",NULL};
const char* urxvtcmd[] = {"urxvt",NULL};
const char* lockcmd[] = {"slock",NULL};
const char* next[] = {"ncmpcpp","next",NULL};
const char* prev[] = {"ncmpcpp","prev",NULL};
const char* toggle[] = {"ncmpcpp","toggle",NULL };
const char* voldown[] = {"amixer","set","PCM","5\%-",NULL};
const char* volup[] = {"amixer","set","PCM","5\%+",NULL};
// Avoid multiple paste
#define DESKTOPCHANGE(K,N) \
{ MOD, K, change_desktop, {.i = N}}, \
{ MOD|ShiftMask, K, client_to_desktop, {.i = N}},
// Shortcuts
static struct key keys[] = {
// MOD KEY FUNCTION ARGS
{ MOD, XK_h, decrease, {NULL}},
{ MOD, XK_l, increase, {NULL}},
{ MOD, XK_x, kill_client, {NULL}},
{ MOD, XK_j, next_win, {NULL}},
{ MOD, XK_Tab, next_win, {NULL}},
{ MOD, XK_k, prev_win, {NULL}},
{ MOD|ShiftMask, XK_j, move_up, {NULL}},
{ MOD|ShiftMask, XK_k, move_down, {NULL}},
{ MOD, XK_Return, swap_master, {NULL}},
{ MOD, XK_space, switch_mode, {NULL}},
{ MOD, XK_c, spawn, {.com = lockcmd}},
{ 0, XF86XK_AudioNext, spawn, {.com = next}},
{ 0, XF86XK_AudioPrev, spawn, {.com = prev}},
{ 0, XF86XK_AudioPlay, spawn, {.com = toggle}},
{ 0, XF86XK_AudioLowerVolume, spawn, {.com = voldown}},
{ 0, XF86XK_AudioRaiseVolume, spawn, {.com = volup}},
{ MOD, XK_p, spawn, {.com = dmenucmd}},
{ MOD|ShiftMask, XK_Return, spawn, {.com = urxvtcmd}},
{ MOD, XK_Right, next_desktop, {NULL}},
{ MOD, XK_Left, prev_desktop, {NULL}},
DESKTOPCHANGE( XK_0, 0)
DESKTOPCHANGE( XK_1, 1)
DESKTOPCHANGE( XK_2, 2)
DESKTOPCHANGE( XK_3, 3)
DESKTOPCHANGE( XK_4, 4)
DESKTOPCHANGE( XK_5, 5)
DESKTOPCHANGE( XK_6, 6)
DESKTOPCHANGE( XK_7, 7)
DESKTOPCHANGE( XK_8, 8)
DESKTOPCHANGE( XK_9, 9)
{ MOD, XK_q, quit, {NULL}}
};
#endif