]> git.tdb.fi Git - libs/gui.git/blobdiff - source/graphics/x11/window.cpp
Split platform-specific parts into separate directories
[libs/gui.git] / source / graphics / x11 / window.cpp
diff --git a/source/graphics/x11/window.cpp b/source/graphics/x11/window.cpp
new file mode 100644 (file)
index 0000000..577f1d4
--- /dev/null
@@ -0,0 +1,216 @@
+#include <vector>
+#include <X11/Xatom.h>
+#include <X11/Xutil.h>
+#ifdef WITH_XF86VIDMODE
+#include <X11/extensions/xf86vmode.h>
+#endif
+#include <msp/core/systemerror.h>
+#include "display_private.h"
+#include "window.h"
+#include "window_private.h"
+
+using namespace std;
+
+namespace {
+
+Bool match_event_type(Display *, XEvent *event, XPointer arg)
+{
+       return event->type==*reinterpret_cast<int *>(arg);
+}
+
+}
+
+namespace Msp {
+namespace Graphics {
+
+void Window::platform_init()
+{
+       DisplayHandle dpy = display.get_private().display;
+
+       priv->wm_delete_window = XInternAtom(dpy, "WM_DELETE_WINDOW", true);
+       priv->invisible_cursor = 0;
+
+       XSetWindowAttributes attr;
+       attr.override_redirect = options.fullscreen;
+       attr.event_mask = ButtonPressMask|ButtonReleaseMask|PointerMotionMask|KeyPressMask|KeyReleaseMask|StructureNotifyMask|EnterWindowMask;
+
+       priv->window = XCreateWindow(dpy,
+               DefaultRootWindow(dpy),
+               0, 0,
+               options.width, options.height,
+               0,
+               CopyFromParent,
+               InputOutput,
+               CopyFromParent,
+               CWOverrideRedirect|CWEventMask, &attr);
+
+       XSetWMProtocols(dpy, priv->window, &priv->wm_delete_window, 1);
+
+       if(!options.resizable)
+       {
+               XSizeHints hints;
+               hints.flags = PMinSize|PMaxSize;
+               hints.min_width=hints.max_width = options.width;
+               hints.min_height=hints.max_height = options.height;
+               XSetWMNormalHints(dpy, priv->window, &hints);
+       }
+}
+
+void Window::platform_cleanup()
+{
+       if(priv->window)
+               XDestroyWindow(display.get_private().display, priv->window);
+
+       if(priv->invisible_cursor)
+               XFreeCursor(display.get_private().display, priv->invisible_cursor);
+}
+
+void Window::set_title(const string &title)
+{
+       vector<unsigned char> buf(title.begin(), title.end());
+       XTextProperty prop;
+       prop.value = &buf[0];
+       prop.encoding = XA_STRING;
+       prop.format = 8;
+       prop.nitems = title.size();
+       XSetWMName(display.get_private().display, priv->window, &prop);
+       display.check_error();
+}
+
+void Window::platform_reconfigure(bool fullscreen_changed)
+{
+       DisplayHandle dpy = display.get_private().display;
+
+       bool was_visible = visible;
+       if(fullscreen_changed)
+       {
+               if(was_visible)
+               {
+                       hide();
+
+                       // Wait for the window to be unmapped.  This makes window managers happy.
+                       XEvent ev;
+                       int ev_type = UnmapNotify;
+                       XPeekIfEvent(dpy, &ev, match_event_type, reinterpret_cast<char *>(&ev_type));
+               }
+
+               XSetWindowAttributes attr;
+               attr.override_redirect = options.fullscreen;
+               XChangeWindowAttributes(dpy, priv->window, CWOverrideRedirect, &attr);
+       }
+
+       XSizeHints hints;
+       if(options.resizable)
+               hints.flags = 0;
+       else
+       {
+               hints.flags = PMinSize|PMaxSize;
+               hints.min_width = hints.max_width = options.width;
+               hints.min_height = hints.max_height = options.height;
+       }
+       XSetWMNormalHints(dpy, priv->window, &hints);
+
+       if(options.fullscreen)
+               XMoveResizeWindow(dpy, priv->window, 0, 0, options.width, options.height);
+       else
+               XResizeWindow(dpy, priv->window, options.width, options.height);
+
+       if(fullscreen_changed && was_visible)
+               show();
+}
+
+void Window::show_cursor(bool s)
+{
+       DisplayHandle dpy = display.get_private().display;
+
+       if(s)
+               XUndefineCursor(dpy, priv->window);
+       else
+       {
+               if(!priv->invisible_cursor)
+               {
+                       int screen = DefaultScreen(dpy);
+
+                       Pixmap pm = XCreatePixmap(dpy, priv->window, 1, 1, 1);
+                       GC gc = XCreateGC(dpy, pm, 0, 0);
+                       XSetFunction(dpy, gc, GXclear);
+                       XDrawPoint(dpy, pm, gc, 0, 0);
+                       XFreeGC(dpy, gc);
+
+                       XColor black;
+                       black.pixel = BlackPixel(dpy, screen);
+                       XQueryColor(dpy, DefaultColormap(dpy, screen), &black);
+
+                       priv->invisible_cursor = XCreatePixmapCursor(dpy, pm, pm, &black, &black, 0, 0);
+
+                       XFreePixmap(dpy, pm);
+               }
+               XDefineCursor(dpy, priv->window, priv->invisible_cursor);
+       }
+}
+
+void Window::warp_pointer(int x, int y)
+{
+       XWarpPointer(display.get_private().display, None, priv->window, 0, 0, 0, 0, x, y);
+}
+
+void Window::platform_show()
+{
+       XMapRaised(display.get_private().display, priv->window);
+}
+
+void Window::platform_hide()
+{
+       XUnmapWindow(display.get_private().display, priv->window);
+}
+
+bool Window::event(const Event &evnt)
+{
+       const XEvent &ev = evnt.xevent;
+       switch(ev.type)
+       {
+       case ButtonPress:
+       case ButtonRelease:
+       case MotionNotify:
+       case KeyPress:
+       case KeyRelease:
+               signal_input_event.emit(evnt);
+               break;
+       case ConfigureNotify:
+               if((ev.xconfigure.width==static_cast<int>(options.width) && ev.xconfigure.height==static_cast<int>(options.height)) == resizing)
+               {
+                       options.width = ev.xconfigure.width;
+                       options.height = ev.xconfigure.height;
+                       resizing = false;
+                       signal_resize.emit(options.width, options.height);
+               }
+#ifdef WITH_XF86VIDMODE
+               if(options.fullscreen)
+               {
+                       DisplayHandle dpy = display.get_private().display;
+                       int screen = DefaultScreen(dpy);
+                       XF86VidModeSetViewPort(dpy, screen, ev.xconfigure.x, ev.xconfigure.y);
+               }
+#endif
+               break;
+       case ClientMessage:
+               if(ev.xclient.data.l[0]==static_cast<long>(priv->wm_delete_window))
+                       signal_close.emit();
+               break;
+       case EnterNotify:
+               if(options.fullscreen)
+                       XSetInputFocus(display.get_private().display, priv->window, RevertToParent, CurrentTime);
+               break;
+       case MapNotify:
+               if(options.fullscreen)
+                       XGrabPointer(display.get_private().display, priv->window, true, None, GrabModeAsync, GrabModeAsync, priv->window, None, CurrentTime);
+               break;
+       default:
+               return false;
+       }
+
+       return true;
+}
+
+} // namespace Graphics
+} // namespace Msp