1/* 2 * Copyright 2011 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7#include "SkTypes.h" 8 9#if defined(SK_BUILD_FOR_WIN) 10 11#include "SkLeanWindows.h" 12 13#include <GL/gl.h> 14#include <WindowsX.h> 15#include "win/SkWGL.h" 16#include "SkWindow.h" 17#include "SkCanvas.h" 18#include "SkOSMenu.h" 19#include "SkTime.h" 20#include "SkUtils.h" 21 22#include "SkGraphics.h" 23 24#if SK_ANGLE 25#include "gl/GrGLAssembleInterface.h" 26#include "gl/GrGLInterface.h" 27#include "GLES2/gl2.h" 28#include <EGL/egl.h> 29#include <EGL/eglext.h> 30#endif // SK_ANGLE 31 32const int kDefaultWindowWidth = 500; 33const int kDefaultWindowHeight = 500; 34 35#define GL_CALL(IFACE, X) \ 36 SkASSERT(IFACE); \ 37 do { \ 38 (IFACE)->fFunctions.f##X; \ 39 } while (false) 40 41#define WM_EVENT_CALLBACK (WM_USER+0) 42 43void post_skwinevent(HWND hwnd) 44{ 45 PostMessage(hwnd, WM_EVENT_CALLBACK, 0, 0); 46} 47 48SkTHashMap<void*, SkOSWindow*> SkOSWindow::gHwndToOSWindowMap; 49 50SkOSWindow::SkOSWindow(const void* winInit) { 51 fWinInit = *(const WindowInit*)winInit; 52 53 fHWND = CreateWindow(fWinInit.fClass, NULL, WS_OVERLAPPEDWINDOW, 54 CW_USEDEFAULT, 0, kDefaultWindowWidth, kDefaultWindowHeight, NULL, NULL, 55 fWinInit.fInstance, NULL); 56 gHwndToOSWindowMap.set(fHWND, this); 57#if SK_SUPPORT_GPU 58#if SK_ANGLE 59 fDisplay = EGL_NO_DISPLAY; 60 fContext = EGL_NO_CONTEXT; 61 fSurface = EGL_NO_SURFACE; 62#endif 63 64 fHGLRC = NULL; 65#endif 66 fAttached = kNone_BackEndType; 67 fFullscreen = false; 68} 69 70SkOSWindow::~SkOSWindow() { 71#if SK_SUPPORT_GPU 72 if (fHGLRC) { 73 wglDeleteContext((HGLRC)fHGLRC); 74 } 75#if SK_ANGLE 76 if (EGL_NO_CONTEXT != fContext) { 77 eglDestroyContext(fDisplay, fContext); 78 fContext = EGL_NO_CONTEXT; 79 } 80 81 if (EGL_NO_SURFACE != fSurface) { 82 eglDestroySurface(fDisplay, fSurface); 83 fSurface = EGL_NO_SURFACE; 84 } 85 86 if (EGL_NO_DISPLAY != fDisplay) { 87 eglTerminate(fDisplay); 88 fDisplay = EGL_NO_DISPLAY; 89 } 90#endif // SK_ANGLE 91#endif // SK_SUPPORT_GPU 92 this->closeWindow(); 93} 94 95static SkKey winToskKey(WPARAM vk) { 96 static const struct { 97 WPARAM fVK; 98 SkKey fKey; 99 } gPair[] = { 100 { VK_BACK, kBack_SkKey }, 101 { VK_CLEAR, kBack_SkKey }, 102 { VK_RETURN, kOK_SkKey }, 103 { VK_UP, kUp_SkKey }, 104 { VK_DOWN, kDown_SkKey }, 105 { VK_LEFT, kLeft_SkKey }, 106 { VK_RIGHT, kRight_SkKey } 107 }; 108 for (size_t i = 0; i < SK_ARRAY_COUNT(gPair); i++) { 109 if (gPair[i].fVK == vk) { 110 return gPair[i].fKey; 111 } 112 } 113 return kNONE_SkKey; 114} 115 116static unsigned getModifiers(UINT message) { 117 return 0; // TODO 118} 119 120bool SkOSWindow::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { 121 switch (message) { 122 case WM_KEYDOWN: { 123 SkKey key = winToskKey(wParam); 124 if (kNONE_SkKey != key) { 125 this->handleKey(key); 126 return true; 127 } 128 } break; 129 case WM_KEYUP: { 130 SkKey key = winToskKey(wParam); 131 if (kNONE_SkKey != key) { 132 this->handleKeyUp(key); 133 return true; 134 } 135 } break; 136 case WM_UNICHAR: 137 this->handleChar((SkUnichar) wParam); 138 return true; 139 case WM_CHAR: { 140 const uint16_t* c = reinterpret_cast<uint16_t*>(&wParam); 141 this->handleChar(SkUTF16_NextUnichar(&c)); 142 return true; 143 } break; 144 case WM_SIZE: { 145 INT width = LOWORD(lParam); 146 INT height = HIWORD(lParam); 147 this->resize(width, height); 148 break; 149 } 150 case WM_PAINT: { 151 PAINTSTRUCT ps; 152 HDC hdc = BeginPaint(hWnd, &ps); 153 this->doPaint(hdc); 154 EndPaint(hWnd, &ps); 155 return true; 156 } break; 157 158 case WM_LBUTTONDOWN: 159 this->handleClick(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), 160 Click::kDown_State, NULL, getModifiers(message)); 161 return true; 162 163 case WM_MOUSEMOVE: 164 this->handleClick(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), 165 Click::kMoved_State, NULL, getModifiers(message)); 166 return true; 167 168 case WM_LBUTTONUP: 169 this->handleClick(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), 170 Click::kUp_State, NULL, getModifiers(message)); 171 return true; 172 173 case WM_EVENT_CALLBACK: 174 if (SkEvent::ProcessEvent()) { 175 post_skwinevent(hWnd); 176 } 177 return true; 178 } 179 return false; 180} 181 182void SkOSWindow::doPaint(void* ctx) { 183 this->update(NULL); 184 185 if (kNone_BackEndType == fAttached) 186 { 187 HDC hdc = (HDC)ctx; 188 const SkBitmap& bitmap = this->getBitmap(); 189 190 BITMAPINFO bmi; 191 memset(&bmi, 0, sizeof(bmi)); 192 bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 193 bmi.bmiHeader.biWidth = bitmap.width(); 194 bmi.bmiHeader.biHeight = -bitmap.height(); // top-down image 195 bmi.bmiHeader.biPlanes = 1; 196 bmi.bmiHeader.biBitCount = 32; 197 bmi.bmiHeader.biCompression = BI_RGB; 198 bmi.bmiHeader.biSizeImage = 0; 199 200 // 201 // Do the SetDIBitsToDevice. 202 // 203 // TODO(wjmaclean): 204 // Fix this call to handle SkBitmaps that have rowBytes != width, 205 // i.e. may have padding at the end of lines. The SkASSERT below 206 // may be ignored by builds, and the only obviously safe option 207 // seems to be to copy the bitmap to a temporary (contiguous) 208 // buffer before passing to SetDIBitsToDevice(). 209 SkASSERT(bitmap.width() * bitmap.bytesPerPixel() == bitmap.rowBytes()); 210 int ret = SetDIBitsToDevice(hdc, 211 0, 0, 212 bitmap.width(), bitmap.height(), 213 0, 0, 214 0, bitmap.height(), 215 bitmap.getPixels(), 216 &bmi, 217 DIB_RGB_COLORS); 218 (void)ret; // we're ignoring potential failures for now. 219 } 220} 221 222void SkOSWindow::updateSize() 223{ 224 RECT r; 225 GetWindowRect((HWND)fHWND, &r); 226 this->resize(r.right - r.left, r.bottom - r.top); 227} 228 229void SkOSWindow::onHandleInval(const SkIRect& r) { 230 RECT rect; 231 rect.left = r.fLeft; 232 rect.top = r.fTop; 233 rect.right = r.fRight; 234 rect.bottom = r.fBottom; 235 InvalidateRect((HWND)fHWND, &rect, FALSE); 236} 237 238void SkOSWindow::onAddMenu(const SkOSMenu* sk_menu) 239{ 240} 241 242void SkOSWindow::onSetTitle(const char title[]){ 243 SetWindowTextA((HWND)fHWND, title); 244} 245 246enum { 247 SK_MacReturnKey = 36, 248 SK_MacDeleteKey = 51, 249 SK_MacEndKey = 119, 250 SK_MacLeftKey = 123, 251 SK_MacRightKey = 124, 252 SK_MacDownKey = 125, 253 SK_MacUpKey = 126, 254 255 SK_Mac0Key = 0x52, 256 SK_Mac1Key = 0x53, 257 SK_Mac2Key = 0x54, 258 SK_Mac3Key = 0x55, 259 SK_Mac4Key = 0x56, 260 SK_Mac5Key = 0x57, 261 SK_Mac6Key = 0x58, 262 SK_Mac7Key = 0x59, 263 SK_Mac8Key = 0x5b, 264 SK_Mac9Key = 0x5c 265}; 266 267static SkKey raw2key(uint32_t raw) 268{ 269 static const struct { 270 uint32_t fRaw; 271 SkKey fKey; 272 } gKeys[] = { 273 { SK_MacUpKey, kUp_SkKey }, 274 { SK_MacDownKey, kDown_SkKey }, 275 { SK_MacLeftKey, kLeft_SkKey }, 276 { SK_MacRightKey, kRight_SkKey }, 277 { SK_MacReturnKey, kOK_SkKey }, 278 { SK_MacDeleteKey, kBack_SkKey }, 279 { SK_MacEndKey, kEnd_SkKey }, 280 { SK_Mac0Key, k0_SkKey }, 281 { SK_Mac1Key, k1_SkKey }, 282 { SK_Mac2Key, k2_SkKey }, 283 { SK_Mac3Key, k3_SkKey }, 284 { SK_Mac4Key, k4_SkKey }, 285 { SK_Mac5Key, k5_SkKey }, 286 { SK_Mac6Key, k6_SkKey }, 287 { SK_Mac7Key, k7_SkKey }, 288 { SK_Mac8Key, k8_SkKey }, 289 { SK_Mac9Key, k9_SkKey } 290 }; 291 292 for (unsigned i = 0; i < SK_ARRAY_COUNT(gKeys); i++) 293 if (gKeys[i].fRaw == raw) 294 return gKeys[i].fKey; 295 return kNONE_SkKey; 296} 297 298/////////////////////////////////////////////////////////////////////////////////////// 299 300void SkEvent::SignalNonEmptyQueue() 301{ 302 SkOSWindow::ForAllWindows([](void* hWND, SkOSWindow**) { 303 post_skwinevent((HWND)hWND); 304 }); 305} 306 307static UINT_PTR gTimer; 308 309VOID CALLBACK sk_timer_proc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) 310{ 311 SkEvent::ServiceQueueTimer(); 312 //SkDebugf("timer task fired\n"); 313} 314 315void SkEvent::SignalQueueTimer(SkMSec delay) 316{ 317 if (gTimer) 318 { 319 KillTimer(NULL, gTimer); 320 gTimer = NULL; 321 } 322 if (delay) 323 { 324 gTimer = SetTimer(NULL, 0, delay, sk_timer_proc); 325 //SkDebugf("SetTimer of %d returned %d\n", delay, gTimer); 326 } 327} 328 329#if SK_SUPPORT_GPU 330 331bool SkOSWindow::attachGL(int msaaSampleCount, bool deepColor, AttachmentInfo* info) { 332 HDC dc = GetDC((HWND)fHWND); 333 if (NULL == fHGLRC) { 334 fHGLRC = SkCreateWGLContext(dc, msaaSampleCount, deepColor, 335 kGLPreferCompatibilityProfile_SkWGLContextRequest); 336 if (NULL == fHGLRC) { 337 return false; 338 } 339 glClearStencil(0); 340 glClearColor(0, 0, 0, 0); 341 glStencilMask(0xffffffff); 342 glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); 343 } 344 if (wglMakeCurrent(dc, (HGLRC)fHGLRC)) { 345 // use DescribePixelFormat to get the stencil and color bit depth. 346 int pixelFormat = GetPixelFormat(dc); 347 PIXELFORMATDESCRIPTOR pfd; 348 DescribePixelFormat(dc, pixelFormat, sizeof(pfd), &pfd); 349 info->fStencilBits = pfd.cStencilBits; 350 // pfd.cColorBits includes alpha, so it will be 32 in 8/8/8/8 and 10/10/10/2 351 info->fColorBits = pfd.cRedBits + pfd.cGreenBits + pfd.cBlueBits; 352 353 // Get sample count if the MSAA WGL extension is present 354 SkWGLExtensions extensions; 355 if (extensions.hasExtension(dc, "WGL_ARB_multisample")) { 356 static const int kSampleCountAttr = SK_WGL_SAMPLES; 357 extensions.getPixelFormatAttribiv(dc, 358 pixelFormat, 359 0, 360 1, 361 &kSampleCountAttr, 362 &info->fSampleCount); 363 } else { 364 info->fSampleCount = 0; 365 } 366 367 glViewport(0, 0, 368 SkScalarRoundToInt(this->width()), 369 SkScalarRoundToInt(this->height())); 370 return true; 371 } 372 return false; 373} 374 375void SkOSWindow::detachGL() { 376 wglMakeCurrent(GetDC((HWND)fHWND), 0); 377 wglDeleteContext((HGLRC)fHGLRC); 378 fHGLRC = NULL; 379} 380 381void SkOSWindow::presentGL() { 382 HDC dc = GetDC((HWND)fHWND); 383 SwapBuffers(dc); 384 ReleaseDC((HWND)fHWND, dc); 385} 386 387#if SK_ANGLE 388 389static void* get_angle_egl_display(void* nativeDisplay) { 390 PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT; 391 eglGetPlatformDisplayEXT = 392 (PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress("eglGetPlatformDisplayEXT"); 393 394 // We expect ANGLE to support this extension 395 if (!eglGetPlatformDisplayEXT) { 396 return EGL_NO_DISPLAY; 397 } 398 399 EGLDisplay display = EGL_NO_DISPLAY; 400 // Try for an ANGLE D3D11 context, fall back to D3D9, and finally GL. 401 EGLint attribs[3][3] = { 402 { 403 EGL_PLATFORM_ANGLE_TYPE_ANGLE, 404 EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, 405 EGL_NONE 406 }, 407 { 408 EGL_PLATFORM_ANGLE_TYPE_ANGLE, 409 EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE, 410 EGL_NONE 411 }, 412 }; 413 for (int i = 0; i < 3 && display == EGL_NO_DISPLAY; ++i) { 414 display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE,nativeDisplay, attribs[i]); 415 } 416 return display; 417} 418 419struct ANGLEAssembleContext { 420 ANGLEAssembleContext() { 421 fEGL = GetModuleHandle("libEGL.dll"); 422 fGL = GetModuleHandle("libGLESv2.dll"); 423 } 424 425 bool isValid() const { return SkToBool(fEGL) && SkToBool(fGL); } 426 427 HMODULE fEGL; 428 HMODULE fGL; 429}; 430 431static GrGLFuncPtr angle_get_gl_proc(void* ctx, const char name[]) { 432 const ANGLEAssembleContext& context = *reinterpret_cast<const ANGLEAssembleContext*>(ctx); 433 GrGLFuncPtr proc = (GrGLFuncPtr) GetProcAddress(context.fGL, name); 434 if (proc) { 435 return proc; 436 } 437 proc = (GrGLFuncPtr) GetProcAddress(context.fEGL, name); 438 if (proc) { 439 return proc; 440 } 441 return eglGetProcAddress(name); 442} 443 444static const GrGLInterface* get_angle_gl_interface() { 445 ANGLEAssembleContext context; 446 if (!context.isValid()) { 447 return nullptr; 448 } 449 return GrGLAssembleGLESInterface(&context, angle_get_gl_proc); 450} 451 452bool create_ANGLE(EGLNativeWindowType hWnd, 453 int msaaSampleCount, 454 EGLDisplay* eglDisplay, 455 EGLContext* eglContext, 456 EGLSurface* eglSurface, 457 EGLConfig* eglConfig) { 458 static const EGLint contextAttribs[] = { 459 EGL_CONTEXT_CLIENT_VERSION, 2, 460 EGL_NONE, EGL_NONE 461 }; 462 static const EGLint configAttribList[] = { 463 EGL_RED_SIZE, 8, 464 EGL_GREEN_SIZE, 8, 465 EGL_BLUE_SIZE, 8, 466 EGL_ALPHA_SIZE, 8, 467 EGL_DEPTH_SIZE, 8, 468 EGL_STENCIL_SIZE, 8, 469 EGL_NONE 470 }; 471 static const EGLint surfaceAttribList[] = { 472 EGL_NONE, EGL_NONE 473 }; 474 475 EGLDisplay display = get_angle_egl_display(GetDC(hWnd)); 476 477 if (EGL_NO_DISPLAY == display) { 478 SkDebugf("Could not create ANGLE egl display!\n"); 479 return false; 480 } 481 482 // Initialize EGL 483 EGLint majorVersion, minorVersion; 484 if (!eglInitialize(display, &majorVersion, &minorVersion)) { 485 return false; 486 } 487 488 EGLint numConfigs; 489 if (!eglGetConfigs(display, NULL, 0, &numConfigs)) { 490 return false; 491 } 492 493 // Choose config 494 bool foundConfig = false; 495 if (msaaSampleCount) { 496 static const int kConfigAttribListCnt = 497 SK_ARRAY_COUNT(configAttribList); 498 EGLint msaaConfigAttribList[kConfigAttribListCnt + 4]; 499 memcpy(msaaConfigAttribList, 500 configAttribList, 501 sizeof(configAttribList)); 502 SkASSERT(EGL_NONE == msaaConfigAttribList[kConfigAttribListCnt - 1]); 503 msaaConfigAttribList[kConfigAttribListCnt - 1] = EGL_SAMPLE_BUFFERS; 504 msaaConfigAttribList[kConfigAttribListCnt + 0] = 1; 505 msaaConfigAttribList[kConfigAttribListCnt + 1] = EGL_SAMPLES; 506 msaaConfigAttribList[kConfigAttribListCnt + 2] = msaaSampleCount; 507 msaaConfigAttribList[kConfigAttribListCnt + 3] = EGL_NONE; 508 if (eglChooseConfig(display, msaaConfigAttribList, eglConfig, 1, &numConfigs)) { 509 SkASSERT(numConfigs > 0); 510 foundConfig = true; 511 } 512 } 513 if (!foundConfig) { 514 if (!eglChooseConfig(display, configAttribList, eglConfig, 1, &numConfigs)) { 515 return false; 516 } 517 } 518 519 // Create a surface 520 EGLSurface surface = eglCreateWindowSurface(display, *eglConfig, 521 (EGLNativeWindowType)hWnd, 522 surfaceAttribList); 523 if (surface == EGL_NO_SURFACE) { 524 return false; 525 } 526 527 // Create a GL context 528 EGLContext context = eglCreateContext(display, *eglConfig, 529 EGL_NO_CONTEXT, 530 contextAttribs ); 531 if (context == EGL_NO_CONTEXT ) { 532 return false; 533 } 534 535 // Make the context current 536 if (!eglMakeCurrent(display, surface, surface, context)) { 537 return false; 538 } 539 540 *eglDisplay = display; 541 *eglContext = context; 542 *eglSurface = surface; 543 return true; 544} 545 546bool SkOSWindow::attachANGLE(int msaaSampleCount, AttachmentInfo* info) { 547 if (EGL_NO_DISPLAY == fDisplay) { 548 bool bResult = create_ANGLE((HWND)fHWND, 549 msaaSampleCount, 550 &fDisplay, 551 &fContext, 552 &fSurface, 553 &fConfig); 554 if (false == bResult) { 555 return false; 556 } 557 fANGLEInterface.reset(get_angle_gl_interface()); 558 if (!fANGLEInterface) { 559 this->detachANGLE(); 560 return false; 561 } 562 GL_CALL(fANGLEInterface, ClearStencil(0)); 563 GL_CALL(fANGLEInterface, ClearColor(0, 0, 0, 0)); 564 GL_CALL(fANGLEInterface, StencilMask(0xffffffff)); 565 GL_CALL(fANGLEInterface, Clear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT)); 566 } 567 if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) { 568 this->detachANGLE(); 569 return false; 570 } 571 eglGetConfigAttrib(fDisplay, fConfig, EGL_STENCIL_SIZE, &info->fStencilBits); 572 eglGetConfigAttrib(fDisplay, fConfig, EGL_SAMPLES, &info->fSampleCount); 573 574 GL_CALL(fANGLEInterface, Viewport(0, 0, SkScalarRoundToInt(this->width()), 575 SkScalarRoundToInt(this->height()))); 576 return true; 577} 578 579void SkOSWindow::detachANGLE() { 580 fANGLEInterface.reset(nullptr); 581 eglMakeCurrent(fDisplay, EGL_NO_SURFACE , EGL_NO_SURFACE , EGL_NO_CONTEXT); 582 583 eglDestroyContext(fDisplay, fContext); 584 fContext = EGL_NO_CONTEXT; 585 586 eglDestroySurface(fDisplay, fSurface); 587 fSurface = EGL_NO_SURFACE; 588 589 eglTerminate(fDisplay); 590 fDisplay = EGL_NO_DISPLAY; 591} 592 593void SkOSWindow::presentANGLE() { 594 GL_CALL(fANGLEInterface, Flush()); 595 596 eglSwapBuffers(fDisplay, fSurface); 597} 598#endif // SK_ANGLE 599 600#endif // SK_SUPPORT_GPU 601 602// return true on success 603bool SkOSWindow::attach(SkBackEndTypes attachType, int msaaSampleCount, bool deepColor, 604 AttachmentInfo* info) { 605 606 // attach doubles as "windowResize" so we need to allo 607 // already bound states to pass through again 608 // TODO: split out the resize functionality 609// SkASSERT(kNone_BackEndType == fAttached); 610 bool result = true; 611 612 switch (attachType) { 613 case kNone_BackEndType: 614 // nothing to do 615 break; 616#if SK_SUPPORT_GPU 617 case kNativeGL_BackEndType: 618 result = attachGL(msaaSampleCount, deepColor, info); 619 break; 620#if SK_ANGLE 621 case kANGLE_BackEndType: 622 result = attachANGLE(msaaSampleCount, info); 623 break; 624#endif // SK_ANGLE 625#endif // SK_SUPPORT_GPU 626 default: 627 SkASSERT(false); 628 result = false; 629 break; 630 } 631 632 if (result) { 633 fAttached = attachType; 634 } 635 636 return result; 637} 638 639void SkOSWindow::release() { 640 switch (fAttached) { 641 case kNone_BackEndType: 642 // nothing to do 643 break; 644#if SK_SUPPORT_GPU 645 case kNativeGL_BackEndType: 646 detachGL(); 647 break; 648#if SK_ANGLE 649 case kANGLE_BackEndType: 650 detachANGLE(); 651 break; 652#endif // SK_ANGLE 653#endif // SK_SUPPORT_GPU 654 default: 655 SkASSERT(false); 656 break; 657 } 658 fAttached = kNone_BackEndType; 659} 660 661void SkOSWindow::present() { 662 switch (fAttached) { 663 case kNone_BackEndType: 664 // nothing to do 665 return; 666#if SK_SUPPORT_GPU 667 case kNativeGL_BackEndType: 668 presentGL(); 669 break; 670#if SK_ANGLE 671 case kANGLE_BackEndType: 672 presentANGLE(); 673 break; 674#endif // SK_ANGLE 675#endif // SK_SUPPORT_GPU 676 default: 677 SkASSERT(false); 678 break; 679 } 680} 681 682bool SkOSWindow::makeFullscreen() { 683 if (fFullscreen) { 684 return true; 685 } 686#if SK_SUPPORT_GPU 687 if (fHGLRC) { 688 this->detachGL(); 689 } 690#endif // SK_SUPPORT_GPU 691 // This is hacked together from various sources on the web. It can certainly be improved and be 692 // made more robust. 693 694 // Save current window/resolution information. We do this in case we ever implement switching 695 // back to windowed mode. 696 fSavedWindowState.fZoomed = SkToBool(IsZoomed((HWND)fHWND)); 697 if (fSavedWindowState.fZoomed) { 698 SendMessage((HWND)fHWND, WM_SYSCOMMAND, SC_RESTORE, 0); 699 } 700 fSavedWindowState.fStyle = GetWindowLong((HWND)fHWND, GWL_STYLE); 701 fSavedWindowState.fExStyle = GetWindowLong((HWND)fHWND, GWL_EXSTYLE); 702 GetWindowRect((HWND)fHWND, &fSavedWindowState.fRect); 703 DEVMODE currScreenSettings; 704 memset(&currScreenSettings,0,sizeof(currScreenSettings)); 705 currScreenSettings.dmSize = sizeof(currScreenSettings); 706 EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &currScreenSettings); 707 fSavedWindowState.fScreenWidth = currScreenSettings.dmPelsWidth; 708 fSavedWindowState.fScreenHeight = currScreenSettings.dmPelsHeight; 709 fSavedWindowState.fScreenBits = currScreenSettings.dmBitsPerPel; 710 fSavedWindowState.fHWND = fHWND; 711 712 // Try different sizes to find an allowed setting? Use ChangeDisplaySettingsEx? 713 static const int kWidth = 1280; 714 static const int kHeight = 1024; 715 DEVMODE newScreenSettings; 716 memset(&newScreenSettings, 0, sizeof(newScreenSettings)); 717 newScreenSettings.dmSize = sizeof(newScreenSettings); 718 newScreenSettings.dmPelsWidth = kWidth; 719 newScreenSettings.dmPelsHeight = kHeight; 720 newScreenSettings.dmBitsPerPel = 32; 721 newScreenSettings.dmFields = DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT; 722 if (ChangeDisplaySettings(&newScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) { 723 return false; 724 } 725 RECT WindowRect; 726 WindowRect.left = 0; 727 WindowRect.right = kWidth; 728 WindowRect.top = 0; 729 WindowRect.bottom = kHeight; 730 ShowCursor(FALSE); 731 AdjustWindowRectEx(&WindowRect, WS_POPUP, FALSE, WS_EX_APPWINDOW); 732 HWND fsHWND = CreateWindowEx( 733 WS_EX_APPWINDOW, 734 fWinInit.fClass, 735 NULL, 736 WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_POPUP, 737 0, 0, WindowRect.right-WindowRect.left, WindowRect.bottom-WindowRect.top, 738 NULL, 739 NULL, 740 fWinInit.fInstance, 741 NULL 742 ); 743 if (!fsHWND) { 744 return false; 745 } 746 // Hide the old window and set the entry in the global mapping for this SkOSWindow to the 747 // new HWND. 748 ShowWindow((HWND)fHWND, SW_HIDE); 749 gHwndToOSWindowMap.remove(fHWND); 750 fHWND = fsHWND; 751 gHwndToOSWindowMap.set(fHWND, this); 752 this->updateSize(); 753 754 fFullscreen = true; 755 return true; 756} 757 758void SkOSWindow::setVsync(bool enable) { 759 SkWGLExtensions wgl; 760 wgl.swapInterval(enable ? 1 : 0); 761} 762 763void SkOSWindow::closeWindow() { 764 DestroyWindow((HWND)fHWND); 765 if (fFullscreen) { 766 DestroyWindow((HWND)fSavedWindowState.fHWND); 767 } 768 gHwndToOSWindowMap.remove(fHWND); 769} 770#endif 771