]> git.tdb.fi Git - libs/gui.git/blob - source/window.cpp
Support reconfiguring Windows on the fly
[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 #include <X11/Xatom.h>
10 #include <X11/Xutil.h>
11 #include <msp/core/except.h>
12 #include "display.h"
13 #include "window.h"
14
15 using namespace std;
16
17 namespace Msp {
18 namespace Graphics {
19
20 WindowOptions::WindowOptions():
21         width(640),
22         height(480),
23         fullscreen(false),
24         resizable(false)
25 { }
26
27
28 Window::Window(Display &dpy, unsigned w, unsigned h, bool fs):
29         display(dpy)
30 {
31         options.width=w;
32         options.height=h;
33         options.fullscreen=fs;
34
35         init();
36 }
37
38 Window::Window(Display &dpy, const WindowOptions &opts):
39         display(dpy),
40         options(opts)
41 {
42         init();
43 }
44
45 Window::~Window()
46 {
47         if(window)
48                 XDestroyWindow(display.get_display(), window);
49
50         display.remove_window(this);
51
52         if(options.fullscreen)
53                 display.restore_mode();
54 }
55
56 void Window::set_title(const string &title)
57 {
58         vector<unsigned char> buf(title.begin(), title.end());
59         XTextProperty prop;
60         prop.value=&buf[0];
61         prop.encoding=XA_STRING;
62         prop.format=8;
63         prop.nitems=title.size();
64         XSetWMName(display.get_display(), window, &prop);
65         display.check_error();
66 }
67
68 void Window::reconfigure(const WindowOptions &opts)
69 {
70         bool fullscreen_changed=(opts.fullscreen!=options.fullscreen);
71
72         options=opts;
73
74         ::Display *dpy=display.get_display();
75
76         XMoveResizeWindow(dpy, window, 0, 0, options.width, options.height);
77
78         if(fullscreen_changed)
79         {
80                 hide();
81                 XSetWindowAttributes attr;
82                 attr.override_redirect=options.fullscreen;
83                 XChangeWindowAttributes(dpy, window, CWOverrideRedirect, &attr);
84                 show();
85         }
86
87         if(options.fullscreen)
88                 display.set_mode(VideoMode(options.width, options.height));
89         else if(fullscreen_changed)
90                 display.restore_mode();
91 }
92
93 void Window::show()
94 {
95         XMapRaised(display.get_display(), window);
96         display.check_error();
97 }
98
99 void Window::hide()
100 {
101         XUnmapWindow(display.get_display(), window);
102         display.check_error();
103 }
104
105 void Window::init()
106 {
107         ::Display *dpy=display.get_display();
108
109         wm_delete_window=XInternAtom(dpy, "WM_DELETE_WINDOW", true);
110
111         XSetWindowAttributes attr;
112         attr.override_redirect=options.fullscreen;
113         attr.event_mask=ButtonPressMask|ButtonReleaseMask|PointerMotionMask|KeyPressMask|KeyReleaseMask|StructureNotifyMask|EnterWindowMask;
114
115         window=XCreateWindow(dpy, DefaultRootWindow(dpy), 0, 0, options.width, options.height, 0, CopyFromParent, InputOutput, CopyFromParent, CWOverrideRedirect|CWEventMask, &attr);
116
117         XSetWMProtocols(dpy, window, &wm_delete_window, 1);
118
119         if(options.fullscreen)
120         {
121                 display.set_mode(VideoMode(options.width, options.height));
122                 XWarpPointer(dpy, None, window, 0, 0, 0, 0, options.width/2, options.height/2);
123         }
124
125         display.add_window(this);
126         display.check_error();
127 }
128
129 void Window::event(const XEvent &ev)
130 {
131         switch(ev.type)
132         {
133         case ButtonPress:
134                 signal_button_press.emit(ev.xbutton.x, ev.xbutton.y, ev.xbutton.button, ev.xbutton.state);
135                 break;
136         case ButtonRelease:
137                 signal_button_release.emit(ev.xbutton.x, ev.xbutton.y, ev.xbutton.button, ev.xbutton.state);
138                 break;
139         case MotionNotify:
140                 signal_pointer_motion.emit(ev.xmotion.x, ev.xmotion.y);
141                 break;
142         case KeyPress:
143                 {
144                         char buf[16];
145                         XLookupString(const_cast<XKeyEvent *>(&ev.xkey), buf, sizeof(buf), 0, 0);
146                         // XXX Handle the result according to locale
147                         signal_key_press.emit(ev.xkey.keycode, ev.xkey.state, buf[0]);
148                 }
149                 break;
150         case KeyRelease:
151                 signal_key_release.emit(ev.xkey.keycode, ev.xkey.state);
152                 break;
153         case ConfigureNotify:
154                 options.width=ev.xconfigure.width;
155                 options.height=ev.xconfigure.height;
156                 signal_resize.emit(options.width, options.height);
157                 break;
158         case ClientMessage:
159                 if(ev.xclient.data.l[0]==static_cast<long>(wm_delete_window))
160                         signal_close.emit();
161                 break;
162         case EnterNotify:
163                 XSetInputFocus(display.get_display(), window, RevertToParent, CurrentTime);
164                 break;
165         case MapNotify:
166                 if(options.fullscreen)
167                         XGrabPointer(display.get_display(), window, true, None, GrabModeAsync, GrabModeAsync, window, None, CurrentTime);
168                 break;
169         default:;
170         }
171 }
172
173 } // namespace Graphics
174 } // namespace Msp