comparison src/device-msw.c @ 442:abe6d1db359e r21-2-36

Import from CVS: tag r21-2-36
author cvs
date Mon, 13 Aug 2007 11:35:02 +0200
parents 8de8e3f6228a
children 1ccc32a20af4
comparison
equal deleted inserted replaced
441:72a7cfa4a488 442:abe6d1db359e
32 #include <config.h> 32 #include <config.h>
33 #include "lisp.h" 33 #include "lisp.h"
34 34
35 #include "console-msw.h" 35 #include "console-msw.h"
36 #include "console-stream.h" 36 #include "console-stream.h"
37 #include "objects-msw.h"
37 #include "events.h" 38 #include "events.h"
38 #include "faces.h" 39 #include "faces.h"
39 #include "frame.h" 40 #include "frame.h"
40 #include "sysdep.h" 41 #include "sysdep.h"
41 42
42 #include <winspool.h> 43 #include <commdlg.h>
44
45 #if !(defined (CYGWIN) || defined(MINGW))
46 #include <objbase.h> /* For CoInitialize */
47 #endif
43 48
44 /* win32 DDE management library globals */ 49 /* win32 DDE management library globals */
45 #ifdef HAVE_DRAGNDROP 50 #ifdef HAVE_DRAGNDROP
46 DWORD mswindows_dde_mlid; 51 DWORD mswindows_dde_mlid;
47 HSZ mswindows_dde_service; 52 HSZ mswindows_dde_service;
51 56
52 /* Control conversion of upper case file names to lower case. 57 /* Control conversion of upper case file names to lower case.
53 nil means no, t means yes. */ 58 nil means no, t means yes. */
54 Lisp_Object Vmswindows_downcase_file_names; 59 Lisp_Object Vmswindows_downcase_file_names;
55 60
56 /* Control whether stat() attempts to determine file type and link count 61 /* Control whether xemacs_stat() attempts to determine file type and link count
57 exactly, at the expense of slower operation. Since true hard links 62 exactly, at the expense of slower operation. Since true hard links
58 are supported on NTFS volumes, this is only relevant on NT. */ 63 are supported on NTFS volumes, this is only relevant on NT. */
59 Lisp_Object Vmswindows_get_true_file_attributes; 64 Lisp_Object Vmswindows_get_true_file_attributes;
60 65
61 Lisp_Object Qinit_pre_mswindows_win, Qinit_post_mswindows_win; 66 Lisp_Object Qinit_pre_mswindows_win, Qinit_post_mswindows_win;
62 67 Lisp_Object Qdevmodep;
68
69 static Lisp_Object allocate_devmode (DEVMODE* src_devmode, int do_copy,
70 char* src_name, struct device *d);
63 71
64 /************************************************************************/ 72 /************************************************************************/
65 /* helpers */ 73 /* helpers */
66 /************************************************************************/ 74 /************************************************************************/
67 75
68 static Lisp_Object 76 static Lisp_Object
69 build_syscolor_string (int idx) 77 build_syscolor_string (int idx)
70 { 78 {
71 DWORD clr; 79 return (idx < 0 ? Qnil : mswindows_color_to_string (GetSysColor (idx)));
72 char buf[16];
73
74 if (idx < 0)
75 return Qnil;
76
77 clr = GetSysColor (idx);
78 sprintf (buf, "#%02X%02X%02X",
79 GetRValue (clr),
80 GetGValue (clr),
81 GetBValue (clr));
82 return build_string (buf);
83 } 80 }
84 81
85 static Lisp_Object 82 static Lisp_Object
86 build_syscolor_cons (int index1, int index2) 83 build_syscolor_cons (int index1, int index2)
87 { 84 {
105 { 102 {
106 return Fcons (index1 < 0 ? Qnil : make_int (GetDeviceCaps (hdc, index1)), 103 return Fcons (index1 < 0 ? Qnil : make_int (GetDeviceCaps (hdc, index1)),
107 index2 < 0 ? Qnil : make_int (GetDeviceCaps (hdc, index2))); 104 index2 < 0 ? Qnil : make_int (GetDeviceCaps (hdc, index2)));
108 } 105 }
109 106
110
111 107
112 /************************************************************************/ 108 /************************************************************************/
113 /* display methods */ 109 /* display methods */
114 /************************************************************************/ 110 /************************************************************************/
115 111
125 init_one_device (d); 121 init_one_device (d);
126 122
127 d->device_data = xnew_and_zero (struct mswindows_device); 123 d->device_data = xnew_and_zero (struct mswindows_device);
128 hdc = CreateCompatibleDC (NULL); 124 hdc = CreateCompatibleDC (NULL);
129 assert (hdc!=NULL); 125 assert (hdc!=NULL);
130 DEVICE_MSWINDOWS_LOGPIXELSX(d) = GetDeviceCaps(hdc, LOGPIXELSX); 126 DEVICE_MSWINDOWS_HCDC(d) = hdc;
131 DEVICE_MSWINDOWS_LOGPIXELSY(d) = GetDeviceCaps(hdc, LOGPIXELSY);
132 DEVICE_MSWINDOWS_PLANES(d) = GetDeviceCaps(hdc, PLANES);
133 /* #### SIZEPALETTE only valid if RC_PALETTE bit set in RASTERCAPS,
134 what should we return for a non-palette-based device? */
135 DEVICE_MSWINDOWS_CELLS(d) = GetDeviceCaps(hdc, SIZEPALETTE);
136 DEVICE_MSWINDOWS_HORZRES(d) = GetDeviceCaps(hdc, HORZRES);
137 DEVICE_MSWINDOWS_VERTRES(d) = GetDeviceCaps(hdc, VERTRES);
138 DEVICE_MSWINDOWS_HORZSIZE(d) = GetDeviceCaps(hdc, HORZSIZE);
139 DEVICE_MSWINDOWS_VERTSIZE(d) = GetDeviceCaps(hdc, VERTSIZE);
140 DEVICE_MSWINDOWS_BITSPIXEL(d) = GetDeviceCaps(hdc, BITSPIXEL);
141 DEVICE_MSWINDOWS_FONTLIST (d) = mswindows_enumerate_fonts (hdc); 127 DEVICE_MSWINDOWS_FONTLIST (d) = mswindows_enumerate_fonts (hdc);
142 128 DEVICE_MSWINDOWS_UPDATE_TICK (d) = GetTickCount ();
143 DeleteDC (hdc);
144 129
145 /* Register the main window class */ 130 /* Register the main window class */
146 wc.cbSize = sizeof (WNDCLASSEX); 131 wc.cbSize = sizeof (WNDCLASSEX);
147 wc.style = CS_OWNDC; /* One DC per window */ 132 wc.style = CS_OWNDC; /* One DC per window */
148 wc.lpfnWndProc = (WNDPROC) mswindows_wnd_proc; 133 wc.lpfnWndProc = (WNDPROC) mswindows_wnd_proc;
149 wc.cbClsExtra = 0; 134 wc.cbClsExtra = 0;
150 wc.cbWndExtra = MSWINDOWS_WINDOW_EXTRA_BYTES; 135 wc.cbWndExtra = MSWINDOWS_WINDOW_EXTRA_BYTES;
151 /* This must match whatever is passed to CreateWIndowEx, NULL is ok 136 /* This must match whatever is passed to CreateWIndowEx, NULL is ok
152 for this. */ 137 for this. */
153 wc.hInstance = NULL; 138 wc.hInstance = NULL;
154 wc.hIcon = LoadIcon (GetModuleHandle(NULL), XEMACS_CLASS); 139 wc.hIcon = LoadIcon (GetModuleHandle(NULL), XEMACS_CLASS);
155 wc.hCursor = LoadCursor (NULL, IDC_ARROW); 140 wc.hCursor = LoadCursor (NULL, IDC_ARROW);
156 /* Background brush is only used during sizing, when XEmacs cannot 141 /* Background brush is only used during sizing, when XEmacs cannot
157 take over */ 142 take over */
158 wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1); 143 wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
159 wc.lpszMenuName = NULL; 144 wc.lpszMenuName = NULL;
160 145
161 wc.lpszClassName = XEMACS_CLASS; 146 wc.lpszClassName = XEMACS_CLASS;
162 wc.hIconSm = LoadImage (GetModuleHandle (NULL), XEMACS_CLASS, 147 if (xLoadImageA) /* not in NT 3.5 */
163 IMAGE_ICON, 16, 16, 0); 148 wc.hIconSm = (HICON) xLoadImageA (GetModuleHandle (NULL), XEMACS_CLASS,
164 RegisterClassEx (&wc); 149 IMAGE_ICON, 16, 16, 0);
150 else
151 wc.hIconSm = 0;
152
153 if (xRegisterClassExA) /* not in NT 3.5 */
154 xRegisterClassExA (&wc);
155 else
156 RegisterClassA ((WNDCLASS *) &wc.style);
165 157
166 #ifdef HAVE_WIDGETS 158 #ifdef HAVE_WIDGETS
167 xzero (wc); 159 xzero (wc);
168 /* Register the main window class */ 160 /* Register the main window class */
169 wc.cbSize = sizeof (WNDCLASSEX); 161 wc.cbSize = sizeof (WNDCLASSEX);
170 wc.lpfnWndProc = (WNDPROC) mswindows_control_wnd_proc; 162 wc.lpfnWndProc = (WNDPROC) mswindows_control_wnd_proc;
171 wc.lpszClassName = XEMACS_CONTROL_CLASS; 163 wc.lpszClassName = XEMACS_CONTROL_CLASS;
172 wc.hInstance = NULL; 164 wc.hInstance = NULL;
173 RegisterClassEx (&wc); 165 if (xRegisterClassExA) /* not in NT 3.5 */
166 xRegisterClassExA (&wc);
167 else
168 RegisterClassA ((WNDCLASS *) &wc.style);
174 #endif 169 #endif
175 170
176 #if defined (HAVE_TOOLBARS) || defined (HAVE_WIDGETS) 171 #if defined (HAVE_TOOLBARS) || defined (HAVE_WIDGETS)
177 InitCommonControls (); 172 InitCommonControls ();
178 #endif 173 #endif
182 mswindows_finish_init_device (struct device *d, Lisp_Object props) 177 mswindows_finish_init_device (struct device *d, Lisp_Object props)
183 { 178 {
184 /* Initialize DDE management library and our related globals. We execute a 179 /* Initialize DDE management library and our related globals. We execute a
185 * dde Open("file") by simulating a drop, so this depends on dnd support. */ 180 * dde Open("file") by simulating a drop, so this depends on dnd support. */
186 #ifdef HAVE_DRAGNDROP 181 #ifdef HAVE_DRAGNDROP
182 # if !(defined(CYGWIN) || defined(MINGW))
183 CoInitialize (NULL);
184 # endif
185
187 mswindows_dde_mlid = 0; 186 mswindows_dde_mlid = 0;
188 DdeInitialize (&mswindows_dde_mlid, (PFNCALLBACK)mswindows_dde_callback, 187 DdeInitialize (&mswindows_dde_mlid, (PFNCALLBACK)mswindows_dde_callback,
189 APPCMD_FILTERINITS|CBF_FAIL_SELFCONNECTIONS|CBF_FAIL_ADVISES| 188 APPCMD_FILTERINITS|CBF_FAIL_SELFCONNECTIONS|CBF_FAIL_ADVISES|
190 CBF_FAIL_POKES|CBF_FAIL_REQUESTS|CBF_SKIP_ALLNOTIFICATIONS, 0); 189 CBF_FAIL_POKES|CBF_FAIL_REQUESTS|CBF_SKIP_ALLNOTIFICATIONS,
191 190 0);
192 mswindows_dde_service = DdeCreateStringHandle (mswindows_dde_mlid, XEMACS_CLASS, 0); 191
193 mswindows_dde_topic_system = DdeCreateStringHandle (mswindows_dde_mlid, SZDDESYS_TOPIC, 0); 192 mswindows_dde_service = DdeCreateStringHandle (mswindows_dde_mlid,
193 XEMACS_CLASS, 0);
194 mswindows_dde_topic_system = DdeCreateStringHandle (mswindows_dde_mlid,
195 SZDDESYS_TOPIC, 0);
194 mswindows_dde_item_open = DdeCreateStringHandle (mswindows_dde_mlid, 196 mswindows_dde_item_open = DdeCreateStringHandle (mswindows_dde_mlid,
195 TEXT(MSWINDOWS_DDE_ITEM_OPEN), 0); 197 TEXT(MSWINDOWS_DDE_ITEM_OPEN), 0);
196 DdeNameService (mswindows_dde_mlid, mswindows_dde_service, 0L, DNS_REGISTER); 198 DdeNameService (mswindows_dde_mlid, mswindows_dde_service, 0L, DNS_REGISTER);
197 #endif 199 #endif
198 } 200 }
199 201
200 static void 202 static void
201 mswindows_delete_device (struct device *d) 203 mswindows_delete_device (struct device *d)
202 { 204 {
203 #ifdef HAVE_DRAGNDROP 205 #ifdef HAVE_DRAGNDROP
204 DdeNameService (mswindows_dde_mlid, 0L, 0L, DNS_REGISTER); 206 DdeNameService (mswindows_dde_mlid, 0L, 0L, DNS_UNREGISTER);
207 DdeFreeStringHandle (mswindows_dde_mlid, mswindows_dde_item_open);
208 DdeFreeStringHandle (mswindows_dde_mlid, mswindows_dde_topic_system);
209 DdeFreeStringHandle (mswindows_dde_mlid, mswindows_dde_service);
205 DdeUninitialize (mswindows_dde_mlid); 210 DdeUninitialize (mswindows_dde_mlid);
211
212 # if !(defined(CYGWIN) || defined(MINGW))
213 CoUninitialize ();
214 # endif
206 #endif 215 #endif
207 216
208 free (d->device_data); 217 DeleteDC (DEVICE_MSWINDOWS_HCDC(d));
218 xfree (d->device_data);
219 }
220
221 void
222 mswindows_get_workspace_coords (RECT *rc)
223 {
224 SystemParametersInfo (SPI_GETWORKAREA, 0, rc, 0);
209 } 225 }
210 226
211 static void 227 static void
212 mswindows_mark_device (struct device *d) 228 mswindows_mark_device (struct device *d)
213 { 229 {
216 232
217 static Lisp_Object 233 static Lisp_Object
218 mswindows_device_system_metrics (struct device *d, 234 mswindows_device_system_metrics (struct device *d,
219 enum device_metrics m) 235 enum device_metrics m)
220 { 236 {
237 const HDC hdc = DEVICE_MSWINDOWS_HCDC(d);
238
221 switch (m) 239 switch (m)
222 { 240 {
223 case DM_size_device: 241 case DM_size_device:
224 return Fcons (make_int (DEVICE_MSWINDOWS_HORZRES(d)), 242 return Fcons (make_int (GetDeviceCaps (hdc, HORZRES)),
225 make_int (DEVICE_MSWINDOWS_VERTRES(d))); 243 make_int (GetDeviceCaps (hdc, VERTRES)));
226 break; 244 break;
227 case DM_device_dpi: 245 case DM_device_dpi:
228 return Fcons (make_int (DEVICE_MSWINDOWS_LOGPIXELSX(d)), 246 return Fcons (make_int (GetDeviceCaps (hdc, LOGPIXELSX)),
229 make_int (DEVICE_MSWINDOWS_LOGPIXELSY(d))); 247 make_int (GetDeviceCaps (hdc, LOGPIXELSY)));
230 break; 248 break;
231 case DM_size_device_mm: 249 case DM_size_device_mm:
232 return Fcons (make_int (DEVICE_MSWINDOWS_HORZSIZE(d)), 250 return Fcons (make_int (GetDeviceCaps (hdc, HORZSIZE)),
233 make_int (DEVICE_MSWINDOWS_VERTSIZE(d))); 251 make_int (GetDeviceCaps (hdc, VERTSIZE)));
234 break; 252 break;
235 case DM_num_bit_planes: 253 case DM_num_bit_planes:
236 /* this is what X means by bitplanes therefore we ought to be 254 /* this is what X means by bitplanes therefore we ought to be
237 consistent. num planes is always 1 under mswindows and 255 consistent. num planes is always 1 under mswindows and
238 therefore useless */ 256 therefore useless */
239 return make_int (DEVICE_MSWINDOWS_BITSPIXEL(d)); 257 return make_int (GetDeviceCaps (hdc, BITSPIXEL));
240 break; 258 break;
241 case DM_num_color_cells: 259 case DM_num_color_cells:
242 return make_int (DEVICE_MSWINDOWS_CELLS(d)); 260 /* #### SIZEPALETTE only valid if RC_PALETTE bit set in RASTERCAPS,
261 what should we return for a non-palette-based device? */
262 return make_int (GetDeviceCaps (hdc, SIZEPALETTE));
243 break; 263 break;
244 264
245 /*** Colors ***/ 265 /*** Colors ***/
246 #define FROB(met, index1, index2) \ 266 #define FROB(met, fore, back) \
247 case DM_##met: \ 267 case DM_##met: \
248 return build_syscolor_cons (index1, index2); 268 return build_syscolor_cons (fore, back);
249 269
250 FROB (color_default, COLOR_WINDOW, COLOR_WINDOWTEXT); 270 FROB (color_default, COLOR_WINDOWTEXT, COLOR_WINDOW);
251 FROB (color_select, COLOR_HIGHLIGHT, COLOR_HIGHLIGHTTEXT); 271 FROB (color_select, COLOR_HIGHLIGHTTEXT, COLOR_HIGHLIGHT);
252 FROB (color_balloon, COLOR_INFOBK, COLOR_INFOTEXT); 272 FROB (color_balloon, COLOR_INFOTEXT, COLOR_INFOBK);
253 FROB (color_3d_face, COLOR_3DFACE, COLOR_BTNTEXT); 273 FROB (color_3d_face, COLOR_BTNTEXT, COLOR_BTNFACE);
254 FROB (color_3d_light, COLOR_3DLIGHT, COLOR_3DHILIGHT); 274 FROB (color_3d_light, COLOR_3DHILIGHT, COLOR_3DLIGHT);
255 FROB (color_3d_dark, COLOR_3DSHADOW, COLOR_3DDKSHADOW); 275 FROB (color_3d_dark, COLOR_3DDKSHADOW, COLOR_3DSHADOW);
256 FROB (color_menu, COLOR_MENU, COLOR_MENUTEXT); 276 FROB (color_menu, COLOR_MENUTEXT, COLOR_MENU);
257 FROB (color_menu_highlight, COLOR_HIGHLIGHT, COLOR_HIGHLIGHTTEXT); 277 FROB (color_menu_highlight, COLOR_HIGHLIGHTTEXT, COLOR_HIGHLIGHT);
258 FROB (color_menu_button, COLOR_MENU, COLOR_MENUTEXT); 278 FROB (color_menu_button, COLOR_MENUTEXT, COLOR_MENU);
259 FROB (color_menu_disabled, COLOR_MENU, COLOR_GRAYTEXT); 279 FROB (color_menu_disabled, COLOR_GRAYTEXT, COLOR_MENU);
260 FROB (color_toolbar, COLOR_BTNFACE, COLOR_BTNTEXT); 280 FROB (color_toolbar, COLOR_BTNTEXT, COLOR_BTNFACE);
261 FROB (color_scrollbar, COLOR_SCROLLBAR, COLOR_CAPTIONTEXT); 281 FROB (color_scrollbar, COLOR_CAPTIONTEXT, COLOR_SCROLLBAR);
262 FROB (color_desktop, -1, COLOR_DESKTOP); 282 FROB (color_desktop, -1, COLOR_DESKTOP);
263 FROB (color_workspace, -1, COLOR_APPWORKSPACE); 283 FROB (color_workspace, -1, COLOR_APPWORKSPACE);
264 #undef FROB 284 #undef FROB
265 285
266 /*** Sizes ***/ 286 /*** Sizes ***/
276 #undef FROB 296 #undef FROB
277 297
278 case DM_size_workspace: 298 case DM_size_workspace:
279 { 299 {
280 RECT rc; 300 RECT rc;
281 SystemParametersInfo (SPI_GETWORKAREA, 0, &rc, 0); 301 mswindows_get_workspace_coords (&rc);
282 return Fcons (make_int (rc.right - rc.left), 302 return Fcons (make_int (rc.right - rc.left),
283 make_int (rc.bottom - rc.top)); 303 make_int (rc.bottom - rc.top));
284 } 304 }
305
306 case DM_offset_workspace:
307 {
308 RECT rc;
309 mswindows_get_workspace_coords (&rc);
310 return Fcons (make_int (rc.left), make_int (rc.top));
311 }
312
285 /* 313 /*
286 case DM_size_toolbar: 314 case DM_size_toolbar:
287 case DM_size_toolbar_button: 315 case DM_size_toolbar_button:
288 case DM_size_toolbar_border: 316 case DM_size_toolbar_border:
289 */ 317 */
312 return XDEVIMPF_PIXEL_GEOMETRY; 340 return XDEVIMPF_PIXEL_GEOMETRY;
313 } 341 }
314 342
315 343
316 /************************************************************************/ 344 /************************************************************************/
317 /* printer methods */ 345 /* printer helpers */
318 /************************************************************************/ 346 /************************************************************************/
319 347
320 static void 348 static void
321 signal_open_printer_error (struct device *d) 349 signal_open_printer_error (struct device *d)
322 { 350 {
323 signal_simple_error ("Failed to open printer", DEVICE_CONNECTION (d)); 351 invalid_operation ("Failed to open printer", DEVICE_CONNECTION (d));
324 } 352 }
325 353
326 static void 354
327 msprinter_init_device (struct device *d, Lisp_Object props) 355 /* Helper function */
328 { 356 static int
329 char* printer_name; 357 msprinter_init_device_internal (struct device *d, char* printer_name)
330 358 {
331 DEVICE_INFD (d) = DEVICE_OUTFD (d) = -1;
332
333 CHECK_STRING (DEVICE_CONNECTION (d));
334
335 TO_EXTERNAL_FORMAT (LISP_STRING, DEVICE_CONNECTION (d),
336 C_STRING_ALLOCA, printer_name,
337 Qctext);
338
339 d->device_data = xnew_and_zero (struct msprinter_device);
340
341 DEVICE_MSPRINTER_NAME(d) = xstrdup (printer_name); 359 DEVICE_MSPRINTER_NAME(d) = xstrdup (printer_name);
342 360
343 if (!OpenPrinter (printer_name, &DEVICE_MSPRINTER_HPRINTER (d), NULL)) 361 if (!OpenPrinter (printer_name, &DEVICE_MSPRINTER_HPRINTER (d), NULL))
344 { 362 {
345 DEVICE_MSPRINTER_HPRINTER (d) = NULL; 363 DEVICE_MSPRINTER_HPRINTER (d) = NULL;
346 signal_open_printer_error (d); 364 return 0;
347 } 365 }
348 366
349 DEVICE_MSPRINTER_HDC (d) = CreateDC ("WINSPOOL", printer_name, 367 DEVICE_MSPRINTER_HDC (d) = CreateDC ("WINSPOOL", printer_name,
350 NULL, NULL); 368 NULL, NULL);
351 if (DEVICE_MSPRINTER_HDC (d) == NULL) 369 if (DEVICE_MSPRINTER_HDC (d) == NULL)
352 signal_open_printer_error (d); 370 return 0;
353 371
354 /* Determinie DEVMODE size and store the default DEVMODE */ 372 DEVICE_MSPRINTER_HCDC(d) =
355 DEVICE_MSPRINTER_DEVMODE_SIZE(d) = 373 CreateCompatibleDC (DEVICE_MSPRINTER_HDC (d));
356 DocumentProperties (NULL, DEVICE_MSPRINTER_HPRINTER(d), 374
357 printer_name, NULL, NULL, 0); 375 DEVICE_CLASS (d) = (GetDeviceCaps (DEVICE_MSPRINTER_HDC (d), BITSPIXEL)
358 if (DEVICE_MSPRINTER_DEVMODE_SIZE(d) <= 0) 376 * GetDeviceCaps (DEVICE_MSPRINTER_HDC (d), PLANES)
359 signal_open_printer_error (d); 377 > 1) ? Qcolor : Qmono;
360 378 return 1;
361 DEVICE_MSPRINTER_DEVMODE(d) = xmalloc (DEVICE_MSPRINTER_DEVMODE_SIZE(d)); 379 }
362 DocumentProperties (NULL, DEVICE_MSPRINTER_HPRINTER(d), 380
363 printer_name, DEVICE_MSPRINTER_DEVMODE(d), 381 static void
364 NULL, DM_OUT_BUFFER); 382 msprinter_delete_device_internal (struct device *d)
383 {
384 if (DEVICE_MSPRINTER_HPRINTER (d))
385 ClosePrinter (DEVICE_MSPRINTER_HPRINTER (d));
386 if (DEVICE_MSPRINTER_HDC (d))
387 DeleteDC (DEVICE_MSPRINTER_HDC (d));
388 if (DEVICE_MSPRINTER_HCDC (d))
389 DeleteDC (DEVICE_MSPRINTER_HCDC (d));
390 if (DEVICE_MSPRINTER_NAME (d))
391 xfree (DEVICE_MSPRINTER_NAME (d));
392
393 DEVICE_MSPRINTER_FONTLIST (d) = Qnil;
394 }
395
396 static int
397 msprinter_reinit_device (struct device *d, char* devname)
398 {
399 msprinter_delete_device_internal (d);
400 return msprinter_init_device_internal (d, devname);
401 }
402
403 Lisp_Object
404 msprinter_default_printer (void)
405 {
406 Extbyte name[666];
407 Bufbyte *nameint;
408
409 if (GetProfileString (XETEXT ("windows"), XETEXT ("device"), NULL, name,
410 sizeof (name) / XETCHAR_SIZE) <= 0)
411 return Qnil;
412 EXTERNAL_TO_C_STRING (name, nameint, Qmswindows_tstr);
413
414 if (name[0] == '\0')
415 return Qnil;
416 strtok (name, ",");
417
418 return build_string (name);
419 }
420
421
422 /************************************************************************/
423 /* printer methods */
424 /************************************************************************/
425
426 static void
427 msprinter_init_device (struct device *d, Lisp_Object props)
428 {
429 char* printer_name;
430 DEVMODE *pdm;
431 size_t dm_size;
432
433 d->device_data = xnew_and_zero (struct msprinter_device);
434
435 DEVICE_INFD (d) = DEVICE_OUTFD (d) = -1;
436 DEVICE_MSPRINTER_DEVMODE(d) = Qnil;
365 437
366 /* We do not use printer fon list as we do with the display 438 /* We do not use printer fon list as we do with the display
367 device. Rather, we allow GDI to pick the closest match to the 439 device. Rather, we allow GDI to pick the closest match to the
368 display font. */ 440 display font. */
369 DEVICE_MSPRINTER_FONTLIST (d) = Qnil; 441 DEVICE_MSPRINTER_FONTLIST (d) = Qnil;
370 442
371 DEVICE_CLASS (d) = (GetDeviceCaps (DEVICE_MSPRINTER_HDC (d), BITSPIXEL) 443 CHECK_STRING (DEVICE_CONNECTION (d));
372 * GetDeviceCaps (DEVICE_MSPRINTER_HDC (d), PLANES) 444
373 > 1) ? Qcolor : Qmono; 445 TO_EXTERNAL_FORMAT (LISP_STRING, DEVICE_CONNECTION (d),
446 C_STRING_ALLOCA, printer_name,
447 Qmswindows_tstr);
448
449 if (!msprinter_init_device_internal (d, printer_name))
450 signal_open_printer_error (d);
451
452 /* Determine DEVMODE size and store the default DEVMODE */
453 dm_size = DocumentProperties (NULL, DEVICE_MSPRINTER_HPRINTER (d),
454 printer_name, NULL, NULL, 0);
455 if (dm_size <= 0)
456 signal_open_printer_error (d);
457
458 pdm = (DEVMODE*) xmalloc (dm_size);
459 DocumentProperties (NULL, DEVICE_MSPRINTER_HPRINTER(d),
460 printer_name, pdm,
461 NULL, DM_OUT_BUFFER);
462
463 assert (DEVMODE_SIZE (pdm) <= dm_size);
464
465 DEVICE_MSPRINTER_DEVMODE(d) =
466 allocate_devmode (pdm, 0, printer_name, d);
467
468 }
469
470 static void
471 msprinter_delete_device (struct device *d)
472 {
473 if (d->device_data)
474 {
475 msprinter_delete_device_internal (d);
476
477 /* Disassociate the selected devmode with the device */
478 if (!NILP (DEVICE_MSPRINTER_DEVMODE (d)))
479 {
480 XDEVMODE (DEVICE_MSPRINTER_DEVMODE (d))->device = Qnil;
481 DEVICE_MSPRINTER_DEVMODE (d) = Qnil;
482 }
483
484 xfree (d->device_data);
485 }
374 } 486 }
375 487
376 static Lisp_Object 488 static Lisp_Object
377 msprinter_device_system_metrics (struct device *d, 489 msprinter_device_system_metrics (struct device *d,
378 enum device_metrics m) 490 enum device_metrics m)
396 /* this is what X means by bitplanes therefore we ought to be 508 /* this is what X means by bitplanes therefore we ought to be
397 consistent. num planes is always 1 under mswindows and 509 consistent. num planes is always 1 under mswindows and
398 therefore useless */ 510 therefore useless */
399 return make_int (GetDeviceCaps (DEVICE_MSPRINTER_HDC(d), BITSPIXEL)); 511 return make_int (GetDeviceCaps (DEVICE_MSPRINTER_HDC(d), BITSPIXEL));
400 512
401 case DM_num_color_cells: /* Prnters are non-palette devices */ 513 case DM_num_color_cells: /* Printers are non-palette devices */
402 case DM_slow_device: /* Animation would be a really bad idea */ 514 case DM_slow_device: /* Animation would be a really bad idea */
403 case DM_security: /* Not provided by windows */ 515 case DM_security: /* Not provided by windows */
404 return Qzero; 516 return Qzero;
405 } 517 }
406 518
407 /* Do not know such property */ 519 /* Do not know such property */
408 return Qunbound; 520 return Qunbound;
409 } 521 }
410 522
411 static void 523 static void
412 msprinter_delete_device (struct device *d)
413 {
414 if (d->device_data)
415 {
416 if (DEVICE_MSPRINTER_HPRINTER (d))
417 ClosePrinter (DEVICE_MSPRINTER_HPRINTER (d));
418 if (DEVICE_MSPRINTER_HDC (d))
419 DeleteDC (DEVICE_MSPRINTER_HDC (d));
420 if (DEVICE_MSPRINTER_NAME (d))
421 free (DEVICE_MSPRINTER_NAME (d));
422 if (DEVICE_MSPRINTER_DEVMODE (d))
423 free (DEVICE_MSPRINTER_DEVMODE (d));
424 if (DEVICE_MSPRINTER_DEVMODE_MIRROR (d))
425 free (DEVICE_MSPRINTER_DEVMODE_MIRROR (d));
426
427 free (d->device_data);
428 }
429 }
430
431 static void
432 msprinter_mark_device (struct device *d) 524 msprinter_mark_device (struct device *d)
433 { 525 {
434 mark_object (DEVICE_MSPRINTER_FONTLIST (d)); 526 mark_object (DEVICE_MSPRINTER_FONTLIST (d));
527 mark_object (DEVICE_MSPRINTER_DEVMODE (d));
435 } 528 }
436 529
437 static unsigned int 530 static unsigned int
438 msprinter_device_implementation_flags (void) 531 msprinter_device_implementation_flags (void)
439 { 532 {
440 return ( XDEVIMPF_PIXEL_GEOMETRY 533 return ( XDEVIMPF_PIXEL_GEOMETRY
441 | XDEVIMPF_IS_A_PRINTER 534 | XDEVIMPF_IS_A_PRINTER
442 | XDEVIMPF_NO_AUTO_REDISPLAY 535 | XDEVIMPF_NO_AUTO_REDISPLAY
443 | XDEVIMPF_FRAMELESS_OK ); 536 | XDEVIMPF_FRAMELESS_OK );
444 } 537 }
445
446 538
447 /************************************************************************/ 539 /************************************************************************/
448 /* printer external functions */ 540 /* printer Lisp subroutines */
449 /************************************************************************/ 541 /************************************************************************/
450 542
451 /* 543 static void
452 * Return a copy of default DEVMODE. The copy returned is in 544 global_free_2_maybe (HGLOBAL hg1, HGLOBAL hg2)
453 * a static buffer which will be overwritten by next call. 545 {
454 */ 546 if (hg1 != NULL)
455 DEVMODE* 547 GlobalFree (hg1);
456 msprinter_get_devmode_copy (struct device *d) 548 if (hg2 != NULL)
457 { 549 GlobalFree (hg2);
458 assert (DEVICE_MSPRINTER_P (d)); 550 }
459 551
460 if (DEVICE_MSPRINTER_DEVMODE_MIRROR(d) == NULL) 552 static HGLOBAL
461 DEVICE_MSPRINTER_DEVMODE_MIRROR(d) = 553 devmode_to_hglobal (Lisp_Devmode *ldm)
462 xmalloc (DEVICE_MSPRINTER_DEVMODE_SIZE(d)); 554 {
463 555 HGLOBAL hg = GlobalAlloc (GHND, XDEVMODE_SIZE (ldm));
464 memcpy (DEVICE_MSPRINTER_DEVMODE_MIRROR(d), 556 memcpy (GlobalLock (hg), ldm->devmode, XDEVMODE_SIZE (ldm));
465 DEVICE_MSPRINTER_DEVMODE(d), 557 GlobalUnlock (hg);
466 DEVICE_MSPRINTER_DEVMODE_SIZE(d)); 558 return hg;
467 559 }
468 return DEVICE_MSPRINTER_DEVMODE_MIRROR(d); 560
469 } 561 /* Returns 0 if the printer has been deleted due to a fatal I/O error,
470 562 1 otherwise. */
471 /* 563 static int
472 * Apply settings from the DEVMODE. The settings are considered 564 sync_printer_with_devmode (struct device* d, DEVMODE* devmode_in,
473 * incremental to the default DEVMODE, so that changes in the 565 DEVMODE* devmode_out, char* devname)
474 * passed structure supercede parameters of the printer. 566 {
475 * 567 /* Change connection if the device changed */
476 * The passed structure is overwritten by the fuction call; 568 if (devname != NULL
477 * complete printer settings are returned. 569 && stricmp (devname, DEVICE_MSPRINTER_NAME(d)) != 0)
478 */ 570 {
479 void 571 Lisp_Object new_connection = build_ext_string (devname, Qmswindows_tstr);
480 msprinter_apply_devmode (struct device *d, DEVMODE *devmode) 572 struct gcpro gcpro1;
481 { 573
482 assert (DEVICE_MSPRINTER_P (d)); 574 GCPRO1 (new_connection);
483 575 DEVICE_CONNECTION (d) = Qnil;
576 if (!NILP (Ffind_device (new_connection, Qmsprinter)))
577 {
578 /* We are in trouble - second msprinter for the same device.
579 Nothing wrong on the Windows side, just forge a unique
580 connection name. Use the memory address of d as a unique
581 suffix. */
582 char* new_connext = alloca (strlen (devname + 11));
583 sprintf (new_connext, "%s:%X", devname, d->header.uid);
584 new_connection = build_ext_string (devname, Qmswindows_tstr);
585 }
586 DEVICE_CONNECTION (d) = new_connection;
587 UNGCPRO;
588
589 /* Reinitialize printer. The device can pop off in process */
590 if (!msprinter_reinit_device (d, devname))
591 {
592 /* Kaboom! */
593 delete_device_internal (d, 1, 0, 1);
594 return 0;
595 }
596 }
597
598 /* Apply the new devmode to the printer */
484 DocumentProperties (NULL, 599 DocumentProperties (NULL,
485 DEVICE_MSPRINTER_HPRINTER(d), 600 DEVICE_MSPRINTER_HPRINTER(d),
486 DEVICE_MSPRINTER_NAME(d), 601 DEVICE_MSPRINTER_NAME(d),
487 devmode, devmode, 602 devmode_out, devmode_in,
488 DM_IN_BUFFER | DM_OUT_BUFFER); 603 DM_IN_BUFFER | DM_OUT_BUFFER);
489 604
490 ResetDC (DEVICE_MSPRINTER_HDC (d), devmode); 605 /* #### ResetDC fails sometimes, Bill only knows why.
606 The solution below looks more like a workaround to me,
607 although it might be fine. --kkm */
608 if (ResetDC (DEVICE_MSPRINTER_HDC (d), devmode_out) == NULL)
609 {
610 DeleteDC (DEVICE_MSPRINTER_HDC (d));
611 DEVICE_MSPRINTER_HDC (d) =
612 CreateDC ("WINSPOOL", DEVICE_MSPRINTER_NAME(d), NULL, devmode_out);
613 }
614
615 return 1;
616 }
617
618 static void
619 handle_devmode_changes (Lisp_Devmode *ldm, HGLOBAL hDevNames, HGLOBAL hDevMode)
620 {
621 DEVNAMES* devnames = (DEVNAMES*) GlobalLock (hDevNames);
622 char *new_name = devnames ? (char*)devnames + devnames->wDeviceOffset : NULL;
623 DEVMODE* devmode = (DEVMODE*) GlobalLock (hDevMode);
624
625 /* Size and name may have changed */
626 ldm->devmode = xrealloc (ldm->devmode, DEVMODE_SIZE (devmode));
627 if (new_name)
628 {
629 if (ldm->printer_name)
630 xfree (ldm->printer_name);
631 ldm->printer_name = xstrdup (new_name);
632 }
633
634 if (!NILP (ldm->device))
635 {
636 /* Apply the new devmode to the printer and get a compete one back */
637 struct device *d = XDEVICE (ldm->device);
638 if (!sync_printer_with_devmode (d, devmode, ldm->devmode, new_name))
639 {
640 global_free_2_maybe (hDevNames, hDevMode);
641 error ("Printer device initialization I/O error, device deleted.");
642 }
643 }
644 else
645 {
646 /* Just copy the devmode structure */
647 memcpy (ldm->devmode, devmode, DEVMODE_SIZE (devmode));
648 }
649 }
650
651 static void
652 ensure_not_printing (struct device *d)
653 {
654 if (!NILP (DEVICE_FRAME_LIST (d)))
655 {
656 Lisp_Object device;
657 XSETDEVICE (device, d);
658 invalid_operation ("Cannot change settings while print job is active",
659 device);
660 }
661 }
662
663 static Lisp_Devmode *
664 decode_devmode (Lisp_Object dev)
665 {
666 if (DEVMODEP (dev))
667 return XDEVMODE (dev);
668 else
669 {
670 ensure_not_printing (XDEVICE (dev));
671 return XDEVMODE (DEVICE_MSPRINTER_DEVMODE (XDEVICE (dev)));
672 }
673 }
674
675 /*
676 * DEV can be either a printer or devmode
677 * PRINT_P is non-zero for the Print dialog, zero for the
678 * Page Setup dialog
679 */
680 static Lisp_Object
681 print_dialog_worker (Lisp_Object dev, int print_p)
682 {
683 Lisp_Devmode *ldm = decode_devmode (dev);
684 PRINTDLG pd;
685
686 memset (&pd, 0, sizeof (pd));
687 pd.lStructSize = sizeof (pd);
688 pd.hwndOwner = mswindows_get_selected_frame_hwnd ();
689 pd.hDevMode = devmode_to_hglobal (ldm);
690 pd.Flags = (PD_NOSELECTION | PD_USEDEVMODECOPIESANDCOLLATE
691 | (print_p ? 0 : PD_PRINTSETUP));
692 pd.nMinPage = 0;
693 pd.nMaxPage = 0xFFFF;
694
695 if (!PrintDlg (&pd))
696 {
697 global_free_2_maybe (pd.hDevNames, pd.hDevMode);
698 return Qnil;
699 }
700
701 handle_devmode_changes (ldm, pd.hDevNames, pd.hDevMode);
702
703 /* Finally, build the resulting plist */
704 {
705 Lisp_Object result = Qnil;
706 struct gcpro gcpro1;
707 GCPRO1 (result);
708
709 /* Do consing in reverse order.
710 Number of copies */
711 if (print_p)
712 result = Fcons (Qcopies, Fcons (make_int (pd.nCopies), result));
713
714 /* Page range */
715 if (print_p && (pd.Flags & PD_PAGENUMS))
716 {
717 result = Fcons (Qto_page, Fcons (make_int (pd.nToPage), result));
718 result = Fcons (Qfrom_page, Fcons (make_int (pd.nFromPage), result));
719 }
720
721 /* Device name */
722 result = Fcons (Qname,
723 Fcons (build_ext_string (ldm->printer_name,
724 Qmswindows_tstr),
725 result));
726 UNGCPRO;
727
728 global_free_2_maybe (pd.hDevNames, pd.hDevMode);
729 return result;
730 }
731 }
732
733 Lisp_Object
734 mswindows_handle_print_setup_dialog_box (struct frame *f, Lisp_Object keys)
735 {
736 Lisp_Object device = Qunbound, settings = Qunbound;
737
738 {
739 EXTERNAL_PROPERTY_LIST_LOOP_3 (key, value, keys)
740 {
741 if (EQ (key, Q_device))
742 {
743 device = wrap_device (decode_device (value));
744 CHECK_MSPRINTER_DEVICE (device);
745 }
746 else if (EQ (key, Q_printer_settings))
747 {
748 CHECK_DEVMODE (value);
749 settings = value;
750 }
751 else
752 syntax_error ("Unrecognized print-dialog keyword", key);
753 }
754 }
755
756 if ((UNBOUNDP (device) && UNBOUNDP (settings)) ||
757 (!UNBOUNDP (device) && !UNBOUNDP (settings)))
758 syntax_error ("Exactly one of :device and :printer-settings must be given",
759 keys);
760
761 return print_dialog_worker (!UNBOUNDP (device) ? device : settings, 0);
762 }
763
764 Lisp_Object
765 mswindows_handle_print_dialog_box (struct frame *f, Lisp_Object keys)
766 {
767 Lisp_Object device = Qunbound, settings = Qunbound;
768
769 {
770 EXTERNAL_PROPERTY_LIST_LOOP_3 (key, value, keys)
771 {
772 if (EQ (key, Q_device))
773 {
774 device = wrap_device (decode_device (value));
775 CHECK_MSPRINTER_DEVICE (device);
776 }
777 else if (EQ (key, Q_printer_settings))
778 {
779 CHECK_DEVMODE (value);
780 settings = value;
781 }
782 else
783 syntax_error ("Unrecognized print-dialog keyword", key);
784 }
785 }
786
787 if ((UNBOUNDP (device) && UNBOUNDP (settings)) ||
788 (!UNBOUNDP (device) && !UNBOUNDP (settings)))
789 syntax_error ("Exactly one of :device and :printer-settings must be given",
790 keys);
791
792 return print_dialog_worker (!UNBOUNDP (device) ? device : settings, 1);
793 }
794
795 static int
796 plist_get_margin (Lisp_Object plist, Lisp_Object prop)
797 {
798 Lisp_Object val = Fplist_get (plist, prop, make_int (1440));
799 if (!INTP (val))
800 invalid_argument ("Margin value must be an integer", val);
801
802 return MulDiv (XINT (val), 100, 144);
803 }
804
805 static Lisp_Object
806 plist_set_margin (Lisp_Object plist, Lisp_Object prop, int margin, int mm_p)
807 {
808 Lisp_Object val = make_int (MulDiv (margin, 144, mm_p ? 2450 : 100));
809 return Fcons (prop, Fcons (val, plist));
810 }
811
812 Lisp_Object
813 mswindows_handle_page_setup_dialog_box (struct frame *f, Lisp_Object keys)
814 {
815 Lisp_Object device = Qunbound, settings = Qunbound;
816 Lisp_Object plist = Qnil;
817
818 {
819 EXTERNAL_PROPERTY_LIST_LOOP_3 (key, value, keys)
820 {
821 if (EQ (key, Q_device))
822 {
823 device = wrap_device (decode_device (value));
824 CHECK_MSPRINTER_DEVICE (device);
825 }
826 else if (EQ (key, Q_printer_settings))
827 {
828 CHECK_DEVMODE (value);
829 settings = value;
830 }
831 else if (EQ (key, Q_properties))
832 {
833 CHECK_LIST (value);
834 plist = value;
835 }
836 else
837 syntax_error ("Unrecognized page-setup dialog keyword", key);
838 }
839 }
840
841 if ((UNBOUNDP (device) && UNBOUNDP (settings)) ||
842 (!UNBOUNDP (device) && !UNBOUNDP (settings)))
843 syntax_error ("Exactly one of :device and :printer-settings must be given",
844 keys);
845
846 if (UNBOUNDP (device))
847 device = settings;
848
849 {
850 Lisp_Devmode *ldm = decode_devmode (device);
851 PAGESETUPDLG pd;
852
853 memset (&pd, 0, sizeof (pd));
854 pd.lStructSize = sizeof (pd);
855 pd.hwndOwner = mswindows_get_selected_frame_hwnd ();
856 pd.Flags = PSD_MARGINS;
857 pd.rtMargin.left = plist_get_margin (plist, Qleft_margin);
858 pd.rtMargin.top = plist_get_margin (plist, Qtop_margin);
859 pd.rtMargin.right = plist_get_margin (plist, Qright_margin);
860 pd.rtMargin.bottom = plist_get_margin (plist, Qbottom_margin);
861 pd.hDevMode = devmode_to_hglobal (ldm);
862
863 if (!PageSetupDlg (&pd))
864 {
865 global_free_2_maybe (pd.hDevNames, pd.hDevMode);
866 return Qnil;
867 }
868
869 if (pd.hDevMode)
870 handle_devmode_changes (ldm, pd.hDevNames, pd.hDevMode);
871
872 /* Finally, build the resulting plist */
873 {
874 Lisp_Object result = Qnil;
875 int mm_p = pd.Flags & PSD_INHUNDREDTHSOFMILLIMETERS;
876 result = plist_set_margin (result, Qbottom_margin, pd.rtMargin.bottom,
877 mm_p);
878 result = plist_set_margin (result, Qright_margin, pd.rtMargin.right,
879 mm_p);
880 result = plist_set_margin (result, Qtop_margin, pd.rtMargin.top, mm_p);
881 result = plist_set_margin (result, Qleft_margin, pd.rtMargin.left, mm_p);
882 return result;
883 }
884 }
885 }
886
887 DEFUN ("msprinter-get-settings", Fmsprinter_get_settings, 1, 1, 0, /*
888 Return the settings object currently used by DEVICE.
889 The object returned is not a copy, but rather a pointer to the
890 original one. Use `msprinter-settings-copy' to create a copy of it.
891 */
892 (device))
893 {
894 struct device *d = decode_device (device);
895 XSETDEVICE (device, d);
896 CHECK_MSPRINTER_DEVICE (device);
897 return DEVICE_MSPRINTER_DEVMODE (d);
898 }
899
900 DEFUN ("msprinter-select-settings", Fmsprinter_select_settings, 2, 2, 0, /*
901 Select SETTINGS object into a DEVICE.
902 The settings from the settings object are immediately applied to the
903 printer, possibly changing even the target printer itself, and all
904 future changes are applied synchronously to the printer device and the
905 selected printer object, until a different settings object is selected
906 into the same printer.
907
908 A settings object can be selected to no more than one printer at a time.
909
910 If the supplied settings object is not specialized, it is specialized
911 for the printer immediately upon selection. The object can be
912 despecialized after it is unselected by calling the function
913 `msprinter-settings-despecialize'.
914
915 Return value is the previously selected settings object.
916 */
917 (device, settings))
918 {
919 Lisp_Devmode *ldm;
920 struct device *d = decode_device (device);
921
922 struct gcpro gcpro1;
923 GCPRO1 (settings);
924
925 XSETDEVICE (device, d);
926 CHECK_MSPRINTER_DEVICE (device);
927 CHECK_DEVMODE (settings);
928 ldm = XDEVMODE (settings);
929
930 if (!NILP (ldm->device))
931 invalid_operation ("The object is currently selected into a device",
932 settings);
933
934 /* If the object being selected is de-specialized, then its
935 size is perhaps not enough to receive the new devmode. We can ask
936 for printer's devmode size here, because despecialized settings
937 cannot force switching to a different printer, as they supply no
938 printer name at all. */
939 if (ldm->printer_name == NULL)
940 {
941 size_t dm_size =
942 DocumentProperties (NULL, DEVICE_MSPRINTER_HPRINTER(d),
943 DEVICE_MSPRINTER_NAME(d), NULL, NULL, 0);
944 if (dm_size <= 0)
945 invalid_operation ("Unable to specialize settings, printer error",
946 device);
947
948 assert (XDEVMODE_SIZE (ldm) <= dm_size);
949 ldm->devmode = xrealloc (ldm->devmode, dm_size);
950 }
951
952 /* If we bail out on signal here, no damage is done, except that
953 the storage for the DEVMODE structure might be reallocated to
954 hold a larger one - not a big deal */
955 if (!sync_printer_with_devmode (d, ldm->devmode, ldm->devmode,
956 ldm->printer_name))
957 error ("Printer device initialization I/O error, device deleted.");
958
959 if (ldm->printer_name == NULL)
960 ldm->printer_name = xstrdup (DEVICE_MSPRINTER_NAME(d));
961
962 {
963 Lisp_Object old_mode = DEVICE_MSPRINTER_DEVMODE (d);
964 ldm->device = device;
965 XDEVMODE (old_mode)->device = Qnil;
966 DEVICE_MSPRINTER_DEVMODE (d) = settings;
967 UNGCPRO;
968 return old_mode;
969 }
970 }
971
972 DEFUN ("msprinter-apply-settings", Fmsprinter_apply_settings, 2, 2, 0, /*
973 Apply settings from a SETTINGS object to a 'msprinter DEVICE.
974 The settings from the settings object are immediately applied to the
975 printer, possibly changing even the target printer itself. The SETTING
976 object is not modified, unlike `msprinter-select-settings', and the
977 supplied object is not changed. The changes are immediately recorded
978 into the settings object which is currently selected into the printer
979 device.
980
981 Return value is the currently selected settings object.
982 */
983 (device, settings))
984 {
985 Lisp_Devmode *ldm_current, *ldm_new;
986 struct device *d = decode_device (device);
987
988 struct gcpro gcpro1;
989 GCPRO1 (settings);
990
991 XSETDEVICE (device, d);
992 CHECK_MSPRINTER_DEVICE (device);
993 CHECK_DEVMODE (settings);
994 ldm_new = XDEVMODE (settings);
995 ldm_current = XDEVMODE (DEVICE_MSPRINTER_DEVMODE (d));
996
997 /* If the supplied devmode is not specialized, then the current
998 devmode size will always be sufficient, as the printer does
999 not change. If it is specialized, we must reallocate the current
1000 devmode storage to match with the supplied one, as it has the right
1001 size for the new printer, if it is going to change. The correct
1002 way is to use the largest of the two though, to keep the old
1003 contents unchanged in case of preliminary exit.
1004 */
1005 if (ldm_new->printer_name)
1006 ldm_current->devmode =
1007 (DEVMODE*) xrealloc (ldm_current->devmode,
1008 max (XDEVMODE_SIZE (ldm_new),
1009 XDEVMODE_SIZE (ldm_current)));
1010
1011 if (!sync_printer_with_devmode (d, ldm_new->devmode,
1012 ldm_current->devmode,
1013 ldm_new->printer_name))
1014 error ("Printer device initialization I/O error, device deleted.");
1015
1016 if (ldm_new->printer_name != NULL)
1017 {
1018 xfree (ldm_current->printer_name);
1019 ldm_current->printer_name = xstrdup (ldm_new->printer_name);
1020 }
1021
1022 return DEVICE_MSPRINTER_DEVMODE (d);
1023 }
1024
1025 /************************************************************************/
1026 /* devmode */
1027 /************************************************************************/
1028
1029 static void
1030 print_devmode (Lisp_Object obj, Lisp_Object printcharfun,
1031 int escapeflag)
1032 {
1033 char buf[100];
1034 Lisp_Devmode *dm = XDEVMODE (obj);
1035 if (print_readably)
1036 error ("printing unreadable object #<msprinter-settings 0x%x>",
1037 dm->header.uid);
1038 write_c_string ("#<msprinter-settings", printcharfun);
1039 if (dm->printer_name)
1040 {
1041 write_c_string (" for \"", printcharfun);
1042 write_c_string (dm->printer_name, printcharfun);
1043 write_c_string ("\"", printcharfun);
1044 }
1045 if (!NILP (dm->device))
1046 {
1047 write_c_string (" (currently on ", printcharfun);
1048 print_internal (dm->device, printcharfun, 0);
1049 write_c_string (")", printcharfun);
1050 }
1051 sprintf (buf, " 0x%x>", dm->header.uid);
1052 write_c_string (buf, printcharfun);
1053 }
1054
1055 static void
1056 finalize_devmode (void *header, int for_disksave)
1057 {
1058 Lisp_Devmode *dm = (Lisp_Devmode *) header;
1059
1060 if (for_disksave)
1061 {
1062 Lisp_Object devmode;
1063 XSETDEVMODE (devmode, dm);
1064 invalid_operation
1065 ("Cannot dump XEmacs containing an msprinter-settings object",
1066 devmode);
1067 }
1068
1069 assert (NILP (dm->device));
1070
1071 if (dm->printer_name)
1072 xfree (dm->printer_name);
1073 }
1074
1075 static int
1076 equal_devmode (Lisp_Object obj1, Lisp_Object obj2, int depth)
1077 {
1078 Lisp_Devmode *dm1 = XDEVMODE (obj1);
1079 Lisp_Devmode *dm2 = XDEVMODE (obj2);
1080
1081 if ((dm1->devmode != NULL) != (dm1->devmode != NULL))
1082 return 0;
1083 if (dm1->devmode == NULL)
1084 return 1;
1085 if (memcmp (dm1->devmode, dm2->devmode, XDEVMODE_SIZE (dm1)) != 0)
1086 return 0;
1087 if (dm1->printer_name == NULL || dm2->printer_name == NULL)
1088 return 1;
1089 return stricmp (dm1->printer_name, dm2->printer_name) == 0;
1090 }
1091
1092 static unsigned long
1093 hash_devmode (Lisp_Object obj, int depth)
1094 {
1095 Lisp_Devmode *dm = XDEVMODE (obj);
1096
1097 return HASH3 (XDEVMODE_SIZE (dm),
1098 dm->devmode ? memory_hash (dm->devmode, XDEVMODE_SIZE (dm))
1099 : 0,
1100 dm->printer_name ? string_hash (dm->printer_name) : 0);
1101 }
1102
1103 DEFINE_LRECORD_IMPLEMENTATION ("msprinter-settings", devmode,
1104 0/*mark*/, print_devmode, finalize_devmode,
1105 equal_devmode, hash_devmode, 0/*description*/,
1106 Lisp_Devmode);
1107 static Lisp_Object
1108 allocate_devmode (DEVMODE* src_devmode, int do_copy,
1109 char* src_name, struct device *d)
1110 {
1111 Lisp_Devmode *dm;
1112 Lisp_Object ob;
1113
1114 dm = alloc_lcrecord_type (Lisp_Devmode, &lrecord_devmode);
1115
1116 if (d)
1117 XSETDEVICE (dm->device, d);
1118 else
1119 dm->device = Qnil;
1120
1121 dm->printer_name = src_name ? xstrdup (src_name) : NULL;
1122
1123 if (src_devmode != NULL && do_copy)
1124 {
1125 dm->devmode = (DEVMODE*) xmalloc (DEVMODE_SIZE (src_devmode));
1126 memcpy (dm->devmode, src_devmode, DEVMODE_SIZE (src_devmode));
1127 }
1128 else
1129 {
1130 dm->devmode = src_devmode;
1131 }
1132
1133 XSETDEVMODE (ob, dm);
1134 return ob;
1135 }
1136
1137 DEFUN ("msprinter-settings-copy", Fmsprinter_settings_copy, 1, 1, 0, /*
1138 Create and returns an exact copy of a printer settings object.
1139 */
1140 (settings))
1141 {
1142 Lisp_Devmode *dm;
1143
1144 CHECK_DEVMODE (settings);
1145 dm = XDEVMODE (settings);
1146
1147 return allocate_devmode (dm->devmode, 1, dm->printer_name, NULL);
1148 }
1149
1150 DEFUN ("msprinter-settings-despecialize", Fmsprinter_settings_despecialize, 1, 1, 0, /*
1151 Erase printer-specific settings from a printer settings object.
1152 */
1153 (settings))
1154 {
1155 Lisp_Devmode *ldm;
1156 DEVMODE *dm;
1157
1158 CHECK_DEVMODE (settings);
1159 ldm = XDEVMODE (settings);
1160
1161 if (!NILP (ldm->device))
1162 invalid_operation ("The object is currently selected into a device",
1163 settings);
1164
1165 dm = ldm->devmode;
1166
1167 /* #### TODO. Either remove references to device specific bins,
1168 paper sizes etc, or signal an error of they are present. */
1169
1170 dm->dmDriverExtra = 0;
1171 dm->dmDeviceName[0] = '\0';
1172
1173 if (ldm->printer_name)
1174 xfree (ldm->printer_name);
1175
1176 return Qnil;
1177 }
1178
1179 DEFUN ("mswindows-get-default-printer", Fmswindows_get_default_printer, 0, 0, 0, /*
1180 Return name of the default printer, as string, on nil if there is no default.
1181 */
1182 ())
1183 {
1184 return msprinter_default_printer ();
1185 }
1186
1187 static void
1188 signal_enum_printer_error (void)
1189 {
1190 invalid_operation ("Error enumerating printers", make_int (GetLastError ()));
1191 }
1192
1193 DEFUN ("mswindows-printer-list", Fmswindows_printer_list, 0, 0, 0, /*
1194 Return a list of string names of installed printers.
1195 If there is a default printer, it is returned as the first element of
1196 the list. If there is no default printer, the first element of the
1197 list will be nil. The rest of elements are guaranteed to have string
1198 values. Return value is nil if there are no printers installed.
1199 */
1200 ())
1201 {
1202 int have_nt, ok;
1203 BYTE *data_buf, dummy_byte;
1204 size_t enum_entry_size;
1205 DWORD enum_flags, enum_level, bytes_needed, num_printers;
1206 struct gcpro gcpro1, gcpro2;
1207 Lisp_Object result = Qnil, def_printer = Qnil;
1208
1209 /* Determine OS flavor, to use the fastest enumeration method available */
1210 have_nt = !mswindows_windows9x_p ();
1211 enum_flags = PRINTER_ENUM_LOCAL | (have_nt ? PRINTER_ENUM_CONNECTIONS : 0);
1212 enum_level = have_nt ? 4 : 5;
1213 enum_entry_size = have_nt ? sizeof (PRINTER_INFO_4) : sizeof (PRINTER_INFO_5);
1214
1215 /* Allocate memory for printer enum structure */
1216 ok = EnumPrinters (enum_flags, NULL, enum_level, &dummy_byte, 1,
1217 &bytes_needed, &num_printers);
1218 if (ok)
1219 /* No printers, if just 1 byte is enough */
1220 return Qnil;
1221
1222 if (GetLastError () != ERROR_INSUFFICIENT_BUFFER)
1223 signal_enum_printer_error ();
1224
1225 data_buf = alloca (bytes_needed);
1226 ok = EnumPrinters (enum_flags, NULL, enum_level, data_buf, bytes_needed,
1227 &bytes_needed, &num_printers);
1228 if (!ok)
1229 signal_enum_printer_error ();
1230
1231 if (num_printers == 0)
1232 /* Strange but... */
1233 return Qnil;
1234
1235 GCPRO2 (result, def_printer);
1236
1237 while (num_printers--)
1238 {
1239 LPCTSTR printer_name;
1240 if (have_nt)
1241 {
1242 PRINTER_INFO_4 *info = (PRINTER_INFO_4*) data_buf;
1243 printer_name = info->pPrinterName;
1244 }
1245 else
1246 {
1247 PRINTER_INFO_5 *info = (PRINTER_INFO_5*) data_buf;
1248 printer_name = info->pPrinterName;
1249 }
1250 data_buf += enum_entry_size;
1251
1252 result = Fcons (build_ext_string (printer_name, Qmswindows_tstr),
1253 result);
1254 }
1255
1256 def_printer = msprinter_default_printer ();
1257 result = Fdelete (def_printer, result);
1258 result = Fcons (def_printer, result);
1259
1260 RETURN_UNGCPRO (result);
491 } 1261 }
492 1262
493 1263
494 /************************************************************************/ 1264 /************************************************************************/
495 /* initialization */ 1265 /* initialization */
496 /************************************************************************/ 1266 /************************************************************************/
497 1267
498 void 1268 void
499 syms_of_device_mswindows (void) 1269 syms_of_device_mswindows (void)
500 { 1270 {
1271 INIT_LRECORD_IMPLEMENTATION (devmode);
1272
1273 DEFSUBR (Fmsprinter_get_settings);
1274 DEFSUBR (Fmsprinter_select_settings);
1275 DEFSUBR (Fmsprinter_apply_settings);
1276 DEFSUBR (Fmsprinter_settings_copy);
1277 DEFSUBR (Fmsprinter_settings_despecialize);
1278 DEFSUBR (Fmswindows_get_default_printer);
1279 DEFSUBR (Fmswindows_printer_list);
1280
501 defsymbol (&Qinit_pre_mswindows_win, "init-pre-mswindows-win"); 1281 defsymbol (&Qinit_pre_mswindows_win, "init-pre-mswindows-win");
502 defsymbol (&Qinit_post_mswindows_win, "init-post-mswindows-win"); 1282 defsymbol (&Qinit_post_mswindows_win, "init-post-mswindows-win");
503 } 1283 }
504 1284
505 void 1285 void