diff options
Diffstat (limited to 'plugingui/nativewindow_x11.cc')
-rw-r--r-- | plugingui/nativewindow_x11.cc | 672 |
1 files changed, 405 insertions, 267 deletions
diff --git a/plugingui/nativewindow_x11.cc b/plugingui/nativewindow_x11.cc index cb6cf73..a0316b9 100644 --- a/plugingui/nativewindow_x11.cc +++ b/plugingui/nativewindow_x11.cc @@ -26,105 +26,152 @@ */ #include "nativewindow_x11.h" -#ifdef X11 #include <X11/Xutil.h> #include <stdlib.h> +#include <hugin.hpp> + #include "window.h" -GUI::NativeWindowX11::NativeWindowX11(GUI::Window *window) - : GUI::NativeWindow() +namespace GUI { + +NativeWindowX11::NativeWindowX11(Window& window) + : buffer(nullptr) + , window(window) { - display = XOpenDisplay(NULL); - - this->window = window; - buffer = NULL; - - // Get some colors - int blackColor = BlackPixel(display, DefaultScreen(display)); - - ::Window w = DefaultRootWindow(display); - - // Create the window - xwindow = XCreateSimpleWindow(display, - w, - window->x(), window->y(), - window->width(), window->height(), - 0, - blackColor, blackColor); - - XSelectInput(display, xwindow, - StructureNotifyMask | - PointerMotionMask | - ButtonPressMask | - ButtonReleaseMask | - KeyPressMask | - KeyReleaseMask| - ExposureMask | - StructureNotifyMask | - SubstructureNotifyMask); - - // register interest in the delete window message - wmDeleteMessage = XInternAtom(display, "WM_DELETE_WINDOW", false); - XSetWMProtocols(display, xwindow, &wmDeleteMessage, 1); - - // "Map" the window (that is, make it appear on the screen) - XMapWindow(display, xwindow); - - // Create a "Graphics Context" - gc = XCreateGC(display, xwindow, 0, NULL); + auto status = XInitThreads(); + if(status) + { + ERR(X11, "Could not initialise threaded Xlib calls (XInitThreads)"); + } + + display = XOpenDisplay(nullptr); + if(display == nullptr) + { + ERR(X11, "XOpenDisplay failed"); + return; + } + + screen = DefaultScreen(display); + + // Get some colors + int blackColor = BlackPixel(display, screen); + + ::Window rootWindow = DefaultRootWindow(display); + + // Create the window + unsigned long border = 0; + xwindow = XCreateSimpleWindow(display, + rootWindow, + window.x(), window.y(), + window.width(), window.height(), + border, + blackColor, blackColor); + + long mask = (StructureNotifyMask | + PointerMotionMask | + ButtonPressMask | + ButtonReleaseMask | + KeyPressMask | + KeyReleaseMask| + ExposureMask | + StructureNotifyMask | + SubstructureNotifyMask); + XSelectInput(display, xwindow, mask); + + // Register the delete window message: + wmDeleteMessage = XInternAtom(display, "WM_DELETE_WINDOW", false); + + Atom protocols[] = { wmDeleteMessage }; + int count = sizeof(protocols)/sizeof(Atom); + XSetWMProtocols(display, xwindow, protocols, count); + + // "Map" the window (that is, make it appear on the screen) + XMapWindow(display, xwindow); + + // Create a "Graphics Context" + gc = XCreateGC(display, xwindow, 0, nullptr); } -GUI::NativeWindowX11::~NativeWindowX11() +NativeWindowX11::~NativeWindowX11() { - XDestroyWindow(display, xwindow); - //widgets.erase(window); - XCloseDisplay(display); + if(display == nullptr) + { + return; + } + + XDestroyWindow(display, xwindow); + XCloseDisplay(display); } -void GUI::NativeWindowX11::setFixedSize(int width, int height) +void NativeWindowX11::setFixedSize(int width, int height) { - resize(width, height); - - XSizeHints *size_hints; - size_hints = XAllocSizeHints(); - - if(size_hints == NULL) { - //fprintf(stderr,"XMallocSizeHints() failed\n"); - //exit(1); - return; - } - - size_hints->flags = USPosition | PMinSize | PMaxSize; - size_hints->min_width = size_hints->max_width = width; - size_hints->min_height = size_hints->max_height = height; - /* - size_hints->min_aspect.x = window->width()/window->height(); - size_hints->max_aspect.x = window->width()/window->height(); - size_hints->min_aspect.y = window->width()/window->height(); - size_hints->max_aspect.y = size_hints->min_aspect.y; - */ - XSetWMNormalHints(display, xwindow, size_hints); + if(display == nullptr) + { + return; + } + + resize(width, height); + + XSizeHints* size_hints; + size_hints = XAllocSizeHints(); + + if(size_hints == nullptr) + { + ERR(X11,"XMallocSizeHints() failed"); + return; + } + + size_hints->flags = USPosition | PMinSize | PMaxSize; + size_hints->min_width = size_hints->max_width = width; + size_hints->min_height = size_hints->max_height = height; + + //size_hints->min_aspect.x = (float)window.width()/(float)window.height(); + //size_hints->max_aspect.x = (float)window.width()/(float)window.height(); + //size_hints->min_aspect.y = (float)window.width()/(float)window.height(); + //size_hints->max_aspect.y = size_hints->min_aspect.y; + + XSetWMNormalHints(display, xwindow, size_hints); } -void GUI::NativeWindowX11::resize(int width, int height) +void NativeWindowX11::resize(int width, int height) { - XResizeWindow(display, xwindow, width, height); + if(display == nullptr) + { + return; + } + + XResizeWindow(display, xwindow, width, height); } -void GUI::NativeWindowX11::move(int x, int y) +void NativeWindowX11::move(int x, int y) { - XMoveWindow(display, xwindow, x, y); + if(display == nullptr) + { + return; + } + + XMoveWindow(display, xwindow, x, y); } -void GUI::NativeWindowX11::show() +void NativeWindowX11::show() { - XMapWindow(display, xwindow); + if(display == nullptr) + { + return; + } + + XMapWindow(display, xwindow); } -void GUI::NativeWindowX11::hide() +void NativeWindowX11::hide() { - XUnmapWindow(display, xwindow); + if(display == nullptr) + { + return; + } + + XUnmapWindow(display, xwindow); } static int get_byte_order (void) @@ -135,254 +182,345 @@ static int get_byte_order (void) } order; order.s = 1; - if ((1 == order.c[0])) { + if((1 == order.c[0])) + { return LSBFirst; - } else { + } + else + { return MSBFirst; } } -static XImage *create_image_from_buffer(Display *dis, int screen, - unsigned char *buf, - int width, int height) +XImage* NativeWindowX11::createImageFromBuffer(unsigned char* buf, + int width, int height) { int depth; - XImage *img = NULL; - Visual *vis; + XImage* img = nullptr; + Visual* vis; double rRatio; double gRatio; double bRatio; - int outIndex = 0; + int outIndex = 0; int i; int numBufBytes = (3 * (width * height)); - - depth = DefaultDepth(dis, screen); - vis = DefaultVisual(dis, screen); + + depth = DefaultDepth(display, screen); + vis = DefaultVisual(display, screen); rRatio = vis->red_mask / 255.0; gRatio = vis->green_mask / 255.0; bRatio = vis->blue_mask / 255.0; - - if (depth >= 24) { + + if(depth >= 24) + { size_t numNewBufBytes = (4 * (width * height)); u_int32_t *newBuf = (u_int32_t *)malloc (numNewBufBytes); - - for (i = 0; i < numBufBytes; ++i) { + + for(i = 0; i < numBufBytes; ++i) + { unsigned int r, g, b; r = (buf[i] * rRatio); ++i; g = (buf[i] * gRatio); ++i; b = (buf[i] * bRatio); - - r &= vis->red_mask; - g &= vis->green_mask; - b &= vis->blue_mask; - - newBuf[outIndex] = r | g | b; - ++outIndex; - } - - img = XCreateImage (dis, - CopyFromParent, depth, - ZPixmap, 0, - (char *) newBuf, - width, height, - 32, 0 - ); - - } else if (depth >= 15) { - size_t numNewBufBytes = (2 * (width * height)); - u_int16_t *newBuf = (u_int16_t *)malloc (numNewBufBytes); - - for (i = 0; i < numBufBytes; ++i) { - unsigned int r, g, b; - r = (buf[i] * rRatio); - ++i; - g = (buf[i] * gRatio); - ++i; - b = (buf[i] * bRatio); - r &= vis->red_mask; g &= vis->green_mask; b &= vis->blue_mask; - + newBuf[outIndex] = r | g | b; ++outIndex; - } - - img = XCreateImage(dis, CopyFromParent, depth, ZPixmap, 0, (char *) newBuf, - width, height, 16, 0); - } else { - //fprintf (stderr, "This program does not support displays with a depth less than 15."); - return NULL; + } + + img = XCreateImage (display, + CopyFromParent, depth, + ZPixmap, 0, + (char*) newBuf, + width, height, + 32, 0); + } + else + { + if(depth >= 15) + { + size_t numNewBufBytes = (2 * (width * height)); + u_int16_t* newBuf = (u_int16_t*)malloc (numNewBufBytes); + + for(i = 0; i < numBufBytes; ++i) + { + unsigned int r, g, b; + + r = (buf[i] * rRatio); + ++i; + g = (buf[i] * gRatio); + ++i; + b = (buf[i] * bRatio); + + r &= vis->red_mask; + g &= vis->green_mask; + b &= vis->blue_mask; + + newBuf[outIndex] = r | g | b; + ++outIndex; + } + + img = XCreateImage(display, CopyFromParent, depth, ZPixmap, 0, + (char*)newBuf, width, height, 16, 0); + } + else + { + //fprintf (stderr, "This program does not support displays with a depth less than 15."); + return nullptr; + } } XInitImage (img); - /*Set the client's byte order, so that XPutImage knows what to do with the data.*/ - /*The default in a new X image is the server's format, which may not be what we want.*/ - if ((LSBFirst == get_byte_order ())) { + + // Set the client's byte order, so that XPutImage knows what + // to do with the data. + // The default in a new X image is the server's format, which + // may not be what we want. + if((LSBFirst == get_byte_order ())) + { img->byte_order = LSBFirst; - } else { + } + else + { img->byte_order = MSBFirst; } - - /*The bitmap_bit_order doesn't matter with ZPixmap images.*/ + + // The bitmap_bit_order doesn't matter with ZPixmap images. img->bitmap_bit_order = MSBFirst; return img; -} +} -void GUI::NativeWindowX11::handleBuffer() +void NativeWindowX11::handleBuffer() { - if(buffer) XDestroyImage(buffer); - buffer = - create_image_from_buffer(display, DefaultScreen(display), - window->wpixbuf.buf, - window->wpixbuf.width, - window->wpixbuf.height); + if(buffer) + { + XDestroyImage(buffer); + } + + buffer = createImageFromBuffer(window.wpixbuf.buf, + window.wpixbuf.width, + window.wpixbuf.height); } -void GUI::NativeWindowX11::redraw() +void NativeWindowX11::redraw() { - // http://stackoverflow.com/questions/6384987/load-image-onto-a-window-using-xlib - if(buffer == NULL) window->updateBuffer(); - XPutImage(display, xwindow, gc, buffer, 0, 0, 0, 0, - window->width(), window->height()); - XFlush(display); + if(display == nullptr) + { + return; + } + + if(buffer == nullptr) + { + window.updateBuffer(); + } + + XPutImage(display, xwindow, gc, buffer, 0, 0, 0, 0, + window.width(), window.height()); + XFlush(display); +} + +void NativeWindowX11::setCaption(const std::string &caption) +{ + if(display == nullptr) + { + return; + } + + XStoreName(display, xwindow, caption.c_str()); } -void GUI::NativeWindowX11::setCaption(const std::string &caption) +void NativeWindowX11::grabMouse(bool grab) { - XStoreName(display, xwindow, caption.c_str()); + (void)grab; + // Don't need to do anything on this platform... } -void GUI::NativeWindowX11::grabMouse(bool grab) +bool NativeWindowX11::hasEvent() { - (void)grab; - // Don't need to do anything on this platoform... + if(display == nullptr) + { + return false; + } + + return XPending(display); } -bool GUI::NativeWindowX11::hasEvent() +Event* NativeWindowX11::getNextEvent() { - return XPending(display); + if(display == nullptr) + { + return nullptr; + } + + XEvent xEvent; + XNextEvent(display, &xEvent); + return translateXMessage(xEvent); } -GUI::Event *GUI::NativeWindowX11::getNextEvent() +Event* NativeWindowX11::peekNextEvent() { - Event *event = NULL; - - XEvent xe; - XNextEvent(display, &xe); - - if(xe.type == MotionNotify) { - while(true) { // Hack to make sure only the last event is played. - if(!hasEvent()) break; - XEvent nxe; - XPeekEvent(display, &nxe); - if(nxe.type != MotionNotify) break; - XNextEvent(display, &xe); - } - - MouseMoveEvent *e = new MouseMoveEvent(); - e->window_id = xe.xmotion.window; - e->x = xe.xmotion.x; - e->y = xe.xmotion.y; - event = e; - } - - if(xe.type == Expose && xe.xexpose.count == 0) { - RepaintEvent *e = new RepaintEvent(); - e->window_id = xe.xexpose.window; - e->x = xe.xexpose.x; - e->y = xe.xexpose.y; - e->width = xe.xexpose.width; - e->height = xe.xexpose.height; - event = e; - } - - if(xe.type == ConfigureNotify) { - ResizeEvent *e = new ResizeEvent(); - e->window_id = xe.xconfigure.window; - // e->x = xe.xconfigure.x; - // e->y = xe.xconfigure.y; - e->width = xe.xconfigure.width; - e->height = xe.xconfigure.height; - event = e; - } - - if(xe.type == ButtonPress || xe.type == ButtonRelease) { - if(xe.xbutton.button == 4 || xe.xbutton.button == 5) { - int scroll = 1; - while(true) { // Hack to make sure only the last event is played. - if(!hasEvent()) break; - XEvent nxe; - XPeekEvent(display, &nxe); - if(nxe.type != ButtonPress && nxe.type != ButtonRelease) break; - scroll += 1; - XNextEvent(display, &xe); - } - ScrollEvent *e = new ScrollEvent(); - e->window_id = xe.xbutton.window; - e->x = xe.xbutton.x; - e->y = xe.xbutton.y; - e->delta = scroll * (xe.xbutton.button==4?-1:1); - event = e; - } else { - ButtonEvent *e = new ButtonEvent(); - e->window_id = xe.xbutton.window; - e->x = xe.xbutton.x; - e->y = xe.xbutton.y; - e->button = 0; - e->direction = xe.type == ButtonPress?1:-1; - e->doubleclick = - xe.type == ButtonPress && (xe.xbutton.time - last_click) < 200; - - if(xe.type == ButtonPress) last_click = xe.xbutton.time; - event = e; - } - } - - if(xe.type == KeyPress || xe.type == KeyRelease) { - //printf("key: %d\n", xe.xkey.keycode); - KeyEvent *e = new KeyEvent(); - e->window_id = xe.xkey.window; - - switch(xe.xkey.keycode) { - case 113: e->keycode = KeyEvent::KEY_LEFT; break; - case 114: e->keycode = KeyEvent::KEY_RIGHT; break; - case 111: e->keycode = KeyEvent::KEY_UP; break; - case 116: e->keycode = KeyEvent::KEY_DOWN; break; - case 119: e->keycode = KeyEvent::KEY_DELETE; break; - case 22: e->keycode = KeyEvent::KEY_BACKSPACE; break; - case 110: e->keycode = KeyEvent::KEY_HOME; break; - case 115: e->keycode = KeyEvent::KEY_END; break; - case 117: e->keycode = KeyEvent::KEY_PGDOWN; break; - case 112: e->keycode = KeyEvent::KEY_PGUP; break; - case 36: e->keycode = KeyEvent::KEY_ENTER; break; - default: e->keycode = KeyEvent::KEY_UNKNOWN; break; - } - - char buf[1024]; - int sz = XLookupString(&xe.xkey, buf, sizeof(buf), NULL, NULL); - if(sz && e->keycode == KeyEvent::KEY_UNKNOWN) { - e->keycode = KeyEvent::KEY_CHARACTER; - } - e->text.append(buf, sz); - - e->direction = xe.type == KeyPress?1:-1; - event = e; - } - - if(xe.type == ClientMessage && - (unsigned int)xe.xclient.data.l[0] == wmDeleteMessage) { - CloseEvent *e = new CloseEvent(); - event = e; - } - - return event; + if(display == nullptr) + { + return nullptr; + } + + XEvent peekXEvent; + XPeekEvent(display, &peekXEvent); + return translateXMessage(peekXEvent, true); } -#endif/*X11*/ + Event* NativeWindowX11::translateXMessage(XEvent& xevent, bool peek) +{ + Event* event = nullptr; + + switch(xevent.type) { + case MotionNotify: + { + auto mouseMoveEvent = new MouseMoveEvent(); + mouseMoveEvent->window_id = xevent.xmotion.window; + mouseMoveEvent->x = xevent.xmotion.x; + mouseMoveEvent->y = xevent.xmotion.y; + event = mouseMoveEvent; + } + break; + + case Expose: + if(xevent.xexpose.count == 0) + { + auto repaintEvent = new RepaintEvent(); + repaintEvent->window_id = xevent.xexpose.window; + repaintEvent->x = xevent.xexpose.x; + repaintEvent->y = xevent.xexpose.y; + repaintEvent->width = xevent.xexpose.width; + repaintEvent->height = xevent.xexpose.height; + event = repaintEvent; + } + break; + + case ConfigureNotify: + { + auto resizeEvent = new ResizeEvent(); + resizeEvent->window_id = xevent.xconfigure.window; + //resizeEvent->x = xevent.xconfigure.x; + //resizeEvent->y = xevent.xconfigure.y; + resizeEvent->width = xevent.xconfigure.width; + resizeEvent->height = xevent.xconfigure.height; + event = resizeEvent; + } + break; + + case ButtonPress: + case ButtonRelease: + { + if((xevent.xbutton.button == 4) || (xevent.xbutton.button == 5)) + { + int scroll = 1; + auto scrollEvent = new ScrollEvent(); + scrollEvent->window_id = xevent.xbutton.window; + scrollEvent->x = xevent.xbutton.x; + scrollEvent->y = xevent.xbutton.y; + scrollEvent->delta = scroll * ((xevent.xbutton.button == 4) ? -1 : 1); + event = scrollEvent; + } + else + { + auto buttonEvent = new ButtonEvent(); + buttonEvent->window_id = xevent.xbutton.window; + buttonEvent->x = xevent.xbutton.x; + buttonEvent->y = xevent.xbutton.y; + switch(xevent.xbutton.button) { + case 1: + buttonEvent->button = MouseButton::left; + break; + case 2: + buttonEvent->button = MouseButton::middle; + break; + case 3: + buttonEvent->button = MouseButton::right; + break; + default: + WARN(X11, "Unknown button %d, setting to MouseButton::left\n", + xevent.xbutton.button); + buttonEvent->button = MouseButton::left; + break; + } + + buttonEvent->direction = + (xevent.type == ButtonPress) ? + Direction::down : Direction::up; + + buttonEvent->doubleClick = + (xevent.type == ButtonPress) && + ((xevent.xbutton.time - last_click) < 200); + + if(!peek && (xevent.type == ButtonPress)) + { + last_click = xevent.xbutton.time; + } + event = buttonEvent; + } + } + break; + + case KeyPress: + case KeyRelease: + { + auto keyEvent = new KeyEvent(); + keyEvent->window_id = xevent.xkey.window; + + switch(xevent.xkey.keycode) { + case 113: keyEvent->keycode = Key::left; break; + case 114: keyEvent->keycode = Key::right; break; + case 111: keyEvent->keycode = Key::up; break; + case 116: keyEvent->keycode = Key::down; break; + case 119: keyEvent->keycode = Key::deleteKey; break; + case 22: keyEvent->keycode = Key::backspace; break; + case 110: keyEvent->keycode = Key::home; break; + case 115: keyEvent->keycode = Key::end; break; + case 117: keyEvent->keycode = Key::pageDown; break; + case 112: keyEvent->keycode = Key::pageUp; break; + case 36: keyEvent->keycode = Key::enter; break; + default: keyEvent->keycode = Key::unknown; break; + } + + char stringBuffer[1024]; + int size = XLookupString(&xevent.xkey, stringBuffer, + sizeof(stringBuffer), nullptr, nullptr); + if(size && keyEvent->keycode == Key::unknown) + { + keyEvent->keycode = Key::character; + } + + keyEvent->text.append(stringBuffer, size); + + keyEvent->direction = + (xevent.type == KeyPress) ? Direction::down : Direction::up; + + event = keyEvent; + } + break; + + case ClientMessage: + if(((unsigned int)xevent.xclient.data.l[0] == wmDeleteMessage)) + { + auto closeEvent = new CloseEvent(); + event = closeEvent; + } + break; + + default: + WARN(X11, "Unhandled xevent.type: %d\n", xevent.type); + break; + } + + return event; +} +} // GUI:: |