]> git.tdb.fi Git - libs/gui.git/blob - source/graphics/x11/window.cpp
Remove some leftover XF86VidMode fragments
[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;
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_show()
155 {
156         XMapRaised(display.get_private().display, priv->window);
157 }
158
159 void Window::platform_hide()
160 {
161         XUnmapWindow(display.get_private().display, priv->window);
162 }
163
164 bool Window::event(const Event &evnt)
165 {
166         const XEvent &ev = evnt.xevent;
167         switch(ev.type)
168         {
169         case ButtonPress:
170         case ButtonRelease:
171         case MotionNotify:
172         case KeyPress:
173         case KeyRelease:
174                 signal_input_event.emit(evnt);
175                 break;
176         case ConfigureNotify:
177                 if((ev.xconfigure.width==static_cast<int>(options.width) && ev.xconfigure.height==static_cast<int>(options.height)) == resizing)
178                 {
179                         options.width = ev.xconfigure.width;
180                         options.height = ev.xconfigure.height;
181                         resizing = false;
182                         signal_resize.emit(options.width, options.height);
183                 }
184                 break;
185         case ClientMessage:
186                 if(ev.xclient.data.l[0]==static_cast<long>(priv->wm_delete_window))
187                         signal_close.emit();
188                 break;
189         case EnterNotify:
190                 if(options.fullscreen)
191                         XSetInputFocus(display.get_private().display, priv->window, RevertToParent, CurrentTime);
192                 break;
193         case MapNotify:
194                 if(options.fullscreen)
195                         XGrabPointer(display.get_private().display, priv->window, true, None, GrabModeAsync, GrabModeAsync, priv->window, None, CurrentTime);
196                 break;
197         default:
198                 return false;
199         }
200
201         return true;
202 }
203
204 } // namespace Graphics
205 } // namespace Msp