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" 17extern "C" { 18 #include "keysym2ucs.h" 19} 20 21const int WIDTH = 500; 22const int HEIGHT = 500; 23 24// Determine which events to listen for. 25const long EVENT_MASK = StructureNotifyMask|ButtonPressMask|ButtonReleaseMask 26 |ExposureMask|PointerMotionMask|KeyPressMask|KeyReleaseMask; 27 28SkOSWindow::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 60SkOSWindow::~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 74void 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 89void 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 148void 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 165bool 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 189void 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 199void SkOSWindow::presentGL() 200{ 201 if (fUnixWindow.fDisplay && fGLAttached) { 202 glXSwapBuffers(fUnixWindow.fDisplay, fUnixWindow.fWin); 203 } 204} 205 206void 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 217void SkOSWindow::onHandleInval(const SkIRect&) 218{ 219 SkEvent* evt = new SkEvent("inval-imageview"); 220 evt->post(getSinkID()); 221} 222 223bool 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 234static 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 253void 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 266bool SkOSWindow::onHandleChar(SkUnichar) 267{ 268 return false; 269} 270 271bool SkOSWindow::onHandleKey(SkKey key) 272{ 273 return false; 274} 275 276bool SkOSWindow::onHandleKeyUp(SkKey key) 277{ 278 return false; 279} 280