8203796: Define API to support specifying ownership of print dialogs
authorprr
Wed, 06 Jun 2018 12:51:44 -0700
changeset 50488 15a2ef1e418e
parent 50487 fe3e444e7fbe
child 50489 580159eeac07
8203796: Define API to support specifying ownership of print dialogs Reviewed-by: serb, kcr
src/java.desktop/share/classes/javax/print/ServiceUI.java
src/java.desktop/share/classes/javax/print/attribute/standard/DialogOwner.java
src/java.desktop/share/classes/sun/print/DialogOnTop.java
src/java.desktop/share/classes/sun/print/DialogOwner.java
src/java.desktop/share/classes/sun/print/DialogOwnerAccessor.java
src/java.desktop/share/classes/sun/print/PrintJob2D.java
src/java.desktop/share/classes/sun/print/RasterPrinterJob.java
src/java.desktop/share/classes/sun/print/ServiceDialog.java
src/java.desktop/unix/classes/sun/print/IPPPrintService.java
src/java.desktop/unix/classes/sun/print/UnixPrintService.java
src/java.desktop/windows/classes/sun/awt/windows/WPrinterJob.java
src/java.desktop/windows/classes/sun/print/Win32PrintService.java
test/jdk/java/awt/print/Dialog/DialogOwnerTest.java
--- a/src/java.desktop/share/classes/javax/print/ServiceUI.java	Wed Jun 06 12:35:44 2018 -0700
+++ b/src/java.desktop/share/classes/javax/print/ServiceUI.java	Wed Jun 06 12:51:44 2018 -0700
@@ -25,8 +25,6 @@
 
 package javax.print;
 
-import java.awt.Dialog;
-import java.awt.Frame;
 import java.awt.GraphicsConfiguration;
 import java.awt.GraphicsEnvironment;
 import java.awt.HeadlessException;
@@ -35,11 +33,11 @@
 
 import javax.print.attribute.Attribute;
 import javax.print.attribute.AttributeSet;
+import javax.print.attribute.standard.DialogOwner;
 import javax.print.attribute.PrintRequestAttributeSet;
 import javax.print.attribute.standard.Destination;
 import javax.print.attribute.standard.Fidelity;
 
-import sun.print.DialogOwner;
 import sun.print.ServiceDialog;
 import sun.print.SunAlternateMedia;
 
@@ -185,6 +183,7 @@
 
         DialogOwner dlgOwner = (DialogOwner)attributes.get(DialogOwner.class);
         Window owner = (dlgOwner != null) ? dlgOwner.getOwner() : null;
+        boolean setOnTop = (dlgOwner != null) && (owner == null);
 
         Rectangle gcBounds = (gc == null) ?  GraphicsEnvironment.
             getLocalGraphicsEnvironment().getDefaultScreenDevice().
@@ -192,21 +191,17 @@
 
         x += gcBounds.x;
         y += gcBounds.y;
