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