1 module ws.wm.x11.wm; 2 3 version(Posix): 4 5 import 6 std.stdio, 7 std.traits, 8 std.meta, 9 std.algorithm, 10 derelict.opengl3.gl, 11 ws.wm, 12 ws.wm.baseWindowManager, 13 ws.wm.x11.api, 14 ws.wm.x11.window, 15 ws.list, 16 ws.wm.baseWindowManager; 17 18 19 __gshared: 20 21 22 23 private struct Mapping(int m, int t, T, string fn){ 24 enum mask = m; 25 enum type = t; 26 alias Event = T; 27 enum attribute = fn; 28 } 29 30 31 alias EventMap = AliasSeq!( 32 Mapping!(ButtonPressMask, ButtonPress, XButtonPressedEvent, "xbutton"), 33 Mapping!(ButtonReleaseMask, ButtonRelease, XButtonReleasedEvent, "xbutton"), 34 Mapping!(ColormapChangeMask, ColormapNotify, XColormapEvent, "xcolormap"), 35 Mapping!(EnterWindowMask, EnterNotify, XEnterWindowEvent, "xcrossing"), 36 Mapping!(LeaveWindowMask, LeaveNotify, XLeaveWindowEvent, "xcrossing"), 37 Mapping!(ExposureMask, Expose, XExposeEvent, "xexpose"), 38 Mapping!(GCGraphicsExposures, GraphicsExpose, XGraphicsExposeEvent, "xgraphicsexpose"), 39 Mapping!(GCGraphicsExposures, NoExpose, XNoExposeEvent, "xnoexpose"), 40 Mapping!(FocusChangeMask, FocusIn, XFocusInEvent, "xfocus"), 41 Mapping!(FocusChangeMask, FocusOut, XFocusOutEvent, "xfocus"), 42 Mapping!(KeymapStateMask, KeymapNotify, XKeymapEvent, "xkeymap"), 43 Mapping!(KeyPressMask, KeyPress, XKeyPressedEvent, "xkey"), 44 Mapping!(KeyReleaseMask, KeyRelease, XKeyReleasedEvent, "xkey"), 45 Mapping!(PointerMotionMask, MotionNotify, XPointerMovedEvent, "xmotion"), 46 Mapping!(PropertyChangeMask, PropertyNotify, XPropertyEvent, "xproperty"), 47 Mapping!(ResizeRedirectMask, ResizeRequest, XResizeRequestEvent, "xresizerequest"), 48 Mapping!(StructureNotifyMask, CirculateNotify, XCirculateEvent, "xcirculate"), 49 Mapping!(StructureNotifyMask, ConfigureNotify, XConfigureEvent, "xconfigure"), 50 Mapping!(StructureNotifyMask, DestroyNotify, XDestroyWindowEvent, "xdestroywindow"), 51 Mapping!(StructureNotifyMask, GravityNotify, XGravityEvent, "xgravity"), 52 Mapping!(StructureNotifyMask, MapNotify, XMapEvent, "xmap"), 53 Mapping!(StructureNotifyMask, ReparentNotify, XReparentEvent, "xreparent"), 54 Mapping!(StructureNotifyMask, UnmapNotify, XUnmapEvent, "xunmap"), 55 56 Mapping!(SubstructureNotifyMask, CirculateNotify, XCirculateEvent, "xcirculate"), 57 Mapping!(SubstructureNotifyMask, ConfigureNotify, XConfigureEvent, "xconfigure"), 58 Mapping!(SubstructureNotifyMask, CreateNotify, XCreateWindowEvent, "xcreatewindow"), 59 Mapping!(SubstructureNotifyMask, GravityNotify, XGravityEvent, "xgravity"), 60 Mapping!(SubstructureNotifyMask, MapNotify, XMapEvent, "xmap"), 61 Mapping!(SubstructureNotifyMask, ReparentNotify, XReparentEvent, "xreparent"), 62 Mapping!(SubstructureNotifyMask, UnmapNotify, XUnmapEvent, "xunmap"), 63 Mapping!(SubstructureRedirectMask, CirculateRequest, XCirculateRequestEvent, "xcirculaterequest"), 64 Mapping!(SubstructureRedirectMask, ConfigureRequest, XConfigureRequestEvent, "xconfigurerequest"), 65 Mapping!(SubstructureRedirectMask, MapRequest, XMapRequestEvent, "xmaprequest"), 66 67 Mapping!(None, ClientMessage, XClientMessageEvent, "xclient"), 68 Mapping!(None, MappingNotify, XMappingEvent, "xmapping"), 69 Mapping!(None, SelectionClear, XSelectionClearEvent, "xselectionclear"), 70 Mapping!(None, SelectionNotify, XSelectionEvent, "xselection"), 71 Mapping!(None, SelectionRequest, XSelectionRequestEvent, "xselectionrequest"), 72 Mapping!(VisibilityChangeMask, VisibilityNotify, XVisibilityEvent, "xvisibility") 73 ); 74 75 76 class X11WindowManager: BaseWindowManager { 77 78 this(){ 79 XInitThreads(); 80 super(); 81 DerelictGL3.load(); 82 displayHandle = XOpenDisplay(null); 83 glCore = true; 84 glXCreateContextAttribsARB = cast(T_glXCreateContextAttribsARB) 85 glXGetProcAddress("glXCreateContextAttribsARB"); 86 if(!glXCreateContextAttribsARB) 87 glCore = false; 88 89 if(glCore){ 90 91 auto getFramebufferConfigs = (int[int] attributes){ 92 int[] attribs; 93 foreach(key, value; attributes){ 94 attribs ~= [key, value]; 95 } 96 attribs ~= 0; 97 98 int configCount; 99 GLXFBConfig* mFBConfig = glXChooseFBConfig(displayHandle, DefaultScreen(displayHandle), 100 attribs.ptr, &configCount); 101 auto result = mFBConfig[0..configCount].dup; 102 XFree(mFBConfig); 103 return result; 104 }; 105 106 auto fbAttribs = [ 107 GLX_DRAWABLE_TYPE: GLX_WINDOW_BIT, 108 GLX_X_RENDERABLE: True, 109 GLX_RENDER_TYPE: GLX_RGBA_BIT, 110 GLX_ALPHA_SIZE: 8, 111 GLX_RED_SIZE: 8, 112 GLX_BLUE_SIZE: 8, 113 GLX_GREEN_SIZE: 8, 114 GLX_DEPTH_SIZE: 16, 115 GLX_DOUBLEBUFFER: True, 116 /+ 117 GLX_STENCIL_SIZE: 8, 118 GLX_SAMPLE_BUFFERS: True, 119 GLX_SAMPLES: 2, 120 +/ 121 ]; 122 123 auto fbConfigs = getFramebufferConfigs(fbAttribs); 124 125 if(!fbConfigs.length) 126 throw new Exception("No FB matches"); 127 128 foreach(config; fbConfigs){ 129 auto info = cast(XVisualInfo*)glXGetVisualFromFBConfig(displayHandle, config); 130 if(info.depth == 32){ 131 graphicsInfo = info; 132 break; 133 } 134 } 135 136 if(!graphicsInfo) 137 throw new Exception("Failed to find FB config"); 138 139 }else{ 140 graphicsInfo = new XVisualInfo; 141 if(!XMatchVisualInfo(displayHandle, DefaultScreen(displayHandle), 32, TrueColor, graphicsInfo)) 142 writeln("XMatchVisualInfo failed"); 143 if(!graphicsInfo) 144 writeln("glXChooseVisual failed"); 145 } 146 } 147 148 Display* displayHandle; 149 XVisualInfo* graphicsInfo; 150 bool glCore; 151 GLXFBConfig* mFBConfig; 152 T_glXCreateContextAttribsARB glXCreateContextAttribsARB; 153 154 void delegate(XEvent*)[][int][x11.X.Window] handler; 155 void delegate(XEvent*)[][int] handlerAll; 156 157 void on(void delegate(XEvent*)[int] handlers){ 158 foreach(ev, dg; handlers){ 159 handlerAll[ev] ~= dg; 160 } 161 } 162 163 void on()(x11.X.Window window, void delegate(XEvent*)[int] handlers){ 164 int mask; 165 foreach(ev, dg; handlers){ 166 foreach(mapping; EventMap){ 167 if(mapping.type == ev) 168 mask |= mapping.mask; 169 } 170 handler[window][ev] ~= dg; 171 } 172 //XSelectInput(displayHandle, window, mask); 173 } 174 175 void on(Args...)(x11.X.Window window, Args args) if(allSatisfy!(isCallable, args)) { 176 int mask; 177 foreach(dg; args){ 178 bool found; 179 foreach(mapping; EventMap){ 180 static if(is(mapping.Event* == Parameters!dg[0])){ 181 mask |= mapping.mask; 182 if(!found){ 183 found = true; 184 handler[window][mapping.type] ~= (XEvent* e) => mixin("dg(&e." ~ mapping.attribute ~ ")"); 185 } 186 } 187 } 188 } 189 XSelectInput(displayHandle, window, mask); 190 } 191 192 ~this(){ 193 XCloseDisplay(displayHandle); 194 } 195 196 GraphicsContext currentContext(){ 197 return glXGetCurrentContext(); 198 } 199 200 void processEvents(void delegate(XEvent*) handleAll=null, bool syncNext=false){ 201 XEvent e; 202 while(XPending(displayHandle) || syncNext){ 203 syncNext = false; 204 XNextEvent(displayHandle, &e); 205 if(handleAll) 206 handleAll(&e); 207 foreach(win; wm.windows){ 208 if(e.xany.window == win.windowHandle){ 209 activeWindow = win; 210 win.processEvent(&e); 211 } 212 } 213 if(e.type in handlerAll) 214 foreach(handler; handlerAll[e.type]) 215 handler(&e); 216 if(e.xany.window in handler){ 217 auto handlerWindow = handler[e.xany.window]; 218 if(e.type in handlerWindow) 219 foreach(handlerWindowType; handlerWindow[e.type]) 220 handlerWindowType(&e); 221 } 222 223 } 224 } 225 226 }