-        ServiceDialog dialog;
-        if (owner instanceof Frame) {
-            dialog = new ServiceDialog(gc,
-                                       x,
-                                       y,
-                                       services, defaultIndex,
-                                       flavor, attributes,
-                                       (Frame)owner);
-        } else {
-            dialog = new ServiceDialog(gc,
-                                       x,
-                                       y,
-                                       services, defaultIndex,
-                                       flavor, attributes,
-                                       (Dialog)owner);
+        ServiceDialog dialog = new ServiceDialog(gc,
+                                                 x,
+                                                 y,
+                                                 services, defaultIndex,
+                                                 flavor, attributes,
+                                                 owner);
+        if (setOnTop) {
+            try {
+                dialog.setAlwaysOnTop(true);
+            } catch (SecurityException e) {
+            }
         }
         Rectangle dlgBounds = dialog.getBounds();
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/share/classes/javax/print/attribute/standard/DialogOwner.java	Wed Jun 06 12:51:44 2018 -0700
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.print.attribute.standard;
+
+import java.awt.Window;
+import javax.print.attribute.Attribute;
+import javax.print.attribute.PrintRequestAttribute;
+import sun.print.DialogOwnerAccessor;
+
+/**
+ * An attribute class used to support requesting a print or page setup dialog
+ * be kept displayed on top of all windows or some specific window.
+ * <p>
+ * Constructed without any arguments it will request that a print or page
+ * setup dialog be configured as if the application directly was to specify
+ * {@code java.awt.Window.setAlwaysOnTop(true)}, subject to permission checks.
+ * <p>
+ * Constructed with a {@link java.awt.Window} parameter, it requests that
+ * the dialog be owned by the specified window.
+ *
+ * @since 11
+ */
+public final class DialogOwner implements PrintRequestAttribute {
+
+    private static class Accessor extends DialogOwnerAccessor {
+
+         public long getOwnerID(DialogOwner owner) {
+             return owner.getID();
+         }
+    }
+
+    static private Accessor accessor = new Accessor();
+    static {
+             DialogOwnerAccessor.setAccessor(accessor);
+    }
+
+    private static final long serialVersionUID = -1901909867156076547L;
+
+    private Window owner;
+    private transient long id;
+
+    /**
+     * Constructs an instance which can be used to request
+     * {@code java.awt.Window.setAlwaysOnTop(true)} behaviour.
+     * This should be used where there is no application preferred owner window.
+     * Whether this has any effect depends on if always on top is supported
+     * for this platform and the particular dialog to be displayed.
+     */
+    public DialogOwner() {
+    }
+
+    /**
+     * Constructs an instance which can be used to request that the
+     * specified {@link java.awt.Window} be the owner of the dialog.
+     * @param owner window.
+     */
+    public DialogOwner(Window owner) {
+        this.owner = owner;
+    }
+
+    /**
+     * Constructs an instance which requests that the dialog be displayed
+     * as if it were a child of a native platform window, specified
+     * using its opqaue platform identifier or handle.
+     * This is useful mainly for the case where the id represents a window
+     * which may not be an AWT {@code Window}, but instead was created by
+     * another UI toolkit, such as OpenJFX.
+     * Any effect is platform dependent.
+     * @param id a native window identifier or handle
+     */
+    DialogOwner(long id) {
+        this.id = id;
+    }
+
+    /**
+     * Returns a native platform id or handle, if one was specified,
+     * otherwise, zero.
+     * @return a native platform id.
+     */
+    long getID() {
+        return id;
+    }
+
+    /**
+     * Returns a {@code Window owner}, if one was specified,
+     * otherwise {@code null}.
+     * @return an owner window.
+     */
+    public Window getOwner() {
+        return owner;
+    }
+
+    /**
+     * Get the printing attribute class which is to be used as the "category"
+     * for this printing attribute value.
+     * <p>
+     * For class {@code DialogOwner}, the category is class
+     * {@code DialogOwner} itself.
+     *
+     * @return printing attribute class (category), an instance of class
+     *         {@link Class java.lang.Class}
+     */
+    public final Class<? extends Attribute> getCategory() {
+        return DialogOwner.class;
+    }
+
+    /**
+     * Get the name of the category of which this attribute value is an
+     * instance.
+     * <p>
+     * For class {@code DialogOwner}, the category name is
+     * {@code "dialog-owner"}.
+     *
+     */
+    public final String getName() {
+        return "dialog-owner";
+
+    }
+}
--- a/src/java.desktop/share/classes/sun/print/DialogOnTop.java	Wed Jun 06 12:35:44 2018 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.print;
-
-import javax.print.attribute.Attribute;
-import javax.print.attribute.PrintRequestAttribute;
-
-/*
- * An implementation class used to request the dialog be set always-on-top.
- * It needs to be read and honoured by the dialog code which will use
- * java.awt.Window.setAlwaysOnTop(true) in cases where it is supported.
- */
-public class DialogOnTop implements PrintRequestAttribute {
-
-    private static final long serialVersionUID = -1901909867156076547L;
-
-    long id;
-
-    public DialogOnTop() {
-    }
-
-    public DialogOnTop(long id) {
-        this.id = id;
-    }
-
-    public final Class<? extends Attribute> getCategory() {
-        return DialogOnTop.class;
-    }
-
-    public long getID() {
-        return id;
-    }
-
-    public final String getName() {
-        return "dialog-on-top";
-    }
-
-    public String toString() {
-       return "dialog-on-top";
-    }
-}
--- a/src/java.desktop/share/classes/sun/print/DialogOwner.java	Wed Jun 06 12:35:44 2018 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,103 +0,0 @@
-/*
- * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.print;
-
-import java.awt.Dialog;
-import javax.print.attribute.Attribute;
-import javax.print.attribute.PrintRequestAttribute;
-import java.awt.Frame;
-import java.awt.Window;
-
-/**
- * Class DialogOwner is a printing attribute class that identifies
- * the window that owns the print dialog.
- *
- * <P>
- * <B>IPP Compatibility:</B> This is not an IPP attribute.
- * <P>
- *
- */
-@SuppressWarnings("serial") // JDK-implementation class
-public final class DialogOwner
-    implements PrintRequestAttribute {
-
-    private Window dlgOwner;
-
-    /**
-     * Construct a new dialog owner attribute with the given frame.
-     *
-     * @param  frame the frame that owns the print dialog
-     */
-    public DialogOwner(Frame frame) {
-        dlgOwner = frame;
-    }
-
-    /**
-     * Construct a new dialog owner attribute with the given dialog.
-     *
-     * @param  dialog the dialog that owns the print dialog
-     */
-    public DialogOwner(Dialog dialog) {
-        dlgOwner = dialog;
-    }
-
-    /**
-     * Returns the string table for class DialogOwner.
-     */
-    public Window getOwner() {
-        return dlgOwner;
-    }
-
-
-    /**
-     * Get the printing attribute class which is to be used as the "category"
-     * for this printing attribute value.
-     * <P>
-     * For class DialogOwner the category is class
-     * DialogOwner itself.
-     *
-     * @return  Printing attribute class (category), an instance of class
-     *          {@link java.lang.Class java.lang.Class}.
-     */
-    public Class<? extends Attribute> getCategory() {
-        return DialogOwner.class;
-    }
-
-
-    /**
-     * Get the name of the category of which this attribute value is an
-     * instance.
-     * <P>
-     * For class DialogOwner the category name is
-     * {@code "dialog-owner"}.
-     *
-     * @return  Attribute category name.
-     */
-    public String getName() {
-        return "dialog-owner";
-    }
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/share/classes/sun/print/DialogOwnerAccessor.java	Wed Jun 06 12:51:44 2018 -0700
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.print;
+
+import javax.print.attribute.standard.DialogOwner;
+
+public abstract class DialogOwnerAccessor {
+
+    public abstract long getOwnerID(DialogOwner owner);
+
+    public static DialogOwnerAccessor accessor = null;
+
+    public static void setAccessor(DialogOwnerAccessor acc) {
+        accessor = acc;
+    }
+
+    public static long getID(DialogOwner owner) {
+        if (accessor == null || owner == null) {
+            return 0;
+        } else {
+            return accessor.getOwnerID(owner);
+        }
+    }
+}
--- a/src/java.desktop/share/classes/sun/print/PrintJob2D.java	Wed Jun 06 12:35:44 2018 -0700
+++ b/src/java.desktop/share/classes/sun/print/PrintJob2D.java	Wed Jun 06 12:51:44 2018 -0700
@@ -60,6 +60,7 @@
 import javax.print.attribute.standard.Copies;
 import javax.print.attribute.standard.Destination;
 import javax.print.attribute.standard.DialogTypeSelection;
+import javax.print.attribute.standard.DialogOwner;
 import javax.print.attribute.standard.JobName;
 import javax.print.attribute.standard.MediaSize;
 import javax.print.attribute.standard.PrintQuality;
--- a/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java	Wed Jun 06 12:35:44 2018 -0700
+++ b/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java	Wed Jun 06 12:51:44 2018 -0700
@@ -74,6 +74,7 @@
 import javax.print.attribute.standard.Copies;
 import javax.print.attribute.standard.Destination;
 import javax.print.attribute.standard.DialogTypeSelection;
+import javax.print.attribute.standard.DialogOwner;
 import javax.print.attribute.standard.Fidelity;
 import javax.print.attribute.standard.JobName;
 import javax.print.attribute.standard.JobSheets;
@@ -830,17 +831,24 @@
         int x = gcBounds.x+50;
         int y = gcBounds.y+50;
         ServiceDialog pageDialog;
+        boolean setOnTop = false;
         if (onTop != null) {
             attributes.add(onTop);
+            Window owner = onTop.getOwner();
+            if (owner != null) {
+                w = owner; // use the one specifed by the app
+            } else if (DialogOwnerAccessor.getID(onTop) == 0) {
+                setOnTop = true;
+            }
         }
-        if (w instanceof Frame) {
             pageDialog = new ServiceDialog(gc, x, y, service,
                                            DocFlavor.SERVICE_FORMATTED.PAGEABLE,
-                                           attributes,(Frame)w);
-        } else {
-            pageDialog = new ServiceDialog(gc, x, y, service,
-                                           DocFlavor.SERVICE_FORMATTED.PAGEABLE,
-                                           attributes, (Dialog)w);
+                                           attributes, w);
+        if (setOnTop) {
+            try {
+                pageDialog.setAlwaysOnTop(true);
+            } catch (SecurityException e) {
+            }
         }
 
         Rectangle dlgBounds = pageDialog.getBounds();
@@ -988,8 +996,7 @@
               * (it might be set in java.awt.PrintJob.printDialog)
               */
             if (attributes.get(DialogOwner.class) == null) {
-                attributes.add(w instanceof Frame ? new DialogOwner((Frame)w) :
-                                                    new DialogOwner((Dialog)w));
+                attributes.add(new DialogOwner(w));
             }
         } else {
             grCfg = GraphicsEnvironment.getLocalGraphicsEnvironment().
@@ -2581,7 +2588,7 @@
         }
     }
 
