1 /** @file
2 * @brief Windows-specific stuff
3 */
4 /* Author:
5 * Lauris Kaplinski <lauris@kaplinski.com>
6 * Abhishek Sharma
7 *
8 * This code is in public domain
9 */
11 #ifdef WIN32
13 #ifdef HAVE_CONFIG_H
14 # include "config.h"
15 #endif
17 #include <glib/gmem.h>
18 #include <libnr/nr-macros.h>
19 #include <2geom/transforms.h>
21 #include "display/nr-arena-item.h"
22 #include "display/nr-arena.h"
23 #include "document.h"
25 #include "win32.h"
26 #include "extension/system.h"
27 #include "extension/print.h"
28 #include <gtk/gtk.h>
30 /* Initialization */
32 namespace Inkscape {
33 namespace Extension {
34 namespace Internal {
36 static unsigned int SPWin32Modal = FALSE;
38 /**
39 * Callback function.. not a method
40 */
41 static void
42 my_gdk_event_handler (GdkEvent *event)
43 {
44 if (SPWin32Modal) {
45 /* Win32 widget is modal, filter events */
46 switch (event->type) {
47 case GDK_NOTHING:
48 case GDK_DELETE:
49 case GDK_SCROLL:
50 case GDK_BUTTON_PRESS:
51 case GDK_2BUTTON_PRESS:
52 case GDK_3BUTTON_PRESS:
53 case GDK_BUTTON_RELEASE:
54 case GDK_KEY_PRESS:
55 case GDK_KEY_RELEASE:
56 case GDK_DRAG_STATUS:
57 case GDK_DRAG_ENTER:
58 case GDK_DRAG_LEAVE:
59 case GDK_DRAG_MOTION:
60 case GDK_DROP_START:
61 case GDK_DROP_FINISHED:
62 return;
63 break;
64 default:
65 break;
66 }
67 }
68 gtk_main_do_event (event);
69 }
71 void
72 PrintWin32::main_init (int argc, char **argv, const char *name)
73 {
74 gdk_event_handler_set ((GdkEventFunc) my_gdk_event_handler, NULL, NULL);
75 }
77 void
78 PrintWin32::finish (void)
79 {
80 }
82 #define SP_FOREIGN_MAX_ITER 10
85 /**
86 * Callback function.. not a method
87 */
88 static VOID CALLBACK
89 my_timer (HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
90 {
91 int cdown = 0;
92 while ((cdown++ < SP_FOREIGN_MAX_ITER) && gdk_events_pending ()) {
93 gtk_main_iteration_do (FALSE);
94 }
95 gtk_main_iteration_do (FALSE);
96 }
99 /* Platform detection */
101 gboolean
102 PrintWin32::is_os_wide()
103 {
104 static gboolean initialized = FALSE;
105 static gboolean is_wide = FALSE;
106 static OSVERSIONINFOA osver;
108 if ( !initialized )
109 {
110 BOOL result;
112 initialized = TRUE;
114 memset (&osver, 0, sizeof(OSVERSIONINFOA));
115 osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
116 result = GetVersionExA (&osver);
117 if (result)
118 {
119 if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT)
120 is_wide = TRUE;
121 }
122 // If we can't even call to get the version, fall back to ANSI API
123 }
125 return is_wide;
126 }
129 /* Printing */
131 PrintWin32::PrintWin32 (void)
132 {
133 /* Nothing here */
134 }
137 PrintWin32::~PrintWin32 (void)
138 {
139 DeleteDC (_hDC);
140 }
143 /**
144 * Callback function.. not a method
145 */
146 static UINT_PTR CALLBACK
147 print_hook (HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
148 {
149 #if 0
150 int cdown = 0;
151 while ((cdown++ < SP_FOREIGN_MAX_ITER) && gdk_events_pending ()) {
152 gtk_main_iteration_do (FALSE);
153 }
154 gtk_main_iteration_do (FALSE);
155 #endif
156 return 0;
157 }
159 unsigned int
160 PrintWin32::setup (Inkscape::Extension::Print *mod)
161 {
162 HRESULT res;
163 PRINTDLG pd = {
164 sizeof (PRINTDLG),
165 NULL, /* hwndOwner */
166 NULL, /* hDevMode */
167 NULL, /* hDevNames */
168 NULL, /* hDC */
169 PD_NOPAGENUMS | PD_NOSELECTION | PD_RETURNDC | PD_USEDEVMODECOPIESANDCOLLATE, /* Flags */
170 1, 1, 1, 1, /* nFromPage, nToPage, nMinPage, nMaxPage */
171 1, /* nCoies */
172 NULL, /* hInstance */
173 0, /* lCustData */
174 NULL, NULL, NULL, NULL, NULL, NULL
175 };
176 UINT_PTR timer;
178 SPWin32Modal = TRUE;
179 pd.Flags |= PD_ENABLEPRINTHOOK;
180 pd.lpfnPrintHook = print_hook;
181 timer = SetTimer (NULL, 0, 40, my_timer);
183 res = PrintDlg (&pd);
185 KillTimer (NULL, timer);
186 SPWin32Modal = FALSE;
188 if (!res) return FALSE;
190 _hDC = pd.hDC;
192 #if 0
193 caps = GetDeviceCaps (_hDC, RASTERCAPS);
194 if (caps & RC_BANDING) {
195 printf ("needs banding\n");
196 }
197 if (caps & RC_BITBLT) {
198 printf ("does bitblt\n");
199 }
200 if (caps & RC_DIBTODEV) {
201 printf ("does dibtodev\n");
202 }
203 if (caps & RC_STRETCHDIB) {
204 printf ("does stretchdib\n");
205 }
206 #endif
207 if (pd.hDevMode) {
208 DEVMODE *devmodep;
209 devmodep = (DEVMODE *)pd.hDevMode;
210 if (devmodep->dmFields & DM_ORIENTATION) {
211 _landscape = (devmodep->dmOrientation == DMORIENT_LANDSCAPE);
212 }
213 }
215 return TRUE;
216 }
218 unsigned int
219 PrintWin32::begin (Inkscape::Extension::Print *mod, SPDocument *doc)
220 {
221 DOCINFO di = {
222 sizeof (DOCINFO),
223 NULL, /* lpszDocName */
224 NULL, /* lpszOutput */
225 NULL, /* lpszDatatype */
226 0 /* DI_APPBANDING */ /* fwType */
227 };
228 int res;
230 _PageWidth = doc->getWidth ();
231 _PageHeight = doc->getHeight ();
233 di.lpszDocName = doc->getName();
235 SPWin32Modal = TRUE;
237 res = StartDoc (_hDC, &di);
238 res = StartPage (_hDC);
240 SPWin32Modal = FALSE;
242 return 0;
243 }
245 unsigned int
246 PrintWin32::finish (Inkscape::Extension::Print *mod)
247 {
248 int dpiX, dpiY;
249 int pPhysicalWidth, pPhysicalHeight;
250 int pPhysicalOffsetX, pPhysicalOffsetY;
251 int pPrintableWidth, pPrintableHeight;
252 float scalex, scaley;
253 int x0, y0, x1, y1;
254 int width, height;
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 Geom::Matrix affine = Geom::Scale(scalex / 1.25, scaley / 1.25);
298 nr_arena_item_set_transform (mod->root, affine);
300 // Calculate printable area in device coordinates
301 x0 = pPhysicalOffsetX;
302 y0 = pPhysicalOffsetY;
303 x1 = x0 + pPrintableWidth;
304 y1 = y0 + pPrintableHeight;
305 x1 = MIN (x1, (int) (_PageWidth * scalex));
306 y1 = MIN (y1, (int) (_PageHeight * scaley));
308 width = x1 - x0;
309 height = y1 - y0;
311 px = g_new (unsigned char, 4 * 64 * width);
312 sheight = 64;
314 /* Printing goes here */
315 for (row = 0; row < height; row += 64) {
316 NRPixBlock pb;
317 NRRectL bbox;
318 NRGC gc(NULL);
319 int num_rows;
320 int i;
322 num_rows = sheight;
323 if ((row + num_rows) > height) num_rows = height - row;
325 /* Set area of interest */
326 bbox.x0 = x0;
327 bbox.y0 = y0 + row;
328 bbox.x1 = bbox.x0 + width;
329 bbox.y1 = bbox.y0 + num_rows;
330 /* Update to renderable state */
331 gc.transform.setIdentity();
332 nr_arena_item_invoke_update (mod->root, &bbox, &gc, NR_ARENA_ITEM_STATE_ALL, NR_ARENA_ITEM_STATE_NONE);
334 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);
336 /* Blitter goes here */
337 bmInfo.bmiHeader.biWidth = bbox.x1 - bbox.x0;
338 bmInfo.bmiHeader.biHeight = -(bbox.y1 - bbox.y0);
340 memset (px, 0xff, 4 * num_rows * width);
341 /* Render */
342 nr_arena_item_invoke_render (NULL, mod->root, &bbox, &pb, 0);
344 /* Swap red and blue channels; we use RGBA, whereas
345 * the Win32 GDI uses BGRx.
346 */
347 for ( i = 0 ; i < num_rows * width ; i++ ) {
348 unsigned char temp=px[i*4];
349 px[i*4] = px[i*4+2];
350 px[i*4+2] = temp;
351 }
353 SetStretchBltMode(_hDC, COLORONCOLOR);
354 res = StretchDIBits (_hDC,
355 bbox.x0 - x0, bbox.y0 - y0, bbox.x1 - bbox.x0, bbox.y1 - bbox.y0,
356 0, 0, bbox.x1 - bbox.x0, bbox.y1 - bbox.y0,
357 px,
358 &bmInfo,
359 DIB_RGB_COLORS,
360 SRCCOPY);
362 /* Blitter ends here */
364 nr_pixblock_release (&pb);
365 }
367 g_free (px);
369 res = EndPage (_hDC);
370 res = EndDoc (_hDC);
372 SPWin32Modal = FALSE;
374 return 0;
375 }
377 /* File dialogs */
379 char *
380 PrintWin32::get_open_filename (unsigned char *dir, unsigned char *filter, unsigned char *title)
381 {
382 char fnbuf[4096] = {0};
383 OPENFILENAME ofn = {
384 sizeof (OPENFILENAME),
385 NULL, /* hwndOwner */
386 NULL, /* hInstance */
387 (const CHAR *)filter, /* lpstrFilter */
388 NULL, /* lpstrCustomFilter */
389 0, /* nMaxCustFilter */
390 1, /* nFilterIndex */
391 fnbuf, /* lpstrFile */
392 sizeof (fnbuf), /* nMaxFile */
393 NULL, /* lpstrFileTitle */
394 0, /* nMaxFileTitle */
395 (const CHAR *)dir, /* lpstrInitialDir */
396 (const CHAR *)title, /* lpstrTitle */
397 OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY, /* Flags */
398 0, /* nFileOffset */
399 0, /* nFileExtension */
400 NULL, /* lpstrDefExt */
401 0, /* lCustData */
402 NULL, /* lpfnHook */
403 NULL /* lpTemplateName */
404 };
405 int retval;
406 UINT_PTR timer;
408 SPWin32Modal = TRUE;
409 timer = SetTimer (NULL, 0, 40, my_timer);
411 retval = GetOpenFileName (&ofn);
413 KillTimer (NULL, timer);
414 SPWin32Modal = FALSE;
416 if (!retval) {
417 int errcode;
418 errcode = CommDlgExtendedError();
419 return NULL;
420 }
421 return g_strdup (fnbuf);
422 }
424 char *
425 PrintWin32::get_write_filename (unsigned char *dir, unsigned char *filter, unsigned char *title)
426 {
427 return NULL;
428 }
430 char *
431 PrintWin32::get_save_filename (unsigned char *dir, unsigned int *spns)
432 {
433 char fnbuf[4096] = {0};
434 OPENFILENAME ofn = {
435 sizeof (OPENFILENAME),
436 NULL, /* hwndOwner */
437 NULL, /* hInstance */
438 "Inkscape SVG (*.svg)\0*\0Plain SVG (*.svg)\0*\0", /* lpstrFilter */
439 NULL, /* lpstrCustomFilter */
440 0, /* nMaxCustFilter */
441 1, /* nFilterIndex */
442 fnbuf, /* lpstrFile */
443 sizeof (fnbuf), /* nMaxFile */
444 NULL, /* lpstrFileTitle */
445 0, /* nMaxFileTitle */
446 (const CHAR *)dir, /* lpstrInitialDir */
447 "Save document to file", /* lpstrTitle */
448 OFN_HIDEREADONLY, /* Flags */
449 0, /* nFileOffset */
450 0, /* nFileExtension */
451 NULL, /* lpstrDefExt */
452 0, /* lCustData */
453 NULL, /* lpfnHook */
454 NULL /* lpTemplateName */
455 };
456 int retval;
457 UINT_PTR timer;
459 SPWin32Modal = TRUE;
460 timer = SetTimer (NULL, 0, 40, my_timer);
462 retval = GetSaveFileName (&ofn);
464 KillTimer (NULL, timer);
465 SPWin32Modal = FALSE;
467 if (!retval) {
468 int errcode;
469 errcode = CommDlgExtendedError();
470 return NULL;
471 }
472 *spns = (ofn.nFilterIndex != 2);
473 return g_strdup (fnbuf);
474 }
476 #include "clear-n_.h"
478 void
479 PrintWin32::init (void)
480 {
481 Inkscape::Extension::Extension * ext;
483 /* SVG in */
484 ext = Inkscape::Extension::build_from_mem(
485 "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
486 "<name>" N_("Windows 32-bit Print") "</name>\n"
487 "<id>" SP_MODULE_KEY_PRINT_WIN32 "</id>\n"
488 "<param name=\"textToPath\" type=\"boolean\">true</param>\n"
489 "<print/>\n"
490 "</inkscape-extension>", new PrintWin32());
492 return;
493 }
495 } /* namespace Internal */
496 } /* namespace Extension */
497 } /* namespace Inkscape */
499 #endif // ifdef WIN32
501 /*
502 Local Variables:
503 mode:c++
504 c-file-style:"stroustrup"
505 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
506 indent-tabs-mode:nil
507 fill-column:99
508 End:
509 */
510 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :