1 /*
   2  * Copyright (c) 1996, 2014, 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 "jni_util.h"
  27 #include "awt_Toolkit.h"
  28 #include "awt_Dialog.h"
  29 #include "awt_Window.h"
  30 
  31 #include <windowsx.h>
  32 
  33 #include "java_awt_Dialog.h"
  34 
  35 /* IMPORTANT! Read the README.JNI file for notes on JNI converted AWT code.
  36  */
  37 
  38 /************************************************************************/
  39 // Struct for _SetIMMOption() method
  40 struct SetIMMOptionStruct {
  41     jobject dialog;
  42     jstring option;
  43 };
  44 /************************************************************************
  45  * AwtDialog fields
  46  */
  47 
  48 jfieldID AwtDialog::titleID;
  49 jfieldID AwtDialog::undecoratedID;
  50 
  51 #if defined(DEBUG)
  52 // counts how many nested modal dialogs are open, a sanity
  53 // check to ensure the somewhat complicated disable/enable
  54 // code is working properly
  55 int AwtModalityNestCounter = 0;
  56 #endif
  57 
  58 HHOOK AWTModalHook;
  59 HHOOK AWTMouseHook;
  60 
  61 int VisibleModalDialogsCount = 0;
  62 
  63 /************************************************************************
  64  * AwtDialog class methods
  65  */
  66 
  67 AwtDialog::AwtDialog() {
  68     m_modalWnd = NULL;
  69 }
  70 
  71 AwtDialog::~AwtDialog()
  72 {
  73 }
  74 
  75 void AwtDialog::Dispose()
  76 {
  77     if (m_modalWnd != NULL) {
  78         WmEndModal();
  79     }
  80     AwtFrame::Dispose();
  81 }
  82 
  83 LPCTSTR AwtDialog::GetClassName() {
  84   return AWT_DIALOG_WINDOW_CLASS_NAME;
  85 }
  86 
  87 void AwtDialog::FillClassInfo(WNDCLASSEX *lpwc)
  88 {
  89     AwtWindow::FillClassInfo(lpwc);
  90     //Fixed 6280303: REGRESSION: Java cup icon appears in title bar of dialogs
  91     // Dialog inherits icon from its owner dinamically
  92     lpwc->hIcon = NULL;
  93     lpwc->hIconSm = NULL;
  94 }
  95 
  96 /*
  97  * Create a new AwtDialog object and window.
  98  */
  99 AwtDialog* AwtDialog::Create(jobject peer, jobject parent)
 100 {
 101     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 102 
 103     jobject background = NULL;
 104     jobject target = NULL;
 105     AwtDialog* dialog = NULL;
 106 
 107     try {
 108         if (env->EnsureLocalCapacity(2) < 0) {
 109             return NULL;
 110         }
 111 
 112         PDATA pData;
 113         AwtWindow* awtParent = NULL;
 114         HWND hwndParent = NULL;
 115 
 116         target = env->GetObjectField(peer, AwtObject::targetID);
 117         JNI_CHECK_NULL_GOTO(target, "null target", done);
 118 
 119         if (parent != NULL) {
 120             JNI_CHECK_PEER_GOTO(parent, done);
 121             awtParent = (AwtWindow *)pData;
 122             hwndParent = awtParent->GetHWnd();
 123         } else {
 124             // There is no way to prevent a parentless dialog from showing on
 125             //  the taskbar other than to specify an invisible parent and set
 126             //  WS_POPUP style for the dialog. Using toolkit window here. That
 127             //  will also excludes the dialog from appearing in window list while
 128             //  ALT+TAB'ing
 129             // From the other point, it may be confusing when the dialog without
 130             //  an owner is missing on the toolbar. So, do not set any fake
 131             //  parent window here.
 132 //            hwndParent = AwtToolkit::GetInstance().GetHWnd();
 133         }
 134         dialog = new AwtDialog();
 135 
 136         {
 137             int colorId = COLOR_3DFACE;
 138             DWORD style = WS_CAPTION | WS_SYSMENU | WS_CLIPCHILDREN;
 139             if (hwndParent != NULL) {
 140                 style |= WS_POPUP;
 141             }
 142             style &= ~(WS_MINIMIZEBOX|WS_MAXIMIZEBOX);
 143             DWORD exStyle = WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME;
 144 
 145             if (GetRTL()) {
 146                 exStyle |= WS_EX_RIGHT | WS_EX_LEFTSCROLLBAR;
 147                 if (GetRTLReadingOrder())
 148                     exStyle |= WS_EX_RTLREADING;
 149             }
 150 
 151 
 152             if (env->GetBooleanField(target, AwtDialog::undecoratedID) == JNI_TRUE) {
 153                 style = WS_POPUP | WS_CLIPCHILDREN;
 154                 exStyle = 0;
 155                 dialog->m_isUndecorated = TRUE;
 156             }
 157 
 158             jint x = env->GetIntField(target, AwtComponent::xID);
 159             jint y = env->GetIntField(target, AwtComponent::yID);
 160             jint width = env->GetIntField(target, AwtComponent::widthID);
 161             jint height = env->GetIntField(target, AwtComponent::heightID);
 162 
 163             dialog->CreateHWnd(env, L"",
 164                                style, exStyle,
 165                                x, y, width, height,
 166                                hwndParent,
 167                                NULL,
 168                                ::GetSysColor(COLOR_WINDOWTEXT),
 169                                ::GetSysColor(colorId),
 170                                peer);
 171 
 172             dialog->RecalcNonClient();
 173             dialog->UpdateSystemMenu();
 174 
 175             /*
 176              * Initialize icon as inherited from parent if it exists
 177              */
 178             if (parent != NULL) {
 179                 dialog->m_hIcon = awtParent->GetHIcon();
 180                 dialog->m_hIconSm = awtParent->GetHIconSm();
 181                 dialog->m_iconInherited = TRUE;
 182             }
 183             dialog->DoUpdateIcon();
 184 
 185 
 186             background = env->GetObjectField(target,
 187                                              AwtComponent::backgroundID);
 188             if (background == NULL) {
 189                 JNU_CallMethodByName(env, NULL,
 190                                      peer, "setDefaultColor", "()V");
 191             }
 192         }
 193     } catch (...) {
 194         env->DeleteLocalRef(background);
 195         env->DeleteLocalRef(target);
 196         throw;
 197     }
 198 
 199 done:
 200     env->DeleteLocalRef(background);
 201     env->DeleteLocalRef(target);
 202 
 203     return dialog;
 204 }
 205 
 206 MsgRouting AwtDialog::WmNcMouseDown(WPARAM hitTest, int x, int y, int button) {
 207     // By the request from Swing team, click on the Dialog's title should generate Ungrab
 208     if (m_grabbedWindow != NULL/* && !m_grabbedWindow->IsOneOfOwnersOf(this)*/) {
 209         m_grabbedWindow->Ungrab();
 210     }
 211 
 212     if (!IsFocusableWindow() && (button & LEFT_BUTTON)) {
 213         // Dialog is non-maximizable
 214         if ((button & DBL_CLICK) && hitTest == HTCAPTION) {
 215             return mrConsume;
 216         }
 217     }
 218     return AwtFrame::WmNcMouseDown(hitTest, x, y, button);
 219 }
 220 
 221 LRESULT CALLBACK AwtDialog::ModalFilterProc(int code,
 222                                             WPARAM wParam, LPARAM lParam)
 223 {
 224     HWND hWnd = (HWND)wParam;
 225     HWND blocker = AwtWindow::GetModalBlocker(hWnd);
 226     if (::IsWindow(blocker) &&
 227         ((code == HCBT_ACTIVATE) ||
 228          (code == HCBT_SETFOCUS)))
 229     {
 230         // fix for 6270632: this window and all its blockers can be minimized by
 231         // "show desktop" button, so we should restore them first
 232         if (::IsIconic(hWnd)) {
 233             ::ShowWindow(hWnd, SW_RESTORE);
 234         }
 235         PopupBlockers(blocker, TRUE, ::GetForegroundWindow(), FALSE);
 236         // return 1 to prevent the system from allowing the operation
 237         return 1;
 238     }
 239     return CallNextHookEx(0, code, wParam, lParam);
 240 }
 241 
 242 LRESULT CALLBACK AwtDialog::MouseHookProc(int nCode,
 243                                           WPARAM wParam, LPARAM lParam)
 244 {
 245     if (nCode >= 0)
 246     {
 247         MOUSEHOOKSTRUCT *mhs = (MOUSEHOOKSTRUCT *)lParam;
 248         HWND hWnd = mhs->hwnd;
 249         if ((wParam == WM_LBUTTONDOWN) ||
 250             (wParam == WM_MBUTTONDOWN) ||
 251             (wParam == WM_RBUTTONDOWN) ||
 252             (wParam == WM_MOUSEACTIVATE) ||
 253             (wParam == WM_MOUSEWHEEL) ||
 254             (wParam == WM_NCLBUTTONDOWN) ||
 255             (wParam == WM_NCMBUTTONDOWN) ||
 256             (wParam == WM_NCRBUTTONDOWN))
 257         {
 258             HWND blocker = AwtWindow::GetModalBlocker(AwtComponent::GetTopLevelParentForWindow(hWnd));
 259             if (::IsWindow(blocker)) {
 260                 BOOL onTaskbar = !(::WindowFromPoint(mhs->pt) == hWnd);
 261                 PopupBlockers(blocker, FALSE, ::GetForegroundWindow(), onTaskbar);
 262                 // return a nonzero value to prevent the system from passing
 263                 // the message to the target window procedure
 264                 return 1;
 265             }
 266         }
 267     }
 268 
 269     return CallNextHookEx(0, nCode, wParam, lParam);
 270 }
 271 
 272 /*
 273  * The function goes through the hierarchy of the blockers and
 274  * popups all the blockers. Note that the function starts from the top
 275  * blocker and goes down to the blocker which is the bottom one.
 276  * Using another traversal algorithm (bottom->top) may cause to flickering
 277  * as the bottom blocker will cover the top blocker for a while.
 278  */
 279 void AwtDialog::PopupBlockers(HWND blocker, BOOL isModalHook, HWND prevFGWindow, BOOL onTaskbar)
 280 {
 281     HWND nextBlocker = AwtWindow::GetModalBlocker(blocker);
 282     BOOL nextBlockerExists = ::IsWindow(nextBlocker);
 283     if (nextBlockerExists) {
 284         PopupBlockers(nextBlocker, isModalHook, prevFGWindow, onTaskbar);
 285     }
 286     PopupBlocker(blocker, nextBlocker, isModalHook, prevFGWindow, onTaskbar);
 287 }
 288 
 289 /*
 290  * The function popups the blocker, for a non-blocked blocker we need
 291  * to activate the blocker but if a blocker is blocked, then we need
 292  * to change z-order of the blocker placing the blocker under the next blocker.
 293  */
 294 void AwtDialog::PopupBlocker(HWND blocker, HWND nextBlocker, BOOL isModalHook, HWND prevFGWindow, BOOL onTaskbar)
 295 {
 296     if (blocker == AwtToolkit::GetInstance().GetHWnd()) {
 297         return;
 298     }
 299 
 300     // fix for 6494032
 301     if (isModalHook && !::IsWindowVisible(blocker)) {
 302         ::ShowWindow(blocker, SW_SHOWNA);
 303     }
 304 
 305     BOOL nextBlockerExists = ::IsWindow(nextBlocker);
 306     UINT flags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE;
 307 
 308     if (nextBlockerExists) {
 309         // Fix for 6829546: if blocker is a top-most window, but window isn't, then
 310         // calling ::SetWindowPos(dialog, blocker, ...) makes window top-most as well
 311         BOOL topmostNextBlocker = (::GetWindowLong(nextBlocker, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0;
 312         BOOL topmostBlocker = (::GetWindowLong(blocker, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0;
 313         if (!topmostNextBlocker || topmostBlocker) {
 314             ::SetWindowPos(blocker, nextBlocker, 0, 0, 0, 0, flags);
 315         } else {
 316             ::SetWindowPos(blocker, HWND_TOP, 0, 0, 0, 0, flags);
 317         }
 318     } else {
 319         ::SetWindowPos(blocker, HWND_TOP, 0, 0, 0, 0, flags);
 320         // no beep/flash if the mouse was clicked in the taskbar menu
 321         // or the dialog is currently inactive
 322         if (!isModalHook && !onTaskbar && (blocker == prevFGWindow)) {
 323             AnimateModalBlocker(blocker);
 324         }
 325         ::BringWindowToTop(blocker);
 326         ::SetForegroundWindow(blocker);
 327     }
 328 }
 329 
 330 void AwtDialog::AnimateModalBlocker(HWND window)
 331 {
 332     ::MessageBeep(MB_OK);
 333     // some heuristics: 3 times x 64 milliseconds
 334     AwtWindow::FlashWindowEx(window, 3, 64, FLASHW_CAPTION);
 335 }
 336 
 337 LRESULT CALLBACK AwtDialog::MouseHookProc_NonTT(int nCode,
 338                                                 WPARAM wParam, LPARAM lParam)
 339 {
 340     static HWND lastHWnd = NULL;
 341     if (nCode >= 0)
 342     {
 343         MOUSEHOOKSTRUCT *mhs = (MOUSEHOOKSTRUCT *)lParam;
 344         HWND hWnd = mhs->hwnd;
 345         HWND blocker = AwtWindow::GetModalBlocker(AwtComponent::GetTopLevelParentForWindow(hWnd));
 346         if (::IsWindow(blocker)) {
 347             if ((wParam == WM_MOUSEMOVE) ||
 348                 (wParam == WM_NCMOUSEMOVE))
 349             {
 350                 if (lastHWnd != hWnd) {
 351                     static HCURSOR hArrowCur = ::LoadCursor(NULL, IDC_ARROW);
 352                     ::SetCursor(hArrowCur);
 353                     lastHWnd = hWnd;
 354                 }
 355                 ::PostMessage(hWnd, WM_SETCURSOR, (WPARAM)hWnd, 0);
 356             } else if (wParam == WM_MOUSELEAVE) {
 357                 lastHWnd = NULL;
 358             }
 359 
 360             AwtDialog::MouseHookProc(nCode, wParam, lParam);
 361             return 1;
 362         }
 363     }
 364 
 365     return CallNextHookEx(0, nCode, wParam, lParam);
 366 }
 367 
 368 void AwtDialog::Show()
 369 {
 370     m_visible = true;
 371     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 372 
 373     BOOL locationByPlatform = env->GetBooleanField(GetTarget(env), AwtWindow::locationByPlatformID);
 374     if (locationByPlatform) {
 375          moveToDefaultLocation();
 376     }
 377     EnableTranslucency(TRUE);
 378     if (IsFocusableWindow() && (IsAutoRequestFocus() || IsFocusedWindowModalBlocker())) {
 379         ::ShowWindow(GetHWnd(), SW_SHOW);
 380     } else {
 381         ::ShowWindow(GetHWnd(), SW_SHOWNA);
 382     }
 383 }
 384 
 385 void AwtDialog::DoUpdateIcon()
 386 {
 387     AwtFrame::DoUpdateIcon();
 388     //Workaround windows bug:
 389     //Decorations are not updated correctly for owned dialogs
 390     //when changing dlg with icon <--> dlg without icon
 391     RECT winRect;
 392     RECT clientRect;
 393     ::GetWindowRect(GetHWnd(), &winRect);
 394     ::GetClientRect(GetHWnd(), &clientRect);
 395     ::MapWindowPoints(HWND_DESKTOP, GetHWnd(), (LPPOINT)&winRect, 2);
 396     HRGN winRgn = CreateRectRgnIndirect(&winRect);
 397     HRGN clientRgn = CreateRectRgnIndirect(&clientRect);
 398     ::CombineRgn(winRgn, winRgn, clientRgn, RGN_DIFF);
 399     ::RedrawWindow(GetHWnd(), NULL, winRgn, RDW_FRAME | RDW_INVALIDATE);
 400     ::DeleteObject(winRgn);
 401     ::DeleteObject(clientRgn);
 402 }
 403 
 404 HICON AwtDialog::GetEffectiveIcon(int iconType)
 405 {
 406     HWND hOwner = ::GetWindow(GetHWnd(), GW_OWNER);
 407     BOOL isResizable = ((GetStyle() & WS_THICKFRAME) != 0);
 408     BOOL smallIcon = ((iconType == ICON_SMALL) || (iconType == 2/*ICON_SMALL2*/));
 409     HICON hIcon = (smallIcon) ? GetHIconSm() : GetHIcon();
 410     if ((hIcon == NULL) && (isResizable || (hOwner == NULL))) {
 411         //Java cup icon is not loaded in window class for dialogs
 412         //It needs to be set explicitly for resizable dialogs
 413         //and ownerless dialogs
 414         hIcon = (smallIcon) ? AwtToolkit::GetInstance().GetAwtIconSm() :
 415             AwtToolkit::GetInstance().GetAwtIcon();
 416     } else if ((hIcon != NULL) && IsIconInherited() && !isResizable) {
 417         //Non-resizable dialogs without explicitely set icon
 418         //Should have no icon
 419         hIcon = NULL;
 420     }
 421     return hIcon;
 422 }
 423 
 424 void AwtDialog::CheckInstallModalHook() {
 425     VisibleModalDialogsCount++;
 426     if (VisibleModalDialogsCount == 1) {
 427         AWTModalHook = ::SetWindowsHookEx(WH_CBT, (HOOKPROC)ModalFilterProc,
 428                                          0, AwtToolkit::MainThread());
 429         AWTMouseHook = ::SetWindowsHookEx(WH_MOUSE, (HOOKPROC)MouseHookProc,
 430                                          0, AwtToolkit::MainThread());
 431     }
 432 }
 433 
 434 void AwtDialog::CheckUninstallModalHook() {
 435     if (VisibleModalDialogsCount == 1) {
 436         UnhookWindowsHookEx(AWTModalHook);
 437         UnhookWindowsHookEx(AWTMouseHook);
 438     }
 439     VisibleModalDialogsCount--;
 440 }
 441 
 442 void AwtDialog::ModalPerformActivation(HWND hWnd)
 443 {
 444     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 445 
 446     AwtWindow *w = (AwtWindow *)AwtComponent::GetComponent(hWnd);
 447     if ((w != NULL) && w->IsEmbeddedFrame()) {
 448         jobject target = w->GetTarget(env);
 449         env->CallVoidMethod(target, AwtFrame::activateEmbeddingTopLevelMID);
 450         env->DeleteLocalRef(target);
 451     } else {
 452         ::BringWindowToTop(hWnd);
 453         ::SetForegroundWindow(hWnd);
 454     }
 455 }
 456 
 457 void AwtDialog::ModalActivateNextWindow(HWND dialogHWnd,
 458                                         jobject dialogTarget, jobject dialogPeer)
 459 {
 460     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 461 
 462     jboolean exc;
 463     jlongArray windows = (jlongArray) JNU_CallStaticMethodByName
 464                                             (env,
 465                                              &exc,
 466                                              "sun/awt/windows/WWindowPeer",
 467                                              "getActiveWindowHandles",
 468                                              "(Ljava/awt/Component;)[J",
 469                                              dialogTarget).l;
 470     if (exc == JNI_TRUE) {
 471         throw std::bad_alloc();
 472     }
 473     if (windows == NULL) {
 474         return;
 475     }
 476 
 477     jboolean isCopy;
 478     jlong *ws = env->GetLongArrayElements(windows, &isCopy);
 479     if (ws == NULL) {
 480         throw std::bad_alloc();
 481     }
 482     int windowsCount = env->GetArrayLength(windows);
 483     for (int i = windowsCount - 1; i >= 0; i--) {
 484         HWND w = (HWND)ws[i];
 485         if ((w != dialogHWnd) && ModalCanBeActivated(w)) {
 486             AwtDialog::ModalPerformActivation(w);
 487             break;
 488         }
 489     }
 490     env->ReleaseLongArrayElements(windows, ws, 0);
 491 
 492     env->DeleteLocalRef(windows);
 493 }
 494 
 495 MsgRouting AwtDialog::WmShowModal()
 496 {
 497     DASSERT(::GetCurrentThreadId() == AwtToolkit::MainThread());
 498 
 499     // fix for 6213128: release capture (got by popups, choices, etc) when
 500     // modal dialog is shown
 501     HWND capturer = ::GetCapture();
 502     if (capturer != NULL) {
 503       ::ReleaseCapture();
 504     }
 505 
 506     SendMessage(WM_AWT_COMPONENT_SHOW);
 507 
 508     CheckInstallModalHook();
 509 
 510     m_modalWnd = GetHWnd();
 511 
 512     return mrConsume;
 513 }
 514 
 515 MsgRouting AwtDialog::WmEndModal()
 516 {
 517     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 518 
 519     DASSERT( ::GetCurrentThreadId() == AwtToolkit::MainThread() );
 520     DASSERT( ::IsWindow(m_modalWnd) );
 521 
 522     m_modalWnd = NULL;
 523 
 524     CheckUninstallModalHook();
 525 
 526     HWND parentHWnd = ::GetParent(GetHWnd());
 527     jobject peer = GetPeer(env);
 528     jobject target = GetTarget(env);
 529     if (::GetForegroundWindow() == GetHWnd()) {
 530         ModalActivateNextWindow(GetHWnd(), target, peer);
 531     }
 532     // hide the dialog
 533     SendMessage(WM_AWT_COMPONENT_HIDE);
 534 
 535     env->DeleteLocalRef(target);
 536 
 537     return mrConsume;
 538 }
 539 
 540 void AwtDialog::SetResizable(BOOL isResizable)
 541 {
 542     // call superclass
 543     AwtFrame::SetResizable(isResizable);
 544 
 545     LONG    style = GetStyle();
 546     LONG    xstyle = GetStyleEx();
 547     if (isResizable || IsUndecorated()) {
 548     // remove modal frame
 549         xstyle &= ~WS_EX_DLGMODALFRAME;
 550     } else {
 551     // add modal frame
 552         xstyle |= WS_EX_DLGMODALFRAME;
 553     }
 554     // dialogs are never minimizable/maximizable, so remove those bits
 555     style &= ~(WS_MINIMIZEBOX|WS_MAXIMIZEBOX);
 556     SetStyle(style);
 557     SetStyleEx(xstyle);
 558     RedrawNonClient();
 559 }
 560 
 561 // Adjust system menu so that:
 562 //  Non-resizable dialogs only have Move and Close items
 563 //  Resizable dialogs have the full system menu with
 564 //     Maximize, Minimize items disabled (the items
 565 //     get disabled by the native system).
 566 // This perfectly mimics the native MS Windows behavior.
 567 // Normally, Win32 dialog system menu handling is done via
 568 // CreateDialog/DefDlgProc, but our dialogs are using DefWindowProc
 569 // so we handle the system menu ourselves
 570 void AwtDialog::UpdateSystemMenu()
 571 {
 572     HWND    hWndSelf = GetHWnd();
 573     BOOL    isResizable = IsResizable();
 574 
 575     // before restoring the default menu, check if there is an
 576     // InputMethodManager menu item already.  Note that it assumes
 577     // that the length of the InputMethodManager menu item string
 578     // should not be longer than 256 bytes.
 579     MENUITEMINFO  mii;
 580     memset(&mii, 0, sizeof(MENUITEMINFO));
 581     TCHAR         immItem[256];
 582     BOOL          hasImm;
 583     mii.cbSize = sizeof(MENUITEMINFO);
 584     mii.fMask = MIIM_TYPE;
 585     mii.cch = sizeof(immItem);
 586     mii.dwTypeData = immItem;
 587     hasImm = ::GetMenuItemInfo(GetSystemMenu(hWndSelf, FALSE),
 588                                SYSCOMMAND_IMM, FALSE, &mii);
 589 
 590     // restore the default menu
 591     ::GetSystemMenu(hWndSelf, TRUE);
 592     // now get a working copy of the menu
 593     HMENU hMenuSys = GetSystemMenu(hWndSelf, FALSE);
 594 
 595     if (!isResizable) {
 596         // remove inapplicable sizing commands
 597         ::DeleteMenu(hMenuSys, SC_MINIMIZE, MF_BYCOMMAND);
 598         ::DeleteMenu(hMenuSys, SC_RESTORE, MF_BYCOMMAND);
 599         ::DeleteMenu(hMenuSys, SC_MAXIMIZE, MF_BYCOMMAND);
 600         ::DeleteMenu(hMenuSys, SC_SIZE, MF_BYCOMMAND);
 601         // remove separator if only 3 items left (Move, Separator, and Close)
 602         if (::GetMenuItemCount(hMenuSys) == 3) {
 603             MENUITEMINFO mi;
 604             memset(&mi, 0, sizeof(MENUITEMINFO));
 605             mi.cbSize = sizeof(MENUITEMINFO);
 606             mi.fMask = MIIM_TYPE;
 607             ::GetMenuItemInfo(hMenuSys, 1, TRUE, &mi);
 608             if (mi.fType & MFT_SEPARATOR) {
 609                 ::DeleteMenu(hMenuSys, 1, MF_BYPOSITION);
 610             }
 611         }
 612     }
 613 
 614     // if there was the InputMethodManager menu item, restore it.
 615     if (hasImm) {
 616         ::AppendMenu(hMenuSys, MF_STRING, SYSCOMMAND_IMM, immItem);
 617     }
 618 }
 619 
 620 // Override WmStyleChanged to adjust system menu for sizable/non-resizable dialogs
 621 MsgRouting AwtDialog::WmStyleChanged(int wStyleType, LPSTYLESTRUCT lpss)
 622 {
 623     UpdateSystemMenu();
 624     DoUpdateIcon();
 625     return mrConsume;
 626 }
 627 
 628 MsgRouting AwtDialog::WmSize(UINT type, int w, int h)
 629 {
 630     if (type == SIZE_MAXIMIZED || type == SIZE_MINIMIZED
 631             || (type == SIZE_RESTORED && !IsResizing()))
 632     {
 633         UpdateSystemMenu(); // adjust to reflect restored vs. maximized state
 634     }
 635 
 636     return AwtFrame::WmSize(type, w, h);
 637 }
 638 
 639 LRESULT AwtDialog::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
 640 {
 641     MsgRouting mr = mrDoDefault;
 642     LRESULT retValue = 0L;
 643 
 644     switch(message) {
 645         case WM_AWT_DLG_SHOWMODAL:
 646             mr = WmShowModal();
 647             break;
 648         case WM_AWT_DLG_ENDMODAL:
 649             mr = WmEndModal();
 650             break;
 651     }
 652 
 653     if (mr != mrConsume) {
 654         retValue = AwtFrame::WindowProc(message, wParam, lParam);
 655     }
 656     return retValue;
 657 }
 658 
 659 void AwtDialog::_ShowModal(void *param)
 660 {
 661     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 662 
 663     jobject self = (jobject)param;
 664 
 665     AwtDialog *d = NULL;
 666 
 667     PDATA pData;
 668     JNI_CHECK_PEER_GOTO(self, ret);
 669     d = (AwtDialog *)pData;
 670     if (::IsWindow(d->GetHWnd())) {
 671         d->SendMessage(WM_AWT_DLG_SHOWMODAL);
 672     }
 673 ret:
 674     env->DeleteGlobalRef(self);
 675 }
 676 
 677 void AwtDialog::_EndModal(void *param)
 678 {
 679     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 680 
 681     jobject self = (jobject)param;
 682 
 683     AwtDialog *d = NULL;
 684 
 685     PDATA pData;
 686     JNI_CHECK_PEER_GOTO(self, ret);
 687     d = (AwtDialog *)pData;
 688     if (::IsWindow(d->GetHWnd())) {
 689         d->SendMessage(WM_AWT_DLG_ENDMODAL);
 690     }
 691 ret:
 692     env->DeleteGlobalRef(self);
 693 }
 694 
 695 void AwtDialog::_SetIMMOption(void *param)
 696 {
 697     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 698 
 699     SetIMMOptionStruct *sios = (SetIMMOptionStruct *)param;
 700     jobject self = sios->dialog;
 701     jstring option = sios->option;
 702 
 703     int badAlloc = 0;
 704     LPCTSTR coption;
 705     LPCTSTR empty = TEXT("InputMethod");
 706     AwtDialog *d = NULL;
 707 
 708     PDATA pData;
 709     JNI_CHECK_PEER_GOTO(self, ret);
 710     JNI_CHECK_NULL_GOTO(option, "null IMMOption", ret);
 711 
 712     d = (AwtDialog *)pData;
 713     if (::IsWindow(d->GetHWnd()))
 714     {
 715         coption = JNU_GetStringPlatformChars(env, option, NULL);
 716         if (coption == NULL)
 717         {
 718             badAlloc = 1;
 719         }
 720         if (!badAlloc)
 721         {
 722             HMENU hSysMenu = ::GetSystemMenu(d->GetHWnd(), FALSE);
 723             ::AppendMenu(hSysMenu,  MF_STRING, SYSCOMMAND_IMM, coption);
 724 
 725             if (coption != empty)
 726             {
 727                 JNU_ReleaseStringPlatformChars(env, option, coption);
 728             }
 729         }
 730     }
 731 ret:
 732     env->DeleteGlobalRef(self);
 733     env->DeleteGlobalRef(option);
 734 
 735     delete sios;
 736 
 737     if (badAlloc)
 738     {
 739         throw std::bad_alloc();
 740     }
 741 }
 742 
 743 /************************************************************************
 744  * Dialog native methods
 745  */
 746 
 747 extern "C" {
 748 
 749 JNIEXPORT void JNICALL
 750 Java_java_awt_Dialog_initIDs(JNIEnv *env, jclass cls)
 751 {
 752     TRY;
 753 
 754     /* java.awt.Dialog fields and methods */
 755     AwtDialog::titleID
 756         = env->GetFieldID(cls, "title", "Ljava/lang/String;");
 757     DASSERT(AwtDialog::titleID != NULL);
 758     CHECK_NULL(AwtDialog::titleID);
 759 
 760     AwtDialog::undecoratedID
 761         = env->GetFieldID(cls,"undecorated","Z");
 762     DASSERT(AwtDialog::undecoratedID != NULL);
 763     CHECK_NULL(AwtDialog::undecoratedID);
 764 
 765     CATCH_BAD_ALLOC;
 766 }
 767 
 768 } /* extern "C" */
 769 
 770 
 771 /************************************************************************
 772  * DialogPeer native methods
 773  */
 774 
 775 extern "C" {
 776 
 777 /*
 778  * Class:     sun_awt_windows_WDialogPeer
 779  * Method:    create
 780  * Signature: (Lsun/awt/windows/WComponentPeer;)V
 781  */
 782 JNIEXPORT void JNICALL
 783 Java_sun_awt_windows_WDialogPeer_createAwtDialog(JNIEnv *env, jobject self,
 784                                         jobject parent)
 785 {
 786     TRY;
 787 
 788     AwtToolkit::CreateComponent(self, parent,
 789                                 (AwtToolkit::ComponentFactory)
 790                                 AwtDialog::Create);
 791 
 792     CATCH_BAD_ALLOC;
 793 }
 794 
 795 /*
 796  * Class:     sun_awt_windows_WDialogPeer
 797  * Method:    _show
 798  * Signature: ()V
 799  */
 800 JNIEXPORT void JNICALL
 801 Java_sun_awt_windows_WDialogPeer_showModal(JNIEnv *env, jobject self)
 802 {
 803     TRY;
 804 
 805     jobject selfGlobalRef = env->NewGlobalRef(self);
 806 
 807     AwtToolkit::GetInstance().SyncCall(AwtDialog::_ShowModal,
 808         (void *)selfGlobalRef);
 809     // selfGlobalRef is deleted in _ShowModal
 810 
 811     CATCH_BAD_ALLOC;
 812 }
 813 
 814 /*
 815  * Class:     sun_awt_windows_WDialogPeer
 816  * Method:    _hide
 817  * Signature: ()V
 818  */
 819 JNIEXPORT void JNICALL
 820 Java_sun_awt_windows_WDialogPeer_endModal(JNIEnv *env, jobject self)
 821 {
 822     TRY;
 823 
 824     jobject selfGlobalRef = env->NewGlobalRef(self);
 825 
 826     AwtToolkit::GetInstance().SyncCall(AwtDialog::_EndModal,
 827         (void *)selfGlobalRef);
 828     // selfGlobalRef is deleted in _EndModal
 829 
 830     CATCH_BAD_ALLOC;
 831 }
 832 
 833 /*
 834  * Class:     sun_awt_windows_WFramePeer
 835  * Method:    pSetIMMOption
 836  * Signature: (Ljava/lang/String;)V
 837  */
 838 JNIEXPORT void JNICALL
 839 Java_sun_awt_windows_WDialogPeer_pSetIMMOption(JNIEnv *env, jobject self,
 840                                                jstring option)
 841 {
 842     TRY;
 843 
 844     SetIMMOptionStruct *sios = new SetIMMOptionStruct;
 845     sios->dialog = env->NewGlobalRef(self);
 846     sios->option = (jstring)env->NewGlobalRef(option);
 847 
 848     AwtToolkit::GetInstance().SyncCall(AwtDialog::_SetIMMOption, sios);
 849     // global refs and sios are deleted in _SetIMMOption
 850 
 851     CATCH_BAD_ALLOC;
 852 }
 853 } /* extern "C" */