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>
27 WindowOptions::WindowOptions():
35 Window::Window(Display &dpy, unsigned w, unsigned h, bool fs):
40 options.fullscreen=fs;
45 Window::Window(Display &dpy, const WindowOptions &opts):
58 XDestroyWindow(display.get_display(), window);
61 display.remove_window(this);
63 if(options.fullscreen)
64 display.restore_mode();
67 void Window::set_title(const string &title)
70 SetWindowText(window, title.c_str());
72 vector<unsigned char> buf(title.begin(), title.end());
75 prop.encoding=XA_STRING;
77 prop.nitems=title.size();
78 XSetWMName(display.get_display(), window, &prop);
79 display.check_error();
83 void Window::reconfigure(const WindowOptions &opts)
85 bool fullscreen_changed=(opts.fullscreen!=options.fullscreen);
90 // XXX Preserve position
91 MoveWindow(window, 0, 0, options.width, options.height, false);
93 (void)fullscreen_changed;
95 ::Display *dpy=display.get_display();
97 XMoveResizeWindow(dpy, window, 0, 0, options.width, options.height);
99 if(fullscreen_changed)
102 XSetWindowAttributes attr;
103 attr.override_redirect=options.fullscreen;
104 XChangeWindowAttributes(dpy, window, CWOverrideRedirect, &attr);
108 if(options.fullscreen)
109 display.set_mode(VideoMode(options.width, options.height));
110 else if(fullscreen_changed)
111 display.restore_mode();
118 ShowWindow(window, SW_SHOWNORMAL);
120 XMapRaised(display.get_display(), window);
121 display.check_error();
128 ShowWindow(window, SW_HIDE);
130 XUnmapWindow(display.get_display(), window);
131 display.check_error();
138 static bool wndclass_created=false;
140 if(!wndclass_created)
144 wndcl.cbSize=sizeof(WNDCLASSEX);
146 wndcl.lpfnWndProc=&wndproc_;
148 wndcl.cbWndExtra=sizeof(Window *);
149 wndcl.hInstance=reinterpret_cast<HINSTANCE>(Application::get_data());
152 wndcl.hbrBackground=0;
153 wndcl.lpszMenuName=0;
154 wndcl.lpszClassName="mspgbase";
157 if(!RegisterClassEx(&wndcl))
158 throw Exception("Couldn't register window class");
160 wndclass_created=true;
166 rect.right=options.width;
167 rect.bottom=options.height;
168 AdjustWindowRectEx(&rect, WS_OVERLAPPEDWINDOW, false, WS_EX_OVERLAPPEDWINDOW);
170 window=CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,
174 CW_USEDEFAULT, CW_USEDEFAULT,
175 rect.right-rect.left, rect.bottom-rect.top,
178 reinterpret_cast<HINSTANCE>(Application::get_data()),
181 throw Exception("CreateWindowEx failed");
184 ::Display *dpy=display.get_display();
186 wm_delete_window=XInternAtom(dpy, "WM_DELETE_WINDOW", true);
188 XSetWindowAttributes attr;
189 attr.override_redirect=options.fullscreen;
190 attr.event_mask=ButtonPressMask|ButtonReleaseMask|PointerMotionMask|KeyPressMask|KeyReleaseMask|StructureNotifyMask|EnterWindowMask;
192 window=XCreateWindow(dpy,
193 DefaultRootWindow(dpy),
195 options.width, options.height,
200 CWOverrideRedirect|CWEventMask, &attr);
202 XSetWMProtocols(dpy, window, &wm_delete_window, 1);
204 if(options.fullscreen)
206 display.set_mode(VideoMode(options.width, options.height));
207 XWarpPointer(dpy, None, window, 0, 0, 0, 0, options.width/2, options.height/2);
211 display.add_window(this);
212 display.check_error();
216 void Window::event(const XEvent &ev)
221 signal_button_press.emit(ev.xbutton.x, ev.xbutton.y, ev.xbutton.button, ev.xbutton.state);
224 signal_button_release.emit(ev.xbutton.x, ev.xbutton.y, ev.xbutton.button, ev.xbutton.state);
227 signal_pointer_motion.emit(ev.xmotion.x, ev.xmotion.y);
232 XLookupString(const_cast<XKeyEvent *>(&ev.xkey), buf, sizeof(buf), 0, 0);
233 // XXX Handle the result according to locale
234 signal_key_press.emit(ev.xkey.keycode, ev.xkey.state, buf[0]);
238 signal_key_release.emit(ev.xkey.keycode, ev.xkey.state);
240 case ConfigureNotify:
241 options.width=ev.xconfigure.width;
242 options.height=ev.xconfigure.height;
243 signal_resize.emit(options.width, options.height);
246 if(ev.xclient.data.l[0]==static_cast<long>(wm_delete_window))
250 XSetInputFocus(display.get_display(), window, RevertToParent, CurrentTime);
253 if(options.fullscreen)
254 XGrabPointer(display.get_display(), window, true, None, GrabModeAsync, GrabModeAsync, window, None, CurrentTime);
262 int Window::wndproc(UINT msg, WPARAM wp, LPARAM lp)
267 signal_key_press.emit(wp, 0, wp);
270 signal_key_release.emit(wp, 0);
273 signal_button_press.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 1, 0);
276 signal_button_release.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 1, 0);
279 signal_button_press.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 2, 0);
282 signal_button_release.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 2, 0);
285 signal_button_press.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 3, 0);
288 signal_button_release.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 3, 0);
291 signal_pointer_motion.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp));
303 LRESULT CALLBACK Window::wndproc_(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
307 CREATESTRUCT *cs=reinterpret_cast<CREATESTRUCT *>(lparam);
308 SetWindowLong(hwnd, 0, reinterpret_cast<LONG>(cs->lpCreateParams));
312 Window *wnd=reinterpret_cast<Window *>(GetWindowLong(hwnd, 0));
313 if(wnd && wnd->wndproc(msg, wparam, lparam))
317 return DefWindowProc(hwnd, msg, wparam, lparam);
321 } // namespace Graphics