Home | History | Annotate | Download | only in unix
      1 #include <X11/Xlib.h>
      2 #include <X11/Xatom.h>
      3 #include <X11/keysym.h>
      4 #include <GL/glx.h>
      5 #include <GL/gl.h>
      6 #include <GL/glu.h>
      7 
      8 #include "SkWindow.h"
      9 
     10 #include "SkBitmap.h"
     11 #include "SkCanvas.h"
     12 #include "SkColor.h"
     13 #include "SkEvent.h"
     14 #include "SkKey.h"
     15 #include "SkWindow.h"
     16 #include "XkeysToSkKeys.h"
     17 extern "C" {
     18     #include "keysym2ucs.h"
     19 }
     20 
     21 const int WIDTH = 500;
     22 const int HEIGHT = 500;
     23 
     24 // Determine which events to listen for.
     25 const long EVENT_MASK = StructureNotifyMask|ButtonPressMask|ButtonReleaseMask
     26         |ExposureMask|PointerMotionMask|KeyPressMask|KeyReleaseMask;
     27 
     28 SkOSWindow::SkOSWindow(void* unused) : fGLAttached(false), fVi(0)
     29 {
     30     fUnixWindow.fDisplay = XOpenDisplay(NULL);
     31     Display* dsp = fUnixWindow.fDisplay;
     32     if (dsp) {
     33         // Attempt to create a window that supports GL
     34         GLint att[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER,
     35                 GLX_STENCIL_SIZE, 8, None };
     36         fVi = glXChooseVisual(dsp, DefaultScreen(dsp), att);
     37         if (fVi) {
     38             Colormap colorMap = XCreateColormap(dsp, RootWindow(dsp, fVi->screen),
     39                 fVi->visual, AllocNone);
     40             XSetWindowAttributes swa;
     41             swa.colormap = colorMap;
     42             swa.event_mask = EVENT_MASK;
     43             fUnixWindow.fWin = XCreateWindow(dsp, RootWindow(dsp, fVi->screen),
     44                     0, 0, WIDTH, HEIGHT, 0, fVi->depth,
     45                     InputOutput, fVi->visual, CWEventMask | CWColormap, &swa);
     46 
     47         } else {
     48             // Create a simple window instead.  We will not be able to
     49             // show GL
     50             fUnixWindow.fWin = XCreateSimpleWindow(dsp, DefaultRootWindow(dsp),
     51                     0, 0, WIDTH, HEIGHT, 0, 0, 0);
     52         }
     53         mapWindowAndWait();
     54         fUnixWindow.fGc = XCreateGC(dsp, fUnixWindow.fWin, 0, NULL);
     55     }
     56     this->resize(WIDTH, HEIGHT);
     57     fUnixWindow.fGLCreated = false;
     58 }
     59 
     60 SkOSWindow::~SkOSWindow()
     61 {
     62     if (fUnixWindow.fDisplay) {
     63         if (fGLAttached)
     64             glXMakeCurrent(fUnixWindow.fDisplay, None, NULL);
     65         XFreeGC(fUnixWindow.fDisplay, fUnixWindow.fGc);
     66         if (fUnixWindow.fGLCreated)
     67             glXDestroyContext(fUnixWindow.fDisplay, fUnixWindow.fGLContext);
     68         XDestroyWindow(fUnixWindow.fDisplay, fUnixWindow.fWin);
     69         XCloseDisplay(fUnixWindow.fDisplay);
     70         fUnixWindow.fDisplay = 0;
     71     }
     72 }
     73 
     74 void SkOSWindow::post_linuxevent()
     75 {
     76     // Put an event in the X queue to fire an SkEvent.
     77     if (!fUnixWindow.fDisplay) return;
     78     long event_mask = NoEventMask;
     79     XClientMessageEvent event;
     80     event.type = ClientMessage;
     81     Atom myAtom(0);
     82     event.message_type = myAtom;
     83     event.format = 32;
     84     event.data.l[0] = 0;
     85     XSendEvent(fUnixWindow.fDisplay, fUnixWindow.fWin, false, 0,
     86                (XEvent*) &event);
     87 }
     88 
     89 void SkOSWindow::loop()
     90 {
     91     Display* dsp = fUnixWindow.fDisplay;
     92     XSelectInput(dsp, fUnixWindow.fWin, EVENT_MASK);
     93 
     94     bool loop = true;
     95     XEvent evt;
     96     while (loop) {
     97         XNextEvent(dsp, &evt);
     98         switch (evt.type) {
     99             case Expose:
    100                 if (evt.xexpose.count == 0)
    101                     this->inval(NULL);
    102                 break;
    103             case ConfigureNotify:
    104                 this->resize(evt.xconfigure.width, evt.xconfigure.height);
    105                 break;
    106             case ButtonPress:
    107                 if (evt.xbutton.button == Button1)
    108                     this->handleClick(evt.xbutton.x, evt.xbutton.y, SkView::Click::kDown_State);
    109                 break;
    110             case ButtonRelease:
    111                 if (evt.xbutton.button == Button1)
    112                     this->handleClick(evt.xbutton.x, evt.xbutton.y, SkView::Click::kUp_State);
    113                 break;
    114             case MotionNotify:
    115                 this->handleClick(evt.xmotion.x, evt.xmotion.y, SkView::Click::kMoved_State);
    116                 break;
    117             case KeyPress:
    118             {
    119                 KeySym keysym = XKeycodeToKeysym(dsp, evt.xkey.keycode, 0);
    120                 //SkDebugf("pressed key %i!\n\tKeySym:%i\n", evt.xkey.keycode, XKeycodeToKeysym(dsp, evt.xkey.keycode, 0));
    121                 if (keysym == XK_Escape) {
    122                     loop = false;
    123                     break;
    124                 }
    125                 this->handleKey(XKeyToSkKey(keysym));
    126                 long uni = keysym2ucs(keysym);
    127                 if (uni != -1) {
    128                     this->handleChar((SkUnichar) uni);
    129                 }
    130                 break;
    131             }
    132             case KeyRelease:
    133                 //SkDebugf("released key %i\n", evt.xkey.keycode);
    134                 this->handleKeyUp(XKeyToSkKey(XKeycodeToKeysym(dsp, evt.xkey.keycode, 0)));
    135                 break;
    136             case ClientMessage:
    137                 if (SkEvent::ProcessEvent()) {
    138                     this->post_linuxevent();
    139                 }
    140                 break;
    141             default:
    142                 // Do nothing for other events
    143                 break;
    144         }
    145     }
    146 }
    147 
    148 void SkOSWindow::mapWindowAndWait()
    149 {
    150     Display* dsp = fUnixWindow.fDisplay;
    151     Window win = fUnixWindow.fWin;
    152     XMapWindow(dsp, win);
    153 
    154     long eventMask = StructureNotifyMask;
    155     XSelectInput(dsp, win, eventMask);
    156 
    157     // Wait until screen is ready.
    158     XEvent evt;
    159     do {
    160         XNextEvent(dsp, &evt);
    161     } while(evt.type != MapNotify);
    162 
    163 }
    164 
    165 bool SkOSWindow::attachGL()
    166 {
    167     if (fGLAttached) return true;
    168     Display* dsp = fUnixWindow.fDisplay;
    169     if (!dsp || !fVi) return false;
    170 
    171     if (!fUnixWindow.fGLCreated) {
    172         fUnixWindow.fGLContext = glXCreateContext(dsp, fVi, NULL, GL_TRUE);
    173         fUnixWindow.fGLCreated = true;
    174         glXMakeCurrent(dsp, fUnixWindow.fWin, fUnixWindow.fGLContext);
    175         glViewport(0, 0, SkScalarRound(this->width()), SkScalarRound(this->height()));
    176         glClearColor(0, 0, 0, 0);
    177         glClearStencil(0);
    178         glStencilMask(0xffffffff);
    179         glDisable(GL_SCISSOR_TEST);
    180         glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    181     }
    182     else
    183         glXMakeCurrent(dsp, fUnixWindow.fWin, fUnixWindow.fGLContext);
    184     fGLAttached = true;
    185 
    186     return true;
    187 }
    188 
    189 void SkOSWindow::detachGL()
    190 {
    191     if (!fUnixWindow.fDisplay || !fGLAttached) return;
    192     fGLAttached = false;
    193     // Returns back to normal drawing.
    194     glXMakeCurrent(fUnixWindow.fDisplay, None, NULL);
    195     // Ensure that we redraw when switching back to raster.
    196     this->inval(NULL);
    197 }
    198 
    199 void SkOSWindow::presentGL()
    200 {
    201     if (fUnixWindow.fDisplay && fGLAttached) {
    202         glXSwapBuffers(fUnixWindow.fDisplay, fUnixWindow.fWin);
    203     }
    204 }
    205 
    206 void SkOSWindow::onSetTitle(const char title[])
    207 {
    208     if (!fUnixWindow.fDisplay) return;
    209     XTextProperty textProp;
    210     textProp.value = (unsigned char*)title;
    211     textProp.format = 8;
    212     textProp.nitems = strlen((char*)textProp.value);
    213     textProp.encoding = XA_STRING;
    214     XSetWMName(fUnixWindow.fDisplay, fUnixWindow.fWin, &textProp);
    215 }
    216 
    217 void SkOSWindow::onHandleInval(const SkIRect&)
    218 {
    219     SkEvent* evt = new SkEvent("inval-imageview");
    220     evt->post(getSinkID());
    221 }
    222 
    223 bool SkOSWindow::onEvent(const SkEvent& evt)
    224 {
    225     if (evt.isType("inval-imageview")) {
    226         update(NULL);
    227         if (!fGLAttached)
    228             doPaint();
    229         return true;
    230     }
    231     return INHERITED::onEvent(evt);
    232 }
    233 
    234 static bool convertBitmapToXImage(XImage& image, const SkBitmap& bitmap)
    235 {
    236     sk_bzero(&image, sizeof(image));
    237 
    238     int bitsPerPixel = bitmap.bytesPerPixel() * 8;
    239     image.width = bitmap.width();
    240     image.height = bitmap.height();
    241     image.format = ZPixmap;
    242     image.data = (char*) bitmap.getPixels();
    243     image.byte_order = LSBFirst;
    244     image.bitmap_unit = bitsPerPixel;
    245     image.bitmap_bit_order = LSBFirst;
    246     image.bitmap_pad = bitsPerPixel;
    247     image.depth = 24;
    248     image.bytes_per_line = bitmap.rowBytes() - bitmap.width() * bitmap.bytesPerPixel();
    249     image.bits_per_pixel = bitsPerPixel;
    250     return XInitImage(&image);
    251 }
    252 
    253 void SkOSWindow::doPaint() {
    254     if (!fUnixWindow.fDisplay) return;
    255     // Draw the bitmap to the screen.
    256     const SkBitmap& bitmap = getBitmap();
    257     int width = bitmap.width();
    258     int height = bitmap.height();
    259 
    260     XImage image;
    261     if (!convertBitmapToXImage(image, bitmap)) return;
    262 
    263     XPutImage(fUnixWindow.fDisplay, fUnixWindow.fWin, fUnixWindow.fGc, &image, 0, 0, 0, 0, width, height);
    264 }
    265 
    266 bool SkOSWindow::onHandleChar(SkUnichar)
    267 {
    268     return false;
    269 }
    270 
    271 bool SkOSWindow::onHandleKey(SkKey key)
    272 {
    273     return false;
    274 }
    275 
    276 bool SkOSWindow::onHandleKeyUp(SkKey key)
    277 {
    278     return false;
    279 }
    280