-    private DialogOnTop onTop = null;
+    private DialogOwner onTop = null;
 
     private long parentWindowID = 0L;
 
@@ -2597,9 +2604,9 @@
 
     private void setParentWindowID(PrintRequestAttributeSet attrs) {
         parentWindowID = 0L;
-        onTop = (DialogOnTop)attrs.get(DialogOnTop.class);
+        onTop = (DialogOwner)attrs.get(DialogOwner.class);
         if (onTop != null) {
-            parentWindowID = onTop.getID();
+            parentWindowID = DialogOwnerAccessor.getID(onTop);
         }
     }
 }
--- a/src/java.desktop/share/classes/sun/print/ServiceDialog.java	Wed Jun 06 12:35:44 2018 -0700
+++ b/src/java.desktop/share/classes/sun/print/ServiceDialog.java	Wed Jun 06 12:51:44 2018 -0700
@@ -38,6 +38,7 @@
 import java.awt.GridLayout;
 import java.awt.Insets;
 import java.awt.Toolkit;
+import java.awt.Window;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.FocusEvent;
@@ -136,33 +137,13 @@
                          int defaultServiceIndex,
                          DocFlavor flavor,
                          PrintRequestAttributeSet attributes,
-                         Dialog dialog)
+                         Window window)
     {
-        super(dialog, getMsg("dialog.printtitle"), true, gc);
+        super(window, getMsg("dialog.printtitle"), Dialog.DEFAULT_MODALITY_TYPE, gc);
         initPrintDialog(x, y, services, defaultServiceIndex,
                         flavor, attributes);
     }
 
