1 #define __SP_MODULE_WIN32_C__
3 /*
4 * Windows stuff
5 *
6 * Author:
7 * Lauris Kaplinski <lauris@kaplinski.com>
8 *
9 * This code is in public domain
10 */
12 #ifdef HAVE_CONFIG_H
13 # include "config.h"
14 #endif
16 #include <glib/gmem.h>
17 #include <libnr/nr-macros.h>
18 #include <libnr/nr-matrix.h>
20 #include "display/nr-arena-item.h"
21 #include "display/nr-arena.h"
22 #include "document.h"
24 #include "win32.h"
25 #include "system.h"
26 #include "extension/print.h"
27 #include <gtk/gtk.h>
29 /* Initialization */
31 namespace Inkscape {
32 namespace Extension {
33 namespace Internal {
35 static unsigned int SPWin32Modal = FALSE;
37 /**
38 * Callback function.. not a method
39 */
40 static void
41 my_gdk_event_handler (GdkEvent *event)
42 {
43 if (SPWin32Modal) {
44 /* Win32 widget is modal, filter events */
45 switch (event->type) {
46 case GDK_NOTHING:
47 case GDK_DELETE:
48 case GDK_SCROLL:
49 case GDK_BUTTON_PRESS:
50 case GDK_2BUTTON_PRESS:
51 case GDK_3BUTTON_PRESS:
52 case GDK_BUTTON_RELEASE:
53 case GDK_KEY_PRESS:
54 case GDK_KEY_RELEASE:
55 case GDK_DRAG_STATUS:
56 case GDK_DRAG_ENTER:
57 case GDK_DRAG_LEAVE:
58 case GDK_DRAG_MOTION:
59 case GDK_DROP_START:
60 case GDK_DROP_FINISHED:
61 return;
62 break;
63 default:
64 break;
65 }
66 }
67 gtk_main_do_event (event);
68 }
70 void
71 PrintWin32::main_init (int argc, char **argv, const char *name)
72 {
73 gdk_event_handler_set ((GdkEventFunc) my_gdk_event_handler, NULL, NULL);
74 }
76 void
77 PrintWin32::finish (void)
78 {
79 }
81 #define SP_FOREIGN_MAX_ITER 10
84 /**
85 * Callback function.. not a method
86 */
87 static VOID CALLBACK
88 my_timer (HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
89 {
90 int cdown = 0;
91 while ((cdown++ < SP_FOREIGN_MAX_ITER) && gdk_events_pending ()) {
92 gtk_main_iteration_do (FALSE);
93 }
94 gtk_main_iteration_do (FALSE);
95 }
98 /* Platform detection */
100 gboolean
101 PrintWin32::is_os_wide()
102 {
103 static gboolean initialized = FALSE;
104 static gboolean is_wide = FALSE;
105 static OSVERSIONINFOA osver;
107 if ( !initialized )
108 {
109 BOOL result;
111 initialized = TRUE;
113 memset (&osver, 0, sizeof(OSVERSIONINFOA));
114 osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
115 result = GetVersionExA (&osver);
116 if (result)
117 {
118 if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT)
119 is_wide = TRUE;
120 }
121 // If we can't even call to get the version, fall back to ANSI API
122 }
124 return is_wide;
125 }
128 /* Printing */
130 PrintWin32::PrintWin32 (void)
131 {
132 /* Nothing here */
133 }
136 PrintWin32::~PrintWin32 (void)
137 {
138 DeleteDC (_hDC);
139 }
142 /**
143 * Callback function.. not a method
144 */
145 static UINT_PTR CALLBACK
146 print_hook (HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
147 {
148 #if 0
149 int cdown = 0;
150 while ((cdown++ < SP_FOREIGN_MAX_ITER) && gdk_events_pending ()) {
151 gtk_main_iteration_do (FALSE);
152 }
153 gtk_main_iteration_do (FALSE);
154 #endif
155 return 0;
156 }
158 unsigned int
159 PrintWin32::setup (Inkscape::Extension::Print *mod)
160 {
161 HRESULT res;
162 PRINTDLG pd = {
163 sizeof (PRINTDLG),
164 NULL, /* hwndOwner */
165 NULL, /* hDevMode */
166 NULL, /* hDevNames */
167 NULL, /* hDC */
168 PD_NOPAGENUMS | PD_NOSELECTION | PD_RETURNDC | PD_USEDEVMODECOPIESANDCOLLATE, /* Flags */
169 1, 1, 1, 1, /* nFromPage, nToPage, nMinPage, nMaxPage */
170 1, /* nCoies */
171 NULL, /* hInstance */
172 0, /* lCustData */
173 NULL, NULL, NULL, NULL, NULL, NULL
174 };
175 UINT_PTR timer;
177 SPWin32Modal = TRUE;
178 pd.Flags |= PD_ENABLEPRINTHOOK;
179 pd.lpfnPrintHook = print_hook;
180 timer = SetTimer (NULL, 0, 40, my_timer);
182 res = PrintDlg (&pd);
184 KillTimer (NULL, timer);
185 SPWin32Modal = FALSE;
187 if (!res) return FALSE;
189 _hDC = pd.hDC;
191 #if 0
192 caps = GetDeviceCaps (_hDC, RASTERCAPS);
193 if (caps & RC_BANDING) {
194 printf ("needs banding\n");
195 }
196 if (caps & RC_BITBLT) {
197 printf ("does bitblt\n");
198 }
199 if (caps & RC_DIBTODEV) {
200 printf ("does dibtodev\n");
201 }
202 if (caps & RC_STRETCHDIB) {
203 printf ("does stretchdib\n");
204 }
205 #endif
206 if (pd.hDevMode) {
207 DEVMODE *devmodep;
208 devmodep = (DEVMODE *)pd.hDevMode;
209 if (devmodep->dmFields & DM_ORIENTATION) {
210 _landscape = (devmodep->dmOrientation == DMORIENT_LANDSCAPE);
211 }
212 }
214 return TRUE;
215 }
217 unsigned int
218 PrintWin32::begin (Inkscape::Extension::Print *mod, SPDocument *doc)
219 {
220 DOCINFO di = {
221 sizeof (DOCINFO),
222 NULL, /* lpszDocName */
223 NULL, /* lpszOutput */
224 NULL, /* lpszDatatype */
225 0 /* DI_APPBANDING */ /* fwType */
226 };
227 int res;
229 _PageWidth = sp_document_width (doc);
230 _PageHeight = sp_document_height (doc);
232 di.lpszDocName = SP_DOCUMENT_NAME (doc);
234 SPWin32Modal = TRUE;
236 res = StartDoc (_hDC, &di);
237 res = StartPage (_hDC);
239 SPWin32Modal = FALSE;
241 return 0;
242 }
244 unsigned int
245 PrintWin32::finish (Inkscape::Extension::Print *mod)
246 {
247 int dpiX, dpiY;
248 int pPhysicalWidth, pPhysicalHeight;
249 int pPhysicalOffsetX, pPhysicalOffsetY;
250 int pPrintableWidth, pPrintableHeight;
251 float scalex, scaley;
252 int x0, y0, x1, y1;
253 int width, height;
254 NRMatrix affine;
255 unsigned char *px;
256 int sheight, row;
257 BITMAPINFO bmInfo = {
258 {
259 sizeof (BITMAPINFOHEADER), // bV4Size
260 64, // biWidth
261 64, // biHeight
262 1, // biPlanes
263 32, // biBitCount
264 BI_RGB, // biCompression
265 0, // biSizeImage
266 2835, // biXPelsPerMeter
267 2835, // biYPelsPerMeter
268 0, // biClrUsed
269 0 // biClrImportant
270 },
271 { { 0, 0, 0, 0 } } // bmiColors
272 };
273 //RECT wrect;
274 int res;
276 SPWin32Modal = TRUE;
278 // Number of pixels per logical inch
279 dpiX = (int) GetDeviceCaps (_hDC, LOGPIXELSX);
280 dpiY = (int) GetDeviceCaps (_hDC, LOGPIXELSY);
281 // Size in pixels of the printable area
282 pPhysicalWidth = GetDeviceCaps (_hDC, PHYSICALWIDTH);
283 pPhysicalHeight = GetDeviceCaps (_hDC, PHYSICALHEIGHT);
284 // Top left corner of prontable area
285 pPhysicalOffsetX = GetDeviceCaps (_hDC, PHYSICALOFFSETX);
286 pPhysicalOffsetY = GetDeviceCaps (_hDC, PHYSICALOFFSETY);
287 // Size in pixels of the printable area
288 pPrintableWidth = GetDeviceCaps (_hDC, HORZRES);
289 pPrintableHeight = GetDeviceCaps (_hDC, VERTRES);
291 // Scaling from document to device
292 scalex = dpiX / 72.0;
293 scaley = dpiY / 72.0;
295 // We simply map document 0,0 to physical page 0,0
296 affine.c[0] = scalex / 1.25;
297 affine.c[1] = 0.0;
298 affine.c[2] = 0.0;
299 affine.c[3] = scaley / 1.25;
300 affine.c[4] = 0.0;
301 affine.c[5] = 0.0;
303 nr_arena_item_set_transform (mod->root, &affine);
305 // Calculate printable area in device coordinates
306 x0 = pPhysicalOffsetX;
307 y0 = pPhysicalOffsetY;
308 x1 = x0 + pPrintableWidth;
309 y1 = y0 + pPrintableHeight;
310 x1 = MIN (x1, (int) (_PageWidth * scalex));
311 y1 = MIN (y1, (int) (_PageHeight * scaley));
313 width = x1 - x0;
314 height = y1 - y0;
316 px = g_new (unsigned char, 4 * 64 * width);
317 sheight = 64;
319 /* Printing goes here */
320 for (row = 0; row < height; row += 64) {
321 NRPixBlock pb;
322 NRRectL bbox;
323 NRGC gc(NULL);
324 int num_rows;
325 int i;
327 num_rows = sheight;
328 if ((row + num_rows) > height) num_rows = height - row;
330 /* Set area of interest */
331 bbox.x0 = x0;
332 bbox.y0 = y0 + row;
333 bbox.x1 = bbox.x0 + width;
334 bbox.y1 = bbox.y0 + num_rows;
335 /* Update to renderable state */
336 nr_matrix_set_identity (&gc.transform);
337 nr_arena_item_invoke_update (mod->root, &bbox, &gc, NR_ARENA_ITEM_STATE_ALL, NR_ARENA_ITEM_STATE_NONE);
339 nr_pixblock_setup_extern (&pb, NR_PIXBLOCK_MODE_R8G8B8A8N, bbox.x0, bbox.y0, bbox.x1, bbox.y1, px, 4 * (bbox.x1 - bbox.x0), FALSE, FALSE);
341 /* Blitter goes here */
342 bmInfo.bmiHeader.biWidth = bbox.x1 - bbox.x0;
343 bmInfo.bmiHeader.biHeight = -(bbox.y1 - bbox.y0);
345 memset (px, 0xff, 4 * num_rows * width);
346 /* Render */
347 nr_arena_item_invoke_render (mod->root, &bbox, &pb, 0);
349 /* Swap red and blue channels; we use RGBA, whereas
350 * the Win32 GDI uses BGRx.
351 */
352 for ( i = 0 ; i < num_rows * width ; i++ ) {
353 unsigned char temp=px[i*4];
354 px[i*4] = px[i*4+2];
355 px[i*4+2] = temp;
356 }
358 SetStretchBltMode(_hDC, COLORONCOLOR);
359 res = StretchDIBits (_hDC,
360 bbox.x0 - x0, bbox.y0 - y0, bbox.x1 - bbox.x0, bbox.y1 - bbox.y0,
361 0, 0, bbox.x1 - bbox.x0, bbox.y1 - bbox.y0,
362 px,
363 &bmInfo,
364 DIB_RGB_COLORS,
365 SRCCOPY);
367 /* Blitter ends here */
369 nr_pixblock_release (&pb);
370 }
372 g_free (px);
374 res = EndPage (_hDC);
375 res = EndDoc (_hDC);
377 SPWin32Modal = FALSE;
379 return 0;
380 }
382 /* File dialogs */
384 char *
385 PrintWin32::get_open_filename (unsigned char *dir, unsigned char *filter, unsigned char *title)
386 {
387 char fnbuf[4096] = {0};
388 OPENFILENAME ofn = {
389 sizeof (OPENFILENAME),
390 NULL, /* hwndOwner */
391 NULL, /* hInstance */
392 (const CHAR *)filter, /* lpstrFilter */
393 NULL, /* lpstrCustomFilter */
394 0, /* nMaxCustFilter */
395 1, /* nFilterIndex */
396 fnbuf, /* lpstrFile */
397 sizeof (fnbuf), /* nMaxFile */
398 NULL, /* lpstrFileTitle */
399 0, /* nMaxFileTitle */
400 (const CHAR *)dir, /* lpstrInitialDir */
401 (const CHAR *)title, /* lpstrTitle */
402 OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY, /* Flags */
403 0, /* nFileOffset */
404 0, /* nFileExtension */
405 NULL, /* lpstrDefExt */
406 0, /* lCustData */
407 NULL, /* lpfnHook */
408 NULL /* lpTemplateName */
409 };
410 int retval;
411 UINT_PTR timer;
413 SPWin32Modal = TRUE;
414 timer = SetTimer (NULL, 0, 40, my_timer);
416 retval = GetOpenFileName (&ofn);
418 KillTimer (NULL, timer);
419 SPWin32Modal = FALSE;
421 if (!retval) {
422 int errcode;
423 errcode = CommDlgExtendedError();
424 return NULL;
425 }
426 return g_strdup (fnbuf);
427 }
429 char *
430 PrintWin32::get_write_filename (unsigned char *dir, unsigned char *filter, unsigned char *title)
431 {
432 return NULL;
433 }
435 char *
436 PrintWin32::get_save_filename (unsigned char *dir, unsigned int *spns)
437 {
438 char fnbuf[4096] = {0};
439 OPENFILENAME ofn = {
440 sizeof (OPENFILENAME),
441 NULL, /* hwndOwner */
442 NULL, /* hInstance */
443 "Inkscape SVG (*.svg)\0*\0Plain SVG (*.svg)\0*\0", /* lpstrFilter */
444 NULL, /* lpstrCustomFilter */
445 0, /* nMaxCustFilter */
446 1, /* nFilterIndex */
447 fnbuf, /* lpstrFile */
448 sizeof (fnbuf), /* nMaxFile */
449 NULL, /* lpstrFileTitle */
450 0, /* nMaxFileTitle */
451 (const CHAR *)dir, /* lpstrInitialDir */
452 "Save document to file", /* lpstrTitle */
453 OFN_HIDEREADONLY, /* Flags */
454 0, /* nFileOffset */
455 0, /* nFileExtension */
456 NULL, /* lpstrDefExt */
457 0, /* lCustData */
458 NULL, /* lpfnHook */
459 NULL /* lpTemplateName */
460 };
461 int retval;
462 UINT_PTR timer;
464 SPWin32Modal = TRUE;
465 timer = SetTimer (NULL, 0, 40, my_timer);
467 retval = GetSaveFileName (&ofn);
469 KillTimer (NULL, timer);
470 SPWin32Modal = FALSE;
472 if (!retval) {
473 int errcode;
474 errcode = CommDlgExtendedError();
475 return NULL;
476 }
477 *spns = (ofn.nFilterIndex != 2);
478 return g_strdup (fnbuf);
479 }
481 #include "clear-n_.h"
483 void
484 PrintWin32::init (void)
485 {
486 Inkscape::Extension::Extension * ext;
488 /* SVG in */
489 ext = Inkscape::Extension::build_from_mem(
490 "<inkscape-extension>\n"
491 "<name>" N_("Windows 32-bit Print") "</name>\n"
492 "<id>" SP_MODULE_KEY_PRINT_WIN32 "</id>\n"
493 "<param name=\"textToPath\" type=\"boolean\">TRUE</param>\n"
494 "<print/>\n"
495 "</inkscape-extension>", new PrintWin32());
497 return;
498 }
500 } /* namespace Internal */
501 } /* namespace Extension */
502 } /* namespace Inkscape */