1 module ws.wm.win32.wm;
2 
3 version(Windows):
4 
5 import
6 	std.utf,
7 
8 	ws.list,
9 	ws.log,
10 	ws.gui.input,
11 	ws.wm.win32.api,
12 	ws.wm.win32.window,
13 	ws.wm.baseWindowManager,
14 	ws.wm;
15 
16 __gshared:
17 
18 
19 class Win32WindowManager: BaseWindowManager {
20 
21 	T_wglChoosePixelFormatARB wglChoosePixelFormatARB;
22 	T_wglCreateContextAttribsARB wglCreateContextAttribsARB;
23 
24 	HINSTANCE appInstance;
25 	WNDCLASSW windowClass = {0};
26 
27 	void load(string s)(){
28 		auto ptr = core.sys.windows.wingdi.wglGetProcAddress(s);
29 		if(!ptr)
30 			throw new Exception("failed to get function \"" ~ s ~ "\"");
31 		mixin(s ~ " = cast(typeof(" ~ s ~ "))ptr;");
32 	}
33 
34 	this(){
35 		super();
36 		DerelictGL3.load();
37 		appInstance = GetModuleHandleW(null);
38 		
39 		windowClass.lpfnWndProc = cast(WNDPROC)&internalEvents;
40 		windowClass.hInstance = appInstance;
41 		windowClass.hIcon = LoadIconA(null, IDI_APPLICATION);
42 		windowClass.hCursor = LoadCursorA(null, IDC_ARROW);
43 		windowClass.hbrBackground = cast(HBRUSH)GetStockObject(BLACK_BRUSH);
44 		windowClass.lpszClassName = "wm::windowClass".toUTF16z();
45 		windowClass.style = CS_OWNDC;
46 		RegisterClassW(&windowClass);
47 		// the following is solely to retrieve wglChoosePixelFormat && wglCreateContext
48 		HWND dummyWindow = CreateWindowExA(
49 				0, "STATIC", "", WS_POPUP | WS_DISABLED,
50 				0, 0, 1, 1, null, null, appInstance, null
51 		);
52 		PIXELFORMATDESCRIPTOR dummyFormatDescriptor = {
53 			(PIXELFORMATDESCRIPTOR).sizeof, 1, 4 | 32 | 1, 0, 8, 0,
54 			0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0, 0
55 		};
56 		HDC dummyDeviceContext = GetDC(dummyWindow);
57 		int pixelFormat = ChoosePixelFormat(dummyDeviceContext, &dummyFormatDescriptor);
58 		SetPixelFormat(dummyDeviceContext, pixelFormat, &dummyFormatDescriptor);
59 		HGLRC dummyContext = wglCreateContext(dummyDeviceContext);
60 		wglMakeCurrent(dummyDeviceContext, dummyContext);
61 		try {
62 			load!"wglChoosePixelFormatARB"();
63 			load!"wglCreateContextAttribsARB"();
64 		} catch (Exception e)
65 			throw new Exception("OpenGL 3.3 not supported");
66 		wglMakeCurrent(null, null);
67 		wglDeleteContext(dummyContext);
68 		ReleaseDC(dummyWindow, dummyDeviceContext);
69 		DestroyWindow(dummyWindow);
70 	}
71 
72 	HINSTANCE getInstance(){
73 		return appInstance;
74 	}
75 
76 	Window[] systemWindows(){
77 		Window[] list;
78 		HWND h = GetTopWindow(null);
79 		while(h){
80 			list ~= new Win32Window(h);
81 			h = GetWindow(h, 2);
82 		}
83 		return list;
84 	}
85 
86 	void processEvents(){
87 		MSG msg;
88 		while(PeekMessageA(&msg, null, 0, 0, PM_REMOVE)){
89 			TranslateMessage(&msg);
90 			DispatchMessageA(&msg);
91 		}
92 		foreach(window; windows){
93 			activeWindow = window;
94 			window.processEvents;
95 		}
96 	}
97 
98 	long[2] getCursorPos(){
99 		POINT point;
100 		GetCursorPos(&point);
101 		return [point.x, point.y];
102 	}
103 
104 	Win32Window findWindow(string title){
105 		HWND window = FindWindowW(null, title.toUTF16z());
106 		if(!window)
107 			throw new WindowNotFound("Could not find window \"" ~ title ~ "\"");
108 		return new Win32Window(window);
109 	}
110 
111 	bool isKeyDown(Keyboard.key key){
112 		return GetKeyState(cast(int)key) < 0;
113 	}
114 
115 }
116 
117 
118 protected:
119 
120 	static HCURSOR getCursor(int i){
121 		return cast(LPWSTR)(cast(DWORD)(cast(WORD)i));
122 	}
123 
124 	HCURSOR[] MOUSE_CURSOR_TO_HCUR = [
125 		getCursor(32512), // IDC_ARROW
126 		getCursor(32516), // IDC_UPARROW
127 
128 		getCursor(32513), // IDC_BEAM
129 
130 		getCursor(32646), // IDC_SIZEALL
131 		getCursor(32645), // IDC_SIZENS
132 		getCursor(32644), // IDC_SIZEWE
133 		getCursor(32642), // IDC_SIZENWSE
134 		getCursor(32643), // IDC_SIZENESW
135 		getCursor(32643), // IDC_SIZENESW
136 		getCursor(32642), // IDC_SIZENWSE
137 
138 		getCursor(32649), // IDC_HAND
139 
140 		getCursor(32512), // IDC_ARROW
141 		null,
142 	];
143 
144 	extern(Windows)
145 	static LRESULT internalEvents(HWND window, UINT msg, WPARAM wpar, LPARAM lpar) nothrow {
146 		try {
147 			foreach(w; cast(List!Win32Window)wm.windows){
148 				if(w.handle == window){
149 					w.addEvent(Event(msg, wpar, lpar));
150 					if(msg == WM_CLOSE)
151 						return 0;
152 				}
153 			}
154 		} catch(Throwable)
155 			assert(0);
156 		return DefWindowProcW(window, msg, wpar, lpar);
157 	}
158