From 24bb55371a5d8d81b23521ebdfcde68f0035697c Mon Sep 17 00:00:00 2001 From: Bent Bisballe Nyeng Date: Sun, 20 Sep 2015 11:36:22 +0200 Subject: Basic project based on DrumGizmo. --- plugingui/nativewindow_x11.cc | 388 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 388 insertions(+) create mode 100644 plugingui/nativewindow_x11.cc (limited to 'plugingui/nativewindow_x11.cc') diff --git a/plugingui/nativewindow_x11.cc b/plugingui/nativewindow_x11.cc new file mode 100644 index 0000000..cb6cf73 --- /dev/null +++ b/plugingui/nativewindow_x11.cc @@ -0,0 +1,388 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * nativewindow_x11.cc + * + * Fri Dec 28 18:45:57 CET 2012 + * Copyright 2012 Bent Bisballe Nyeng + * deva@aasimon.org + ****************************************************************************/ + +/* + * This file is part of DrumGizmo. + * + * DrumGizmo is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * DrumGizmo is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with DrumGizmo; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#include "nativewindow_x11.h" + +#ifdef X11 +#include +#include + +#include "window.h" + +GUI::NativeWindowX11::NativeWindowX11(GUI::Window *window) + : GUI::NativeWindow() +{ + 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); +} + +GUI::NativeWindowX11::~NativeWindowX11() +{ + XDestroyWindow(display, xwindow); + //widgets.erase(window); + XCloseDisplay(display); +} + +void GUI::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); +} + +void GUI::NativeWindowX11::resize(int width, int height) +{ + XResizeWindow(display, xwindow, width, height); +} + +void GUI::NativeWindowX11::move(int x, int y) +{ + XMoveWindow(display, xwindow, x, y); +} + +void GUI::NativeWindowX11::show() +{ + XMapWindow(display, xwindow); +} + +void GUI::NativeWindowX11::hide() +{ + XUnmapWindow(display, xwindow); +} + +static int get_byte_order (void) +{ + union { + char c[sizeof(short)]; + short s; + } order; + + order.s = 1; + if ((1 == order.c[0])) { + return LSBFirst; + } else { + return MSBFirst; + } +} + +static XImage *create_image_from_buffer(Display *dis, int screen, + unsigned char *buf, + int width, int height) +{ + int depth; + XImage *img = NULL; + Visual *vis; + double rRatio; + double gRatio; + double bRatio; + int outIndex = 0; + int i; + int numBufBytes = (3 * (width * height)); + + depth = DefaultDepth(dis, screen); + vis = DefaultVisual(dis, screen); + + rRatio = vis->red_mask / 255.0; + gRatio = vis->green_mask / 255.0; + bRatio = vis->blue_mask / 255.0; + + if (depth >= 24) { + size_t numNewBufBytes = (4 * (width * height)); + u_int32_t *newBuf = (u_int32_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, + 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; + } + + 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 ())) { + img->byte_order = LSBFirst; + } else { + img->byte_order = MSBFirst; + } + + /*The bitmap_bit_order doesn't matter with ZPixmap images.*/ + img->bitmap_bit_order = MSBFirst; + + return img; +} + +void GUI::NativeWindowX11::handleBuffer() +{ + if(buffer) XDestroyImage(buffer); + buffer = + create_image_from_buffer(display, DefaultScreen(display), + window->wpixbuf.buf, + window->wpixbuf.width, + window->wpixbuf.height); +} + +void GUI::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); +} + +void GUI::NativeWindowX11::setCaption(const std::string &caption) +{ + XStoreName(display, xwindow, caption.c_str()); +} + +void GUI::NativeWindowX11::grabMouse(bool grab) +{ + (void)grab; + // Don't need to do anything on this platoform... +} + +bool GUI::NativeWindowX11::hasEvent() +{ + return XPending(display); +} + +GUI::Event *GUI::NativeWindowX11::getNextEvent() +{ + 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; +} + +#endif/*X11*/ + -- cgit v1.2.3