about summary refs log tree commit diff stats
path: root/dwm.h
blob: a410f4e71cc03124c3b43c79bd8d2e41268251c1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/*
 * (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
 * See LICENSE file for license details.
 */

#include <X11/Xlib.h>

/********** CUSTOMIZE **********/

#define FONT				"-*-terminus-medium-*-*-*-13-*-*-*-*-*-iso10646-*"
#define BGCOLOR				"#0a2c2d"
#define FGCOLOR				"#ddeeee"
#define BORDERCOLOR			"#176164"
#define MODKEY				 Mod1Mask /* Mod4Mask */
/*
#define BGCOLOR				"#666699"
#define FGCOLOR				"#eeeeee"
#define BORDERCOLOR			"#9999CC"
*/
#define MASTERW				52 /* percent */
#define WM_PROTOCOL_DELWIN	1

/* tags */
enum { Tscratch, Tdev, Twww, Twork, TLast };

/********** CUSTOMIZE **********/

typedef union Arg Arg;
typedef struct Client Client;
typedef enum Corner Corner;
typedef struct DC DC;
typedef struct Fnt Fnt;

union Arg {
	const char **argv;
	int i;
};

/* atoms */
enum { NetSupported, NetWMName, NetLast };
enum { WMProtocols, WMDelete, WMLast };

/* cursor */
enum { CurNormal, CurResize, CurMove, CurLast };

enum Corner { TopLeft, TopRight, BotLeft, BotRight };

struct Fnt {
	int ascent;
	int descent;
	int height;
	XFontSet set;
	XFontStruct *xfont;
};

struct DC { /* draw context */
	int x, y, w, h;
	unsigned long bg;
	unsigned long fg;
	unsigned long border;
	Drawable drawable;
	Fnt font;
	GC gc;
};

struct Client {
	char name[256];
	char *tags[TLast];
	int proto;
	int x, y, w, h;
	int tx, ty, tw, th; /* title */
	int basew, baseh, incw, inch, maxw, maxh, minw, minh;
	int grav;
	unsigned int border;
	long flags; 
	Bool isfloat;
	Client *next;
	Client *revert;
	Window win;
	Window title;
};

extern char *tags[TLast], stext[1024];
extern int tsel, screen, sx, sy, sw, sh, bx, by, bw, bh, mw;
extern void (*handler[LASTEvent])(XEvent *);
extern void (*arrange)(Arg *);
extern Atom wmatom[WMLast], netatom[NetLast];
extern Bool running, issel;
extern Client *clients, *sel;
extern Cursor cursor[CurLast];
extern DC dc;
extern Display *dpy;
extern Window root, barwin;

/* client.c */
extern void ban(Client *c);
extern void focus(Client *c);
extern void focusnext(Arg *arg);
extern void focusprev(Arg *arg);
extern Client *getclient(Window w);
extern Client *getctitle(Window w);
extern void gravitate(Client *c, Bool invert);
extern void higher(Client *c);
extern void killclient(Arg *arg);
extern void lower(Client *c);
extern void manage(Window w, XWindowAttributes *wa);
extern void maximize(Arg *arg);
extern void pop(Client *c);
extern void resize(Client *c, Bool inc, Corner sticky);
extern void setsize(Client *c);
extern void settitle(Client *c);
extern void unmanage(Client *c);
extern void zoom(Arg *arg);

/* draw.c */
extern void drawall();
extern void drawstatus();
extern void drawtitle(Client *c);
extern unsigned long getcolor(const char *colstr);
extern void setfont(const char *fontstr);
extern unsigned int textw(char *text);

/* event.c */
extern void grabkeys();

/* main.c */
extern int getproto(Window w);
extern void quit(Arg *arg);
extern void sendevent(Window w, Atom a, long value);
extern int xerror(Display *dsply, XErrorEvent *ee);

/* tag.c */
extern void appendtag(Arg *arg);
extern void dofloat(Arg *arg);
extern void dotile(Arg *arg);
extern Client *getnext(Client *c, unsigned int t);
extern void heretag(Arg *arg);
extern void replacetag(Arg *arg);
extern void settags(Client *c);
extern void view(Arg *arg);

