1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci* Copyright 2016 Google Inc. 3cb93a386Sopenharmony_ci* 4cb93a386Sopenharmony_ci* Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci* f 49 6cb93a386Sopenharmony_ci* Prev 7cb93a386Sopenharmony_ci* Up 8cb93a386Sopenharmony_ci* 9cb93a386Sopenharmony_ci* 10cb93a386Sopenharmony_ci* found in the LICENSE file. 11cb93a386Sopenharmony_ci*/ 12cb93a386Sopenharmony_ci 13cb93a386Sopenharmony_ci//#include <tchar.h> 14cb93a386Sopenharmony_ci 15cb93a386Sopenharmony_ci#include "tools/sk_app/unix/WindowContextFactory_unix.h" 16cb93a386Sopenharmony_ci 17cb93a386Sopenharmony_ci#include "src/utils/SkUTF.h" 18cb93a386Sopenharmony_ci#include "tools/sk_app/GLWindowContext.h" 19cb93a386Sopenharmony_ci#include "tools/sk_app/unix/Window_unix.h" 20cb93a386Sopenharmony_ci#include "tools/skui/ModifierKey.h" 21cb93a386Sopenharmony_ci#include "tools/timer/Timer.h" 22cb93a386Sopenharmony_ci 23cb93a386Sopenharmony_ciextern "C" { 24cb93a386Sopenharmony_ci #include "tools/sk_app/unix/keysym2ucs.h" 25cb93a386Sopenharmony_ci} 26cb93a386Sopenharmony_ci#include <X11/Xatom.h> 27cb93a386Sopenharmony_ci#include <X11/Xutil.h> 28cb93a386Sopenharmony_ci#include <X11/XKBlib.h> 29cb93a386Sopenharmony_ci 30cb93a386Sopenharmony_cinamespace sk_app { 31cb93a386Sopenharmony_ci 32cb93a386Sopenharmony_ciSkTDynamicHash<Window_unix, XWindow> Window_unix::gWindowMap; 33cb93a386Sopenharmony_ci 34cb93a386Sopenharmony_ciWindow* Window::CreateNativeWindow(void* platformData) { 35cb93a386Sopenharmony_ci Display* display = (Display*)platformData; 36cb93a386Sopenharmony_ci SkASSERT(display); 37cb93a386Sopenharmony_ci 38cb93a386Sopenharmony_ci Window_unix* window = new Window_unix(); 39cb93a386Sopenharmony_ci if (!window->initWindow(display)) { 40cb93a386Sopenharmony_ci delete window; 41cb93a386Sopenharmony_ci return nullptr; 42cb93a386Sopenharmony_ci } 43cb93a386Sopenharmony_ci 44cb93a386Sopenharmony_ci return window; 45cb93a386Sopenharmony_ci} 46cb93a386Sopenharmony_ci 47cb93a386Sopenharmony_ciconst long kEventMask = ExposureMask | StructureNotifyMask | 48cb93a386Sopenharmony_ci KeyPressMask | KeyReleaseMask | 49cb93a386Sopenharmony_ci PointerMotionMask | ButtonPressMask | ButtonReleaseMask; 50cb93a386Sopenharmony_ci 51cb93a386Sopenharmony_cibool Window_unix::initWindow(Display* display) { 52cb93a386Sopenharmony_ci if (fRequestedDisplayParams.fMSAASampleCount != fMSAASampleCount) { 53cb93a386Sopenharmony_ci this->closeWindow(); 54cb93a386Sopenharmony_ci } 55cb93a386Sopenharmony_ci // we already have a window 56cb93a386Sopenharmony_ci if (fDisplay) { 57cb93a386Sopenharmony_ci return true; 58cb93a386Sopenharmony_ci } 59cb93a386Sopenharmony_ci fDisplay = display; 60cb93a386Sopenharmony_ci 61cb93a386Sopenharmony_ci constexpr int initialWidth = 1280; 62cb93a386Sopenharmony_ci constexpr int initialHeight = 960; 63cb93a386Sopenharmony_ci 64cb93a386Sopenharmony_ci // Attempt to create a window that supports GL 65cb93a386Sopenharmony_ci 66cb93a386Sopenharmony_ci // We prefer the more recent glXChooseFBConfig but fall back to glXChooseVisual. They have 67cb93a386Sopenharmony_ci // slight differences in how attributes are specified. 68cb93a386Sopenharmony_ci static int constexpr kChooseFBConfigAtt[] = { 69cb93a386Sopenharmony_ci GLX_RENDER_TYPE, GLX_RGBA_BIT, 70cb93a386Sopenharmony_ci GLX_DOUBLEBUFFER, True, 71cb93a386Sopenharmony_ci GLX_STENCIL_SIZE, 8, 72cb93a386Sopenharmony_ci None 73cb93a386Sopenharmony_ci }; 74cb93a386Sopenharmony_ci // For some reason glXChooseVisual takes a non-const pointer to the attributes. 75cb93a386Sopenharmony_ci int chooseVisualAtt[] = { 76cb93a386Sopenharmony_ci GLX_RGBA, 77cb93a386Sopenharmony_ci GLX_DOUBLEBUFFER, 78cb93a386Sopenharmony_ci GLX_STENCIL_SIZE, 8, 79cb93a386Sopenharmony_ci None 80cb93a386Sopenharmony_ci }; 81cb93a386Sopenharmony_ci SkASSERT(nullptr == fVisualInfo); 82cb93a386Sopenharmony_ci if (fRequestedDisplayParams.fMSAASampleCount > 1) { 83cb93a386Sopenharmony_ci static const GLint kChooseFBConifgAttCnt = SK_ARRAY_COUNT(kChooseFBConfigAtt); 84cb93a386Sopenharmony_ci GLint msaaChooseFBConfigAtt[kChooseFBConifgAttCnt + 4]; 85cb93a386Sopenharmony_ci memcpy(msaaChooseFBConfigAtt, kChooseFBConfigAtt, sizeof(kChooseFBConfigAtt)); 86cb93a386Sopenharmony_ci SkASSERT(None == msaaChooseFBConfigAtt[kChooseFBConifgAttCnt - 1]); 87cb93a386Sopenharmony_ci msaaChooseFBConfigAtt[kChooseFBConifgAttCnt - 1] = GLX_SAMPLE_BUFFERS_ARB; 88cb93a386Sopenharmony_ci msaaChooseFBConfigAtt[kChooseFBConifgAttCnt + 0] = 1; 89cb93a386Sopenharmony_ci msaaChooseFBConfigAtt[kChooseFBConifgAttCnt + 1] = GLX_SAMPLES_ARB; 90cb93a386Sopenharmony_ci msaaChooseFBConfigAtt[kChooseFBConifgAttCnt + 2] = fRequestedDisplayParams.fMSAASampleCount; 91cb93a386Sopenharmony_ci msaaChooseFBConfigAtt[kChooseFBConifgAttCnt + 3] = None; 92cb93a386Sopenharmony_ci int n; 93cb93a386Sopenharmony_ci fFBConfig = glXChooseFBConfig(fDisplay, DefaultScreen(fDisplay), msaaChooseFBConfigAtt, &n); 94cb93a386Sopenharmony_ci if (n > 0) { 95cb93a386Sopenharmony_ci fVisualInfo = glXGetVisualFromFBConfig(fDisplay, *fFBConfig); 96cb93a386Sopenharmony_ci } else { 97cb93a386Sopenharmony_ci static const GLint kChooseVisualAttCnt = SK_ARRAY_COUNT(chooseVisualAtt); 98cb93a386Sopenharmony_ci GLint msaaChooseVisualAtt[kChooseVisualAttCnt + 4]; 99cb93a386Sopenharmony_ci memcpy(msaaChooseVisualAtt, chooseVisualAtt, sizeof(chooseVisualAtt)); 100cb93a386Sopenharmony_ci SkASSERT(None == msaaChooseVisualAtt[kChooseVisualAttCnt - 1]); 101cb93a386Sopenharmony_ci msaaChooseFBConfigAtt[kChooseVisualAttCnt - 1] = GLX_SAMPLE_BUFFERS_ARB; 102cb93a386Sopenharmony_ci msaaChooseFBConfigAtt[kChooseVisualAttCnt + 0] = 1; 103cb93a386Sopenharmony_ci msaaChooseFBConfigAtt[kChooseVisualAttCnt + 1] = GLX_SAMPLES_ARB; 104cb93a386Sopenharmony_ci msaaChooseFBConfigAtt[kChooseVisualAttCnt + 2] = 105cb93a386Sopenharmony_ci fRequestedDisplayParams.fMSAASampleCount; 106cb93a386Sopenharmony_ci msaaChooseFBConfigAtt[kChooseVisualAttCnt + 3] = None; 107cb93a386Sopenharmony_ci fVisualInfo = glXChooseVisual(display, DefaultScreen(display), msaaChooseVisualAtt); 108cb93a386Sopenharmony_ci fFBConfig = nullptr; 109cb93a386Sopenharmony_ci } 110cb93a386Sopenharmony_ci } 111cb93a386Sopenharmony_ci if (nullptr == fVisualInfo) { 112cb93a386Sopenharmony_ci int n; 113cb93a386Sopenharmony_ci fFBConfig = glXChooseFBConfig(fDisplay, DefaultScreen(fDisplay), kChooseFBConfigAtt, &n); 114cb93a386Sopenharmony_ci if (n > 0) { 115cb93a386Sopenharmony_ci fVisualInfo = glXGetVisualFromFBConfig(fDisplay, *fFBConfig); 116cb93a386Sopenharmony_ci } else { 117cb93a386Sopenharmony_ci fVisualInfo = glXChooseVisual(display, DefaultScreen(display), chooseVisualAtt); 118cb93a386Sopenharmony_ci fFBConfig = nullptr; 119cb93a386Sopenharmony_ci } 120cb93a386Sopenharmony_ci } 121cb93a386Sopenharmony_ci 122cb93a386Sopenharmony_ci if (fVisualInfo) { 123cb93a386Sopenharmony_ci Colormap colorMap = XCreateColormap(display, 124cb93a386Sopenharmony_ci RootWindow(display, fVisualInfo->screen), 125cb93a386Sopenharmony_ci fVisualInfo->visual, 126cb93a386Sopenharmony_ci AllocNone); 127cb93a386Sopenharmony_ci XSetWindowAttributes swa; 128cb93a386Sopenharmony_ci swa.colormap = colorMap; 129cb93a386Sopenharmony_ci swa.event_mask = kEventMask; 130cb93a386Sopenharmony_ci fWindow = XCreateWindow(display, 131cb93a386Sopenharmony_ci RootWindow(display, fVisualInfo->screen), 132cb93a386Sopenharmony_ci 0, 0, // x, y 133cb93a386Sopenharmony_ci initialWidth, initialHeight, 134cb93a386Sopenharmony_ci 0, // border width 135cb93a386Sopenharmony_ci fVisualInfo->depth, 136cb93a386Sopenharmony_ci InputOutput, 137cb93a386Sopenharmony_ci fVisualInfo->visual, 138cb93a386Sopenharmony_ci CWEventMask | CWColormap, 139cb93a386Sopenharmony_ci &swa); 140cb93a386Sopenharmony_ci } else { 141cb93a386Sopenharmony_ci // Create a simple window instead. We will not be able to show GL 142cb93a386Sopenharmony_ci fWindow = XCreateSimpleWindow(display, 143cb93a386Sopenharmony_ci DefaultRootWindow(display), 144cb93a386Sopenharmony_ci 0, 0, // x, y 145cb93a386Sopenharmony_ci initialWidth, initialHeight, 146cb93a386Sopenharmony_ci 0, // border width 147cb93a386Sopenharmony_ci 0, // border value 148cb93a386Sopenharmony_ci 0); // background value 149cb93a386Sopenharmony_ci XSelectInput(display, fWindow, kEventMask); 150cb93a386Sopenharmony_ci } 151cb93a386Sopenharmony_ci 152cb93a386Sopenharmony_ci if (!fWindow) { 153cb93a386Sopenharmony_ci return false; 154cb93a386Sopenharmony_ci } 155cb93a386Sopenharmony_ci 156cb93a386Sopenharmony_ci fMSAASampleCount = fRequestedDisplayParams.fMSAASampleCount; 157cb93a386Sopenharmony_ci 158cb93a386Sopenharmony_ci // set up to catch window delete message 159cb93a386Sopenharmony_ci fWmDeleteMessage = XInternAtom(display, "WM_DELETE_WINDOW", False); 160cb93a386Sopenharmony_ci XSetWMProtocols(display, fWindow, &fWmDeleteMessage, 1); 161cb93a386Sopenharmony_ci 162cb93a386Sopenharmony_ci // add to hashtable of windows 163cb93a386Sopenharmony_ci gWindowMap.add(this); 164cb93a386Sopenharmony_ci 165cb93a386Sopenharmony_ci // init event variables 166cb93a386Sopenharmony_ci fPendingPaint = false; 167cb93a386Sopenharmony_ci fPendingResize = false; 168cb93a386Sopenharmony_ci 169cb93a386Sopenharmony_ci return true; 170cb93a386Sopenharmony_ci} 171cb93a386Sopenharmony_ci 172cb93a386Sopenharmony_civoid Window_unix::closeWindow() { 173cb93a386Sopenharmony_ci if (fDisplay) { 174cb93a386Sopenharmony_ci this->detach(); 175cb93a386Sopenharmony_ci if (fGC) { 176cb93a386Sopenharmony_ci XFreeGC(fDisplay, fGC); 177cb93a386Sopenharmony_ci fGC = nullptr; 178cb93a386Sopenharmony_ci } 179cb93a386Sopenharmony_ci gWindowMap.remove(fWindow); 180cb93a386Sopenharmony_ci XDestroyWindow(fDisplay, fWindow); 181cb93a386Sopenharmony_ci fWindow = 0; 182cb93a386Sopenharmony_ci if (fFBConfig) { 183cb93a386Sopenharmony_ci XFree(fFBConfig); 184cb93a386Sopenharmony_ci fFBConfig = nullptr; 185cb93a386Sopenharmony_ci } 186cb93a386Sopenharmony_ci if (fVisualInfo) { 187cb93a386Sopenharmony_ci XFree(fVisualInfo); 188cb93a386Sopenharmony_ci fVisualInfo = nullptr; 189cb93a386Sopenharmony_ci } 190cb93a386Sopenharmony_ci fDisplay = nullptr; 191cb93a386Sopenharmony_ci } 192cb93a386Sopenharmony_ci} 193cb93a386Sopenharmony_ci 194cb93a386Sopenharmony_cistatic skui::Key get_key(KeySym keysym) { 195cb93a386Sopenharmony_ci static const struct { 196cb93a386Sopenharmony_ci KeySym fXK; 197cb93a386Sopenharmony_ci skui::Key fKey; 198cb93a386Sopenharmony_ci } gPair[] = { 199cb93a386Sopenharmony_ci { XK_BackSpace, skui::Key::kBack }, 200cb93a386Sopenharmony_ci { XK_Clear, skui::Key::kBack }, 201cb93a386Sopenharmony_ci { XK_Return, skui::Key::kOK }, 202cb93a386Sopenharmony_ci { XK_Up, skui::Key::kUp }, 203cb93a386Sopenharmony_ci { XK_Down, skui::Key::kDown }, 204cb93a386Sopenharmony_ci { XK_Left, skui::Key::kLeft }, 205cb93a386Sopenharmony_ci { XK_Right, skui::Key::kRight }, 206cb93a386Sopenharmony_ci { XK_Tab, skui::Key::kTab }, 207cb93a386Sopenharmony_ci { XK_Page_Up, skui::Key::kPageUp }, 208cb93a386Sopenharmony_ci { XK_Page_Down, skui::Key::kPageDown }, 209cb93a386Sopenharmony_ci { XK_Home, skui::Key::kHome }, 210cb93a386Sopenharmony_ci { XK_End, skui::Key::kEnd }, 211cb93a386Sopenharmony_ci { XK_Delete, skui::Key::kDelete }, 212cb93a386Sopenharmony_ci { XK_Escape, skui::Key::kEscape }, 213cb93a386Sopenharmony_ci { XK_Shift_L, skui::Key::kShift }, 214cb93a386Sopenharmony_ci { XK_Shift_R, skui::Key::kShift }, 215cb93a386Sopenharmony_ci { XK_Control_L, skui::Key::kCtrl }, 216cb93a386Sopenharmony_ci { XK_Control_R, skui::Key::kCtrl }, 217cb93a386Sopenharmony_ci { XK_Alt_L, skui::Key::kOption }, 218cb93a386Sopenharmony_ci { XK_Alt_R, skui::Key::kOption }, 219cb93a386Sopenharmony_ci { 'a', skui::Key::kA }, 220cb93a386Sopenharmony_ci { 'c', skui::Key::kC }, 221cb93a386Sopenharmony_ci { 'v', skui::Key::kV }, 222cb93a386Sopenharmony_ci { 'x', skui::Key::kX }, 223cb93a386Sopenharmony_ci { 'y', skui::Key::kY }, 224cb93a386Sopenharmony_ci { 'z', skui::Key::kZ }, 225cb93a386Sopenharmony_ci }; 226cb93a386Sopenharmony_ci for (size_t i = 0; i < SK_ARRAY_COUNT(gPair); i++) { 227cb93a386Sopenharmony_ci if (gPair[i].fXK == keysym) { 228cb93a386Sopenharmony_ci return gPair[i].fKey; 229cb93a386Sopenharmony_ci } 230cb93a386Sopenharmony_ci } 231cb93a386Sopenharmony_ci return skui::Key::kNONE; 232cb93a386Sopenharmony_ci} 233cb93a386Sopenharmony_ci 234cb93a386Sopenharmony_cistatic skui::ModifierKey get_modifiers(const XEvent& event) { 235cb93a386Sopenharmony_ci static const struct { 236cb93a386Sopenharmony_ci unsigned fXMask; 237cb93a386Sopenharmony_ci skui::ModifierKey fSkMask; 238cb93a386Sopenharmony_ci } gModifiers[] = { 239cb93a386Sopenharmony_ci { ShiftMask, skui::ModifierKey::kShift }, 240cb93a386Sopenharmony_ci { ControlMask, skui::ModifierKey::kControl }, 241cb93a386Sopenharmony_ci { Mod1Mask, skui::ModifierKey::kOption }, 242cb93a386Sopenharmony_ci }; 243cb93a386Sopenharmony_ci 244cb93a386Sopenharmony_ci skui::ModifierKey modifiers = skui::ModifierKey::kNone; 245cb93a386Sopenharmony_ci for (size_t i = 0; i < SK_ARRAY_COUNT(gModifiers); ++i) { 246cb93a386Sopenharmony_ci if (event.xkey.state & gModifiers[i].fXMask) { 247cb93a386Sopenharmony_ci modifiers |= gModifiers[i].fSkMask; 248cb93a386Sopenharmony_ci } 249cb93a386Sopenharmony_ci } 250cb93a386Sopenharmony_ci return modifiers; 251cb93a386Sopenharmony_ci} 252cb93a386Sopenharmony_ci 253cb93a386Sopenharmony_cibool Window_unix::handleEvent(const XEvent& event) { 254cb93a386Sopenharmony_ci switch (event.type) { 255cb93a386Sopenharmony_ci case MapNotify: 256cb93a386Sopenharmony_ci if (!fGC) { 257cb93a386Sopenharmony_ci fGC = XCreateGC(fDisplay, fWindow, 0, nullptr); 258cb93a386Sopenharmony_ci } 259cb93a386Sopenharmony_ci break; 260cb93a386Sopenharmony_ci 261cb93a386Sopenharmony_ci case ClientMessage: 262cb93a386Sopenharmony_ci if ((Atom)event.xclient.data.l[0] == fWmDeleteMessage && 263cb93a386Sopenharmony_ci gWindowMap.count() == 1) { 264cb93a386Sopenharmony_ci return true; 265cb93a386Sopenharmony_ci } 266cb93a386Sopenharmony_ci break; 267cb93a386Sopenharmony_ci 268cb93a386Sopenharmony_ci case ButtonPress: 269cb93a386Sopenharmony_ci switch (event.xbutton.button) { 270cb93a386Sopenharmony_ci case Button1: 271cb93a386Sopenharmony_ci this->onMouse(event.xbutton.x, event.xbutton.y, 272cb93a386Sopenharmony_ci skui::InputState::kDown, get_modifiers(event)); 273cb93a386Sopenharmony_ci break; 274cb93a386Sopenharmony_ci case Button4: 275cb93a386Sopenharmony_ci this->onMouseWheel(1.0f, get_modifiers(event)); 276cb93a386Sopenharmony_ci break; 277cb93a386Sopenharmony_ci case Button5: 278cb93a386Sopenharmony_ci this->onMouseWheel(-1.0f, get_modifiers(event)); 279cb93a386Sopenharmony_ci break; 280cb93a386Sopenharmony_ci } 281cb93a386Sopenharmony_ci break; 282cb93a386Sopenharmony_ci 283cb93a386Sopenharmony_ci case ButtonRelease: 284cb93a386Sopenharmony_ci if (event.xbutton.button == Button1) { 285cb93a386Sopenharmony_ci this->onMouse(event.xbutton.x, event.xbutton.y, 286cb93a386Sopenharmony_ci skui::InputState::kUp, get_modifiers(event)); 287cb93a386Sopenharmony_ci } 288cb93a386Sopenharmony_ci break; 289cb93a386Sopenharmony_ci 290cb93a386Sopenharmony_ci case MotionNotify: 291cb93a386Sopenharmony_ci this->onMouse(event.xmotion.x, event.xmotion.y, 292cb93a386Sopenharmony_ci skui::InputState::kMove, get_modifiers(event)); 293cb93a386Sopenharmony_ci break; 294cb93a386Sopenharmony_ci 295cb93a386Sopenharmony_ci case KeyPress: { 296cb93a386Sopenharmony_ci int shiftLevel = (event.xkey.state & ShiftMask) ? 1 : 0; 297cb93a386Sopenharmony_ci KeySym keysym = XkbKeycodeToKeysym(fDisplay, event.xkey.keycode, 0, shiftLevel); 298cb93a386Sopenharmony_ci skui::Key key = get_key(keysym); 299cb93a386Sopenharmony_ci if (key != skui::Key::kNONE) { 300cb93a386Sopenharmony_ci if (!this->onKey(key, skui::InputState::kDown, get_modifiers(event))) { 301cb93a386Sopenharmony_ci if (keysym == XK_Escape) { 302cb93a386Sopenharmony_ci return true; 303cb93a386Sopenharmony_ci } 304cb93a386Sopenharmony_ci } 305cb93a386Sopenharmony_ci } 306cb93a386Sopenharmony_ci 307cb93a386Sopenharmony_ci long uni = keysym2ucs(keysym); 308cb93a386Sopenharmony_ci if (uni != -1) { 309cb93a386Sopenharmony_ci (void) this->onChar((SkUnichar) uni, get_modifiers(event)); 310cb93a386Sopenharmony_ci } 311cb93a386Sopenharmony_ci } break; 312cb93a386Sopenharmony_ci 313cb93a386Sopenharmony_ci case KeyRelease: { 314cb93a386Sopenharmony_ci int shiftLevel = (event.xkey.state & ShiftMask) ? 1 : 0; 315cb93a386Sopenharmony_ci KeySym keysym = XkbKeycodeToKeysym(fDisplay, event.xkey.keycode, 316cb93a386Sopenharmony_ci 0, shiftLevel); 317cb93a386Sopenharmony_ci skui::Key key = get_key(keysym); 318cb93a386Sopenharmony_ci (void) this->onKey(key, skui::InputState::kUp, 319cb93a386Sopenharmony_ci get_modifiers(event)); 320cb93a386Sopenharmony_ci } break; 321cb93a386Sopenharmony_ci 322cb93a386Sopenharmony_ci case SelectionClear: { 323cb93a386Sopenharmony_ci // Lost selection ownership 324cb93a386Sopenharmony_ci fClipboardText.clear(); 325cb93a386Sopenharmony_ci } break; 326cb93a386Sopenharmony_ci 327cb93a386Sopenharmony_ci case SelectionRequest: { 328cb93a386Sopenharmony_ci Atom UTF8 = XInternAtom(fDisplay, "UTF8_STRING", 0), 329cb93a386Sopenharmony_ci CLIPBOARD = XInternAtom(fDisplay, "CLIPBOARD", 0); 330cb93a386Sopenharmony_ci 331cb93a386Sopenharmony_ci const XSelectionRequestEvent* xsr = &event.xselectionrequest; 332cb93a386Sopenharmony_ci 333cb93a386Sopenharmony_ci XSelectionEvent xsel = {}; 334cb93a386Sopenharmony_ci xsel.type = SelectionNotify; 335cb93a386Sopenharmony_ci xsel.requestor = xsr->requestor; 336cb93a386Sopenharmony_ci xsel.selection = xsr->selection; 337cb93a386Sopenharmony_ci xsel.target = xsr->target; 338cb93a386Sopenharmony_ci xsel.property = xsr->property; 339cb93a386Sopenharmony_ci xsel.time = xsr->time; 340cb93a386Sopenharmony_ci 341cb93a386Sopenharmony_ci if (xsr->selection != CLIPBOARD) { 342cb93a386Sopenharmony_ci // A request for a different kind of selection. This shouldn't happen. 343cb93a386Sopenharmony_ci break; 344cb93a386Sopenharmony_ci } 345cb93a386Sopenharmony_ci 346cb93a386Sopenharmony_ci if (fClipboardText.empty() || xsr->target != UTF8 || xsr->property == None) { 347cb93a386Sopenharmony_ci // We can't fulfill this request. Deny it. 348cb93a386Sopenharmony_ci xsel.property = None; 349cb93a386Sopenharmony_ci XSendEvent(fDisplay, xsr->requestor, True, NoEventMask, (XEvent*)&xsel); 350cb93a386Sopenharmony_ci } else { 351cb93a386Sopenharmony_ci // We can fulfill this request! Update the contents of the CLIPBOARD property, 352cb93a386Sopenharmony_ci // and let the requestor know. 353cb93a386Sopenharmony_ci XChangeProperty(fDisplay, xsr->requestor, xsr->property, UTF8, /*format=*/8, 354cb93a386Sopenharmony_ci PropModeReplace, (unsigned char*)fClipboardText.data(), 355cb93a386Sopenharmony_ci fClipboardText.length()); 356cb93a386Sopenharmony_ci XSendEvent(fDisplay, xsr->requestor, True, NoEventMask, (XEvent*)&xsel); 357cb93a386Sopenharmony_ci } 358cb93a386Sopenharmony_ci } break; 359cb93a386Sopenharmony_ci 360cb93a386Sopenharmony_ci default: 361cb93a386Sopenharmony_ci // these events should be handled in the main event loop 362cb93a386Sopenharmony_ci SkASSERT(event.type != Expose && event.type != ConfigureNotify); 363cb93a386Sopenharmony_ci break; 364cb93a386Sopenharmony_ci } 365cb93a386Sopenharmony_ci 366cb93a386Sopenharmony_ci return false; 367cb93a386Sopenharmony_ci} 368cb93a386Sopenharmony_ci 369cb93a386Sopenharmony_civoid Window_unix::setTitle(const char* title) { 370cb93a386Sopenharmony_ci XTextProperty textproperty; 371cb93a386Sopenharmony_ci if (!XStringListToTextProperty(const_cast<char**>(&title), 1, &textproperty)) { 372cb93a386Sopenharmony_ci return; 373cb93a386Sopenharmony_ci } 374cb93a386Sopenharmony_ci XSetWMName(fDisplay, fWindow, &textproperty); 375cb93a386Sopenharmony_ci XFree(textproperty.value); 376cb93a386Sopenharmony_ci} 377cb93a386Sopenharmony_ci 378cb93a386Sopenharmony_civoid Window_unix::show() { 379cb93a386Sopenharmony_ci XMapWindow(fDisplay, fWindow); 380cb93a386Sopenharmony_ci} 381cb93a386Sopenharmony_ci 382cb93a386Sopenharmony_cibool Window_unix::attach(BackendType attachType) { 383cb93a386Sopenharmony_ci fBackend = attachType; 384cb93a386Sopenharmony_ci 385cb93a386Sopenharmony_ci this->initWindow(fDisplay); 386cb93a386Sopenharmony_ci 387cb93a386Sopenharmony_ci window_context_factory::XlibWindowInfo winInfo; 388cb93a386Sopenharmony_ci winInfo.fDisplay = fDisplay; 389cb93a386Sopenharmony_ci winInfo.fWindow = fWindow; 390cb93a386Sopenharmony_ci winInfo.fFBConfig = fFBConfig; 391cb93a386Sopenharmony_ci winInfo.fVisualInfo = fVisualInfo; 392cb93a386Sopenharmony_ci 393cb93a386Sopenharmony_ci XWindowAttributes attrs; 394cb93a386Sopenharmony_ci if (XGetWindowAttributes(fDisplay, fWindow, &attrs)) { 395cb93a386Sopenharmony_ci winInfo.fWidth = attrs.width; 396cb93a386Sopenharmony_ci winInfo.fHeight = attrs.height; 397cb93a386Sopenharmony_ci } else { 398cb93a386Sopenharmony_ci winInfo.fWidth = winInfo.fHeight = 0; 399cb93a386Sopenharmony_ci } 400cb93a386Sopenharmony_ci 401cb93a386Sopenharmony_ci switch (attachType) { 402cb93a386Sopenharmony_ci#ifdef SK_DAWN 403cb93a386Sopenharmony_ci case kDawn_BackendType: 404cb93a386Sopenharmony_ci fWindowContext = 405cb93a386Sopenharmony_ci window_context_factory::MakeDawnVulkanForXlib(winInfo, fRequestedDisplayParams); 406cb93a386Sopenharmony_ci break; 407cb93a386Sopenharmony_ci#endif 408cb93a386Sopenharmony_ci#ifdef SK_VULKAN 409cb93a386Sopenharmony_ci case kVulkan_BackendType: 410cb93a386Sopenharmony_ci fWindowContext = 411cb93a386Sopenharmony_ci window_context_factory::MakeVulkanForXlib(winInfo, fRequestedDisplayParams); 412cb93a386Sopenharmony_ci break; 413cb93a386Sopenharmony_ci#endif 414cb93a386Sopenharmony_ci#ifdef SK_GL 415cb93a386Sopenharmony_ci case kNativeGL_BackendType: 416cb93a386Sopenharmony_ci fWindowContext = 417cb93a386Sopenharmony_ci window_context_factory::MakeGLForXlib(winInfo, fRequestedDisplayParams); 418cb93a386Sopenharmony_ci break; 419cb93a386Sopenharmony_ci#endif 420cb93a386Sopenharmony_ci case kRaster_BackendType: 421cb93a386Sopenharmony_ci fWindowContext = 422cb93a386Sopenharmony_ci window_context_factory::MakeRasterForXlib(winInfo, fRequestedDisplayParams); 423cb93a386Sopenharmony_ci break; 424cb93a386Sopenharmony_ci } 425cb93a386Sopenharmony_ci this->onBackendCreated(); 426cb93a386Sopenharmony_ci 427cb93a386Sopenharmony_ci return (SkToBool(fWindowContext)); 428cb93a386Sopenharmony_ci} 429cb93a386Sopenharmony_ci 430cb93a386Sopenharmony_civoid Window_unix::onInval() { 431cb93a386Sopenharmony_ci XEvent event; 432cb93a386Sopenharmony_ci event.type = Expose; 433cb93a386Sopenharmony_ci event.xexpose.send_event = True; 434cb93a386Sopenharmony_ci event.xexpose.display = fDisplay; 435cb93a386Sopenharmony_ci event.xexpose.window = fWindow; 436cb93a386Sopenharmony_ci event.xexpose.x = 0; 437cb93a386Sopenharmony_ci event.xexpose.y = 0; 438cb93a386Sopenharmony_ci event.xexpose.width = this->width(); 439cb93a386Sopenharmony_ci event.xexpose.height = this->height(); 440cb93a386Sopenharmony_ci event.xexpose.count = 0; 441cb93a386Sopenharmony_ci 442cb93a386Sopenharmony_ci XSendEvent(fDisplay, fWindow, False, 0, &event); 443cb93a386Sopenharmony_ci} 444cb93a386Sopenharmony_ci 445cb93a386Sopenharmony_civoid Window_unix::setRequestedDisplayParams(const DisplayParams& params, bool allowReattach) { 446cb93a386Sopenharmony_ci#if defined(SK_VULKAN) 447cb93a386Sopenharmony_ci // Vulkan on unix crashes if we try to reinitialize the vulkan context without remaking the 448cb93a386Sopenharmony_ci // window. 449cb93a386Sopenharmony_ci if (fBackend == kVulkan_BackendType && allowReattach) { 450cb93a386Sopenharmony_ci // Need to change these early, so attach() creates the window context correctly 451cb93a386Sopenharmony_ci fRequestedDisplayParams = params; 452cb93a386Sopenharmony_ci 453cb93a386Sopenharmony_ci this->detach(); 454cb93a386Sopenharmony_ci this->attach(fBackend); 455cb93a386Sopenharmony_ci return; 456cb93a386Sopenharmony_ci } 457cb93a386Sopenharmony_ci#endif 458cb93a386Sopenharmony_ci 459cb93a386Sopenharmony_ci INHERITED::setRequestedDisplayParams(params, allowReattach); 460cb93a386Sopenharmony_ci} 461cb93a386Sopenharmony_ci 462cb93a386Sopenharmony_ciconst char* Window_unix::getClipboardText() { 463cb93a386Sopenharmony_ci Atom UTF8 = XInternAtom(fDisplay, "UTF8_STRING", 0), 464cb93a386Sopenharmony_ci CLIPBOARD = XInternAtom(fDisplay, "CLIPBOARD", 0), 465cb93a386Sopenharmony_ci XSEL_DATA = XInternAtom(fDisplay, "XSEL_DATA", 0); 466cb93a386Sopenharmony_ci 467cb93a386Sopenharmony_ci // Ask for a UTF8 copy of the CLIPBOARD... 468cb93a386Sopenharmony_ci XEvent event; 469cb93a386Sopenharmony_ci XConvertSelection(fDisplay, CLIPBOARD, UTF8, XSEL_DATA, fWindow, CurrentTime); 470cb93a386Sopenharmony_ci XSync(fDisplay, 0); 471cb93a386Sopenharmony_ci XNextEvent(fDisplay, &event); 472cb93a386Sopenharmony_ci if (event.type == SelectionNotify && 473cb93a386Sopenharmony_ci event.xselection.selection == CLIPBOARD && 474cb93a386Sopenharmony_ci event.xselection.property != None) { 475cb93a386Sopenharmony_ci 476cb93a386Sopenharmony_ci // We got a response 477cb93a386Sopenharmony_ci Atom type; 478cb93a386Sopenharmony_ci int format; 479cb93a386Sopenharmony_ci unsigned long nitems, bytes_after; 480cb93a386Sopenharmony_ci char* data; 481cb93a386Sopenharmony_ci 482cb93a386Sopenharmony_ci // Fetch the CLIPBOARD property 483cb93a386Sopenharmony_ci XSelectionEvent xsel = event.xselection; 484cb93a386Sopenharmony_ci XGetWindowProperty(xsel.display, xsel.requestor, xsel.property, /*offset=*/0, 485cb93a386Sopenharmony_ci /*length=*/~0L, /*delete=*/False, AnyPropertyType, &type, &format, 486cb93a386Sopenharmony_ci &nitems, &bytes_after, (unsigned char**)&data); 487cb93a386Sopenharmony_ci SkASSERT(bytes_after == 0); 488cb93a386Sopenharmony_ci if (type == UTF8) { 489cb93a386Sopenharmony_ci fClipboardText.assign(data, nitems); 490cb93a386Sopenharmony_ci } 491cb93a386Sopenharmony_ci XFree(data); 492cb93a386Sopenharmony_ci XDeleteProperty(xsel.display, xsel.requestor, xsel.property); 493cb93a386Sopenharmony_ci } 494cb93a386Sopenharmony_ci return fClipboardText.c_str(); 495cb93a386Sopenharmony_ci} 496cb93a386Sopenharmony_ci 497cb93a386Sopenharmony_civoid Window_unix::setClipboardText(const char* text) { 498cb93a386Sopenharmony_ci fClipboardText.assign(text); 499cb93a386Sopenharmony_ci 500cb93a386Sopenharmony_ci // Take ownership of the CLIPBOARD 501cb93a386Sopenharmony_ci Atom CLIPBOARD = XInternAtom(fDisplay, "CLIPBOARD", 0); 502cb93a386Sopenharmony_ci XSetSelectionOwner(fDisplay, CLIPBOARD, fWindow, CurrentTime); 503cb93a386Sopenharmony_ci} 504cb93a386Sopenharmony_ci 505cb93a386Sopenharmony_ci} // namespace sk_app 506