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