1 /******************************************************************************* 2 * Copyright (c) 2000, 2008 IBM Corporation and others. 3 * All rights reserved. This program and the accompanying materials 4 * are made available under the terms of the Eclipse Public License v1.0 5 * which accompanies this distribution, and is available at 6 * http://www.eclipse.org/legal/epl-v10.html 7 * 8 * Contributors: 9 * IBM Corporation - initial API and implementation 10 * Port to the D programming language: 11 * Frank Benoit <benoit@tionex.de> 12 *******************************************************************************/ 13 module org.eclipse.swt.printing.Printer; 14 15 16 17 import org.eclipse.swt.SWT; 18 import org.eclipse.swt.SWTError; 19 import org.eclipse.swt.SWTException; 20 import org.eclipse.swt.graphics.Device; 21 import org.eclipse.swt.graphics.DeviceData; 22 import org.eclipse.swt.graphics.Font; 23 import org.eclipse.swt.graphics.GCData; 24 import org.eclipse.swt.graphics.Point; 25 import org.eclipse.swt.graphics.Rectangle; 26 import org.eclipse.swt.internal.cairo.Cairo : Cairo; 27 import org.eclipse.swt.internal.gtk.OS; 28 import org.eclipse.swt.printing.PrinterData; 29 import java.lang.all; 30 31 version(Tango){ 32 import tango.util.Convert; 33 } else { // Phobos 34 import std.conv; 35 } 36 37 38 /** 39 * Instances of this class are used to print to a printer. 40 * Applications create a GC on a printer using <code>new GC(printer)</code> 41 * and then draw on the printer GC using the usual graphics calls. 42 * <p> 43 * A <code>Printer</code> object may be constructed by providing 44 * a <code>PrinterData</code> object which identifies the printer. 45 * A <code>PrintDialog</code> presents a print dialog to the user 46 * and returns an initialized instance of <code>PrinterData</code>. 47 * Alternatively, calling <code>new Printer()</code> will construct a 48 * printer object for the user's default printer. 49 * </p><p> 50 * Application code must explicitly invoke the <code>Printer.dispose()</code> 51 * method to release the operating system resources managed by each instance 52 * when those instances are no longer required. 53 * </p> 54 * 55 * @see PrinterData 56 * @see PrintDialog 57 * @see <a href="http://www.eclipse.org/swt/snippets/#printing">Printing snippets</a> 58 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a> 59 */ 60 public final class Printer : Device { 61 static PrinterData [] printerList; 62 63 PrinterData data; 64 GtkPrinter* printer; 65 GtkPrintJob* printJob; 66 GtkPrintSettings* settings; 67 void* pageSetup; 68 org.eclipse.swt.internal.gtk.OS.cairo_surface_t* surface; 69 org.eclipse.swt.internal.gtk.OS.cairo_t* cairo; 70 71 /** 72 * whether or not a GC was created for this printer 73 */ 74 bool isGCCreated = false; 75 Font systemFont; 76 77 static String settingsData; 78 static int start, end; 79 80 static const String GTK_LPR_BACKEND = "GtkPrintBackendLpr"; //$NON-NLS-1$ 81 82 static const bool disablePrinting = false;// System.getProperty("org.eclipse.swt.internal.gtk.disablePrinting") !is null; //$NON-NLS-1$ 83 84 /** 85 * Returns an array of <code>PrinterData</code> objects 86 * representing all available printers. 87 * 88 * @return the list of available printers 89 */ 90 public static PrinterData[] getPrinterList() { 91 printerList = new PrinterData [0]; 92 if (OS.GTK_VERSION < OS.buildVERSION (2, 10, 0) || disablePrinting) { 93 return printerList; 94 } 95 if (!OS.g_thread_supported ()) { 96 OS.g_thread_init (null); 97 } 98 OS.gtk_set_locale(); 99 int argc = 0; 100 if (!OS.gtk_init_check ( &argc, null)) { 101 SWT.error (SWT.ERROR_NO_HANDLES, null, " [gtk_init_check() failed]"); 102 } 103 OS.gtk_enumerate_printers(&GtkPrinterFunc_List, null, null, true); 104 return printerList; 105 } 106 107 private static extern(C) int GtkPrinterFunc_List (GtkPrinter* printer, void* user_data) { 108 size_t length_ = printerList.length; 109 PrinterData [] newList = new PrinterData [length_ + 1]; 110 System.arraycopy (printerList, 0, newList, 0, length_); 111 printerList = newList; 112 printerList [length_] = printerDataFromGtkPrinter(printer); 113 /* 114 * Bug in GTK. While performing a gtk_enumerate_printers(), GTK finds all of the 115 * available printers from each backend and can hang. If a backend requires more 116 * time to gather printer info, GTK will start an event loop waiting for a done 117 * signal before continuing. For the Lpr backend, GTK does not send a done signal 118 * which means the event loop never ends. The fix is to check to see if the driver 119 * is of type Lpr, and stop the enumeration, which exits the event loop. 120 */ 121 if (printerList[length_].driver.equals(GTK_LPR_BACKEND)) return 1; 122 return 0; 123 } 124 125 /** 126 * Returns a <code>PrinterData</code> object representing 127 * the default printer or <code>null</code> if there is no 128 * printer available on the System. 129 * 130 * @return the default printer data or null 131 * 132 * @since 2.1 133 */ 134 public static PrinterData getDefaultPrinterData() { 135 printerList = new PrinterData [1]; 136 if (OS.GTK_VERSION < OS.buildVERSION (2, 10, 0) || disablePrinting) { 137 return null; 138 } 139 if (!OS.g_thread_supported ()) { 140 OS.g_thread_init (null); 141 } 142 OS.gtk_set_locale(); 143 int argc = 0; 144 if (!OS.gtk_init_check (&argc, null)) { 145 SWT.error (SWT.ERROR_NO_HANDLES, null, " [gtk_init_check() failed]"); 146 } 147 OS.gtk_enumerate_printers(&GtkPrinterFunc_Default, null, null, true); 148 return printerList[0]; 149 } 150 151 private static extern(C) int GtkPrinterFunc_Default (GtkPrinter* printer, void* user_data) { 152 if (OS.gtk_printer_is_default(printer)) { 153 printerList[0] = printerDataFromGtkPrinter(printer); 154 return 1; 155 } else if (OS.GTK_VERSION < OS.buildVERSION(2, 10, 12) && printerDataFromGtkPrinter(printer).driver.equals (GTK_LPR_BACKEND)) { 156 return 1; 157 } 158 return 0; 159 } 160 161 GtkPrinter* gtkPrinterFromPrinterData() { 162 printer = null; 163 OS.gtk_enumerate_printers(&GtkPrinterFunc_FindNamedPrinterFunc, cast(void*)this, null, true); 164 return printer; 165 } 166 167 private static extern(C) int GtkPrinterFunc_FindNamedPrinterFunc (GtkPrinter* printer, void* user_data) { 168 return (cast(Printer)user_data).GtkPrinterFunc_FindNamedPrinter( printer, null ); 169 } 170 int GtkPrinterFunc_FindNamedPrinter (GtkPrinter* printer, void* user_data) { 171 PrinterData pd = printerDataFromGtkPrinter(printer); 172 if (pd.driver.equals(data.driver) && pd.name.equals(data.name)) { 173 this.printer = printer; 174 OS.g_object_ref(printer); 175 return 1; 176 } else if (OS.GTK_VERSION < OS.buildVERSION (2, 10, 12) && pd.driver.equals(GTK_LPR_BACKEND)) { 177 return 1; 178 } 179 return 0; 180 } 181 182 static PrinterData printerDataFromGtkPrinter(GtkPrinter* printer) { 183 auto backend = OS.gtk_printer_get_backend(printer); 184 auto address = OS.G_OBJECT_TYPE_NAME(backend); 185 String backendType = fromStringz( address )._idup(); 186 187 address = OS.gtk_printer_get_name (printer); 188 String name = fromStringz( address )._idup(); 189 190 return new PrinterData (backendType, name); 191 } 192 193 /* 194 * Restore printer settings and page_setup data from data. 195 */ 196 static void restore(char[] data, GtkPrintSettings* settings, GtkPageSetup* page_setup) { 197 settingsData = data._idup(); 198 start = end = 0; 199 while (end < settingsData.length && settingsData[end] !is 0) { 200 start = end; 201 while (end < settingsData.length && settingsData[end] !is 0) end++; 202 end++; 203 char [] keyBuffer = new char [end - start]; 204 System.arraycopy (settingsData, start, keyBuffer, 0, keyBuffer.length); 205 start = end; 206 while (end < settingsData.length && settingsData[end] !is 0) end++; 207 end++; 208 char [] valueBuffer = new char [end - start]; 209 System.arraycopy (settingsData, start, valueBuffer, 0, valueBuffer.length); 210 OS.gtk_print_settings_set(settings, keyBuffer.ptr, valueBuffer.ptr); 211 if (DEBUG) getDwtLogger().info( __FILE__, __LINE__, "{}: {}", keyBuffer, valueBuffer ); 212 } 213 end++; // skip extra null terminator 214 215 /* Retrieve stored page_setup data. 216 * Note that page_setup properties must be stored (in PrintDialog) and restored (here) in the same order. 217 */ 218 OS.gtk_page_setup_set_orientation(page_setup, restoreInt("orientation")); //$NON-NLS-1$ 219 OS.gtk_page_setup_set_top_margin(page_setup, restoreDouble("top_margin"), OS.GTK_UNIT_MM); //$NON-NLS-1$ 220 OS.gtk_page_setup_set_bottom_margin(page_setup, restoreDouble("bottom_margin"), OS.GTK_UNIT_MM); //$NON-NLS-1$ 221 OS.gtk_page_setup_set_left_margin(page_setup, restoreDouble("left_margin"), OS.GTK_UNIT_MM); //$NON-NLS-1$ 222 OS.gtk_page_setup_set_right_margin(page_setup, restoreDouble("right_margin"), OS.GTK_UNIT_MM); //$NON-NLS-1$ 223 String name = restoreBytes("paper_size_name", true); //$NON-NLS-1$ 224 String display_name = restoreBytes("paper_size_display_name", true); //$NON-NLS-1$ 225 String ppd_name = restoreBytes("paper_size_ppd_name", true); //$NON-NLS-1$ 226 double width = restoreDouble("paper_size_width"); //$NON-NLS-1$ 227 double height = restoreDouble("paper_size_height"); //$NON-NLS-1$ 228 bool custom = restoreBoolean("paper_size_is_custom"); //$NON-NLS-1$ 229 GtkPaperSize* paper_size = null; 230 if (custom) { 231 if (ppd_name.length > 0) { 232 paper_size = OS.gtk_paper_size_new_from_ppd(ppd_name.ptr, display_name.ptr, width, height); 233 } else { 234 paper_size = OS.gtk_paper_size_new_custom(name.ptr, display_name.ptr, width, height, OS.GTK_UNIT_MM); 235 } 236 } else { 237 paper_size = OS.gtk_paper_size_new(name.ptr); 238 } 239 OS.gtk_page_setup_set_paper_size(page_setup, paper_size); 240 OS.gtk_paper_size_free(paper_size); 241 } 242 243 static void setScope(GtkPrintSettings* settings, int scope_, int startPage, int endPage) { 244 switch (scope_) { 245 case PrinterData.ALL_PAGES: 246 OS.gtk_print_settings_set_print_pages(settings, OS.GTK_PRINT_PAGES_ALL); 247 break; 248 case PrinterData.PAGE_RANGE: 249 OS.gtk_print_settings_set_print_pages(settings, OS.GTK_PRINT_PAGES_RANGES); 250 GtkPageRange pageRange; 251 pageRange.start = startPage - 1; 252 pageRange.end = endPage - 1; 253 OS.gtk_print_settings_set_page_ranges(settings, &pageRange, 1); 254 break; 255 case PrinterData.SELECTION: 256 //TODO: Not correctly implemented. May need new API. For now, set to ALL. (see gtk bug 344519) 257 OS.gtk_print_settings_set_print_pages(settings, OS.GTK_PRINT_PAGES_ALL); 258 break; 259 default: 260 } 261 } 262 263 static DeviceData checkNull (PrinterData data) { 264 if (data is null) data = new PrinterData(); 265 if (data.driver is null || data.name is null) { 266 PrinterData defaultPrinter = getDefaultPrinterData(); 267 if (defaultPrinter is null) SWT.error(SWT.ERROR_NO_HANDLES); 268 data.driver = defaultPrinter.driver; 269 data.name = defaultPrinter.name; 270 } 271 return data; 272 } 273 274 /** 275 * Constructs a new printer representing the default printer. 276 * <p> 277 * You must dispose the printer when it is no longer required. 278 * </p> 279 * 280 * @exception SWTError <ul> 281 * <li>ERROR_NO_HANDLES - if there are no valid printers 282 * </ul> 283 * 284 * @see Device#dispose 285 */ 286 public this() { 287 this(null); 288 } 289 290 /** 291 * Constructs a new printer given a <code>PrinterData</code> 292 * object representing the desired printer. 293 * <p> 294 * You must dispose the printer when it is no longer required. 295 * </p> 296 * 297 * @param data the printer data for the specified printer 298 * 299 * @exception IllegalArgumentException <ul> 300 * <li>ERROR_INVALID_ARGUMENT - if the specified printer data does not represent a valid printer 301 * </ul> 302 * @exception SWTError <ul> 303 * <li>ERROR_NO_HANDLES - if there are no valid printers 304 * </ul> 305 * 306 * @see Device#dispose 307 */ 308 public this(PrinterData data) { 309 super(checkNull(data)); 310 } 311 312 static int restoreInt(String key) { 313 String value = restoreBytes(key, false); 314 return Integer.parseInt( value ); 315 } 316 317 static double restoreDouble(String key) { 318 String value = restoreBytes(key, false); 319 return Double.parseDouble( value ); 320 } 321 322 static bool restoreBoolean(String key) { 323 String value = restoreBytes(key, false); 324 return Boolean.getBoolean( value ); 325 } 326 327 static String restoreBytes(String key, bool nullTerminate) { 328 //get key 329 start = end; 330 while (end < settingsData.length && settingsData[end] !is 0) end++; 331 end++; 332 char [] keyBuffer = new char [end - start]; 333 System.arraycopy (settingsData, start, keyBuffer, 0, keyBuffer.length); 334 335 //get value 336 start = end; 337 while (end < settingsData.length && settingsData[end] !is 0) end++; 338 int length_ = end - start; 339 end++; 340 if (nullTerminate) length_++; 341 char [] valueBuffer = new char [length_]; 342 System.arraycopy (settingsData, start, valueBuffer, 0, length_); 343 344 if (DEBUG) getDwtLogger().info( __FILE__, __LINE__, "{}: {}", keyBuffer, valueBuffer ); 345 346 return cast(String)valueBuffer; 347 } 348 349 /** 350 * Returns a reasonable font for applications to use. 351 * On some platforms, this will match the "default font" 352 * or "system font" if such can be found. This font 353 * should not be free'd because it was allocated by the 354 * system, not the application. 355 * <p> 356 * Typically, applications which want the default look 357 * should simply not set the font on the widgets they 358 * create. Widgets are always created with the correct 359 * default font for the class of user-interface component 360 * they represent. 361 * </p> 362 * 363 * @return a font 364 * 365 * @exception SWTException <ul> 366 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 367 * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li> 368 * </ul> 369 */ 370 public override Font getSystemFont () { 371 checkDevice (); 372 if (systemFont !is null) return systemFont; 373 auto style = OS.gtk_widget_get_default_style(); 374 auto defaultFont = OS.pango_font_description_copy (OS.gtk_style_get_font_desc (style)); 375 return systemFont = Font.gtk_new (this, defaultFont); 376 } 377 378 /** 379 * Invokes platform specific functionality to allocate a new GC handle. 380 * <p> 381 * <b>IMPORTANT:</b> This method is <em>not</em> part of the public 382 * API for <code>Printer</code>. It is marked public only so that it 383 * can be shared within the packages provided by SWT. It is not 384 * available on all platforms, and should never be called from 385 * application code. 386 * </p> 387 * 388 * @param data the platform specific GC data 389 * @return the platform specific GC handle 390 */ 391 public override GdkGC* internal_new_GC(GCData data) { 392 auto drawable = OS.gdk_pixmap_new(OS.GDK_ROOT_PARENT(), 1, 1, 1); 393 auto gdkGC = OS.gdk_gc_new (drawable); 394 if (gdkGC is null) SWT.error (SWT.ERROR_NO_HANDLES); 395 if (data !is null) { 396 if (isGCCreated) SWT.error(SWT.ERROR_INVALID_ARGUMENT); 397 int mask = SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT; 398 if ((data.style & mask) is 0) { 399 data.style |= SWT.LEFT_TO_RIGHT; 400 } 401 data.device = this; 402 data.drawable = drawable; 403 data.background = getSystemColor (SWT.COLOR_WHITE).handle; 404 data.foreground = getSystemColor (SWT.COLOR_BLACK).handle; 405 data.font = getSystemFont (); 406 //TODO: We are supposed to return this in pixels, but GTK_UNIT_PIXELS is currently not implemented (gtk bug 346245) 407 data.width = cast(int)OS.gtk_page_setup_get_paper_width (pageSetup, OS.GTK_UNIT_POINTS); 408 data.height = cast(int)OS.gtk_page_setup_get_paper_height (pageSetup, OS.GTK_UNIT_POINTS); 409 if (cairo is null) SWT.error(SWT.ERROR_NO_HANDLES); 410 data.cairo = cairo; 411 isGCCreated = true; 412 } 413 return gdkGC; 414 } 415 416 /** 417 * Invokes platform specific functionality to dispose a GC handle. 418 * <p> 419 * <b>IMPORTANT:</b> This method is <em>not</em> part of the public 420 * API for <code>Printer</code>. It is marked public only so that it 421 * can be shared within the packages provided by SWT. It is not 422 * available on all platforms, and should never be called from 423 * application code. 424 * </p> 425 * 426 * @param hDC the platform specific GC handle 427 * @param data the platform specific GC data 428 */ 429 public override void internal_dispose_GC(GdkGC* gdkGC, GCData data) { 430 if (data !is null) isGCCreated = false; 431 OS.g_object_unref (gdkGC); 432 if (data !is null) { 433 if (data.drawable !is null) OS.g_object_unref (data.drawable); 434 data.drawable = null; 435 data.cairo = null; 436 } 437 } 438 439 /** 440 * Releases any internal state prior to destroying this printer. 441 * This method is called internally by the dispose 442 * mechanism of the <code>Device</code> class. 443 */ 444 protected override void release () { 445 super.release(); 446 447 /* Dispose the default font */ 448 if (systemFont !is null) systemFont.dispose (); 449 systemFont = null; 450 } 451 452 /** 453 * Starts a print job and returns true if the job started successfully 454 * and false otherwise. 455 * <p> 456 * This must be the first method called to initiate a print job, 457 * followed by any number of startPage/endPage calls, followed by 458 * endJob. Calling startPage, endPage, or endJob before startJob 459 * will result in undefined behavior. 460 * </p> 461 * 462 * @param jobName the name of the print job to start 463 * @return true if the job started successfully and false otherwise. 464 * 465 * @exception SWTException <ul> 466 * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li> 467 * </ul> 468 * 469 * @see #startPage 470 * @see #endPage 471 * @see #endJob 472 */ 473 public bool startJob(String jobName) { 474 checkDevice(); 475 char* buffer = toStringz(jobName); 476 printJob = OS.gtk_print_job_new (buffer, printer, settings, pageSetup); 477 if (printJob is null) return false; 478 surface = OS.gtk_print_job_get_surface(printJob, null); 479 if (surface is null) { 480 OS.g_object_unref(printJob); 481 printJob = null; 482 return false; 483 } 484 cairo = Cairo.cairo_create(surface); 485 if (cairo is null) { 486 OS.g_object_unref(printJob); 487 printJob = null; 488 return false; 489 } 490 return true; 491 } 492 493 /** 494 * Destroys the printer handle. 495 * This method is called internally by the dispose 496 * mechanism of the <code>Device</code> class. 497 */ 498 protected override void destroy () { 499 if (printer !is null) OS.g_object_unref (printer); 500 if (settings !is null) OS.g_object_unref (settings); 501 if (pageSetup !is null) OS.g_object_unref (pageSetup); 502 if (cairo !is null) Cairo.cairo_destroy (cairo); 503 if (printJob !is null) OS.g_object_unref (printJob); 504 printer = null; 505 settings = null; 506 pageSetup = null; 507 cairo = null; 508 printJob = null; 509 } 510 511 /** 512 * Ends the current print job. 513 * 514 * @exception SWTException <ul> 515 * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li> 516 * </ul> 517 * 518 * @see #startJob 519 * @see #startPage 520 * @see #endPage 521 */ 522 public void endJob() { 523 checkDevice(); 524 if (printJob is null) return; 525 Cairo.cairo_surface_finish(surface); 526 OS.gtk_print_job_send(printJob, null, null, null ); 527 } 528 529 /** 530 * Cancels a print job in progress. 531 * 532 * @exception SWTException <ul> 533 * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li> 534 * </ul> 535 */ 536 public void cancelJob() { 537 checkDevice(); 538 if (printJob is null) return; 539 //TODO: Need to implement (waiting on gtk bug 339323) 540 //OS.g_object_unref(printJob); 541 //printJob = 0; 542 } 543 544 /** 545 * Starts a page and returns true if the page started successfully 546 * and false otherwise. 547 * <p> 548 * After calling startJob, this method may be called any number of times 549 * along with a matching endPage. 550 * </p> 551 * 552 * @return true if the page started successfully and false otherwise. 553 * 554 * @exception SWTException <ul> 555 * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li> 556 * </ul> 557 * 558 * @see #endPage 559 * @see #startJob 560 * @see #endJob 561 */ 562 public bool startPage() { 563 checkDevice(); 564 if (printJob is null) return false; 565 double width = OS.gtk_page_setup_get_paper_width (pageSetup, OS.GTK_UNIT_POINTS); 566 double height = OS.gtk_page_setup_get_paper_height (pageSetup, OS.GTK_UNIT_POINTS); 567 ptrdiff_t type = Cairo.cairo_surface_get_type (surface); 568 switch (type) { 569 case Cairo.CAIRO_SURFACE_TYPE_PS: 570 Cairo.cairo_ps_surface_set_size (surface, width, height); 571 break; 572 case Cairo.CAIRO_SURFACE_TYPE_PDF: 573 Cairo.cairo_pdf_surface_set_size (surface, width, height); 574 break; 575 default: 576 } 577 return true; 578 } 579 580 /** 581 * Ends the current page. 582 * 583 * @exception SWTException <ul> 584 * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li> 585 * </ul> 586 * 587 * @see #startPage 588 * @see #startJob 589 * @see #endJob 590 */ 591 public void endPage() { 592 checkDevice(); 593 if (cairo !is null) Cairo.cairo_show_page(cairo); 594 } 595 596 /** 597 * Returns a point whose x coordinate is the horizontal 598 * dots per inch of the printer, and whose y coordinate 599 * is the vertical dots per inch of the printer. 600 * 601 * @return the horizontal and vertical DPI 602 * 603 * @exception SWTException <ul> 604 * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li> 605 * </ul> 606 */ 607 public override Point getDPI() { 608 checkDevice(); 609 int resolution = OS.gtk_print_settings_get_resolution(settings); 610 if (DEBUG) getDwtLogger().info( __FILE__, __LINE__, "print_settings.resolution={}", resolution); 611 //TODO: Return 72 (1/72 inch = 1 point) until gtk bug 346245 is fixed 612 //TODO: Fix this: gtk_print_settings_get_resolution returns 0? (see gtk bug 346252) 613 if (true || resolution is 0) return new Point(72, 72); 614 return new Point(resolution, resolution); 615 } 616 617 /** 618 * Returns a rectangle describing the receiver's size and location. 619 * <p> 620 * For a printer, this is the size of the physical page, in pixels. 621 * </p> 622 * 623 * @return the bounding rectangle 624 * 625 * @exception SWTException <ul> 626 * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li> 627 * </ul> 628 * 629 * @see #getClientArea 630 * @see #computeTrim 631 */ 632 public override Rectangle getBounds() { 633 checkDevice(); 634 //TODO: We are supposed to return this in pixels, but GTK_UNIT_PIXELS is currently not implemented (gtk bug 346245) 635 double width = OS.gtk_page_setup_get_paper_width (pageSetup, OS.GTK_UNIT_POINTS); 636 double height = OS.gtk_page_setup_get_paper_height (pageSetup, OS.GTK_UNIT_POINTS); 637 return new Rectangle(0, 0, cast(int) width, cast(int) height); 638 } 639 640 /** 641 * Returns a rectangle which describes the area of the 642 * receiver which is capable of displaying data. 643 * <p> 644 * For a printer, this is the size of the printable area 645 * of the page, in pixels. 646 * </p> 647 * 648 * @return the client area 649 * 650 * @exception SWTException <ul> 651 * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li> 652 * </ul> 653 * 654 * @see #getBounds 655 * @see #computeTrim 656 */ 657 public override Rectangle getClientArea() { 658 checkDevice(); 659 //TODO: We are supposed to return this in pixels, but GTK_UNIT_PIXELS is currently not implemented (gtk bug 346245) 660 double width = OS.gtk_page_setup_get_page_width(pageSetup, OS.GTK_UNIT_POINTS); 661 double height = OS.gtk_page_setup_get_page_height(pageSetup, OS.GTK_UNIT_POINTS); 662 return new Rectangle(0, 0, cast(int) width, cast(int) height); 663 } 664 665 /** 666 * Given a <em>client area</em> (as described by the arguments), 667 * returns a rectangle, relative to the client area's coordinates, 668 * that is the client area expanded by the printer's trim (or minimum margins). 669 * <p> 670 * Most printers have a minimum margin on each edge of the paper where the 671 * printer device is unable to print. This margin is known as the "trim." 672 * This method can be used to calculate the printer's minimum margins 673 * by passing in a client area of 0, 0, 0, 0 and then using the resulting 674 * x and y coordinates (which will be <= 0) to determine the minimum margins 675 * for the top and left edges of the paper, and the resulting width and height 676 * (offset by the resulting x and y) to determine the minimum margins for the 677 * bottom and right edges of the paper, as follows: 678 * <ul> 679 * <li>The left trim width is -x pixels</li> 680 * <li>The top trim height is -y pixels</li> 681 * <li>The right trim width is (x + width) pixels</li> 682 * <li>The bottom trim height is (y + height) pixels</li> 683 * </ul> 684 * </p> 685 * 686 * @param x the x coordinate of the client area 687 * @param y the y coordinate of the client area 688 * @param width the width of the client area 689 * @param height the height of the client area 690 * @return a rectangle, relative to the client area's coordinates, that is 691 * the client area expanded by the printer's trim (or minimum margins) 692 * 693 * @exception SWTException <ul> 694 * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li> 695 * </ul> 696 * 697 * @see #getBounds 698 * @see #getClientArea 699 */ 700 public Rectangle computeTrim(int x, int y, int width, int height) { 701 checkDevice(); 702 //TODO: We are supposed to return this in pixels, but GTK_UNIT_PIXELS is currently not implemented (gtk bug 346245) 703 double printWidth = OS.gtk_page_setup_get_page_width(pageSetup, OS.GTK_UNIT_POINTS); 704 double printHeight = OS.gtk_page_setup_get_page_height(pageSetup, OS.GTK_UNIT_POINTS); 705 double paperWidth = OS.gtk_page_setup_get_paper_width (pageSetup, OS.GTK_UNIT_POINTS); 706 double paperHeight = OS.gtk_page_setup_get_paper_height (pageSetup, OS.GTK_UNIT_POINTS); 707 double printX = -OS.gtk_page_setup_get_left_margin(pageSetup, OS.GTK_UNIT_POINTS); 708 double printY = -OS.gtk_page_setup_get_top_margin(pageSetup, OS.GTK_UNIT_POINTS); 709 double hTrim = paperWidth - printWidth; 710 double vTrim = paperHeight - printHeight; 711 return new Rectangle(x + cast(int)printX, y + cast(int)printY, width + cast(int)hTrim, height + cast(int)vTrim); 712 } 713 714 /** 715 * Creates the printer handle. 716 * This method is called internally by the instance creation 717 * mechanism of the <code>Device</code> class. 718 * @param deviceData the device data 719 */ 720 protected override void create(DeviceData deviceData) { 721 this.data = cast(PrinterData)deviceData; 722 if (OS.GTK_VERSION < OS.buildVERSION (2, 10, 0) || disablePrinting) SWT.error(SWT.ERROR_NO_HANDLES); 723 printer = gtkPrinterFromPrinterData(); 724 if (printer is null) SWT.error(SWT.ERROR_NO_HANDLES); 725 } 726 727 /** 728 * Initializes any internal resources needed by the 729 * device. 730 * <p> 731 * This method is called after <code>create</code>. 732 * </p><p> 733 * If subclasses reimplement this method, they must 734 * call the <code>super</code> implementation. 735 * </p> 736 * 737 * @see #create 738 */ 739 protected override void init_() { 740 super.init_ (); 741 settings = OS.gtk_print_settings_new(); 742 pageSetup = OS.gtk_page_setup_new(); 743 if (data.otherData !is null) { 744 restore(data.otherData, settings, pageSetup); 745 } 746 747 /* Set values of settings from PrinterData. */ 748 setScope(settings, data.scope_, data.startPage, data.endPage); 749 //TODO: Should we look at printToFile, or driver/name for "Print to File", or both? (see gtk bug 345590) 750 if (data.printToFile) { 751 char* buffer = toStringz( data.fileName ); 752 OS.gtk_print_settings_set(settings, OS.GTK_PRINT_SETTINGS_OUTPUT_URI.ptr, buffer); 753 } 754 if (data.driver.equals("GtkPrintBackendFile") && data.name.equals("Print to File")) { //$NON-NLS-1$ //$NON-NLS-2$ 755 char* buffer = toStringz( data.fileName ); 756 OS.gtk_print_settings_set(settings, OS.GTK_PRINT_SETTINGS_OUTPUT_URI.ptr, buffer); 757 } 758 OS.gtk_print_settings_set_n_copies(settings, data.copyCount); 759 OS.gtk_print_settings_set_collate(settings, data.collate); 760 } 761 762 /** 763 * Returns a <code>PrinterData</code> object representing the 764 * target printer for this print job. 765 * 766 * @return a PrinterData object describing the receiver 767 */ 768 public PrinterData getPrinterData() { 769 checkDevice(); 770 return data; 771 } 772 773 }