about summary refs log tree commit diff stats
path: root/dwm.h
blob: 1d672fdcd60b7493ea5ed59dfd9013413afb0441 (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
/*
 * (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		"DarkSlateGrey"
#define FGCOLOR		"LightSteelBlue"
#define BORDERCOLOR	"SlateGray"
#define WM_PROTOCOL_DELWIN 1

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

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

typedef struct DC DC;
typedef struct Client Client;
typedef struct Fnt Fnt;
typedef struct Key Key;

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

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

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

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

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

struct Key {
	unsigned long mod;
	KeySym keysym;
	void (*func)(void *aux);
	void *aux;
};

extern Display *dpy;
extern Window root;
extern Atom wm_atom[WMLast], net_atom[NetLast];
extern Cursor cursor[CurLast];
extern Bool running, issel;
extern void (*handler[LASTEvent]) (XEvent *);

extern int tsel, screen, sx, sy, sw, sh, th;
extern char stext[1024], *tags[TLast];

extern DC dc;
extern Client *clients, *stack;

/* client.c */
extern void manage(Window w, XWindowAttributes *wa);
extern void unmanage(Client *c);
extern Client *getclient(Window w);
extern void focus(Client *c);
extern void update_name(Client *c);
extern void draw_client(Client *c);
extern void resize(Client *c);
extern void update_size(Client *c);
extern Client *gettitle(Window w);
extern void craise(Client *c);
extern void lower(Client *c);
extern void ckill(void *aux);
extern void sel(void *aux);
extern void max(void *aux);
extern void floating(void *aux);
extern void tiling(void *aux);
extern void gravitate(Client *c, Bool invert);

/* draw.c */
extern void draw(Bool border, const char *text);
extern unsigned long initcolor(const char *colstr);
extern void initfont(const char *fontstr);
extern unsigned int textnw(char *text, unsigned int len);
extern unsigned int textw(char *text);
extern unsigned int texth(void);

/* event.c */
extern void discard_events(long even_mask);

/* dev.c */
extern void update_keys(void);
extern void keypress(XEvent *e);
extern void mresize(Client *c);
extern void mmove(Client *c);

/* main.c */
extern int error_handler(Display *dsply, XErrorEvent *e);
extern void send_message(Window w, Atom a, long value);
extern int win_proto(Window w);
extern void quit(void *aux);

/* util.c */
extern void error(const char *errstr, ...);
extern void *emallocz(unsigned int size);
extern void *emalloc(unsigned int size);
extern void *erealloc(void *ptr, unsigned int size);
extern char *estrdup(const char *str);
extern void spawn(char *argv[]);
extern void swap(void **p1, void **p2);
="w"> vector<string> metadata; string original; }; :(before "struct line") struct word { string original; string data; vector<string> metadata; }; //:: parse :(code) void parse(istream& fin, program& out) { segment* curr_segment = NULL; vector<line> l; while (has_data(fin)) { string line_data; line curr; getline(fin, line_data); curr.original = line_data; trace(99, "parse") << "line: " << line_data << end(); // End Line Parsing Special-cases(line_data -> l) istringstream lin(line_data); while (has_data(lin)) { string word_data; lin >> word_data; if (word_data.empty()) continue; if (word_data[0] == '#') break; // comment if (word_data == ".") continue; // comment token if (word_data == "==") { flush(curr_segment, l); string segment_name; lin >> segment_name; curr_segment = find(out, segment_name); if (curr_segment != NULL) { trace(3, "parse") << "appending to segment '" << segment_name << "'" << end(); } else { trace(3, "parse") << "new segment '" << segment_name << "'" << end(); uint32_t seg_start = 0; lin >> std::hex >> seg_start; sanity_check_program_segment(out, seg_start); out.segments.push_back(segment()); curr_segment = &out.segments.back(); curr_segment->name = segment_name; curr_segment->start = seg_start; if (trace_contains_errors()) continue; trace(3, "parse") << "starts at address 0x" << HEXWORD << curr_segment->start << end(); } break; // skip rest of line } if (word_data[0] == ':') { // todo: line metadata break; } curr.words.push_back(word()); parse_word(word_data, curr.words.back()); trace(99, "parse") << "word: " << to_string(curr.words.back()); } if (!curr.words.empty()) l.push_back(curr); } flush(curr_segment, l); trace(99, "parse") << "done" << end(); } segment* find(program& p, const string& segment_name) { for (int i = 0; i < SIZE(p.segments); ++i) { if (p.segments.at(i).name == segment_name) return &p.segments.at(i); } return NULL; } void flush(segment* s, vector<line>& lines) { if (lines.empty()) return; if (s == NULL) { raise << "input does not start with a '==' section header\n" << end(); return; } trace(3, "parse") << "flushing segment" << end(); s->lines.insert(s->lines.end(), lines.begin(), lines.end()); lines.clear(); } void parse_word(const string& data, word& out) { out.original = data; istringstream win(data); if (getline(win, out.data, '/')) { string m; while (getline(win, m, '/')) out.metadata.push_back(m); } } void sanity_check_program_segment(const program& p, uint32_t addr) { for (int i = 0; i < SIZE(p.segments); ++i) { if (p.segments.at(i).start == addr) raise << "can't have multiple segments starting at address 0x" << HEXWORD << addr << '\n' << end(); } } // helper for tests void parse(const string& text_bytes) { program p; istringstream in(text_bytes); parse(in, p); } void test_detect_duplicate_segments() { Hide_errors = true; parse( "== segment1 0xee\n" "ab\n" "== segment2 0xee\n" "cd\n" ); CHECK_TRACE_CONTENTS( "error: can't have multiple segments starting at address 0x000000ee\n" ); } //:: load void load(const program& p) { if (find(p, "code") == NULL) { raise << "no code to run\n" << end(); return; } // Ensure segments are disjoint. set<uint32_t> overlap; for (int i = 0; i < SIZE(p.segments); ++i) { const segment& seg = p.segments.at(i); uint32_t addr = seg.start; if (!already_allocated(addr)) Mem.push_back(vma(seg.start)); trace(99, "load") << "loading segment " << i << " from " << HEXWORD << addr << end(); for (int j = 0; j < SIZE(seg.lines); ++j) { const line& l = seg.lines.at(j); for (int k = 0; k < SIZE(l.words); ++k) { const word& w = l.words.at(k); uint8_t val = hex_byte(w.data); if (trace_contains_errors()) return; assert(overlap.find(addr) == overlap.end()); write_mem_u8(addr, val); overlap.insert(addr); trace(99, "load") << "0x" << HEXWORD << addr << " -> " << HEXBYTE << NUM(read_mem_u8(addr)) << end(); ++addr; } } if (seg.name == "code") { End_of_program = addr; } } } const segment* find(const program& p, const string& segment_name) { for (int i = 0; i < SIZE(p.segments); ++i) { if (p.segments.at(i).name == segment_name) return &p.segments.at(i); } return NULL; } uint8_t hex_byte(const string& s) { if (contains_uppercase(s)) { raise << "uppercase hex not allowed: " << s << '\n' << end(); return 0; } istringstream in(s); int result = 0; in >> std::hex >> result; if (!in || !in.eof()) { raise << "token '" << s << "' is not a hex byte\n" << end(); return '\0'; } if (result > 0xff || result < -0x8f) { raise << "token '" << s << "' is not a hex byte\n" << end(); return '\0'; } return static_cast<uint8_t>(result); } void test_number_too_large() { Hide_errors = true; parse_and_load( "== code 0x1\n" "01 cab\n" ); CHECK_TRACE_CONTENTS( "error: token 'cab' is not a hex byte\n" ); } void test_invalid_hex() { Hide_errors = true; parse_and_load( "== code 0x1\n" "01 cx\n" ); CHECK_TRACE_CONTENTS( "error: token 'cx' is not a hex byte\n" ); } void test_negative_number() { parse_and_load( "== code 0x1\n" "01 -02\n" ); CHECK_TRACE_COUNT("error", 0); } void test_negative_number_too_small() { Hide_errors = true; parse_and_load( "== code 0x1\n" "01 -12345\n" ); CHECK_TRACE_CONTENTS( "error: token '-12345' is not a hex byte\n" ); } void test_hex_prefix() { parse_and_load( "== code 0x1\n" "0x01 -0x02\n" ); CHECK_TRACE_COUNT("error", 0); } void test_repeated_segment_merges_data() { parse_and_load( "== code 0x1\n" "11 22\n" "== code\n" // again "33 44\n" ); CHECK_TRACE_CONTENTS( "parse: new segment 'code'\n" "parse: appending to segment 'code'\n" // first segment "load: 0x00000001 -> 11\n" "load: 0x00000002 -> 22\n" // second segment "load: 0x00000003 -> 33\n" "load: 0x00000004 -> 44\n" ); } void test_error_on_missing_segment_header() { Hide_errors = true; parse_and_load( "01 02\n" ); CHECK_TRACE_CONTENTS( "error: input does not start with a '==' section header\n" ); } void test_error_on_uppercase_hex() { Hide_errors = true; parse_and_load( "== code\n" "01 Ab\n" ); CHECK_TRACE_CONTENTS( "error: uppercase hex not allowed: Ab\n" ); } //: helper for tests void parse_and_load(const string& text_bytes) { program p; istringstream in(text_bytes); parse(in, p); if (trace_contains_errors()) return; // if any stage raises errors, stop immediately load(p); } //:: run :(before "End Initialize Op Names") put_new(Name, "b8", "copy imm32 to EAX (mov)"); //: our first opcode :(before "End Single-Byte Opcodes") case 0xb8: { // copy imm32 to EAX const int32_t src = next32(); trace(Callstack_depth+1, "run") << "copy imm32 0x" << HEXWORD << src << " to EAX" << end(); Reg[EAX].i = src; break; } :(code) void test_copy_imm32_to_EAX_again() { run( "== code 0x1\n" // code segment // op ModR/M SIB displacement immediate " b8 0a 0b 0c 0d \n" // copy 0x0d0c0b0a to EAX ); CHECK_TRACE_CONTENTS( "run: copy imm32 0x0d0c0b0a to EAX\n" ); } // read a 32-bit int in little-endian order from the instruction stream int32_t next32() { int32_t result = read_mem_i32(EIP); EIP+=4; return result; } //:: helpers string to_string(const word& w) { ostringstream out; out << w.data; for (int i = 0; i < SIZE(w.metadata); ++i) out << " /" << w.metadata.at(i); return out.str(); } bool contains_uppercase(const string& s) { for (int i = 0; i < SIZE(s); ++i) if (isupper(s.at(i))) return true; return false; }