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