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 }