1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com 2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/* 3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2011 Google Inc. 4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * 5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be 6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file. 7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com */ 8b7e9aee1acf27fc98cb37ed69c05da71b4c3c69bscroggo#include <X11/Xlib.h> 9b7e9aee1acf27fc98cb37ed69c05da71b4c3c69bscroggo#include <X11/Xatom.h> 1075356a713f0576d5e4f542898267acbcf4d18d88bsalomon@google.com#include <X11/XKBlib.h> 11b7e9aee1acf27fc98cb37ed69c05da71b4c3c69bscroggo#include <GL/glx.h> 129df214e836f2b897224178676c03017e9190b7e0Scroggo#include <GL/gl.h> 139df214e836f2b897224178676c03017e9190b7e0Scroggo#include <GL/glu.h> 14b7e9aee1acf27fc98cb37ed69c05da71b4c3c69bscroggo 15b7e9aee1acf27fc98cb37ed69c05da71b4c3c69bscroggo#include "SkWindow.h" 16b7e9aee1acf27fc98cb37ed69c05da71b4c3c69bscroggo 17b7e9aee1acf27fc98cb37ed69c05da71b4c3c69bscroggo#include "SkBitmap.h" 1808526c07f4f530e56b70d4b22f5a4af35d9ebccascroggo#include "SkCanvas.h" 19b7e9aee1acf27fc98cb37ed69c05da71b4c3c69bscroggo#include "SkColor.h" 20b7e9aee1acf27fc98cb37ed69c05da71b4c3c69bscroggo#include "SkEvent.h" 219df214e836f2b897224178676c03017e9190b7e0Scroggo#include "SkKey.h" 229df214e836f2b897224178676c03017e9190b7e0Scroggo#include "SkWindow.h" 239df214e836f2b897224178676c03017e9190b7e0Scroggo#include "XkeysToSkKeys.h" 249df214e836f2b897224178676c03017e9190b7e0Scroggoextern "C" { 259df214e836f2b897224178676c03017e9190b7e0Scroggo #include "keysym2ucs.h" 269df214e836f2b897224178676c03017e9190b7e0Scroggo} 279df214e836f2b897224178676c03017e9190b7e0Scroggo 28aed68d999bfd307c2cdf1539e4ed4caa9130c7f3Scroggoconst int WIDTH = 500; 29aed68d999bfd307c2cdf1539e4ed4caa9130c7f3Scroggoconst int HEIGHT = 500; 309df214e836f2b897224178676c03017e9190b7e0Scroggo 319df214e836f2b897224178676c03017e9190b7e0Scroggo// Determine which events to listen for. 329df214e836f2b897224178676c03017e9190b7e0Scroggoconst long EVENT_MASK = StructureNotifyMask|ButtonPressMask|ButtonReleaseMask 339df214e836f2b897224178676c03017e9190b7e0Scroggo |ExposureMask|PointerMotionMask|KeyPressMask|KeyReleaseMask; 34b7e9aee1acf27fc98cb37ed69c05da71b4c3c69bscroggo 3593c7ee34dc5c8f6bfad65809f4b39f8d00d7f0d4sugoi@google.comSkOSWindow::SkOSWindow(void*) 364bdfb8c9d6482a56c7212034a6f73046227ed023robertphillips@google.com : fVi(NULL) 371195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com , fMSAASampleCount(0) { 381195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com fUnixWindow.fDisplay = NULL; 398108c47b50d13cf55b0265b97d729f354e7a697ebsalomon@google.com fUnixWindow.fGLContext = NULL; 4064cc810ad165724f9c666a75bd52e41c67f13564bsalomon@google.com this->initWindow(0, NULL); 419df214e836f2b897224178676c03017e9190b7e0Scroggo this->resize(WIDTH, HEIGHT); 42b7e9aee1acf27fc98cb37ed69c05da71b4c3c69bscroggo} 43b7e9aee1acf27fc98cb37ed69c05da71b4c3c69bscroggo 448108c47b50d13cf55b0265b97d729f354e7a697ebsalomon@google.comSkOSWindow::~SkOSWindow() { 451195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com this->closeWindow(); 461195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com} 471195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com 481195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.comvoid SkOSWindow::closeWindow() { 498108c47b50d13cf55b0265b97d729f354e7a697ebsalomon@google.com if (NULL != fUnixWindow.fDisplay) { 501195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com this->detach(); 511195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com SkASSERT(NULL != fUnixWindow.fGc); 528108c47b50d13cf55b0265b97d729f354e7a697ebsalomon@google.com XFreeGC(fUnixWindow.fDisplay, fUnixWindow.fGc); 531195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com fUnixWindow.fGc = NULL; 549df214e836f2b897224178676c03017e9190b7e0Scroggo XDestroyWindow(fUnixWindow.fDisplay, fUnixWindow.fWin); 551195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com fVi = NULL; 569df214e836f2b897224178676c03017e9190b7e0Scroggo XCloseDisplay(fUnixWindow.fDisplay); 571195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com fUnixWindow.fDisplay = NULL; 581195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com fMSAASampleCount = 0; 591195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com } 601195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com} 611195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com 6264cc810ad165724f9c666a75bd52e41c67f13564bsalomon@google.comvoid SkOSWindow::initWindow(int requestedMSAASampleCount, AttachmentInfo* info) { 631195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com if (fMSAASampleCount != requestedMSAASampleCount) { 641195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com this->closeWindow(); 651195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com } 661195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com // presence of fDisplay means we already have a window 671195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com if (NULL != fUnixWindow.fDisplay) { 6864cc810ad165724f9c666a75bd52e41c67f13564bsalomon@google.com if (NULL != info) { 6964cc810ad165724f9c666a75bd52e41c67f13564bsalomon@google.com if (NULL != fVi) { 7064cc810ad165724f9c666a75bd52e41c67f13564bsalomon@google.com glXGetConfig(fUnixWindow.fDisplay, fVi, GLX_SAMPLES_ARB, &info->fSampleCount); 7164cc810ad165724f9c666a75bd52e41c67f13564bsalomon@google.com glXGetConfig(fUnixWindow.fDisplay, fVi, GLX_STENCIL_SIZE, &info->fStencilBits); 7264cc810ad165724f9c666a75bd52e41c67f13564bsalomon@google.com } else { 7364cc810ad165724f9c666a75bd52e41c67f13564bsalomon@google.com info->fSampleCount = 0; 7464cc810ad165724f9c666a75bd52e41c67f13564bsalomon@google.com info->fStencilBits = 0; 7564cc810ad165724f9c666a75bd52e41c67f13564bsalomon@google.com } 7664cc810ad165724f9c666a75bd52e41c67f13564bsalomon@google.com } 771195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com return; 781195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com } 791195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com fUnixWindow.fDisplay = XOpenDisplay(NULL); 801195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com Display* dsp = fUnixWindow.fDisplay; 811195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com if (NULL == dsp) { 821195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com SkDebugf("Could not open an X Display"); 831195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com return; 841195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com } 851195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com // Attempt to create a window that supports GL 861195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com GLint att[] = { 871195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com GLX_RGBA, 881195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com GLX_DEPTH_SIZE, 24, 891195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com GLX_DOUBLEBUFFER, 901195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com GLX_STENCIL_SIZE, 8, 911195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com None 921195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com }; 931195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com SkASSERT(NULL == fVi); 941195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com if (requestedMSAASampleCount > 0) { 951195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com static const GLint kAttCount = SK_ARRAY_COUNT(att); 961195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com GLint msaaAtt[kAttCount + 4]; 971195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com memcpy(msaaAtt, att, sizeof(att)); 981195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com SkASSERT(None == msaaAtt[kAttCount - 1]); 991195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com msaaAtt[kAttCount - 1] = GLX_SAMPLE_BUFFERS_ARB; 1001195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com msaaAtt[kAttCount + 0] = 1; 1011195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com msaaAtt[kAttCount + 1] = GLX_SAMPLES_ARB; 1021195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com msaaAtt[kAttCount + 2] = requestedMSAASampleCount; 1031195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com msaaAtt[kAttCount + 3] = None; 1041195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com fVi = glXChooseVisual(dsp, DefaultScreen(dsp), msaaAtt); 1051195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com fMSAASampleCount = requestedMSAASampleCount; 1061195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com } 1071195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com if (NULL == fVi) { 1081195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com fVi = glXChooseVisual(dsp, DefaultScreen(dsp), att); 1091195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com fMSAASampleCount = 0; 1101195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com } 1111195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com 1121195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com if (fVi) { 11364cc810ad165724f9c666a75bd52e41c67f13564bsalomon@google.com if (NULL != info) { 11464cc810ad165724f9c666a75bd52e41c67f13564bsalomon@google.com glXGetConfig(dsp, fVi, GLX_SAMPLES_ARB, &info->fSampleCount); 11564cc810ad165724f9c666a75bd52e41c67f13564bsalomon@google.com glXGetConfig(dsp, fVi, GLX_STENCIL_SIZE, &info->fStencilBits); 11664cc810ad165724f9c666a75bd52e41c67f13564bsalomon@google.com } 1171195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com Colormap colorMap = XCreateColormap(dsp, 1181195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com RootWindow(dsp, fVi->screen), 1191195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com fVi->visual, 1201195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com AllocNone); 1211195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com XSetWindowAttributes swa; 1221195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com swa.colormap = colorMap; 1231195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com swa.event_mask = EVENT_MASK; 1241195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com fUnixWindow.fWin = XCreateWindow(dsp, 1251195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com RootWindow(dsp, fVi->screen), 1261195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com 0, 0, // x, y 1271195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com WIDTH, HEIGHT, 1281195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com 0, // border width 1291195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com fVi->depth, 1301195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com InputOutput, 1311195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com fVi->visual, 1321195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com CWEventMask | CWColormap, 1331195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com &swa); 1341195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com } else { 13564cc810ad165724f9c666a75bd52e41c67f13564bsalomon@google.com if (NULL != info) { 13664cc810ad165724f9c666a75bd52e41c67f13564bsalomon@google.com info->fSampleCount = 0; 13764cc810ad165724f9c666a75bd52e41c67f13564bsalomon@google.com info->fStencilBits = 0; 13864cc810ad165724f9c666a75bd52e41c67f13564bsalomon@google.com } 1391195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com // Create a simple window instead. We will not be able to show GL 1401195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com fUnixWindow.fWin = XCreateSimpleWindow(dsp, 1411195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com DefaultRootWindow(dsp), 1421195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com 0, 0, // x, y 1431195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com WIDTH, HEIGHT, 1441195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com 0, // border width 1451195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com 0, // border value 1461195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com 0); // background value 1479df214e836f2b897224178676c03017e9190b7e0Scroggo } 1481195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com this->mapWindowAndWait(); 1491195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com fUnixWindow.fGc = XCreateGC(dsp, fUnixWindow.fWin, 0, NULL); 150b7e9aee1acf27fc98cb37ed69c05da71b4c3c69bscroggo} 151b7e9aee1acf27fc98cb37ed69c05da71b4c3c69bscroggo 15237924183583cf3fdc59b91de0acc26e1fcf2598dreed@google.comstatic unsigned getModi(const XEvent& evt) { 153e378d833489476f68485a64dc437da325e75ee71reed@google.com static const struct { 154e378d833489476f68485a64dc437da325e75ee71reed@google.com unsigned fXMask; 155e378d833489476f68485a64dc437da325e75ee71reed@google.com unsigned fSkMask; 156e378d833489476f68485a64dc437da325e75ee71reed@google.com } gModi[] = { 157e378d833489476f68485a64dc437da325e75ee71reed@google.com // X values found by experiment. Is there a better way? 158e378d833489476f68485a64dc437da325e75ee71reed@google.com { 1, kShift_SkModifierKey }, 159e378d833489476f68485a64dc437da325e75ee71reed@google.com { 4, kControl_SkModifierKey }, 160e378d833489476f68485a64dc437da325e75ee71reed@google.com { 8, kOption_SkModifierKey }, 161e378d833489476f68485a64dc437da325e75ee71reed@google.com }; 1624e73aa1566f2ee9a2525942cab4e885cb51b855cskia.committer@gmail.com 163e378d833489476f68485a64dc437da325e75ee71reed@google.com unsigned modi = 0; 164e378d833489476f68485a64dc437da325e75ee71reed@google.com for (size_t i = 0; i < SK_ARRAY_COUNT(gModi); ++i) { 165e378d833489476f68485a64dc437da325e75ee71reed@google.com if (evt.xkey.state & gModi[i].fXMask) { 166e378d833489476f68485a64dc437da325e75ee71reed@google.com modi |= gModi[i].fSkMask; 167e378d833489476f68485a64dc437da325e75ee71reed@google.com } 168e378d833489476f68485a64dc437da325e75ee71reed@google.com } 169e378d833489476f68485a64dc437da325e75ee71reed@google.com return modi; 1704d5c26de0a24f86c37c1da8b0e30d11a550ea67breed@google.com} 1714d5c26de0a24f86c37c1da8b0e30d11a550ea67breed@google.com 172acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.comstatic SkMSec gTimerDelay; 173acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com 174d1f1b67f5eab110fa0c47c082776d9da1c5fba86reed@google.comstatic bool MyXNextEventWithDelay(Display* dsp, XEvent* evt) { 17504018f37af9d1b231111dc557fa281689b8a4616commit-bot@chromium.org // Check for pending events before entering the select loop. There might 17604018f37af9d1b231111dc557fa281689b8a4616commit-bot@chromium.org // be events in the in-memory queue but not processed yet. 17704018f37af9d1b231111dc557fa281689b8a4616commit-bot@chromium.org if (XPending(dsp)) { 17804018f37af9d1b231111dc557fa281689b8a4616commit-bot@chromium.org XNextEvent(dsp, evt); 17904018f37af9d1b231111dc557fa281689b8a4616commit-bot@chromium.org return true; 18004018f37af9d1b231111dc557fa281689b8a4616commit-bot@chromium.org } 18104018f37af9d1b231111dc557fa281689b8a4616commit-bot@chromium.org 182acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com SkMSec ms = gTimerDelay; 183acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com if (ms > 0) { 184acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com int x11_fd = ConnectionNumber(dsp); 185acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com fd_set input_fds; 186acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com FD_ZERO(&input_fds); 187acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com FD_SET(x11_fd, &input_fds); 188acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com 189acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com timeval tv; 190acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com tv.tv_sec = ms / 1000; // seconds 191acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com tv.tv_usec = (ms % 1000) * 1000; // microseconds 192a48595d8633208b3e0d46f67a8d530ebbc452ad0skia.committer@gmail.com 193d1f1b67f5eab110fa0c47c082776d9da1c5fba86reed@google.com if (!select(x11_fd + 1, &input_fds, NULL, NULL, &tv)) { 194d1f1b67f5eab110fa0c47c082776d9da1c5fba86reed@google.com if (!XPending(dsp)) { 195d1f1b67f5eab110fa0c47c082776d9da1c5fba86reed@google.com return false; 196d1f1b67f5eab110fa0c47c082776d9da1c5fba86reed@google.com } 197d1f1b67f5eab110fa0c47c082776d9da1c5fba86reed@google.com } 198acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com } 199d1f1b67f5eab110fa0c47c082776d9da1c5fba86reed@google.com XNextEvent(dsp, evt); 200d1f1b67f5eab110fa0c47c082776d9da1c5fba86reed@google.com return true; 201acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com} 202acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com 203acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.comSkOSWindow::NextXEventResult SkOSWindow::nextXEvent() { 204acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com XEvent evt; 205acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com Display* dsp = fUnixWindow.fDisplay; 206acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com 207d1f1b67f5eab110fa0c47c082776d9da1c5fba86reed@google.com if (!MyXNextEventWithDelay(fUnixWindow.fDisplay, &evt)) { 208d1f1b67f5eab110fa0c47c082776d9da1c5fba86reed@google.com return kContinue_NextXEventResult; 209d1f1b67f5eab110fa0c47c082776d9da1c5fba86reed@google.com } 210acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com 211acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com switch (evt.type) { 212acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com case Expose: 213acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com if (0 == evt.xexpose.count) { 214acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com return kPaintRequest_NextXEventResult; 215acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com } 216acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com break; 217acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com case ConfigureNotify: 218acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com this->resize(evt.xconfigure.width, evt.xconfigure.height); 219acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com break; 220acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com case ButtonPress: 221acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com if (evt.xbutton.button == Button1) 222acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com this->handleClick(evt.xbutton.x, evt.xbutton.y, 223acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com SkView::Click::kDown_State, NULL, getModi(evt)); 224acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com break; 225acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com case ButtonRelease: 226acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com if (evt.xbutton.button == Button1) 227acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com this->handleClick(evt.xbutton.x, evt.xbutton.y, 228acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com SkView::Click::kUp_State, NULL, getModi(evt)); 229acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com break; 230acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com case MotionNotify: 231acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com this->handleClick(evt.xmotion.x, evt.xmotion.y, 232acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com SkView::Click::kMoved_State, NULL, getModi(evt)); 233acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com break; 234acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com case KeyPress: { 2355e4fe216892927ae81edd7a22b2b00521920f2f3bungeman@google.com int shiftLevel = (evt.xkey.state & ShiftMask) ? 1 : 0; 236acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com KeySym keysym = XkbKeycodeToKeysym(dsp, evt.xkey.keycode, 237acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com 0, shiftLevel); 238acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com if (keysym == XK_Escape) { 239acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com return kQuitRequest_NextXEventResult; 240acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com } 241acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com this->handleKey(XKeyToSkKey(keysym)); 242acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com long uni = keysym2ucs(keysym); 243acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com if (uni != -1) { 244acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com this->handleChar((SkUnichar) uni); 245acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com } 246acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com break; 247acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com } 248acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com case KeyRelease: 249acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com this->handleKeyUp(XKeyToSkKey(XkbKeycodeToKeysym(dsp, evt.xkey.keycode, 0, 0))); 250acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com break; 251acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com default: 252acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com // Do nothing for other events 253acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com break; 254acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com } 255acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com return kContinue_NextXEventResult; 256acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com} 257acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com 2588108c47b50d13cf55b0265b97d729f354e7a697ebsalomon@google.comvoid SkOSWindow::loop() { 2599df214e836f2b897224178676c03017e9190b7e0Scroggo Display* dsp = fUnixWindow.fDisplay; 2601195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com if (NULL == dsp) { 2611195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com return; 2621195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com } 263d1f1b67f5eab110fa0c47c082776d9da1c5fba86reed@google.com Window win = fUnixWindow.fWin; 264d1f1b67f5eab110fa0c47c082776d9da1c5fba86reed@google.com 265d1f1b67f5eab110fa0c47c082776d9da1c5fba86reed@google.com XSelectInput(dsp, win, EVENT_MASK); 2669df214e836f2b897224178676c03017e9190b7e0Scroggo 267d1f1b67f5eab110fa0c47c082776d9da1c5fba86reed@google.com bool sentExposeEvent = false; 268acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com 269acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com for (;;) { 270d1f1b67f5eab110fa0c47c082776d9da1c5fba86reed@google.com SkEvent::ServiceQueueTimer(); 271d1f1b67f5eab110fa0c47c082776d9da1c5fba86reed@google.com 272d1f1b67f5eab110fa0c47c082776d9da1c5fba86reed@google.com bool moreToDo = SkEvent::ProcessEvent(); 273d1f1b67f5eab110fa0c47c082776d9da1c5fba86reed@google.com 274d1f1b67f5eab110fa0c47c082776d9da1c5fba86reed@google.com if (this->isDirty() && !sentExposeEvent) { 275d1f1b67f5eab110fa0c47c082776d9da1c5fba86reed@google.com sentExposeEvent = true; 276d1f1b67f5eab110fa0c47c082776d9da1c5fba86reed@google.com 277d1f1b67f5eab110fa0c47c082776d9da1c5fba86reed@google.com XEvent evt; 278d1f1b67f5eab110fa0c47c082776d9da1c5fba86reed@google.com sk_bzero(&evt, sizeof(evt)); 279d1f1b67f5eab110fa0c47c082776d9da1c5fba86reed@google.com evt.type = Expose; 280d1f1b67f5eab110fa0c47c082776d9da1c5fba86reed@google.com evt.xexpose.display = dsp; 281d1f1b67f5eab110fa0c47c082776d9da1c5fba86reed@google.com XSendEvent(dsp, win, false, ExposureMask, &evt); 282acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com } 283d1f1b67f5eab110fa0c47c082776d9da1c5fba86reed@google.com 284acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com if (XPending(dsp) || !moreToDo) { 285acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com switch (this->nextXEvent()) { 286acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com case kContinue_NextXEventResult: 2879df214e836f2b897224178676c03017e9190b7e0Scroggo break; 288acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com case kPaintRequest_NextXEventResult: 289d1f1b67f5eab110fa0c47c082776d9da1c5fba86reed@google.com sentExposeEvent = false; 290d1f1b67f5eab110fa0c47c082776d9da1c5fba86reed@google.com if (this->isDirty()) { 291d1f1b67f5eab110fa0c47c082776d9da1c5fba86reed@google.com this->update(NULL); 292d1f1b67f5eab110fa0c47c082776d9da1c5fba86reed@google.com } 293d1f1b67f5eab110fa0c47c082776d9da1c5fba86reed@google.com this->doPaint(); 294acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com break; 295acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com case kQuitRequest_NextXEventResult: 296acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com return; 2979df214e836f2b897224178676c03017e9190b7e0Scroggo } 2989df214e836f2b897224178676c03017e9190b7e0Scroggo } 2999df214e836f2b897224178676c03017e9190b7e0Scroggo } 3009df214e836f2b897224178676c03017e9190b7e0Scroggo} 3019df214e836f2b897224178676c03017e9190b7e0Scroggo 3028108c47b50d13cf55b0265b97d729f354e7a697ebsalomon@google.comvoid SkOSWindow::mapWindowAndWait() { 3031195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com SkASSERT(NULL != fUnixWindow.fDisplay); 3049df214e836f2b897224178676c03017e9190b7e0Scroggo Display* dsp = fUnixWindow.fDisplay; 3059df214e836f2b897224178676c03017e9190b7e0Scroggo Window win = fUnixWindow.fWin; 3069df214e836f2b897224178676c03017e9190b7e0Scroggo XMapWindow(dsp, win); 3079df214e836f2b897224178676c03017e9190b7e0Scroggo 3089df214e836f2b897224178676c03017e9190b7e0Scroggo long eventMask = StructureNotifyMask; 3099df214e836f2b897224178676c03017e9190b7e0Scroggo XSelectInput(dsp, win, eventMask); 3109df214e836f2b897224178676c03017e9190b7e0Scroggo 3119df214e836f2b897224178676c03017e9190b7e0Scroggo // Wait until screen is ready. 3129df214e836f2b897224178676c03017e9190b7e0Scroggo XEvent evt; 3139df214e836f2b897224178676c03017e9190b7e0Scroggo do { 3149df214e836f2b897224178676c03017e9190b7e0Scroggo XNextEvent(dsp, &evt); 3159df214e836f2b897224178676c03017e9190b7e0Scroggo } while(evt.type != MapNotify); 3169df214e836f2b897224178676c03017e9190b7e0Scroggo 317b7e9aee1acf27fc98cb37ed69c05da71b4c3c69bscroggo} 318b7e9aee1acf27fc98cb37ed69c05da71b4c3c69bscroggo 31964cc810ad165724f9c666a75bd52e41c67f13564bsalomon@google.combool SkOSWindow::attach(SkBackEndTypes, int msaaSampleCount, AttachmentInfo* info) { 32064cc810ad165724f9c666a75bd52e41c67f13564bsalomon@google.com this->initWindow(msaaSampleCount, info); 32164cc810ad165724f9c666a75bd52e41c67f13564bsalomon@google.com 3221195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com if (NULL == fUnixWindow.fDisplay) { 3231195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com return false; 324d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com } 3258108c47b50d13cf55b0265b97d729f354e7a697ebsalomon@google.com if (NULL == fUnixWindow.fGLContext) { 3261195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com SkASSERT(NULL != fVi); 3279df214e836f2b897224178676c03017e9190b7e0Scroggo 3288108c47b50d13cf55b0265b97d729f354e7a697ebsalomon@google.com fUnixWindow.fGLContext = glXCreateContext(fUnixWindow.fDisplay, 3298108c47b50d13cf55b0265b97d729f354e7a697ebsalomon@google.com fVi, 3308108c47b50d13cf55b0265b97d729f354e7a697ebsalomon@google.com NULL, 3318108c47b50d13cf55b0265b97d729f354e7a697ebsalomon@google.com GL_TRUE); 3328108c47b50d13cf55b0265b97d729f354e7a697ebsalomon@google.com if (NULL == fUnixWindow.fGLContext) { 3338108c47b50d13cf55b0265b97d729f354e7a697ebsalomon@google.com return false; 3348108c47b50d13cf55b0265b97d729f354e7a697ebsalomon@google.com } 3359df214e836f2b897224178676c03017e9190b7e0Scroggo } 3368108c47b50d13cf55b0265b97d729f354e7a697ebsalomon@google.com glXMakeCurrent(fUnixWindow.fDisplay, 3378108c47b50d13cf55b0265b97d729f354e7a697ebsalomon@google.com fUnixWindow.fWin, 3388108c47b50d13cf55b0265b97d729f354e7a697ebsalomon@google.com fUnixWindow.fGLContext); 3398108c47b50d13cf55b0265b97d729f354e7a697ebsalomon@google.com glViewport(0, 0, 340e1ca705cac4b946993f6cbf798e2a0ba27e739f3reed@google.com SkScalarRoundToInt(this->width()), 341e1ca705cac4b946993f6cbf798e2a0ba27e739f3reed@google.com SkScalarRoundToInt(this->height())); 3428108c47b50d13cf55b0265b97d729f354e7a697ebsalomon@google.com glClearColor(0, 0, 0, 0); 3438108c47b50d13cf55b0265b97d729f354e7a697ebsalomon@google.com glClearStencil(0); 3448108c47b50d13cf55b0265b97d729f354e7a697ebsalomon@google.com glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); 3459df214e836f2b897224178676c03017e9190b7e0Scroggo return true; 346b7e9aee1acf27fc98cb37ed69c05da71b4c3c69bscroggo} 347b7e9aee1acf27fc98cb37ed69c05da71b4c3c69bscroggo 3488108c47b50d13cf55b0265b97d729f354e7a697ebsalomon@google.comvoid SkOSWindow::detach() { 3498108c47b50d13cf55b0265b97d729f354e7a697ebsalomon@google.com if (NULL == fUnixWindow.fDisplay || NULL == fUnixWindow.fGLContext) { 3508108c47b50d13cf55b0265b97d729f354e7a697ebsalomon@google.com return; 3518108c47b50d13cf55b0265b97d729f354e7a697ebsalomon@google.com } 3529df214e836f2b897224178676c03017e9190b7e0Scroggo glXMakeCurrent(fUnixWindow.fDisplay, None, NULL); 3538108c47b50d13cf55b0265b97d729f354e7a697ebsalomon@google.com glXDestroyContext(fUnixWindow.fDisplay, fUnixWindow.fGLContext); 3548108c47b50d13cf55b0265b97d729f354e7a697ebsalomon@google.com fUnixWindow.fGLContext = NULL; 355b7e9aee1acf27fc98cb37ed69c05da71b4c3c69bscroggo} 356b7e9aee1acf27fc98cb37ed69c05da71b4c3c69bscroggo 3578108c47b50d13cf55b0265b97d729f354e7a697ebsalomon@google.comvoid SkOSWindow::present() { 3588108c47b50d13cf55b0265b97d729f354e7a697ebsalomon@google.com if (NULL != fUnixWindow.fDisplay && NULL != fUnixWindow.fGLContext) { 3599df214e836f2b897224178676c03017e9190b7e0Scroggo glXSwapBuffers(fUnixWindow.fDisplay, fUnixWindow.fWin); 3609df214e836f2b897224178676c03017e9190b7e0Scroggo } 361b7e9aee1acf27fc98cb37ed69c05da71b4c3c69bscroggo} 362b7e9aee1acf27fc98cb37ed69c05da71b4c3c69bscroggo 3638108c47b50d13cf55b0265b97d729f354e7a697ebsalomon@google.comvoid SkOSWindow::onSetTitle(const char title[]) { 3641195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com if (NULL == fUnixWindow.fDisplay) { 3658108c47b50d13cf55b0265b97d729f354e7a697ebsalomon@google.com return; 3668108c47b50d13cf55b0265b97d729f354e7a697ebsalomon@google.com } 367b7e9aee1acf27fc98cb37ed69c05da71b4c3c69bscroggo XTextProperty textProp; 368b7e9aee1acf27fc98cb37ed69c05da71b4c3c69bscroggo textProp.value = (unsigned char*)title; 369b7e9aee1acf27fc98cb37ed69c05da71b4c3c69bscroggo textProp.format = 8; 370b7e9aee1acf27fc98cb37ed69c05da71b4c3c69bscroggo textProp.nitems = strlen((char*)textProp.value); 371b7e9aee1acf27fc98cb37ed69c05da71b4c3c69bscroggo textProp.encoding = XA_STRING; 372b7e9aee1acf27fc98cb37ed69c05da71b4c3c69bscroggo XSetWMName(fUnixWindow.fDisplay, fUnixWindow.fWin, &textProp); 373b7e9aee1acf27fc98cb37ed69c05da71b4c3c69bscroggo} 374b7e9aee1acf27fc98cb37ed69c05da71b4c3c69bscroggo 3758108c47b50d13cf55b0265b97d729f354e7a697ebsalomon@google.comstatic bool convertBitmapToXImage(XImage& image, const SkBitmap& bitmap) { 376b66365f5dd8cba718e1657ee3c85b4406e55f17dscroggo sk_bzero(&image, sizeof(image)); 377b66365f5dd8cba718e1657ee3c85b4406e55f17dscroggo 378b66365f5dd8cba718e1657ee3c85b4406e55f17dscroggo int bitsPerPixel = bitmap.bytesPerPixel() * 8; 379b66365f5dd8cba718e1657ee3c85b4406e55f17dscroggo image.width = bitmap.width(); 380b66365f5dd8cba718e1657ee3c85b4406e55f17dscroggo image.height = bitmap.height(); 381b66365f5dd8cba718e1657ee3c85b4406e55f17dscroggo image.format = ZPixmap; 382b66365f5dd8cba718e1657ee3c85b4406e55f17dscroggo image.data = (char*) bitmap.getPixels(); 383b66365f5dd8cba718e1657ee3c85b4406e55f17dscroggo image.byte_order = LSBFirst; 384b66365f5dd8cba718e1657ee3c85b4406e55f17dscroggo image.bitmap_unit = bitsPerPixel; 385b66365f5dd8cba718e1657ee3c85b4406e55f17dscroggo image.bitmap_bit_order = LSBFirst; 386b66365f5dd8cba718e1657ee3c85b4406e55f17dscroggo image.bitmap_pad = bitsPerPixel; 387b66365f5dd8cba718e1657ee3c85b4406e55f17dscroggo image.depth = 24; 388acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com image.bytes_per_line = bitmap.rowBytes() - bitmap.width() * 4; 389b66365f5dd8cba718e1657ee3c85b4406e55f17dscroggo image.bits_per_pixel = bitsPerPixel; 39008526c07f4f530e56b70d4b22f5a4af35d9ebccascroggo return XInitImage(&image); 39108526c07f4f530e56b70d4b22f5a4af35d9ebccascroggo} 39208526c07f4f530e56b70d4b22f5a4af35d9ebccascroggo 39308526c07f4f530e56b70d4b22f5a4af35d9ebccascroggovoid SkOSWindow::doPaint() { 3941195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com if (NULL == fUnixWindow.fDisplay) { 3951195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com return; 3961195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com } 3977fa22f33290e3a1777c781eb059c97d5b674b27acommit-bot@chromium.org // If we are drawing with GL, we don't need XPutImage. 3987fa22f33290e3a1777c781eb059c97d5b674b27acommit-bot@chromium.org if (NULL != fUnixWindow.fGLContext) { 3997fa22f33290e3a1777c781eb059c97d5b674b27acommit-bot@chromium.org return; 4007fa22f33290e3a1777c781eb059c97d5b674b27acommit-bot@chromium.org } 40108526c07f4f530e56b70d4b22f5a4af35d9ebccascroggo // Draw the bitmap to the screen. 40208526c07f4f530e56b70d4b22f5a4af35d9ebccascroggo const SkBitmap& bitmap = getBitmap(); 40308526c07f4f530e56b70d4b22f5a4af35d9ebccascroggo int width = bitmap.width(); 40408526c07f4f530e56b70d4b22f5a4af35d9ebccascroggo int height = bitmap.height(); 40508526c07f4f530e56b70d4b22f5a4af35d9ebccascroggo 4060f185c2709f638c0f4d452cb38b434cadfd15ab9Scroggo XImage image; 4071195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com if (!convertBitmapToXImage(image, bitmap)) { 4081195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com return; 4091195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com } 41008526c07f4f530e56b70d4b22f5a4af35d9ebccascroggo 4111195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com XPutImage(fUnixWindow.fDisplay, 4121195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com fUnixWindow.fWin, 4131195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com fUnixWindow.fGc, 4141195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com &image, 4151195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com 0, 0, // src x,y 4161195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com 0, 0, // dst x,y 4171195925b05ee9d666ea8a8f68fde5d8ca7e49b04bsalomon@google.com width, height); 418b7e9aee1acf27fc98cb37ed69c05da71b4c3c69bscroggo} 419b7e9aee1acf27fc98cb37ed69c05da71b4c3c69bscroggo 420acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com/////////////////////////////////////////////////////////////////////////////// 421b7e9aee1acf27fc98cb37ed69c05da71b4c3c69bscroggo 422acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.comvoid SkEvent::SignalNonEmptyQueue() { 423acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com // nothing to do, since we spin on our event-queue, polling for XPending 424b7e9aee1acf27fc98cb37ed69c05da71b4c3c69bscroggo} 425b7e9aee1acf27fc98cb37ed69c05da71b4c3c69bscroggo 426acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.comvoid SkEvent::SignalQueueTimer(SkMSec delay) { 427acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com // just need to record the delay time. We handle waking up for it in 428acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com // MyXNextEventWithDelay() 429acb3d88cf84adf367c173a7a33cd3b0c379291dcreed@google.com gTimerDelay = delay; 430b7e9aee1acf27fc98cb37ed69c05da71b4c3c69bscroggo} 431