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