/* util.c */
extern void *emallocz(unsigned int size);
extern void eprint(const char *errstr, ...);
extern void spawn(Arg *arg);
w"> inc(hits) else: when countCacheMisses: inc(misses) result = newRope(s) if cmp < 0: result.left = t.left result.right = t t.left = nil else: # i > t.item: result.right = t.right result.left = t t.right = nil proc rope*(s: string): Rope {.rtl, extern: "nro$1Str".} = ## Converts a string to a rope. if s.len == 0: result = nil elif cacheEnabled: result = insertInCache(s, cache) cache = result else: result = newRope(s) proc rope*(i: BiggestInt): Rope {.rtl, extern: "nro$1BiggestInt".} = ## Converts an int to a rope. result = rope($i) proc rope*(f: BiggestFloat): Rope {.rtl, extern: "nro$1BiggestFloat".} = ## Converts a float to a rope. result = rope($f) proc enableCache*() {.rtl, extern: "nro$1".} = ## Enables the caching of leaves. This reduces the memory footprint at ## the cost of runtime efficiency. cacheEnabled = true proc disableCache*() {.rtl, extern: "nro$1".} = ## the cache is discarded and disabled. The GC will reuse its used memory. cache = nil cacheEnabled = false proc `&`*(a, b: Rope): Rope {.rtl, extern: "nroConcRopeRope".} = ## the concatenation operator for ropes. if a == nil: result = b elif b == nil: result = a else: result = newRope() result.length = a.length + b.length when false: # XXX rebalancing would be nice, but is too expensive. result.left = a.left var x = newRope() x.left = a.right x.right = b result.right = x else: result.left = a result.right = b proc `&`*(a: Rope, b: string): Rope {.rtl, extern: "nroConcRopeStr".} = ## the concatenation operator for ropes. result = a & rope(b) proc `&`*(a: string, b: Rope): Rope {.rtl, extern: "nroConcStrRope".} = ## the concatenation operator for ropes. result = rope(a) & b proc `&`*(a: openArray[Rope]): Rope {.rtl, extern: "nroConcOpenArray".} = ## the concatenation operator for an openarray of ropes. for i in countup(0, high(a)): result = result & a[i] proc add*(a: var Rope, b: Rope) {.rtl, extern: "nro$1Rope".} = ## adds `b` to the rope `a`. a = a & b proc add*(a: var Rope, b: string) {.rtl, extern: "nro$1Str".} = ## adds `b` to the rope `a`. a = a & b proc `[]`*(r: Rope, i: int): char {.rtl, extern: "nroCharAt".} = ## returns the character at position `i` in the rope `r`. This is quite ## expensive! Worst-case: O(n). If ``i >= r.len``, ``\0`` is returned. var x = r var j = i if x == nil: return while true: if not isConc(x): if x.data.len <% j: return x.data[j] return '\0' else: if x.left.len >% j: x = x.left else: x = x.right dec(j, x.len) iterator leaves*(r: Rope): string = ## iterates over any leaf string in the rope `r`. if r != nil: var stack = @[r] while stack.len > 0: var it = stack.pop while isConc(it): stack.add(it.right) it = it.left assert(it != nil) assert(it.data != nil) yield it.data iterator items*(r: Rope): char = ## iterates over any character in the rope `r`. for s in leaves(r): for c in items(s): yield c proc write*(f: File, r: Rope) {.rtl, extern: "nro$1".} = ## writes a rope to a file. for s in leaves(r): write(f, s) proc `$`*(r: Rope): string {.rtl, extern: "nroToString".}= ## converts a rope back to a string. result = newString(r.len) setLen(result, 0) for s in leaves(r): add(result, s) when false: # Format string caching seems reasonable: All leaves can be shared and format # string parsing has to be done only once. A compiled format string is stored # as a rope. A negative length is used for the index into the args array. proc compiledArg(idx: int): Rope = new(result) result.length = -idx proc compileFrmt(frmt: string): Rope = var i = 0 var length = len(frmt) result = nil var num = 0 while i < length: if frmt[i] == '$': inc(i) case frmt[i] of '$': add(result, "$") inc(i) of '#': inc(i) add(result, compiledArg(num+1)) inc(num) of '0'..'9': var j = 0 while true: j = j * 10 + ord(frmt[i]) - ord('0') inc(i) if frmt[i] notin {'0'..'9'}: break add(s, compiledArg(j)) of '{': inc(i) var j = 0 while frmt[i] in {'0'..'9'}: j = j * 10 + ord(frmt[i]) - ord('0') inc(i) if frmt[i] == '}': inc(i) else: raise newException(EInvalidValue, "invalid format string") add(s, compiledArg(j)) else: raise newException(EInvalidValue, "invalid format string") var start = i while i < length: if frmt[i] != '$': inc(i) else: break if i - 1 >= start: add(result, substr(frmt, start, i-1)) proc `%`*(frmt: string, args: openArray[Rope]): Rope {. rtl, extern: "nroFormat".} = ## `%` substitution operator for ropes. Does not support the ``$identifier`` ## nor ``${identifier}`` notations. var i = 0 var length = len(frmt) result = nil var num = 0 while i < length: if frmt[i] == '$': inc(i) case frmt[i] of '$': add(result, "$") inc(i) of '#': inc(i) add(result, args[num]) inc(num) of '0'..'9': var j = 0 while true: j = j * 10 + ord(frmt[i]) - ord('0') inc(i) if frmt[i] notin {'0'..'9'}: break add(result, args[j-1]) of '{': inc(i) var j = 0 while frmt[i] in {'0'..'9'}: j = j * 10 + ord(frmt[i]) - ord('0') inc(i) if frmt[i] == '}': inc(i) else: raise newException(ValueError, "invalid format string") add(result, args[j-1]) else: raise newException(ValueError, "invalid format string") var start = i while i < length: if frmt[i] != '$': inc(i) else: break if i - 1 >= start: add(result, substr(frmt, start, i - 1)) proc addf*(c: var Rope, frmt: string, args: openArray[Rope]) {. rtl, extern: "nro$1".} = ## shortcut for ``add(c, frmt % args)``. add(c, frmt % args) const bufSize = 1024 # 1 KB is reasonable proc equalsFile*(r: Rope, f: File): bool {.rtl, extern: "nro$1File".} = ## returns true if the contents of the file `f` equal `r`. var buf: array[bufSize, char] bpos = buf.len blen = buf.len for s in leaves(r): var spos = 0 let slen = s.len while spos < slen: if bpos == blen: # Read more data bpos = 0 blen = readBuffer(f, addr(buf[0]), buf.len) if blen == 0: # no more data in file result = false return let n = min(blen - bpos, slen - spos) # TODO There's gotta be a better way of comparing here... if not equalMem(addr(buf[bpos]), cast[pointer](cast[int](cstring(s))+spos), n): result = false return spos += n bpos += n result = readBuffer(f, addr(buf[0]), 1) == 0 # check that we've read all proc equalsFile*(r: Rope, filename: string): bool {.rtl, extern: "nro$1Str".} = ## returns true if the contents of the file `f` equal `r`. If `f` does not ## exist, false is returned. var f: File result = open(f, filename) if result: result = equalsFile(r, f) close(f) new(N) # init dummy node for splay algorithm {.pop.}