XEmacs 21.2.34 "Molpe".
[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 "objects-msw.h"
38 #include "events.h"
39 #include "faces.h"
40 #include "frame.h"
41 #include "sysdep.h"
42
43 #if !(defined (__CYGWIN32__) || defined(__MINGW32__))
44 # include <objbase.h>   /* For CoInitialize */
45 #endif
46
47 /* win32 DDE management library globals */
48 #ifdef HAVE_DRAGNDROP
49 DWORD mswindows_dde_mlid;
50 HSZ mswindows_dde_service;
51 HSZ mswindows_dde_topic_system;
52 HSZ mswindows_dde_item_open;
53 #endif
54
55 /* Control conversion of upper case file names to lower case.
56    nil means no, t means yes. */
57 Lisp_Object Vmswindows_downcase_file_names;
58
59 /* Control whether stat() attempts to determine file type and link count
60    exactly, at the expense of slower operation.  Since true hard links
61    are supported on NTFS volumes, this is only relevant on NT.  */
62 Lisp_Object Vmswindows_get_true_file_attributes;
63
64 Lisp_Object Qinit_pre_mswindows_win, Qinit_post_mswindows_win;
65
66
67 /************************************************************************/
68 /*                               helpers                                */
69 /************************************************************************/
70
71 static Lisp_Object
72 build_syscolor_string (int idx)
73 {
74   return (idx < 0 ? Qnil : mswindows_color_to_string (GetSysColor (idx)));
75 }
76
77 static Lisp_Object
78 build_syscolor_cons (int index1, int index2)
79 {
80   Lisp_Object color1, color2;
81   struct gcpro gcpro1;
82   GCPRO1 (color1);
83   color1 = build_syscolor_string (index1);
84   color2 = build_syscolor_string (index2);
85   RETURN_UNGCPRO (Fcons (color1, color2));
86 }
87
88 static Lisp_Object
89 build_sysmetrics_cons (int index1, int index2)
90 {
91   return Fcons (index1 < 0 ? Qnil : make_int (GetSystemMetrics (index1)),
92                 index2 < 0 ? Qnil : make_int (GetSystemMetrics (index2)));
93 }
94
95 static Lisp_Object
96 build_devicecaps_cons (HDC hdc, int index1, int index2)
97 {
98   return Fcons (index1 < 0 ? Qnil : make_int (GetDeviceCaps (hdc, index1)),
99                 index2 < 0 ? Qnil : make_int (GetDeviceCaps (hdc, index2)));
100 }
101
102
103 \f
104 /************************************************************************/
105 /*                          display methods                             */
106 /************************************************************************/
107
108 static void
109 mswindows_init_device (struct device *d, Lisp_Object props)
110 {
111   WNDCLASSEX wc;
112   HDC hdc;
113
114   DEVICE_CLASS (d) = Qcolor;
115   DEVICE_INFD (d) = DEVICE_OUTFD (d) = -1;
116   init_baud_rate (d);
117   init_one_device (d);
118
119   d->device_data = xnew_and_zero (struct mswindows_device);
120   hdc = CreateCompatibleDC (NULL);
121   assert (hdc!=NULL);
122   DEVICE_MSWINDOWS_LOGPIXELSX(d) =  GetDeviceCaps(hdc, LOGPIXELSX);
123   DEVICE_MSWINDOWS_LOGPIXELSY(d) =  GetDeviceCaps(hdc, LOGPIXELSY);
124   DEVICE_MSWINDOWS_PLANES(d) = GetDeviceCaps(hdc, PLANES);
125   /* #### SIZEPALETTE only valid if RC_PALETTE bit set in RASTERCAPS,
126      what should we return for a non-palette-based device? */
127   DEVICE_MSWINDOWS_CELLS(d) = GetDeviceCaps(hdc, SIZEPALETTE);
128   DEVICE_MSWINDOWS_HORZRES(d) = GetDeviceCaps(hdc, HORZRES);
129   DEVICE_MSWINDOWS_VERTRES(d) = GetDeviceCaps(hdc, VERTRES);
130   DEVICE_MSWINDOWS_HORZSIZE(d) = GetDeviceCaps(hdc, HORZSIZE);
131   DEVICE_MSWINDOWS_VERTSIZE(d) = GetDeviceCaps(hdc, VERTSIZE);
132   DEVICE_MSWINDOWS_BITSPIXEL(d) = GetDeviceCaps(hdc, BITSPIXEL);
133   DEVICE_MSWINDOWS_FONTLIST (d) = mswindows_enumerate_fonts (hdc);
134   
135   DEVICE_MSWINDOWS_HCDC(d) = hdc;
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. */
145   wc.hInstance = NULL;  
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;
154   wc.hIconSm = (HICON) LoadImage (GetModuleHandle (NULL), XEMACS_CLASS,
155                           IMAGE_ICON, 16, 16, 0);
156   RegisterClassEx (&wc);
157
158 #ifdef HAVE_WIDGETS
159   xzero (wc);
160   /* Register the main window class */
161   wc.cbSize = sizeof (WNDCLASSEX);
162   wc.lpfnWndProc = (WNDPROC) mswindows_control_wnd_proc;
163   wc.lpszClassName = XEMACS_CONTROL_CLASS;
164   wc.hInstance = NULL;
165   RegisterClassEx (&wc);
166 #endif
167
168 #if defined (HAVE_TOOLBARS) || defined (HAVE_WIDGETS)
169   InitCommonControls ();
170 #endif
171 }
172
173 static void
174 mswindows_finish_init_device (struct device *d, Lisp_Object props)
175 {
176   /* Initialize DDE management library and our related globals. We execute a
177    * dde Open("file") by simulating a drop, so this depends on dnd support. */
178 #ifdef HAVE_DRAGNDROP
179 # if !(defined(__CYGWIN32__) || defined(__MINGW32__))
180   CoInitialize (NULL);
181 # endif
182
183   mswindows_dde_mlid = 0;
184   DdeInitialize (&mswindows_dde_mlid, (PFNCALLBACK)mswindows_dde_callback,
185                  APPCMD_FILTERINITS|CBF_FAIL_SELFCONNECTIONS|CBF_FAIL_ADVISES|
186                  CBF_FAIL_POKES|CBF_FAIL_REQUESTS|CBF_SKIP_ALLNOTIFICATIONS,
187                  0);
188   
189   mswindows_dde_service = DdeCreateStringHandle (mswindows_dde_mlid,
190                                                  XEMACS_CLASS, 0);
191   mswindows_dde_topic_system = DdeCreateStringHandle (mswindows_dde_mlid,
192                                                       SZDDESYS_TOPIC, 0);
193   mswindows_dde_item_open = DdeCreateStringHandle (mswindows_dde_mlid,
194                                                    TEXT(MSWINDOWS_DDE_ITEM_OPEN), 0);
195   DdeNameService (mswindows_dde_mlid, mswindows_dde_service, 0L, DNS_REGISTER);
196 #endif
197 }
198
199 static void
200 mswindows_delete_device (struct device *d)
201 {
202 #ifdef HAVE_DRAGNDROP
203   DdeNameService (mswindows_dde_mlid, 0L, 0L, DNS_UNREGISTER);
204   DdeFreeStringHandle (mswindows_dde_mlid, mswindows_dde_item_open);
205   DdeFreeStringHandle (mswindows_dde_mlid, mswindows_dde_topic_system);
206   DdeFreeStringHandle (mswindows_dde_mlid, mswindows_dde_service);
207   DdeUninitialize (mswindows_dde_mlid);
208
209 # if !(defined(__CYGWIN32__) || defined(__MINGW32__))
210   CoUninitialize ();
211 # endif
212 #endif
213
214   DeleteDC (DEVICE_MSWINDOWS_HCDC(d));
215   free (d->device_data);
216 }
217
218 void
219 msw_get_workspace_coords (RECT *rc)
220 {
221   SystemParametersInfo (SPI_GETWORKAREA, 0, rc, 0);
222 }
223
224 static void
225 mswindows_mark_device (struct device *d)
226 {
227   mark_object (DEVICE_MSWINDOWS_FONTLIST (d));
228 }
229
230 static Lisp_Object
231 mswindows_device_system_metrics (struct device *d,
232                                  enum device_metrics m)
233 {
234   switch (m)
235     {
236     case DM_size_device:
237       return Fcons (make_int (DEVICE_MSWINDOWS_HORZRES(d)),
238                     make_int (DEVICE_MSWINDOWS_VERTRES(d)));
239       break;
240     case DM_device_dpi:
241       return Fcons (make_int (DEVICE_MSWINDOWS_LOGPIXELSX(d)),
242                     make_int (DEVICE_MSWINDOWS_LOGPIXELSY(d)));
243       break;
244     case DM_size_device_mm:
245       return Fcons (make_int (DEVICE_MSWINDOWS_HORZSIZE(d)),
246                     make_int (DEVICE_MSWINDOWS_VERTSIZE(d)));
247       break;
248     case DM_num_bit_planes:
249       /* this is what X means by bitplanes therefore we ought to be
250          consistent. num planes is always 1 under mswindows and
251          therefore useless */
252       return make_int (DEVICE_MSWINDOWS_BITSPIXEL(d));
253       break;
254     case DM_num_color_cells:
255       return make_int (DEVICE_MSWINDOWS_CELLS(d));
256       break;
257
258       /*** Colors ***/
259 #define FROB(met, fore, back)                           \
260     case DM_##met:                                      \
261       return build_syscolor_cons (fore, back);
262       
263       FROB (color_default, COLOR_WINDOWTEXT, COLOR_WINDOW);
264       FROB (color_select, COLOR_HIGHLIGHTTEXT, COLOR_HIGHLIGHT);
265       FROB (color_balloon, COLOR_INFOTEXT, COLOR_INFOBK);
266       FROB (color_3d_face, COLOR_BTNTEXT, COLOR_BTNFACE);
267       FROB (color_3d_light, COLOR_3DHILIGHT, COLOR_3DLIGHT);
268       FROB (color_3d_dark, COLOR_3DDKSHADOW, COLOR_3DSHADOW);
269       FROB (color_menu, COLOR_MENUTEXT, COLOR_MENU);
270       FROB (color_menu_highlight, COLOR_HIGHLIGHTTEXT, COLOR_HIGHLIGHT);
271       FROB (color_menu_button, COLOR_MENUTEXT, COLOR_MENU);
272       FROB (color_menu_disabled, COLOR_GRAYTEXT, COLOR_MENU);
273       FROB (color_toolbar, COLOR_BTNTEXT, COLOR_BTNFACE);
274       FROB (color_scrollbar, COLOR_CAPTIONTEXT, COLOR_SCROLLBAR);
275       FROB (color_desktop, -1, COLOR_DESKTOP);
276       FROB (color_workspace, -1, COLOR_APPWORKSPACE);
277 #undef FROB
278
279       /*** Sizes ***/
280 #define FROB(met, index1, index2)                       \
281     case DM_##met:                                      \
282       return build_sysmetrics_cons (index1, index2);
283
284       FROB (size_cursor, SM_CXCURSOR, SM_CYCURSOR);
285       FROB (size_scrollbar, SM_CXVSCROLL, SM_CYHSCROLL);
286       FROB (size_menu, -1, SM_CYMENU);
287       FROB (size_icon, SM_CXICON, SM_CYICON);
288       FROB (size_icon_small, SM_CXSMICON, SM_CYSMICON);
289 #undef FROB
290
291     case DM_size_workspace:
292       {
293         RECT rc;
294         msw_get_workspace_coords (&rc);
295         return Fcons (make_int (rc.right - rc.left),
296                       make_int (rc.bottom - rc.top));
297       }
298
299     case DM_offset_workspace:
300       {
301         RECT rc;
302         msw_get_workspace_coords (&rc);
303         return Fcons (make_int (rc.left), make_int (rc.top));
304       }
305
306       /*
307         case DM_size_toolbar:
308         case DM_size_toolbar_button:
309         case DM_size_toolbar_border:
310       */
311
312       /*** Features ***/
313 #define FROB(met, index)                        \
314     case DM_##met:                              \
315       return make_int (GetSystemMetrics (index));
316
317       FROB (mouse_buttons, SM_CMOUSEBUTTONS);
318       FROB (swap_buttons, SM_SWAPBUTTON);
319       FROB (show_sounds, SM_SHOWSOUNDS);
320       FROB (slow_device, SM_SLOWMACHINE);
321       FROB (security, SM_SECURE);
322 #undef FROB
323
324     }
325
326   /* Do not know such property */
327   return Qunbound;
328 }
329
330 static unsigned int
331 mswindows_device_implementation_flags (void)
332 {
333   return XDEVIMPF_PIXEL_GEOMETRY;
334 }
335
336 \f
337 /************************************************************************/
338 /*                          printer methods                             */
339 /************************************************************************/
340
341 static void
342 signal_open_printer_error (struct device *d)
343 {
344   signal_simple_error ("Failed to open printer", DEVICE_CONNECTION (d));
345 }
346
347 static void
348 msprinter_init_device (struct device *d, Lisp_Object props)
349 {
350   char* printer_name;
351
352   DEVICE_INFD (d) = DEVICE_OUTFD (d) = -1;
353
354   CHECK_STRING (DEVICE_CONNECTION (d));
355
356   TO_EXTERNAL_FORMAT (LISP_STRING, DEVICE_CONNECTION (d),
357                       C_STRING_ALLOCA, printer_name,
358                       Qctext);
359
360   d->device_data = xnew_and_zero (struct msprinter_device);
361
362   DEVICE_MSPRINTER_NAME(d) = xstrdup (printer_name);
363
364   if (!OpenPrinter (printer_name, &DEVICE_MSPRINTER_HPRINTER (d), NULL))
365     {
366       DEVICE_MSPRINTER_HPRINTER (d) = NULL;
367       signal_open_printer_error (d);
368     }
369
370   DEVICE_MSPRINTER_HDC (d) = CreateDC ("WINSPOOL", printer_name,
371                                        NULL, NULL);
372   if (DEVICE_MSPRINTER_HDC (d) == NULL)
373     signal_open_printer_error (d);
374
375   DEVICE_MSPRINTER_HCDC(d) =
376     CreateCompatibleDC (DEVICE_MSPRINTER_HDC (d));
377
378   /* Determinie DEVMODE size and store the default DEVMODE */
379   DEVICE_MSPRINTER_DEVMODE_SIZE(d) =
380     DocumentProperties (NULL, DEVICE_MSPRINTER_HPRINTER(d),
381                         printer_name, NULL, NULL, 0);
382   if (DEVICE_MSPRINTER_DEVMODE_SIZE(d) <= 0)
383     signal_open_printer_error (d);
384
385   DEVICE_MSPRINTER_DEVMODE(d) =
386     (DEVMODE*) xmalloc (DEVICE_MSPRINTER_DEVMODE_SIZE(d));
387   DocumentProperties (NULL, DEVICE_MSPRINTER_HPRINTER(d),
388                       printer_name, DEVICE_MSPRINTER_DEVMODE(d),
389                       NULL, DM_OUT_BUFFER);
390
391   /* We do not use printer fon list as we do with the display
392      device. Rather, we allow GDI to pick the closest match to the
393      display font. */
394   DEVICE_MSPRINTER_FONTLIST (d) = Qnil;
395
396   DEVICE_CLASS (d) = (GetDeviceCaps (DEVICE_MSPRINTER_HDC (d), BITSPIXEL)
397                       * GetDeviceCaps (DEVICE_MSPRINTER_HDC (d), PLANES)
398                       > 1) ? Qcolor : Qmono;
399 }
400
401 static Lisp_Object
402 msprinter_device_system_metrics (struct device *d,
403                                  enum device_metrics m)
404 {
405   switch (m)
406     {
407       /* Device sizes - pixel and mm */
408 #define FROB(met, index1, index2)                       \
409     case DM_##met:                                      \
410       return build_devicecaps_cons                      \
411          (DEVICE_MSPRINTER_HDC(d), index1, index2);
412
413       FROB (size_device, PHYSICALWIDTH, PHYSICALHEIGHT);
414       FROB (size_device_mm, HORZSIZE, VERTSIZE);
415       FROB (size_workspace, HORZRES, VERTRES);
416       FROB (offset_workspace, PHYSICALOFFSETX, PHYSICALOFFSETY);
417       FROB (device_dpi, LOGPIXELSX, LOGPIXELSY);
418 #undef FROB
419
420     case DM_num_bit_planes:
421       /* this is what X means by bitplanes therefore we ought to be
422          consistent. num planes is always 1 under mswindows and
423          therefore useless */
424       return make_int (GetDeviceCaps (DEVICE_MSPRINTER_HDC(d), BITSPIXEL));
425
426     case DM_num_color_cells:    /* Prnters are non-palette devices */
427     case DM_slow_device:        /* Animation would be a really bad idea */
428     case DM_security:           /* Not provided by windows */
429       return Qzero;
430     }
431
432   /* Do not know such property */
433   return Qunbound;
434 }
435
436 static void
437 msprinter_delete_device (struct device *d)
438 {
439   if (d->device_data)
440     {
441       if (DEVICE_MSPRINTER_HPRINTER (d))
442         ClosePrinter (DEVICE_MSPRINTER_HPRINTER (d));
443       if (DEVICE_MSPRINTER_HDC (d))
444         DeleteDC (DEVICE_MSPRINTER_HDC (d));
445       if (DEVICE_MSPRINTER_HCDC (d))
446         DeleteDC (DEVICE_MSPRINTER_HCDC (d));
447       if (DEVICE_MSPRINTER_NAME (d))
448         free (DEVICE_MSPRINTER_NAME (d));
449       if (DEVICE_MSPRINTER_DEVMODE (d))
450         free (DEVICE_MSPRINTER_DEVMODE (d));
451       if (DEVICE_MSPRINTER_DEVMODE_MIRROR (d))
452         free (DEVICE_MSPRINTER_DEVMODE_MIRROR (d));
453
454       free (d->device_data);
455     }
456 }
457
458 static void
459 msprinter_mark_device (struct device *d)
460 {
461   mark_object (DEVICE_MSPRINTER_FONTLIST (d));
462 }
463
464 static unsigned int
465 msprinter_device_implementation_flags (void)
466 {
467   return (  XDEVIMPF_PIXEL_GEOMETRY
468           | XDEVIMPF_IS_A_PRINTER
469           | XDEVIMPF_NO_AUTO_REDISPLAY
470           | XDEVIMPF_FRAMELESS_OK );
471 }
472
473 \f
474 /************************************************************************/
475 /*                      printer external functions                      */
476 /************************************************************************/
477
478 /* 
479  * Return a copy of default DEVMODE. The copy returned is in
480  * a static buffer which will be overwritten by next call.
481  */
482 DEVMODE*
483 msprinter_get_devmode_copy (struct device *d)
484 {
485   assert (DEVICE_MSPRINTER_P (d));
486
487   if (DEVICE_MSPRINTER_DEVMODE_MIRROR(d) == NULL)
488     DEVICE_MSPRINTER_DEVMODE_MIRROR(d) = 
489       (DEVMODE*) xmalloc (DEVICE_MSPRINTER_DEVMODE_SIZE(d));
490
491   memcpy (DEVICE_MSPRINTER_DEVMODE_MIRROR(d),
492           DEVICE_MSPRINTER_DEVMODE(d),
493           DEVICE_MSPRINTER_DEVMODE_SIZE(d));
494
495   return DEVICE_MSPRINTER_DEVMODE_MIRROR(d);
496 }
497
498 /*
499  * Apply settings from the DEVMODE. The settings are considered
500  * incremental to the default DEVMODE, so that changes in the
501  * passed structure supercede parameters of the printer.
502  *
503  * The passed structure is overwritten by the fuction call;
504  * complete printer settings are returned.
505  */
506 void
507 msprinter_apply_devmode (struct device *d, DEVMODE *devmode)
508 {
509   assert (DEVICE_MSPRINTER_P (d));
510
511   DocumentProperties (NULL,
512                       DEVICE_MSPRINTER_HPRINTER(d),
513                       DEVICE_MSPRINTER_NAME(d),
514                       devmode, devmode,
515                       DM_IN_BUFFER | DM_OUT_BUFFER);
516
517   /* #### ResetDC fails sometimes, Bill only know s why.
518      The solution below looks more like a workaround to me,
519      although it might be fine. --kkm */
520   if (ResetDC (DEVICE_MSPRINTER_HDC (d), devmode) == NULL)
521     {
522       DeleteDC (DEVICE_MSPRINTER_HDC (d));
523       DEVICE_MSPRINTER_HDC (d) =
524         CreateDC ("WINSPOOL", DEVICE_MSPRINTER_NAME(d), NULL, devmode);
525     }
526 }
527
528 \f
529 /************************************************************************/
530 /*                            initialization                            */
531 /************************************************************************/
532
533 void
534 syms_of_device_mswindows (void)
535 {
536   defsymbol (&Qinit_pre_mswindows_win, "init-pre-mswindows-win");
537   defsymbol (&Qinit_post_mswindows_win, "init-post-mswindows-win");
538 }
539
540 void
541 console_type_create_device_mswindows (void)
542 {
543   CONSOLE_HAS_METHOD (mswindows, init_device);
544   CONSOLE_HAS_METHOD (mswindows, finish_init_device);
545   CONSOLE_HAS_METHOD (mswindows, mark_device);
546   CONSOLE_HAS_METHOD (mswindows, delete_device);
547   CONSOLE_HAS_METHOD (mswindows, device_system_metrics);
548   CONSOLE_HAS_METHOD (mswindows, device_implementation_flags);
549
550   CONSOLE_HAS_METHOD (msprinter, init_device);
551   CONSOLE_HAS_METHOD (msprinter, mark_device);
552   CONSOLE_HAS_METHOD (msprinter, delete_device);
553   CONSOLE_HAS_METHOD (msprinter, device_system_metrics);
554   CONSOLE_HAS_METHOD (msprinter, device_implementation_flags);
555 }
556
557
558 void
559 vars_of_device_mswindows (void)
560 {
561   DEFVAR_LISP ("mswindows-downcase-file-names", &Vmswindows_downcase_file_names /*
562 Non-nil means convert all-upper case file names to lower case.
563 This applies when performing completions and file name expansion.
564 */ );
565   Vmswindows_downcase_file_names = Qnil;
566
567   DEFVAR_LISP ("mswindows-get-true-file-attributes", &Vmswindows_get_true_file_attributes /*
568 Non-nil means determine accurate link count in file-attributes.
569 This option slows down file-attributes noticeably, so is disabled by
570 default.  Note that it is only useful for files on NTFS volumes,
571 where hard links are supported.
572 */ );
573   Vmswindows_get_true_file_attributes = Qnil;
574 }