X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fgbase%2Fwindow.cpp;h=fbcbd519f99dbe01a49f70490b4f6de259d6c87b;hb=dce7552c5e2f64fcf5f58b0c934bb4a01f6cbcf7;hp=b9e3fa49790df373fd08b2420b5d908f6dced860;hpb=8f8480438244fd04058049ace22071a8e2e0b85c;p=libs%2Fgui.git diff --git a/source/gbase/window.cpp b/source/gbase/window.cpp index b9e3fa4..fbcbd51 100644 --- a/source/gbase/window.cpp +++ b/source/gbase/window.cpp @@ -1,14 +1,10 @@ -/* $Id$ - -This file is part of libmspgbase -Copyright © 2007-2008 Mikko Rasa, Mikkosoft Productions -Distributed under the LGPL -*/ - #include #ifndef WIN32 #include #include +#ifdef WITH_XF86VIDMODE +#include +#endif #else #include #endif @@ -27,16 +23,16 @@ LRESULT CALLBACK wndproc_(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { if(msg==WM_CREATE) { - CREATESTRUCT *cs=reinterpret_cast(lparam); + 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 *wnd = reinterpret_cast(GetWindowLong(hwnd, 0)); Msp::Graphics::Window::Event ev; - ev.msg=msg; - ev.wparam=wparam; - ev.lparam=lparam; + ev.msg = msg; + ev.wparam = wparam; + ev.lparam = lparam; if(wnd && wnd->event(ev)) return 0; } @@ -46,7 +42,7 @@ LRESULT CALLBACK wndproc_(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) #else Bool match_event_type(Display *, XEvent *event, XPointer arg) { - return event->type==reinterpret_cast(arg); + return event->type==*reinterpret_cast(arg); } #endif @@ -66,9 +62,9 @@ WindowOptions::WindowOptions(): Window::Window(Display &dpy, unsigned w, unsigned h, bool fs): display(dpy) { - options.width=w; - options.height=h; - options.fullscreen=fs; + options.width = w; + options.height = h; + options.fullscreen = fs; init(); } @@ -80,6 +76,98 @@ Window::Window(Display &dpy, const WindowOptions &opts): init(); } +void Window::init() +{ + visible = false; + kbd_autorepeat = true; + resizing = false; + priv = new Private; + +#ifdef WIN32 + static bool wndclass_created = false; + + if(!wndclass_created) + { + WNDCLASSEX wndcl; + + wndcl.cbSize = sizeof(WNDCLASSEX); + wndcl.style = 0; + wndcl.lpfnWndProc = &wndproc_; + wndcl.cbClsExtra = 0; + wndcl.cbWndExtra = sizeof(Window *); + wndcl.hInstance = reinterpret_cast(Application::get_data()); + wndcl.hIcon = 0; + wndcl.hCursor = LoadCursor(0, IDC_ARROW); + wndcl.hbrBackground = 0; + wndcl.lpszMenuName = 0; + wndcl.lpszClassName = "mspgbase"; + wndcl.hIconSm = 0; + + if(!RegisterClassEx(&wndcl)) + throw Exception("Couldn't register window class"); + + wndclass_created = true; + } + + RECT rect; + 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); + + priv->window = CreateWindowEx(exstyle, + "mspgbase", + "Window", + style, + CW_USEDEFAULT, CW_USEDEFAULT, + rect.right-rect.left, rect.bottom-rect.top, + 0, + 0, + reinterpret_cast(Application::get_data()), + this); + if(!priv->window) + throw Exception("CreateWindowEx failed"); + +#else + ::Display *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); + } + +#endif + + display.add_window(*this); + display.check_error(); +} + Window::~Window() { if(priv->window) @@ -96,6 +184,8 @@ Window::~Window() if(options.fullscreen) display.restore_mode(); + + delete priv; } void Window::set_title(const string &title) @@ -105,10 +195,10 @@ void Window::set_title(const string &title) #else vector buf(title.begin(), title.end()); XTextProperty prop; - prop.value=&buf[0]; - prop.encoding=XA_STRING; - prop.format=8; - prop.nitems=title.size(); + 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(); #endif @@ -116,18 +206,19 @@ void Window::set_title(const string &title) void Window::reconfigure(const WindowOptions &opts) { - bool fullscreen_changed=(opts.fullscreen!=options.fullscreen); + bool fullscreen_changed = (opts.fullscreen!=options.fullscreen); + resizing = (opts.width!=options.width || opts.height!=options.height); - options=opts; + options = opts; #ifdef WIN32 RECT rect; SetRect(&rect, 0, 0, options.width, options.height); - int style=(options.fullscreen ? WS_POPUP : WS_OVERLAPPEDWINDOW); + int style = (options.fullscreen ? WS_POPUP : WS_OVERLAPPEDWINDOW); if(!options.resizable) - style&=~WS_THICKFRAME; - int exstyle=(options.fullscreen ? WS_EX_APPWINDOW : WS_EX_OVERLAPPEDWINDOW); + style &= ~WS_THICKFRAME; + int exstyle = (options.fullscreen ? WS_EX_APPWINDOW : WS_EX_OVERLAPPEDWINDOW); AdjustWindowRectEx(&rect, style, false, exstyle); if(fullscreen_changed) @@ -143,30 +234,34 @@ void Window::reconfigure(const WindowOptions &opts) 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; + ::Display *dpy = display.get_private().display; + bool was_visible = visible; if(fullscreen_changed) { - hide(); + if(was_visible) + { + hide(); - // Wait for the window to be unmapped. This makes window managers happy. - XEvent ev; - XPeekIfEvent(dpy, &ev, match_event_type, reinterpret_cast(UnmapNotify)); + // 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; + attr.override_redirect = options.fullscreen; XChangeWindowAttributes(dpy, priv->window, CWOverrideRedirect, &attr); - show(); } XSizeHints hints; if(options.resizable) - hints.flags=0; + hints.flags = 0; else { - hints.flags=PMinSize|PMaxSize; - hints.min_width=hints.max_width=options.width; - hints.min_height=hints.max_height=options.height; + 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); @@ -174,12 +269,26 @@ void Window::reconfigure(const WindowOptions &opts) XMoveResizeWindow(dpy, priv->window, 0, 0, options.width, options.height); else XResizeWindow(dpy, priv->window, options.width, options.height); + + if(fullscreen_changed) + { + if(was_visible) + show(); + } #endif - if(options.fullscreen) - display.set_mode(VideoMode(options.width, options.height)); - else if(fullscreen_changed) - display.restore_mode(); + if(visible) + { + if(options.fullscreen) + display.set_mode(VideoMode(options.width, options.height)); + else if(fullscreen_changed) + display.restore_mode(); + } +} + +void Window::set_keyboard_autorepeat(bool r) +{ + kbd_autorepeat = r; } void Window::show_cursor(bool s) @@ -187,7 +296,7 @@ void Window::show_cursor(bool s) #ifdef WIN32 ShowCursor(s); #else - ::Display *dpy=display.get_private().display; + ::Display *dpy = display.get_private().display; if(s) XUndefineCursor(dpy, priv->window); @@ -195,19 +304,19 @@ void Window::show_cursor(bool s) { if(!priv->invisible_cursor) { - int screen=DefaultScreen(dpy); + int screen = DefaultScreen(dpy); - Pixmap pm=XCreatePixmap(dpy, priv->window, 1, 1, 1); - GC gc=XCreateGC(dpy, pm, 0, 0); + 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); + black.pixel = BlackPixel(dpy, screen); XQueryColor(dpy, DefaultColormap(dpy, screen), &black); - priv->invisible_cursor=XCreatePixmapCursor(dpy, pm, pm, &black, &black, 0, 0); + priv->invisible_cursor = XCreatePixmapCursor(dpy, pm, pm, &black, &black, 0, 0); XFreePixmap(dpy, pm); } @@ -216,6 +325,16 @@ void Window::show_cursor(bool s) #endif } +void Window::warp_pointer(int x, int y) +{ +#ifndef WIN32 + XWarpPointer(display.get_private().display, None, priv->window, 0, 0, 0, 0, x, y); +#else + (void)x; + (void)y; +#endif +} + void Window::show() { #ifdef WIN32 @@ -223,6 +342,15 @@ void Window::show() #else XMapRaised(display.get_private().display, priv->window); #endif + visible = true; + + if(options.fullscreen) + { + display.set_mode(VideoMode(options.width, options.height)); +#ifndef WIN32 + XWarpPointer(display.get_private().display, None, priv->window, 0, 0, 0, 0, options.width/2, options.height/2); +#endif + } } void Window::hide() @@ -232,110 +360,17 @@ void Window::hide() #else XUnmapWindow(display.get_private().display, priv->window); #endif -} - -void Window::init() -{ - priv=new Private; - -#ifdef WIN32 - static bool wndclass_created=false; - - if(!wndclass_created) - { - WNDCLASSEX wndcl; - - wndcl.cbSize=sizeof(WNDCLASSEX); - wndcl.style=0; - wndcl.lpfnWndProc=&wndproc_; - wndcl.cbClsExtra=0; - wndcl.cbWndExtra=sizeof(Window *); - wndcl.hInstance=reinterpret_cast(Application::get_data()); - wndcl.hIcon=0; - wndcl.hCursor=LoadCursor(0, IDC_ARROW); - wndcl.hbrBackground=0; - wndcl.lpszMenuName=0; - wndcl.lpszClassName="mspgbase"; - wndcl.hIconSm=0; - - if(!RegisterClassEx(&wndcl)) - throw Exception("Couldn't register window class"); - - wndclass_created=true; - } - - RECT rect; - 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); - - priv->window=CreateWindowEx(exstyle, - "mspgbase", - "Window", - style, - CW_USEDEFAULT, CW_USEDEFAULT, - rect.right-rect.left, rect.bottom-rect.top, - 0, - 0, - reinterpret_cast(Application::get_data()), - this); - if(!priv->window) - throw Exception("CreateWindowEx failed"); + visible = false; if(options.fullscreen) - display.set_mode(VideoMode(options.width, options.height)); - -#else - ::Display *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); - } - - if(options.fullscreen) - { - display.set_mode(VideoMode(options.width, options.height)); - XWarpPointer(dpy, None, priv->window, 0, 0, 0, 0, options.width/2, options.height/2); - } -#endif - - display.add_window(*this); - display.check_error(); + display.restore_mode(); } bool Window::event(const Event &evnt) { #ifdef WIN32 - WPARAM wp=evnt.wparam; - LPARAM lp=evnt.lparam; + WPARAM wp = evnt.wparam; + LPARAM lp = evnt.lparam; switch(evnt.msg) { case WM_KEYDOWN: @@ -362,12 +397,19 @@ bool Window::event(const Event &evnt) case WM_RBUTTONUP: signal_button_release.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 3, 0); break; + case WM_MOUSEWHEEL: + { + unsigned btn = (HIWORD(wp)&0x8000) ? 5 : 4; + signal_button_press.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), btn, 0); + signal_button_release.emit(GET_X_LPARAM(lp), GET_Y_LPARAM(lp), btn, 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); + options.width = LOWORD(lp); + options.height = HIWORD(lp); signal_resize.emit(options.width, options.height); break; case WM_CLOSE: @@ -377,7 +419,7 @@ bool Window::event(const Event &evnt) return false; } #else - const XEvent &ev=evnt.xevent; + const XEvent &ev = evnt.xevent; switch(ev.type) { case ButtonPress: @@ -401,9 +443,21 @@ bool Window::event(const Event &evnt) signal_key_release.emit(XKeycodeToKeysym(display.get_private().display, ev.xkey.keycode, 0), ev.xkey.state); break; case ConfigureNotify: - options.width=ev.xconfigure.width; - options.height=ev.xconfigure.height; - signal_resize.emit(options.width, options.height); + 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) + { + ::Display *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))