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       HWND parent = AwtPrintControl::getParentID(env, control);
 252       if (parent != NULL) {
 253           // Windows native modality is requested (used by JavaFX).
 254           pd.hwndOwner = parent;
 255       }
 256       /*
 257           Fix for 6488834.
 258           To disable Win32 native parent modality we have to set
 259           hwndOwner field to either NULL or some hidden window. For
 260           parentless dialogs we use NULL to show them in the taskbar,
 261           and for all other dialogs AwtToolkit's HWND is used.
 262       */
 263       else if (awtParent != NULL)
 264       {
 265           pd.hwndOwner = AwtToolkit::GetInstance().GetHWnd();
 266       }
 267       else
 268       {
 269           pd.hwndOwner = NULL;
 270       }
 271 
 272       AwtDialog::CheckInstallModalHook();
 273 
 274       BOOL ret = AwtPrintDialog::PrintDlg(&pd);
 275       if (ret)
 276       {
 277         AwtPrintControl::UpdateAttributes(env, control, pd);
 278         result = JNI_TRUE;
 279       }
 280       else
 281       {
 282         result = JNI_FALSE;
 283       }
 284 
 285       DASSERT(env->GetLongField(peer, AwtComponent::hwndID) == 0L);
 286 
 287       AwtDialog::CheckUninstallModalHook();
 288 
 289       AwtDialog::ModalActivateNextWindow(NULL, target, peer);
 290     }
 291 
 292     env->DeleteGlobalRef(peerGlobalRef);
 293     env->DeleteLocalRef(target);
 294     if (parent != NULL) {
 295       env->DeleteLocalRef(parent);
 296     }
 297     env->DeleteLocalRef(control);
 298 
 299     return result;
 300 
 301     CATCH_BAD_ALLOC_RET(0);
 302 }
 303 
 304 JNIEXPORT void JNICALL
 305 Java_sun_awt_windows_WPrintDialogPeer_toFront(JNIEnv *env, jobject peer)
 306 {
 307     TRY;
 308 
 309     AwtToolkit::GetInstance().SyncCall(AwtPrintDialog::_ToFront,
 310                                        (void *)(env->NewGlobalRef(peer)));
 311     // global ref is deleted in _ToFront
 312 
 313     CATCH_BAD_ALLOC;
 314 }
 315 
 316 JNIEXPORT void JNICALL
 317 Java_sun_awt_windows_WPrintDialogPeer_toBack(JNIEnv *env, jobject peer)
 318 {
 319     TRY;
 320 
 321     AwtToolkit::GetInstance().SyncCall(AwtPrintDialog::_ToBack,
 322                                        (void *)(env->NewGlobalRef(peer)));
 323     // global ref is deleted in _ToBack
 324 
 325     CATCH_BAD_ALLOC;
 326 }
 327 
 328 } /* extern "C" */