/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /*************************************************************************** * window.cc * * Sun Oct 9 13:11:53 CEST 2011 * Copyright 2011 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 "window.h" #include "painter.h" #include "img_back.h" #ifdef X11 #include #include #endif/*X11*/ #include #include #include GUI::Window *gwindow = NULL; #ifdef WIN32 // Delared in eventhandler.cc LRESULT CALLBACK dialogProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp); #endif/*WIN32*/ GUI::Window::Window(GlobalContext *gctx) : Widget(NULL), wpixbuf(640, 200) { gwindow = this; this->gctx = gctx; _x = _y = 100; _width = wpixbuf.width; _height = wpixbuf.height; refcount = 0; _keyboardFocus = this; _buttonDownFocus = NULL; #ifdef X11 buffer = NULL; // Get some colors int blackColor = BlackPixel(gctx->display, DefaultScreen(gctx->display)); ::Window w = DefaultRootWindow(gctx->display); // Create the window xwindow = XCreateSimpleWindow(gctx->display, w, _x, _y, _width, _height, 0, blackColor, blackColor); XSelectInput(gctx->display, xwindow, StructureNotifyMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask| ExposureMask | StructureNotifyMask | SubstructureNotifyMask); // register interest in the delete window message gctx->wmDeleteMessage = XInternAtom(gctx->display, "WM_DELETE_WINDOW", false); XSetWMProtocols(gctx->display, xwindow, &gctx->wmDeleteMessage, 1); // "Map" the window (that is, make it appear on the screen) XMapWindow(gctx->display, xwindow); // Create a "Graphics Context" gc = XCreateGC(gctx->display, xwindow, 0, NULL); #endif/*X11*/ #ifdef WIN32 WNDCLASSEX wcex; WNDID wndId; gctx->m_hwnd = 0; gctx->m_className = NULL; memset(&wcex, 0, sizeof(wcex)); //Time to register a window class. //Generic flags and everything. cbWndExtra is the size of a pointer to an // object - we need this in the wndproc handler. wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = 0;//class_style; wcex.lpfnWndProc = (WNDPROC)dialogProc; wcex.hCursor = LoadCursor(NULL, IDC_ARROW); // Set data: wcex.cbWndExtra = sizeof(EventHandler*); // Size of data. wcex.hInstance = GetModuleHandle(NULL); // if(ex_style && WS_EX_TRANSPARENT == WS_EX_TRANSPARENT) { // wcex.hbrBackground = NULL; // } else { wcex.hbrBackground = NULL;//(HBRUSH) COLOR_BACKGROUND + 1; // } wcex.lpszClassName = gctx->m_className = strdup("DrumGizmoClass"); RegisterClassEx(&wcex); /* if(parent) { style = style | WS_CHILD; wndId = parent->getWndId(); } else { */ //style = style | WS_OVERLAPPEDWINDOW; wndId = 0; // } gctx->m_hwnd = CreateWindowEx(NULL/*ex_style*/, gctx->m_className, "DGBasisWidget", (WS_OVERLAPPEDWINDOW | WS_VISIBLE), _x, _y, _width, _height, wndId, NULL, GetModuleHandle(NULL), NULL); SetWindowLong(gctx->m_hwnd, GWL_USERDATA, (LONG)gctx->eventhandler); #endif/*WIN32*/ } GUI::Window::~Window() { #ifdef X11 XDestroyWindow(gctx->display, xwindow); //gctx->widgets.erase(window); #endif/*X11*/ #ifdef WIN32 UnregisterClass(gctx->m_className, GetModuleHandle(NULL)); free(gctx->m_className); #endif/*WIN32*/ } void GUI::Window::repaintEvent(GUI::RepaintEvent *e) { Painter p(this); p.drawImage(0, 0, (struct __img__*)&img_back); } void GUI::Window::resize(size_t width, size_t height) { // printf("Window::resize(%d, %d)\n", width, height); #ifdef X11 XResizeWindow(gctx->display, xwindow, width, height); #endif/*X11*/ #ifdef WIN32 SetWindowPos(gctx->m_hwnd, NULL, -1, -1, (int)width, (int)height + 27, SWP_NOMOVE); #endif/*WIN32*/ Widget::resize(width, height); } void GUI::Window::move(size_t x, size_t y) { #ifdef X11 XMoveWindow(gctx->display, xwindow, x, y); #endif/*X11*/ #ifdef WIN32 SetWindowPos(gctx->m_hwnd, NULL, (int)x, (int)y, -1, -1, SWP_NOSIZE); #endif/*WIN32*/ // Make sure widget corrds are updated. Widget::move(x, y); } size_t GUI::Window::x() { return _x; } size_t GUI::Window::y() { return _y; } size_t GUI::Window::width() { return _width; } size_t GUI::Window::height() { return _height; } void GUI::Window::show() { repaint_r(NULL); #ifdef X11 XMapWindow(gctx->display, xwindow); #endif/*X11*/ #ifdef WIN32 ShowWindow(gctx->m_hwnd, SW_SHOW); #endif/*WIN32*/ } void GUI::Window::hide() { #ifdef X11 XUnmapWindow(gctx->display, xwindow); #endif/*X11*/ #ifdef WIN32 ShowWindow(gctx->m_hwnd, SW_HIDE); #endif/*WIN32*/ } GUI::Window *GUI::Window::window() { return this; } void GUI::Window::beginPaint() { refcount++; // printf("beginPaint(%d)\n", refcount); } void GUI::Window::endPaint() { // printf("endPaint(%d)\n", refcount); if(refcount) refcount--; if(!refcount) { updateBuffer(); #ifdef X11 //XSendEvent(gctx->display, window, false, ExposureMask, event_send) #endif/*X11*/ redraw(); } } #ifdef X11 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; } #endif/*X11*/ void GUI::Window::updateBuffer() { // printf("updateBuffer w:%d h:%d\n", width(), height()); memset(wpixbuf.buf, 0, wpixbuf.width * wpixbuf.height * 3); std::vector pl = getPixelBuffers(); std::vector::iterator pli = pl.begin(); while(pli != pl.end()) { PixelBufferAlpha *pb = *pli; // printf("Buffer idx %d (%d %d) [%d %d]\n", pb->idx, pb->x, pb->y, // pb->width, pb->height); for(size_t x = 0; x < pb->width; x++) { for(size_t y = 0; y < pb->height; y++) { unsigned char r,g,b,a; pb->pixel(x,y,&r,&g,&b,&a); wpixbuf.setPixel(x + pb->x, y + pb->y, r, g, b, a); } } pli++; } #ifdef X11 if(buffer) XDestroyImage(buffer); buffer = create_image_from_buffer(gctx->display, DefaultScreen(gctx->display), wpixbuf.buf, wpixbuf.width, wpixbuf.height); #endif/*X11*/ } void GUI::Window::resized(size_t w, size_t h) { _width = w; _height = h; wpixbuf.realloc(w, h); updateBuffer(); pixbuf.realloc(w, h); repaintEvent(NULL); } void GUI::Window::redraw() { #ifdef X11 // http://stackoverflow.com/questions/6384987/load-image-onto-a-window-using-xlib if(buffer == NULL) updateBuffer(); XPutImage(gctx->display, xwindow, gc, buffer, 0, 0, 0, 0, width(), height()); XFlush(gctx->display); #endif/*X11*/ #ifdef WIN32 RedrawWindow(gctx->m_hwnd, NULL, NULL, RDW_ERASE|RDW_INVALIDATE); UpdateWindow(gctx->m_hwnd); #endif/*WIN32*/ } GUI::Widget *GUI::Window::keyboardFocus() { return _keyboardFocus; } void GUI::Window::setKeyboardFocus(GUI::Widget *widget) { _keyboardFocus = widget; repaint_r(NULL); } GUI::Widget *GUI::Window::buttonDownFocus() { return _buttonDownFocus; } void GUI::Window::setButtonDownFocus(GUI::Widget *widget) { _buttonDownFocus = widget; // repaint_r(NULL); } #ifdef TEST_WINDOW //Additional dependency files //deps: //Required cflags (autoconf vars may be used) //cflags: //Required link options (autoconf vars may be used) //libs: #include "test.h" TEST_BEGIN; // TODO: Put some testcode here (see test.h for usable macros). TEST_END; #endif/*TEST_WINDOW*/