forked from AuroraMiddleware/gtk
f339cc276c
gtk_widget_set_visible and gtk_window_present are better alternatives, and calling gtk_widget_show on newly created widgets is no longer necessary anyway.
2245 lines
63 KiB
C
2245 lines
63 KiB
C
/* GTK - The GIMP Toolkit
|
|
* gtkprintoperation-win32.c: Print Operation Details for Win32
|
|
* Copyright (C) 2006, Red Hat, Inc.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library 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
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#ifndef _MSC_VER
|
|
#ifndef _WIN32_WINNT
|
|
/* Vista or newer */
|
|
#define _WIN32_WINNT 0x0600
|
|
#endif
|
|
#ifndef WINVER
|
|
#define WINVER _WIN32_WINNT
|
|
#endif
|
|
#endif
|
|
|
|
#define COBJMACROS
|
|
#include "config.h"
|
|
#include <math.h>
|
|
#ifdef HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
#include <io.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <windows.h>
|
|
#include <cairo-win32.h>
|
|
#include <glib.h>
|
|
#include <glib/gi18n-lib.h>
|
|
#include "gtkprintoperation-private.h"
|
|
#include "gtkprint-win32.h"
|
|
#include "gtkwindow.h"
|
|
#include "gtkprivate.h"
|
|
#include "gtkwidgetprivate.h"
|
|
#include "gtknative.h"
|
|
#include "win32/gdkprivate-win32.h"
|
|
|
|
#define MAX_PAGE_RANGES 20
|
|
#define STATUS_POLLING_TIME 2000
|
|
|
|
#ifndef JOB_STATUS_RESTART
|
|
#define JOB_STATUS_RESTART 0x800
|
|
#endif
|
|
|
|
#ifndef JOB_STATUS_COMPLETE
|
|
#define JOB_STATUS_COMPLETE 0x1000
|
|
#endif
|
|
|
|
/* Forward declarations */
|
|
GtkPrintOperationResult
|
|
gtk_print_operation_run_without_dialog (GtkPrintOperation *op,
|
|
gboolean *do_print);
|
|
GtkPrintOperationResult
|
|
gtk_print_operation_run_with_dialog (GtkPrintOperation *op,
|
|
GtkWindow *parent,
|
|
gboolean *do_print);
|
|
UINT_PTR CALLBACK
|
|
run_mainloop_hook (HWND hdlg,
|
|
UINT uiMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam);
|
|
void
|
|
win32_start_page (GtkPrintOperation *op,
|
|
GtkPrintContext *print_context,
|
|
GtkPageSetup *page_setup);
|
|
|
|
typedef struct {
|
|
HDC hdc;
|
|
HGLOBAL devmode;
|
|
HGLOBAL devnames;
|
|
HANDLE printerHandle;
|
|
int job_id;
|
|
guint timeout_id;
|
|
|
|
cairo_surface_t *surface;
|
|
GtkWidget *embed_widget;
|
|
} GtkPrintOperationWin32;
|
|
|
|
static void win32_poll_status (GtkPrintOperation *op);
|
|
|
|
static const GUID myIID_IPrintDialogCallback = {0x5852a2c3,0x6530,0x11d1,{0xb6,0xa3,0x0,0x0,0xf8,0x75,0x7b,0xf9}};
|
|
|
|
#if !defined (_MSC_VER) && !defined (HAVE_IPRINTDIALOGCALLBACK)
|
|
#undef INTERFACE
|
|
#define INTERFACE IPrintDialogCallback
|
|
DECLARE_INTERFACE_ (IPrintDialogCallback, IUnknown)
|
|
{
|
|
STDMETHOD (QueryInterface)(THIS_ REFIID,LPVOID*) PURE;
|
|
STDMETHOD_ (ULONG, AddRef)(THIS) PURE;
|
|
STDMETHOD_ (ULONG, Release)(THIS) PURE;
|
|
STDMETHOD (InitDone)(THIS) PURE;
|
|
STDMETHOD (SelectionChange)(THIS) PURE;
|
|
STDMETHOD (HandleMessage)(THIS_ HWND,UINT,WPARAM,LPARAM,LRESULT*) PURE;
|
|
};
|
|
#endif
|
|
|
|
static UINT got_gdk_events_message;
|
|
|
|
UINT_PTR CALLBACK
|
|
run_mainloop_hook (HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if (uiMsg == WM_INITDIALOG)
|
|
{
|
|
gdk_win32_set_modal_dialog_libgtk_only (hdlg);
|
|
while (g_main_context_pending (NULL))
|
|
g_main_context_iteration (NULL, TRUE);
|
|
}
|
|
else if (uiMsg == got_gdk_events_message)
|
|
{
|
|
while (g_main_context_pending (NULL))
|
|
g_main_context_iteration (NULL, TRUE);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static GtkPageOrientation
|
|
orientation_from_win32 (short orientation)
|
|
{
|
|
if (orientation == DMORIENT_LANDSCAPE)
|
|
return GTK_PAGE_ORIENTATION_LANDSCAPE;
|
|
return GTK_PAGE_ORIENTATION_PORTRAIT;
|
|
}
|
|
|
|
static short
|
|
orientation_to_win32 (GtkPageOrientation orientation)
|
|
{
|
|
if (orientation == GTK_PAGE_ORIENTATION_LANDSCAPE ||
|
|
orientation == GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE)
|
|
return DMORIENT_LANDSCAPE;
|
|
return DMORIENT_PORTRAIT;
|
|
}
|
|
|
|
static GtkPaperSize *
|
|
paper_size_from_win32 (short size)
|
|
{
|
|
const char *name;
|
|
|
|
switch (size)
|
|
{
|
|
case DMPAPER_LETTER_TRANSVERSE:
|
|
case DMPAPER_LETTER:
|
|
case DMPAPER_LETTERSMALL:
|
|
name = "na_letter";
|
|
break;
|
|
case DMPAPER_TABLOID:
|
|
case DMPAPER_LEDGER:
|
|
name = "na_ledger";
|
|
break;
|
|
case DMPAPER_LEGAL:
|
|
name = "na_legal";
|
|
break;
|
|
case DMPAPER_STATEMENT:
|
|
name = "na_invoice";
|
|
break;
|
|
case DMPAPER_EXECUTIVE:
|
|
name = "na_executive";
|
|
break;
|
|
case DMPAPER_A3:
|
|
case DMPAPER_A3_TRANSVERSE:
|
|
name = "iso_a3";
|
|
break;
|
|
case DMPAPER_A4:
|
|
case DMPAPER_A4SMALL:
|
|
case DMPAPER_A4_TRANSVERSE:
|
|
name = "iso_a4";
|
|
break;
|
|
case DMPAPER_A5:
|
|
case DMPAPER_A5_TRANSVERSE:
|
|
name = "iso_a5";
|
|
break;
|
|
case DMPAPER_B4:
|
|
name = "jis_b4";
|
|
break;
|
|
case DMPAPER_B5:
|
|
case DMPAPER_B5_TRANSVERSE:
|
|
name = "jis_b5";
|
|
break;
|
|
case DMPAPER_QUARTO:
|
|
name = "na_quarto";
|
|
break;
|
|
case DMPAPER_10X14:
|
|
name = "na_10x14";
|
|
break;
|
|
case DMPAPER_11X17:
|
|
name = "na_ledger";
|
|
break;
|
|
case DMPAPER_NOTE:
|
|
name = "na_letter";
|
|
break;
|
|
case DMPAPER_ENV_9:
|
|
name = "na_number-9";
|
|
break;
|
|
case DMPAPER_ENV_10:
|
|
name = "na_number-10";
|
|
break;
|
|
case DMPAPER_ENV_11:
|
|
name = "na_number-11";
|
|
break;
|
|
case DMPAPER_ENV_12:
|
|
name = "na_number-12";
|
|
break;
|
|
case DMPAPER_ENV_14:
|
|
name = "na_number-14";
|
|
break;
|
|
case DMPAPER_CSHEET:
|
|
name = "na_c";
|
|
break;
|
|
case DMPAPER_DSHEET:
|
|
name = "na_d";
|
|
break;
|
|
case DMPAPER_ESHEET:
|
|
name = "na_e";
|
|
break;
|
|
case DMPAPER_ENV_DL:
|
|
name = "iso_dl";
|
|
break;
|
|
case DMPAPER_ENV_C5:
|
|
name = "iso_c5";
|
|
break;
|
|
case DMPAPER_ENV_C3:
|
|
name = "iso_c3";
|
|
break;
|
|
case DMPAPER_ENV_C4:
|
|
name = "iso_c4";
|
|
break;
|
|
case DMPAPER_ENV_C6:
|
|
name = "iso_c6";
|
|
break;
|
|
case DMPAPER_ENV_C65:
|
|
name = "iso_c6c5";
|
|
break;
|
|
case DMPAPER_ENV_B4:
|
|
name = "iso_b4";
|
|
break;
|
|
case DMPAPER_ENV_B5:
|
|
name = "iso_b5";
|
|
break;
|
|
case DMPAPER_ENV_B6:
|
|
name = "iso_b6";
|
|
break;
|
|
case DMPAPER_ENV_ITALY:
|
|
name = "om_italian";
|
|
break;
|
|
case DMPAPER_ENV_MONARCH:
|
|
name = "na_monarch";
|
|
break;
|
|
case DMPAPER_ENV_PERSONAL:
|
|
name = "na_personal";
|
|
break;
|
|
case DMPAPER_FANFOLD_US:
|
|
name = "na_fanfold-us";
|
|
break;
|
|
case DMPAPER_FANFOLD_STD_GERMAN:
|
|
name = "na_fanfold-eur";
|
|
break;
|
|
case DMPAPER_FANFOLD_LGL_GERMAN:
|
|
name = "na_foolscap";
|
|
break;
|
|
case DMPAPER_ISO_B4:
|
|
name = "iso_b4";
|
|
break;
|
|
case DMPAPER_JAPANESE_POSTCARD:
|
|
name = "jpn_hagaki";
|
|
break;
|
|
case DMPAPER_9X11:
|
|
name = "na_9x11";
|
|
break;
|
|
case DMPAPER_10X11:
|
|
name = "na_10x11";
|
|
break;
|
|
case DMPAPER_ENV_INVITE:
|
|
name = "om_invite";
|
|
break;
|
|
case DMPAPER_LETTER_EXTRA:
|
|
case DMPAPER_LETTER_EXTRA_TRANSVERSE:
|
|
name = "na_letter-extra";
|
|
break;
|
|
case DMPAPER_LEGAL_EXTRA:
|
|
name = "na_legal-extra";
|
|
break;
|
|
case DMPAPER_TABLOID_EXTRA:
|
|
name = "na_arch";
|
|
break;
|
|
case DMPAPER_A4_EXTRA:
|
|
name = "iso_a4-extra";
|
|
break;
|
|
case DMPAPER_B_PLUS:
|
|
name = "na_b-plus";
|
|
break;
|
|
case DMPAPER_LETTER_PLUS:
|
|
name = "na_letter-plus";
|
|
break;
|
|
case DMPAPER_A3_EXTRA:
|
|
case DMPAPER_A3_EXTRA_TRANSVERSE:
|
|
name = "iso_a3-extra";
|
|
break;
|
|
case DMPAPER_A5_EXTRA:
|
|
name = "iso_a5-extra";
|
|
break;
|
|
case DMPAPER_B5_EXTRA:
|
|
name = "iso_b5-extra";
|
|
break;
|
|
case DMPAPER_A2:
|
|
name = "iso_a2";
|
|
break;
|
|
|
|
default:
|
|
name = NULL;
|
|
break;
|
|
}
|
|
|
|
if (name)
|
|
return gtk_paper_size_new (name);
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
static short
|
|
paper_size_to_win32 (GtkPaperSize *paper_size)
|
|
{
|
|
const char *format;
|
|
|
|
if (gtk_paper_size_is_custom (paper_size))
|
|
return 0;
|
|
|
|
format = gtk_paper_size_get_name (paper_size);
|
|
|
|
if (strcmp (format, "na_letter") == 0)
|
|
return DMPAPER_LETTER;
|
|
if (strcmp (format, "na_ledger") == 0)
|
|
return DMPAPER_LEDGER;
|
|
if (strcmp (format, "na_legal") == 0)
|
|
return DMPAPER_LEGAL;
|
|
if (strcmp (format, "na_invoice") == 0)
|
|
return DMPAPER_STATEMENT;
|
|
if (strcmp (format, "na_executive") == 0)
|
|
return DMPAPER_EXECUTIVE;
|
|
if (strcmp (format, "iso_a2") == 0)
|
|
return DMPAPER_A2;
|
|
if (strcmp (format, "iso_a3") == 0)
|
|
return DMPAPER_A3;
|
|
if (strcmp (format, "iso_a4") == 0)
|
|
return DMPAPER_A4;
|
|
if (strcmp (format, "iso_a5") == 0)
|
|
return DMPAPER_A5;
|
|
if (strcmp (format, "iso_b4") == 0)
|
|
return DMPAPER_B4;
|
|
if (strcmp (format, "iso_b5") == 0)
|
|
return DMPAPER_B5;
|
|
if (strcmp (format, "na_quarto") == 0)
|
|
return DMPAPER_QUARTO;
|
|
if (strcmp (format, "na_10x14") == 0)
|
|
return DMPAPER_10X14;
|
|
if (strcmp (format, "na_number-9") == 0)
|
|
return DMPAPER_ENV_9;
|
|
if (strcmp (format, "na_number-10") == 0)
|
|
return DMPAPER_ENV_10;
|
|
if (strcmp (format, "na_number-11") == 0)
|
|
return DMPAPER_ENV_11;
|
|
if (strcmp (format, "na_number-12") == 0)
|
|
return DMPAPER_ENV_12;
|
|
if (strcmp (format, "na_number-14") == 0)
|
|
return DMPAPER_ENV_14;
|
|
if (strcmp (format, "na_c") == 0)
|
|
return DMPAPER_CSHEET;
|
|
if (strcmp (format, "na_d") == 0)
|
|
return DMPAPER_DSHEET;
|
|
if (strcmp (format, "na_e") == 0)
|
|
return DMPAPER_ESHEET;
|
|
if (strcmp (format, "iso_dl") == 0)
|
|
return DMPAPER_ENV_DL;
|
|
if (strcmp (format, "iso_c3") == 0)
|
|
return DMPAPER_ENV_C3;
|
|
if (strcmp (format, "iso_c4") == 0)
|
|
return DMPAPER_ENV_C4;
|
|
if (strcmp (format, "iso_c5") == 0)
|
|
return DMPAPER_ENV_C5;
|
|
if (strcmp (format, "iso_c6") == 0)
|
|
return DMPAPER_ENV_C6;
|
|
if (strcmp (format, "iso_c5c6") == 0)
|
|
return DMPAPER_ENV_C65;
|
|
if (strcmp (format, "iso_b6") == 0)
|
|
return DMPAPER_ENV_B6;
|
|
if (strcmp (format, "om_italian") == 0)
|
|
return DMPAPER_ENV_ITALY;
|
|
if (strcmp (format, "na_monarch") == 0)
|
|
return DMPAPER_ENV_MONARCH;
|
|
if (strcmp (format, "na_personal") == 0)
|
|
return DMPAPER_ENV_PERSONAL;
|
|
if (strcmp (format, "na_fanfold-us") == 0)
|
|
return DMPAPER_FANFOLD_US;
|
|
if (strcmp (format, "na_fanfold-eur") == 0)
|
|
return DMPAPER_FANFOLD_STD_GERMAN;
|
|
if (strcmp (format, "na_foolscap") == 0)
|
|
return DMPAPER_FANFOLD_LGL_GERMAN;
|
|
if (strcmp (format, "jpn_hagaki") == 0)
|
|
return DMPAPER_JAPANESE_POSTCARD;
|
|
if (strcmp (format, "na_9x11") == 0)
|
|
return DMPAPER_9X11;
|
|
if (strcmp (format, "na_10x11") == 0)
|
|
return DMPAPER_10X11;
|
|
if (strcmp (format, "om_invite") == 0)
|
|
return DMPAPER_ENV_INVITE;
|
|
if (strcmp (format, "na_letter-extra") == 0)
|
|
return DMPAPER_LETTER_EXTRA;
|
|
if (strcmp (format, "na_legal-extra") == 0)
|
|
return DMPAPER_LEGAL_EXTRA;
|
|
if (strcmp (format, "na_arch") == 0)
|
|
return DMPAPER_TABLOID_EXTRA;
|
|
if (strcmp (format, "iso_a3-extra") == 0)
|
|
return DMPAPER_A3_EXTRA;
|
|
if (strcmp (format, "iso_a4-extra") == 0)
|
|
return DMPAPER_A4_EXTRA;
|
|
if (strcmp (format, "iso_a5-extra") == 0)
|
|
return DMPAPER_A5_EXTRA;
|
|
if (strcmp (format, "iso_b5-extra") == 0)
|
|
return DMPAPER_B5_EXTRA;
|
|
if (strcmp (format, "na_b-plus") == 0)
|
|
return DMPAPER_B_PLUS;
|
|
if (strcmp (format, "na_letter-plus") == 0)
|
|
return DMPAPER_LETTER_PLUS;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static char *
|
|
get_default_printer (void)
|
|
{
|
|
wchar_t *win32_printer_name = NULL;
|
|
char *printer_name = NULL;
|
|
DWORD needed;
|
|
|
|
GetDefaultPrinterW (NULL, &needed);
|
|
win32_printer_name = g_malloc ((gsize) needed * sizeof (wchar_t));
|
|
if (!GetDefaultPrinterW (win32_printer_name, &needed))
|
|
{
|
|
g_free (win32_printer_name);
|
|
return NULL;
|
|
}
|
|
printer_name = g_utf16_to_utf8 (win32_printer_name, -1, NULL, NULL, NULL);
|
|
g_free (win32_printer_name);
|
|
|
|
return printer_name;
|
|
}
|
|
|
|
static void
|
|
set_hard_margins (GtkPrintOperation *op)
|
|
{
|
|
double top, bottom, left, right;
|
|
GtkPrintOperationWin32 *op_win32 = op->priv->platform_data;
|
|
|
|
top = GetDeviceCaps (op_win32->hdc, PHYSICALOFFSETY);
|
|
bottom = GetDeviceCaps (op_win32->hdc, PHYSICALHEIGHT)
|
|
- GetDeviceCaps (op_win32->hdc, VERTRES) - top;
|
|
left = GetDeviceCaps (op_win32->hdc, PHYSICALOFFSETX);
|
|
right = GetDeviceCaps (op_win32->hdc, PHYSICALWIDTH)
|
|
- GetDeviceCaps (op_win32->hdc, HORZRES) - left;
|
|
|
|
_gtk_print_context_set_hard_margins (op->priv->print_context, top, bottom, left, right);
|
|
}
|
|
|
|
void
|
|
win32_start_page (GtkPrintOperation *op,
|
|
GtkPrintContext *print_context,
|
|
GtkPageSetup *page_setup)
|
|
{
|
|
GtkPrintOperationWin32 *op_win32 = op->priv->platform_data;
|
|
LPDEVMODEW devmode;
|
|
GtkPaperSize *paper_size;
|
|
double x_off, y_off;
|
|
|
|
devmode = GlobalLock (op_win32->devmode);
|
|
|
|
devmode->dmFields |= DM_ORIENTATION;
|
|
devmode->dmOrientation =
|
|
orientation_to_win32 (gtk_page_setup_get_orientation (page_setup));
|
|
|
|
paper_size = gtk_page_setup_get_paper_size (page_setup);
|
|
devmode->dmFields |= DM_PAPERSIZE;
|
|
devmode->dmFields &= ~(DM_PAPERWIDTH | DM_PAPERLENGTH);
|
|
devmode->dmPaperSize = paper_size_to_win32 (paper_size);
|
|
if (devmode->dmPaperSize == 0)
|
|
{
|
|
devmode->dmPaperSize = DMPAPER_USER;
|
|
devmode->dmFields |= DM_PAPERWIDTH | DM_PAPERLENGTH;
|
|
|
|
/* Lengths in DEVMODE are in tenths of a millimeter */
|
|
devmode->dmPaperWidth = gtk_paper_size_get_width (paper_size, GTK_UNIT_MM) * 10.0;
|
|
devmode->dmPaperLength = gtk_paper_size_get_height (paper_size, GTK_UNIT_MM) * 10.0;
|
|
}
|
|
|
|
ResetDCW (op_win32->hdc, devmode);
|
|
|
|
GlobalUnlock (op_win32->devmode);
|
|
|
|
set_hard_margins (op);
|
|
x_off = GetDeviceCaps (op_win32->hdc, PHYSICALOFFSETX);
|
|
y_off = GetDeviceCaps (op_win32->hdc, PHYSICALOFFSETY);
|
|
cairo_surface_set_device_offset (op_win32->surface, -x_off, -y_off);
|
|
|
|
StartPage (op_win32->hdc);
|
|
}
|
|
|
|
static void
|
|
win32_end_page (GtkPrintOperation *op,
|
|
GtkPrintContext *print_context)
|
|
{
|
|
GtkPrintOperationWin32 *op_win32 = op->priv->platform_data;
|
|
|
|
cairo_surface_show_page (op_win32->surface);
|
|
|
|
EndPage (op_win32->hdc);
|
|
}
|
|
|
|
static gboolean
|
|
win32_poll_status_timeout (GtkPrintOperation *op)
|
|
{
|
|
GtkPrintOperationWin32 *op_win32 = op->priv->platform_data;
|
|
|
|
op_win32->timeout_id = 0;
|
|
/* We need to ref this, as setting the status to finished
|
|
might unref the object */
|
|
g_object_ref (op);
|
|
win32_poll_status (op);
|
|
|
|
if (!gtk_print_operation_is_finished (op)) {
|
|
op_win32->timeout_id = g_timeout_add (STATUS_POLLING_TIME,
|
|
(GSourceFunc)win32_poll_status_timeout,
|
|
op);
|
|
gdk_source_set_static_name_by_id (op_win32->timeout_id, "[gtk] win32_poll_status_timeout");
|
|
}
|
|
g_object_unref (op);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
static void
|
|
win32_end_run (GtkPrintOperation *op,
|
|
gboolean wait,
|
|
gboolean cancelled)
|
|
{
|
|
GtkPrintOperationWin32 *op_win32 = op->priv->platform_data;
|
|
LPDEVNAMES devnames;
|
|
HANDLE printerHandle = 0;
|
|
|
|
cairo_surface_finish (op_win32->surface);
|
|
|
|
EndDoc (op_win32->hdc);
|
|
|
|
if (op->priv->track_print_status)
|
|
{
|
|
devnames = GlobalLock (op_win32->devnames);
|
|
if (!OpenPrinterW (((gunichar2 *)devnames) + devnames->wDeviceOffset,
|
|
&printerHandle, NULL))
|
|
printerHandle = 0;
|
|
GlobalUnlock (op_win32->devnames);
|
|
}
|
|
|
|
GlobalFree (op_win32->devmode);
|
|
GlobalFree (op_win32->devnames);
|
|
|
|
cairo_surface_destroy (op_win32->surface);
|
|
op_win32->surface = NULL;
|
|
|
|
DeleteDC (op_win32->hdc);
|
|
|
|
if (printerHandle != 0)
|
|
{
|
|
op_win32->printerHandle = printerHandle;
|
|
win32_poll_status (op);
|
|
op_win32->timeout_id = g_timeout_add (STATUS_POLLING_TIME,
|
|
(GSourceFunc)win32_poll_status_timeout,
|
|
op);
|
|
gdk_source_set_static_name_by_id (op_win32->timeout_id, "[gtk] win32_poll_status_timeout");
|
|
}
|
|
else
|
|
/* Dunno what happened, pretend its finished */
|
|
_gtk_print_operation_set_status (op, GTK_PRINT_STATUS_FINISHED, NULL);
|
|
}
|
|
|
|
static void
|
|
win32_poll_status (GtkPrintOperation *op)
|
|
{
|
|
GtkPrintOperationWin32 *op_win32 = op->priv->platform_data;
|
|
guchar *data;
|
|
DWORD needed;
|
|
JOB_INFO_1W *job_info;
|
|
GtkPrintStatus status;
|
|
char *status_str;
|
|
BOOL ret;
|
|
|
|
GetJobW (op_win32->printerHandle, op_win32->job_id,
|
|
1,(LPBYTE)NULL, 0, &needed);
|
|
data = g_malloc (needed);
|
|
ret = GetJobW (op_win32->printerHandle, op_win32->job_id,
|
|
1, (LPBYTE)data, needed, &needed);
|
|
|
|
status_str = NULL;
|
|
if (ret)
|
|
{
|
|
DWORD win32_status;
|
|
job_info = (JOB_INFO_1W *)data;
|
|
win32_status = job_info->Status;
|
|
|
|
if (job_info->pStatus)
|
|
status_str = g_utf16_to_utf8 (job_info->pStatus,
|
|
-1, NULL, NULL, NULL);
|
|
|
|
if (win32_status &
|
|
(JOB_STATUS_COMPLETE | JOB_STATUS_PRINTED))
|
|
status = GTK_PRINT_STATUS_FINISHED;
|
|
else if (win32_status &
|
|
(JOB_STATUS_OFFLINE |
|
|
JOB_STATUS_PAPEROUT |
|
|
JOB_STATUS_PAUSED |
|
|
JOB_STATUS_USER_INTERVENTION))
|
|
{
|
|
status = GTK_PRINT_STATUS_PENDING_ISSUE;
|
|
if (status_str == NULL)
|
|
{
|
|
if (win32_status & JOB_STATUS_OFFLINE)
|
|
status_str = g_strdup (_("Printer offline"));
|
|
else if (win32_status & JOB_STATUS_PAPEROUT)
|
|
status_str = g_strdup (_("Out of paper"));
|
|
else if (win32_status & JOB_STATUS_PAUSED)
|
|
status_str = g_strdup (_("Paused"));
|
|
else if (win32_status & JOB_STATUS_USER_INTERVENTION)
|
|
status_str = g_strdup (_("Need user intervention"));
|
|
}
|
|
}
|
|
else if (win32_status &
|
|
(JOB_STATUS_BLOCKED_DEVQ |
|
|
JOB_STATUS_DELETED |
|
|
JOB_STATUS_ERROR))
|
|
status = GTK_PRINT_STATUS_FINISHED_ABORTED;
|
|
else if (win32_status &
|
|
(JOB_STATUS_SPOOLING |
|
|
JOB_STATUS_DELETING))
|
|
status = GTK_PRINT_STATUS_PENDING;
|
|
else if (win32_status & JOB_STATUS_PRINTING)
|
|
status = GTK_PRINT_STATUS_PRINTING;
|
|
else
|
|
status = GTK_PRINT_STATUS_FINISHED;
|
|
}
|
|
else
|
|
status = GTK_PRINT_STATUS_FINISHED;
|
|
|
|
g_free (data);
|
|
|
|
_gtk_print_operation_set_status (op, status, status_str);
|
|
|
|
g_free (status_str);
|
|
}
|
|
|
|
static void
|
|
op_win32_free (GtkPrintOperationWin32 *op_win32)
|
|
{
|
|
if (op_win32->printerHandle)
|
|
ClosePrinter (op_win32->printerHandle);
|
|
if (op_win32->timeout_id != 0)
|
|
g_source_remove (op_win32->timeout_id);
|
|
g_free (op_win32);
|
|
}
|
|
|
|
static HWND
|
|
get_parent_hwnd (GtkWidget *widget)
|
|
{
|
|
GtkNative *native;
|
|
|
|
native = gtk_widget_get_native (widget);
|
|
gtk_widget_realize (GTK_WIDGET (native));
|
|
return gdk_win32_surface_get_handle (gtk_native_get_surface (native));
|
|
}
|
|
|
|
static void
|
|
devnames_to_settings (GtkPrintSettings *settings,
|
|
HANDLE hDevNames)
|
|
{
|
|
GtkPrintWin32Devnames *devnames = gtk_print_win32_devnames_from_win32 (hDevNames);
|
|
gtk_print_settings_set_printer (settings, devnames->device);
|
|
gtk_print_win32_devnames_free (devnames);
|
|
}
|
|
|
|
static void
|
|
devmode_to_settings (GtkPrintSettings *settings,
|
|
HANDLE hDevMode)
|
|
{
|
|
LPDEVMODEW devmode;
|
|
|
|
devmode = GlobalLock (hDevMode);
|
|
|
|
gtk_print_settings_set_int (settings, GTK_PRINT_SETTINGS_WIN32_DRIVER_VERSION,
|
|
devmode->dmDriverVersion);
|
|
if (devmode->dmDriverExtra != 0)
|
|
{
|
|
char *extra = g_base64_encode (((const guchar *)devmode) + sizeof (DEVMODEW),
|
|
devmode->dmDriverExtra);
|
|
gtk_print_settings_set (settings,
|
|
GTK_PRINT_SETTINGS_WIN32_DRIVER_EXTRA,
|
|
extra);
|
|
g_free (extra);
|
|
}
|
|
|
|
char *devmode_name = g_utf16_to_utf8 (devmode->dmDeviceName, -1, NULL, NULL, NULL);
|
|
gtk_print_settings_set (settings, "win32-devmode-name", devmode_name);
|
|
g_free (devmode_name);
|
|
|
|
if (devmode->dmFields & DM_ORIENTATION)
|
|
gtk_print_settings_set_orientation (settings,
|
|
orientation_from_win32 (devmode->dmOrientation));
|
|
|
|
|
|
if (devmode->dmFields & DM_PAPERSIZE &&
|
|
devmode->dmPaperSize != 0)
|
|
{
|
|
GtkPaperSize *paper_size = paper_size_from_win32 (devmode->dmPaperSize);
|
|
if (paper_size)
|
|
{
|
|
gtk_print_settings_set_paper_size (settings, paper_size);
|
|
gtk_paper_size_free (paper_size);
|
|
}
|
|
gtk_print_settings_set_int (settings, "win32-paper-size", (int)devmode->dmPaperSize);
|
|
}
|
|
else if ((devmode->dmFields & DM_PAPERSIZE &&
|
|
devmode->dmPaperSize == 0) ||
|
|
((devmode->dmFields & DM_PAPERWIDTH) &&
|
|
(devmode->dmFields & DM_PAPERLENGTH)))
|
|
{
|
|
GtkPaperSize *paper_size;
|
|
char *form_name = NULL;
|
|
if (devmode->dmFields & DM_FORMNAME)
|
|
form_name = g_utf16_to_utf8 (devmode->dmFormName,
|
|
-1, NULL, NULL, NULL);
|
|
if (form_name == NULL || form_name[0] == 0)
|
|
form_name = g_strdup (_("Custom size"));
|
|
|
|
/* Lengths in DEVMODE are in tenths of a millimeter */
|
|
paper_size = gtk_paper_size_new_custom (form_name,
|
|
form_name,
|
|
devmode->dmPaperWidth / 10.0,
|
|
devmode->dmPaperLength / 10.0,
|
|
GTK_UNIT_MM);
|
|
gtk_print_settings_set_paper_size (settings, paper_size);
|
|
gtk_paper_size_free (paper_size);
|
|
}
|
|
|
|
if (devmode->dmFields & DM_SCALE)
|
|
gtk_print_settings_set_scale (settings, devmode->dmScale);
|
|
|
|
if (devmode->dmFields & DM_COPIES)
|
|
gtk_print_settings_set_n_copies (settings,
|
|
devmode->dmCopies);
|
|
|
|
if (devmode->dmFields & DM_DEFAULTSOURCE)
|
|
{
|
|
const char *source;
|
|
switch (devmode->dmDefaultSource)
|
|
{
|
|
default:
|
|
case DMBIN_AUTO:
|
|
source = "auto";
|
|
break;
|
|
case DMBIN_CASSETTE:
|
|
source = "cassette";
|
|
break;
|
|
case DMBIN_ENVELOPE:
|
|
source = "envelope";
|
|
break;
|
|
case DMBIN_ENVMANUAL:
|
|
source = "envelope-manual";
|
|
break;
|
|
case DMBIN_LOWER:
|
|
source = "lower";
|
|
break;
|
|
case DMBIN_MANUAL:
|
|
source = "manual";
|
|
break;
|
|
case DMBIN_MIDDLE:
|
|
source = "middle";
|
|
break;
|
|
case DMBIN_ONLYONE:
|
|
source = "only-one";
|
|
break;
|
|
case DMBIN_FORMSOURCE:
|
|
source = "form-source";
|
|
break;
|
|
case DMBIN_LARGECAPACITY:
|
|
source = "large-capacity";
|
|
break;
|
|
case DMBIN_LARGEFMT:
|
|
source = "large-format";
|
|
break;
|
|
case DMBIN_TRACTOR:
|
|
source = "tractor";
|
|
break;
|
|
case DMBIN_SMALLFMT:
|
|
source = "small-format";
|
|
break;
|
|
}
|
|
gtk_print_settings_set_default_source (settings, source);
|
|
gtk_print_settings_set_int (settings, "win32-default-source", devmode->dmDefaultSource);
|
|
}
|
|
|
|
if (devmode->dmFields & DM_PRINTQUALITY)
|
|
{
|
|
GtkPrintQuality quality;
|
|
switch (devmode->dmPrintQuality)
|
|
{
|
|
case DMRES_LOW:
|
|
quality = GTK_PRINT_QUALITY_LOW;
|
|
break;
|
|
case DMRES_MEDIUM:
|
|
quality = GTK_PRINT_QUALITY_NORMAL;
|
|
break;
|
|
default:
|
|
case DMRES_HIGH:
|
|
quality = GTK_PRINT_QUALITY_HIGH;
|
|
break;
|
|
case DMRES_DRAFT:
|
|
quality = GTK_PRINT_QUALITY_DRAFT;
|
|
break;
|
|
}
|
|
gtk_print_settings_set_quality (settings, quality);
|
|
gtk_print_settings_set_int (settings, "win32-print-quality", devmode->dmPrintQuality);
|
|
}
|
|
|
|
if (devmode->dmFields & DM_COLOR)
|
|
gtk_print_settings_set_use_color (settings, devmode->dmColor == DMCOLOR_COLOR);
|
|
|
|
if (devmode->dmFields & DM_DUPLEX)
|
|
{
|
|
GtkPrintDuplex duplex;
|
|
switch (devmode->dmDuplex)
|
|
{
|
|
default:
|
|
case DMDUP_SIMPLEX:
|
|
duplex = GTK_PRINT_DUPLEX_SIMPLEX;
|
|
break;
|
|
case DMDUP_HORIZONTAL:
|
|
duplex = GTK_PRINT_DUPLEX_HORIZONTAL;
|
|
break;
|
|
case DMDUP_VERTICAL:
|
|
duplex = GTK_PRINT_DUPLEX_VERTICAL;
|
|
break;
|
|
}
|
|
|
|
gtk_print_settings_set_duplex (settings, duplex);
|
|
}
|
|
|
|
if (devmode->dmFields & DM_COLLATE)
|
|
gtk_print_settings_set_collate (settings,
|
|
devmode->dmCollate == DMCOLLATE_TRUE);
|
|
|
|
if (devmode->dmFields & DM_MEDIATYPE)
|
|
{
|
|
const char *media_type;
|
|
switch (devmode->dmMediaType)
|
|
{
|
|
default:
|
|
case DMMEDIA_STANDARD:
|
|
media_type = "stationery";
|
|
break;
|
|
case DMMEDIA_TRANSPARENCY:
|
|
media_type = "transparency";
|
|
break;
|
|
case DMMEDIA_GLOSSY:
|
|
media_type = "photographic-glossy";
|
|
break;
|
|
}
|
|
gtk_print_settings_set_media_type (settings, media_type);
|
|
gtk_print_settings_set_int (settings, "win32-media-type", devmode->dmMediaType);
|
|
}
|
|
|
|
if (devmode->dmFields & DM_DITHERTYPE)
|
|
{
|
|
const char *dither;
|
|
switch (devmode->dmDitherType)
|
|
{
|
|
default:
|
|
case DMDITHER_FINE:
|
|
dither = "fine";
|
|
break;
|
|
case DMDITHER_NONE:
|
|
dither = "none";
|
|
break;
|
|
case DMDITHER_COARSE:
|
|
dither = "coarse";
|
|
break;
|
|
case DMDITHER_LINEART:
|
|
dither = "lineart";
|
|
break;
|
|
case DMDITHER_GRAYSCALE:
|
|
dither = "grayscale";
|
|
break;
|
|
case DMDITHER_ERRORDIFFUSION:
|
|
dither = "error-diffusion";
|
|
break;
|
|
}
|
|
gtk_print_settings_set_dither (settings, dither);
|
|
gtk_print_settings_set_int (settings, "win32-dither-type", devmode->dmDitherType);
|
|
}
|
|
|
|
GlobalUnlock (hDevMode);
|
|
}
|
|
|
|
static void
|
|
dialog_to_print_settings (GtkPrintOperation *op,
|
|
LPPRINTDLGEXW printdlgex)
|
|
{
|
|
guint i;
|
|
GtkPrintSettings *settings;
|
|
|
|
settings = gtk_print_settings_new ();
|
|
|
|
gtk_print_settings_set_print_pages (settings,
|
|
GTK_PRINT_PAGES_ALL);
|
|
if (printdlgex->Flags & PD_CURRENTPAGE)
|
|
gtk_print_settings_set_print_pages (settings,
|
|
GTK_PRINT_PAGES_CURRENT);
|
|
else if (printdlgex->Flags & PD_PAGENUMS)
|
|
gtk_print_settings_set_print_pages (settings,
|
|
GTK_PRINT_PAGES_RANGES);
|
|
|
|
if (printdlgex->nPageRanges > 0)
|
|
{
|
|
GtkPageRange *ranges;
|
|
ranges = g_new (GtkPageRange, printdlgex->nPageRanges);
|
|
|
|
for (i = 0; i < printdlgex->nPageRanges; i++)
|
|
{
|
|
ranges[i].start = printdlgex->lpPageRanges[i].nFromPage - 1;
|
|
ranges[i].end = printdlgex->lpPageRanges[i].nToPage - 1;
|
|
}
|
|
|
|
gtk_print_settings_set_page_ranges (settings, ranges,
|
|
printdlgex->nPageRanges);
|
|
g_free (ranges);
|
|
}
|
|
|
|
if (printdlgex->hDevNames != NULL)
|
|
devnames_to_settings (settings, printdlgex->hDevNames);
|
|
|
|
if (printdlgex->hDevMode != NULL)
|
|
devmode_to_settings (settings, printdlgex->hDevMode);
|
|
|
|
gtk_print_operation_set_print_settings (op, settings);
|
|
}
|
|
|
|
static HANDLE
|
|
devmode_from_settings (GtkPrintSettings *settings,
|
|
GtkPageSetup *page_setup,
|
|
HANDLE hDevModeParam)
|
|
{
|
|
HANDLE hDevMode = hDevModeParam;
|
|
LPDEVMODEW devmode;
|
|
guchar *extras;
|
|
GtkPaperSize *paper_size;
|
|
const char *extras_base64;
|
|
gsize extras_len;
|
|
const char *val;
|
|
|
|
/* If we already provided a valid hDevMode, don't initialize a new one; just lock the one we have */
|
|
if (hDevMode)
|
|
{
|
|
devmode = GlobalLock (hDevMode);
|
|
}
|
|
else
|
|
{
|
|
extras = NULL;
|
|
extras_len = 0;
|
|
extras_base64 = gtk_print_settings_get (settings, GTK_PRINT_SETTINGS_WIN32_DRIVER_EXTRA);
|
|
if (extras_base64)
|
|
extras = g_base64_decode (extras_base64, &extras_len);
|
|
|
|
hDevMode = GlobalAlloc (GMEM_MOVEABLE,
|
|
sizeof (DEVMODEW) + extras_len);
|
|
|
|
devmode = GlobalLock (hDevMode);
|
|
|
|
memset (devmode, 0, sizeof (DEVMODEW));
|
|
|
|
devmode->dmSpecVersion = DM_SPECVERSION;
|
|
devmode->dmSize = sizeof (DEVMODEW);
|
|
|
|
gunichar2 *device_name = g_utf8_to_utf16 (gtk_print_settings_get (settings, "win32-devmode-name"), -1, NULL, NULL, NULL);
|
|
memcpy (devmode->dmDeviceName, device_name, CCHDEVICENAME);
|
|
g_free (device_name);
|
|
|
|
|
|
devmode->dmDriverExtra = 0;
|
|
if (extras && extras_len > 0)
|
|
{
|
|
devmode->dmDriverExtra = extras_len;
|
|
memcpy (((char *)devmode) + sizeof (DEVMODEW), extras, extras_len);
|
|
}
|
|
g_free (extras);
|
|
|
|
if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_WIN32_DRIVER_VERSION))
|
|
{
|
|
devmode->dmDriverVersion = gtk_print_settings_get_int (settings, GTK_PRINT_SETTINGS_WIN32_DRIVER_VERSION);
|
|
}
|
|
}
|
|
|
|
if (page_setup ||
|
|
gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_ORIENTATION))
|
|
{
|
|
GtkPageOrientation orientation = gtk_print_settings_get_orientation (settings);
|
|
if (page_setup)
|
|
orientation = gtk_page_setup_get_orientation (page_setup);
|
|
devmode->dmFields |= DM_ORIENTATION;
|
|
devmode->dmOrientation = orientation_to_win32 (orientation);
|
|
}
|
|
|
|
if (page_setup)
|
|
paper_size = gtk_paper_size_copy (gtk_page_setup_get_paper_size (page_setup));
|
|
else
|
|
{
|
|
int size;
|
|
if (gtk_print_settings_has_key (settings, "win32-paper-size") &&
|
|
(size = gtk_print_settings_get_int (settings, "win32-paper-size")) != 0)
|
|
{
|
|
devmode->dmFields |= DM_PAPERSIZE;
|
|
devmode->dmPaperSize = size;
|
|
paper_size = NULL;
|
|
}
|
|
else
|
|
paper_size = gtk_print_settings_get_paper_size (settings);
|
|
}
|
|
if (paper_size)
|
|
{
|
|
devmode->dmFields |= DM_PAPERSIZE;
|
|
devmode->dmPaperSize = paper_size_to_win32 (paper_size);
|
|
if (devmode->dmPaperSize == 0)
|
|
{
|
|
devmode->dmPaperSize = DMPAPER_USER;
|
|
devmode->dmFields |= DM_PAPERWIDTH | DM_PAPERLENGTH;
|
|
|
|
/* Lengths in DEVMODE are in tenths of a millimeter */
|
|
devmode->dmPaperWidth = gtk_paper_size_get_width (paper_size, GTK_UNIT_MM) * 10.0;
|
|
devmode->dmPaperLength = gtk_paper_size_get_height (paper_size, GTK_UNIT_MM) * 10.0;
|
|
}
|
|
gtk_paper_size_free (paper_size);
|
|
}
|
|
|
|
if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_SCALE))
|
|
{
|
|
devmode->dmFields |= DM_SCALE;
|
|
devmode->dmScale = gtk_print_settings_get_scale (settings);
|
|
}
|
|
|
|
if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_N_COPIES))
|
|
{
|
|
devmode->dmFields |= DM_COPIES;
|
|
devmode->dmCopies = gtk_print_settings_get_n_copies (settings);
|
|
}
|
|
|
|
if (gtk_print_settings_has_key (settings, "win32-default-source"))
|
|
{
|
|
devmode->dmFields |= DM_DEFAULTSOURCE;
|
|
devmode->dmDefaultSource = gtk_print_settings_get_int (settings, "win32-default-source");
|
|
}
|
|
else if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_DEFAULT_SOURCE))
|
|
{
|
|
devmode->dmFields |= DM_DEFAULTSOURCE;
|
|
devmode->dmDefaultSource = DMBIN_AUTO;
|
|
|
|
val = gtk_print_settings_get_default_source (settings);
|
|
if (strcmp (val, "auto") == 0)
|
|
devmode->dmDefaultSource = DMBIN_AUTO;
|
|
if (strcmp (val, "cassette") == 0)
|
|
devmode->dmDefaultSource = DMBIN_CASSETTE;
|
|
if (strcmp (val, "envelope") == 0)
|
|
devmode->dmDefaultSource = DMBIN_ENVELOPE;
|
|
if (strcmp (val, "envelope-manual") == 0)
|
|
devmode->dmDefaultSource = DMBIN_ENVMANUAL;
|
|
if (strcmp (val, "lower") == 0)
|
|
devmode->dmDefaultSource = DMBIN_LOWER;
|
|
if (strcmp (val, "manual") == 0)
|
|
devmode->dmDefaultSource = DMBIN_MANUAL;
|
|
if (strcmp (val, "middle") == 0)
|
|
devmode->dmDefaultSource = DMBIN_MIDDLE;
|
|
if (strcmp (val, "only-one") == 0)
|
|
devmode->dmDefaultSource = DMBIN_ONLYONE;
|
|
if (strcmp (val, "form-source") == 0)
|
|
devmode->dmDefaultSource = DMBIN_FORMSOURCE;
|
|
if (strcmp (val, "large-capacity") == 0)
|
|
devmode->dmDefaultSource = DMBIN_LARGECAPACITY;
|
|
if (strcmp (val, "large-format") == 0)
|
|
devmode->dmDefaultSource = DMBIN_LARGEFMT;
|
|
if (strcmp (val, "tractor") == 0)
|
|
devmode->dmDefaultSource = DMBIN_TRACTOR;
|
|
if (strcmp (val, "small-format") == 0)
|
|
devmode->dmDefaultSource = DMBIN_SMALLFMT;
|
|
}
|
|
|
|
if (gtk_print_settings_has_key (settings, "win32-print-quality"))
|
|
{
|
|
devmode->dmFields |= DM_PRINTQUALITY;
|
|
devmode->dmPrintQuality = gtk_print_settings_get_int (settings, "win32-print-quality");
|
|
}
|
|
else if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_RESOLUTION))
|
|
{
|
|
devmode->dmFields |= DM_PRINTQUALITY;
|
|
devmode->dmPrintQuality = gtk_print_settings_get_resolution (settings);
|
|
}
|
|
else if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_QUALITY))
|
|
{
|
|
devmode->dmFields |= DM_PRINTQUALITY;
|
|
switch (gtk_print_settings_get_quality (settings))
|
|
{
|
|
case GTK_PRINT_QUALITY_LOW:
|
|
devmode->dmPrintQuality = DMRES_LOW;
|
|
break;
|
|
case GTK_PRINT_QUALITY_DRAFT:
|
|
devmode->dmPrintQuality = DMRES_DRAFT;
|
|
break;
|
|
default:
|
|
case GTK_PRINT_QUALITY_NORMAL:
|
|
devmode->dmPrintQuality = DMRES_MEDIUM;
|
|
break;
|
|
case GTK_PRINT_QUALITY_HIGH:
|
|
devmode->dmPrintQuality = DMRES_HIGH;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_USE_COLOR))
|
|
{
|
|
devmode->dmFields |= DM_COLOR;
|
|
if (gtk_print_settings_get_use_color (settings))
|
|
devmode->dmColor = DMCOLOR_COLOR;
|
|
else
|
|
devmode->dmColor = DMCOLOR_MONOCHROME;
|
|
}
|
|
|
|
if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_DUPLEX))
|
|
{
|
|
devmode->dmFields |= DM_DUPLEX;
|
|
switch (gtk_print_settings_get_duplex (settings))
|
|
{
|
|
default:
|
|
case GTK_PRINT_DUPLEX_SIMPLEX:
|
|
devmode->dmDuplex = DMDUP_SIMPLEX;
|
|
break;
|
|
case GTK_PRINT_DUPLEX_HORIZONTAL:
|
|
devmode->dmDuplex = DMDUP_HORIZONTAL;
|
|
break;
|
|
case GTK_PRINT_DUPLEX_VERTICAL:
|
|
devmode->dmDuplex = DMDUP_VERTICAL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_COLLATE))
|
|
{
|
|
devmode->dmFields |= DM_COLLATE;
|
|
if (gtk_print_settings_get_collate (settings))
|
|
devmode->dmCollate = DMCOLLATE_TRUE;
|
|
else
|
|
devmode->dmCollate = DMCOLLATE_FALSE;
|
|
}
|
|
|
|
if (gtk_print_settings_has_key (settings, "win32-media-type"))
|
|
{
|
|
devmode->dmFields |= DM_MEDIATYPE;
|
|
devmode->dmMediaType = gtk_print_settings_get_int (settings, "win32-media-type");
|
|
}
|
|
else if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_MEDIA_TYPE))
|
|
{
|
|
devmode->dmFields |= DM_MEDIATYPE;
|
|
devmode->dmMediaType = DMMEDIA_STANDARD;
|
|
|
|
val = gtk_print_settings_get_media_type (settings);
|
|
if (strcmp (val, "transparency") == 0)
|
|
devmode->dmMediaType = DMMEDIA_TRANSPARENCY;
|
|
if (strcmp (val, "photographic-glossy") == 0)
|
|
devmode->dmMediaType = DMMEDIA_GLOSSY;
|
|
}
|
|
|
|
if (gtk_print_settings_has_key (settings, "win32-dither-type"))
|
|
{
|
|
devmode->dmFields |= DM_DITHERTYPE;
|
|
devmode->dmDitherType = gtk_print_settings_get_int (settings, "win32-dither-type");
|
|
}
|
|
else if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_DITHER))
|
|
{
|
|
devmode->dmFields |= DM_DITHERTYPE;
|
|
devmode->dmDitherType = DMDITHER_FINE;
|
|
|
|
val = gtk_print_settings_get_dither (settings);
|
|
if (strcmp (val, "none") == 0)
|
|
devmode->dmDitherType = DMDITHER_NONE;
|
|
if (strcmp (val, "coarse") == 0)
|
|
devmode->dmDitherType = DMDITHER_COARSE;
|
|
if (strcmp (val, "fine") == 0)
|
|
devmode->dmDitherType = DMDITHER_FINE;
|
|
if (strcmp (val, "lineart") == 0)
|
|
devmode->dmDitherType = DMDITHER_LINEART;
|
|
if (strcmp (val, "grayscale") == 0)
|
|
devmode->dmDitherType = DMDITHER_GRAYSCALE;
|
|
if (strcmp (val, "error-diffusion") == 0)
|
|
devmode->dmDitherType = DMDITHER_ERRORDIFFUSION;
|
|
}
|
|
|
|
GlobalUnlock (hDevMode);
|
|
|
|
return hDevMode;
|
|
}
|
|
|
|
static void
|
|
dialog_from_print_settings (GtkPrintOperation *op,
|
|
LPPRINTDLGEXW printdlgex)
|
|
{
|
|
GtkPrintSettings *settings = op->priv->print_settings;
|
|
const char *printer;
|
|
|
|
if (settings == NULL)
|
|
return;
|
|
|
|
if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_PRINT_PAGES))
|
|
{
|
|
GtkPrintPages print_pages = gtk_print_settings_get_print_pages (settings);
|
|
|
|
switch (print_pages)
|
|
{
|
|
default:
|
|
case GTK_PRINT_PAGES_SELECTION:
|
|
case GTK_PRINT_PAGES_ALL:
|
|
printdlgex->Flags |= PD_ALLPAGES;
|
|
break;
|
|
case GTK_PRINT_PAGES_CURRENT:
|
|
printdlgex->Flags |= PD_CURRENTPAGE;
|
|
break;
|
|
case GTK_PRINT_PAGES_RANGES:
|
|
printdlgex->Flags |= PD_PAGENUMS;
|
|
break;
|
|
}
|
|
}
|
|
if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_PAGE_RANGES))
|
|
{
|
|
GtkPageRange *ranges;
|
|
int num_ranges, i;
|
|
|
|
ranges = gtk_print_settings_get_page_ranges (settings, &num_ranges);
|
|
|
|
if (num_ranges > MAX_PAGE_RANGES)
|
|
num_ranges = MAX_PAGE_RANGES;
|
|
|
|
printdlgex->nPageRanges = num_ranges;
|
|
for (i = 0; i < num_ranges; i++)
|
|
{
|
|
printdlgex->lpPageRanges[i].nFromPage = ranges[i].start + 1;
|
|
printdlgex->lpPageRanges[i].nToPage = ranges[i].end + 1;
|
|
}
|
|
}
|
|
|
|
/* If we have a printer saved, restore our settings */
|
|
printer = gtk_print_settings_get_printer (settings);
|
|
if (printer)
|
|
{
|
|
printdlgex->hDevNames = gtk_print_win32_devnames_to_win32_from_printer_name (printer);
|
|
|
|
printdlgex->hDevMode = devmode_from_settings (settings,
|
|
op->priv->default_page_setup, NULL);
|
|
}
|
|
else
|
|
{
|
|
/* Otherwise, use the default settings */
|
|
DWORD FlagsCopy = printdlgex->Flags;
|
|
printdlgex->Flags |= PD_RETURNDEFAULT;
|
|
PrintDlgExW (printdlgex);
|
|
printdlgex->Flags = FlagsCopy;
|
|
|
|
devmode_from_settings (settings, op->priv->default_page_setup, printdlgex->hDevMode);
|
|
}
|
|
}
|
|
|
|
typedef struct {
|
|
IPrintDialogCallback iPrintDialogCallback;
|
|
gboolean set_hwnd;
|
|
int ref_count;
|
|
} PrintDialogCallback;
|
|
|
|
|
|
static ULONG STDMETHODCALLTYPE
|
|
iprintdialogcallback_addref (IPrintDialogCallback *This)
|
|
{
|
|
PrintDialogCallback *callback = (PrintDialogCallback *)This;
|
|
return ++callback->ref_count;
|
|
}
|
|
|
|
static ULONG STDMETHODCALLTYPE
|
|
iprintdialogcallback_release (IPrintDialogCallback *This)
|
|
{
|
|
PrintDialogCallback *callback = (PrintDialogCallback *)This;
|
|
int ref_count = --callback->ref_count;
|
|
|
|
if (ref_count == 0)
|
|
g_free (This);
|
|
|
|
return ref_count;
|
|
}
|
|
|
|
static HRESULT STDMETHODCALLTYPE
|
|
iprintdialogcallback_queryinterface (IPrintDialogCallback *This,
|
|
REFIID riid,
|
|
LPVOID *ppvObject)
|
|
{
|
|
if (IsEqualIID (riid, &IID_IUnknown) ||
|
|
IsEqualIID (riid, &myIID_IPrintDialogCallback))
|
|
{
|
|
*ppvObject = This;
|
|
IUnknown_AddRef ((IUnknown *)This);
|
|
return NOERROR;
|
|
}
|
|
else
|
|
{
|
|
*ppvObject = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
}
|
|
|
|
static HRESULT STDMETHODCALLTYPE
|
|
iprintdialogcallback_initdone (IPrintDialogCallback *This)
|
|
{
|
|
return S_FALSE;
|
|
}
|
|
|
|
static HRESULT STDMETHODCALLTYPE
|
|
iprintdialogcallback_selectionchange (IPrintDialogCallback *This)
|
|
{
|
|
return S_FALSE;
|
|
}
|
|
|
|
static HRESULT STDMETHODCALLTYPE
|
|
iprintdialogcallback_handlemessage (IPrintDialogCallback *This,
|
|
HWND hDlg,
|
|
UINT uMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam,
|
|
LRESULT *pResult)
|
|
{
|
|
PrintDialogCallback *callback = (PrintDialogCallback *)This;
|
|
|
|
if (!callback->set_hwnd)
|
|
{
|
|
gdk_win32_set_modal_dialog_libgtk_only (hDlg);
|
|
callback->set_hwnd = TRUE;
|
|
while (g_main_context_pending (NULL))
|
|
g_main_context_iteration (NULL, TRUE);
|
|
}
|
|
else if (uMsg == got_gdk_events_message)
|
|
{
|
|
while (g_main_context_pending (NULL))
|
|
g_main_context_iteration (NULL, TRUE);
|
|
*pResult = TRUE;
|
|
return S_OK;
|
|
}
|
|
|
|
*pResult = 0;
|
|
return S_FALSE;
|
|
}
|
|
|
|
static IPrintDialogCallbackVtbl ipdc_vtbl = {
|
|
iprintdialogcallback_queryinterface,
|
|
iprintdialogcallback_addref,
|
|
iprintdialogcallback_release,
|
|
iprintdialogcallback_initdone,
|
|
iprintdialogcallback_selectionchange,
|
|
iprintdialogcallback_handlemessage
|
|
};
|
|
|
|
static IPrintDialogCallback *
|
|
print_callback_new (void)
|
|
{
|
|
PrintDialogCallback *callback;
|
|
|
|
callback = g_new0 (PrintDialogCallback, 1);
|
|
callback->iPrintDialogCallback.lpVtbl = &ipdc_vtbl;
|
|
callback->ref_count = 1;
|
|
callback->set_hwnd = FALSE;
|
|
|
|
return &callback->iPrintDialogCallback;
|
|
}
|
|
|
|
static INT_PTR CALLBACK
|
|
pageDlgProc (HWND wnd, UINT message, WPARAM wparam, LPARAM lparam)
|
|
{
|
|
GtkPrintOperation *op;
|
|
GtkPrintOperationWin32 *op_win32;
|
|
|
|
if (message == WM_INITDIALOG)
|
|
{
|
|
PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lparam;
|
|
GtkWidget *plug;
|
|
|
|
op = GTK_PRINT_OPERATION ((gpointer)page->lParam);
|
|
op_win32 = op->priv->platform_data;
|
|
plug = g_object_new(GTK_TYPE_WIDGET, NULL);
|
|
|
|
SetWindowLongPtrW (wnd, GWLP_USERDATA, (LONG_PTR)op);
|
|
|
|
gtk_window_set_modal (GTK_WINDOW (plug), TRUE);
|
|
op_win32->embed_widget = plug;
|
|
gtk_box_append (GTK_BOX (plug), op->priv->custom_widget);
|
|
gtk_widget_set_visible (op->priv->custom_widget, TRUE);
|
|
gtk_widget_set_visible (plug, TRUE);
|
|
|
|
/* This dialog is modal, so we grab the embed widget */
|
|
gtk_grab_add (plug);
|
|
return FALSE;
|
|
}
|
|
else if (message == WM_DESTROY)
|
|
{
|
|
op = GTK_PRINT_OPERATION (GetWindowLongPtrW (wnd, GWLP_USERDATA));
|
|
op_win32 = op->priv->platform_data;
|
|
|
|
g_signal_emit_by_name (op, "custom-widget-apply", op->priv->custom_widget);
|
|
g_object_unref (g_object_ref_sink (op_win32->embed_widget));
|
|
op_win32->embed_widget = NULL;
|
|
op->priv->custom_widget = NULL;
|
|
}
|
|
else
|
|
{
|
|
op = GTK_PRINT_OPERATION (GetWindowLongPtrW (wnd, GWLP_USERDATA));
|
|
op_win32 = op->priv->platform_data;
|
|
|
|
/* TODO: We don't have GtkWin32EmbedWidgets anymore, but it is not currently clear
|
|
* at this point what will be the proper replacement for this. For now,
|
|
* do the message handling that was in _gtk_win32_embed_widget_dialog_procedure ()
|
|
* here and fill in the rest when things become clearer.
|
|
*/
|
|
if (message == WM_SIZE)
|
|
{
|
|
gtk_widget_queue_resize (op_win32->embed_widget);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static HPROPSHEETPAGE
|
|
create_application_page (GtkPrintOperation *op)
|
|
{
|
|
HPROPSHEETPAGE hpage;
|
|
PROPSHEETPAGEW page;
|
|
DLGTEMPLATE *template;
|
|
HGLOBAL htemplate;
|
|
LONG base_units;
|
|
WORD baseunitX, baseunitY;
|
|
WORD *array;
|
|
GtkRequisition requisition;
|
|
const char *tab_label;
|
|
|
|
/* Make the template the size of the custom widget size request */
|
|
gtk_widget_get_preferred_size (op->priv->custom_widget,
|
|
&requisition, NULL);
|
|
|
|
base_units = GetDialogBaseUnits ();
|
|
baseunitX = LOWORD (base_units);
|
|
baseunitY = HIWORD (base_units);
|
|
|
|
htemplate = GlobalAlloc (GMEM_MOVEABLE,
|
|
sizeof (DLGTEMPLATE) + sizeof (WORD) * 3);
|
|
template = GlobalLock (htemplate);
|
|
template->style = WS_CHILDWINDOW | DS_CONTROL;
|
|
template->dwExtendedStyle = WS_EX_CONTROLPARENT;
|
|
template->cdit = 0;
|
|
template->x = MulDiv (0, 4, baseunitX);
|
|
template->y = MulDiv (0, 8, baseunitY);
|
|
template->cx = MulDiv (requisition.width, 4, baseunitX);
|
|
template->cy = MulDiv (requisition.height, 8, baseunitY);
|
|
|
|
array = (WORD *) (template+1);
|
|
*array++ = 0; /* menu */
|
|
*array++ = 0; /* class */
|
|
*array++ = 0; /* title */
|
|
|
|
memset (&page, 0, sizeof (page));
|
|
page.dwSize = sizeof (page);
|
|
page.dwFlags = PSP_DLGINDIRECT | PSP_USETITLE | PSP_PREMATURE;
|
|
page.hInstance = GetModuleHandle (NULL);
|
|
page.pResource = template;
|
|
|
|
tab_label = op->priv->custom_tab_label;
|
|
if (tab_label == NULL)
|
|
tab_label = g_get_application_name ();
|
|
if (tab_label == NULL)
|
|
tab_label = _("Application");
|
|
page.pszTitle = g_utf8_to_utf16 (tab_label,
|
|
-1, NULL, NULL, NULL);
|
|
page.pfnDlgProc = pageDlgProc;
|
|
page.pfnCallback = NULL;
|
|
page.lParam = (LPARAM) op;
|
|
hpage = CreatePropertySheetPageW (&page);
|
|
|
|
GlobalUnlock (htemplate);
|
|
|
|
/* TODO: We're leaking htemplate here... */
|
|
|
|
return hpage;
|
|
}
|
|
|
|
static GtkPageSetup *
|
|
create_page_setup (GtkPrintOperation *op)
|
|
{
|
|
GtkPrintOperationPrivate *priv = op->priv;
|
|
GtkPageSetup *page_setup;
|
|
GtkPrintSettings *settings;
|
|
|
|
if (priv->default_page_setup)
|
|
page_setup = gtk_page_setup_copy (priv->default_page_setup);
|
|
else
|
|
page_setup = gtk_page_setup_new ();
|
|
|
|
settings = priv->print_settings;
|
|
if (settings)
|
|
{
|
|
GtkPaperSize *paper_size;
|
|
|
|
if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_ORIENTATION))
|
|
gtk_page_setup_set_orientation (page_setup,
|
|
gtk_print_settings_get_orientation (settings));
|
|
|
|
|
|
paper_size = gtk_print_settings_get_paper_size (settings);
|
|
if (paper_size)
|
|
{
|
|
gtk_page_setup_set_paper_size (page_setup, paper_size);
|
|
gtk_paper_size_free (paper_size);
|
|
}
|
|
|
|
/* TODO: Margins? */
|
|
}
|
|
|
|
return page_setup;
|
|
}
|
|
|
|
GtkPrintOperationResult
|
|
gtk_print_operation_run_without_dialog (GtkPrintOperation *op,
|
|
gboolean *do_print)
|
|
{
|
|
GtkPrintOperationResult result;
|
|
GtkPrintOperationWin32 *op_win32;
|
|
GtkPrintOperationPrivate *priv;
|
|
GtkPrintSettings *settings;
|
|
GtkPageSetup *page_setup;
|
|
DOCINFOW docinfo;
|
|
HGLOBAL hDevMode = NULL;
|
|
HGLOBAL hDevNames = NULL;
|
|
HDC hDC = NULL;
|
|
const char *printer = NULL;
|
|
double dpi_x, dpi_y;
|
|
int job_id;
|
|
cairo_t *cr;
|
|
DEVNAMES *pdn;
|
|
DEVMODEW *pdm;
|
|
|
|
*do_print = FALSE;
|
|
|
|
priv = op->priv;
|
|
settings = priv->print_settings;
|
|
|
|
op_win32 = g_new0 (GtkPrintOperationWin32, 1);
|
|
priv->platform_data = op_win32;
|
|
priv->free_platform_data = (GDestroyNotify) op_win32_free;
|
|
printer = gtk_print_settings_get_printer (settings);
|
|
|
|
if (!printer)
|
|
{
|
|
/* No printer selected. Get the system default printer and store
|
|
* it in settings.
|
|
*/
|
|
char *tmp_printer = get_default_printer ();
|
|
if (!tmp_printer)
|
|
{
|
|
result = GTK_PRINT_OPERATION_RESULT_ERROR;
|
|
g_set_error_literal (&priv->error,
|
|
GTK_PRINT_ERROR,
|
|
GTK_PRINT_ERROR_INTERNAL_ERROR,
|
|
_("No printer found"));
|
|
goto out;
|
|
}
|
|
gtk_print_settings_set_printer (settings, tmp_printer);
|
|
printer = gtk_print_settings_get_printer (settings);
|
|
g_free (tmp_printer);
|
|
}
|
|
|
|
hDevNames = gtk_print_win32_devnames_to_win32_from_printer_name (printer);
|
|
hDevMode = devmode_from_settings (settings, op->priv->default_page_setup, NULL);
|
|
|
|
/* Create a printer DC for the print settings and page setup provided. */
|
|
pdn = GlobalLock (hDevNames);
|
|
pdm = GlobalLock (hDevMode);
|
|
hDC = CreateDCW ((wchar_t*)pdn + pdn->wDriverOffset,
|
|
(wchar_t*)pdn + pdn->wDeviceOffset,
|
|
(wchar_t*)pdn + pdn->wOutputOffset,
|
|
pdm );
|
|
GlobalUnlock (hDevNames);
|
|
GlobalUnlock (hDevMode);
|
|
|
|
if (!hDC)
|
|
{
|
|
result = GTK_PRINT_OPERATION_RESULT_ERROR;
|
|
g_set_error_literal (&priv->error,
|
|
GTK_PRINT_ERROR,
|
|
GTK_PRINT_ERROR_INTERNAL_ERROR,
|
|
_("Invalid argument to CreateDC"));
|
|
goto out;
|
|
}
|
|
|
|
priv->print_context = _gtk_print_context_new (op);
|
|
page_setup = create_page_setup (op);
|
|
_gtk_print_context_set_page_setup (priv->print_context, page_setup);
|
|
g_object_unref (page_setup);
|
|
|
|
*do_print = TRUE;
|
|
|
|
op_win32->surface = cairo_win32_printing_surface_create (hDC);
|
|
dpi_x = (double) GetDeviceCaps (hDC, LOGPIXELSX);
|
|
dpi_y = (double) GetDeviceCaps (hDC, LOGPIXELSY);
|
|
|
|
cr = cairo_create (op_win32->surface);
|
|
gtk_print_context_set_cairo_context (priv->print_context, cr, dpi_x, dpi_y);
|
|
cairo_destroy (cr);
|
|
|
|
set_hard_margins (op);
|
|
|
|
memset (&docinfo, 0, sizeof (DOCINFOW));
|
|
docinfo.cbSize = sizeof (DOCINFOW);
|
|
docinfo.lpszDocName = g_utf8_to_utf16 (op->priv->job_name, -1, NULL, NULL, NULL);
|
|
docinfo.lpszOutput = NULL;
|
|
docinfo.lpszDatatype = NULL;
|
|
docinfo.fwType = 0;
|
|
|
|
job_id = StartDocW (hDC, &docinfo);
|
|
g_free ((void *)docinfo.lpszDocName);
|
|
if (job_id <= 0)
|
|
{
|
|
result = GTK_PRINT_OPERATION_RESULT_ERROR;
|
|
g_set_error_literal (&priv->error,
|
|
GTK_PRINT_ERROR,
|
|
GTK_PRINT_ERROR_GENERAL,
|
|
_("Error from StartDoc"));
|
|
*do_print = FALSE;
|
|
cairo_surface_destroy (op_win32->surface);
|
|
op_win32->surface = NULL;
|
|
goto out;
|
|
}
|
|
|
|
result = GTK_PRINT_OPERATION_RESULT_APPLY;
|
|
op_win32->hdc = hDC;
|
|
op_win32->devmode = hDevMode;
|
|
op_win32->devnames = hDevNames;
|
|
op_win32->job_id = job_id;
|
|
op->priv->print_pages = gtk_print_settings_get_print_pages (op->priv->print_settings);
|
|
op->priv->num_page_ranges = 0;
|
|
if (op->priv->print_pages == GTK_PRINT_PAGES_RANGES)
|
|
op->priv->page_ranges = gtk_print_settings_get_page_ranges (op->priv->print_settings,
|
|
&op->priv->num_page_ranges);
|
|
op->priv->manual_num_copies = 1;
|
|
op->priv->manual_collation = FALSE;
|
|
op->priv->manual_reverse = FALSE;
|
|
op->priv->manual_orientation = FALSE;
|
|
op->priv->manual_scale = 1.0;
|
|
op->priv->manual_page_set = GTK_PAGE_SET_ALL;
|
|
op->priv->manual_number_up = 1;
|
|
op->priv->manual_number_up_layout = GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM;
|
|
|
|
op->priv->start_page = win32_start_page;
|
|
op->priv->end_page = win32_end_page;
|
|
op->priv->end_run = win32_end_run;
|
|
|
|
out:
|
|
if (!*do_print && hDC != NULL)
|
|
DeleteDC (hDC);
|
|
|
|
if (!*do_print && hDevMode != NULL)
|
|
GlobalFree (hDevMode);
|
|
|
|
if (!*do_print && hDevNames != NULL)
|
|
GlobalFree (hDevNames);
|
|
|
|
return result;
|
|
}
|
|
|
|
GtkPrintOperationResult
|
|
gtk_print_operation_run_with_dialog (GtkPrintOperation *op,
|
|
GtkWindow *parent,
|
|
gboolean *do_print)
|
|
{
|
|
HRESULT hResult;
|
|
LPPRINTDLGEXW printdlgex = NULL;
|
|
LPPRINTPAGERANGE page_ranges = NULL;
|
|
HWND parentHWnd;
|
|
GtkWidget *invisible = NULL;
|
|
GtkPrintOperationResult result;
|
|
GtkPrintOperationWin32 *op_win32;
|
|
GtkPrintOperationPrivate *priv;
|
|
IPrintDialogCallback *callback;
|
|
HPROPSHEETPAGE prop_page;
|
|
static gsize common_controls_initialized = 0;
|
|
|
|
if (g_once_init_enter (&common_controls_initialized))
|
|
{
|
|
BOOL initialized;
|
|
INITCOMMONCONTROLSEX icc;
|
|
|
|
memset (&icc, 0, sizeof (icc));
|
|
icc.dwSize = sizeof (icc);
|
|
icc.dwICC = ICC_WIN95_CLASSES;
|
|
|
|
initialized = InitCommonControlsEx (&icc);
|
|
if (!initialized)
|
|
g_warning ("Failed to InitCommonControlsEx: %lu", GetLastError ());
|
|
|
|
_gtk_load_dll_with_libgtk3_manifest ("comdlg32.dll");
|
|
|
|
g_once_init_leave (&common_controls_initialized, initialized ? 1 : 0);
|
|
}
|
|
|
|
*do_print = FALSE;
|
|
|
|
priv = op->priv;
|
|
|
|
op_win32 = g_new0 (GtkPrintOperationWin32, 1);
|
|
priv->platform_data = op_win32;
|
|
priv->free_platform_data = (GDestroyNotify) op_win32_free;
|
|
|
|
if (parent == NULL)
|
|
{
|
|
invisible = gtk_window_new ();
|
|
parentHWnd = get_parent_hwnd (invisible);
|
|
}
|
|
else
|
|
parentHWnd = get_parent_hwnd (GTK_WIDGET (parent));
|
|
|
|
printdlgex = (LPPRINTDLGEXW)GlobalAlloc (GPTR, sizeof (PRINTDLGEXW));
|
|
if (!printdlgex)
|
|
{
|
|
result = GTK_PRINT_OPERATION_RESULT_ERROR;
|
|
g_set_error_literal (&priv->error,
|
|
GTK_PRINT_ERROR,
|
|
GTK_PRINT_ERROR_NOMEM,
|
|
_("Not enough free memory"));
|
|
goto out;
|
|
}
|
|
|
|
printdlgex->lStructSize = sizeof (PRINTDLGEXW);
|
|
printdlgex->hwndOwner = parentHWnd;
|
|
printdlgex->hDevMode = NULL;
|
|
printdlgex->hDevNames = NULL;
|
|
printdlgex->hDC = NULL;
|
|
printdlgex->Flags = PD_RETURNDC | PD_NOSELECTION;
|
|
if (op->priv->current_page == -1)
|
|
printdlgex->Flags |= PD_NOCURRENTPAGE;
|
|
printdlgex->Flags2 = 0;
|
|
printdlgex->ExclusionFlags = 0;
|
|
|
|
page_ranges = (LPPRINTPAGERANGE) GlobalAlloc (GPTR,
|
|
MAX_PAGE_RANGES * sizeof (PRINTPAGERANGE));
|
|
if (!page_ranges)
|
|
{
|
|
result = GTK_PRINT_OPERATION_RESULT_ERROR;
|
|
g_set_error_literal (&priv->error,
|
|
GTK_PRINT_ERROR,
|
|
GTK_PRINT_ERROR_NOMEM,
|
|
_("Not enough free memory"));
|
|
goto out;
|
|
}
|
|
|
|
printdlgex->nPageRanges = 0;
|
|
printdlgex->nMaxPageRanges = MAX_PAGE_RANGES;
|
|
printdlgex->lpPageRanges = page_ranges;
|
|
printdlgex->nMinPage = 1;
|
|
if (op->priv->nr_of_pages != -1)
|
|
printdlgex->nMaxPage = op->priv->nr_of_pages;
|
|
else
|
|
printdlgex->nMaxPage = 10000;
|
|
printdlgex->nCopies = 1;
|
|
printdlgex->hInstance = 0;
|
|
printdlgex->lpPrintTemplateName = NULL;
|
|
printdlgex->lpCallback = NULL;
|
|
|
|
g_signal_emit_by_name (op, "create-custom-widget",
|
|
&op->priv->custom_widget);
|
|
if (op->priv->custom_widget) {
|
|
prop_page = create_application_page (op);
|
|
printdlgex->nPropertyPages = 1;
|
|
printdlgex->lphPropertyPages = &prop_page;
|
|
} else {
|
|
printdlgex->nPropertyPages = 0;
|
|
printdlgex->lphPropertyPages = NULL;
|
|
}
|
|
|
|
printdlgex->nStartPage = START_PAGE_GENERAL;
|
|
printdlgex->dwResultAction = 0;
|
|
|
|
dialog_from_print_settings (op, printdlgex);
|
|
|
|
callback = print_callback_new ();
|
|
printdlgex->lpCallback = (IUnknown *)callback;
|
|
got_gdk_events_message = RegisterWindowMessage ("GDK_WIN32_GOT_EVENTS");
|
|
|
|
hResult = PrintDlgExW (printdlgex);
|
|
IUnknown_Release ((IUnknown *)callback);
|
|
gdk_win32_set_modal_dialog_libgtk_only (NULL);
|
|
|
|
if (hResult != S_OK)
|
|
{
|
|
result = GTK_PRINT_OPERATION_RESULT_ERROR;
|
|
if (hResult == E_OUTOFMEMORY)
|
|
g_set_error_literal (&priv->error,
|
|
GTK_PRINT_ERROR,
|
|
GTK_PRINT_ERROR_NOMEM,
|
|
_("Not enough free memory"));
|
|
else if (hResult == E_INVALIDARG)
|
|
g_set_error_literal (&priv->error,
|
|
GTK_PRINT_ERROR,
|
|
GTK_PRINT_ERROR_INTERNAL_ERROR,
|
|
_("Invalid argument to PrintDlgEx"));
|
|
else if (hResult == E_POINTER)
|
|
g_set_error_literal (&priv->error,
|
|
GTK_PRINT_ERROR,
|
|
GTK_PRINT_ERROR_INTERNAL_ERROR,
|
|
_("Invalid pointer to PrintDlgEx"));
|
|
else if (hResult == E_HANDLE)
|
|
g_set_error_literal (&priv->error,
|
|
GTK_PRINT_ERROR,
|
|
GTK_PRINT_ERROR_INTERNAL_ERROR,
|
|
_("Invalid handle to PrintDlgEx"));
|
|
else /* E_FAIL */
|
|
g_set_error_literal (&priv->error,
|
|
GTK_PRINT_ERROR,
|
|
GTK_PRINT_ERROR_GENERAL,
|
|
_("Unspecified error"));
|
|
goto out;
|
|
}
|
|
|
|
if (printdlgex->dwResultAction == PD_RESULT_PRINT ||
|
|
printdlgex->dwResultAction == PD_RESULT_APPLY)
|
|
{
|
|
result = GTK_PRINT_OPERATION_RESULT_APPLY;
|
|
dialog_to_print_settings (op, printdlgex);
|
|
}
|
|
else
|
|
result = GTK_PRINT_OPERATION_RESULT_CANCEL;
|
|
|
|
if (printdlgex->dwResultAction == PD_RESULT_PRINT)
|
|
{
|
|
DOCINFOW docinfo;
|
|
int job_id;
|
|
double dpi_x, dpi_y;
|
|
cairo_t *cr;
|
|
GtkPageSetup *page_setup;
|
|
|
|
priv->print_context = _gtk_print_context_new (op);
|
|
page_setup = create_page_setup (op);
|
|
_gtk_print_context_set_page_setup (priv->print_context, page_setup);
|
|
g_object_unref (page_setup);
|
|
|
|
*do_print = TRUE;
|
|
|
|
op_win32->surface = cairo_win32_printing_surface_create (printdlgex->hDC);
|
|
|
|
dpi_x = (double)GetDeviceCaps (printdlgex->hDC, LOGPIXELSX);
|
|
dpi_y = (double)GetDeviceCaps (printdlgex->hDC, LOGPIXELSY);
|
|
|
|
cr = cairo_create (op_win32->surface);
|
|
gtk_print_context_set_cairo_context (priv->print_context, cr, dpi_x, dpi_y);
|
|
cairo_destroy (cr);
|
|
|
|
set_hard_margins (op);
|
|
|
|
memset ( &docinfo, 0, sizeof (DOCINFOW));
|
|
docinfo.cbSize = sizeof (DOCINFOW);
|
|
docinfo.lpszDocName = g_utf8_to_utf16 (op->priv->job_name, -1, NULL, NULL, NULL);
|
|
docinfo.lpszOutput = (LPCWSTR) NULL;
|
|
docinfo.lpszDatatype = (LPCWSTR) NULL;
|
|
docinfo.fwType = 0;
|
|
|
|
job_id = StartDocW (printdlgex->hDC, &docinfo);
|
|
g_free ((void *)docinfo.lpszDocName);
|
|
if (job_id <= 0)
|
|
{
|
|
result = GTK_PRINT_OPERATION_RESULT_ERROR;
|
|
g_set_error_literal (&priv->error,
|
|
GTK_PRINT_ERROR,
|
|
GTK_PRINT_ERROR_GENERAL,
|
|
_("Error from StartDoc"));
|
|
*do_print = FALSE;
|
|
cairo_surface_destroy (op_win32->surface);
|
|
op_win32->surface = NULL;
|
|
goto out;
|
|
}
|
|
|
|
op_win32->hdc = printdlgex->hDC;
|
|
op_win32->devmode = printdlgex->hDevMode;
|
|
op_win32->devnames = printdlgex->hDevNames;
|
|
op_win32->job_id = job_id;
|
|
|
|
op->priv->print_pages = gtk_print_settings_get_print_pages (op->priv->print_settings);
|
|
op->priv->num_page_ranges = 0;
|
|
if (op->priv->print_pages == GTK_PRINT_PAGES_RANGES)
|
|
op->priv->page_ranges = gtk_print_settings_get_page_ranges (op->priv->print_settings,
|
|
&op->priv->num_page_ranges);
|
|
op->priv->manual_num_copies = printdlgex->nCopies;
|
|
op->priv->manual_collation = (printdlgex->Flags & PD_COLLATE) != 0;
|
|
op->priv->manual_reverse = FALSE;
|
|
op->priv->manual_orientation = FALSE;
|
|
op->priv->manual_scale = 1.0;
|
|
op->priv->manual_page_set = GTK_PAGE_SET_ALL;
|
|
op->priv->manual_number_up = 1;
|
|
op->priv->manual_number_up_layout = GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM;
|
|
}
|
|
|
|
op->priv->start_page = win32_start_page;
|
|
op->priv->end_page = win32_end_page;
|
|
op->priv->end_run = win32_end_run;
|
|
|
|
out:
|
|
if (!*do_print && printdlgex && printdlgex->hDC != NULL)
|
|
DeleteDC (printdlgex->hDC);
|
|
|
|
if (!*do_print && printdlgex && printdlgex->hDevMode != NULL)
|
|
GlobalFree (printdlgex->hDevMode);
|
|
|
|
if (!*do_print && printdlgex && printdlgex->hDevNames != NULL)
|
|
GlobalFree (printdlgex->hDevNames);
|
|
|
|
if (page_ranges)
|
|
GlobalFree (page_ranges);
|
|
|
|
if (printdlgex)
|
|
GlobalFree (printdlgex);
|
|
|
|
if (invisible)
|
|
gtk_window_destroy (GTK_WINDOW (invisible));
|
|
|
|
return result;
|
|
}
|
|
|
|
GtkPrintOperationResult
|
|
_gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op,
|
|
gboolean show_dialog,
|
|
GtkWindow *parent,
|
|
gboolean *do_print)
|
|
{
|
|
if (show_dialog)
|
|
return gtk_print_operation_run_with_dialog (op, parent, do_print);
|
|
else
|
|
return gtk_print_operation_run_without_dialog (op, do_print);
|
|
}
|
|
|
|
void
|
|
_gtk_print_operation_platform_backend_launch_preview (GtkPrintOperation *op,
|
|
cairo_surface_t *surface,
|
|
GtkWindow *parent,
|
|
const char *filename)
|
|
{
|
|
HDC dc;
|
|
HENHMETAFILE metafile;
|
|
|
|
dc = cairo_win32_surface_get_dc (surface);
|
|
cairo_surface_destroy (surface);
|
|
metafile = CloseEnhMetaFile (dc);
|
|
DeleteEnhMetaFile (metafile);
|
|
|
|
ShellExecuteW (NULL, L"open", (gunichar2 *)filename, NULL, NULL, SW_SHOW);
|
|
}
|
|
|
|
void
|
|
_gtk_print_operation_platform_backend_preview_start_page (GtkPrintOperation *op,
|
|
cairo_surface_t *surface,
|
|
cairo_t *cr)
|
|
{
|
|
HDC dc = cairo_win32_surface_get_dc (surface);
|
|
StartPage (dc);
|
|
}
|
|
|
|
void
|
|
_gtk_print_operation_platform_backend_preview_end_page (GtkPrintOperation *op,
|
|
cairo_surface_t *surface,
|
|
cairo_t *cr)
|
|
{
|
|
HDC dc;
|
|
|
|
cairo_surface_show_page (surface);
|
|
|
|
/* TODO: Enhanced metafiles don't support multiple pages.
|
|
*/
|
|
dc = cairo_win32_surface_get_dc (surface);
|
|
EndPage (dc);
|
|
}
|
|
|
|
cairo_surface_t *
|
|
_gtk_print_operation_platform_backend_create_preview_surface (GtkPrintOperation *op,
|
|
GtkPageSetup *page_setup,
|
|
double *dpi_x,
|
|
double *dpi_y,
|
|
char **target)
|
|
{
|
|
GtkPaperSize *paper_size;
|
|
HDC metafile_dc;
|
|
RECT rect;
|
|
char *template;
|
|
char *filename;
|
|
gunichar2 *filename_utf16;
|
|
int fd;
|
|
|
|
template = g_build_filename (g_get_tmp_dir (), "prXXXXXX", NULL);
|
|
fd = g_mkstemp (template);
|
|
close (fd);
|
|
|
|
filename = g_strconcat (template, ".emf", NULL);
|
|
g_free (template);
|
|
|
|
filename_utf16 = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
|
|
g_free (filename);
|
|
|
|
paper_size = gtk_page_setup_get_paper_size (page_setup);
|
|
|
|
/* The rectangle dimensions are given in hundredths of a millimeter */
|
|
rect.left = 0;
|
|
rect.right = 100.0 * gtk_paper_size_get_width (paper_size, GTK_UNIT_MM);
|
|
rect.top = 0;
|
|
rect.bottom = 100.0 * gtk_paper_size_get_height (paper_size, GTK_UNIT_MM);
|
|
|
|
metafile_dc = CreateEnhMetaFileW (NULL, filename_utf16,
|
|
&rect, L"Gtk+\0Print Preview\0\0");
|
|
if (metafile_dc == NULL)
|
|
{
|
|
g_warning ("Can't create metafile");
|
|
return NULL;
|
|
}
|
|
|
|
*target = (char *)filename_utf16;
|
|
|
|
*dpi_x = (double)GetDeviceCaps (metafile_dc, LOGPIXELSX);
|
|
*dpi_y = (double)GetDeviceCaps (metafile_dc, LOGPIXELSY);
|
|
|
|
return cairo_win32_printing_surface_create (metafile_dc);
|
|
}
|
|
|
|
void
|
|
_gtk_print_operation_platform_backend_resize_preview_surface (GtkPrintOperation *op,
|
|
GtkPageSetup *page_setup,
|
|
cairo_surface_t *surface)
|
|
{
|
|
/* TODO: Implement */
|
|
}
|
|
|
|
/**
|
|
* gtk_print_run_page_setup_dialog:
|
|
* @parent: (nullable): transient parent
|
|
* @page_setup: (nullable): an existing `GtkPageSetup`
|
|
* @settings: a `GtkPrintSettings`
|
|
*
|
|
* Runs a page setup dialog, letting the user modify the values from
|
|
* @page_setup. If the user cancels the dialog, the returned `GtkPageSetup`
|
|
* is identical to the passed in @page_setup, otherwise it contains the
|
|
* modifications done in the dialog.
|
|
*
|
|
* Note that this function may use a recursive mainloop to show the page
|
|
* setup dialog. See gtk_print_run_page_setup_dialog_async() if this is
|
|
* a problem.
|
|
*
|
|
* Returns: (transfer full): a new `GtkPageSetup`
|
|
*/
|
|
GtkPageSetup *
|
|
gtk_print_run_page_setup_dialog (GtkWindow *parent,
|
|
GtkPageSetup *page_setup,
|
|
GtkPrintSettings *settings)
|
|
{
|
|
LPPAGESETUPDLGW pagesetupdlg = NULL;
|
|
BOOL res;
|
|
gboolean free_settings;
|
|
const char *printer;
|
|
GtkPaperSize *paper_size;
|
|
DWORD measure_system;
|
|
GtkUnit unit;
|
|
double scale;
|
|
|
|
pagesetupdlg = (LPPAGESETUPDLGW)GlobalAlloc (GPTR, sizeof (PAGESETUPDLGW));
|
|
if (!pagesetupdlg)
|
|
return NULL;
|
|
|
|
free_settings = FALSE;
|
|
if (settings == NULL)
|
|
{
|
|
settings = gtk_print_settings_new ();
|
|
free_settings = TRUE;
|
|
}
|
|
|
|
memset (pagesetupdlg, 0, sizeof (PAGESETUPDLGW));
|
|
|
|
pagesetupdlg->lStructSize = sizeof (PAGESETUPDLGW);
|
|
|
|
if (parent != NULL)
|
|
pagesetupdlg->hwndOwner = get_parent_hwnd (GTK_WIDGET (parent));
|
|
else
|
|
pagesetupdlg->hwndOwner = NULL;
|
|
|
|
pagesetupdlg->Flags = PSD_DEFAULTMINMARGINS;
|
|
pagesetupdlg->hDevMode = devmode_from_settings (settings, page_setup, NULL);
|
|
pagesetupdlg->hDevNames = NULL;
|
|
printer = gtk_print_settings_get_printer (settings);
|
|
if (printer)
|
|
pagesetupdlg->hDevNames = gtk_print_win32_devnames_to_win32_from_printer_name (printer);
|
|
|
|
GetLocaleInfoW (LOCALE_USER_DEFAULT, LOCALE_IMEASURE|LOCALE_RETURN_NUMBER,
|
|
(LPWSTR)&measure_system, sizeof (DWORD));
|
|
|
|
if (measure_system == 0)
|
|
{
|
|
pagesetupdlg->Flags |= PSD_INHUNDREDTHSOFMILLIMETERS;
|
|
unit = GTK_UNIT_MM;
|
|
scale = 100;
|
|
}
|
|
else
|
|
{
|
|
pagesetupdlg->Flags |= PSD_INTHOUSANDTHSOFINCHES;
|
|
unit = GTK_UNIT_INCH;
|
|
scale = 1000;
|
|
}
|
|
|
|
/* This is the object we return, we allocate it here so that
|
|
* we can use the default page margins */
|
|
if (page_setup)
|
|
page_setup = gtk_page_setup_copy (page_setup);
|
|
else
|
|
page_setup = gtk_page_setup_new ();
|
|
|
|
pagesetupdlg->Flags |= PSD_MARGINS;
|
|
pagesetupdlg->rtMargin.left =
|
|
floor (gtk_page_setup_get_left_margin (page_setup, unit) * scale + 0.5);
|
|
pagesetupdlg->rtMargin.right =
|
|
floor (gtk_page_setup_get_right_margin (page_setup, unit) * scale + 0.5);
|
|
pagesetupdlg->rtMargin.top =
|
|
floor (gtk_page_setup_get_top_margin (page_setup, unit) * scale + 0.5);
|
|
pagesetupdlg->rtMargin.bottom =
|
|
floor (gtk_page_setup_get_bottom_margin (page_setup, unit) * scale + 0.5);
|
|
|
|
pagesetupdlg->Flags |= PSD_ENABLEPAGESETUPHOOK;
|
|
pagesetupdlg->lpfnPageSetupHook = run_mainloop_hook;
|
|
got_gdk_events_message = RegisterWindowMessage ("GDK_WIN32_GOT_EVENTS");
|
|
|
|
res = PageSetupDlgW (pagesetupdlg);
|
|
gdk_win32_set_modal_dialog_libgtk_only (NULL);
|
|
|
|
if (res)
|
|
{
|
|
if (pagesetupdlg->hDevNames != NULL)
|
|
devnames_to_settings (settings, pagesetupdlg->hDevNames);
|
|
|
|
if (pagesetupdlg->hDevMode != NULL)
|
|
devmode_to_settings (settings, pagesetupdlg->hDevMode);
|
|
}
|
|
|
|
if (res)
|
|
{
|
|
gtk_page_setup_set_orientation (page_setup,
|
|
gtk_print_settings_get_orientation (settings));
|
|
paper_size = gtk_print_settings_get_paper_size (settings);
|
|
if (paper_size)
|
|
{
|
|
gtk_page_setup_set_paper_size (page_setup, paper_size);
|
|
gtk_paper_size_free (paper_size);
|
|
}
|
|
|
|
if (pagesetupdlg->Flags & PSD_INHUNDREDTHSOFMILLIMETERS)
|
|
{
|
|
unit = GTK_UNIT_MM;
|
|
scale = 100;
|
|
}
|
|
else
|
|
{
|
|
unit = GTK_UNIT_INCH;
|
|
scale = 1000;
|
|
}
|
|
|
|
gtk_page_setup_set_left_margin (page_setup,
|
|
pagesetupdlg->rtMargin.left / scale,
|
|
unit);
|
|
gtk_page_setup_set_right_margin (page_setup,
|
|
pagesetupdlg->rtMargin.right / scale,
|
|
unit);
|
|
gtk_page_setup_set_top_margin (page_setup,
|
|
pagesetupdlg->rtMargin.top / scale,
|
|
unit);
|
|
gtk_page_setup_set_bottom_margin (page_setup,
|
|
pagesetupdlg->rtMargin.bottom / scale,
|
|
unit);
|
|
}
|
|
|
|
if (free_settings)
|
|
g_object_unref (settings);
|
|
|
|
return page_setup;
|
|
}
|
|
|
|
/**
|
|
* gtk_print_run_page_setup_dialog_async:
|
|
* @parent: (nullable): transient parent
|
|
* @page_setup: (nullable): an existing `GtkPageSetup`
|
|
* @settings: a `GtkPrintSettings`
|
|
* @done_cb: (scope async): a function to call when the user saves
|
|
* the modified page setup
|
|
* @data: user data to pass to @done_cb
|
|
*
|
|
* Runs a page setup dialog, letting the user modify the values from @page_setup.
|
|
*
|
|
* In contrast to gtk_print_run_page_setup_dialog(), this function returns after
|
|
* showing the page setup dialog on platforms that support this, and calls @done_cb
|
|
* from a signal handler for the ::response signal of the dialog.
|
|
*/
|
|
void
|
|
gtk_print_run_page_setup_dialog_async (GtkWindow *parent,
|
|
GtkPageSetup *page_setup,
|
|
GtkPrintSettings *settings,
|
|
GtkPageSetupDoneFunc done_cb,
|
|
gpointer data)
|
|
{
|
|
GtkPageSetup *new_page_setup;
|
|
|
|
new_page_setup = gtk_print_run_page_setup_dialog (parent, page_setup, settings);
|
|
done_cb (new_page_setup, data);
|
|
g_object_unref (new_page_setup);
|
|
}
|