Initial revision
[chise/xemacs-chise.git.1] / src / device-msw.c
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.
29 */
30
31
32 #include <config.h>
33 #include "lisp.h"
34
35 #include "console-msw.h"
36 #include "console-stream.h"
37 #include "events.h"
38 #include "faces.h"
39 #include "frame.h"
40 #include "sysdep.h"
41
42 #include <winspool.h>
43
44 /* win32 DDE management library globals */
45 #ifdef HAVE_DRAGNDROP
46 DWORD mswindows_dde_mlid;
47 HSZ mswindows_dde_service;
48 HSZ mswindows_dde_topic_system;
49 HSZ mswindows_dde_item_open;
50 #endif
51
52 /* Control conversion of upper case file names to lower case.
53    nil means no, t means yes. */
54 Lisp_Object Vmswindows_downcase_file_names;
55
56 /* Control whether stat() attempts to determine file type and link count
57    exactly, at the expense of slower operation.  Since true hard links
58    are supported on NTFS volumes, this is only relevant on NT.  */
59 Lisp_Object Vmswindows_get_true_file_attributes;
60
61 Lisp_Object Qinit_pre_mswindows_win, Qinit_post_mswindows_win;
62
63
64 /************************************************************************/
65 /*                               helpers                                */
66 /************************************************************************/
67
68 static Lisp_Object
69 build_syscolor_string (int idx)
70 {
71   DWORD clr;
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 }
84
85 static Lisp_Object
86 build_syscolor_cons (int index1, int index2)
87 {
88   Lisp_Object color1, color2;
89   struct gcpro gcpro1;
90   GCPRO1 (color1);
91   color1 = build_syscolor_string (index1);
92   color2 = build_syscolor_string (index2);
93   RETURN_UNGCPRO (Fcons (color1, color2));
94 }
95
96 static Lisp_Object
97 build_sysmetrics_cons (int index1, int index2)
98 {
99   return Fcons (index1 < 0 ? Qnil : make_int (GetSystemMetrics (index1)),
100                 index2 < 0 ? Qnil : make_int (GetSystemMetrics (index2)));
101 }
102
103 static Lisp_Object
104 build_devicecaps_cons (HDC hdc, int index1, int index2)
105 {
106   return Fcons (index1 < 0 ? Qnil : make_int (GetDeviceCaps (hdc, index1)),
107                 index2 < 0 ? Qnil : make_int (GetDeviceCaps (hdc, index2)));
108 }
109
110
111 \f
112 /************************************************************************/
113 /*                          display methods                             */
114 /************************************************************************/
115
116 static void
117 mswindows_init_device (struct device *d, Lisp_Object props)
118 {
119   WNDCLASSEX wc;
120   HDC hdc;
121
122   DEVICE_CLASS (d) = Qcolor;
123   DEVICE_INFD (d) = DEVICE_OUTFD (d) = -1;
124   init_baud_rate (d);
125   init_one_device (d);
126
127   d->device_data = xnew_and_zero (struct mswindows_device);
128   hdc = CreateCompatibleDC (NULL);
129   assert (hdc!=NULL);
130   DEVICE_MSWINDOWS_LOGPIXELSX(d) =  GetDeviceCaps(hdc, LOGPIXELSX);
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);
142
143   DeleteDC (hdc);
144
145   /* Register the main window class */
146   wc.cbSize = sizeof (WNDCLASSEX);
147   wc.style = CS_OWNDC;  /* One DC per window */
148   wc.lpfnWndProc = (WNDPROC) mswindows_wnd_proc;
149   wc.cbClsExtra = 0;
150   wc.cbWndExtra = MSWINDOWS_WINDOW_EXTRA_BYTES;
151   /* This must match whatever is passed to CreateWIndowEx, NULL is ok
152      for this. */
153   wc.hInstance = NULL;  
154   wc.hIcon = LoadIcon (GetModuleHandle(NULL), XEMACS_CLASS);
155   wc.hCursor = LoadCursor (NULL, IDC_ARROW);
156   /* Background brush is only used during sizing, when XEmacs cannot
157      take over */
158   wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
159   wc.lpszMenuName = NULL;
160
161   wc.lpszClassName = XEMACS_CLASS;
162   wc.hIconSm = LoadImage (GetModuleHandle (NULL), XEMACS_CLASS,
163                           IMAGE_ICON, 16, 16, 0);
164   RegisterClassEx (&wc);
165
166 #ifdef HAVE_WIDGETS
167   xzero (wc);
168   /* Register the main window class */
169   wc.cbSize = sizeof (WNDCLASSEX);
170   wc.lpfnWndProc = (WNDPROC) mswindows_control_wnd_proc;
171   wc.lpszClassName = XEMACS_CONTROL_CLASS;
172   wc.hInstance = NULL;
173   RegisterClassEx (&wc);
174 #endif
175
176 #if defined (HAVE_TOOLBARS) || defined (HAVE_WIDGETS)
177   InitCommonControls ();
178 #endif
179 }
180
181 static void
182 mswindows_finish_init_device (struct device *d, Lisp_Object props)
183 {
184   /* 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. */
186 #ifdef HAVE_DRAGNDROP
187   mswindows_dde_mlid = 0;
188   DdeInitialize (&mswindows_dde_mlid, (PFNCALLBACK)mswindows_dde_callback,
189                  APPCMD_FILTERINITS|CBF_FAIL_SELFCONNECTIONS|CBF_FAIL_ADVISES|
190                  CBF_FAIL_POKES|CBF_FAIL_REQUESTS|CBF_SKIP_ALLNOTIFICATIONS, 0);
191   
192   mswindows_dde_service = DdeCreateStringHandle (mswindows_dde_mlid, XEMACS_CLASS, 0);
193   mswindows_dde_topic_system = DdeCreateStringHandle (mswindows_dde_mlid, SZDDESYS_TOPIC, 0);
194   mswindows_dde_item_open = DdeCreateStringHandle (mswindows_dde_mlid,
195                                                    TEXT(MSWINDOWS_DDE_ITEM_OPEN), 0);
196   DdeNameService (mswindows_dde_mlid, mswindows_dde_service, 0L, DNS_REGISTER);
197 #endif
198 }
199
200 static void
201 mswindows_delete_device (struct device *d)
202 {
203 #ifdef HAVE_DRAGNDROP
204   DdeNameService (mswindows_dde_mlid, 0L, 0L, DNS_REGISTER);
205   DdeUninitialize (mswindows_dde_mlid);
206 #endif
207
208   free (d->device_data);
209 }
210
211 static void
212 mswindows_mark_device (struct device *d)
213 {
214   mark_object (DEVICE_MSWINDOWS_FONTLIST (d));
215 }
216
217 static Lisp_Object
218 mswindows_device_system_metrics (struct device *d,
219                                  enum device_metrics m)
220 {
221   switch (m)
222     {
223     case DM_size_device:
224       return Fcons (make_int (DEVICE_MSWINDOWS_HORZRES(d)),
225                     make_int (DEVICE_MSWINDOWS_VERTRES(d)));
226       break;
227     case DM_device_dpi:
228       return Fcons (make_int (DEVICE_MSWINDOWS_LOGPIXELSX(d)),
229                     make_int (DEVICE_MSWINDOWS_LOGPIXELSY(d)));
230       break;
231     case DM_size_device_mm:
232       return Fcons (make_int (DEVICE_MSWINDOWS_HORZSIZE(d)),
233                     make_int (DEVICE_MSWINDOWS_VERTSIZE(d)));
234       break;
235     case DM_num_bit_planes:
236       /* this is what X means by bitplanes therefore we ought to be
237          consistent. num planes is always 1 under mswindows and
238          therefore useless */
239       return make_int (DEVICE_MSWINDOWS_BITSPIXEL(d));
240       break;
241     case DM_num_color_cells:
242       return make_int (DEVICE_MSWINDOWS_CELLS(d));
243       break;
244
245       /*** Colors ***/
246 #define FROB(met, index1, index2)                       \
247     case DM_##met:                                      \
248       return build_syscolor_cons (index1, index2);
249       
250       FROB (color_default, COLOR_WINDOW, COLOR_WINDOWTEXT);
251       FROB (color_select, COLOR_HIGHLIGHT, COLOR_HIGHLIGHTTEXT);
252       FROB (color_balloon, COLOR_INFOBK, COLOR_INFOTEXT);
253       FROB (color_3d_face, COLOR_3DFACE, COLOR_BTNTEXT);
254       FROB (color_3d_light, COLOR_3DLIGHT, COLOR_3DHILIGHT);
255       FROB (color_3d_dark, COLOR_3DSHADOW, COLOR_3DDKSHADOW);
256       FROB (color_menu, COLOR_MENU, COLOR_MENUTEXT);
257       FROB (color_menu_highlight, COLOR_HIGHLIGHT, COLOR_HIGHLIGHTTEXT);
258       FROB (color_menu_button, COLOR_MENU, COLOR_MENUTEXT);
259       FROB (color_menu_disabled, COLOR_MENU, COLOR_GRAYTEXT);
260       FROB (color_toolbar, COLOR_BTNFACE, COLOR_BTNTEXT);
261       FROB (color_scrollbar, COLOR_SCROLLBAR, COLOR_CAPTIONTEXT);
262       FROB (color_desktop, -1, COLOR_DESKTOP);
263       FROB (color_workspace, -1, COLOR_APPWORKSPACE);
264 #undef FROB
265
266       /*** Sizes ***/
267 #define FROB(met, index1, index2)                       \
268     case DM_##met:                                      \
269       return build_sysmetrics_cons (index1, index2);
270
271       FROB (size_cursor, SM_CXCURSOR, SM_CYCURSOR);
272       FROB (size_scrollbar, SM_CXVSCROLL, SM_CYHSCROLL);
273       FROB (size_menu, -1, SM_CYMENU);
274       FROB (size_icon, SM_CXICON, SM_CYICON);
275       FROB (size_icon_small, SM_CXSMICON, SM_CYSMICON);
276 #undef FROB
277
278     case DM_size_workspace:
279       {
280         RECT rc;
281         SystemParametersInfo (SPI_GETWORKAREA, 0, &rc, 0);
282         return Fcons (make_int (rc.right - rc.left),
283                       make_int (rc.bottom - rc.top));
284       }
285       /*
286         case DM_size_toolbar:
287         case DM_size_toolbar_button:
288         case DM_size_toolbar_border:
289       */
290
291       /*** Features ***/
292 #define FROB(met, index)                        \
293     case DM_##met:                              \
294       return make_int (GetSystemMetrics (index));
295
296       FROB (mouse_buttons, SM_CMOUSEBUTTONS);
297       FROB (swap_buttons, SM_SWAPBUTTON);
298       FROB (show_sounds, SM_SHOWSOUNDS);
299       FROB (slow_device, SM_SLOWMACHINE);
300       FROB (security, SM_SECURE);
301 #undef FROB
302
303     }
304
305   /* Do not know such property */
306   return Qunbound;
307 }
308
309 static unsigned int
310 mswindows_device_implementation_flags (void)
311 {
312   return XDEVIMPF_PIXEL_GEOMETRY;
313 }
314
315 \f
316 /************************************************************************/
317 /*                          printer methods                             */
318 /************************************************************************/
319
320 static void
321 signal_open_printer_error (struct device *d)
322 {
323   signal_simple_error ("Failed to open printer", DEVICE_CONNECTION (d));
324 }
325
326 static void
327 msprinter_init_device (struct device *d, Lisp_Object props)
328 {
329   char* printer_name;
330
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);
342
343   if (!OpenPrinter (printer_name, &DEVICE_MSPRINTER_HPRINTER (d), NULL))
344     {
345       DEVICE_MSPRINTER_HPRINTER (d) = NULL;
346       signal_open_printer_error (d);
347     }
348
349   DEVICE_MSPRINTER_HDC (d) = CreateDC ("WINSPOOL", printer_name,
350                                        NULL, NULL);
351   if (DEVICE_MSPRINTER_HDC (d) == NULL)
352     signal_open_printer_error (d);
353
354   /* Determinie DEVMODE size and store the default DEVMODE */
355   DEVICE_MSPRINTER_DEVMODE_SIZE(d) = 
356     DocumentProperties (NULL, DEVICE_MSPRINTER_HPRINTER(d),
357                         printer_name, NULL, NULL, 0);
358   if (DEVICE_MSPRINTER_DEVMODE_SIZE(d) <= 0)
359     signal_open_printer_error (d);
360
361   DEVICE_MSPRINTER_DEVMODE(d) = xmalloc (DEVICE_MSPRINTER_DEVMODE_SIZE(d));
362   DocumentProperties (NULL, DEVICE_MSPRINTER_HPRINTER(d),
363                       printer_name, DEVICE_MSPRINTER_DEVMODE(d),
364                       NULL, DM_OUT_BUFFER);
365
366   /* 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
368      display font. */
369   DEVICE_MSPRINTER_FONTLIST (d) = Qnil;
370
371   DEVICE_CLASS (d) = (GetDeviceCaps (DEVICE_MSPRINTER_HDC (d), BITSPIXEL)
372                       * GetDeviceCaps (DEVICE_MSPRINTER_HDC (d), PLANES)
373                       > 1) ? Qcolor : Qmono;
374 }
375
376 static Lisp_Object
377 msprinter_device_system_metrics (struct device *d,
378                                  enum device_metrics m)
379 {
380   switch (m)
381     {
382       /* Device sizes - pixel and mm */
383 #define FROB(met, index1, index2)                       \
384     case DM_##met:                                      \
385       return build_devicecaps_cons                      \
386          (DEVICE_MSPRINTER_HDC(d), index1, index2);
387
388       FROB (size_device, PHYSICALWIDTH, PHYSICALHEIGHT);
389       FROB (size_device_mm, HORZSIZE, VERTSIZE);
390       FROB (size_workspace, HORZRES, VERTRES);
391       FROB (offset_workspace, PHYSICALOFFSETX, PHYSICALOFFSETY);
392       FROB (device_dpi, LOGPIXELSX, LOGPIXELSY);
393 #undef FROB
394
395     case DM_num_bit_planes:
396       /* this is what X means by bitplanes therefore we ought to be
397          consistent. num planes is always 1 under mswindows and
398          therefore useless */
399       return make_int (GetDeviceCaps (DEVICE_MSPRINTER_HDC(d), BITSPIXEL));
400
401     case DM_num_color_cells:    /* Prnters are non-palette devices */
402     case DM_slow_device:        /* Animation would be a really bad idea */
403     case DM_security:           /* Not provided by windows */
404       return Qzero;
405     }
406
407   /* Do not know such property */
408   return Qunbound;
409 }
410
411 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)
433 {
434   mark_object (DEVICE_MSPRINTER_FONTLIST (d));
435 }
436
437 static unsigned int
438 msprinter_device_implementation_flags (void)
439 {
440   return (  XDEVIMPF_PIXEL_GEOMETRY
441           | XDEVIMPF_IS_A_PRINTER
442           | XDEVIMPF_NO_AUTO_REDISPLAY
443           | XDEVIMPF_FRAMELESS_OK );
444 }
445
446 \f
447 /************************************************************************/
448 /*                      printer external functions                      */
449 /************************************************************************/
450
451 /* 
452  * Return a copy of default DEVMODE. The copy returned is in
453  * a static buffer which will be overwritten by next call.
454  */
455 DEVMODE*
456 msprinter_get_devmode_copy (struct device *d)
457 {
458   assert (DEVICE_MSPRINTER_P (d));
459
460   if (DEVICE_MSPRINTER_DEVMODE_MIRROR(d) == NULL)
461     DEVICE_MSPRINTER_DEVMODE_MIRROR(d) = 
462       xmalloc (DEVICE_MSPRINTER_DEVMODE_SIZE(d));
463
464   memcpy (DEVICE_MSPRINTER_DEVMODE_MIRROR(d),
465           DEVICE_MSPRINTER_DEVMODE(d),
466           DEVICE_MSPRINTER_DEVMODE_SIZE(d));
467
468   return DEVICE_MSPRINTER_DEVMODE_MIRROR(d);
469 }
470
471 /*
472  * Apply settings from the DEVMODE. The settings are considered
473  * incremental to the default DEVMODE, so that changes in the
474  * passed structure supercede parameters of the printer.
475  *
476  * The passed structure is overwritten by the fuction call;
477  * complete printer settings are returned.
478  */
479 void
480 msprinter_apply_devmode (struct device *d, DEVMODE *devmode)
481 {
482   assert (DEVICE_MSPRINTER_P (d));
483
484   DocumentProperties (NULL,
485                       DEVICE_MSPRINTER_HPRINTER(d),
486                       DEVICE_MSPRINTER_NAME(d),
487                       devmode, devmode,
488                       DM_IN_BUFFER | DM_OUT_BUFFER);
489
490   ResetDC (DEVICE_MSPRINTER_HDC (d), devmode);
491 }
492
493 \f
494 /************************************************************************/
495 /*                            initialization                            */
496 /************************************************************************/
497
498 void
499 syms_of_device_mswindows (void)
500 {
501   defsymbol (&Qinit_pre_mswindows_win, "init-pre-mswindows-win");
502   defsymbol (&Qinit_post_mswindows_win, "init-post-mswindows-win");
503 }
504
505 void
506 console_type_create_device_mswindows (void)
507 {
508   CONSOLE_HAS_METHOD (mswindows, init_device);
509   CONSOLE_HAS_METHOD (mswindows, finish_init_device);
510   CONSOLE_HAS_METHOD (mswindows, mark_device);
511   CONSOLE_HAS_METHOD (mswindows, delete_device);
512   CONSOLE_HAS_METHOD (mswindows, device_system_metrics);
513   CONSOLE_HAS_METHOD (mswindows, device_implementation_flags);
514
515   CONSOLE_HAS_METHOD (msprinter, init_device);
516   CONSOLE_HAS_METHOD (msprinter, mark_device);
517   CONSOLE_HAS_METHOD (msprinter, delete_device);
518   CONSOLE_HAS_METHOD (msprinter, device_system_metrics);
519   CONSOLE_HAS_METHOD (msprinter, device_implementation_flags);
520 }
521
522
523 void
524 vars_of_device_mswindows (void)
525 {
526   DEFVAR_LISP ("mswindows-downcase-file-names", &Vmswindows_downcase_file_names /*
527 Non-nil means convert all-upper case file names to lower case.
528 This applies when performing completions and file name expansion.
529 */ );
530   Vmswindows_downcase_file_names = Qnil;
531
532   DEFVAR_LISP ("mswindows-get-true-file-attributes", &Vmswindows_get_true_file_attributes /*
533 Non-nil means determine accurate link count in file-attributes.
534 This option slows down file-attributes noticeably, so is disabled by
535 default.  Note that it is only useful for files on NTFS volumes,
536 where hard links are supported.
537 */ );
538   Vmswindows_get_true_file_attributes = Qnil;
539 }