-
-
-    /**
-     * Constructor for the "standard" print dialog (containing all relevant
-     * tabs)
-     */
-    public ServiceDialog(GraphicsConfiguration gc,
-                         int x, int y,
-                         PrintService[] services,
-                         int defaultServiceIndex,
-                         DocFlavor flavor,
-                         PrintRequestAttributeSet attributes,
-                         Frame frame)
-    {
-        super(frame, getMsg("dialog.printtitle"), true, gc);
-        initPrintDialog(x, y, services, defaultServiceIndex,
-                        flavor, attributes);
-    }
-
-
     /**
      * Initialize print dialog.
      */
@@ -184,8 +165,22 @@
             isAWT = true;
         }
 
-        if (attributes.get(DialogOnTop.class) != null) {
-            setAlwaysOnTop(true);
+        if (attributes.get(DialogOwner.class) != null) {
+            DialogOwner owner = (DialogOwner)attributes.get(DialogOwner.class);
+            /* When the ServiceDialog is constructed the caller of the
+             * constructor checks for this attribute and if it specifies a
+             * window then it will use that in the constructor instead of
+             * inferring one from keyboard focus.
+             * In this case the owner of the dialog is the same as that
+             * specified in the attribute and we do not need to set the
+             * on top property
+             */
+            if ((getOwner() == null) || (owner.getOwner() != getOwner())) {
+                try {
+                    setAlwaysOnTop(true);
+                } catch (SecurityException e) {
+                }
+            }
         }
         Container c = getContentPane();
         c.setLayout(new BorderLayout());
@@ -244,28 +239,13 @@
                          PrintService ps,
                          DocFlavor flavor,
                          PrintRequestAttributeSet attributes,
-                         Dialog dialog)
+                         Window window)
     {
-        super(dialog, getMsg("dialog.pstitle"), true, gc);
+        super(window, getMsg("dialog.pstitle"), Dialog.DEFAULT_MODALITY_TYPE, gc);
         initPageDialog(x, y, ps, flavor, attributes);
     }
 
     /**
-     * Constructor for the solitary "page setup" dialog
-     */
-    public ServiceDialog(GraphicsConfiguration gc,
-                         int x, int y,
-                         PrintService ps,
-                         DocFlavor flavor,
-                         PrintRequestAttributeSet attributes,
-                         Frame frame)
-    {
-        super(frame, getMsg("dialog.pstitle"), true, gc);
-        initPageDialog(x, y, ps, flavor, attributes);
-    }
-
-
-    /**
      * Initialize "page setup" dialog
      */
     void initPageDialog(int x, int y,
@@ -278,8 +258,15 @@
         this.asOriginal = attributes;
         this.asCurrent = new HashPrintRequestAttributeSet(attributes);
 
-        if (attributes.get(DialogOnTop.class) != null) {
-            setAlwaysOnTop(true);
+        if (attributes.get(DialogOwner.class) != null) {
+            /* See comments in same block in initPrintDialog */
+            DialogOwner owner = (DialogOwner)attributes.get(DialogOwner.class);
+            if ((getOwner() == null) || (owner.getOwner() != getOwner())) {
+                try {
+                    setAlwaysOnTop(true);
+                } catch (SecurityException e) {
+                }
+            }
         }
 
         Container c = getContentPane();
--- a/src/java.desktop/unix/classes/sun/print/IPPPrintService.java	Wed Jun 06 12:35:44 2018 -0700
+++ b/src/java.desktop/unix/classes/sun/print/IPPPrintService.java	Wed Jun 06 12:51:44 2018 -0700
@@ -25,6 +25,8 @@
 
 package sun.print;
 
+import java.awt.GraphicsEnvironment;
+import java.awt.Toolkit;
 import javax.print.attribute.*;
 import javax.print.attribute.standard.*;
 import javax.print.DocFlavor;
@@ -1071,6 +1073,11 @@
             catList.add(PrinterResolution.class);
         }
 
+        if (GraphicsEnvironment.isHeadless() == false) {
+            catList.add(DialogOwner.class);
+            catList.add(DialogTypeSelection.class);
+        }
+
         supportedCats = new Class<?>[catList.size()];
         catList.toArray(supportedCats);
         Class<?>[] copyCats = new Class<?>[supportedCats.length];
@@ -1392,10 +1399,38 @@
                 }
             }
             return false;
