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 "FullScreenWindow.h"
  29 #include "GlassApplication.h"
  30 #include "GlassWindow.h"
  31 #include "GlassScreen.h"
  32 #include "GlassMenu.h"
  33 #include "GlassView.h"
  34 #include "GlassDnD.h"
  35 #include "Pixels.h"
  36 #include "AccessibleRoot.h"
  37 #include "GlassCursor.h"
  38 
  39 #include "com_sun_glass_events_WindowEvent.h"
  40 #include "com_sun_glass_ui_Window.h"
  41 #include "com_sun_glass_ui_Window_Level.h"
  42 #include "com_sun_glass_ui_win_WinWindow.h"
  43 
  44 
  45 // Helper LEAVE_MAIN_THREAD for GlassWindow
  46 #define LEAVE_MAIN_THREAD_WITH_hWnd  \
  47     HWND hWnd;  \
  48     LEAVE_MAIN_THREAD;  \
  49     ARG(hWnd) = (HWND)ptr;
  50 
  51 static LPCTSTR szGlassWindowClassName = TEXT("GlassWindowClass");
  52 
  53 static jmethodID midNotifyClose;
  54 static jmethodID midNotifyMove;
  55 static jmethodID midNotifyResize;
  56 static jmethodID midNotifyMoveToAnotherScreen;
  57 
  58 unsigned int GlassWindow::sm_instanceCounter = 0;
  59 HHOOK GlassWindow::sm_hCBTFilter = NULL;
  60 HWND GlassWindow::sm_grabWindow = NULL;
  61 
  62 GlassWindow::GlassWindow(jobject jrefThis, bool isTransparent, bool isDecorated, bool isUnified, bool isChild, HWND parentOrOwner)
  63     : BaseWnd(parentOrOwner),
  64     ViewContainer(),
  65     m_state(Normal),
  66     m_isFocusable(true),
  67     m_isFocused(false),
  68     m_focusEvent(0),
  69     m_isResizable(true),
  70     m_isTransparent(isTransparent),
  71     m_isDecorated(isDecorated),
  72     m_isUnified(isUnified),
  73     m_hMenu(NULL),
  74     m_alpha(255),
  75     m_isEnabled(true),
  76     m_parent(isChild ? parentOrOwner : NULL),
  77     m_delegateWindow(NULL),
  78     m_isInFullScreen(false),
  79     m_beforeFullScreenStyle(0),
  80     m_beforeFullScreenExStyle(0),
  81     m_beforeFullScreenMenu(NULL),
  82     m_pProvider(NULL),
  83     m_a11yInitRequested(false),
  84     m_a11yTreeIsReady(false)
  85 {
  86     m_grefThis = GetEnv()->NewGlobalRef(jrefThis);
  87     m_minSize.x = m_minSize.y = -1;   // "not set" value
  88     m_maxSize.x = m_maxSize.y = -1;   // "not set" value
  89     m_hMonitor = NULL;
  90     m_insets.left = m_insets.top = m_insets.right = m_insets.bottom = 0;
  91     m_beforeFullScreenRect.left = m_beforeFullScreenRect.top =
  92         m_beforeFullScreenRect.right = m_beforeFullScreenRect.bottom = 0;
  93 
  94     if (++GlassWindow::sm_instanceCounter == 1) {
  95         GlassWindow::sm_hCBTFilter =
  96             ::SetWindowsHookEx(WH_CBT,
  97                     (HOOKPROC)GlassWindow::CBTFilter,
  98                     0, GlassApplication::GetMainThreadId());
  99     }
 100     if (isChild) {
 101         GlassApplication::InstallMouseLLHook();
 102     }
 103 }
 104 
 105 GlassWindow::~GlassWindow()
 106 {
 107     if (m_grefThis) {
 108         GetEnv()->DeleteGlobalRef(m_grefThis);
 109     }
 110 
 111     if (IsChild()) {
 112         GlassApplication::UninstallMouseLLHook();
 113     }
 114 
 115     if (--GlassWindow::sm_instanceCounter == 0) {
 116         ::UnhookWindowsHookEx(GlassWindow::sm_hCBTFilter);
 117     }
 118 }
 119 
 120 LPCTSTR GlassWindow::GetWindowClassNameSuffix()
 121 {
 122     return szGlassWindowClassName;
 123 }
 124 
 125 HWND GlassWindow::Create(DWORD dwStyle, DWORD dwExStyle, HMONITOR hMonitor, HWND owner)
 126 {
 127     m_hMonitor = hMonitor;
 128 
 129     int x = CW_USEDEFAULT;
 130     int y = CW_USEDEFAULT;
 131     int w = CW_USEDEFAULT;
 132     int h = CW_USEDEFAULT;
 133     if ((dwStyle & WS_POPUP) != 0) {
 134         // CW_USEDEFAULT doesn't work for WS_POPUP windows
 135         RECT r;
 136         if (BaseWnd::GetDefaultWindowBounds(&r)) {
 137             x = r.left;
 138             y = r.top;
 139             w = r.right - r.left;
 140             h = r.bottom - r.top;
 141         }
 142     }
 143 
 144     HWND hwnd = BaseWnd::Create(owner, x, y, w, h,
 145                                 TEXT(""), dwExStyle, dwStyle, NULL);
 146 
 147     ViewContainer::InitDropTarget(hwnd);
 148     ViewContainer::InitManipProcessor(hwnd);
 149 
 150     return hwnd;
 151 }
 152 
 153 void GlassWindow::Close()
 154 {
 155     UngrabFocus();
 156     ViewContainer::ReleaseDropTarget();
 157     ViewContainer::ReleaseManipProcessor();
 158 }
 159 
 160 void GlassWindow::setMinSize(long width, long height)
 161 {
 162     m_minSize.x = width;
 163     m_minSize.y = height;
 164 }
 165 
 166 void GlassWindow::setMaxSize(long width, long height)
 167 {
 168     m_maxSize.x = width;
 169     m_maxSize.y = height;
 170 }
 171 
 172 void GlassWindow::updateMinMaxSize(RECT &windowRect)
 173 {
 174     if (m_minSize.x >= 0) {
 175         // min size has been set
 176         if (windowRect.right - windowRect.left < m_minSize.x) {
 177             windowRect.right = windowRect.left + m_minSize.x;
 178         }
 179         if (windowRect.bottom - windowRect.top < m_minSize.y) {
 180             windowRect.bottom = windowRect.top + m_minSize.y;
 181         }
 182     }
 183     if (m_maxSize.x >= 0) {
 184         // max size has been set
 185         if (windowRect.right - windowRect.left > m_maxSize.x) {
 186             windowRect.right = windowRect.left + m_maxSize.x;
 187         }
 188         if (windowRect.bottom - windowRect.top > m_maxSize.y) {
 189             windowRect.bottom = windowRect.top + m_maxSize.y;
 190         }
 191     }
 192 
 193 }
 194 
 195 void GlassWindow::SetFocusable(bool isFocusable)
 196 {
 197     m_isFocusable = isFocusable;
 198 
 199     LONG exStyle = ::GetWindowLong(GetHWND(), GWL_EXSTYLE);
 200     if (!isFocusable) {
 201         //NOTE: this style works 'by itself' when there's only one window
 202         //      in this application. It does prevent the window from activation
 203         //      then. However, as soon as there is another window, we also need
 204         //      to handle WM_MOUSEACTIVATE and use the CBTFilter() hook.
 205         //      The useful part of the style: it removes the window from the
 206         //      task bar (and the Alt-Tab list).
 207         ::SetWindowLong(GetHWND(), GWL_EXSTYLE, exStyle | WS_EX_NOACTIVATE);
 208 
 209         if (::GetFocus() == GetHWND()) {
 210             // We can't resign activation, but at least we can reset the focus
 211             ::SetFocus(NULL);
 212         }
 213     } else {
 214         ::SetWindowLong(GetHWND(), GWL_EXSTYLE, exStyle & ~WS_EX_NOACTIVATE);
 215     }
 216 }
 217 
 218 LRESULT CALLBACK GlassWindow::CBTFilter(int nCode, WPARAM wParam, LPARAM lParam)
 219 {
 220     if (nCode == HCBT_ACTIVATE || nCode == HCBT_SETFOCUS) {
 221         BaseWnd *pWindow = BaseWnd::FromHandle((HWND)wParam);
 222         if (pWindow && pWindow->IsGlassWindow()) {
 223             GlassWindow * window = (GlassWindow*)pWindow;
 224 
 225             if (!window->IsEnabled()) {
 226                 window->HandleFocusDisabledEvent();
 227                 return 1;
 228             }
 229             if (!window->IsFocusable()) {
 230                 return 1;
 231             }
 232         }
 233     }
 234     return ::CallNextHookEx(GlassWindow::sm_hCBTFilter, nCode, wParam, lParam);
 235 }
 236 
 237 LRESULT GlassWindow::WindowProc(UINT msg, WPARAM wParam, LPARAM lParam)
 238 {
 239     MessageResult commonResult = BaseWnd::CommonWindowProc(msg, wParam, lParam);
 240     if (commonResult.processed) {
 241         return commonResult.result;
 242     }
 243 
 244     switch (msg) {
 245         case WM_SHOWWINDOW:
 246             // It's possible that move/size events are reported by the platform
 247             // before the peer listener is set. As a result, location/size are
 248             // not reported, so resending them from here.
 249             HandleMoveEvent(NULL);
 250             HandleSizeEvent(com_sun_glass_events_WindowEvent_RESIZE, NULL);
 251             // The call below may be restricted to WS_POPUP windows
 252             NotifyViewSize(GetHWND());
 253 
 254             if (!wParam) {
 255                 ResetMouseTracking(GetHWND());
 256             }
 257             if (IS_WINVISTA) {
 258                 ::SendMessage(GetHWND(), WM_DWMCOMPOSITIONCHANGED, 0, 0);
 259             }
 260             break;
 261         case WM_DWMCOMPOSITIONCHANGED:
 262             if (m_isUnified && (IS_WINVISTA)) {
 263                 BOOL bEnabled = FALSE;
 264                 if(SUCCEEDED(::DwmIsCompositionEnabled(&bEnabled)) && bEnabled) {
 265                     MARGINS dwmMargins = { -1, -1, -1, -1 };
 266                     ::DwmExtendFrameIntoClientArea(GetHWND(), &dwmMargins);
 267                 }
 268             }
 269             //When toggling between Aero and Classic theme the size of window changes
 270             //No predefined WM_SIZE event type for this, so using -1 as parameters
 271             HandleViewSizeEvent(GetHWND(), -1, -1, -1);
 272             break;
 273         case WM_SIZE:
 274             switch (wParam) {
 275                 case SIZE_RESTORED:
 276                     if (m_state != Normal) {
 277                         HandleSizeEvent(com_sun_glass_events_WindowEvent_RESTORE, NULL);
 278                         m_state = Normal;
 279                     } else {
 280                         HandleSizeEvent(com_sun_glass_events_WindowEvent_RESIZE, NULL);
 281                     }
 282                     break;
 283                 case SIZE_MINIMIZED:
 284                     HandleSizeEvent(com_sun_glass_events_WindowEvent_MINIMIZE, NULL);
 285                     m_state = Minimized;
 286                     break;
 287                 case SIZE_MAXIMIZED:
 288                     HandleSizeEvent(com_sun_glass_events_WindowEvent_MAXIMIZE, NULL);
 289                     m_state = Maximized;
 290                     break;
 291             }
 292             HandleViewSizeEvent(GetHWND(), msg, wParam, lParam);
 293             break;
 294 //        case WM_MOVING:
 295 //            HandleMoveEvent((RECT *)lParam);
 296 //            break;
 297         case WM_MOVE:
 298             HandleMoveEvent(NULL);
 299             break;
 300         case WM_WINDOWPOSCHANGED:
 301             HandleWindowPosChangedEvent();
 302             break;
 303         case WM_CLOSE:
 304             HandleCloseEvent();
 305             return 0;
 306         case WM_DESTROY:
 307             HandleDestroyEvent();
 308             return 0;
 309         case WM_ACTIVATE:
 310             if (IsInFullScreenMode()) {
 311                 HWND hWndInsertAfter = LOWORD(wParam) != WA_INACTIVE ? HWND_TOPMOST : HWND_BOTTOM;
 312                 ::SetWindowPos(GetHWND(), hWndInsertAfter, 0, 0, 0, 0,
 313                         SWP_ASYNCWINDOWPOS | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOSIZE);
 314             }
 315             if (!GetDelegateWindow()) {
 316                 HandleActivateEvent(LOWORD(wParam) != WA_INACTIVE ?
 317                         com_sun_glass_events_WindowEvent_FOCUS_GAINED :
 318                         com_sun_glass_events_WindowEvent_FOCUS_LOST);
 319             }
 320             // Let the DefWindowProc() set the focus to this window
 321             break;
 322         case WM_MOUSEACTIVATE:
 323             if (!IsEnabled()) {
 324                 HandleFocusDisabledEvent();
 325                 // Do not activate, and discard the event
 326                 return MA_NOACTIVATEANDEAT;
 327             }
 328             if (!IsFocusable()) {
 329                 // Do not activate, but pass the mouse event
 330                 return MA_NOACTIVATE;
 331             }
 332             break;
 333         case WM_SETFOCUS:
 334             if (!GetDelegateWindow()) {
 335                 SetFocused(true);
 336                 if (IsChild()) {
 337                     // Synthesize the event
 338                     HandleActivateEvent(m_focusEvent ? m_focusEvent : com_sun_glass_events_WindowEvent_FOCUS_GAINED);
 339                     m_focusEvent = 0;
 340                 }
 341             }
 342             break;
 343         case WM_KILLFOCUS:
 344             if (!GetDelegateWindow()) {
 345                 SetFocused(false);
 346                 if (IsChild()) {
 347                     // Synthesize the event
 348                     HandleActivateEvent(com_sun_glass_events_WindowEvent_FOCUS_LOST);
 349                 }
 350             }
 351             break;
 352         case WM_GETMINMAXINFO:
 353             if (m_minSize.x >= 0 || m_minSize.y >= 0 ||
 354                     m_maxSize.x >= 0 || m_maxSize.y >= 0)
 355             {
 356                 MINMAXINFO *info = (MINMAXINFO *)lParam;
 357                 if (m_minSize.x >= 0) {
 358                     info->ptMinTrackSize.x = m_minSize.x;
 359                 }
 360                 if (m_minSize.y >= 0) {
 361                     info->ptMinTrackSize.y = m_minSize.y;
 362                 }
 363                 if (m_maxSize.x >= 0) {
 364                     info->ptMaxTrackSize.x = m_maxSize.x;
 365                 }
 366                 if (m_maxSize.y >= 0) {
 367                     info->ptMaxTrackSize.y = m_maxSize.y;
 368                 }
 369                 return 0;
 370             }
 371             break;
 372         case WM_COMMAND:
 373             if (HandleCommand(LOWORD(wParam))) {
 374                 return 0;
 375             }
 376             break;
 377         case WM_INPUTLANGCHANGE:
 378             HandleViewInputLangChange(GetHWND(), msg, wParam, lParam);
 379             return 0;
 380         case WM_NCCALCSIZE:
 381 // Workaround for RT-13998. It has some side effects and thus commented out
 382 //            if ((BOOL)wParam && !IsDecorated()) {
 383 //                NCCALCSIZE_PARAMS *p = (NCCALCSIZE_PARAMS *)lParam;
 384 //                p->rgrc[0].right++;
 385 //                p->rgrc[0].bottom++;
 386 //                return WVR_VALIDRECTS;
 387 //            }
 388             break;
 389         case WM_PAINT:
 390             HandleViewPaintEvent(GetHWND(), msg, wParam, lParam);
 391             break;
 392         case WM_CONTEXTMENU:
 393             HandleViewMenuEvent(GetHWND(), msg, wParam, lParam);
 394             break;
 395         case WM_LBUTTONDOWN:
 396         case WM_RBUTTONDOWN:
 397         case WM_MBUTTONDOWN:
 398             CheckUngrab(); // check if other owned windows hierarchy holds the grab
 399             if (IsChild() && !IsFocused() && IsFocusable()) {
 400                 RequestFocus(com_sun_glass_events_WindowEvent_FOCUS_GAINED);
 401             }
 402             // ... and fall through for other mouse events
 403         case WM_LBUTTONUP:
 404         case WM_LBUTTONDBLCLK:
 405         case WM_RBUTTONUP:
 406         case WM_RBUTTONDBLCLK:
 407         case WM_MBUTTONUP:
 408         case WM_MBUTTONDBLCLK:
 409         case WM_MOUSEWHEEL:
 410         case WM_MOUSEHWHEEL:
 411         case WM_MOUSELEAVE:
 412         case WM_MOUSEMOVE:
 413             if (IsEnabled()) {
 414                 if (msg == WM_MOUSELEAVE && GetDelegateWindow()) {
 415                     // Skip generating MouseEvent.EXIT when entering FullScreen
 416                     return 0;
 417                 }
 418                 BOOL handled = HandleViewMouseEvent(GetHWND(), msg, wParam, lParam);
 419                 if (handled && msg == WM_RBUTTONUP) {
 420                     // By default, DefWindowProc() sends WM_CONTEXTMENU from WM_LBUTTONUP
 421                     // Since DefWindowProc() is not called, call the mouse menu handler directly 
 422                     HandleViewMenuEvent(GetHWND(), WM_CONTEXTMENU, (WPARAM) GetHWND(), ::GetMessagePos ());
 423                     //::DefWindowProc(GetHWND(), msg, wParam, lParam);
 424                 }
 425                 if (handled) {
 426                     // Do not call the DefWindowProc() for mouse events that were handled
 427                     return 0;
 428                 }
 429             } else {
 430                 HandleFocusDisabledEvent();
 431                 return 0;
 432             }
 433             break;
 434         case WM_CAPTURECHANGED:
 435             ViewContainer::NotifyCaptureChanged(GetHWND(), (HWND)lParam);
 436             break;
 437         case WM_SYSKEYDOWN:
 438         case WM_SYSKEYUP:
 439         case WM_KEYDOWN:
 440         case WM_KEYUP:
 441             if (!IsEnabled()) {
 442                 return 0;
 443             }
 444             HandleViewKeyEvent(GetHWND(), msg, wParam, lParam);
 445             // Always pass the message down to the DefWindowProc() to handle
 446             // system keys (Alt+F4, etc.) with only excpetion for F10 and ALT:
 447             if (!GetMenu()) {
 448                 if (wParam == VK_MENU || (wParam == VK_F10 && !GetModifiers())) {
 449                     // Disable activation of the window's system menu
 450                     return 0;
 451                 }
 452             }
 453             break;
 454         case WM_CHAR:
 455         case WM_IME_CHAR:
 456             if (IsEnabled()) {
 457                 HandleViewTypedEvent(GetHWND(), msg, wParam, lParam);
 458                 return 0;
 459             }
 460             break;
 461         case WM_IME_COMPOSITION:
 462         case WM_IME_ENDCOMPOSITION:
 463         case WM_IME_NOTIFY:
 464         case WM_IME_STARTCOMPOSITION:
 465             if (IsEnabled() &&
 466                 HandleViewInputMethodEvent(GetHWND(), msg, wParam, lParam)) {
 467                 return 0;
 468             }
 469             break;
 470         case WM_NCLBUTTONDOWN:
 471         case WM_NCMBUTTONDOWN:
 472         case WM_NCRBUTTONDOWN:
 473         case WM_NCXBUTTONDOWN:
 474             UngrabFocus(); // ungrab itself
 475             CheckUngrab(); // check if other owned windows hierarchy holds the grab
 476             // Pass the event to DefWindowProc()
 477             break;
 478         case WM_TOUCH:
 479             if (IsEnabled()) {
 480                 HandleViewTouchEvent(GetHWND(), msg, wParam, lParam);
 481                 return 0;
 482             }
 483             break;
 484         case WM_TIMER:
 485             HandleViewTimerEvent(GetHWND(), wParam);
 486             return 0;
 487         case WM_GETOBJECT:
 488             //setvbuf(stdout, NULL, _IONBF, 0);  // turn off stdout buffering
 489             if (!m_a11yInitRequested) {
 490                 m_a11yInitRequested = true;  // only call once
 491                 HandleAccessibilityInitEvent();  // initialize
 492             } else if (m_a11yTreeIsReady) {
 493                 //TODO: From spec: When a window that previously returned providers has been destroyed,
 494                 // you should notify UI Automation by calling UiaReturnRawElementProvider(hwnd, 0, 0, NULL)
 495                 // Do this from WM_DESTROY?
 496                 LRESULT lr = UiaReturnRawElementProvider(GetHWND(), wParam, lParam, m_pProvider);
 497                 //TODO: It's not clear that Release() is needed.  Some examples use it; some don't.
 498                 // I'm getting a premature call to the d'tor so I'm removing it at least for now
 499                 //m_pProvider->Release();
 500                 return lr;
 501             }
 502             break;
 503     }
 504 
 505     return ::DefWindowProc(GetHWND(), msg, wParam, lParam);
 506 }
 507 
 508 void GlassWindow::HandleCloseEvent()
 509 {
 510     JNIEnv* env = GetEnv();
 511 
 512     env->CallVoidMethod(m_grefThis, midNotifyClose);
 513     CheckAndClearException(env);
 514 }
 515 
 516 void GlassWindow::HandleDestroyEvent()
 517 {
 518     JNIEnv* env = GetEnv();
 519 
 520     env->CallVoidMethod(m_grefThis, javaIDs.Window.notifyDestroy);
 521     CheckAndClearException(env);
 522 }
 523 
 524 // if pRect == NULL => get position/size by GetWindowRect
 525 void GlassWindow::HandleMoveEvent(RECT *pRect)
 526 {
 527     JNIEnv* env = GetEnv();
 528 
 529     RECT r;
 530     if (pRect == NULL) {
 531         ::GetWindowRect(GetHWND(), &r);
 532         pRect = &r;
 533     }
 534 
 535     env->CallVoidMethod(m_grefThis, midNotifyMove, pRect->left, pRect->top);
 536     CheckAndClearException(env);
 537 }
 538 
 539 // if pRect == NULL => get position/size by GetWindowRect
 540 void GlassWindow::HandleSizeEvent(int type, RECT *pRect)
 541 {
 542     JNIEnv* env = GetEnv();
 543 
 544     RECT r;
 545     if (pRect == NULL) {
 546         ::GetWindowRect(GetHWND(), &r);
 547         pRect = &r;
 548     }
 549 
 550     env->CallVoidMethod(m_grefThis, midNotifyResize,
 551                         type, pRect->right-pRect->left, pRect->bottom-pRect->top);
 552     CheckAndClearException(env);
 553 }
 554 
 555 void GlassWindow::HandleWindowPosChangedEvent()
 556 {
 557     JNIEnv* env = GetEnv();
 558 
 559     HMONITOR toMonitor = ::MonitorFromWindow(GetHWND(), MONITOR_DEFAULTTOPRIMARY);
 560     HMONITOR fromMonitor = GetMonitor();
 561     if (toMonitor != fromMonitor) {
 562         env->CallVoidMethod(m_grefThis, midNotifyMoveToAnotherScreen,
 563                             ptr_to_jlong(fromMonitor), ptr_to_jlong(toMonitor));
 564         CheckAndClearException(env);
 565         SetMonitor(toMonitor);
 566     }
 567 }
 568 
 569 void GlassWindow::HandleActivateEvent(jint event)
 570 {
 571     const bool active = event != com_sun_glass_events_WindowEvent_FOCUS_LOST;
 572 
 573     if (!active) {
 574         UngrabFocus();
 575     }
 576     
 577     JNIEnv* env = GetEnv();
 578     env->CallVoidMethod(m_grefThis, javaIDs.Window.notifyFocus, event);
 579     CheckAndClearException(env);
 580 }
 581 
 582 void GlassWindow::HandleFocusDisabledEvent()
 583 {
 584     JNIEnv* env = GetEnv();
 585 
 586     env->CallVoidMethod(m_grefThis, javaIDs.Window.notifyFocusDisabled);
 587     CheckAndClearException(env);
 588 }
 589 
 590 void GlassWindow::HandleAccessibilityInitEvent() {
 591 
 592     JNIEnv* env = GetEnv();
 593     env->CallVoidMethod(m_grefThis, javaIDs.Window.notifyInitAccessibility);
 594     CheckAndClearException(env);
 595 }
 596 
 597 void GlassWindow::SetAccessibilityInitIsComplete(AccessibleRoot* pAcc) {
 598     m_pProvider = pAcc;
 599     m_a11yTreeIsReady = true;
 600 }
 601 
 602 bool GlassWindow::HandleCommand(WORD cmdID) {
 603     return HandleMenuCommand(GetHWND(), cmdID);
 604 }
 605 
 606 HMONITOR GlassWindow::GetMonitor()
 607 {
 608     return m_hMonitor;
 609 }
 610 
 611 void GlassWindow::SetMonitor(HMONITOR hMonitor)
 612 {
 613     m_hMonitor = hMonitor;
 614 }
 615 
 616 void GlassWindow::SetAlpha(BYTE alpha)
 617 {
 618     m_alpha = alpha;
 619 
 620     if (m_isTransparent) {
 621         // If the window is transparent, the opacity is handled in
 622         // uploadPixels() below (see BLENDFUNCTION structure
 623         // and its SourceConstantAlpha member)
 624         return;
 625     }
 626 
 627     // The window is opaque. We make it layered temporarily only when
 628     // its alpha is less than 0xFF.
 629     LONG exStyle = ::GetWindowLong(GetHWND(), GWL_EXSTYLE);
 630 
 631     if (alpha == 0xFF) {
 632         if (exStyle & WS_EX_LAYERED) {
 633             ::SetWindowLong(GetHWND(), GWL_EXSTYLE, exStyle & ~WS_EX_LAYERED);
 634         }
 635     } else {
 636         if (!(exStyle & WS_EX_LAYERED)) {
 637             ::SetWindowLong(GetHWND(), GWL_EXSTYLE, exStyle | WS_EX_LAYERED);
 638         }
 639         ::SetLayeredWindowAttributes(GetHWND(), RGB(0, 0, 0), alpha, LWA_ALPHA);
 640     }
 641 }
 642 
 643 void GlassWindow::UpdateInsets()
 644 {
 645     if (::IsIconic(GetHWND())) {
 646         return;
 647     }
 648 
 649     RECT outer, inner;
 650 
 651     ::GetWindowRect(GetHWND(), &outer);
 652     ::GetClientRect(GetHWND(), &inner);
 653 
 654     ::MapWindowPoints(GetHWND(), (HWND)NULL, (LPPOINT)&inner, (sizeof(RECT)/sizeof(POINT)));
 655 
 656     m_insets.top = inner.top - outer.top;
 657     m_insets.left = inner.left - outer.left;
 658     m_insets.bottom = outer.bottom - inner.bottom;
 659     m_insets.right = outer.right - inner.right;
 660 
 661     if (m_insets.top < 0 || m_insets.left < 0 ||
 662             m_insets.bottom < 0 || m_insets.right < 0)
 663     {
 664         if (!IsDecorated()) {
 665             ::ZeroMemory(&m_insets, sizeof(m_insets));
 666         } else {
 667             if (GetStyle() & WS_THICKFRAME) {
 668                 m_insets.left = m_insets.right =
 669                     ::GetSystemMetrics(SM_CXSIZEFRAME);
 670                 m_insets.top = m_insets.bottom =
 671                     ::GetSystemMetrics(SM_CYSIZEFRAME);
 672             } else {
 673                 m_insets.left = m_insets.right =
 674                     ::GetSystemMetrics(SM_CXDLGFRAME);
 675                 m_insets.top = m_insets.bottom =
 676                     ::GetSystemMetrics(SM_CYDLGFRAME);
 677             }
 678 
 679             m_insets.top += ::GetSystemMetrics(SM_CYCAPTION);
 680         }
 681         if (GetMenu()) {
 682             //Well, if menu wraps on multiple lines... sorry about that.
 683             m_insets.top += ::GetSystemMetrics(SM_CYMENU);
 684         }
 685     }
 686 }
 687 
 688 bool GlassWindow::SetResizable(bool resizable)
 689 {
 690     LONG style = GetStyle();
 691 
 692     if (style & WS_CHILD) {
 693         return false;
 694     }
 695 
 696     LONG resizableStyle = WS_MAXIMIZEBOX;
 697     if (IsDecorated()) {
 698         resizableStyle |= WS_THICKFRAME;
 699     }
 700 
 701     if (resizable) {
 702         style |= resizableStyle;
 703     } else {
 704         style &= ~resizableStyle;
 705     }
 706 
 707     SetStyle(style);
 708     m_isResizable = resizable;
 709 
 710     return true;
 711 }
 712 
 713 /* static */ void GlassWindow::ResetGrab()
 714 {
 715     if (sm_grabWindow) {
 716         GlassWindow *pWindow = GlassWindow::FromHandle(sm_grabWindow);
 717         if (pWindow) {
 718             pWindow->UngrabFocus();
 719         }
 720         sm_grabWindow = NULL;
 721     }
 722 }
 723 
 724 bool GlassWindow::GrabFocus()
 725 {
 726     HWND hwnd = GetCurrentHWND();
 727 
 728     if (sm_grabWindow == hwnd) {
 729         // Already grabbed
 730         return true;
 731     }
 732 
 733     GlassWindow::ResetGrab();
 734 
 735     sm_grabWindow = hwnd;
 736 
 737     return true;
 738 }
 739 
 740 void GlassWindow::UngrabFocus()
 741 {
 742     HWND hwnd = GetCurrentHWND();
 743 
 744     if (hwnd != sm_grabWindow) {
 745         return;
 746     }
 747 
 748     JNIEnv* env = GetEnv();
 749     env->CallVoidMethod(m_grefThis, javaIDs.Window.notifyFocusUngrab);
 750     CheckAndClearException(env);
 751 
 752     sm_grabWindow = NULL;
 753 }
 754 
 755 void GlassWindow::CheckUngrab()
 756 {
 757     if (!sm_grabWindow) {
 758         return;
 759     }
 760 
 761     // If this window doesn't belong to an owned windows hierarchy that
 762     // holds the grab currently, then the grab should be released.
 763     // Fix RT-16490: use GetAncestor() instead of ::GetParent() to support embedded windows
 764     for (BaseWnd * window = this; window != NULL; window = BaseWnd::FromHandle(window->GetAncestor())) {
 765         if (window->GetHWND() == sm_grabWindow) {
 766             return;
 767         }
 768     }
 769 
 770     GlassWindow::ResetGrab();
 771 }
 772 
 773 bool GlassWindow::RequestFocus(jint event)
 774 {
 775     if (!IsChild()) {
 776         ASSERT(event == com_sun_glass_events_WindowEvent_FOCUS_GAINED);
 777         // The event will be delivered as a part of WM_ACTIVATE message handling
 778         return ::SetForegroundWindow(GetHWND()) != FALSE;
 779     }
 780 
 781     if (event == com_sun_glass_events_WindowEvent_FOCUS_LOST) {
 782         if (IsFocused()) {
 783             ::SetFocus(NULL);
 784         }
 785 
 786         return true;
 787     }
 788 
 789     // First try to activate the toplevel window
 790     HWND toplevel = ::GetAncestor(GetHWND(), GA_ROOT);
 791     if (::GetForegroundWindow() != toplevel && !::SetForegroundWindow(toplevel)) {
 792         // We're unable to bring our top-level window to foreground.
 793         // But since it anyway becomes active, we (or the plugin) won't receive
 794         // any subsequent notifications. So let's pretend we got the focus - 
 795         //IGNORE: return false;
 796         //We'll anyway get a reasonable response from the ::SetFocus() later
 797     }
 798 
 799     m_focusEvent = event; // reset upon WM_SETFOCUS
 800 
 801     // If we request focus from 'nowhere', the SetFocus may still return NULL I guess
 802     return ::SetFocus(GetHWND()) != NULL || ::GetLastError() == 0;
 803 }
 804 
 805 static BOOL CALLBACK EnumChildWndProc(HWND hwnd, LPARAM lParam)
 806 {
 807     HWND * hwnds = (HWND*)lParam;
 808 
 809     ::SetParent(hwnd, hwnds[1]);
 810 
 811     BaseWnd * window = BaseWnd::FromHandle(hwnd);
 812     if (window) {
 813         window->SetAncestor(hwnds[1]);
 814     }
 815 
 816     return TRUE;
 817 }
 818 
 819 static BOOL CALLBACK EnumOwnedWndProc(HWND hwnd, LPARAM lParam)
 820 {
 821     HWND * hwnds = (HWND*)lParam;
 822 
 823     GlassWindow * window = NULL;
 824     if ((HWND)::GetWindowLongPtr(hwnd, GWLP_HWNDPARENT) == hwnds[0] && (window = GlassWindow::FromHandle(hwnd)) != NULL) {
 825         ::SetWindowLongPtr(hwnd, GWLP_HWNDPARENT, (LONG_PTR)hwnds[1]);
 826         window->SetAncestor(hwnds[1]);
 827         ::SetWindowPos(hwnd, hwnds[1], 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED | SWP_NOACTIVATE);
 828     }
 829 
 830     return TRUE;
 831 }
 832 
 833 void GlassWindow::SetDelegateWindow(HWND hWnd)
 834 {
 835     if (m_delegateWindow == hWnd) {
 836         return;
 837     }
 838 
 839     // Make sure any popups are hidden
 840     UngrabFocus();
 841 
 842     HWND hwnds[2]; // [0] = from; [1] = to;
 843 
 844     hwnds[0] = m_delegateWindow ? m_delegateWindow : GetHWND();
 845     hwnds[1] = hWnd ? hWnd : GetHWND();
 846 
 847     STRACE(_T("SetDelegateWindow: from %p to %p"), hwnds[0], hwnds[1]);
 848 
 849     // Reparent child, and then owned windows
 850     ::EnumChildWindows(hwnds[0], &EnumChildWndProc, (LPARAM)&hwnds);
 851     ::EnumThreadWindows(GlassApplication::GetMainThreadId(), &EnumOwnedWndProc, (LPARAM)&hwnds);
 852 
 853     m_delegateWindow = hWnd;
 854 
 855     GetEnv()->CallVoidMethod(m_grefThis,
 856             javaIDs.Window.notifyDelegatePtr, (jlong)hWnd);
 857     CheckAndClearException(GetEnv());
 858 }
 859 
 860 BOOL GlassWindow::EnterFullScreenMode(GlassView * view, BOOL animate, BOOL keepRatio)
 861 {
 862     if (IsChild()) {
 863         return FALSE;
 864     }
 865     if (IsInFullScreenMode()) {
 866         return TRUE;
 867     }
 868     if (view != GetGlassView()) {
 869         STRACE(_T("EnterFullScreenMode(view = %p) while the real view for this window is: %p"), view, GetGlassView());
 870         return FALSE;
 871     }
 872 
 873     static const LONG FS_STYLE_MASK = WS_CAPTION | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_BORDER | WS_THICKFRAME;
 874     static const LONG FS_EXSTYLE_MASK = WS_EX_WINDOWEDGE;
 875 
 876     LONG style = ::GetWindowLong(GetHWND(), GWL_STYLE);
 877     LONG exStyle = ::GetWindowLong(GetHWND(), GWL_EXSTYLE);
 878 
 879     ::GetWindowRect(GetHWND(), &m_beforeFullScreenRect);
 880     m_beforeFullScreenStyle = style & FS_STYLE_MASK;
 881     m_beforeFullScreenExStyle = exStyle & FS_EXSTYLE_MASK;
 882     m_beforeFullScreenMenu = ::GetMenu(GetHWND());
 883 
 884     RECT viewRect, screenRect, contentRect;
 885 
 886     FullScreenWindow::ClientRectInScreen(GetHWND(), &viewRect);
 887     FullScreenWindow::CalculateBounds(GetHWND(), &screenRect,
 888             &contentRect, keepRatio, viewRect);
 889 
 890     //XXX: if (keepRatio) initBlackBackground(screenRect);
 891 
 892     ::SetWindowLong(GetHWND(), GWL_STYLE, style & ~FS_STYLE_MASK);
 893     ::SetWindowLong(GetHWND(), GWL_EXSTYLE, exStyle & ~FS_EXSTYLE_MASK);
 894 
 895     ::SetMenu(GetHWND(), NULL);
 896 
 897     ::SetWindowPos(GetHWND(), HWND_TOPMOST,
 898             contentRect.left, contentRect.top,
 899             contentRect.right - contentRect.left, contentRect.bottom - contentRect.top,
 900             SWP_FRAMECHANGED | SWP_NOCOPYBITS);
 901 
 902     m_isInFullScreen = true;
 903 
 904     return TRUE;
 905 }
 906 
 907 void GlassWindow::ExitFullScreenMode(BOOL animate)
 908 {
 909     if (IsChild() || !IsInFullScreenMode()) {
 910         return;
 911     }
 912 
 913     LONG style = ::GetWindowLong(GetHWND(), GWL_STYLE);
 914     LONG exStyle = ::GetWindowLong(GetHWND(), GWL_EXSTYLE);
 915 
 916     ::SetWindowLong(GetHWND(), GWL_STYLE, style | m_beforeFullScreenStyle);
 917     ::SetWindowLong(GetHWND(), GWL_EXSTYLE, exStyle | m_beforeFullScreenExStyle);
 918 
 919     ::SetMenu(GetHWND(), m_beforeFullScreenMenu);
 920 
 921     LONG swpFlags = SWP_FRAMECHANGED | SWP_NOCOPYBITS;
 922     if (!IsFocused()) {
 923         swpFlags |= SWP_NOACTIVATE;
 924     }
 925     ::SetWindowPos(GetHWND(), HWND_NOTOPMOST,
 926             m_beforeFullScreenRect.left, m_beforeFullScreenRect.top,
 927             m_beforeFullScreenRect.right - m_beforeFullScreenRect.left,
 928             m_beforeFullScreenRect.bottom - m_beforeFullScreenRect.top,
 929             swpFlags);
 930 
 931     m_isInFullScreen = false;
 932 }
 933 
 934 void GlassWindow::SetEnabled(bool enabled)
 935 {
 936     if (!enabled) {
 937         ResetMouseTracking(GetHWND());
 938     }
 939 
 940     m_isEnabled = enabled;
 941 }
 942 
 943 /*
 944  * JNI methods section
 945  *
 946  */
 947 
 948 extern "C" {
 949 
 950 /*
 951  * Class:     com_sun_glass_ui_win_WinWindow
 952  * Method:    _initIDs
 953  * Signature: ()V
 954  */
 955 JNIEXPORT void JNICALL Java_com_sun_glass_ui_win_WinWindow__1initIDs
 956     (JNIEnv *env, jclass cls)
 957 {
 958     midNotifyClose = env->GetMethodID(cls, "notifyClose", "()V");
 959     ASSERT(midNotifyClose);
 960 
 961     midNotifyMove = env->GetMethodID(cls, "notifyMove", "(II)V");
 962     ASSERT(midNotifyMove);
 963 
 964     midNotifyResize = env->GetMethodID(cls, "notifyResize", "(III)V");
 965     ASSERT(midNotifyResize);
 966 
 967     javaIDs.Window.notifyFocus = env->GetMethodID(cls, "notifyFocus", "(I)V");
 968     ASSERT(javaIDs.Window.notifyFocus);
 969 
 970     javaIDs.Window.notifyFocusDisabled = env->GetMethodID(cls, "notifyFocusDisabled", "()V");
 971     ASSERT(javaIDs.Window.notifyFocusDisabled);
 972 
 973     javaIDs.Window.notifyFocusUngrab = env->GetMethodID(cls, "notifyFocusUngrab", "()V");
 974     ASSERT(javaIDs.Window.notifyFocusUngrab);
 975 
 976     midNotifyMoveToAnotherScreen = env->GetMethodID(cls, "notifyMoveToAnotherScreen", "(JJ)V");
 977     ASSERT(midNotifyMoveToAnotherScreen);
 978 
 979 
 980     javaIDs.Window.notifyDestroy = env->GetMethodID(cls, "notifyDestroy", "()V");
 981     ASSERT(javaIDs.Window.notifyDestroy);
 982 
 983     javaIDs.Window.notifyDelegatePtr = env->GetMethodID(cls, "notifyDelegatePtr", "(J)V");
 984     ASSERT(javaIDs.Window.notifyDelegatePtr);
 985 
 986     javaIDs.Window.notifyInitAccessibility = env->GetMethodID(cls, "notifyInitAccessibility", "()V");
 987     ASSERT(javaIDs.Window.notifyInitAccessibility);
 988 }
 989 
 990 /*
 991  * Class:     com_sun_glass_ui_win_WinWindow
 992  * Method:    _createWindow
 993  * Signature: (JJZI)J
 994  */
 995 JNIEXPORT jlong JNICALL Java_com_sun_glass_ui_win_WinWindow__1createWindow
 996     (JNIEnv *env, jobject jThis, jlong ownerPtr, jlong screenPtr, jint mask)
 997 {
 998     ENTER_MAIN_THREAD_AND_RETURN(jlong)
 999     {
1000         DWORD dwStyle;
1001         DWORD dwExStyle;
1002         bool closeable;
1003 
1004         dwStyle = WS_CLIPCHILDREN | WS_SYSMENU;
1005         closeable = (mask & com_sun_glass_ui_Window_CLOSABLE) != 0;
1006 
1007         if (mask & com_sun_glass_ui_Window_TITLED) {
1008             dwExStyle = WS_EX_WINDOWEDGE;
1009             dwStyle |= WS_CAPTION;
1010 
1011             if (mask & com_sun_glass_ui_Window_MINIMIZABLE) {
1012                 dwStyle |= WS_MINIMIZEBOX;
1013             }
1014             if (mask & com_sun_glass_ui_Window_MAXIMIZABLE) {
1015                 dwStyle |= WS_MAXIMIZEBOX;
1016             }
1017         } else {
1018             dwExStyle = 0;
1019             dwStyle |= WS_POPUP;
1020         }
1021 
1022         if (mask & com_sun_glass_ui_Window_TRANSPARENT) {
1023             dwExStyle |= WS_EX_LAYERED;
1024         }
1025 
1026         if (mask & com_sun_glass_ui_Window_POPUP) {
1027             dwStyle |= WS_POPUP;
1028             // Popups should not appear in the taskbar, so WS_EX_TOOLWINDOW
1029             dwExStyle |= WS_EX_TOOLWINDOW;
1030         }
1031 
1032         if (mask & com_sun_glass_ui_Window_UTILITY) {
1033             dwExStyle |= WS_EX_TOOLWINDOW;
1034         }
1035 
1036         if (mask & com_sun_glass_ui_Window_RIGHT_TO_LEFT) {
1037             dwExStyle |= WS_EX_NOINHERITLAYOUT | WS_EX_LAYOUTRTL;
1038         }
1039 
1040         GlassWindow *pWindow =
1041             new GlassWindow(jThis,
1042                 (mask & com_sun_glass_ui_Window_TRANSPARENT) != 0,
1043                 (mask & com_sun_glass_ui_Window_TITLED) != 0,
1044                 (mask & com_sun_glass_ui_Window_UNIFIED) != 0,
1045                 false,
1046                 owner);
1047 
1048         HWND hWnd = pWindow->Create(dwStyle, dwExStyle, hMonitor, owner);
1049 
1050         if (!hWnd) {
1051             delete pWindow;
1052         } else {
1053             if (!closeable) {
1054                 HMENU hSysMenu = ::GetSystemMenu(hWnd, FALSE);
1055                 if (hSysMenu != NULL) {
1056                     ::EnableMenuItem(hSysMenu, SC_CLOSE,
1057                             MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
1058                 }
1059             }
1060         }
1061 
1062         return (jlong)hWnd;
1063     }
1064     DECL_jobject(jThis);
1065     HWND owner;
1066     HMONITOR hMonitor;
1067     jint mask;
1068     LEAVE_MAIN_THREAD;
1069 
1070     ARG(jThis) = jThis;
1071     ARG(owner) = (HWND)ownerPtr;
1072     ARG(hMonitor) = (HMONITOR)screenPtr;
1073     ARG(mask) = mask;
1074 
1075     return PERFORM_AND_RETURN();
1076 }
1077 
1078 /*
1079  * Class:     com_sun_glass_ui_win_WinWindow
1080  * Method:    _createChildWindow
1081  * Signature: (J)J
1082  */
1083 JNIEXPORT jlong JNICALL Java_com_sun_glass_ui_win_WinWindow__1createChildWindow
1084     (JNIEnv *env, jobject jThis, jlong parentPtr)
1085 {
1086     ENTER_MAIN_THREAD_AND_RETURN(jlong)
1087     {
1088         // Check that the 'parent' isn't a garbage value
1089         if (!::IsWindow((HWND)parent)) {
1090             return (jlong)0;
1091         }
1092 
1093         DWORD dwStyle;
1094         DWORD dwExStyle;
1095 
1096         dwStyle = WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_CHILD;
1097         dwExStyle = WS_EX_NOINHERITLAYOUT;
1098 
1099         GlassWindow *pWindow =
1100             new GlassWindow(jThis, false, false, false, true, parent);
1101 
1102         HWND hWnd = pWindow->Create(dwStyle, dwExStyle, NULL, parent);
1103 
1104         if (!hWnd) {
1105             delete pWindow;
1106         }
1107 
1108         return (jlong)hWnd;
1109     }
1110     DECL_jobject(jThis);
1111     HWND parent;
1112     LEAVE_MAIN_THREAD;
1113 
1114     ARG(jThis) = jThis;
1115     ARG(parent) = (HWND)parentPtr;
1116 
1117     return PERFORM_AND_RETURN();
1118 }
1119 /*
1120  * Class:     com_sun_glass_ui_win_WinWindow
1121  * Method:    _close
1122  * Signature: (J)Z
1123  */
1124 JNIEXPORT jboolean JNICALL Java_com_sun_glass_ui_win_WinWindow__1close
1125     (JNIEnv *env, jobject jThis, jlong ptr)
1126 {
1127     ENTER_MAIN_THREAD_AND_RETURN(jboolean)
1128     {
1129         GlassWindow *pWindow = GlassWindow::FromHandle(hWnd);
1130         pWindow->Close();
1131         return bool_to_jbool(::DestroyWindow(hWnd));
1132     }
1133     LEAVE_MAIN_THREAD_WITH_hWnd;
1134 
1135     return PERFORM_AND_RETURN();
1136 }
1137 
1138 /*
1139  * Class:     com_sun_glass_ui_win_WinWindow
1140  * Method:    _setView
1141  * Signature: (JJ)Z
1142  */
1143 JNIEXPORT jboolean JNICALL Java_com_sun_glass_ui_win_WinWindow__1setView
1144     (JNIEnv * env, jobject jThis, jlong ptr, jobject view)
1145 {
1146     ENTER_MAIN_THREAD()
1147     {
1148         GlassWindow *pWindow = GlassWindow::FromHandle(hWnd);
1149         pWindow->ResetMouseTracking(hWnd);
1150         pWindow->SetGlassView(view);
1151         // The condition below may be restricted to WS_POPUP windows
1152         if (::IsWindowVisible(hWnd)) {
1153             pWindow->NotifyViewSize(hWnd);
1154         }
1155     }
1156     GlassView * view;
1157     LEAVE_MAIN_THREAD_WITH_hWnd;
1158 
1159     ARG(view) = view == NULL ? NULL : (GlassView*)env->GetLongField(view, javaIDs.View.ptr);
1160 
1161     PERFORM();
1162     return JNI_TRUE;
1163 }
1164 
1165 /*
1166  * Class:     com_sun_glass_ui_win_WinWindow
1167  * Method:    _setMenubar
1168  * Signature: (JJ)Z
1169  */
1170 JNIEXPORT jboolean JNICALL Java_com_sun_glass_ui_win_WinWindow__1setMenubar
1171     (JNIEnv *env, jobject jThis, jlong ptr, jlong menuPtr)
1172 {
1173     ENTER_MAIN_THREAD_AND_RETURN(jboolean)
1174     {
1175         if (::SetMenu(hWnd, hMenu))
1176         {
1177             GlassWindow *pWindow = GlassWindow::FromHandle(hWnd);
1178             if (pWindow) {
1179                 pWindow->SetMenu(hMenu);
1180             }
1181 
1182             return JNI_TRUE;
1183         }
1184         return JNI_FALSE;
1185     }
1186     HMENU hMenu;
1187     LEAVE_MAIN_THREAD_WITH_hWnd;
1188 
1189     ARG(hMenu) = (HMENU)menuPtr;
1190     return PERFORM_AND_RETURN();
1191 }
1192 
1193 /*
1194  * Class:     com_sun_glass_ui_win_WinWindow
1195  * Method:    _setLevel
1196  * Signature: (JI)V
1197  */
1198 JNIEXPORT void JNICALL Java_com_sun_glass_ui_win_WinWindow__1setLevel
1199 (JNIEnv *env, jobject jwindow, jlong ptr, jint jLevel)
1200 {
1201     ENTER_MAIN_THREAD()
1202     {
1203         ::SetWindowPos(hWnd, hWndInsertAfter, 0, 0, 0, 0,
1204                 SWP_ASYNCWINDOWPOS | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOSIZE);
1205     }
1206     HWND hWndInsertAfter;
1207     LEAVE_MAIN_THREAD_WITH_hWnd;
1208 
1209     ARG(hWndInsertAfter) = HWND_NOTOPMOST;
1210     switch (jLevel) {
1211         case com_sun_glass_ui_Window_Level_FLOATING:
1212         case com_sun_glass_ui_Window_Level_TOPMOST:
1213             ARG(hWndInsertAfter) = HWND_TOPMOST;
1214             break;
1215     }
1216     PERFORM();
1217 }
1218 
1219 /*
1220  * Class:     com_sun_glass_ui_win_WinWindow
1221  * Method:    _setFocusable
1222  * Signature: (JZ)V
1223  */
1224 JNIEXPORT void JNICALL Java_com_sun_glass_ui_win_WinWindow__1setFocusable
1225 (JNIEnv *env, jobject jwindow, jlong ptr, jboolean isFocusable)
1226 {
1227     ENTER_MAIN_THREAD()
1228     {
1229         GlassWindow *pWindow = GlassWindow::FromHandle(hWnd);
1230         pWindow->SetFocusable(isFocusable);
1231     }
1232     bool isFocusable;
1233     LEAVE_MAIN_THREAD_WITH_hWnd;
1234 
1235     ARG(isFocusable) = isFocusable == JNI_TRUE;
1236     PERFORM();
1237 }
1238 
1239 /*
1240  * Class:     com_sun_glass_ui_win_WinWindow
1241  * Method:    _setEnabled
1242  * Signature: (JZ)V
1243  */
1244 JNIEXPORT void JNICALL Java_com_sun_glass_ui_win_WinWindow__1setEnabled
1245 (JNIEnv *env, jobject jwindow, jlong ptr, jboolean isEnabled)
1246 {
1247     ENTER_MAIN_THREAD()
1248     {
1249         GlassWindow *pWindow = GlassWindow::FromHandle(hWnd);
1250         pWindow->SetEnabled(isEnabled);
1251         ::EnableWindow(hWnd, isEnabled);
1252     }
1253     bool isEnabled;
1254     LEAVE_MAIN_THREAD_WITH_hWnd;
1255 
1256     ARG(isEnabled) = isEnabled == JNI_TRUE;
1257     PERFORM();
1258 }
1259 
1260 // Converts a float [0..1] to a BYTE [0..255]
1261 #define F2B(value) BYTE(255.f * (value))
1262 
1263 /*
1264  * Class:     com_sun_glass_ui_win_WinWindow
1265  * Method:    _setAlpha
1266  * Signature: (JF)V
1267  */
1268 JNIEXPORT void JNICALL Java_com_sun_glass_ui_win_WinWindow__1setAlpha
1269     (JNIEnv *env, jobject jThis, jlong ptr, jfloat alpha)
1270 {
1271     ENTER_MAIN_THREAD()
1272     {
1273         GlassWindow *pWindow = GlassWindow::FromHandle(hWnd);
1274         pWindow->SetAlpha(alpha);
1275     }
1276     BYTE alpha;
1277     LEAVE_MAIN_THREAD_WITH_hWnd;
1278 
1279     ARG(alpha) = F2B(alpha);
1280     PERFORM();
1281 }
1282 
1283 /*
1284  * Class:     com_sun_glass_ui_win_WinWindow
1285  * Method:    _setBackground
1286  * Signature: (JFFF)Z
1287  */
1288 JNIEXPORT jboolean JNICALL Java_com_sun_glass_ui_win_WinWindow__1setBackground
1289     (JNIEnv *env, jobject jThis, jlong ptr, jfloat r, jfloat g, jfloat b)
1290 {
1291     ENTER_MAIN_THREAD()
1292     {
1293         HBRUSH hbrBackground;
1294 
1295         // That's a hack with 'negative' color
1296         if (r < 0) {
1297             hbrBackground = NULL;
1298         } else {
1299             hbrBackground = ::CreateSolidBrush(RGB(F2B(r), F2B(g), F2B(b)));
1300         }
1301 
1302         HBRUSH oldBrush = (HBRUSH)::SetClassLongPtr(hWnd, GCLP_HBRBACKGROUND, (LONG_PTR)hbrBackground);
1303 
1304         if (oldBrush) {
1305             ::DeleteObject(oldBrush);
1306         }
1307     }
1308     jfloat r, g, b;
1309     LEAVE_MAIN_THREAD_WITH_hWnd;
1310 
1311     ARG(r) = r;
1312     ARG(g) = g;
1313     ARG(b) = b;
1314     PERFORM();
1315 
1316     return JNI_TRUE;
1317 }
1318 
1319 /*
1320  * Class:     com_sun_glass_ui_win_WinWindow
1321  * Method:    _setBounds
1322  * Signature: (JIIZZIIIIFF)Z
1323  */
1324 JNIEXPORT void JNICALL Java_com_sun_glass_ui_win_WinWindow__1setBounds
1325     (JNIEnv *env, jobject jThis, jlong ptr,
1326      jint x, jint y, jboolean xSet, jboolean ySet,
1327      jint w, jint h, jint cw, jint ch,
1328      jfloat xGravity, jfloat yGravity)
1329 {
1330     ENTER_MAIN_THREAD()
1331     {
1332         GlassWindow *pWindow = GlassWindow::FromHandle(hWnd);
1333 
1334         pWindow->UpdateInsets();
1335         RECT is = pWindow->GetInsets();
1336 
1337         RECT r;
1338         ::GetWindowRect(hWnd, &r);
1339 
1340         int newX = jbool_to_bool(xSet) ? x : r.left;
1341         int newY = jbool_to_bool(ySet) ? y : r.top;
1342         int newW = w > 0 ? w :
1343                        cw > 0 ? cw + is.right + is.left : r.right - r.left;
1344         int newH = h > 0 ? h :
1345                        ch > 0 ? ch + is.bottom + is.top : r.bottom - r.top;
1346 
1347         if (xSet || ySet) {
1348             ::SetWindowPos(hWnd, NULL, newX, newY, newW, newH,
1349                            SWP_NOACTIVATE | SWP_NOZORDER);
1350         } else {
1351             ::SetWindowPos(hWnd, NULL, 0, 0, newW, newH,
1352                            SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE);
1353         }
1354     }
1355     jint x, y;
1356     jboolean xSet, ySet;
1357     jint w, h, cw, ch;
1358     LEAVE_MAIN_THREAD_WITH_hWnd;
1359 
1360     ARG(x) = x;
1361     ARG(y) = y;
1362     ARG(xSet) = xSet;
1363     ARG(ySet) = ySet;
1364     ARG(w) = w;
1365     ARG(h) = h;
1366     ARG(cw) = cw;
1367     ARG(ch) = ch;
1368     PERFORM();
1369 
1370 }
1371 
1372 /*
1373  * Class:     com_sun_glass_ui_win_WinWindow
1374  * Method:    _setTitle
1375  * Signature: (JLjava/lang/String;)Z
1376  */
1377 JNIEXPORT jboolean JNICALL Java_com_sun_glass_ui_win_WinWindow__1setTitle
1378     (JNIEnv *env, jobject jThis, jlong ptr, jstring jTitle)
1379 {
1380     ENTER_MAIN_THREAD_AND_RETURN(jboolean)
1381     {
1382         if (::SetWindowText(hWnd, title)) {
1383             return JNI_TRUE;
1384         }
1385         return JNI_FALSE;
1386     }
1387     LPCTSTR title;
1388     LEAVE_MAIN_THREAD_WITH_hWnd;
1389 
1390     JString title(env, jTitle);
1391     ARG(title) = title;
1392     return PERFORM_AND_RETURN();
1393 }
1394 
1395 /*
1396  * Class:     com_sun_glass_ui_win_WinWindow
1397  * Method:    _setResizable
1398  * Signature: (Z)Z
1399  */
1400 JNIEXPORT jboolean JNICALL Java_com_sun_glass_ui_win_WinWindow__1setResizable
1401 (JNIEnv *env, jobject jWindow, jlong ptr, jboolean jResizable)
1402 {
1403     ENTER_MAIN_THREAD_AND_RETURN(jboolean)
1404     {
1405         GlassWindow *pWindow = GlassWindow::FromHandle(hWnd);
1406         if (pWindow && pWindow->SetResizable(jbool_to_bool(jResizable))) {
1407             return JNI_TRUE;
1408         }
1409 
1410         return JNI_FALSE;
1411     }
1412     jboolean jResizable;
1413     LEAVE_MAIN_THREAD_WITH_hWnd;
1414 
1415     ARG(jResizable) = jResizable;
1416     return PERFORM_AND_RETURN();
1417 }
1418 
1419 /*
1420  * Class:     com_sun_glass_ui_win_WinWindow
1421  * Method:    _setVisible
1422  * Signature: (JZ)Z
1423  */
1424 JNIEXPORT jboolean JNICALL Java_com_sun_glass_ui_win_WinWindow__1setVisible
1425     (JNIEnv *env, jobject jThis, jlong ptr, jboolean visible)
1426 {
1427     ENTER_MAIN_THREAD()
1428     {
1429         GlassWindow *pWindow = GlassWindow::FromHandle(hWnd);
1430         if (!visible) {
1431             if (pWindow) {
1432                 pWindow->UngrabFocus();
1433             }
1434         }
1435         
1436         ::ShowWindow(hWnd, visible ? SW_SHOW : SW_HIDE);
1437         
1438         if (visible) {
1439             if (pWindow) {
1440                 if (pWindow->IsFocusable()) {
1441                     ::SetForegroundWindow(hWnd);
1442                 } else {
1443                     // RT-14197:
1444                     // On some latest platform versions, unfocusable windows
1445                     // are shown below the currently active window, so we
1446                     // need to pull them to front explicitly. However,
1447                     // neither BringWindowToTop nor SetForegroundWindow()
1448                     // can be used because of the window unfocusability, so
1449                     // here is a workaround: we first made the window TOPMOST
1450                     // and then reset this flag to just TOP.
1451                     ::SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0,
1452                                    SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
1453                     ::SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0,
1454                                    SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
1455                 }
1456             }
1457             ::UpdateWindow(hWnd);
1458         }
1459     }
1460     jboolean visible;
1461     LEAVE_MAIN_THREAD_WITH_hWnd;
1462 
1463     ARG(visible) = visible;
1464     PERFORM();
1465     return visible;
1466 }
1467 
1468 /*
1469  * Class:     com_sun_glass_ui_win_WinWindow
1470  * Method:    _requestFocus
1471  * Signature: (JI)Z
1472  */
1473 JNIEXPORT jboolean JNICALL Java_com_sun_glass_ui_win_WinWindow__1requestFocus
1474     (JNIEnv *env, jobject jThis, jlong ptr, jint event)
1475 {
1476     ENTER_MAIN_THREAD_AND_RETURN(jboolean)
1477     {
1478         GlassWindow *pWindow = GlassWindow::FromHandle(hWnd);
1479         return bool_to_jbool(pWindow && pWindow->RequestFocus(event));
1480     }
1481     jint event;
1482     LEAVE_MAIN_THREAD_WITH_hWnd;
1483 
1484     ARG(event) = event;
1485 
1486     return PERFORM_AND_RETURN();
1487 }
1488 
1489 /*
1490  * Class:     com_sun_glass_ui_win_WinWindow
1491  * Method:    _grabFocus
1492  * Signature: (J)Z
1493  */
1494 JNIEXPORT jboolean JNICALL Java_com_sun_glass_ui_win_WinWindow__1grabFocus
1495     (JNIEnv *env, jobject jThis, jlong ptr)
1496 {
1497     ENTER_MAIN_THREAD_AND_RETURN(jboolean)
1498     {
1499         GlassWindow *pWindow = GlassWindow::FromHandle(hWnd);
1500         return bool_to_jbool(pWindow && pWindow->GrabFocus());
1501     }
1502     LEAVE_MAIN_THREAD_WITH_hWnd;
1503 
1504     return PERFORM_AND_RETURN();
1505 }
1506 
1507 /*
1508  * Class:     com_sun_glass_ui_win_WinWindow
1509  * Method:    _ungrabFocus
1510  * Signature: (J)V
1511  */
1512 JNIEXPORT void JNICALL Java_com_sun_glass_ui_win_WinWindow__1ungrabFocus
1513     (JNIEnv *env, jobject jThis, jlong ptr)
1514 {
1515     ENTER_MAIN_THREAD()
1516     {
1517         GlassWindow *pWindow = GlassWindow::FromHandle(hWnd);
1518         if (pWindow) {
1519             pWindow->UngrabFocus();
1520         }
1521     }
1522     LEAVE_MAIN_THREAD_WITH_hWnd;
1523 
1524     PERFORM();
1525 }
1526 
1527 /*
1528  * Class:     com_sun_glass_ui_win_WinWindow
1529  * Method:    _minimize
1530  * Signature: (JZ)Z
1531  */
1532 JNIEXPORT jboolean JNICALL Java_com_sun_glass_ui_win_WinWindow__1minimize
1533     (JNIEnv *env, jobject jThis, jlong ptr, jboolean minimize)
1534 {
1535     ENTER_MAIN_THREAD()
1536     {
1537         ::ShowWindow(hWnd, minimize ? SW_MINIMIZE : SW_RESTORE);
1538     }
1539     jboolean minimize;
1540     LEAVE_MAIN_THREAD_WITH_hWnd;
1541 
1542     ARG(minimize) = minimize;
1543     PERFORM();
1544 
1545     return JNI_TRUE;
1546 }
1547 
1548 /*
1549  * Class:     com_sun_glass_ui_win_WinWindow
1550  * Method:    _maximize
1551  * Signature: (JZ)Z
1552  */
1553 JNIEXPORT jboolean JNICALL Java_com_sun_glass_ui_win_WinWindow__1maximize
1554   (JNIEnv *env, jobject jThis, jlong ptr, jboolean maximize, jboolean wasMaximized)
1555 {
1556     ENTER_MAIN_THREAD()
1557     {
1558         ::ShowWindow(hWnd, maximize ? SW_MAXIMIZE : SW_RESTORE);
1559     }
1560     jboolean maximize;
1561     LEAVE_MAIN_THREAD_WITH_hWnd;
1562 
1563     ARG(maximize) = maximize;
1564     PERFORM();
1565 
1566     return JNI_TRUE;
1567 }
1568 
1569 /*
1570  * Class:     com_sun_glass_ui_win_WinWindow
1571  * Method:    _setMinimumSize
1572  * Signature: (JII)Z
1573  */
1574 JNIEXPORT jboolean JNICALL Java_com_sun_glass_ui_win_WinWindow__1setMinimumSize
1575     (JNIEnv *env, jobject jThis, jlong ptr, jint minWidth, jint minHeight)
1576 {
1577     ENTER_MAIN_THREAD_AND_RETURN(jboolean)
1578     {
1579         GlassWindow *pWindow = GlassWindow::FromHandle(hWnd);
1580         if (pWindow) {
1581             pWindow->setMinSize(minWidth, minHeight);
1582             return JNI_TRUE;
1583         }
1584         return JNI_FALSE;
1585     }
1586     jint minWidth;
1587     jint minHeight;
1588     LEAVE_MAIN_THREAD_WITH_hWnd;
1589 
1590     ARG(minWidth) = minWidth == 0 ? -1 : minWidth;
1591     ARG(minHeight) = minHeight == 0 ? -1 : minHeight;
1592     return PERFORM_AND_RETURN();
1593 }
1594 
1595 /*
1596  * Class:     com_sun_glass_ui_win_WinWindow
1597  * Method:    _setMaximumSize
1598  * Signature: (JII)Z
1599  */
1600 JNIEXPORT jboolean JNICALL Java_com_sun_glass_ui_win_WinWindow__1setMaximumSize
1601     (JNIEnv *env, jobject jThis, jlong ptr, jint maxWidth, jint maxHeight)
1602 {
1603     ENTER_MAIN_THREAD_AND_RETURN(jboolean)
1604     {
1605         GlassWindow *pWindow = GlassWindow::FromHandle(hWnd);
1606         if (pWindow) {
1607             pWindow->setMaxSize(maxWidth, maxHeight);
1608             return JNI_TRUE;
1609         }
1610         return JNI_FALSE;
1611     }
1612     jint maxWidth;
1613     jint maxHeight;
1614     LEAVE_MAIN_THREAD_WITH_hWnd;
1615 
1616     ARG(maxWidth) = maxWidth;
1617     ARG(maxHeight) = maxHeight;
1618     return PERFORM_AND_RETURN();
1619 }
1620 
1621 /*
1622  * Class:     com_sun_glass_ui_win_WinWindow
1623  * Method:    _setIcon
1624  * Signature: (JLcom/sun/glass/ui/Pixels;)V
1625  */
1626 JNIEXPORT void JNICALL Java_com_sun_glass_ui_win_WinWindow__1setIcon
1627     (JNIEnv *env, jobject jThis, jlong ptr, jobject jPixels)
1628 {
1629     HWND hWnd = (HWND)ptr;
1630 
1631     // ::SendMessage() is OK to call from any thread - don't bother with ENTER...
1632     if (!jPixels) {
1633         ::SendMessage(hWnd, WM_SETICON, ICON_SMALL, NULL);
1634         ::SendMessage(hWnd, WM_SETICON, ICON_BIG, NULL);
1635     } else {
1636         HICON hIcon = Pixels::CreateIcon(env, jPixels);
1637 
1638         ::SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM)hIcon);
1639         ::SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
1640     }
1641 }
1642 
1643 /*
1644  * Class:     com_sun_glass_ui_win_WinWindow
1645  * Method:    _toFront
1646  * Signature: (J)V
1647  */
1648 JNIEXPORT void JNICALL Java_com_sun_glass_ui_win_WinWindow__1toFront
1649     (JNIEnv *env, jobject jThis, jlong ptr)
1650 {
1651     ENTER_MAIN_THREAD()
1652     {
1653         GlassWindow *pWindow = GlassWindow::FromHandle(hWnd);
1654         // See comment in __1setVisible() above about unfocusable windows
1655         if (pWindow && !pWindow->IsFocusable()) {
1656             ::SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
1657         }
1658         ::SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
1659     }
1660     LEAVE_MAIN_THREAD_WITH_hWnd;
1661 
1662     PERFORM();
1663 }
1664 
1665 /*
1666  * Class:     com_sun_glass_ui_win_WinWindow
1667  * Method:    _toBack
1668  * Signature: (J)V
1669  */
1670 JNIEXPORT void JNICALL Java_com_sun_glass_ui_win_WinWindow__1toBack
1671     (JNIEnv *env, jobject jThis, jlong ptr)
1672 {
1673     ENTER_MAIN_THREAD()
1674     {
1675         ::SetWindowPos(hWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
1676     }
1677     LEAVE_MAIN_THREAD_WITH_hWnd;
1678 
1679     PERFORM();
1680 }
1681 
1682 /*
1683  * Class:     com_sun_glass_ui_win_WinWindow
1684  * Method:    _getEmbeddedX
1685  * Signature: (J)I
1686  */
1687 JNIEXPORT jint JNICALL Java_com_sun_glass_ui_win_WinWindow__1getEmbeddedX
1688     (JNIEnv *env, jobject jThis, jlong ptr)
1689 {
1690     ENTER_MAIN_THREAD_AND_RETURN(jint)
1691     {
1692         GlassWindow *pWindow = GlassWindow::FromHandle(hWnd);
1693         HWND delegateHWnd = pWindow ? pWindow->GetDelegateWindow() : 0;
1694         RECT rect = {0};
1695         ::MapWindowPoints(delegateHWnd ? delegateHWnd : hWnd, (HWND)NULL, (LPPOINT)&rect, (sizeof(RECT)/sizeof(POINT)));
1696         return rect.left;
1697     }
1698     LEAVE_MAIN_THREAD_WITH_hWnd;
1699 
1700     return PERFORM_AND_RETURN();
1701 }
1702 
1703 /*
1704  * Class:     com_sun_glass_ui_win_WinWindow
1705  * Method:    _getEmbeddedY
1706  * Signature: (J)I
1707  */
1708 JNIEXPORT jint JNICALL Java_com_sun_glass_ui_win_WinWindow__1getEmbeddedY
1709     (JNIEnv *env, jobject jThis, jlong ptr)
1710 {
1711     ENTER_MAIN_THREAD_AND_RETURN(jint)
1712     {
1713         GlassWindow *pWindow = GlassWindow::FromHandle(hWnd);
1714         HWND delegateHWnd = pWindow ? pWindow->GetDelegateWindow() : 0;
1715         RECT rect = {0};
1716         ::MapWindowPoints(delegateHWnd ? delegateHWnd : hWnd, (HWND)NULL, (LPPOINT)&rect, (sizeof(RECT)/sizeof(POINT)));
1717         return rect.top;
1718     }
1719     LEAVE_MAIN_THREAD_WITH_hWnd;
1720 
1721     return PERFORM_AND_RETURN();
1722 }
1723 
1724 /*
1725  * Class:     com_sun_glass_ui_win_WinWindow
1726  * Method:    _setCursor
1727  * Signature: (Lcom/sun/glass/ui/Cursor;)V
1728  */
1729 JNIEXPORT void JNICALL Java_com_sun_glass_ui_win_WinWindow__1setCursor
1730     (JNIEnv *env, jobject jThis, jlong ptr, jobject jCursor)
1731 {
1732     ENTER_MAIN_THREAD()
1733     {
1734         const HCURSOR cursor = JCursorToHCURSOR(GetEnv(), jCursor);
1735 
1736         GlassWindow *pWindow = GlassWindow::FromHandle(hWnd);
1737         if (pWindow) {
1738             pWindow->SetCursor(cursor);
1739 
1740             // Update the delegate window as well if present
1741             HWND delegateHwnd = pWindow->GetDelegateWindow();
1742             if (delegateHwnd) {
1743                 BaseWnd *pDelegateWindow = BaseWnd::FromHandle(delegateHwnd);
1744                 if (pDelegateWindow) {
1745                     pDelegateWindow->SetCursor(cursor);
1746                 }
1747             }
1748         }
1749     }
1750     DECL_jobject(jCursor);
1751     LEAVE_MAIN_THREAD_WITH_hWnd;
1752 
1753     ARG(jCursor) = jCursor;
1754     PERFORM();
1755 }
1756 
1757 }   // extern "C"