use select() so we can wait for XEvents or our timer
authorreed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Mon, 17 Jun 2013 13:42:43 +0000 (13:42 +0000)
committerreed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Mon, 17 Jun 2013 13:42:43 +0000 (13:42 +0000)
poll for xevents using XPending

BUG=

Review URL: https://codereview.chromium.org/17275003

git-svn-id: http://skia.googlecode.com/svn/trunk@9633 2bbb7eff-a529-9590-31e7-b0007b416f81

include/views/SkOSWindow_Unix.h
src/views/unix/SkOSWindow_Unix.cpp
src/views/unix/skia_unix.cpp

index 89265a4367ab2195d06fd7104ea4c5df6e2bfbc5..8a55ef455ef1f98892345a4d11efba03718a8b74 100644 (file)
@@ -32,7 +32,6 @@ public:
     void* getDisplay() const { return (void*)fUnixWindow.fDisplay; }
     void* getUnixWindow() const { return (void*)&fUnixWindow; }
     void loop();
-    void post_linuxevent();
 
     enum SkBackEndTypes {
         kNone_BackEndType,
@@ -54,14 +53,16 @@ public:
 
 protected:
     // Overridden from from SkWindow:
-    virtual bool onEvent(const SkEvent&) SK_OVERRIDE;
-    virtual void onHandleInval(const SkIRect&) SK_OVERRIDE;
-    virtual bool onHandleChar(SkUnichar) SK_OVERRIDE;
-    virtual bool onHandleKey(SkKey) SK_OVERRIDE;
-    virtual bool onHandleKeyUp(SkKey) SK_OVERRIDE;
     virtual void onSetTitle(const char title[]) SK_OVERRIDE;
 
 private:
+    enum NextXEventResult {
+        kContinue_NextXEventResult,
+        kQuitRequest_NextXEventResult,
+        kPaintRequest_NextXEventResult
+    };
+
+    NextXEventResult nextXEvent();
     void doPaint();
     void mapWindowAndWait();
 
index a20644556dc8e18509ae1fc5f47f1991ec6d1792..591493e57eee9987e3ec36ae25b71d28a940f837 100644 (file)
@@ -149,23 +149,6 @@ void SkOSWindow::initWindow(int requestedMSAASampleCount, AttachmentInfo* info)
     fUnixWindow.fGc = XCreateGC(dsp, fUnixWindow.fWin, 0, NULL);
 }
 
