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