]> git.tdb.fi Git - libs/gui.git/blob - source/graphics/x11/window.cpp
Add a signal for window exposure
[libs/gui.git] / source / graphics / x11 / window.cpp
1 #include <vector>
2 #include <X11/Xatom.h>
3 #include <X11/Xutil.h>
4 #include <msp/core/systemerror.h>
5 #include "display_private.h"
6 #include "window.h"
7 #include "window_private.h"
8
9 using namespace std;
10
11 namespace {
12
13 Bool match_event_type(Display *, XEvent *event, XPointer arg)
14 {
15         return event->type==*reinterpret_cast<int *>(arg);
16 }
17
18 }
19
20 namespace Msp {
21 namespace Graphics {
22
23 void Window::platform_init()
24 {
25         DisplayHandle dpy = display.get_private().display;
26
27         priv->wm_delete_window = XInternAtom(dpy, "WM_DELETE_WINDOW", true);
28         priv->invisible_cursor = 0;
29
30         XSetWindowAttributes attr;
31         attr.override_redirect = options.fullscreen;
32         attr.event_mask = ButtonPressMask|ButtonReleaseMask|PointerMotionMask|KeyPressMask|KeyReleaseMask|StructureNotifyMask|EnterWindowMask|ExposureMask;
33
34         priv->window = XCreateWindow(dpy,
35                 DefaultRootWindow(dpy),
36                 0, 0,
37                 options.width, options.height,
38                 0,
39                 CopyFromParent,
40                 InputOutput,
41                 CopyFromParent,
42                 CWOverrideRedirect|CWEventMask, &attr);
43
44         XSetWMProtocols(dpy, priv->window, &priv->wm_delete_window, 1);
45
46         if(!options.resizable)
47         {
48                 XSizeHints hints;
49                 hints.flags = PMinSize|PMaxSize;
50                 hints.min_width=hints.max_width = options.width;
51                 hints.min_height=hints.max_height = options.height;
52                 XSetWMNormalHints(dpy, priv->window, &hints);
53         }
54 }
55
56 void Window::platform_cleanup()
57 {
58         if(priv->window)
59                 XDestroyWindow(display.get_private().display, priv->window);
60
61         if(priv->invisible_cursor)
62                 XFreeCursor(display.get_private().display, priv->invisible_cursor);
63 }
64
65 void Window::set_title(const string &title)
66 {
67         vector<unsigned char> buf(title.begin(), title.end());
68         XTextProperty prop;
69         prop.value = &buf[0];
70         prop.encoding = XA_STRING;
71         prop.format = 8;
72         prop.nitems = title.size();
73         XSetWMName(display.get_private().display, priv->window, &prop);
74         display.check_error();
75 }
76
77 void Window::platform_reconfigure(bool fullscreen_changed)
78 {
79         DisplayHandle dpy = display.get_private().display;
80
81         bool was_visible = visible;
82         if(fullscreen_changed)
83         {
84                 if(was_visible)
85                 {
86                         hide();
87
88                         // Wait for the window to be unmapped.  This makes window managers happy.
89                         XEvent ev;
90                         int ev_type = UnmapNotify;
91                         XPeekIfEvent(dpy, &ev, match_event_type, reinterpret_cast<char *>(&ev_type));
92                 }
93
94                 XSetWindowAttributes attr;
95                 attr.override_redirect = options.fullscreen;
96                 XChangeWindowAttributes(dpy, priv->window, CWOverrideRedirect, &attr);
97         }
98
99         XSizeHints hints;
100         if(options.resizable)
101                 hints.flags = 0;
102         else
103         {
104                 hints.flags = PMinSize|PMaxSize;
105                 hints.min_width = hints.max_width = options.width;
106                 hints.min_height = hints.max_height = options.height;
107         }
108         XSetWMNormalHints(dpy, priv->window, &hints);
109
110         if(options.fullscreen)
111                 XMoveResizeWindow(dpy, priv->window, 0, 0, options.width, options.height);
112         else
113                 XResizeWindow(dpy, priv->window, options.width, options.height);
114
115         if(fullscreen_changed && was_visible)
116                 show();
117 }
118
119 void Window::show_cursor(bool s)
120 {
121         DisplayHandle dpy = display.get_private().display;
122
123         if(s)
124                 XUndefineCursor(dpy, priv->window);
125         else
126         {
127                 if(!priv->invisible_cursor)
128                 {
129                         int screen = DefaultScreen(dpy);
130
131                         Pixmap pm = XCreatePixmap(dpy, priv->window, 1, 1, 1);
132                         GC gc = XCreateGC(dpy, pm, 0, 0);
133                         XSetFunction(dpy, gc, GXclear);
134                         XDrawPoint(dpy, pm, gc, 0, 0);
135                         XFreeGC(dpy, gc);
136
137                         XColor black;
138                         black.pixel = BlackPixel(dpy, screen);
139                         XQueryColor(dpy, DefaultColormap(dpy, screen), &black);
140
141                         priv->invisible_cursor = XCreatePixmapCursor(dpy, pm, pm, &black, &black, 0, 0);
142
143                         XFreePixmap(dpy, pm);
144                 }
145                 XDefineCursor(dpy, priv->window, priv->invisible_cursor);
146         }
147 }
148
149 void Window::warp_pointer(int x, int y)
150 {
151         XWarpPointer(display.get_private().display, None, priv->window, 0, 0, 0, 0, x, y);
152 }
153
154 void Window::platform_set_touch_input()
155 {
156 }
157
158 void Window::platform_show()
159 {
160         XMapRaised(display.get_private().display, priv->window);
161 }
162
163 void Window::platform_hide()
164 {
165         XUnmapWindow(display.get_private().display, priv->window);
166 }
167
168 bool Window::event(const Event &evnt)
169 {
170         const XEvent &ev = evnt.xevent;
171         switch(ev.type)
172         {
173         case ButtonPress:
174         case ButtonRelease:
175         case MotionNotify:
176         case KeyPress:
177         case KeyRelease:
178                 signal_input_event.emit(evnt);
179                 break;
180         case ConfigureNotify:
181                 if((ev.xconfigure.width==static_cast<int>(options.width) && ev.xconfigure.height==static_cast<int>(options.height)) == resizing)
182                 {
183                         options.width = ev.xconfigure.width;
184                         options.height = ev.xconfigure.height;
185                         resizing = false;
186                         signal_resize.emit(options.width, options.height);
187                 }
188                 break;
189         case ClientMessage:
190                 if(ev.xclient.data.l[0]==static_cast<long>(priv->wm_delete_window))
191                         signal_close.emit();
192                 break;
193         case EnterNotify:
194                 if(options.fullscreen)
195                         XSetInputFocus(display.get_private().display, priv->window, RevertToParent, CurrentTime);
196                 break;
197         case MapNotify:
198                 if(options.fullscreen)
199                         XGrabPointer(display.get_private().display, priv->window, true, None, GrabModeAsync, GrabModeAsync, priv->window, None, CurrentTime);
200                 break;
201         case Expose:
202                 signal_expose.emit(ev.xexpose.x, ev.xexpose.y, ev.xexpose.width, ev.xexpose.height, evnt);
203                 break;
204         default:
205                 return false;
206         }
207
208         return true;
209 }
210
211 } // namespace Graphics
212 } // namespace Msp