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 }