1 /*
   2  * Copyright (c) 1999, 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 "awt.h"
  27 #include "awt_PrintDialog.h"
  28 #include "awt_Dialog.h"
  29 #include "awt_PrintControl.h"
  30 #include "awt_Window.h"
  31 #include "ComCtl32Util.h"
  32 #include <sun_awt_windows_WPrintDialog.h>
  33 #include <sun_awt_windows_WPrintDialogPeer.h>
  34 
  35 jfieldID AwtPrintDialog::controlID;
  36 jfieldID AwtPrintDialog::parentID;
  37 
  38 jmethodID AwtPrintDialog::setHWndMID;
  39 
  40 BOOL
  41 AwtPrintDialog::PrintDlg(LPPRINTDLG data) {
  42     return static_cast<BOOL>(reinterpret_cast<INT_PTR>(
  43         AwtToolkit::GetInstance().InvokeFunction(
  44             reinterpret_cast<void *(*)(void *)>(::PrintDlg), data)));
  45 }
  46 
  47 LRESULT CALLBACK PrintDialogWndProc(HWND hWnd, UINT message,
  48                                     WPARAM wParam, LPARAM lParam)
  49 {
  50     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
  51 
  52     switch (message) {
  53         case WM_COMMAND: {
  54             if ((LOWORD(wParam) == IDOK) ||
  55                 (LOWORD(wParam) == IDCANCEL))
  56             {
  57                 // If we recieve on of these two notifications, the dialog
  58                 // is about to be closed. It's time to unblock all the
  59                 // windows blocked by this dialog, as doing so from the
  60                 // WM_DESTROY handler is too late
  61                 jobject peer = (jobject)(::GetProp(hWnd, ModalDialogPeerProp));
  62                 env->CallVoidMethod(peer, AwtPrintDialog::setHWndMID, (jlong)0);
  63             }
  64             break;
  65         }
  66     }
  67 
  68     WNDPROC lpfnWndProc = (WNDPROC)(::GetProp(hWnd, NativeDialogWndProcProp));
  69     return ComCtl32Util::GetInstance().DefWindowProc(lpfnWndProc, hWnd, message, wParam, lParam);
  70 }
  71 
  72 static UINT_PTR CALLBACK
  73 PrintDialogHookProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
  74 {
  75     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
  76 
  77     TRY;
  78 
  79     switch(uiMsg) {
  80         case WM_INITDIALOG: {
  81             PRINTDLG *pd = (PRINTDLG *)lParam;
  82             jobject peer = (jobject)(pd->lCustData);
  83             env->CallVoidMethod(peer, AwtPrintDialog::setHWndMID,
  84                                 (jlong)hdlg);
  85             ::SetProp(hdlg, ModalDialogPeerProp, reinterpret_cast<HANDLE>(peer));
  86 
  87             // fix for 4632159 - disable CS_SAVEBITS
  88             DWORD style = ::GetClassLong(hdlg, GCL_STYLE);
  89             ::SetClassLong(hdlg,GCL_STYLE, style & ~CS_SAVEBITS);
  90 
  91             ::SetFocus(hdlg); // will not break synthetic focus as hdlg is a native toplevel
  92 
  93             // set appropriate icon for parentless dialogs
  94             jobject awtParent = env->GetObjectField(peer, AwtPrintDialog::parentID);
  95             if (awtParent == NULL) {
  96                 ::SendMessage(hdlg, WM_SETICON, (WPARAM)ICON_BIG,
  97                               (LPARAM)AwtToolkit::GetInstance().GetAwtIcon());
  98             } else {
  99                 env->DeleteLocalRef(awtParent);
 100             }
 101 
 102             // subclass dialog's parent to receive additional messages
 103             WNDPROC lpfnWndProc = ComCtl32Util::GetInstance().SubclassHWND(hdlg,
 104                                                                            PrintDialogWndProc);
 105             ::SetProp(hdlg, NativeDialogWndProcProp, reinterpret_cast<HANDLE>(lpfnWndProc));
 106 
 107             break;
 108         }
 109         case WM_DESTROY: {
 110             WNDPROC lpfnWndProc = (WNDPROC)(::GetProp(hdlg, NativeDialogWndProcProp));
 111             ComCtl32Util::GetInstance().UnsubclassHWND(hdlg,
 112                                                        PrintDialogWndProc,
 113                                                        lpfnWndProc);
 114             ::RemoveProp(hdlg, ModalDialogPeerProp);
 115             ::RemoveProp(hdlg, NativeDialogWndProcProp);
 116             break;
 117         }
 118     }
 119     return FALSE;
 120 
 121     CATCH_BAD_ALLOC_RET(TRUE);
 122 }
 123 
 124 void AwtPrintDialog::_ToFront(void *param)
 125 {
 126     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 127 
 128     jobject self = (jobject)param;
 129     HWND hdlg = (HWND)(env->GetLongField(self, AwtComponent::hwndID));
 130     if (::IsWindow(hdlg))
 131     {
 132         ::SetWindowPos(hdlg, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
 133     }
 134 
 135     env->DeleteGlobalRef(self);
 136 }
 137 
 138 void AwtPrintDialog::_ToBack(void *param)
 139 {
 140     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 141 
 142     jobject self = (jobject)param;
 143     HWND hdlg = (HWND)(env->GetLongField(self, AwtComponent::hwndID));
 144     if (::IsWindow(hdlg))
 145     {
 146         ::SetWindowPos(hdlg, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
 147     }
 148 
 149     env->DeleteGlobalRef(self);
 150 }
 151 
 152 
 153 extern "C" {
 154 JNIEXPORT void JNICALL
 155 Java_sun_awt_windows_WPrintDialog_initIDs(JNIEnv *env, jclass cls)
 156 {
 157     TRY;
 158 
 159     AwtPrintDialog::controlID =
 160         env->GetFieldID(cls, "pjob", "Ljava/awt/print/PrinterJob;");
 161     DASSERT(AwtPrintDialog::controlID != NULL);
 162 
 163     AwtPrintControl::initIDs(env, cls);
 164 
 165     CATCH_BAD_ALLOC;
 166 }
 167 
 168 JNIEXPORT void JNICALL
 169 Java_sun_awt_windows_WPrintDialogPeer_initIDs(JNIEnv *env, jclass cls)
 170 {
 171     TRY;
 172 
 173     AwtPrintDialog::parentID =
 174         env->GetFieldID(cls, "parent", "Lsun/awt/windows/WComponentPeer;");
 175     DASSERT(AwtPrintDialog::parentID != NULL);
 176     CHECK_NULL(AwtPrintDialog::parentID);
 177 
 178     AwtPrintDialog::setHWndMID =
 179         env->GetMethodID(cls, "setHWnd", "(J)V");
 180     DASSERT(AwtPrintDialog::setHWndMID != NULL);
 181     CHECK_NULL(AwtPrintDialog::setHWndMID);
 182 
 183     CATCH_BAD_ALLOC;
 184 }
 185 
 186 JNIEXPORT jboolean JNICALL
 187 Java_sun_awt_windows_WPrintDialogPeer__1show(JNIEnv *env, jobject peer)
 188 {
 189     TRY;
 190 
 191     jboolean result = JNI_FALSE;
 192 
 193     // as peer object is used later on another thread, create a global ref
 194     jobject peerGlobalRef = env->NewGlobalRef(peer);
 195     DASSERT(peerGlobalRef != NULL);
 196     CHECK_NULL_RETURN(peerGlobalRef, 0);
 197     jobject target = env->GetObjectField(peerGlobalRef, AwtObject::targetID);
 198     DASSERT(target != NULL);
 199     if (target == NULL) {
 200         env->DeleteGlobalRef(peerGlobalRef);
 201         return 0;
 202     }
 203     jobject parent = env->GetObjectField(peerGlobalRef, AwtPrintDialog::parentID);
 204     jobject control = env->GetObjectField(target, AwtPrintDialog::controlID);
 205     DASSERT(control != NULL);
 206     if (control == NULL) {
 207         env->DeleteGlobalRef(peerGlobalRef);
 208         env->DeleteLocalRef(target);
 209         if (parent != NULL) {
 210           env->DeleteLocalRef(parent);
 211         }
 212         return 0;
 213     }
 214 
 215     AwtComponent *awtParent = (parent != NULL) ? (AwtComponent *)JNI_GET_PDATA(parent) : NULL;
 216     HWND hwndOwner = awtParent ? awtParent->GetHWnd() : NULL;
 217 
 218     PRINTDLG pd;
 219     memset(&pd, 0, sizeof(PRINTDLG));
 220     pd.lStructSize = sizeof(PRINTDLG);
 221     pd.lCustData = (LPARAM)peerGlobalRef;
 222     BOOL ret;
 223     try {
 224         ret = AwtPrintControl::InitPrintDialog(env, control, pd);
 225     } catch (std::bad_alloc&) {
 226         env->DeleteGlobalRef(peerGlobalRef);
 227         env->DeleteLocalRef(target);
 228         if (parent != NULL) {
 229           env->DeleteLocalRef(parent);
 230         }
 231         env->DeleteLocalRef(control);
 232         throw;
 233     }
 234     if (!ret) {
 235         /* Couldn't use the printer, or spooler isn't running
 236          * Call Page dialog with ' PD_RETURNDEFAULT' so it doesn't try
 237          * to show the dialog, but does prompt the user to install a printer.
 238          * If this returns false, then they declined and we just return.
 239          */
 240         pd.Flags = PD_RETURNDEFAULT | PD_RETURNDC;
 241         ret = AwtPrintDialog::PrintDlg(&pd);
 242     }
 243     if (!ret) {
 244       result = JNI_FALSE;
 245     }
 246     else
 247     {
 248       pd.lpfnPrintHook = (LPPRINTHOOKPROC)PrintDialogHookProc;
 249       pd.lpfnSetupHook = (LPSETUPHOOKPROC)PrintDialogHookProc;
 250       pd.Flags |= PD_ENABLESETUPHOOK | PD_ENABLEPRINTHOOK;
 251       /*
 252           Fix for 6488834.
 253           To disable Win32 native parent modality we have to set
 254           hwndOwner field to either NULL or some hidden window. For
 255           parentless dialogs we use NULL to show them in the taskbar,
 256           and for all other dialogs AwtToolkit's HWND is used.
 257       */
 258       if (awtParent != NULL)
 259       {
 260           pd.hwndOwner = AwtToolkit::GetInstance().GetHWnd();
 261       }
 262       else
 263       {
 264           pd.hwndOwner = NULL;
 265       }
 266 
 267       AwtDialog::CheckInstallModalHook();
 268 
 269       BOOL ret = AwtPrintDialog::PrintDlg(&pd);
 270       if (ret)
 271       {
 272         AwtPrintControl::UpdateAttributes(env, control, pd);
 273         result = JNI_TRUE;
 274       }
 275       else
 276       {
 277         result = JNI_FALSE;
 278       }
 279 
 280       DASSERT(env->GetLongField(peer, AwtComponent::hwndID) == 0L);
 281 
 282       AwtDialog::CheckUninstallModalHook();
 283 
 284       AwtDialog::ModalActivateNextWindow(NULL, target, peer);
 285     }
 286 
 287     env->DeleteGlobalRef(peerGlobalRef);
 288     env->DeleteLocalRef(target);
 289     if (parent != NULL) {
 290       env->DeleteLocalRef(parent);
 291     }
 292     env->DeleteLocalRef(control);
 293 
 294     return result;
 295 
 296     CATCH_BAD_ALLOC_RET(0);
 297 }
 298 
 299 JNIEXPORT void JNICALL
 300 Java_sun_awt_windows_WPrintDialogPeer_toFront(JNIEnv *env, jobject peer)
 301 {
 302     TRY;
 303 
 304     AwtToolkit::GetInstance().SyncCall(AwtPrintDialog::_ToFront,
 305                                        (void *)(env->NewGlobalRef(peer)));
 306     // global ref is deleted in _ToFront
 307 
 308     CATCH_BAD_ALLOC;
 309 }
 310 
 311 JNIEXPORT void JNICALL
 312 Java_sun_awt_windows_WPrintDialogPeer_toBack(JNIEnv *env, jobject peer)
 313 {
 314     TRY;
 315 
 316     AwtToolkit::GetInstance().SyncCall(AwtPrintDialog::_ToBack,
 317                                        (void *)(env->NewGlobalRef(peer)));
 318     // global ref is deleted in _ToBack
 319 
 320     CATCH_BAD_ALLOC;
 321 }
 322 
 323 } /* extern "C" */