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 }