summaryrefslogtreecommitdiff
path: root/plugingui/nativewindow_x11.cc
diff options
context:
space:
mode:
Diffstat (limited to 'plugingui/nativewindow_x11.cc')
-rw-r--r--plugingui/nativewindow_x11.cc388
1 files changed, 388 insertions, 0 deletions
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 <X11/Xutil.h>
+#include <stdlib.h>
+
+#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*/
+