3 This file is part of libmspgbase
4 Copyright © 2007 Mikko Rasa, Mikkosoft Productions
5 Distributed under the LGPL
10 #include <X11/Xatom.h>
11 #include <X11/Xutil.h>
15 #include <msp/core/application.h>
16 #include <msp/core/except.h>
25 WindowOptions::WindowOptions():
33 Window::Window(Display &dpy, unsigned w, unsigned h, bool fs):
38 options.fullscreen=fs;
43 Window::Window(Display &dpy, const WindowOptions &opts):
56 XDestroyWindow(display.get_display(), window);
59 display.remove_window(this);
61 if(options.fullscreen)
62 display.restore_mode();
65 void Window::set_title(const string &title)
68 SetWindowText(window, title.c_str());
70 vector<unsigned char> buf(title.begin(), title.end());
73 prop.encoding=XA_STRING;
75 prop.nitems=title.size();
76 XSetWMName(display.get_display(), window, &prop);
77 display.check_error();
81 void Window::reconfigure(const WindowOptions &opts)
83 bool fullscreen_changed=(opts.fullscreen!=options.fullscreen);
89 SetRect(&rect, 0, 0, options.width, options.height);
91 int style=(options.fullscreen ? WS_POPUP : WS_OVERLAPPEDWINDOW);
92 if(!options.resizable)
93 style&=~WS_THICKFRAME;
94 int exstyle=(options.fullscreen ? WS_EX_APPWINDOW : WS_EX_OVERLAPPEDWINDOW);
95 AdjustWindowRectEx(&rect, style, false, exstyle);
97 if(fullscreen_changed)
100 SetWindowLong(window, GWL_EXSTYLE, exstyle);
101 SetWindowLong(window, GWL_STYLE, style);
105 if(options.fullscreen)
106 SetWindowPos(window, 0, 0, 0, rect.right-rect.left, rect.bottom-rect.top, SWP_NOZORDER);
108 SetWindowPos(window, 0, 0, 0, rect.right-rect.left, rect.bottom-rect.top, SWP_NOMOVE|SWP_NOZORDER);
110 (void)fullscreen_changed;
112 ::Display *dpy=display.get_display();
114 if(fullscreen_changed)
117 XSetWindowAttributes attr;
118 attr.override_redirect=options.fullscreen;
119 XChangeWindowAttributes(dpy, window, CWOverrideRedirect, &attr);
124 if(options.resizable)
128 hints.flags=PMinSize|PMaxSize;
129 hints.min_width=hints.max_width=options.width;
130 hints.min_height=hints.max_height=options.height;
132 XSetWMNormalHints(dpy, window, &hints);
134 if(options.fullscreen)
135 XMoveResizeWindow(dpy, window, 0, 0, options.width, options.height);
137 XResizeWindow(dpy, window, options.width, options.height);
140 if(options.fullscreen)
141 display.set_mode(VideoMode(options.width, options.height));
142 else if(fullscreen_changed)
143 display.restore_mode();
149 ShowWindow(window, SW_SHOWNORMAL);
151 XMapRaised(display.get_display(), window);
152 display.check_error();
159 ShowWindow(window, SW_HIDE);
161 XUnmapWindow(display.get_display(), window);
162 display.check_error();
169 static bool wndclass_created=false;
171 if(!wndclass_created)
175 wndcl.cbSize=sizeof(WNDCLASSEX);
177 wndcl.lpfnWndProc=&wndproc_;
179 wndcl.cbWndExtra=sizeof(Window *);
180 wndcl.hInstance=reinterpret_cast<HINSTANCE>(Application::get_data());
182 wndcl.hCursor=LoadCursor(0, IDC_ARROW);
183 wndcl.hbrBackground=0;
184 wndcl.lpszMenuName=0;
185 wndcl.lpszClassName="mspgbase";
188 if(!RegisterClassEx(&wndcl))
189 throw Exception("Couldn't register window class");
191 wndclass_created=true;
195 SetRect(&rect, 0, 0, options.width, options.height);
197 int style=(options.fullscreen ? WS_POPUP : WS_OVERLAPPEDWINDOW);
198 if(!options.resizable)
199 style&=~WS_THICKFRAME;
200 int exstyle=(options.fullscreen ? WS_EX_APPWINDOW : WS_EX_OVERLAPPEDWINDOW);
201 AdjustWindowRectEx(&rect, style, false, exstyle);
203 window=CreateWindowEx(exstyle,
207 CW_USEDEFAULT, CW_USEDEFAULT,
208 rect.right-rect.left, rect.bottom-rect.top,
211 reinterpret_cast<HINSTANCE>(Application::get_data()),
214 throw Exception("CreateWindowEx failed");
216 if(options.fullscreen)
217 display.set_mode(VideoMode(options.width, options.height));
220 ::Display *dpy=display.get_display();
222 wm_delete_window=XInternAtom(dpy, "WM_DELETE_WINDOW", true);
224 XSetWindowAttributes attr;
225 attr.override_redirect=options.fullscreen;
226 attr.event_mask=ButtonPressMask|ButtonReleaseMask|PointerMotionMask|KeyPressMask|KeyReleaseMask|StructureNotifyMask|EnterWindowMask;
228 window=XCreateWindow(dpy,
229 DefaultRootWindow(dpy),
231 options.width, options.height,
236 CWOverrideRedirect|CWEventMask, &attr);
238 XSetWMProtocols(dpy, window, &wm_delete_window, 1);
240 if(!options.resizable)
243 hints.flags=PMinSize|PMaxSize;
244 hints.min_width=hints.max_width=options.width;
245 hints.min_height=hints.max_height=options.height;
246 XSetWMNormalHints(dpy, window, &hints);
249 if(options.fullscreen)
251 display.set_mode(VideoMode(options.width, options.height));
252 XWarpPointer(dpy, None, window, 0, 0, 0, 0, options.width/2, options.height/2);
256 display.add_window(this);
257 display.check_error();
261 void Window::event(const XEvent &ev)
266 signal_button_press.emit(ev.xbutton.x, ev.xbutton.y, ev.xbutton.button, ev.xbutton.state);
269 signal_button_release.emit(ev.xbutton.x, ev.xbutton.y, ev.xbutton.button, ev.xbutton.state);
272 signal_pointer_motion.emit(ev.xmotion.x, ev.xmotion.y);
277 XLookupString(const_cast<XKeyEvent *>(&ev.xkey), buf, sizeof(buf), 0, 0);
278 // XXX Handle the result according to locale
279 signal_key_press.emit(XKeycodeToKeysym(display.get_display(), ev.xkey.keycode, 0), ev.xkey.state, buf[0]);
283 signal_key_release.emit(XKeycodeToKeysym(display.get_display(), ev.xkey.keycode, 0), ev.xkey.state);
285 case ConfigureNotify:
286 options.width=ev.xconfigure.width;
287 options.height=ev.xconfigure.height;
288 signal_resize.emit(options.width, options.height);
291 if(ev.xclient.data.l[0]==static_cast<long>(wm_delete_window))
295 XSetInputFocus(display.get_display(), window, RevertToParent, CurrentTime);
298 if(options.fullscreen)
299 XGrabPointer(display.get_display(), window, true, None, GrabModeAsync, GrabModeAsync, window, None, CurrentTime);
307 int Window::wndproc(UINT msg, WPARAM wp, LPARAM lp)
312 signal_key_press.emit(wp, 0, wp);
315 signal_key_release.emit(wp, 0);
318 signal_button_press.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 1, 0);
321 signal_button_release.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 1, 0);
324 signal_button_press.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 2, 0);
327 signal_button_release.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 2, 0);
330 signal_button_press.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 3, 0);
333 signal_button_release.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 3, 0);
336 signal_pointer_motion.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp));
339 options.width=LOWORD(lp);
340 options.height=HIWORD(lp);
341 signal_resize.emit(options.width, options.height);
353 LRESULT CALLBACK Window::wndproc_(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
357 CREATESTRUCT *cs=reinterpret_cast<CREATESTRUCT *>(lparam);
358 SetWindowLong(hwnd, 0, reinterpret_cast<LONG>(cs->lpCreateParams));
362 Window *wnd=reinterpret_cast<Window *>(GetWindowLong(hwnd, 0));
363 if(wnd && wnd->wndproc(msg, wparam, lparam))
367 return DefWindowProc(hwnd, msg, wparam, lparam);
371 } // namespace Graphics