1 module kernel;
2
3 import std.c.locale;
4 import std.c..string;
5 import std.c.stdlib;
6
7 import std.stdio;
8 import std..string;
9 import std.algorithm;
10 import std.conv;
11 import std.process;
12 import std.traits;
13 import helper.process;
14
15 import core.sys.posix.signal;
16 import core.sys.posix.sys.wait;
17 import core.sys.posix.unistd;
18 import core.memory;
19
20 import x11.X;
21 import x11.Xlib;
22 import x11.keysymdef;
23 import x11.Xutil;
24 import x11.Xatom;
25
26 import cboxapp;
27 import types;
28 import utils;
29 import legacy;
30 import old;
31 import config;
32 import events.handler;
33 import events.keyboard;
34 import events.mouse;
35 import window;
36 import helper.x11;
37 import gui.cursor;
38 import gui.font;
39 import gui.bar;
40 import theme.layout;
41 import theme.manager;
42 import monitor;
43
44 static Drw *drw;
45 static Fnt *fnt;
46 static Key[] keys;
47
48 /* button definitions */
49 /* click can be ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */
50 static Button[] buttons;
51 static void function(XEvent*)[LASTEvent] handler;
52
53
54 EventHandler eventManager;
55 KeyboardEvents keyboardEventHandler;
56 MouseEvents mouseEventHandler;
57 WindowManager windowManager;
58
59 static Atom[WMLast] wmatom;
60 static Atom[NetLast] netatom;
61
62 void quit(const Arg *arg)
63 {
64 AppDisplay.instance().running = false;
65 }
66
67 class Kernel
68 {
69 this()
70 {
71 keyboardEventHandler = new KeyboardEvents();
72 keyboardEventHandler.addEvent(MODKEY|ShiftMask, XK_q, &quit);
73 keyboardEventHandler.addEvent(MODKEY, XK_p, &spawn, dmenucmd);
74
75 mouseEventHandler = new MouseEvents();
76 eventManager = new EventHandler(keyboardEventHandler, mouseEventHandler);
77 windowManager = new WindowManager();
78
79 wmatom = windowManager.getAllAtoms("WMLast");
80 netatom = windowManager.getAllAtoms("NetLast");
81 }
82
83 int boot()
84 {
85 keys = keyboardEventHandler.getKeys();
86 buttons = mouseEventHandler.getButtons();
87
88 this.checkotherwm();
89 this.setup();
90 this.scan();
91 this.run();
92 this.close();
93
94 return 0;
95 }
96
97 void checkotherwm()
98 {
99 xerrorxlib = XSetErrorHandler(&xerrorstart);
100 /* this causes an error if some other window manager is running */
101 XSelectInput(AppDisplay.instance().dpy, DefaultRootWindow(AppDisplay.instance().dpy), SubstructureRedirectMask);
102 XSync(AppDisplay.instance().dpy, false);
103 XSetErrorHandler(&xerror);
104 XSync(AppDisplay.instance().dpy, false);
105 }
106
107 void setup()
108 {
109 XSetWindowAttributes wa;
110
111 /* clean up any zombies immediately */
112 sigchld(0);
113
114 /* init screen */
115 screen = DefaultScreen(AppDisplay.instance().dpy);
116 rootWin = RootWindow(AppDisplay.instance().dpy, screen);
117
118 fnt = new Fnt(AppDisplay.instance().dpy, font);
119 sw = DisplayWidth(AppDisplay.instance().dpy, screen);
120 sh = DisplayHeight(AppDisplay.instance().dpy, screen);
121 bh = fnt.h + 2;
122
123 drw = new Drw(AppDisplay.instance().dpy, screen, rootWin, sw, sh);
124 drw.setfont(fnt);
125 updategeom();
126
127 /* init cursors */
128 cursor[CurNormal] = new Cur(drw.dpy, CursorFont.XC_left_ptr);
129 cursor[CurResize] = new Cur(drw.dpy, CursorFont.XC_sizing);
130 cursor[CurMove] = new Cur(drw.dpy, CursorFont.XC_fleur);
131
132
133 /* init bars */
134 updatebars();
135 updatestatus();
136
137 /* EWMH support per view */
138 XChangeProperty(
139 AppDisplay.instance().dpy,
140 rootWin,
141 windowManager.getAtom("NetLast",NetSupported),
142 XA_ATOM, 32,
143 PropModeReplace,
144 cast(ubyte*) windowManager.getAllAtoms("NetLast"),
145 NetLast
146 );
147
148 XDeleteProperty(
149 AppDisplay.instance().dpy,
150 rootWin,
151 windowManager.getAtom("NetLast", NetClientList)
152 );
153
154 /* select for events */
155 wa.cursor = cursor[CurNormal].cursor;
156 wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask|ButtonPressMask|PointerMotionMask
157 |EnterWindowMask|LeaveWindowMask|StructureNotifyMask|PropertyChangeMask;
158
159 XChangeWindowAttributes(AppDisplay.instance().dpy, rootWin, CWEventMask|CWCursor, &wa);
160 XSelectInput(AppDisplay.instance().dpy, rootWin, wa.event_mask);
161 keyboardEventHandler.grabkeys();
162
163 focus(null);
164 }
165
166 void scan()
167 {
168 uint i, num;
169 Window d1, d2;
170 Window* wins = null;
171 XWindowAttributes wa;
172
173 if(XQueryTree(AppDisplay.instance().dpy, rootWin, &d1, &d2, &wins, &num)) {
174 for(i = 0; i < num; i++) {
175 if(!XGetWindowAttributes(AppDisplay.instance().dpy, wins[i], &wa)
176 || wa.override_redirect || XGetTransientForHint(AppDisplay.instance().dpy, wins[i], &d1))
177 continue;
178 if(wa.map_state == IsViewable || this.getstate(wins[i]) == IconicState)
179 windowManager.manage(wins[i], &wa);
180 }
181 for(i = 0; i < num; i++) { /* now the transients */
182 if(!XGetWindowAttributes(AppDisplay.instance().dpy, wins[i], &wa))
183 continue;
184 if(XGetTransientForHint(AppDisplay.instance().dpy, wins[i], &d1)
185 && (wa.map_state == IsViewable || this.getstate(wins[i]) == IconicState))
186 windowManager.manage(wins[i], &wa);
187 }
188 if(wins)
189 XFree(wins);
190 }
191 }
192
193 void run()
194 {
195 extern(C) __gshared XEvent ev;
196
197 /* main event loop */
198 XSync(AppDisplay.instance().dpy, false);
199 while(AppDisplay.instance().running && !XNextEvent(AppDisplay.instance().dpy, &ev)) {
200 eventManager.listen(&ev);
201 }
202 }
203
204 void cleanup()
205 {
206 auto a = Arg(-1);
207 Layout foo = { "", null };
208
209 view(&a);
210 selmon.lt[selmon.sellt] = &foo;
211 foreach(m; mons.range) {
212 while(m.stack) {
213 unmanage(m.stack, false);
214 }
215 }
216 XUngrabKey(AppDisplay.instance().dpy, AnyKey, AnyModifier, rootWin);
217 while(mons) {
218 cleanupmon(mons);
219 }
220
221 Cur.free(cursor[CurNormal]);
222 Cur.free(cursor[CurResize]);
223 Cur.free(cursor[CurMove]);
224 Fnt.free(AppDisplay.instance().dpy, fnt);
225 Clr.free(ThemeManager.instance().getScheme(SchemeNorm).border);
226 Clr.free(ThemeManager.instance().getScheme(SchemeNorm).bg);
227 Clr.free(ThemeManager.instance().getScheme(SchemeNorm).fg);
228 Clr.free(ThemeManager.instance().getScheme(SchemeSel).border);
229 Clr.free(ThemeManager.instance().getScheme(SchemeSel).bg);
230 Clr.free(ThemeManager.instance().getScheme(SchemeSel).fg);
231
232
233 Drw.free(drw);
234 XSync(AppDisplay.instance().dpy, false);
235 XSetInputFocus(AppDisplay.instance().dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
236 XDeleteProperty(AppDisplay.instance().dpy, rootWin, netatom[NetActiveWindow]);
237 }
238
239 void close()
240 {
241 this.cleanup();
242 XCloseDisplay(AppDisplay.instance().dpy);
243 }
244
245 /**
246 * Get window State
247 **/
248 long getstate(Window w)
249 {
250 int format;
251 long result = -1;
252 ubyte *p = null;
253 ulong n, extra;
254 Atom realVal;
255
256 if(XGetWindowProperty(AppDisplay.instance().dpy, w, wmatom[WMState], 0L, 2L, false, wmatom[WMState],
257 &realVal, &format, &n, &extra, cast(ubyte **)&p) != XErrorCode.Success) {
258 return -1;
259 }
260
261 if(n != 0) {
262 result = *p;
263 }
264
265 XFree(p);
266 return result;
267 }
268
269 }