X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fgraphics%2Fx11%2Fwindow.cpp;fp=source%2Fgraphics%2Fx11%2Fwindow.cpp;h=577f1d42d65f41af62b08d10c9d57f23167dbc12;hb=1aca77b93853ee127ac3bbf6886f7f04920542ef;hp=0000000000000000000000000000000000000000;hpb=4464dd5d973c47f6d7a7c352a90bd88cdb717cd2;p=libs%2Fgui.git diff --git a/source/graphics/x11/window.cpp b/source/graphics/x11/window.cpp new file mode 100644 index 0000000..577f1d4 --- /dev/null +++ b/source/graphics/x11/window.cpp @@ -0,0 +1,216 @@ +#include +#include +#include +#ifdef WITH_XF86VIDMODE +#include +#endif +#include +#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(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 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(&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(options.width) && ev.xconfigure.height==static_cast(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(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