blob: 2e2777c3e9ff08aaf4d89dbab4bea63493fb300d [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2000-2007 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.print;
27
28import java.io.BufferedReader;
29import java.io.InputStream;
30import java.io.InputStreamReader;
31import java.io.IOException;
32import java.util.ArrayList;
33import java.security.AccessController;
34import java.security.PrivilegedActionException;
35import java.security.PrivilegedExceptionAction;
36import javax.print.DocFlavor;
37import javax.print.MultiDocPrintService;
38import javax.print.PrintService;
39import javax.print.PrintServiceLookup;
40import javax.print.attribute.Attribute;
41import javax.print.attribute.AttributeSet;
42import javax.print.attribute.HashPrintRequestAttributeSet;
43import javax.print.attribute.HashPrintServiceAttributeSet;
44import javax.print.attribute.PrintRequestAttribute;
45import javax.print.attribute.PrintRequestAttributeSet;
46import javax.print.attribute.PrintServiceAttribute;
47import javax.print.attribute.PrintServiceAttributeSet;
48import javax.print.attribute.standard.PrinterName;
49
50public class Win32PrintServiceLookup extends PrintServiceLookup {
51
52 private String defaultPrinter;
53 private PrintService defaultPrintService;
54 private String[] printers; /* excludes the default printer */
55 private PrintService[] printServices; /* includes the default printer */
56
57 static {
58 java.security.AccessController.doPrivileged(
59 new sun.security.action.LoadLibraryAction("awt"));
60 }
61
62 /* The singleton win32 print lookup service.
63 * Code that is aware of this field and wants to use it must first
64 * see if its null, and if so instantiate it by calling a method such as
65 * javax.print.PrintServiceLookup.defaultPrintService() so that the
66 * same instance is stored there.
67 */
68 private static Win32PrintServiceLookup win32PrintLUS;
69
70 /* Think carefully before calling this. Preferably don't call it. */
71 public static Win32PrintServiceLookup getWin32PrintLUS() {
72 if (win32PrintLUS == null) {
73 /* This call is internally synchronized.
74 * When it returns an instance of this class will have
75 * been instantiated - else there's a JDK internal error.
76 */
77 PrintServiceLookup.lookupDefaultPrintService();
78 }
79 return win32PrintLUS;
80 }
81
82 public Win32PrintServiceLookup() {
83
84 if (win32PrintLUS == null) {
85 win32PrintLUS = this;
86
87 String osName = AccessController.doPrivileged(
88 new sun.security.action.GetPropertyAction("os.name"));
89 // There's no capability for Win98 to refresh printers.
90 // See "OpenPrinter" for more info.
91 if (osName != null && osName.startsWith("Windows 98")) {
92 return;
93 }
94 // start the printer listener thread
95 PrinterChangeListener thr = new PrinterChangeListener();
96 thr.setDaemon(true);
97 thr.start();
98 } /* else condition ought to never happen! */
99 }
100
101 /* Want the PrintService which is default print service to have
102 * equality of reference with the equivalent in list of print services
103 * This isn't required by the API and there's a risk doing this will
104 * lead people to assume its guaranteed.
105 */
106 public synchronized PrintService[] getPrintServices() {
107 SecurityManager security = System.getSecurityManager();
108 if (security != null) {
109 security.checkPrintJobAccess();
110 }
111 if (printServices == null) {
112 refreshServices();
113 }
114 return printServices;
115 }
116
117 private synchronized void refreshServices() {
118 printers = getAllPrinterNames();
119 if (printers == null) {
120 // In Windows it is safe to assume no default if printers == null so we
121 // don't get the default.
122 printServices = new PrintService[0];
123 return;
124 }
125
126 PrintService[] newServices = new PrintService[printers.length];
127 PrintService defService = getDefaultPrintService();
128 for (int p = 0; p < printers.length; p++) {
129 if (defService != null &&
130 printers[p].equals(defService.getName())) {
131 newServices[p] = defService;
132 } else {
133 if (printServices == null) {
134 newServices[p] = new Win32PrintService(printers[p]);
135 } else {
136 int j;
137 for (j = 0; j < printServices.length; j++) {
138 if ((printServices[j]!= null) &&
139 (printers[p].equals(printServices[j].getName()))) {
140 newServices[p] = printServices[j];
141 printServices[j] = null;
142 break;
143 }
144 }
145 if (j == printServices.length) {
146 newServices[p] = new Win32PrintService(printers[p]);
147 }
148 }
149 }
150 }
151
152 // Look for deleted services and invalidate these
153 if (printServices != null) {
154 for (int j=0; j < printServices.length; j++) {
155 if ((printServices[j] instanceof Win32PrintService) &&
156 (!printServices[j].equals(defaultPrintService))) {
157 ((Win32PrintService)printServices[j]).invalidateService();
158 }
159 }
160 }
161 printServices = newServices;
162 }
163
164
165 public synchronized PrintService getPrintServiceByName(String name) {
166
167 if (name == null || name.equals("")) {
168 return null;
169 } else {
170 /* getPrintServices() is now very fast. */
171 PrintService[] printServices = getPrintServices();
172 for (int i=0; i<printServices.length; i++) {
173 if (printServices[i].getName().equals(name)) {
174 return printServices[i];
175 }
176 }
177 return null;
178 }
179 }
180
181 boolean matchingService(PrintService service,
182 PrintServiceAttributeSet serviceSet) {
183 if (serviceSet != null) {
184 Attribute [] attrs = serviceSet.toArray();
185 Attribute serviceAttr;
186 for (int i=0; i<attrs.length; i++) {
187 serviceAttr
188 = service.getAttribute((Class<PrintServiceAttribute>)attrs[i].getCategory());
189 if (serviceAttr == null || !serviceAttr.equals(attrs[i])) {
190 return false;
191 }
192 }
193 }
194 return true;
195 }
196
197 public PrintService[] getPrintServices(DocFlavor flavor,
198 AttributeSet attributes) {
199
200 SecurityManager security = System.getSecurityManager();
201 if (security != null) {
202 security.checkPrintJobAccess();
203 }
204 PrintRequestAttributeSet requestSet = null;
205 PrintServiceAttributeSet serviceSet = null;
206
207 if (attributes != null && !attributes.isEmpty()) {
208
209 requestSet = new HashPrintRequestAttributeSet();
210 serviceSet = new HashPrintServiceAttributeSet();
211
212 Attribute[] attrs = attributes.toArray();
213 for (int i=0; i<attrs.length; i++) {
214 if (attrs[i] instanceof PrintRequestAttribute) {
215 requestSet.add(attrs[i]);
216 } else if (attrs[i] instanceof PrintServiceAttribute) {
217 serviceSet.add(attrs[i]);
218 }
219 }
220 }
221
222 /*
223 * Special case: If client is asking for a particular printer
224 * (by name) then we can save time by getting just that service
225 * to check against the rest of the specified attributes.
226 */
227 PrintService[] services = null;
228 if (serviceSet != null && serviceSet.get(PrinterName.class) != null) {
229 PrinterName name = (PrinterName)serviceSet.get(PrinterName.class);
230 PrintService service = getPrintServiceByName(name.getValue());
231 if (service == null || !matchingService(service, serviceSet)) {
232 services = new PrintService[0];
233 } else {
234 services = new PrintService[1];
235 services[0] = service;
236 }
237 } else {
238 services = getPrintServices();
239 }
240
241 if (services.length == 0) {
242 return services;
243 } else {
244 ArrayList matchingServices = new ArrayList();
245 for (int i=0; i<services.length; i++) {
246 try {
247 if (services[i].
248 getUnsupportedAttributes(flavor, requestSet) == null) {
249 matchingServices.add(services[i]);
250 }
251 } catch (IllegalArgumentException e) {
252 }
253 }
254 services = new PrintService[matchingServices.size()];
255 return (PrintService[])matchingServices.toArray(services);
256 }
257 }
258
259 /*
260 * return empty array as don't support multi docs
261 */
262 public MultiDocPrintService[]
263 getMultiDocPrintServices(DocFlavor[] flavors,
264 AttributeSet attributes) {
265 SecurityManager security = System.getSecurityManager();
266 if (security != null) {
267 security.checkPrintJobAccess();
268 }
269 return new MultiDocPrintService[0];
270 }
271
272
273 public synchronized PrintService getDefaultPrintService() {
274 SecurityManager security = System.getSecurityManager();
275 if (security != null) {
276 security.checkPrintJobAccess();
277 }
278
279
280 // Windows does not have notification for a change in default
281 // so we always get the latest.
282 defaultPrinter = getDefaultPrinterName();
283 if (defaultPrinter == null) {
284 return null;
285 }
286
287 if ((defaultPrintService != null) &&
288 defaultPrintService.getName().equals(defaultPrinter)) {
289
290 return defaultPrintService;
291 }
292
293 // Not the same as default so proceed to get new PrintService.
294
295 // clear defaultPrintService
296 defaultPrintService = null;
297
298 if (printServices != null) {
299 for (int j=0; j<printServices.length; j++) {
300 if (defaultPrinter.equals(printServices[j].getName())) {
301 defaultPrintService = printServices[j];
302 break;
303 }
304 }
305 }
306
307 if (defaultPrintService == null) {
308 defaultPrintService = new Win32PrintService(defaultPrinter);
309 }
310 return defaultPrintService;
311 }
312
313 class PrinterChangeListener extends Thread {
314 long chgObj;
315 PrinterChangeListener() {
316 chgObj = notifyFirstPrinterChange(null);
317 }
318
319 public void run() {
320 if (chgObj != -1) {
321 while (true) {
322 // wait for configuration to change
323 if (notifyPrinterChange(chgObj) != 0) {
324 try {
325 refreshServices();
326 } catch (SecurityException se) {
327 break;
328 }
329 } else {
330 notifyClosePrinterChange(chgObj);
331 break;
332 }
333 }
334 }
335 }
336 }
337
338 private native String getDefaultPrinterName();
339 private native String[] getAllPrinterNames();
340 private native long notifyFirstPrinterChange(String printer);
341 private native void notifyClosePrinterChange(long chgObj);
342 private native int notifyPrinterChange(long chgObj);
343}