OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "ui/gfx/screen_compatible_dc_win.h" |
| 6 |
| 7 #include "base/logging.h" |
| 8 #include "base/memory/singleton.h" |
| 9 #include "base/win/wrapped_window_proc.h" |
| 10 #include "ui/base/win/hwnd_util.h" |
| 11 |
| 12 namespace { |
| 13 |
| 14 // Windows class name to use for the listener window. |
| 15 const wchar_t kWindowClassName[] = L"CachedCompatibleDC_Invalidator"; |
| 16 |
| 17 class CachedCompatibleDC { |
| 18 public: |
| 19 // Singleton getter. |
| 20 static CachedCompatibleDC* GetInstance(); |
| 21 |
| 22 // Returns the cached screen compatible DC or creates one if needed. |
| 23 HDC GetOrCreateCompatibleDC(); |
| 24 |
| 25 // Deletes the cached DC, called on WM_DISPLAYCHANGE notifications. |
| 26 void DeleteCachedCompatibleDC(); |
| 27 |
| 28 private: |
| 29 // Cached device context compatible with the screen. |
| 30 HDC compatible_dc_; |
| 31 |
| 32 // HWND for listening to WM_DISPLAYCHANGE notifications. |
| 33 HWND listener_window_; |
| 34 |
| 35 CachedCompatibleDC(); |
| 36 ~CachedCompatibleDC(); |
| 37 |
| 38 friend struct DefaultSingletonTraits<CachedCompatibleDC>; |
| 39 |
| 40 DISALLOW_COPY_AND_ASSIGN(CachedCompatibleDC); |
| 41 }; |
| 42 |
| 43 // Windows callback for listening for WM_DISPLAYCHANGE messages. |
| 44 LRESULT CALLBACK ListenerWindowProc(HWND hwnd, |
| 45 UINT message, |
| 46 WPARAM wparam, |
| 47 LPARAM lparam) { |
| 48 if (message == WM_DISPLAYCHANGE) |
| 49 CachedCompatibleDC::GetInstance()->DeleteCachedCompatibleDC(); |
| 50 |
| 51 return ::DefWindowProc(hwnd, message, wparam, lparam); |
| 52 } |
| 53 |
| 54 // Creates a listener window to handle WM_DISPLAYCHANGE messages. |
| 55 HWND CreateListenerWindow() { |
| 56 HINSTANCE hinst = 0; |
| 57 if (!::GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, |
| 58 reinterpret_cast<char*>(&ListenerWindowProc), |
| 59 &hinst)) { |
| 60 NOTREACHED(); |
| 61 } |
| 62 |
| 63 WNDCLASSEX wc = {0}; |
| 64 wc.cbSize = sizeof(wc); |
| 65 wc.lpfnWndProc = base::win::WrappedWindowProc<ListenerWindowProc>; |
| 66 wc.hInstance = hinst; |
| 67 wc.lpszClassName = kWindowClassName; |
| 68 ATOM clazz = ::RegisterClassEx(&wc); |
| 69 DCHECK(clazz); |
| 70 |
| 71 return ::CreateWindow(MAKEINTATOM(clazz), 0, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, |
| 72 hinst, 0); |
| 73 } |
| 74 |
| 75 CachedCompatibleDC::CachedCompatibleDC() |
| 76 : compatible_dc_(NULL), |
| 77 listener_window_(NULL) { |
| 78 } |
| 79 |
| 80 CachedCompatibleDC::~CachedCompatibleDC() { |
| 81 DeleteCachedCompatibleDC(); |
| 82 if (listener_window_) { |
| 83 ::DestroyWindow(listener_window_); |
| 84 ::UnregisterClass(kWindowClassName, GetModuleHandle(NULL)); |
| 85 } |
| 86 } |
| 87 |
| 88 // static |
| 89 CachedCompatibleDC* CachedCompatibleDC::GetInstance() { |
| 90 return Singleton<CachedCompatibleDC>::get(); |
| 91 } |
| 92 |
| 93 HDC CachedCompatibleDC::GetOrCreateCompatibleDC() { |
| 94 if (!compatible_dc_) { |
| 95 compatible_dc_ = ::CreateCompatibleDC(NULL); |
| 96 if (!listener_window_) { |
| 97 listener_window_ = CreateListenerWindow(); |
| 98 ui::CheckWindowCreated(listener_window_); |
| 99 } |
| 100 } |
| 101 return compatible_dc_; |
| 102 } |
| 103 |
| 104 void CachedCompatibleDC::DeleteCachedCompatibleDC() { |
| 105 if (compatible_dc_) { |
| 106 ::DeleteDC(compatible_dc_); |
| 107 compatible_dc_ = NULL; |
| 108 } |
| 109 } |
| 110 |
| 111 } // namespace |
| 112 |
| 113 namespace gfx { |
| 114 |
| 115 ScopedTemporaryScreenCompatibleDC::ScopedTemporaryScreenCompatibleDC() |
| 116 : hdc_(CachedCompatibleDC::GetInstance()->GetOrCreateCompatibleDC()) { |
| 117 } |
| 118 |
| 119 ScopedTemporaryScreenCompatibleDC::~ScopedTemporaryScreenCompatibleDC() { |
| 120 } |
| 121 |
| 122 } // namespace gfx |
OLD | NEW |