-        } if (attr.getCategory() == PrinterResolution.class) {
+        } else if (attr.getCategory() == PrinterResolution.class) {
             if (attr instanceof PrinterResolution) {
                 return isSupportedResolution((PrinterResolution)attr);
             }
+        } else if (attr.getCategory() == DialogOwner.class) {
+            DialogOwner owner = (DialogOwner)attr;
+            // ID not supported on any dialog type on Unix platforms.
+            if (DialogOwnerAccessor.getID(owner) != 0) {
+                return false;
+            }
+            // On Mac we have no control over the native dialog.
+            DialogTypeSelection dst = (attributes == null) ? null :
+               (DialogTypeSelection)attributes.get(DialogTypeSelection.class);
+            if (PrintServiceLookupProvider.isMac() &&
+                dst == DialogTypeSelection.NATIVE) {
+                return false;
+            }
+            // The other case is always a Swing dialog on all Unix platforms.
+            // So we only need to check that the toolkit supports
+            // always on top.
+            if (owner.getOwner() != null) {
+                return true;
+            } else {
+                return Toolkit.getDefaultToolkit().isAlwaysOnTopSupported();
+            }
+        } else if (attr.getCategory() == DialogTypeSelection.class) {
+            if (PrintServiceLookupProvider.isMac()) {
+                return true;
+            } else {
+               DialogTypeSelection dst = (DialogTypeSelection)attr;
+               return attr == DialogTypeSelection.COMMON;
+            }
         }
         return true;
     }
--- a/src/java.desktop/unix/classes/sun/print/UnixPrintService.java	Wed Jun 06 12:35:44 2018 -0700
+++ b/src/java.desktop/unix/classes/sun/print/UnixPrintService.java	Wed Jun 06 12:51:44 2018 -0700
@@ -31,6 +31,8 @@
 import java.util.ArrayList;
 import java.util.Locale;
 
+import java.awt.GraphicsEnvironment;
+import java.awt.Toolkit;
 import javax.print.DocFlavor;
 import javax.print.DocPrintJob;
 import javax.print.PrintService;
@@ -54,6 +56,8 @@
 import javax.print.attribute.standard.Copies;
 import javax.print.attribute.standard.CopiesSupported;
 import javax.print.attribute.standard.Destination;
+import javax.print.attribute.standard.DialogOwner;
+import javax.print.attribute.standard.DialogTypeSelection;
 import javax.print.attribute.standard.Fidelity;
 import javax.print.attribute.standard.Media;
 import javax.print.attribute.standard.MediaPrintableArea;
