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);
88 // XXX Preserve position
89 MoveWindow(window, 0, 0, options.width, options.height, false);
91 (void)fullscreen_changed;
93 ::Display *dpy=display.get_display();
95 XMoveResizeWindow(dpy, window, 0, 0, options.width, options.height);
97 if(fullscreen_changed)
100 XSetWindowAttributes attr;
101 attr.override_redirect=options.fullscreen;
102 XChangeWindowAttributes(dpy, window, CWOverrideRedirect, &attr);
106 if(options.fullscreen)
107 display.set_mode(VideoMode(options.width, options.height));
108 else if(fullscreen_changed)
109 display.restore_mode();
116 ShowWindow(window, SW_SHOWNORMAL);
118 XMapRaised(display.get_display(), window);
119 display.check_error();
126 ShowWindow(window, SW_HIDE);
128 XUnmapWindow(display.get_display(), window);
129 display.check_error();
136 static bool wndclass_created=false;
138 if(!wndclass_created)
142 wndcl.cbSize=sizeof(WNDCLASSEX);
144 wndcl.lpfnWndProc=&wndproc_;
146 wndcl.cbWndExtra=sizeof(Window *);
147 wndcl.hInstance=reinterpret_cast<HINSTANCE>(Application::get_data());
149 wndcl.hCursor=LoadCursor(0, IDC_ARROW);
150 wndcl.hbrBackground=0;
151 wndcl.lpszMenuName=0;
152 wndcl.lpszClassName="mspgbase";
155 if(!RegisterClassEx(&wndcl))
156 throw Exception("Couldn't register window class");
158 wndclass_created=true;
164 rect.right=options.width;
165 rect.bottom=options.height;
166 AdjustWindowRectEx(&rect, WS_OVERLAPPEDWINDOW, false, WS_EX_OVERLAPPEDWINDOW);
168 window=CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,
172 CW_USEDEFAULT, CW_USEDEFAULT,
173 rect.right-rect.left, rect.bottom-rect.top,
176 reinterpret_cast<HINSTANCE>(Application::get_data()),
179 throw Exception("CreateWindowEx failed");
182 ::Display *dpy=display.get_display();
184 wm_delete_window=XInternAtom(dpy, "WM_DELETE_WINDOW", true);
186 XSetWindowAttributes attr;
187 attr.override_redirect=options.fullscreen;
188 attr.event_mask=ButtonPressMask|ButtonReleaseMask|PointerMotionMask|KeyPressMask|KeyReleaseMask|StructureNotifyMask|EnterWindowMask;
190 window=XCreateWindow(dpy,
191 DefaultRootWindow(dpy),
193 options.width, options.height,
198 CWOverrideRedirect|CWEventMask, &attr);
200 XSetWMProtocols(dpy, window, &wm_delete_window, 1);
202 if(options.fullscreen)
204 display.set_mode(VideoMode(options.width, options.height));
205 XWarpPointer(dpy, None, window, 0, 0, 0, 0, options.width/2, options.height/2);
209 display.add_window(this);
210 display.check_error();
214 void Window::event(const XEvent &ev)
219 signal_button_press.emit(ev.xbutton.x, ev.xbutton.y, ev.xbutton.button, ev.xbutton.state);
222 signal_button_release.emit(ev.xbutton.x, ev.xbutton.y, ev.xbutton.button, ev.xbutton.state);
225 signal_pointer_motion.emit(ev.xmotion.x, ev.xmotion.y);
230 XLookupString(const_cast<XKeyEvent *>(&ev.xkey), buf, sizeof(buf), 0, 0);
231 // XXX Handle the result according to locale
232 signal_key_press.emit(XKeycodeToKeysym(display.get_display(), ev.xkey.keycode, 0), ev.xkey.state, buf[0]);
236 signal_key_release.emit(XKeycodeToKeysym(display.get_display(), ev.xkey.keycode, 0), ev.xkey.state);
238 case ConfigureNotify:
239 options.width=ev.xconfigure.width;
240 options.height=ev.xconfigure.height;
241 signal_resize.emit(options.width, options.height);
244 if(ev.xclient.data.l[0]==static_cast<long>(wm_delete_window))
248 XSetInputFocus(display.get_display(), window, RevertToParent, CurrentTime);
251 if(options.fullscreen)
252 XGrabPointer(display.get_display(), window, true, None, GrabModeAsync, GrabModeAsync, window, None, CurrentTime);
260 int Window::wndproc(UINT msg, WPARAM wp, LPARAM lp)
265 signal_key_press.emit(wp, 0, wp);
268 signal_key_release.emit(wp, 0);
271 signal_button_press.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 1, 0);
274 signal_button_release.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 1, 0);
277 signal_button_press.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 2, 0);
280 signal_button_release.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 2, 0);
283 signal_button_press.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 3, 0);
286 signal_button_release.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 3, 0);
289 signal_pointer_motion.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp));
301 LRESULT CALLBACK Window::wndproc_(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
305 CREATESTRUCT *cs=reinterpret_cast<CREATESTRUCT *>(lparam);
306 SetWindowLong(hwnd, 0, reinterpret_cast<LONG>(cs->lpCreateParams));
310 Window *wnd=reinterpret_cast<Window *>(GetWindowLong(hwnd, 0));
311 if(wnd && wnd->wndproc(msg, wparam, lparam))
315 return DefWindowProc(hwnd, msg, wparam, lparam);
319 } // namespace Graphics