1 /* 2 * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #include "common.h" 27 28 #include "BaseWnd.h" 29 #include "GlassApplication.h" 30 31 32 //NOTE: it's not thread-safe 33 unsigned int BaseWnd::sm_classNameCounter = 0; 34 35 static LPCTSTR szBaseWndProp = TEXT("BaseWndProp"); 36 37 BaseWnd::BaseWnd(HWND ancestor) : 38 m_hWnd(NULL), 39 m_ancestor(ancestor), 40 m_wndClassAtom(0), 41 m_isCommonDialogOwner(false), 42 m_hCursor(NULL), 43 m_updatesCursor(true) 44 { 45 46 } 47 48 BaseWnd::~BaseWnd() 49 { 50 if (m_wndClassAtom) 51 { 52 // This is called from WM_NCDESTROY, and ::UnregisterClass() will fail. 53 // Schedule the operation for later time when the HWND is dead and 54 // the window class is really free already. 55 ENTER_MAIN_THREAD() 56 { 57 if (!::UnregisterClass(reinterpret_cast<LPCTSTR>(wndClassAtom), 58 ::GetModuleHandle(NULL))) 59 { 60 _tprintf_s(L"BaseWnd::UnregisterClass(%i) error: %u\n", 61 (int)wndClassAtom, ::GetLastError()); 62 } 63 } 64 ATOM wndClassAtom; 65 LEAVE_MAIN_THREAD_LATER; 66 67 ARG(wndClassAtom) = m_wndClassAtom; 68 69 PERFORM_LATER(); 70 } 71 } 72 73 /*static*/ 74 BaseWnd* BaseWnd::FromHandle(HWND hWnd) 75 { 76 return (BaseWnd *)::GetProp(hWnd, szBaseWndProp); 77 } 78 79 HWND BaseWnd::Create(HWND hParent, int x, int y, int width, int height, 80 LPCTSTR lpWindowName, DWORD dwExStyle, DWORD dwStyle, HBRUSH hbrBackground) 81 { 82 HINSTANCE hInst = ::GetModuleHandle(NULL); 83 TCHAR szClassName[256]; 84 85 ::ZeroMemory(szClassName, sizeof(szClassName)); 86 _stprintf_s(szClassName, sizeof(szClassName)/sizeof(szClassName[0]), 87 _T("GlassWndClass-%s-%u"), GetWindowClassNameSuffix(), ++BaseWnd::sm_classNameCounter); 88 89 WNDCLASSEX wndcls; 90 wndcls.cbSize = sizeof(WNDCLASSEX); 91 wndcls.style = CS_HREDRAW | CS_VREDRAW; 92 wndcls.lpfnWndProc = StaticWindowProc; 93 wndcls.cbClsExtra = 0; 94 wndcls.cbWndExtra = 0; 95 wndcls.hInstance = hInst; 96 wndcls.hIcon = NULL; 97 wndcls.hCursor = ::LoadCursor(NULL, IDC_ARROW); 98 wndcls.hbrBackground = hbrBackground; 99 wndcls.lpszMenuName = NULL; 100 wndcls.lpszClassName = szClassName; 101 wndcls.hIconSm = NULL; 102 103 m_hCursor = wndcls.hCursor; 104 105 m_wndClassAtom = ::RegisterClassEx(&wndcls); 106 107 if (!m_wndClassAtom) { 108 _tprintf_s(L"BaseWnd::RegisterClassEx(%s) error: %u\n", szClassName, ::GetLastError()); 109 } else { 110 if (lpWindowName == NULL) { 111 lpWindowName = TEXT(""); 112 } 113 ::CreateWindowEx(dwExStyle, szClassName, lpWindowName, 114 dwStyle, x, y, width, height, hParent, 115 NULL, hInst, (void *)this); 116 117 if (GetHWND() == NULL) { 118 _tprintf_s(L"BaseWnd::Create(%s) error: %u\n", szClassName, ::GetLastError()); 119 } 120 } 121 122 return m_hWnd; 123 124 } 125 126 /*static*/ 127 BOOL BaseWnd::GetDefaultWindowBounds(LPRECT r) 128 { 129 HINSTANCE hInst = ::GetModuleHandle(NULL); 130 TCHAR* szClassName = L"GLASSDEFAULTWINDOW"; 131 132 WNDCLASS wndcls; 133 ::ZeroMemory(&wndcls, sizeof(WNDCLASS)); 134 wndcls.lpfnWndProc = StaticWindowProc; 135 wndcls.hInstance = hInst; 136 wndcls.lpszClassName = szClassName; 137 ::RegisterClass(&wndcls); 138 139 HWND hwnd = ::CreateWindow(szClassName, L"", WS_OVERLAPPED, 140 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 141 0, 0, 0, 0); 142 BOOL res = ::GetWindowRect(hwnd, r); 143 ::DestroyWindow(hwnd); 144 ::UnregisterClass(szClassName, hInst); 145 146 return res; 147 } 148 149 /*static*/ 150 LRESULT CALLBACK BaseWnd::StaticWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 151 { 152 BaseWnd *pThis = NULL; 153 if (msg == WM_CREATE) { 154 pThis = (BaseWnd *)((CREATESTRUCT *)lParam)->lpCreateParams; 155 ::SetProp(hWnd, szBaseWndProp, (HANDLE)pThis); 156 if (pThis != NULL) { 157 pThis->m_hWnd = hWnd; 158 } 159 } else { 160 pThis = (BaseWnd *)::GetProp(hWnd, szBaseWndProp); 161 } 162 if (pThis != NULL) { 163 LRESULT result = pThis->WindowProc(msg, wParam, lParam); 164 if (msg == WM_NCDESTROY) { 165 ::RemoveProp(hWnd, szBaseWndProp); 166 delete pThis; 167 } 168 return result; 169 } 170 return ::DefWindowProc(hWnd, msg, wParam, lParam); 171 } 172 173 /*virtual*/ 174 MessageResult BaseWnd::CommonWindowProc(UINT msg, WPARAM wParam, LPARAM lParam) 175 { 176 static const MessageResult NOT_PROCESSED; 177 178 switch (msg) { 179 case WM_SETCURSOR: 180 if (LOWORD(lParam) == HTCLIENT) { 181 if (m_updatesCursor) { 182 ::SetCursor(m_hCursor); 183 } 184 return TRUE; 185 } 186 break; 187 } 188 189 return NOT_PROCESSED; 190 } 191 192 void BaseWnd::SetCursor(HCURSOR cursor) 193 { 194 m_hCursor = cursor; 195 196 // Might be worth checking the current cursor position. 197 // However, we've always set cursor unconditionally relying on the caller 198 // invoking this method only when it processes mouse_move or alike events. 199 // As long as there's no bugs filed, let it be. 200 ::SetCursor(m_hCursor); 201 } 202 203 void BaseWnd::SetUpdatesCursor(bool updatesCursor) 204 { 205 m_updatesCursor = updatesCursor; 206 } 207