Mercurial > hg > xemacs-beta
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 |