-
-void SkOSWindow::post_linuxevent() {
-    // Put an event in the X queue to fire an SkEvent.
-    if (NULL == fUnixWindow.fDisplay) {
-        return;
-    }
-    XClientMessageEvent event;
-    event.type = ClientMessage;
-    Atom myAtom(0);
-    event.message_type = myAtom;
-    event.format = 32;
-    event.data.l[0] = 0;
-    XSendEvent(fUnixWindow.fDisplay, fUnixWindow.fWin, false, 0,
-               (XEvent*) &event);
-    XFlush(fUnixWindow.fDisplay);
-}
-
 static unsigned getModi(const XEvent& evt) {
     static const struct {
         unsigned    fXMask;
@@ -186,6 +169,81 @@ static unsigned getModi(const XEvent& evt) {
     return modi;
 }
 
+static SkMSec gTimerDelay;
+
+static void MyXNextEventWithDelay(Display* dsp, XEvent* evt) {
+    SkMSec ms = gTimerDelay;
+    if (ms > 0) {
+        int x11_fd = ConnectionNumber(dsp);
+        fd_set input_fds;
+        FD_ZERO(&input_fds);
+        FD_SET(x11_fd, &input_fds);
+
+        timeval tv;
+        tv.tv_sec = ms / 1000;              // seconds
+        tv.tv_usec = (ms % 1000) * 1000;    // microseconds
+        
+        (void)select(x11_fd + 1, &input_fds, NULL, NULL, &tv);
+    }
+
+    if (XPending(dsp)) {
+        XNextEvent(dsp, evt);
+    }
+}
+
+SkOSWindow::NextXEventResult SkOSWindow::nextXEvent() {
+    XEvent evt;
+    Display* dsp = fUnixWindow.fDisplay;
+
+    MyXNextEventWithDelay(fUnixWindow.fDisplay, &evt);
+
+    switch (evt.type) {
+        case Expose:
+            if (0 == evt.xexpose.count) {
+                return kPaintRequest_NextXEventResult;
+            }
+            break;
+        case ConfigureNotify:
+            this->resize(evt.xconfigure.width, evt.xconfigure.height);
+            break;
+        case ButtonPress:
+            if (evt.xbutton.button == Button1)
+                this->handleClick(evt.xbutton.x, evt.xbutton.y,
+                            SkView::Click::kDown_State, NULL, getModi(evt));
+            break;
+        case ButtonRelease:
+            if (evt.xbutton.button == Button1)
+                this->handleClick(evt.xbutton.x, evt.xbutton.y,
+                              SkView::Click::kUp_State, NULL, getModi(evt));
+            break;
+        case MotionNotify:
+            this->handleClick(evt.xmotion.x, evt.xmotion.y,
+                           SkView::Click::kMoved_State, NULL, getModi(evt));
+            break;
+        case KeyPress: {
+            int shiftLevel = (evt.xkey.keycode & ShiftMask) ? 1 : 0;
+            KeySym keysym = XkbKeycodeToKeysym(dsp, evt.xkey.keycode,
+                                               0, shiftLevel);
+            if (keysym == XK_Escape) {
+                return kQuitRequest_NextXEventResult;
+            }
+            this->handleKey(XKeyToSkKey(keysym));
+            long uni = keysym2ucs(keysym);
+            if (uni != -1) {
+                this->handleChar((SkUnichar) uni);
+            }
+            break;
+        }
+        case KeyRelease:
+            this->handleKeyUp(XKeyToSkKey(XkbKeycodeToKeysym(dsp, evt.xkey.keycode, 0, 0)));
+            break;
+        default:
+            // Do nothing for other events
+            break;
+    }
+    return kContinue_NextXEventResult;
+}
+
 void SkOSWindow::loop() {
     Display* dsp = fUnixWindow.fDisplay;
     if (NULL == dsp) {
@@ -193,58 +251,31 @@ void SkOSWindow::loop() {
     }
     XSelectInput(dsp, fUnixWindow.fWin, EVENT_MASK);
 
-    bool loop = true;
-    XEvent evt;
-    while (loop) {
-        XNextEvent(dsp, &evt);
-        switch (evt.type) {
-            case Expose:
-                if (evt.xexpose.count == 0)
-                    this->inval(NULL);
-                break;
-            case ConfigureNotify:
-                this->resize(evt.xconfigure.width, evt.xconfigure.height);
-                break;
-            case ButtonPress:
-                if (evt.xbutton.button == Button1)
-                    this->handleClick(evt.xbutton.x, evt.xbutton.y,
-                                SkView::Click::kDown_State, NULL, getModi(evt));
-                break;
-            case ButtonRelease:
-                if (evt.xbutton.button == Button1)
-                    this->handleClick(evt.xbutton.x, evt.xbutton.y,
-                                  SkView::Click::kUp_State, NULL, getModi(evt));
-                break;
-            case MotionNotify:
-                this->handleClick(evt.xmotion.x, evt.xmotion.y,
-                               SkView::Click::kMoved_State, NULL, getModi(evt));
-                break;
-            case KeyPress: {
-                KeySym keysym = XkbKeycodeToKeysym(dsp, evt.xkey.keycode, 0, 0);
-                //SkDebugf("pressed key %i!\n\tKeySym:%i\n", evt.xkey.keycode, XKeycodeToKeysym(dsp, evt.xkey.keycode, 0));
-                if (keysym == XK_Escape) {
-                    loop = false;
+    bool needPaint = false;
+
+    for (;;) {
+        if (this->isDirty()) {
+            this->update(NULL);
+            needPaint = true;
+        }
+        if (needPaint) {
+            this->doPaint();
+            needPaint = false;
+        }
+        if (gTimerDelay) {
+            SkEvent::ServiceQueueTimer();
+        }
+        bool moreToDo = SkEvent::ProcessEvent() || needPaint || this->isDirty();
+        if (XPending(dsp) || !moreToDo) {
+            switch (this->nextXEvent()) {
+                case kContinue_NextXEventResult:
                     break;
-                }
-                this->handleKey(XKeyToSkKey(keysym));
-                long uni = keysym2ucs(keysym);
-                if (uni != -1) {
-                    this->handleChar((SkUnichar) uni);
-                }
-                break;
+                case kPaintRequest_NextXEventResult:
+                    needPaint = true;
+                    break;
+                case kQuitRequest_NextXEventResult:
+                    return;
             }
-            case KeyRelease:
-                //SkDebugf("released key %i\n", evt.xkey.keycode);
-                this->handleKeyUp(XKeyToSkKey(XkbKeycodeToKeysym(dsp, evt.xkey.keycode, 0, 0)));
-                break;
-            case ClientMessage:
-                if (SkEvent::ProcessEvent()) {
-                    this->post_linuxevent();
-                }
-                break;
-            default:
-                // Do nothing for other events
-                break;
         }
     }
 }
@@ -321,20 +352,6 @@ void SkOSWindow::onSetTitle(const char title[]) {
     XSetWMName(fUnixWindow.fDisplay, fUnixWindow.fWin, &textProp);
 }
 
-void SkOSWindow::onHandleInval(const SkIRect&) {
-    (new SkEvent("inval-imageview", this->getSinkID()))->post();
-}
-
-bool SkOSWindow::onEvent(const SkEvent& evt) {
-    if (evt.isType("inval-imageview")) {
-        update(NULL);
-        if (NULL == fUnixWindow.fGLContext)
-            this->doPaint();
-        return true;
-    }
-    return INHERITED::onEvent(evt);
-}
-
 static bool convertBitmapToXImage(XImage& image, const SkBitmap& bitmap) {
     sk_bzero(&image, sizeof(image));
 
@@ -348,7 +365,7 @@ static bool convertBitmapToXImage(XImage& image, const SkBitmap& bitmap) {
     image.bitmap_bit_order = LSBFirst;
     image.bitmap_pad = bitsPerPixel;
     image.depth = 24;
-    image.bytes_per_line = bitmap.rowBytes() - bitmap.width() * bitmap.bytesPerPixel();
+    image.bytes_per_line = bitmap.rowBytes() - bitmap.width() * 4;
     image.bits_per_pixel = bitsPerPixel;
     return XInitImage(&image);
 }
@@ -376,14 +393,15 @@ void SkOSWindow::doPaint() {
               width, height);
 }
 
-bool SkOSWindow::onHandleChar(SkUnichar) {
-    return false;
-}
+///////////////////////////////////////////////////////////////////////////////
 
-bool SkOSWindow::onHandleKey(SkKey) {
-    return false;
+void SkEvent::SignalNonEmptyQueue() {
+    // nothing to do, since we spin on our event-queue, polling for XPending
 }
 
-bool SkOSWindow::onHandleKeyUp(SkKey) {
-    return false;
+void SkEvent::SignalQueueTimer(SkMSec delay) {
+    // just need to record the delay time. We handle waking up for it in
+    // MyXNextEventWithDelay()
+    gTimerDelay = delay;
 }
+
index 108e9ac20688e05ccdfe278990b0ba4d50d2f0b5..d77a8161fbd8b59d787f08ad94ac44cc9cf491b0 100644 (file)
 
 SkOSWindow* gWindow;
 
-static void catch_alarm(int sig)
-{
-    SkEvent::ServiceQueueTimer();
-}
-
 int main(int argc, char** argv){
-    signal(SIGALRM, catch_alarm);
-
     gWindow = create_sk_window(NULL, argc, argv);
 
     // drain any events that occurred before gWindow was assigned.
@@ -43,20 +36,4 @@ int main(int argc, char** argv){
 
 // SkEvent handlers
 
-void SkEvent::SignalNonEmptyQueue()
-{
-    if (gWindow) {
-        gWindow->post_linuxevent();
-    }
-}
-
-void SkEvent::SignalQueueTimer(SkMSec delay)
-{
-    itimerval newTimer;
-    newTimer.it_interval.tv_sec = 0;
-    newTimer.it_interval.tv_usec = 0;
-    newTimer.it_value.tv_sec = 0;
-    newTimer.it_value.tv_usec = delay * 1000;
 
-    setitimer(ITIMER_REAL, &newTimer, NULL);
-}