1 /** @file
2 * @brief Windows-specific stuff
3 */
4 /* Author:
5 * Lauris Kaplinski <lauris@kaplinski.com>
6 *
7 * This code is in public domain
8 */
10 #ifdef WIN32
12 #ifdef HAVE_CONFIG_H
13 # include "config.h"
14 #endif
16 #include <glib/gmem.h>
17 #include <libnr/nr-macros.h>
18 #include <2geom/transforms.h>
20 #include "display/nr-arena-item.h"
21 #include "display/nr-arena.h"
22 #include "document.h"
24 #include "win32.h"
25 #include "extension/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 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 Geom::Matrix affine = Geom::Scale(scalex / 1.25, scaley / 1.25);
297 nr_arena_item_set_transform (mod->root, affine);
299 // Calculate printable area in device coordinates
300 x0 = pPhysicalOffsetX;
301 y0 = pPhysicalOffsetY;
302 x1 = x0 + pPrintableWidth;
303 y1 = y0 + pPrintableHeight;
304 x1 = MIN (x1, (int) (_PageWidth * scalex));
305 y1 = MIN (y1, (int) (_PageHeight * scaley));
307 width = x1 - x0;
308 height = y1 - y0;
310 px = g_new (unsigned char, 4 * 64 * width);
311 sheight = 64;
313 /* Printing goes here */
314 for (row = 0; row < height; row += 64) {
315 NRPixBlock pb;
316 NRRectL bbox;
317 NRGC gc(NULL);
318 int num_rows;
319 int i;
321 num_rows = sheight;
322 if ((row + num_rows) > height) num_rows = height - row;
324 /* Set area of interest */
325 bbox.x0 = x0;
326 bbox.y0 = y0 + row;
327 bbox.x1 = bbox.x0 + width;
328 bbox.y1 = bbox.y0 + num_rows;
329 /* Update to renderable state */
330 gc.transform.setIdentity();
331 nr_arena_item_invoke_update (mod->root, &bbox, &gc, NR_ARENA_ITEM_STATE_ALL, NR_ARENA_ITEM_STATE_NONE);
333 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);
335 /* Blitter goes here */
336 bmInfo.bmiHeader.biWidth = bbox.x1 - bbox.x0;
337 bmInfo.bmiHeader.biHeight = -(bbox.y1 - bbox.y0);
339 memset (px, 0xff, 4 * num_rows * width);
340 /* Render */
341 nr_arena_item_invoke_render (NULL, mod->root, &bbox, &pb, 0);
343 /* Swap red and blue channels; we use RGBA, whereas
344 * the Win32 GDI uses BGRx.
345 */
346 for ( i = 0 ; i < num_rows * width ; i++ ) {
347 unsigned char temp=px[i*4];
348 px[i*4] = px[i*4+2];
349 px[i*4+2] = temp;
350 }
352 SetStretchBltMode(_hDC, COLORONCOLOR);
353 res = StretchDIBits (_hDC,
354 bbox.x0 - x0, bbox.y0 - y0, bbox.x1 - bbox.x0, bbox.y1 - bbox.y0,
355 0, 0, bbox.x1 - bbox.x0, bbox.y1 - bbox.y0,
356 px,
357 &bmInfo,
358 DIB_RGB_COLORS,
359 SRCCOPY);
361 /* Blitter ends here */
363 nr_pixblock_release (&pb);
364 }
366 g_free (px);
368 res = EndPage (_hDC);
369 res = EndDoc (_hDC);
371 SPWin32Modal = FALSE;
373 return 0;
374 }
376 /* File dialogs */
378 char *
379 PrintWin32::get_open_filename (unsigned char *dir, unsigned char *filter, unsigned char *title)
380 {
381 char fnbuf[4096] = {0};
382 OPENFILENAME ofn = {
383 sizeof (OPENFILENAME),
384 NULL, /* hwndOwner */
385 NULL, /* hInstance */
386 (const CHAR *)filter, /* lpstrFilter */
387 NULL, /* lpstrCustomFilter */
388 0, /* nMaxCustFilter */
389 1, /* nFilterIndex */
390 fnbuf, /* lpstrFile */
391 sizeof (fnbuf), /* nMaxFile */
392 NULL, /* lpstrFileTitle */
393 0, /* nMaxFileTitle */
394 (const CHAR *)dir, /* lpstrInitialDir */
395 (const CHAR *)title, /* lpstrTitle */
396 OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY, /* Flags */
397 0, /* nFileOffset */
398 0, /* nFileExtension */
399 NULL, /* lpstrDefExt */
400 0, /* lCustData */
401 NULL, /* lpfnHook */
402 NULL /* lpTemplateName */
403 };
404 int retval;
405 UINT_PTR timer;
407 SPWin32Modal = TRUE;
408 timer = SetTimer (NULL, 0, 40, my_timer);
410 retval = GetOpenFileName (&ofn);
412 KillTimer (NULL, timer);
413 SPWin32Modal = FALSE;
415 if (!retval) {
416 int errcode;
417 errcode = CommDlgExtendedError();
418 return NULL;
419 }
420 return g_strdup (fnbuf);
421 }
423 char *
424 PrintWin32::get_write_filename (unsigned char *dir, unsigned char *filter, unsigned char *title)
425 {
426 return NULL;
427 }
429 char *
430 PrintWin32::get_save_filename (unsigned char *dir, unsigned int *spns)
431 {
432 char fnbuf[4096] = {0};
433 OPENFILENAME ofn = {
434 sizeof (OPENFILENAME),
435 NULL, /* hwndOwner */
436 NULL, /* hInstance */
437 "Inkscape SVG (*.svg)\0*\0Plain SVG (*.svg)\0*\0", /* lpstrFilter */
438 NULL, /* lpstrCustomFilter */
439 0, /* nMaxCustFilter */
440 1, /* nFilterIndex */
441 fnbuf, /* lpstrFile */
442 sizeof (fnbuf), /* nMaxFile */
443 NULL, /* lpstrFileTitle */
444 0, /* nMaxFileTitle */
445 (const CHAR *)dir, /* lpstrInitialDir */
446 "Save document to file", /* lpstrTitle */
447 OFN_HIDEREADONLY, /* Flags */
448 0, /* nFileOffset */
449 0, /* nFileExtension */
450 NULL, /* lpstrDefExt */
451 0, /* lCustData */
452 NULL, /* lpfnHook */
453 NULL /* lpTemplateName */
454 };
455 int retval;
456 UINT_PTR timer;
458 SPWin32Modal = TRUE;
459 timer = SetTimer (NULL, 0, 40, my_timer);
461 retval = GetSaveFileName (&ofn);
463 KillTimer (NULL, timer);
464 SPWin32Modal = FALSE;
466 if (!retval) {
467 int errcode;
468 errcode = CommDlgExtendedError();
469 return NULL;
470 }
471 *spns = (ofn.nFilterIndex != 2);
472 return g_strdup (fnbuf);
473 }
475 #include "clear-n_.h"
477 void
478 PrintWin32::init (void)
479 {
480 Inkscape::Extension::Extension * ext;
482 /* SVG in */
483 ext = Inkscape::Extension::build_from_mem(
484 "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
485 "<name>" N_("Windows 32-bit Print") "</name>\n"
486 "<id>" SP_MODULE_KEY_PRINT_WIN32 "</id>\n"
487 "<param name=\"textToPath\" type=\"boolean\">true</param>\n"
488 "<print/>\n"
489 "</inkscape-extension>", new PrintWin32());
491 return;
492 }
494 } /* namespace Internal */
495 } /* namespace Extension */
496 } /* namespace Inkscape */
498 #endif // ifdef WIN32
500 /*
501 Local Variables:
502 mode:c++
503 c-file-style:"stroustrup"
504 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
505 indent-tabs-mode:nil
506 fill-column:99
507 End:
508 */
509 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :