import -ko -b 1.1.3 XEmacs XEmacs-21_2 r21-2-35
[chise/xemacs-chise.git.1] / src / console-msw.c
1 /* Console functions for mswindows.
2    Copyright (C) 1996, 2000 Ben Wing.
3
4 This file is part of XEmacs.
5
6 XEmacs is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
9 later version.
10
11 XEmacs is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with XEmacs; see the file COPYING.  If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.  */
20
21 /* Synched up with: Not in FSF. */
22
23 /* Authorship:
24
25    Ben Wing: January 1996, for 19.14.
26    Rewritten for mswindows by Jonathan Harris, November 1997 for 21.0
27  */
28
29 #include <config.h>
30 #include "lisp.h"
31
32 #include "buffer.h"
33 #include "console-msw.h"
34 #include "events.h"
35 #include "opaque.h"
36
37 DEFINE_CONSOLE_TYPE (mswindows);
38 DEFINE_CONSOLE_TYPE (msprinter);
39
40 Lisp_Object Qabortretryignore;
41 Lisp_Object Qapplmodal;
42 Lisp_Object Qdefault_desktop_only;
43 Lisp_Object Qdefbutton1;
44 Lisp_Object Qdefbutton2;
45 Lisp_Object Qdefbutton3;
46 Lisp_Object Qdefbutton4;
47 /* Lisp_Object Qhelp; */
48 Lisp_Object Qiconasterisk;
49 Lisp_Object Qiconexclamation;
50 Lisp_Object Qiconhand;
51 Lisp_Object Qiconinformation;
52 Lisp_Object Qiconquestion;
53 Lisp_Object Qiconstop;
54 /* Lisp_Object Qok; */
55 Lisp_Object Qokcancel;
56 Lisp_Object Qretrycancel;
57 /* Lisp_Object Qright; */
58 Lisp_Object Qrtlreading;
59 Lisp_Object Qservice_notification;
60 Lisp_Object Qsetforeground;
61 Lisp_Object Qsystemmodal;
62 Lisp_Object Qtaskmodal;
63 Lisp_Object Qtopmost;
64 Lisp_Object Qyesno;
65 Lisp_Object Qyesnocancel;
66
67 /* Lisp_Object Qabort; */
68 /* Lisp_Object Qcancel; */
69 /* Lisp_Object Qignore; */
70 /* Lisp_Object Qno; */
71 /* Lisp_Object Qok; */
72 /* Lisp_Object Qretry; */
73 /* Lisp_Object Qyes; */
74
75
76 /************************************************************************/
77 /*                       mswindows console methods                      */
78 /************************************************************************/
79
80 static int
81 mswindows_initially_selected_for_input (struct console *con)
82 {
83   return 1;
84 }
85
86 static HWND mswindows_console_hwnd = 0;
87
88 #define KLUDGE_BUFSIZE 1024 /* buffer size for console window titles */
89
90 /* Direct from the horse's mouth: Microsoft KB article Q124103 */
91 static HWND
92 GetConsoleHwnd (void)
93
94   HWND hwndFound;         /* this is what is returned to the caller */
95   char pszNewWindowTitle[KLUDGE_BUFSIZE]; /* contains fabricated WindowTitle */
96   char pszOldWindowTitle[KLUDGE_BUFSIZE]; /* contains original WindowTitle */
97
98   /* fetch current window title */
99
100   GetConsoleTitle(pszOldWindowTitle, KLUDGE_BUFSIZE);
101
102   /* format a "unique" NewWindowTitle */
103
104   wsprintf(pszNewWindowTitle,"%d/%d",
105            GetTickCount(),
106            GetCurrentProcessId());
107
108   /* change current window title */
109
110   SetConsoleTitle(pszNewWindowTitle);
111
112   /* ensure window title has been updated */
113
114   Sleep(40);
115
116   /* look for NewWindowTitle */
117
118   hwndFound=FindWindow(NULL, pszNewWindowTitle);
119
120   /* restore original window title */
121
122   SetConsoleTitle(pszOldWindowTitle);
123
124   return(hwndFound);
125
126
127 HWND
128 mswindows_get_console_hwnd (void)
129 {
130   if (!mswindows_console_hwnd)
131     mswindows_console_hwnd = GetConsoleHwnd ();
132   return mswindows_console_hwnd;
133 }
134
135 static int
136 mswindows_ensure_console_allocated (void)
137 {
138   HWND fgwin = GetForegroundWindow ();
139   /* stupid mswin api won't let you create the console window
140      hidden!  creating it changes the focus!  fuck me! */
141   if (AllocConsole ())
142     {
143       SetForegroundWindow (fgwin);
144       return 1;
145     }
146   return 0;
147 }
148
149 static Lisp_Object
150 mswindows_canonicalize_console_connection (Lisp_Object connection,
151                                            Error_behavior errb)
152 {
153   /* Do not allow more than one mswindows device, by explicitly
154      requiring that CONNECTION is nil, the only allowed connection in
155      Windows. */
156   if (!NILP (connection))
157     {
158       if (ERRB_EQ (errb, ERROR_ME))
159         signal_simple_error
160           ("Invalid (non-nil) connection for mswindows device/console",
161            connection);
162       else
163         return Qunbound;
164     }
165
166   return Qnil;
167 }
168
169 static Lisp_Object
170 mswindows_canonicalize_device_connection (Lisp_Object connection,
171                                           Error_behavior errb)
172 {
173   return mswindows_canonicalize_console_connection (connection, errb);
174 }
175
176 void
177 mswindows_hide_console (void)
178 {
179   ShowWindow (mswindows_get_console_hwnd (), SW_HIDE);
180 }
181
182 void
183 mswindows_show_console (void)
184 {
185   HWND hwnd = mswindows_get_console_hwnd ();
186   ShowWindow (hwnd, SW_SHOWNA);
187
188   /* I tried to raise the window to the top without activating
189      it, but this fails.  Apparently Windows just doesn't like
190      having the active window not be on top.  So instead, we
191      at least put it just below our own window, where part of it
192      will likely be seen. */
193   SetWindowPos (hwnd, GetForegroundWindow (), 0, 0, 0, 0,
194                 SWP_NOSIZE | SWP_NOMOVE | SWP_NOSENDCHANGING |
195                 SWP_NOACTIVATE);
196 }
197
198 static int mswindows_console_buffered = 0;
199 HANDLE mswindows_console_buffer;
200
201 static void
202 mswindows_ensure_console_buffered (void)
203 {
204   if (!mswindows_console_buffered)
205     {
206       COORD new_size;
207
208       new_size.X = 80;
209       new_size.Y = 1000;
210       mswindows_ensure_console_allocated ();
211       mswindows_console_buffer =
212         CreateConsoleScreenBuffer (GENERIC_WRITE, 0, NULL,
213                                    CONSOLE_TEXTMODE_BUFFER, NULL);
214       SetConsoleScreenBufferSize (mswindows_console_buffer, new_size);
215       SetConsoleActiveScreenBuffer (mswindows_console_buffer);
216       mswindows_console_buffered = 1;
217     }
218 }
219
220 int mswindows_message_outputted;
221
222 int
223 mswindows_output_console_string (CONST Extbyte *str, Extcount len)
224 {
225   DWORD num_written;
226
227   mswindows_message_outputted = 1;
228   mswindows_ensure_console_buffered ();
229   mswindows_show_console ();
230   return WriteConsole (mswindows_console_buffer, str, len, &num_written, NULL);
231 }
232
233 /* Determine if running on Windows 9x and not NT */
234 int
235 mswindows_windows9x_p (void)
236 {
237   return GetVersion () & 0x80000000;
238 }
239
240
241 #ifdef DEBUG_XEMACS
242
243 /*
244  * Random helper functions for debugging.
245  * Intended for use in the MSVC "Watch" window which doesn't like
246  * the aborts that the error_check_foo() functions can make.
247  */
248 struct lrecord_header *DHEADER (Lisp_Object obj);
249 struct lrecord_header *
250 DHEADER (Lisp_Object obj)
251 {
252   return LRECORDP (obj) ? XRECORD_LHEADER (obj) : NULL;
253 }
254
255 void *DOPAQUE_DATA (Lisp_Object obj);
256 void *
257 DOPAQUE_DATA (Lisp_Object obj)
258 {
259   return OPAQUEP (obj) ? OPAQUE_DATA (XOPAQUE (obj)) : NULL;
260 }
261
262 Lisp_Event *DEVENT (Lisp_Object obj);
263 Lisp_Event *
264 DEVENT (Lisp_Object obj)
265 {
266   return EVENTP (obj) ? XEVENT (obj) : NULL;
267 }
268
269 Lisp_Cons *DCONS (Lisp_Object obj);
270 Lisp_Cons *
271 DCONS (Lisp_Object obj)
272 {
273   return CONSP (obj) ? XCONS (obj) : NULL;
274 }
275
276 Lisp_Cons *DCONSCDR (Lisp_Object obj);
277 Lisp_Cons *
278 DCONSCDR (Lisp_Object obj)
279 {
280   return (CONSP (obj) && CONSP (XCDR (obj))) ? XCONS (XCDR (obj)) : 0;
281 }
282
283 Bufbyte *DSTRING (Lisp_Object obj);
284 Bufbyte *
285 DSTRING (Lisp_Object obj)
286 {
287   return STRINGP (obj) ? XSTRING_DATA (obj) : NULL;
288 }
289
290 Lisp_Vector *DVECTOR (Lisp_Object obj);
291 Lisp_Vector *
292 DVECTOR (Lisp_Object obj)
293 {
294   return VECTORP (obj) ? XVECTOR (obj) : NULL;
295 }
296
297 Lisp_Symbol *DSYMBOL (Lisp_Object obj);
298 Lisp_Symbol *
299 DSYMBOL (Lisp_Object obj)
300 {
301   return SYMBOLP (obj) ? XSYMBOL (obj) : NULL;
302 }
303
304 Bufbyte *DSYMNAME (Lisp_Object obj);
305 Bufbyte *
306 DSYMNAME (Lisp_Object obj)
307 {
308   return SYMBOLP (obj) ? string_data (XSYMBOL (obj)->name) : NULL;
309 }
310
311 #endif /* DEBUG_XEMACS */
312
313 DEFUN ("mswindows-message-box", Fmswindows_message_box, 1, 3, 0, /*
314 Pop up an MS Windows message box.
315 MESSAGE is the string to display.  Optional argument FLAG controls
316 what appears in the box and how it behaves; it is a symbol or list of
317 symbols, described below.  Second optional argument TITLE controls the
318 title bar; if omitted, a standard title bar will be used, probably
319 displaying "XEmacs".
320
321 Possible flags are
322
323
324 -- To specify the buttons in the message box:
325
326 abortretryignore 
327   The message box contains three push buttons: Abort, Retry, and Ignore. 
328 ok 
329   The message box contains one push button: OK. This is the default. 
330 okcancel 
331   The message box contains two push buttons: OK and Cancel. 
332 retrycancel 
333   The message box contains two push buttons: Retry and Cancel. 
334 yesno 
335   The message box contains two push buttons: Yes and No. 
336 yesnocancel 
337   The message box contains three push buttons: Yes, No, and Cancel. 
338
339
340 -- To display an icon in the message box:
341  
342 iconexclamation, iconwarning
343   An exclamation-point icon appears in the message box. 
344 iconinformation, iconasterisk
345   An icon consisting of a lowercase letter i in a circle appears in
346   the message box. 
347 iconquestion
348   A question-mark icon appears in the message box. 
349 iconstop, iconerror, iconhand
350   A stop-sign icon appears in the message box. 
351
352
353 -- To indicate the default button: 
354
355 defbutton1
356   The first button is the default button.  This is the default.
357 defbutton2
358   The second button is the default button. 
359 defbutton3
360   The third button is the default button. 
361 defbutton4
362   The fourth button is the default button. 
363
364
365 -- To indicate the modality of the dialog box:
366  
367 applmodal
368   The user must respond to the message box before continuing work in
369   the window identified by the hWnd parameter. However, the user can
370   move to the windows of other applications and work in those windows.
371   Depending on the hierarchy of windows in the application, the user
372   may be able to move to other windows within the application. All
373   child windows of the parent of the message box are automatically
374   disabled, but popup windows are not.  This is the default.
375 systemmodal
376   Same as applmodal except that the message box has the WS_EX_TOPMOST
377   style. Use system-modal message boxes to notify the user of serious,
378   potentially damaging errors that require immediate attention (for
379   example, running out of memory). This flag has no effect on the
380   user's ability to interact with windows other than those associated
381   with hWnd.
382 taskmodal
383   Same as applmodal except that all the top-level windows belonging to
384   the current task are disabled if the hWnd parameter is NULL. Use
385   this flag when the calling application or library does not have a
386   window handle available but still needs to prevent input to other
387   windows in the current application without suspending other
388   applications.
389
390
391 In addition, you can specify the following flags: 
392
393 default-desktop-only 
394   The desktop currently receiving input must be a default desktop;
395   otherwise, the function fails. A default desktop is one an
396   application runs on after the user has logged on.
397 help 
398   Adds a Help button to the message box. Choosing the Help button or
399   pressing F1 generates a Help event.
400 right 
401   The text is right-justified. 
402 rtlreading 
403   Displays message and caption text using right-to-left reading order
404   on Hebrew and Arabic systems.
405 setforeground 
406   The message box becomes the foreground window. Internally, Windows
407   calls the SetForegroundWindow function for the message box.
408 topmost 
409   The message box is created with the WS_EX_TOPMOST window style. 
410 service-notification 
411   Windows NT only: The caller is a service notifying the user of an
412   event. The function displays a message box on the current active
413   desktop, even if there is no user logged on to the computer.  If
414   this flag is set, the hWnd parameter must be NULL. This is so the
415   message box can appear on a desktop other than the desktop
416   corresponding to the hWnd.
417
418
419
420 The return value is one of the following menu-item values returned by
421 the dialog box:
422  
423 abort
424   Abort button was selected. 
425 cancel
426   Cancel button was selected. 
427 ignore
428   Ignore button was selected. 
429 no
430   No button was selected. 
431 ok
432   OK button was selected. 
433 retry
434   Retry button was selected. 
435 yes
436   Yes button was selected. 
437
438 If a message box has a Cancel button, the function returns the
439 `cancel' value if either the ESC key is pressed or the Cancel button
440 is selected.  If the message box has no Cancel button, pressing ESC has
441 no effect.  */
442        (message_, flags, title))
443 {
444   Lisp_Object tail;
445   Extbyte *msgout;
446   Extbyte *titleout = 0;
447   UINT sty = 0;
448
449   if (noninteractive)
450     return Qcancel;
451
452   if (!CONSP (flags))
453     {
454       CHECK_SYMBOL (flags);
455       flags = list1 (flags);
456     }
457
458   CHECK_STRING (message_);
459   TO_EXTERNAL_FORMAT (LISP_STRING, message_,
460                       C_STRING_ALLOCA, msgout,
461                       Qmswindows_tstr);
462   
463   if (!NILP (title))
464     {
465       CHECK_STRING (title);
466       TO_EXTERNAL_FORMAT (LISP_STRING, title,
467                           C_STRING_ALLOCA, titleout,
468                           Qmswindows_tstr);
469     }
470
471   EXTERNAL_LIST_LOOP (tail, flags)
472     {
473       Lisp_Object st = XCAR (tail);
474       CHECK_SYMBOL (st);
475       if (0)
476         ;
477 #define FROB(sym, val) else if (EQ (st, sym)) sty |= val
478       FROB (Qabortretryignore, MB_ABORTRETRYIGNORE);
479       FROB (Qapplmodal, MB_APPLMODAL);
480       FROB (Qdefault_desktop_only, MB_DEFAULT_DESKTOP_ONLY);
481       FROB (Qdefbutton1, MB_DEFBUTTON1);
482       FROB (Qdefbutton2, MB_DEFBUTTON2);
483       FROB (Qdefbutton3, MB_DEFBUTTON3);
484       FROB (Qdefbutton4, MB_DEFBUTTON4);
485       FROB (Qhelp, MB_HELP);
486       FROB (Qiconasterisk, MB_ICONASTERISK);
487       FROB (Qiconexclamation, MB_ICONEXCLAMATION);
488       FROB (Qiconhand, MB_ICONHAND);
489       FROB (Qiconinformation, MB_ICONINFORMATION);
490       FROB (Qiconquestion, MB_ICONQUESTION);
491       FROB (Qiconstop, MB_ICONSTOP);
492       FROB (Qok, MB_OK);
493       FROB (Qokcancel, MB_OKCANCEL);
494       FROB (Qretrycancel, MB_RETRYCANCEL);
495       FROB (Qright, MB_RIGHT);
496       FROB (Qrtlreading, MB_RTLREADING);
497       FROB (Qservice_notification, MB_SERVICE_NOTIFICATION);
498       FROB (Qsetforeground, MB_SETFOREGROUND);
499       FROB (Qsystemmodal, MB_SYSTEMMODAL);
500       FROB (Qtaskmodal, MB_TASKMODAL);
501       FROB (Qtopmost, MB_TOPMOST);
502       FROB (Qyesno, MB_YESNO);
503       FROB (Qyesnocancel, MB_YESNOCANCEL);
504 #undef FROB
505
506       else
507         signal_simple_error ("Unrecognized flag", st);
508     }
509
510   {
511     int retval = MessageBox (NULL, msgout, titleout, sty);
512
513     if (retval == 0)
514       error ("Out of memory when calling `mswindows-message-box'");
515
516 #define FROB(sym, val) if (retval == val) return sym
517     FROB (Qabort, IDABORT);
518     FROB (Qcancel, IDCANCEL);
519     FROB (Qignore, IDIGNORE);
520     FROB (Qno, IDNO);
521     FROB (Qok, IDOK);
522     FROB (Qretry, IDRETRY);
523     FROB (Qyes, IDYES);
524 #undef FROB
525     
526     signal_simple_error ("Unknown return value from MessageBox()",
527                          make_int (retval));
528   }
529
530   return Qnil;
531 }
532
533 void
534 mswindows_output_last_error (char *frob)
535 {
536   LPVOID lpMsgBuf;
537   int errval = GetLastError();
538   
539   FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER
540                  | FORMAT_MESSAGE_FROM_SYSTEM,
541                  NULL, errval,
542                  MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
543                  (LPTSTR) &lpMsgBuf,
544                  0,
545                  NULL);
546   stderr_out ("last error during %s is %d: %s\n",
547               frob, errval, (char*)lpMsgBuf);
548 }
549
550 \f
551 /************************************************************************/
552 /*                            initialization                            */
553 /************************************************************************/
554
555 void
556 syms_of_console_mswindows (void)
557 {
558   defsymbol (&Qabortretryignore, "abortretryignore");
559   defsymbol (&Qapplmodal, "applmodal");
560   defsymbol (&Qdefault_desktop_only, "default-desktop-only");
561   defsymbol (&Qdefbutton1, "defbutton1");
562   defsymbol (&Qdefbutton2, "defbutton2");
563   defsymbol (&Qdefbutton3, "defbutton3");
564   defsymbol (&Qdefbutton4, "defbutton4");
565   /* defsymbol (&Qhelp, "help"); */
566   defsymbol (&Qiconasterisk, "iconasterisk");
567   defsymbol (&Qiconexclamation, "iconexclamation");
568   defsymbol (&Qiconhand, "iconhand");
569   defsymbol (&Qiconinformation, "iconinformation");
570   defsymbol (&Qiconquestion, "iconquestion");
571   defsymbol (&Qiconstop, "iconstop");
572   /* defsymbol (&Qok, "ok"); */
573   defsymbol (&Qokcancel, "okcancel");
574   defsymbol (&Qretrycancel, "retrycancel");
575   /* defsymbol (&Qright, "right"); */
576   defsymbol (&Qrtlreading, "rtlreading");
577   defsymbol (&Qservice_notification, "service-notification");
578   defsymbol (&Qsetforeground, "setforeground");
579   defsymbol (&Qsystemmodal, "systemmodal");
580   defsymbol (&Qtaskmodal, "taskmodal");
581   defsymbol (&Qtopmost, "topmost");
582   defsymbol (&Qyesno, "yesno");
583   defsymbol (&Qyesnocancel, "yesnocancel");
584
585   /* defsymbol (&Qabort, "abort"); */
586   /* defsymbol (&Qcancel, "cancel"); */
587   /* defsymbol (&Qignore, "ignore"); */
588   /* defsymbol (&Qno, "no"); */
589   /* defsymbol (&Qok, "ok"); */
590   /* defsymbol (&Qretry, "retry"); */
591   /* defsymbol (&Qyes, "yes"); */
592
593   DEFSUBR (Fmswindows_message_box);
594 }
595
596 void
597 console_type_create_mswindows (void)
598 {
599   INITIALIZE_CONSOLE_TYPE (mswindows, "mswindows", "console-mswindows-p");
600
601   /* console methods */
602 /*  CONSOLE_HAS_METHOD (mswindows, init_console); */
603 /*  CONSOLE_HAS_METHOD (mswindows, mark_console); */
604   CONSOLE_HAS_METHOD (mswindows, initially_selected_for_input);
605 /*  CONSOLE_HAS_METHOD (mswindows, delete_console); */
606   CONSOLE_HAS_METHOD (mswindows, canonicalize_console_connection);
607   CONSOLE_HAS_METHOD (mswindows, canonicalize_device_connection);
608 /*  CONSOLE_HAS_METHOD (mswindows, semi_canonicalize_console_connection); */
609 /*  CONSOLE_HAS_METHOD (mswindows, semi_canonicalize_device_connection); */
610
611   INITIALIZE_CONSOLE_TYPE (msprinter, "msprinter", "console-msprinter-p");
612 }
613
614 void
615 reinit_console_type_create_mswindows (void)
616 {
617   REINITIALIZE_CONSOLE_TYPE (mswindows);
618   REINITIALIZE_CONSOLE_TYPE (msprinter);
619 }
620
621 void
622 vars_of_console_mswindows (void)
623 {
624   Fprovide (Qmswindows);
625 }