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