]> git.tdb.fi Git - libs/gui.git/blob - source/window.cpp
Set override_redirect attribute when fullscreen is requested
[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 "window.h"
13
14 using namespace std;
15
16 namespace Msp {
17
18 DisplayOptions::DisplayOptions():
19         width(640),
20         height(480),
21         fullscreen(false)
22 { }
23
24
25 /**
26 Initializes the class but does not open the window.  Intended for use by
27 derived classes.
28 */
29 Window::Window():
30         display(0),
31         window(0)
32 { }
33
34 Window::Window(unsigned w, unsigned h)
35 {
36         options.width=w;
37         options.height=h;
38
39         init();
40 }
41
42 Window::Window(const DisplayOptions &dopt):
43         options(dopt)
44 {
45         init();
46 }
47
48 Window::~Window()
49 {
50         if(window)
51                 XDestroyWindow(display, window);
52         if(display)
53                 XCloseDisplay(display);
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, window, &prop);
65 }
66
67 void Window::show()
68 {
69         XMapRaised(display, window);
70 }
71
72 void Window::hide()
73 {
74         XUnmapWindow(display, window);
75 }
76
77 void Window::tick()
78 {
79         while(1)
80         {
81                 int pending=XPending(display);
82                 if(pending==0)
83                         break;
84
85                 for(int i=0; i<pending; ++i)
86                 {
87                         XEvent event;
88                         XNextEvent(display, &event);
89                         process_event(event);
90                 }
91         }
92 }
93
94 void Window::prepare()
95 {
96         if(options.display.empty())
97                 display=XOpenDisplay(0);
98         else
99                 display=XOpenDisplay(options.display.c_str());
100         if(!display)
101                 throw Exception("Couldn't open X display");
102
103         wm_delete_window=XInternAtom(display, "WM_DELETE_WINDOW", true);
104
105         /* Throwing from the error handler doesn't work too well and I don't know
106            how to dig up all the information that Xlib gives by default, so disable
107                 custom error handling for now. */
108         //XSetErrorHandler(x_error_handler);
109 }
110
111 void Window::set_window(Handle wnd)
112 {
113         window=wnd;
114
115         XSelectInput(display, window, ButtonPressMask|ButtonReleaseMask|PointerMotionMask|KeyPressMask|KeyReleaseMask|StructureNotifyMask|EnterWindowMask);
116
117         XSetWMProtocols(display, window, &wm_delete_window, 1);
118 }
119
120 void Window::init()
121 {
122         prepare();
123
124         XSetWindowAttributes attr;
125         attr.override_redirect=options.fullscreen;
126
127         Handle wnd=XCreateWindow(display, DefaultRootWindow(display), 0, 0, options.width, options.height, 0, CopyFromParent, InputOutput, CopyFromParent, CWOverrideRedirect, &attr);
128         set_window(wnd);
129 }
130
131 void Window::process_event(const XEvent &event)
132 {
133         switch(event.type)
134         {
135         case ButtonPress:
136                 signal_button_press.emit(event.xbutton.x, event.xbutton.y, event.xbutton.button, event.xbutton.state);
137                 break;
138         case ButtonRelease:
139                 signal_button_release.emit(event.xbutton.x, event.xbutton.y, event.xbutton.button, event.xbutton.state);
140                 break;
141         case MotionNotify:
142                 signal_pointer_motion.emit(event.xmotion.x, event.xmotion.y);
143                 break;
144         case KeyPress:
145                 {
146                         char buf[16];
147                         XLookupString(const_cast<XKeyEvent *>(&event.xkey), buf, sizeof(buf), 0, 0);
148                         // XXX Handle the result according to locale
149                         signal_key_press.emit(event.xkey.keycode, event.xkey.state, buf[0]);
150                 }
151                 break;
152         case KeyRelease:
153                 signal_key_release.emit(event.xkey.keycode, event.xkey.state);
154                 break;
155         case ConfigureNotify:
156                 options.width=event.xconfigure.width;
157                 options.height=event.xconfigure.height;
158                 signal_resize.emit(options.width, options.height);
159                 break;
160         case ClientMessage:
161                 if(event.xclient.data.l[0]==static_cast<long>(wm_delete_window))
162                         signal_close.emit();
163                 break;
164         case EnterNotify:
165                 XSetInputFocus(display, window, RevertToParent, CurrentTime);
166                 break;
167         default:;
168         }
169
170         on_event(event);
171 }
172
173 int Window::x_error_handler(Display *display, XErrorEvent *error)
174 {
175         char buf[128];
176         XGetErrorText(display, error->error_code, buf, sizeof(buf));
177         /*string request_code=lexical_cast(error->request_code);
178         char buf2[1024];
179         XGetErrorDatabaseText(display, "XRequest", request_code.c_str(), buf, buf2, sizeof(buf2));*/
180         throw Exception(buf);
181 }
182
183 } // namespace Msp