]> git.tdb.fi Git - libs/gui.git/blob - source/gbase/window.cpp
Add platform independent constants for keys (win32 code untested)
[libs/gui.git] / source / gbase / window.cpp
1 /* $Id$
2
3 This file is part of libmspgbase
4 Copyright © 2007 Mikko Rasa, Mikkosoft Productions
5 Distributed under the LGPL
6 */
7
8 #include <vector>
9 #ifndef WIN32
10 #include <X11/Xatom.h>
11 #include <X11/Xutil.h>
12 #else
13 #include <windowsx.h>
14 #endif
15 #include <msp/core/application.h>
16 #include <msp/core/except.h>
17 #include "display.h"
18 #include "window.h"
19
20 using namespace std;
21
22 namespace Msp {
23 namespace Graphics {
24
25 WindowOptions::WindowOptions():
26         width(640),
27         height(480),
28         fullscreen(false),
29         resizable(false)
30 { }
31
32
33 Window::Window(Display &dpy, unsigned w, unsigned h, bool fs):
34         display(dpy)
35 {
36         options.width=w;
37         options.height=h;
38         options.fullscreen=fs;
39
40         init();
41 }
42
43 Window::Window(Display &dpy, const WindowOptions &opts):
44         display(dpy),
45         options(opts)
46 {
47         init();
48 }
49
50 Window::~Window()
51 {
52         if(window)
53 #ifdef WIN32
54                 CloseWindow(window);
55 #else
56                 XDestroyWindow(display.get_display(), window);
57 #endif
58
59         display.remove_window(this);
60
61         if(options.fullscreen)
62                 display.restore_mode();
63 }
64
65 void Window::set_title(const string &title)
66 {
67 #ifdef WIN32
68         SetWindowText(window, title.c_str());
69 #else
70         vector<unsigned char> buf(title.begin(), title.end());
71         XTextProperty prop;
72         prop.value=&buf[0];
73         prop.encoding=XA_STRING;
74         prop.format=8;
75         prop.nitems=title.size();
76         XSetWMName(display.get_display(), window, &prop);
77         display.check_error();
78 #endif
79 }
80
81 void Window::reconfigure(const WindowOptions &opts)
82 {
83         bool fullscreen_changed=(opts.fullscreen!=options.fullscreen);
84
85         options=opts;
86
87 #ifdef WIN32
88         // XXX Preserve position
89         MoveWindow(window, 0, 0, options.width, options.height, false);
90
91         (void)fullscreen_changed;
92 #else
93         ::Display *dpy=display.get_display();
94
95         XMoveResizeWindow(dpy, window, 0, 0, options.width, options.height);
96
97         if(fullscreen_changed)
98         {
99                 hide();
100                 XSetWindowAttributes attr;
101                 attr.override_redirect=options.fullscreen;
102                 XChangeWindowAttributes(dpy, window, CWOverrideRedirect, &attr);
103                 show();
104         }
105
106         if(options.fullscreen)
107                 display.set_mode(VideoMode(options.width, options.height));
108         else if(fullscreen_changed)
109                 display.restore_mode();
110 #endif
111 }
112
113 void Window::show()
114 {
115 #ifdef WIN32
116         ShowWindow(window, SW_SHOWNORMAL);
117 #else
118         XMapRaised(display.get_display(), window);
119         display.check_error();
120 #endif
121 }
122
123 void Window::hide()
124 {
125 #ifdef WIN32
126         ShowWindow(window, SW_HIDE);
127 #else
128         XUnmapWindow(display.get_display(), window);
129         display.check_error();
130 #endif
131 }
132
133 void Window::init()
134 {
135 #ifdef WIN32
136         static bool wndclass_created=false;
137
138         if(!wndclass_created)
139         {
140                 WNDCLASSEX wndcl;
141
142                 wndcl.cbSize=sizeof(WNDCLASSEX);
143                 wndcl.style=0;
144                 wndcl.lpfnWndProc=&wndproc_;
145                 wndcl.cbClsExtra=0;
146                 wndcl.cbWndExtra=sizeof(Window *);
147                 wndcl.hInstance=reinterpret_cast<HINSTANCE>(Application::get_data());
148                 wndcl.hIcon=0;
149                 wndcl.hCursor=LoadCursor(0, IDC_ARROW);
150                 wndcl.hbrBackground=0;
151                 wndcl.lpszMenuName=0;
152                 wndcl.lpszClassName="mspgbase";
153                 wndcl.hIconSm=0;
154
155                 if(!RegisterClassEx(&wndcl))
156                         throw Exception("Couldn't register window class");
157
158                 wndclass_created=true;
159         }
160
161         RECT rect;
162         rect.left=0;
163         rect.top=0;
164         rect.right=options.width;
165         rect.bottom=options.height;
166         AdjustWindowRectEx(&rect, WS_OVERLAPPEDWINDOW, false, WS_EX_OVERLAPPEDWINDOW);
167
168         window=CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,
169                 "mspgbase",
170                 "Window",
171                 WS_OVERLAPPEDWINDOW,
172                 CW_USEDEFAULT, CW_USEDEFAULT,
173                 rect.right-rect.left, rect.bottom-rect.top,
174                 0,
175                 0,
176                 reinterpret_cast<HINSTANCE>(Application::get_data()),
177                 this);
178         if(!window)
179                 throw Exception("CreateWindowEx failed");
180
181 #else
182         ::Display *dpy=display.get_display();
183
184         wm_delete_window=XInternAtom(dpy, "WM_DELETE_WINDOW", true);
185
186         XSetWindowAttributes attr;
187         attr.override_redirect=options.fullscreen;
188         attr.event_mask=ButtonPressMask|ButtonReleaseMask|PointerMotionMask|KeyPressMask|KeyReleaseMask|StructureNotifyMask|EnterWindowMask;
189
190         window=XCreateWindow(dpy,
191                 DefaultRootWindow(dpy),
192                 0, 0,
193                 options.width, options.height,
194                 0,
195                 CopyFromParent,
196                 InputOutput,
197                 CopyFromParent,
198                 CWOverrideRedirect|CWEventMask, &attr);
199
200         XSetWMProtocols(dpy, window, &wm_delete_window, 1);
201
202         if(options.fullscreen)
203         {
204                 display.set_mode(VideoMode(options.width, options.height));
205                 XWarpPointer(dpy, None, window, 0, 0, 0, 0, options.width/2, options.height/2);
206         }
207 #endif
208
209         display.add_window(this);
210         display.check_error();
211 }
212
213 #ifndef WIN32
214 void Window::event(const XEvent &ev)
215 {
216         switch(ev.type)
217         {
218         case ButtonPress:
219                 signal_button_press.emit(ev.xbutton.x, ev.xbutton.y, ev.xbutton.button, ev.xbutton.state);
220                 break;
221         case ButtonRelease:
222                 signal_button_release.emit(ev.xbutton.x, ev.xbutton.y, ev.xbutton.button, ev.xbutton.state);
223                 break;
224         case MotionNotify:
225                 signal_pointer_motion.emit(ev.xmotion.x, ev.xmotion.y);
226                 break;
227         case KeyPress:
228                 {
229                         char buf[16];
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]);
233                 }
234                 break;
235         case KeyRelease:
236                 signal_key_release.emit(XKeycodeToKeysym(display.get_display(), ev.xkey.keycode, 0), ev.xkey.state);
237                 break;
238         case ConfigureNotify:
239                 options.width=ev.xconfigure.width;
240                 options.height=ev.xconfigure.height;
241                 signal_resize.emit(options.width, options.height);
242                 break;
243         case ClientMessage:
244                 if(ev.xclient.data.l[0]==static_cast<long>(wm_delete_window))
245                         signal_close.emit();
246                 break;
247         case EnterNotify:
248                 XSetInputFocus(display.get_display(), window, RevertToParent, CurrentTime);
249                 break;
250         case MapNotify:
251                 if(options.fullscreen)
252                         XGrabPointer(display.get_display(), window, true, None, GrabModeAsync, GrabModeAsync, window, None, CurrentTime);
253                 break;
254         default:;
255         }
256 }
257 #endif
258
259 #ifdef WIN32
260 int Window::wndproc(UINT msg, WPARAM wp, LPARAM lp)
261 {
262         switch(msg)
263         {
264         case WM_KEYDOWN:
265                 signal_key_press.emit(wp, 0, wp);
266                 break;
267         case WM_KEYUP:
268                 signal_key_release.emit(wp, 0);
269                 break;
270         case WM_LBUTTONDOWN:
271                 signal_button_press.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 1, 0);
272                 break;
273         case WM_LBUTTONUP:
274                 signal_button_release.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 1, 0);
275                 break;
276         case WM_MBUTTONDOWN:
277                 signal_button_press.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 2, 0);
278                 break;
279         case WM_MBUTTONUP:
280                 signal_button_release.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 2, 0);
281                 break;
282         case WM_RBUTTONDOWN:
283                 signal_button_press.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 3, 0);
284                 break;
285         case WM_RBUTTONUP:
286                 signal_button_release.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 3, 0);
287                 break;
288         case WM_MOUSEMOVE:
289                 signal_pointer_motion.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp));
290                 break;
291         case WM_CLOSE:
292                 signal_close.emit();
293                 break;
294         default:
295                 return 0;
296         }
297
298         return 1;
299 }
300
301 LRESULT CALLBACK Window::wndproc_(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
302 {
303         if(msg==WM_CREATE)
304         {
305                 CREATESTRUCT *cs=reinterpret_cast<CREATESTRUCT *>(lparam);
306                 SetWindowLong(hwnd, 0, reinterpret_cast<LONG>(cs->lpCreateParams));
307         }
308         else
309         {
310                 Window *wnd=reinterpret_cast<Window *>(GetWindowLong(hwnd, 0));
311                 if(wnd && wnd->wndproc(msg, wparam, lparam))
312                         return 0;
313         }
314
315         return DefWindowProc(hwnd, msg, wparam, lparam);
316 }
317 #endif
318
319 } // namespace Graphics
320 } // namespace Msp