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