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 
14 import core.sys.posix.signal;
15 import core.sys.posix.sys.wait;
16 import core.sys.posix.unistd;
17 import core.memory;
18 
19 import deimos.X11.X;
20 import deimos.X11.Xlib;
21 import deimos.X11.keysymdef;
22 import deimos.X11.Xutil;
23 import deimos.X11.Xatom;
24 
25 import cboxapp;
26 import types;
27 import utils;
28 import legacy;
29 import old;
30 import config;
31 import events.handler;
32 import events.keyboard;
33 import events.mouse;
34 import window;
35 import helper.x11;
36 import gui.cursor;
37 import gui.font;
38 import gui.bar;
39 import theme.layout;
40 import theme.manager;
41 import monitor;
42 
43 static Drw *drw;
44 static Fnt *fnt;
45 static Key[] keys;
46 
47 /* button definitions */
48 /* click can be ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */
49 static Button[] buttons;
50 static void function(XEvent*)[LASTEvent] handler;
51 static immutable string VERSION = "0.1 Cobox";
52 
53 
54 void arrange(Monitor *m) 
55 {
56     if(m) {
57         windowManager.showhide(m.stack);
58     } else foreach(m; mons.range) {
59         windowManager.showhide(m.stack);
60     }
61     if(m) {
62         arrangemon(m);
63         restack(m);
64     } else foreach(m; mons.range) {
65         arrangemon(m);
66     }
67 }
68 
69 void arrangemon(Monitor *m) {
70     
71     m.ltsymbol = m.lt[m.sellt].symbol;
72 
73     if(m.lt[m.sellt].arrange)
74         m.lt[m.sellt].arrange(m);
75 }
76 
77 void attach(Client *c) {
78     
79     c.next = c.mon.clients;
80     c.mon.clients = c;
81 }
82 
83 void attachstack(Client *c) {
84     
85     c.snext = c.mon.stack;
86     c.mon.stack = c;
87 }
88 
89 long getstate(Window w) 
90 {
91     int format;
92     long result = -1;
93     ubyte *p = null;
94     ulong n, extra;
95     Atom realVal;
96 
97     if(XGetWindowProperty(AppDisplay.instance().dpy, w, wmatom[WMState], 0L, 2L, false, wmatom[WMState],
98        &realVal, &format, &n, &extra, cast(ubyte **)&p) != XErrorCode.Success) {
99        	writeln("here");
100         return -1;
101     }
102     if(n != 0) {
103         result = *p;
104     }
105     XFree(p);
106     return result;
107 }
108 
109 
110 
111     void applyrules(Client *c) 
112     {
113         XClassHint ch = { null, null };
114         /* rule matching */
115         c.isfloating = false;
116         c.tags = 0;
117         XGetClassHint(AppDisplay.instance().dpy, c.win, &ch);
118         immutable auto klass    = ch.res_class ? ch.res_class.to!string : broken;
119         immutable auto instance = ch.res_name  ? ch.res_name.to!string : broken;
120         foreach(immutable r; rules) {
121             if( (r.title.length==0 || r.title.indexOf(c.name) >= 0) &&
122                     (r.klass.length==0 || r.klass.indexOf(klass) >= 0) &&
123                     (r.instance.length==0 || r.instance.indexOf(instance) >= 0)) {
124                 c.isfloating = r.isfloating;
125                 c.tags |= r.tags;
126 
127                 auto m = mons.range.find!(mon => mon.num == r.monitor).front;
128                 if(m) {
129                     c.mon = m;
130                 }
131             }
132         }
133         if(ch.res_class)
134             XFree(ch.res_class);
135         if(ch.res_name)
136             XFree(ch.res_name);
137         c.tags = c.tags & TAGMASK ? c.tags & TAGMASK : c.mon.tagset[c.mon.seltags];
138     }
139 
140     
141 
142 void quit(const Arg *arg) 
143 {
144     AppDisplay.instance().running = false;
145 }
146 
147 EventHandler eventManager;
148 KeyboardEvents keyboardEventHandler;
149 MouseEvents mouseEventHandler;
150 WindowManager windowManager;
151 
152 static Atom[WMLast] wmatom;
153 static Atom[NetLast] netatom;
154 
155 class Kernel
156 {
157     this()
158     {
159         keyboardEventHandler = new KeyboardEvents();
160 
161         mouseEventHandler = new MouseEvents();
162         eventManager = new EventHandler(keyboardEventHandler, mouseEventHandler);
163         windowManager = new WindowManager();
164 
165         wmatom = windowManager.getAllAtoms("WMLast");
166         netatom = windowManager.getAllAtoms("NetLast");
167     }
168 
169     void setup() 
170     {
171         XSetWindowAttributes wa;
172 
173         /* clean up any zombies immediately */
174         sigchld(0);
175 
176         /* init screen */
177         screen = DefaultScreen(AppDisplay.instance().dpy);
178         rootWin = RootWindow(AppDisplay.instance().dpy, screen);
179 
180         fnt = new Fnt(AppDisplay.instance().dpy, font);
181         sw = DisplayWidth(AppDisplay.instance().dpy, screen);
182         sh = DisplayHeight(AppDisplay.instance().dpy, screen);
183         bh = fnt.h + 2;
184 
185         drw = new Drw(AppDisplay.instance().dpy, screen, rootWin, sw, sh);
186         drw.setfont(fnt);
187         updategeom();
188 
189         /* init cursors */
190         cursor[CurNormal] = new Cur(drw.dpy, CursorFont.XC_left_ptr);
191         cursor[CurResize] = new Cur(drw.dpy, CursorFont.XC_sizing);
192         cursor[CurMove] = new Cur(drw.dpy, CursorFont.XC_fleur);
193 
194 
195         /* init bars */
196         updatebars();
197         updatestatus();
198 
199         /* EWMH support per view */
200         XChangeProperty(
201             AppDisplay.instance().dpy, 
202             rootWin, 
203             windowManager.getAtom("NetLast",NetSupported), 
204             XA_ATOM, 32,
205             PropModeReplace, 
206             cast(ubyte*) windowManager.getAllAtoms("NetLast"), 
207             NetLast
208         );
209 
210         XDeleteProperty(
211             AppDisplay.instance().dpy, 
212             rootWin, 
213             windowManager.getAtom("NetLast", NetClientList)
214         );
215 
216         /* select for events */
217         wa.cursor = cursor[CurNormal].cursor;
218         wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask|ButtonPressMask|PointerMotionMask
219                         |EnterWindowMask|LeaveWindowMask|StructureNotifyMask|PropertyChangeMask;
220 
221         XChangeWindowAttributes(AppDisplay.instance().dpy, rootWin, CWEventMask|CWCursor, &wa);
222         XSelectInput(AppDisplay.instance().dpy, rootWin, wa.event_mask);
223         keyboardEventHandler.grabkeys();
224 
225         focus(null);
226     }
227 
228     void checkotherwm() 
229     {
230         xerrorxlib = XSetErrorHandler(&xerrorstart);
231         /* this causes an error if some other window manager is running */
232         XSelectInput(AppDisplay.instance().dpy, DefaultRootWindow(AppDisplay.instance().dpy), SubstructureRedirectMask);
233         XSync(AppDisplay.instance().dpy, false);
234         XSetErrorHandler(&xerror);
235         XSync(AppDisplay.instance().dpy, false);
236     }
237 
238     void scan() 
239     {
240         uint i, num;
241         Window d1, d2;
242         Window* wins = null;
243         XWindowAttributes wa;
244 
245         if(XQueryTree(AppDisplay.instance().dpy, rootWin, &d1, &d2, &wins, &num)) {
246             for(i = 0; i < num; i++) {
247                 if(!XGetWindowAttributes(AppDisplay.instance().dpy, wins[i], &wa)
248                         || wa.override_redirect || XGetTransientForHint(AppDisplay.instance().dpy, wins[i], &d1))
249                     continue;
250                 if(wa.map_state == IsViewable || getstate(wins[i]) == IconicState)
251                     windowManager.manage(wins[i], &wa);
252             }
253             for(i = 0; i < num; i++) { /* now the transients */
254                 if(!XGetWindowAttributes(AppDisplay.instance().dpy, wins[i], &wa))
255                     continue;
256                 if(XGetTransientForHint(AppDisplay.instance().dpy, wins[i], &d1)
257                         && (wa.map_state == IsViewable || getstate(wins[i]) == IconicState))
258                     windowManager.manage(wins[i], &wa);
259             }
260             if(wins)
261                 XFree(wins);
262         }
263     }
264 
265     void run() 
266     {
267         extern(C) __gshared XEvent ev;
268 
269         /* main event loop */
270         XSync(AppDisplay.instance().dpy, false);
271         while(AppDisplay.instance().running && !XNextEvent(AppDisplay.instance().dpy, &ev)) {
272             eventManager.listen(&ev);
273         }
274     }
275 
276     int boot()
277     {
278         keys = keyboardEventHandler.getKeys();
279         buttons = mouseEventHandler.getButtons();
280 
281         this.checkotherwm();
282         this.setup();    
283         this.scan();
284         this.run();
285         this.close();
286 
287         return 0;
288     }
289 
290     void cleanup() 
291     {
292         auto a = Arg(-1);
293         Layout foo = { "", null };
294 
295         view(&a);
296         selmon.lt[selmon.sellt] = &foo;
297         foreach(m; mons.range) {
298             while(m.stack) {
299                 unmanage(m.stack, false);
300             }
301         }
302         XUngrabKey(AppDisplay.instance().dpy, AnyKey, AnyModifier, rootWin);
303         while(mons) {
304             cleanupmon(mons);
305         }
306 
307         Cur.free(cursor[CurNormal]);
308         Cur.free(cursor[CurResize]);
309         Cur.free(cursor[CurMove]);
310         Fnt.free(AppDisplay.instance().dpy, fnt);
311         Clr.free(ThemeManager.instance().getScheme(SchemeNorm).border);
312         Clr.free(ThemeManager.instance().getScheme(SchemeNorm).bg);
313         Clr.free(ThemeManager.instance().getScheme(SchemeNorm).fg);
314         Clr.free(ThemeManager.instance().getScheme(SchemeSel).border);
315         Clr.free(ThemeManager.instance().getScheme(SchemeSel).bg);
316         Clr.free(ThemeManager.instance().getScheme(SchemeSel).fg);
317 
318 
319         Drw.free(drw);
320         XSync(AppDisplay.instance().dpy, false);
321         XSetInputFocus(AppDisplay.instance().dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
322         XDeleteProperty(AppDisplay.instance().dpy, rootWin, netatom[NetActiveWindow]);
323     }
324 
325     void close()
326     {
327         this.cleanup();
328         XCloseDisplay(AppDisplay.instance().dpy);
329     }
330 }