@@ -619,10 +623,15 @@
     }
 
     public Class<?>[] getSupportedAttributeCategories() {
-        int totalCats = otherAttrCats.length;
-        Class<?>[] cats = new Class<?>[totalCats];
-        System.arraycopy(otherAttrCats, 0, cats, 0, otherAttrCats.length);
-        return cats;
+        ArrayList<Class<?>> categList = new ArrayList<>(otherAttrCats.length);
+        for (Class<?> c : otherAttrCats) {
+            categList.add(c);
+        }
+        if (GraphicsEnvironment.isHeadless() == false) {
+            categList.add(DialogOwner.class);
+            categList.add(DialogTypeSelection.class);
+        }
+        return categList.toArray(new Class<?>[categList.size()]);
     }
 
     public boolean
@@ -1023,6 +1032,24 @@
                 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE))) {
                 return false;
             }
+        } else if (attr.getCategory() == DialogOwner.class) {
+            DialogOwner owner = (DialogOwner)attr;
+            // ID not supported on any dialog type on Unix platforms.
+            if (DialogOwnerAccessor.getID(owner) != 0) {
+                return false;
+            }
+            // UnixPrintService is not used on Mac, so this is
+            // always some Unix system that does not have CUPS/IPP
+            // Which means we always use a Swing dialog and we need
+            // only check if alwaysOnTop is supported by the toolkit.
+            if (owner.getOwner() != null) {
+                return true;
+            } else {
+                return Toolkit.getDefaultToolkit().isAlwaysOnTopSupported();
+            }
+        } else if (attr.getCategory() == DialogTypeSelection.class) {
+            DialogTypeSelection dts = (DialogTypeSelection)attr;
+            return dts == DialogTypeSelection.COMMON;
         }
         return true;
     }
--- a/src/java.desktop/windows/classes/sun/awt/windows/WPrinterJob.java	Wed Jun 06 12:35:44 2018 -0700
+++ b/src/java.desktop/windows/classes/sun/awt/windows/WPrinterJob.java	Wed Jun 06 12:51:44 2018 -0700
@@ -79,6 +79,7 @@
 import javax.print.attribute.standard.SheetCollate;
 import javax.print.attribute.standard.Copies;
 import javax.print.attribute.standard.Destination;
+import javax.print.attribute.standard.DialogOwner;
 import javax.print.attribute.standard.OrientationRequested;
 import javax.print.attribute.standard.Media;
 import javax.print.attribute.standard.MediaSizeName;
@@ -95,7 +96,6 @@
 import sun.print.Win32PrintService;
 import sun.print.PrintServiceLookupProvider;
 import sun.print.ServiceDialog;
-import sun.print.DialogOwner;
 
 import java.awt.Frame;
 import java.io.FilePermission;
--- a/src/java.desktop/windows/classes/sun/print/Win32PrintService.java	Wed Jun 06 12:35:44 2018 -0700
+++ b/src/java.desktop/windows/classes/sun/print/Win32PrintService.java	Wed Jun 06 12:51:44 2018 -0700
@@ -25,6 +25,8 @@
 
 package sun.print;
 
+import java.awt.GraphicsEnvironment;
+import java.awt.Toolkit;
 import java.awt.Window;
 import java.awt.print.PrinterJob;
 import java.io.File;
@@ -54,6 +56,8 @@
 import javax.print.attribute.standard.Copies;
 import javax.print.attribute.standard.CopiesSupported;
 import javax.print.attribute.standard.Destination;
+import javax.print.attribute.standard.DialogOwner;
+import javax.print.attribute.standard.DialogTypeSelection;
 import javax.print.attribute.standard.Fidelity;
 import javax.print.attribute.standard.Media;
 import javax.print.attribute.standard.MediaSizeName;
@@ -1042,6 +1046,10 @@
             categList.add(PrinterResolution.class);
         }
 
+        if (GraphicsEnvironment.isHeadless() == false) {
+            categList.add(DialogOwner.class);
+            categList.add(DialogTypeSelection.class);
+        }
         return categList.toArray(new Class<?>[categList.size()]);
     }
 
@@ -1585,6 +1593,23 @@
                 (isColorSup && (attr == ColorSupported.NOT_SUPPORTED))) {
                 return false;
             }
