Java tutorial
/******************************************************************************* * Copyright (c) 2000, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.swt.printing; import org.eclipse.swt.*; import org.eclipse.swt.graphics.*; import org.eclipse.swt.internal.*; import org.eclipse.swt.internal.cairo.*; import org.eclipse.swt.internal.gtk.*; /** * Instances of this class are used to print to a printer. * Applications create a GC on a printer using <code>new GC(printer)</code> * and then draw on the printer GC using the usual graphics calls. * <p> * A <code>Printer</code> object may be constructed by providing * a <code>PrinterData</code> object which identifies the printer. * A <code>PrintDialog</code> presents a print dialog to the user * and returns an initialized instance of <code>PrinterData</code>. * Alternatively, calling <code>new Printer()</code> will construct a * printer object for the user's default printer. * </p><p> * Application code must explicitly invoke the <code>Printer.dispose()</code> * method to release the operating system resources managed by each instance * when those instances are no longer required. * </p> * * @see PrinterData * @see PrintDialog * @see <a href="http://www.eclipse.org/swt/snippets/#printing">Printing snippets</a> * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a> */ public final class Printer extends Device { static PrinterData[] printerList; static long findPrinter; static PrinterData findData; PrinterData data; long printer; long printJob; long settings; long pageSetup; long surface; long cairo; /** * whether or not a GC was created for this printer */ boolean isGCCreated = false; static byte[] settingsData; static int start, end; static final String GTK_LPR_BACKEND = "GtkPrintBackendLpr"; //$NON-NLS-1$ static final String GTK_FILE_BACKEND = "GtkPrintBackendFile"; //$NON-NLS-1$ static boolean disablePrinting = OS.IsWin32 || System.getProperty("org.eclipse.swt.internal.gtk.disablePrinting") != null; //$NON-NLS-1$ static void gtk_init() { if (!GTK.gtk_init_check(new long[] { 0 }, null)) { SWT.error(SWT.ERROR_NO_HANDLES, null, " [gtk_init_check() failed]"); } } /** * Returns an array of <code>PrinterData</code> objects * representing all available printers. If there are no * printers, the array will be empty. * * @return an array of PrinterData objects representing the available printers */ public static PrinterData[] getPrinterList() { printerList = new PrinterData[0]; if (disablePrinting) { return printerList; } gtk_init(); Callback printerCallback = new Callback(Printer.class, "GtkPrinterFunc_List", 2); //$NON-NLS-1$ long GtkPrinterFunc_List = printerCallback.getAddress(); if (GtkPrinterFunc_List == 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS); GTK.gtk_enumerate_printers(GtkPrinterFunc_List, 0, 0, true); /* * This call to gdk_threads_leave() is a temporary work around * to avoid deadlocks when gdk_threads_init() is called by native * code outside of SWT (i.e AWT, etc). It ensures that the current * thread leaves the GTK lock acquired by the function above. */ if (!GTK.GTK4) GDK.gdk_threads_leave(); printerCallback.dispose(); return printerList; } static long GtkPrinterFunc_List(long printer, long user_data) { int length = printerList.length; PrinterData[] newList = new PrinterData[length + 1]; System.arraycopy(printerList, 0, newList, 0, length); printerList = newList; printerList[length] = printerDataFromGtkPrinter(printer); /* * Bug in GTK. While performing a gtk_enumerate_printers(), GTK finds all of the * available printers from each backend and can hang. If a backend requires more * time to gather printer info, GTK will start an event loop waiting for a done * signal before continuing. For the Lpr backend, GTK does not send a done signal * which means the event loop never ends. The fix is to check to see if the driver * is of type Lpr, and stop the enumeration, which exits the event loop. */ if (printerList[length].driver.equals(GTK_LPR_BACKEND)) return 1; return 0; } /** * Returns a <code>PrinterData</code> object representing * the default printer or <code>null</code> if there is no * default printer. * * @return the default printer data or null * * @since 2.1 */ public static PrinterData getDefaultPrinterData() { findData = null; if (disablePrinting) { return null; } gtk_init(); Callback printerCallback = new Callback(Printer.class, "GtkPrinterFunc_Default", 2); //$NON-NLS-1$ long GtkPrinterFunc_Default = printerCallback.getAddress(); if (GtkPrinterFunc_Default == 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS); GTK.gtk_enumerate_printers(GtkPrinterFunc_Default, 0, 0, true); /* * This call to gdk_threads_leave() is a temporary work around * to avoid deadlocks when gdk_threads_init() is called by native * code outside of SWT (i.e AWT, etc). It ensures that the current * thread leaves the GTK lock acquired by the function above. */ if (!GTK.GTK4) GDK.gdk_threads_leave(); printerCallback.dispose(); return findData; } static long GtkPrinterFunc_Default(long printer, long user_data) { if (GTK.gtk_printer_is_default(printer)) { findData = printerDataFromGtkPrinter(printer); return 1; } return 0; } static long gtkPrinterFromPrinterData(PrinterData data) { gtk_init(); Callback printerCallback = new Callback(Printer.class, "GtkPrinterFunc_FindNamedPrinter", 2); //$NON-NLS-1$ long GtkPrinterFunc_FindNamedPrinter = printerCallback.getAddress(); if (GtkPrinterFunc_FindNamedPrinter == 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS); findPrinter = 0; findData = data; GTK.gtk_enumerate_printers(GtkPrinterFunc_FindNamedPrinter, 0, 0, true); /* * This call to gdk_threads_leave() is a temporary work around * to avoid deadlocks when gdk_threads_init() is called by native * code outside of SWT (i.e AWT, etc). It ensures that the current * thread leaves the GTK lock acquired by the function above. */ if (!GTK.GTK4) GDK.gdk_threads_leave(); printerCallback.dispose(); return findPrinter; } static long GtkPrinterFunc_FindNamedPrinter(long printer, long user_data) { PrinterData pd = printerDataFromGtkPrinter(printer); if ((pd.driver.equals(findData.driver) && pd.name.equals(findData.name)) || (pd.driver.equals(GTK_FILE_BACKEND)) && findData.printToFile && findData.driver == null && findData.name == null) { // TODO: GTK_FILE_BACKEND is not GTK API (see gtk bug 345590) findPrinter = printer; OS.g_object_ref(printer); return 1; } return 0; } static PrinterData printerDataFromGtkPrinter(long printer) { long backend = GTK.gtk_printer_get_backend(printer); long address = OS.G_OBJECT_TYPE_NAME(backend); int length = C.strlen(address); byte[] buffer = new byte[length]; C.memmove(buffer, address, length); String backendType = new String(Converter.mbcsToWcs(buffer)); address = GTK.gtk_printer_get_name(printer); length = C.strlen(address); buffer = new byte[length]; C.memmove(buffer, address, length); String name = new String(Converter.mbcsToWcs(buffer)); return new PrinterData(backendType, name); } /* * Restore printer settings and page_setup data from data. */ static void restore(byte[] data, long settings, long page_setup) { settingsData = data; start = end = 0; while (end < settingsData.length && settingsData[end] != 0) { start = end; while (end < settingsData.length && settingsData[end] != 0) end++; end++; byte[] keyBuffer = new byte[end - start]; System.arraycopy(settingsData, start, keyBuffer, 0, keyBuffer.length); start = end; while (end < settingsData.length && settingsData[end] != 0) end++; end++; byte[] valueBuffer = new byte[end - start]; System.arraycopy(settingsData, start, valueBuffer, 0, valueBuffer.length); GTK.gtk_print_settings_set(settings, keyBuffer, valueBuffer); if (DEBUG) System.out.println(new String(Converter.mbcsToWcs(keyBuffer)) + ": " + new String(Converter.mbcsToWcs(valueBuffer))); } end++; // skip extra null terminator /* Retrieve stored page_setup data. * Note that page_setup properties must be stored (in PrintDialog) and restored (here) in the same order. */ GTK.gtk_page_setup_set_orientation(page_setup, restoreInt("orientation")); //$NON-NLS-1$ GTK.gtk_page_setup_set_top_margin(page_setup, restoreDouble("top_margin"), GTK.GTK_UNIT_MM); //$NON-NLS-1$ GTK.gtk_page_setup_set_bottom_margin(page_setup, restoreDouble("bottom_margin"), GTK.GTK_UNIT_MM); //$NON-NLS-1$ GTK.gtk_page_setup_set_left_margin(page_setup, restoreDouble("left_margin"), GTK.GTK_UNIT_MM); //$NON-NLS-1$ GTK.gtk_page_setup_set_right_margin(page_setup, restoreDouble("right_margin"), GTK.GTK_UNIT_MM); //$NON-NLS-1$ byte[] name = restoreBytes("paper_size_name", true); //$NON-NLS-1$ byte[] display_name = restoreBytes("paper_size_display_name", true); //$NON-NLS-1$ byte[] ppd_name = restoreBytes("paper_size_ppd_name", true); //$NON-NLS-1$ double width = restoreDouble("paper_size_width"); //$NON-NLS-1$ double height = restoreDouble("paper_size_height"); //$NON-NLS-1$ boolean custom = restoreBoolean("paper_size_is_custom"); //$NON-NLS-1$ long paper_size = 0; if (custom) { if (ppd_name.length > 0) { paper_size = GTK.gtk_paper_size_new_from_ppd(ppd_name, display_name, width, height); } else { paper_size = GTK.gtk_paper_size_new_custom(name, display_name, width, height, GTK.GTK_UNIT_MM); } } else { paper_size = GTK.gtk_paper_size_new(name); } GTK.gtk_page_setup_set_paper_size(page_setup, paper_size); GTK.gtk_paper_size_free(paper_size); } static byte[] uriFromFilename(String filename) { if (filename == null) return null; int length = filename.length(); if (length == 0) return null; char[] chars = new char[length]; filename.getChars(0, length, chars, 0); long[] error = new long[1]; long utf8Ptr = OS.g_utf16_to_utf8(chars, chars.length, null, null, error); if (error[0] != 0 || utf8Ptr == 0) return null; long localePtr = OS.g_filename_from_utf8(utf8Ptr, -1, null, null, error); OS.g_free(utf8Ptr); if (error[0] != 0 || localePtr == 0) return null; long uriPtr = OS.g_filename_to_uri(localePtr, 0, error); OS.g_free(localePtr); if (error[0] != 0 || uriPtr == 0) return null; length = C.strlen(uriPtr); byte[] uri = new byte[length + 1]; C.memmove(uri, uriPtr, length); OS.g_free(uriPtr); return uri; } static DeviceData checkNull(PrinterData data) { if (data == null) data = new PrinterData(); if (data.driver == null || data.name == null) { PrinterData defaultData = null; if (data.printToFile) { long filePrinter = gtkPrinterFromPrinterData(data); if (filePrinter != 0) { defaultData = printerDataFromGtkPrinter(filePrinter); OS.g_object_unref(filePrinter); } } if (defaultData == null) { defaultData = getDefaultPrinterData(); if (defaultData == null) SWT.error(SWT.ERROR_NO_HANDLES); } data.driver = defaultData.driver; data.name = defaultData.name; } return data; } /** * Constructs a new printer representing the default printer. * <p> * Note: You must dispose the printer when it is no longer required. * </p> * * @exception SWTError <ul> * <li>ERROR_NO_HANDLES - if there is no valid default printer * </ul> * * @see Device#dispose */ public Printer() { this(null); } /** * Constructs a new printer given a <code>PrinterData</code> * object representing the desired printer. If the argument * is null, then the default printer will be used. * <p> * Note: You must dispose the printer when it is no longer required. * </p> * * @param data the printer data for the specified printer, or null to use the default printer * * @exception IllegalArgumentException <ul> * <li>ERROR_INVALID_ARGUMENT - if the specified printer data does not represent a valid printer * </ul> * @exception SWTError <ul> * <li>ERROR_NO_HANDLES - if there are no valid printers * </ul> * * @see Device#dispose */ public Printer(PrinterData data) { super(checkNull(data)); } static int restoreInt(String key) { byte[] value = restoreBytes(key, false); return Integer.parseInt(new String(value)); } static double restoreDouble(String key) { byte[] value = restoreBytes(key, false); return Double.parseDouble(new String(value)); } static boolean restoreBoolean(String key) { byte[] value = restoreBytes(key, false); return Boolean.parseBoolean(new String(value)); } static byte[] restoreBytes(String key, boolean nullTerminate) { //get key start = end; while (end < settingsData.length && settingsData[end] != 0) end++; end++; byte[] keyBuffer = new byte[end - start]; System.arraycopy(settingsData, start, keyBuffer, 0, keyBuffer.length); //get value start = end; while (end < settingsData.length && settingsData[end] != 0) end++; int length = end - start; end++; if (nullTerminate) length++; byte[] valueBuffer = new byte[length]; System.arraycopy(settingsData, start, valueBuffer, 0, length); if (DEBUG) System.out.println(new String(Converter.mbcsToWcs(keyBuffer)) + ": " + new String(Converter.mbcsToWcs(valueBuffer))); return valueBuffer; } /** * Invokes platform specific functionality to allocate a new GC handle. * <p> * <b>IMPORTANT:</b> This method is <em>not</em> part of the public * API for <code>Printer</code>. It is marked public only so that it * can be shared within the packages provided by SWT. It is not * available on all platforms, and should never be called from * application code. * </p> * * @param data the platform specific GC data * @return the platform specific GC handle * * @noreference This method is not intended to be referenced by clients. */ @Override public long internal_new_GC(GCData data) { long drawable = 0; long gc = cairo; if (gc == 0) SWT.error(SWT.ERROR_NO_HANDLES); if (data != null) { if (isGCCreated) SWT.error(SWT.ERROR_INVALID_ARGUMENT); int mask = SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT; if ((data.style & mask) == 0) { data.style |= SWT.LEFT_TO_RIGHT; } data.device = this; data.drawable = drawable; data.backgroundRGBA = getSystemColor(SWT.COLOR_WHITE).handle; data.foregroundRGBA = getSystemColor(SWT.COLOR_BLACK).handle; data.font = getSystemFont(); Point dpi = getDPI(), screenDPI = getIndependentDPI(); data.width = (int) (GTK.gtk_page_setup_get_paper_width(pageSetup, GTK.GTK_UNIT_POINTS) * dpi.x / screenDPI.x); data.height = (int) (GTK.gtk_page_setup_get_paper_height(pageSetup, GTK.GTK_UNIT_POINTS) * dpi.y / screenDPI.y); if (cairo == 0) SWT.error(SWT.ERROR_NO_HANDLES); Cairo.cairo_identity_matrix(cairo); double printX = GTK.gtk_page_setup_get_left_margin(pageSetup, GTK.GTK_UNIT_POINTS); double printY = GTK.gtk_page_setup_get_top_margin(pageSetup, GTK.GTK_UNIT_POINTS); Cairo.cairo_translate(cairo, printX, printY); Cairo.cairo_scale(cairo, screenDPI.x / (float) dpi.x, screenDPI.y / (float) dpi.y); double[] matrix = new double[6]; Cairo.cairo_get_matrix(cairo, matrix); data.identity = matrix; data.cairo = cairo; isGCCreated = true; } return gc; } /** * Invokes platform specific functionality to dispose a GC handle. * <p> * <b>IMPORTANT:</b> This method is <em>not</em> part of the public * API for <code>Printer</code>. It is marked public only so that it * can be shared within the packages provided by SWT. It is not * available on all platforms, and should never be called from * application code. * </p> * * @param hDC the platform specific GC handle * @param data the platform specific GC data * * @noreference This method is not intended to be referenced by clients. */ @Override public void internal_dispose_GC(long hDC, GCData data) { if (data != null) isGCCreated = false; } /** * @noreference This method is not intended to be referenced by clients. */ @Override public boolean isAutoScalable() { return false; } /** * Starts a print job and returns true if the job started successfully * and false otherwise. * <p> * This must be the first method called to initiate a print job, * followed by any number of startPage/endPage calls, followed by * endJob. Calling startPage, endPage, or endJob before startJob * will result in undefined behavior. * </p> * * @param jobName the name of the print job to start * @return true if the job started successfully and false otherwise. * * @exception SWTException <ul> * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li> * </ul> * * @see #startPage * @see #endPage * @see #endJob */ public boolean startJob(String jobName) { checkDevice(); byte[] buffer = Converter.wcsToMbcs(jobName, true); printJob = GTK.gtk_print_job_new(buffer, printer, settings, pageSetup); if (printJob == 0) return false; surface = GTK.gtk_print_job_get_surface(printJob, null); if (surface == 0) { OS.g_object_unref(printJob); printJob = 0; return false; } cairo = Cairo.cairo_create(surface); if (cairo == 0) { OS.g_object_unref(printJob); printJob = 0; return false; } return true; } /** * Destroys the printer handle. * This method is called internally by the dispose * mechanism of the <code>Device</code> class. */ @Override protected void destroy() { if (printer != 0) OS.g_object_unref(printer); if (settings != 0) OS.g_object_unref(settings); if (pageSetup != 0) OS.g_object_unref(pageSetup); if (cairo != 0) Cairo.cairo_destroy(cairo); if (printJob != 0) OS.g_object_unref(printJob); printer = settings = pageSetup = cairo = printJob = 0; } /** * Ends the current print job. * * @exception SWTException <ul> * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li> * </ul> * * @see #startJob * @see #startPage * @see #endPage */ public void endJob() { checkDevice(); if (printJob == 0) return; Cairo.cairo_surface_finish(surface); GTK.gtk_print_job_send(printJob, 0, 0, 0); OS.g_object_unref(printJob); printJob = 0; } /** * Cancels a print job in progress. * * @exception SWTException <ul> * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li> * </ul> */ public void cancelJob() { checkDevice(); if (printJob == 0) return; //TODO: Need to implement (waiting on gtk bug 339323) Cairo.cairo_surface_finish(surface); OS.g_object_unref(printJob); printJob = 0; } /** * Starts a page and returns true if the page started successfully * and false otherwise. * <p> * After calling startJob, this method may be called any number of times * along with a matching endPage. * </p> * * @return true if the page started successfully and false otherwise. * * @exception SWTException <ul> * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li> * </ul> * * @see #endPage * @see #startJob * @see #endJob */ public boolean startPage() { checkDevice(); if (printJob == 0) return false; double width = GTK.gtk_page_setup_get_paper_width(pageSetup, GTK.GTK_UNIT_POINTS); double height = GTK.gtk_page_setup_get_paper_height(pageSetup, GTK.GTK_UNIT_POINTS); int type = Cairo.cairo_surface_get_type(surface); switch (type) { case Cairo.CAIRO_SURFACE_TYPE_PS: Cairo.cairo_ps_surface_set_size(surface, width, height); break; case Cairo.CAIRO_SURFACE_TYPE_PDF: Cairo.cairo_pdf_surface_set_size(surface, width, height); break; } return true; } /** * Ends the current page. * * @exception SWTException <ul> * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li> * </ul> * * @see #startPage * @see #startJob * @see #endJob */ public void endPage() { checkDevice(); Cairo.cairo_show_page(cairo); } /** * Returns a point whose x coordinate is the horizontal * dots per inch of the printer, and whose y coordinate * is the vertical dots per inch of the printer. * * @return the horizontal and vertical DPI * * @exception SWTException <ul> * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li> * </ul> */ @Override public Point getDPI() { checkDevice(); int resolution = GTK.gtk_print_settings_get_resolution(settings); if (DEBUG) System.out.println("print_settings.resolution=" + resolution); //TODO: use new api for get x resolution and get y resolution if (resolution == 0) return new Point(72, 72); return new Point(resolution, resolution); } /** * Returns a rectangle describing the receiver's size and location. * <p> * For a printer, this is the size of the physical page, in pixels. * </p> * * @return the bounding rectangle * * @exception SWTException <ul> * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li> * </ul> * * @see #getClientArea * @see #computeTrim */ @Override public Rectangle getBounds() { checkDevice(); Point dpi = getDPI(), screenDPI = getIndependentDPI(); double width = GTK.gtk_page_setup_get_paper_width(pageSetup, GTK.GTK_UNIT_POINTS) * dpi.x / screenDPI.x; double height = GTK.gtk_page_setup_get_paper_height(pageSetup, GTK.GTK_UNIT_POINTS) * dpi.y / screenDPI.y; return new Rectangle(0, 0, (int) width, (int) height); } /** * Returns a rectangle which describes the area of the * receiver which is capable of displaying data. * <p> * For a printer, this is the size of the printable area * of the page, in pixels. * </p> * * @return the client area * * @exception SWTException <ul> * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li> * </ul> * * @see #getBounds * @see #computeTrim */ @Override public Rectangle getClientArea() { checkDevice(); Point dpi = getDPI(), screenDPI = getIndependentDPI(); double width = GTK.gtk_page_setup_get_page_width(pageSetup, GTK.GTK_UNIT_POINTS) * dpi.x / screenDPI.x; double height = GTK.gtk_page_setup_get_page_height(pageSetup, GTK.GTK_UNIT_POINTS) * dpi.y / screenDPI.y; return new Rectangle(0, 0, (int) width, (int) height); } Point getIndependentDPI() { return new Point(72, 72); } /** * Given a <em>client area</em> (as described by the arguments), * returns a rectangle, relative to the client area's coordinates, * that is the client area expanded by the printer's trim (or minimum margins). * <p> * Most printers have a minimum margin on each edge of the paper where the * printer device is unable to print. This margin is known as the "trim." * This method can be used to calculate the printer's minimum margins * by passing in a client area of 0, 0, 0, 0 and then using the resulting * x and y coordinates (which will be <= 0) to determine the minimum margins * for the top and left edges of the paper, and the resulting width and height * (offset by the resulting x and y) to determine the minimum margins for the * bottom and right edges of the paper, as follows: * </p> * <ul> * <li>The left trim width is -x pixels</li> * <li>The top trim height is -y pixels</li> * <li>The right trim width is (x + width) pixels</li> * <li>The bottom trim height is (y + height) pixels</li> * </ul> * * @param x the x coordinate of the client area * @param y the y coordinate of the client area * @param width the width of the client area * @param height the height of the client area * @return a rectangle, relative to the client area's coordinates, that is * the client area expanded by the printer's trim (or minimum margins) * * @exception SWTException <ul> * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li> * </ul> * * @see #getBounds * @see #getClientArea */ public Rectangle computeTrim(int x, int y, int width, int height) { checkDevice(); Point dpi = getDPI(), screenDPI = getIndependentDPI(); double printWidth = GTK.gtk_page_setup_get_page_width(pageSetup, GTK.GTK_UNIT_POINTS) * dpi.x / screenDPI.x; double printHeight = GTK.gtk_page_setup_get_page_height(pageSetup, GTK.GTK_UNIT_POINTS) * dpi.y / screenDPI.y; double paperWidth = GTK.gtk_page_setup_get_paper_width(pageSetup, GTK.GTK_UNIT_POINTS) * dpi.x / screenDPI.x; double paperHeight = GTK.gtk_page_setup_get_paper_height(pageSetup, GTK.GTK_UNIT_POINTS) * dpi.y / screenDPI.y; double printX = -GTK.gtk_page_setup_get_left_margin(pageSetup, GTK.GTK_UNIT_POINTS) * dpi.x / screenDPI.x; double printY = -GTK.gtk_page_setup_get_top_margin(pageSetup, GTK.GTK_UNIT_POINTS) * dpi.y / screenDPI.y; double hTrim = paperWidth - printWidth; double vTrim = paperHeight - printHeight; return new Rectangle(x + (int) printX, y + (int) printY, width + (int) hTrim, height + (int) vTrim); } /** * Creates the printer handle. * This method is called internally by the instance creation * mechanism of the <code>Device</code> class. * @param deviceData the device data */ @Override protected void create(DeviceData deviceData) { this.data = (PrinterData) deviceData; if (disablePrinting) SWT.error(SWT.ERROR_NO_HANDLES); printer = gtkPrinterFromPrinterData(data); if (printer == 0) SWT.error(SWT.ERROR_NO_HANDLES); } /** * Initializes any internal resources needed by the * device. * <p> * This method is called after <code>create</code>. * </p><p> * If subclasses reimplement this method, they must * call the <code>super</code> implementation. * </p> * * @see #create */ @Override protected void init() { settings = GTK.gtk_print_settings_new(); pageSetup = GTK.gtk_page_setup_new(); if (data.otherData != null) { restore(data.otherData, settings, pageSetup); } /* Set values of print_settings and page_setup from PrinterData. */ if (data.printToFile && data.fileName != null) { byte[] uri = uriFromFilename(data.fileName); if (uri != null) { GTK.gtk_print_settings_set(settings, GTK.GTK_PRINT_SETTINGS_OUTPUT_URI, uri); } } GTK.gtk_print_settings_set_n_copies(settings, data.copyCount); GTK.gtk_print_settings_set_collate(settings, data.collate); if (data.duplex != SWT.DEFAULT) { int duplex = data.duplex == PrinterData.DUPLEX_LONG_EDGE ? GTK.GTK_PRINT_DUPLEX_HORIZONTAL : data.duplex == PrinterData.DUPLEX_SHORT_EDGE ? GTK.GTK_PRINT_DUPLEX_VERTICAL : GTK.GTK_PRINT_DUPLEX_SIMPLEX; GTK.gtk_print_settings_set_duplex(settings, duplex); /* * Bug in GTK. The cups backend only looks at the value * of the non-API field cups-Duplex in the print_settings. * The fix is to manually set cups-Duplex to Tumble or NoTumble. */ String cupsDuplexType = null; if (duplex == GTK.GTK_PRINT_DUPLEX_HORIZONTAL) cupsDuplexType = "DuplexNoTumble"; else if (duplex == GTK.GTK_PRINT_DUPLEX_VERTICAL) cupsDuplexType = "DuplexTumble"; if (cupsDuplexType != null) { byte[] keyBuffer = Converter.wcsToMbcs("cups-Duplex", true); byte[] valueBuffer = Converter.wcsToMbcs(cupsDuplexType, true); GTK.gtk_print_settings_set(settings, keyBuffer, valueBuffer); } } int orientation = data.orientation == PrinterData.LANDSCAPE ? GTK.GTK_PAGE_ORIENTATION_LANDSCAPE : GTK.GTK_PAGE_ORIENTATION_PORTRAIT; GTK.gtk_page_setup_set_orientation(pageSetup, orientation); GTK.gtk_print_settings_set_orientation(settings, orientation); super.init(); } /** * Returns a <code>PrinterData</code> object representing the * target printer for this print job. * * @return a PrinterData object describing the receiver */ public PrinterData getPrinterData() { checkDevice(); return data; } }