X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fgbase%2Fwindow.cpp;h=b9e3fa49790df373fd08b2420b5d908f6dced860;hb=39ec5cd588bf8b49717033d841be689df68537a3;hp=da877e966679b8ffd8f66b362a9f8feec2b6e695;hpb=999ca92aa9ee10585c0b2094d84364159253982f;p=libs%2Fgui.git diff --git a/source/gbase/window.cpp b/source/gbase/window.cpp index da877e9..b9e3fa4 100644 --- a/source/gbase/window.cpp +++ b/source/gbase/window.cpp @@ -1,7 +1,7 @@ /* $Id$ This file is part of libmspgbase -Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Copyright © 2007-2008 Mikko Rasa, Mikkosoft Productions Distributed under the LGPL */ @@ -16,10 +16,41 @@ Distributed under the LGPL #include #include "display.h" #include "window.h" +#include "display_priv.h" using namespace std; -#include +namespace { + +#ifdef WIN32 +LRESULT CALLBACK wndproc_(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + if(msg==WM_CREATE) + { + CREATESTRUCT *cs=reinterpret_cast(lparam); + SetWindowLong(hwnd, 0, reinterpret_cast(cs->lpCreateParams)); + } + else + { + Msp::Graphics::Window *wnd=reinterpret_cast(GetWindowLong(hwnd, 0)); + Msp::Graphics::Window::Event ev; + ev.msg=msg; + ev.wparam=wparam; + ev.lparam=lparam; + if(wnd && wnd->event(ev)) + return 0; + } + + return DefWindowProc(hwnd, msg, wparam, lparam); +} +#else +Bool match_event_type(Display *, XEvent *event, XPointer arg) +{ + return event->type==reinterpret_cast(arg); +} +#endif + +} namespace Msp { namespace Graphics { @@ -51,14 +82,17 @@ Window::Window(Display &dpy, const WindowOptions &opts): Window::~Window() { - if(window) + if(priv->window) #ifdef WIN32 - CloseWindow(window); + CloseWindow(priv->window); #else - XDestroyWindow(display.get_display(), window); + XDestroyWindow(display.get_private().display, priv->window); + + if(priv->invisible_cursor) + XFreeCursor(display.get_private().display, priv->invisible_cursor); #endif - display.remove_window(this); + display.remove_window(*this); if(options.fullscreen) display.restore_mode(); @@ -67,7 +101,7 @@ Window::~Window() void Window::set_title(const string &title) { #ifdef WIN32 - SetWindowText(window, title.c_str()); + SetWindowText(priv->window, title.c_str()); #else vector buf(title.begin(), title.end()); XTextProperty prop; @@ -75,7 +109,7 @@ void Window::set_title(const string &title) prop.encoding=XA_STRING; prop.format=8; prop.nitems=title.size(); - XSetWMName(display.get_display(), window, &prop); + XSetWMName(display.get_private().display, priv->window, &prop); display.check_error(); #endif } @@ -87,53 +121,123 @@ void Window::reconfigure(const WindowOptions &opts) options=opts; #ifdef WIN32 - // XXX Preserve position - MoveWindow(window, 0, 0, options.width, options.height, false); + RECT rect; + SetRect(&rect, 0, 0, options.width, options.height); - (void)fullscreen_changed; -#else - ::Display *dpy=display.get_display(); + int style=(options.fullscreen ? WS_POPUP : WS_OVERLAPPEDWINDOW); + if(!options.resizable) + style&=~WS_THICKFRAME; + int exstyle=(options.fullscreen ? WS_EX_APPWINDOW : WS_EX_OVERLAPPEDWINDOW); + AdjustWindowRectEx(&rect, style, false, exstyle); + + if(fullscreen_changed) + { + hide(); + SetWindowLong(priv->window, GWL_EXSTYLE, exstyle); + SetWindowLong(priv->window, GWL_STYLE, style); + show(); + } - XMoveResizeWindow(dpy, window, 0, 0, options.width, options.height); + if(options.fullscreen) + SetWindowPos(priv->window, 0, 0, 0, rect.right-rect.left, rect.bottom-rect.top, SWP_NOZORDER); + else + SetWindowPos(priv->window, 0, 0, 0, rect.right-rect.left, rect.bottom-rect.top, SWP_NOMOVE|SWP_NOZORDER); +#else + ::Display *dpy=display.get_private().display; if(fullscreen_changed) { hide(); + + // Wait for the window to be unmapped. This makes window managers happy. + XEvent ev; + XPeekIfEvent(dpy, &ev, match_event_type, reinterpret_cast(UnmapNotify)); + XSetWindowAttributes attr; attr.override_redirect=options.fullscreen; - XChangeWindowAttributes(dpy, window, CWOverrideRedirect, &attr); + XChangeWindowAttributes(dpy, priv->window, CWOverrideRedirect, &attr); show(); } + 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); +#endif + if(options.fullscreen) display.set_mode(VideoMode(options.width, options.height)); else if(fullscreen_changed) display.restore_mode(); +} + +void Window::show_cursor(bool s) +{ +#ifdef WIN32 + ShowCursor(s); +#else + ::Display *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); + } #endif } void Window::show() { #ifdef WIN32 - ShowWindow(window, SW_SHOWNORMAL); + ShowWindow(priv->window, SW_SHOWNORMAL); #else - XMapRaised(display.get_display(), window); - display.check_error(); + XMapRaised(display.get_private().display, priv->window); #endif } void Window::hide() { #ifdef WIN32 - ShowWindow(window, SW_HIDE); + ShowWindow(priv->window, SW_HIDE); #else - XUnmapWindow(display.get_display(), window); - display.check_error(); + XUnmapWindow(display.get_private().display, priv->window); #endif } void Window::init() { + priv=new Private; + #ifdef WIN32 static bool wndclass_created=false; @@ -161,35 +265,41 @@ void Window::init() } RECT rect; - rect.left=0; - rect.top=0; - rect.right=options.width; - rect.bottom=options.height; - AdjustWindowRectEx(&rect, WS_OVERLAPPEDWINDOW, false, WS_EX_OVERLAPPEDWINDOW); + SetRect(&rect, 0, 0, options.width, options.height); + + int style=(options.fullscreen ? WS_POPUP : WS_OVERLAPPEDWINDOW); + if(!options.resizable) + style&=~WS_THICKFRAME; + int exstyle=(options.fullscreen ? WS_EX_APPWINDOW : WS_EX_OVERLAPPEDWINDOW); + AdjustWindowRectEx(&rect, style, false, exstyle); - window=CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, + priv->window=CreateWindowEx(exstyle, "mspgbase", "Window", - WS_OVERLAPPEDWINDOW, + style, CW_USEDEFAULT, CW_USEDEFAULT, rect.right-rect.left, rect.bottom-rect.top, 0, 0, reinterpret_cast(Application::get_data()), this); - if(!window) + if(!priv->window) throw Exception("CreateWindowEx failed"); + if(options.fullscreen) + display.set_mode(VideoMode(options.width, options.height)); + #else - ::Display *dpy=display.get_display(); + ::Display *dpy=display.get_private().display; - wm_delete_window=XInternAtom(dpy, "WM_DELETE_WINDOW", true); + 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; - window=XCreateWindow(dpy, + priv->window=XCreateWindow(dpy, DefaultRootWindow(dpy), 0, 0, options.width, options.height, @@ -199,22 +309,75 @@ void Window::init() CopyFromParent, CWOverrideRedirect|CWEventMask, &attr); - XSetWMProtocols(dpy, window, &wm_delete_window, 1); + 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); + } if(options.fullscreen) { display.set_mode(VideoMode(options.width, options.height)); - XWarpPointer(dpy, None, window, 0, 0, 0, 0, options.width/2, options.height/2); + XWarpPointer(dpy, None, priv->window, 0, 0, 0, 0, options.width/2, options.height/2); } #endif - display.add_window(this); + display.add_window(*this); display.check_error(); } -#ifndef WIN32 -void Window::event(const XEvent &ev) +bool Window::event(const Event &evnt) { +#ifdef WIN32 + WPARAM wp=evnt.wparam; + LPARAM lp=evnt.lparam; + switch(evnt.msg) + { + case WM_KEYDOWN: + signal_key_press.emit(wp, 0, wp); + break; + case WM_KEYUP: + signal_key_release.emit(wp, 0); + break; + case WM_LBUTTONDOWN: + signal_button_press.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 1, 0); + break; + case WM_LBUTTONUP: + signal_button_release.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 1, 0); + break; + case WM_MBUTTONDOWN: + signal_button_press.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 2, 0); + break; + case WM_MBUTTONUP: + signal_button_release.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 2, 0); + break; + case WM_RBUTTONDOWN: + signal_button_press.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 3, 0); + break; + case WM_RBUTTONUP: + signal_button_release.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 3, 0); + break; + case WM_MOUSEMOVE: + signal_pointer_motion.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp)); + break; + case WM_SIZE: + options.width=LOWORD(lp); + options.height=HIWORD(lp); + signal_resize.emit(options.width, options.height); + break; + case WM_CLOSE: + signal_close.emit(); + break; + default: + return false; + } +#else + const XEvent &ev=evnt.xevent; switch(ev.type) { case ButtonPress: @@ -231,11 +394,11 @@ void Window::event(const XEvent &ev) char buf[16]; XLookupString(const_cast(&ev.xkey), buf, sizeof(buf), 0, 0); // XXX Handle the result according to locale - signal_key_press.emit(ev.xkey.keycode, ev.xkey.state, buf[0]); + signal_key_press.emit(XKeycodeToKeysym(display.get_private().display, ev.xkey.keycode, 0), ev.xkey.state, buf[0]); } break; case KeyRelease: - signal_key_release.emit(ev.xkey.keycode, ev.xkey.state); + signal_key_release.emit(XKeycodeToKeysym(display.get_private().display, ev.xkey.keycode, 0), ev.xkey.state); break; case ConfigureNotify: options.width=ev.xconfigure.width; @@ -243,80 +406,23 @@ void Window::event(const XEvent &ev) signal_resize.emit(options.width, options.height); break; case ClientMessage: - if(ev.xclient.data.l[0]==static_cast(wm_delete_window)) + if(ev.xclient.data.l[0]==static_cast(priv->wm_delete_window)) signal_close.emit(); break; case EnterNotify: - XSetInputFocus(display.get_display(), window, RevertToParent, CurrentTime); + if(options.fullscreen) + XSetInputFocus(display.get_private().display, priv->window, RevertToParent, CurrentTime); break; case MapNotify: if(options.fullscreen) - XGrabPointer(display.get_display(), window, true, None, GrabModeAsync, GrabModeAsync, window, None, CurrentTime); - break; - default:; - } -} -#endif - -#ifdef WIN32 -int Window::wndproc(UINT msg, WPARAM wp, LPARAM lp) -{ - switch(msg) - { - case WM_KEYDOWN: - signal_key_press.emit((lp>>16)&0x1FF, 0, wp); - break; - case WM_KEYUP: - signal_key_release.emit((lp>>16)&0x1FF, 0); - break; - case WM_LBUTTONDOWN: - signal_button_press.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 1, 0); - break; - case WM_LBUTTONUP: - signal_button_release.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 1, 0); - break; - case WM_MBUTTONDOWN: - signal_button_press.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 2, 0); - break; - case WM_MBUTTONUP: - signal_button_release.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 2, 0); - break; - case WM_RBUTTONDOWN: - signal_button_press.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 3, 0); - break; - case WM_RBUTTONUP: - signal_button_release.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 3, 0); - break; - case WM_MOUSEMOVE: - signal_pointer_motion.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp)); - break; - case WM_CLOSE: - signal_close.emit(); + XGrabPointer(display.get_private().display, priv->window, true, None, GrabModeAsync, GrabModeAsync, priv->window, None, CurrentTime); break; default: - return 0; + return false; } - - return 1; -} - -LRESULT CALLBACK Window::wndproc_(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) -{ - if(msg==WM_CREATE) - { - CREATESTRUCT *cs=reinterpret_cast(lparam); - SetWindowLong(hwnd, 0, reinterpret_cast(cs->lpCreateParams)); - } - else - { - Window *wnd=reinterpret_cast(GetWindowLong(hwnd, 0)); - if(wnd && wnd->wndproc(msg, wparam, lparam)) - return 0; - } - - return DefWindowProc(hwnd, msg, wparam, lparam); -} #endif + return true; +} } // namespace Graphics } // namespace Msp