+        } else if (category == DialogTypeSelection.class) {
+            return true; // isHeadless was checked by category support
+        } else if (category == DialogOwner.class) {
+            DialogOwner owner = (DialogOwner)attr;
+            DialogTypeSelection dts = (attributes == null) ? null :
+                (DialogTypeSelection)attributes.get(DialogTypeSelection.class);
+            if (dts == DialogTypeSelection.NATIVE) {
+                return DialogOwnerAccessor.getID(owner) != 0;
+            } else {
+               if (DialogOwnerAccessor.getID(owner) != 0) {
+                  return false;
+               } else if (owner.getOwner() != null) {
+                   return true;
+               } else {
+                   return Toolkit.getDefaultToolkit().isAlwaysOnTopSupported();
+               }
+            }
         }
         return true;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/awt/print/Dialog/DialogOwnerTest.java	Wed Jun 06 12:51:44 2018 -0700
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+   @bug 8203796
+   @run main/manual DialogOwnerTest
+   @summary Test DialogOwner API
+*/
+
+import java.util.ArrayList;
+import java.util.List;
+import java.awt.GraphicsConfiguration;
+import java.awt.GridLayout;
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.print.PrinterJob;
+import javax.print.PrintService;
+import javax.print.PrintServiceLookup;
+import javax.print.ServiceUI;
+import javax.print.attribute.HashPrintRequestAttributeSet;
+import javax.print.attribute.PrintRequestAttributeSet;
+import javax.print.attribute.standard.DialogOwner;
+import javax.print.attribute.standard.DialogTypeSelection;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.JTextArea;
+import javax.swing.SwingUtilities;
+
+public class DialogOwnerTest extends JPanel {
+
+    static final int NONE      =     0x0;
+    static final int PRINT     =     0x1;
+    static final int PAGE      =     0x2;
+    static final int SWING2D   =     0x4;
+    static final int NATIVE2D  =     0x8;
+    static final int SERVICEUI =    0x10;
+
+    static final int ONTOP      =   0x20;
+    static final int OWNED      =   0x40;
+
+    static PrintService[] services =
+        PrintServiceLookup.lookupPrintServices(null, null);
+
+    public static void main(String[] args) {
+        if (services.length == 0) {
+            System.out.println("No printers, exiting");
+            return;
+        } else {
+           service = PrinterJob.getPrinterJob().getPrintService();
+        }
+        SwingUtilities.invokeLater(() -> {
+            createUI();
+        });
+        while (!testFinished) {
+           try {
+                Thread.sleep(1000);
+           } catch (InterruptedException e){
+           }
+        }
+        if (!testPassed) {
+            throw new RuntimeException("TEST FAILED.");
+        }
+    }
+
+
+    static final String otherText =
+       "This window is used to test on top behaviour\n" +
+       "For tests that are 'Owned' or 'On Top' the dialog\n" +
+       "must always stay above this window. Verify this\n " +
+       "by moving the dialog so that it partially obscures\n" +
+       "this window and then trying to raise this window.";
+
+    static final String instructions =
+       " Instructions\n" +
+       "This tests that a print dialog stays on top of either another\n" +
+       "window, or on top of all windows.\n" +
+       "For Owned tests the window titled 'Owner Window' should always \n" +
+       "stay behind the print dialog.\n" +
+       "For On Top tests all windows should stay behind the owner window.\n" +
+       "This test tracks if you have checked all the scenarios and will\n" +
+       "not allow the test to pass unless you have visited them all.\n";
+
+    static PrintService service;
+
+    public DialogOwnerTest() {
+       super();
+       //setLayout(new GridLayout(24, 1));
+    }
+
+    static boolean isNative(int flags) {
+        return (flags & NATIVE2D) != 0;
+    }
+
+    static boolean isCommon(int flags) {
+        return (flags & SWING2D) != 0;
+    }
+
+    static boolean is2D(int flags) {
+        return (flags & SWING2D|NATIVE2D) != 0;
+    }
+
+    static boolean isPage(int flags) {
+        return (flags & PAGE ) != 0;
+    }
+
+    static JFrame frame;
+    static JFrame other;
+    static JButton pass;
+    static ArrayList<JPanel> panelList = new ArrayList<JPanel>();
+    static volatile boolean testPassed, testFinished;
+
+    int testCount = 0;
+    List<String> testList = new ArrayList<String>();
+
+    static void createUI() {
+        other = new JFrame("Owner Window");
+        JTextArea otherTextArea = new JTextArea(otherText, 10, 40);
+        other.add(otherTextArea);
+        other.pack();
+        other.setVisible(true);
+        other.setLocation(800, 100);
+
+        frame = new JFrame("Test Dialog Owner");
+        frame.pack();
+        JTextArea instructionsPanel = new JTextArea(instructions, 10, 50);
+        instructionsPanel.setEditable(false);
+        frame.add("North", instructionsPanel);
+        DialogOwnerTest test = new DialogOwnerTest();
+
+        test.addTest("Owned Swing Print", OWNED, frame, PRINT|SWING2D);
+        test.addTest("On Top Swing Print", ONTOP, null, PRINT|SWING2D);
+
+        test.addTest("Owned Swing Page", OWNED, frame, PAGE|SWING2D);
+        test.addTest("On Top Swing Page", ONTOP, null, PAGE|SWING2D);
+
+        test.addTest("Owned javax.print", OWNED, frame, PRINT|SERVICEUI);
+        test.addTest("On Top javax.print", OWNED, null, PRINT|SERVICEUI);
+
+        test.addTest("Owned Native Print", OWNED, frame, PRINT|NATIVE2D);
+        test.addTest("On Top Native Print", OWNED, null, PRINT|NATIVE2D);
+
+        test.addTest("Owned Native Page", OWNED, frame, PAGE|NATIVE2D);
+        test.addTest("On Top Native Page", OWNED, null, PAGE|NATIVE2D);
+
+        test.setLayout(new GridLayout(panelList.size()+2, 1));
+
+        pass = new JButton("Pass");
+        pass.setEnabled(false);
+        pass.addActionListener((ActionEvent e) -> {
+            if (test.testList.size() > 0) {
+                return;
+            }
+            frame.dispose();
+            other.dispose();
+            System.out.println("User says test passed.");
+            testPassed = true;
+            testFinished = true;
+        });
+
+        JButton fail = new JButton("Fail");
+        fail.addActionListener((ActionEvent e) -> {
+            frame.dispose();
+            other.dispose();
+            System.out.println("User says test failed.");
+            testPassed = false;
+            testFinished = true;
+        });
+
+        JPanel p = new JPanel();
+        p.add(pass);
+        p.add(fail);
+        test.add(p);
+
+
+        for (JPanel panel : panelList) {
+            test.add(panel);
+        }
+
+        frame.add("Center", test);
+        frame.pack();
+        frame.setLocation(0,0);
+        frame.setVisible(true);
+     }
+
+   boolean isSupported(PrintRequestAttributeSet aset,
+                     int ownerFlags, Window owner, int dlgFlags) {
+
+       boolean supported = true;
+       DialogOwner ownerAttr = null;
+       if (ownerFlags != NONE) {
+           if (ownerFlags == ONTOP) {
+               ownerAttr = new DialogOwner();
+           } else if (ownerFlags == OWNED) {
+               ownerAttr = new DialogOwner(owner);
+           }
+           aset.add(ownerAttr);
+        }
+        if (is2D(dlgFlags)) {
+           DialogTypeSelection dst = null;
+           if (isNative(dlgFlags)) {
+               dst = DialogTypeSelection.NATIVE;
+           } else if (isCommon(dlgFlags)) {
+               dst = DialogTypeSelection.COMMON;
+           }
+           if (dst != null &&
+               !service.isAttributeValueSupported(dst, null, aset)) {
+               //System.out.println("This DialogType not supported");
+               supported = false;
+           }
+           if (dst != null) {
+               aset.add(dst);
+           }
+           if (ownerAttr != null &&
+               !service.isAttributeValueSupported(ownerAttr, null, aset)) {
+               //System.out.println("This DialogOwner not supported");
+               supported = false;
+           }
+        }
+        return supported;
+   }
+
+   void addTest(String title, int ownerFlags, Window owner, int dlgFlags) {
+
+        PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet();
+        if (!isSupported(aset, ownerFlags, owner, dlgFlags)) {
+            return;
+        }
+
+        // if we are here then this is supportable and worth testing
+        // and the attribute set is configured.
+
+        String label = title + " Dialog";
+        JButton button = new JButton(label);
+        JCheckBox tested = new JCheckBox("Tested");
+        tested.setEnabled(false);
+        JPanel panel = new JPanel();
+        panel.add(tested);
+        panel.add(button);
+        panelList.add(panel);
+        //add(panel);
+        testList.add(title);
+        if (++testCount != testList.size()) {
+            throw new RuntimeException("Test titles must be unique");
+        }
+
+        button.addActionListener((ActionEvent e) -> {
+            tested.setSelected(true);
+            testList.remove(title);
+            if (testList.isEmpty()) {
+              pass.setEnabled(true);
+            }
+
+            if (is2D(dlgFlags)) {
+               PrinterJob job = PrinterJob.getPrinterJob();
+               if (isPage(dlgFlags)) {
+                   job.pageDialog(aset);
+               } else {
+                   job.printDialog(aset);
+               }
+            } else {
+               GraphicsConfiguration gc = null;
+               int x = 0, y = 0;
+               ServiceUI.printDialog(gc, x, y, services, services[0], null,aset);
+            }
+        });
+    }
+}