Format and doc changes to bring closer to xfns.c.
[bpt/emacs.git] / src / w32fns.c
1 /* Graphical user interface functions for the Microsoft W32 API.
2 Copyright (C) 1989, 92, 93, 94, 95, 1996, 1997, 1998, 1999
3 Free Software Foundation, Inc.
4
5 This file is part of GNU Emacs.
6
7 GNU Emacs is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs; 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 /* Added by Kevin Gallo */
23
24 #include <config.h>
25
26 #include <signal.h>
27 #include <stdio.h>
28 #include <limits.h>
29 #include <errno.h>
30
31 #include "lisp.h"
32 #include "charset.h"
33 #include "w32term.h"
34 #include "frame.h"
35 #include "window.h"
36 #include "buffer.h"
37 #include "dispextern.h"
38 #include "fontset.h"
39 #include "intervals.h"
40 #include "keyboard.h"
41 #include "blockinput.h"
42 #include "epaths.h"
43 #include "w32heap.h"
44 #include "termhooks.h"
45 #include "coding.h"
46 #include "ccl.h"
47 #include "systime.h"
48
49 #include "bitmaps/gray.xbm"
50
51 #include <commdlg.h>
52 #include <shellapi.h>
53 #include <ctype.h>
54
55 extern void free_frame_menubar ();
56 extern double atof ();
57 extern int w32_console_toggle_lock_key (int vk_code, Lisp_Object new_state);
58 extern int quit_char;
59
60 /* A definition of XColor for non-X frames. */
61 #ifndef HAVE_X_WINDOWS
62 typedef struct {
63 unsigned long pixel;
64 unsigned short red, green, blue;
65 char flags;
66 char pad;
67 } XColor;
68 #endif
69
70 extern char *lispy_function_keys[];
71
72 /* The gray bitmap `bitmaps/gray'. This is done because w32term.c uses
73 it, and including `bitmaps/gray' more than once is a problem when
74 config.h defines `static' as an empty replacement string. */
75
76 int gray_bitmap_width = gray_width;
77 int gray_bitmap_height = gray_height;
78 unsigned char *gray_bitmap_bits = gray_bits;
79
80 /* The colormap for converting color names to RGB values */
81 Lisp_Object Vw32_color_map;
82
83 /* Non nil if alt key presses are passed on to Windows. */
84 Lisp_Object Vw32_pass_alt_to_system;
85
86 /* Non nil if alt key is translated to meta_modifier, nil if it is translated
87 to alt_modifier. */
88 Lisp_Object Vw32_alt_is_meta;
89
90 /* If non-zero, the windows virtual key code for an alternative quit key. */
91 Lisp_Object Vw32_quit_key;
92
93 /* Non nil if left window key events are passed on to Windows (this only
94 affects whether "tapping" the key opens the Start menu). */
95 Lisp_Object Vw32_pass_lwindow_to_system;
96
97 /* Non nil if right window key events are passed on to Windows (this
98 only affects whether "tapping" the key opens the Start menu). */
99 Lisp_Object Vw32_pass_rwindow_to_system;
100
101 /* Virtual key code used to generate "phantom" key presses in order
102 to stop system from acting on Windows key events. */
103 Lisp_Object Vw32_phantom_key_code;
104
105 /* Modifier associated with the left "Windows" key, or nil to act as a
106 normal key. */
107 Lisp_Object Vw32_lwindow_modifier;
108
109 /* Modifier associated with the right "Windows" key, or nil to act as a
110 normal key. */
111 Lisp_Object Vw32_rwindow_modifier;
112
113 /* Modifier associated with the "Apps" key, or nil to act as a normal
114 key. */
115 Lisp_Object Vw32_apps_modifier;
116
117 /* Value is nil if Num Lock acts as a function key. */
118 Lisp_Object Vw32_enable_num_lock;
119
120 /* Value is nil if Caps Lock acts as a function key. */
121 Lisp_Object Vw32_enable_caps_lock;
122
123 /* Modifier associated with Scroll Lock, or nil to act as a normal key. */
124 Lisp_Object Vw32_scroll_lock_modifier;
125
126 /* Switch to control whether we inhibit requests for synthesized bold
127 and italic versions of fonts. */
128 Lisp_Object Vw32_enable_synthesized_fonts;
129
130 /* Enable palette management. */
131 Lisp_Object Vw32_enable_palette;
132
133 /* Control how close left/right button down events must be to
134 be converted to a middle button down event. */
135 Lisp_Object Vw32_mouse_button_tolerance;
136
137 /* Minimum interval between mouse movement (and scroll bar drag)
138 events that are passed on to the event loop. */
139 Lisp_Object Vw32_mouse_move_interval;
140
141 /* The name we're using in resource queries. */
142 Lisp_Object Vx_resource_name;
143
144 /* Non nil if no window manager is in use. */
145 Lisp_Object Vx_no_window_manager;
146
147 /* Non-zero means we're allowed to display a busy cursor. */
148
149 int display_busy_cursor_p;
150
151 /* The background and shape of the mouse pointer, and shape when not
152 over text or in the modeline. */
153
154 Lisp_Object Vx_pointer_shape, Vx_nontext_pointer_shape, Vx_mode_pointer_shape;
155 Lisp_Object Vx_busy_pointer_shape;
156
157 /* The shape when over mouse-sensitive text. */
158
159 Lisp_Object Vx_sensitive_text_pointer_shape;
160
161 /* Color of chars displayed in cursor box. */
162
163 Lisp_Object Vx_cursor_fore_pixel;
164
165 /* Nonzero if using Windows. */
166
167 static int w32_in_use;
168
169 /* Search path for bitmap files. */
170
171 Lisp_Object Vx_bitmap_file_path;
172
173 /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'. */
174
175 Lisp_Object Vx_pixel_size_width_font_regexp;
176
177 /* Alist of bdf fonts and the files that define them. */
178 Lisp_Object Vw32_bdf_filename_alist;
179
180 Lisp_Object Vw32_system_coding_system;
181
182 /* A flag to control whether fonts are matched strictly or not. */
183 int w32_strict_fontnames;
184
185 /* A flag to control whether we should only repaint if GetUpdateRect
186 indicates there is an update region. */
187 int w32_strict_painting;
188
189 /* Associative list linking character set strings to Windows codepages. */
190 Lisp_Object Vw32_charset_info_alist;
191
192 /* VIETNAMESE_CHARSET is not defined in some versions of MSVC. */
193 #ifndef VIETNAMESE_CHARSET
194 #define VIETNAMESE_CHARSET 163
195 #endif
196
197
198 /* Evaluate this expression to rebuild the section of syms_of_w32fns
199 that initializes and staticpros the symbols declared below. Note
200 that Emacs 18 has a bug that keeps C-x C-e from being able to
201 evaluate this expression.
202
203 (progn
204 ;; Accumulate a list of the symbols we want to initialize from the
205 ;; declarations at the top of the file.
206 (goto-char (point-min))
207 (search-forward "/\*&&& symbols declared here &&&*\/\n")
208 (let (symbol-list)
209 (while (looking-at "Lisp_Object \\(Q[a-z_]+\\)")
210 (setq symbol-list
211 (cons (buffer-substring (match-beginning 1) (match-end 1))
212 symbol-list))
213 (forward-line 1))
214 (setq symbol-list (nreverse symbol-list))
215 ;; Delete the section of syms_of_... where we initialize the symbols.
216 (search-forward "\n /\*&&& init symbols here &&&*\/\n")
217 (let ((start (point)))
218 (while (looking-at "^ Q")
219 (forward-line 2))
220 (kill-region start (point)))
221 ;; Write a new symbol initialization section.
222 (while symbol-list
223 (insert (format " %s = intern (\"" (car symbol-list)))
224 (let ((start (point)))
225 (insert (substring (car symbol-list) 1))
226 (subst-char-in-region start (point) ?_ ?-))
227 (insert (format "\");\n staticpro (&%s);\n" (car symbol-list)))
228 (setq symbol-list (cdr symbol-list)))))
229
230 */
231
232 /*&&& symbols declared here &&&*/
233 Lisp_Object Qauto_raise;
234 Lisp_Object Qauto_lower;
235 Lisp_Object Qbar;
236 Lisp_Object Qborder_color;
237 Lisp_Object Qborder_width;
238 Lisp_Object Qbox;
239 Lisp_Object Qcursor_color;
240 Lisp_Object Qcursor_type;
241 Lisp_Object Qgeometry;
242 Lisp_Object Qicon_left;
243 Lisp_Object Qicon_top;
244 Lisp_Object Qicon_type;
245 Lisp_Object Qicon_name;
246 Lisp_Object Qinternal_border_width;
247 Lisp_Object Qleft;
248 Lisp_Object Qright;
249 Lisp_Object Qmouse_color;
250 Lisp_Object Qnone;
251 Lisp_Object Qparent_id;
252 Lisp_Object Qscroll_bar_width;
253 Lisp_Object Qsuppress_icon;
254 Lisp_Object Qundefined_color;
255 Lisp_Object Qvertical_scroll_bars;
256 Lisp_Object Qvisibility;
257 Lisp_Object Qwindow_id;
258 Lisp_Object Qx_frame_parameter;
259 Lisp_Object Qx_resource_name;
260 Lisp_Object Quser_position;
261 Lisp_Object Quser_size;
262 Lisp_Object Qscreen_gamma;
263 Lisp_Object Qline_spacing;
264 Lisp_Object Qcenter;
265 Lisp_Object Qhyper;
266 Lisp_Object Qsuper;
267 Lisp_Object Qmeta;
268 Lisp_Object Qalt;
269 Lisp_Object Qctrl;
270 Lisp_Object Qcontrol;
271 Lisp_Object Qshift;
272
273 Lisp_Object Qw32_charset_ansi;
274 Lisp_Object Qw32_charset_default;
275 Lisp_Object Qw32_charset_symbol;
276 Lisp_Object Qw32_charset_shiftjis;
277 Lisp_Object Qw32_charset_hangul;
278 Lisp_Object Qw32_charset_gb2312;
279 Lisp_Object Qw32_charset_chinesebig5;
280 Lisp_Object Qw32_charset_oem;
281
282 #ifdef JOHAB_CHARSET
283 Lisp_Object Qw32_charset_easteurope;
284 Lisp_Object Qw32_charset_turkish;
285 Lisp_Object Qw32_charset_baltic;
286 Lisp_Object Qw32_charset_russian;
287 Lisp_Object Qw32_charset_arabic;
288 Lisp_Object Qw32_charset_greek;
289 Lisp_Object Qw32_charset_hebrew;
290 Lisp_Object Qw32_charset_thai;
291 Lisp_Object Qw32_charset_johab;
292 Lisp_Object Qw32_charset_mac;
293 #endif
294
295 #ifdef UNICODE_CHARSET
296 Lisp_Object Qw32_charset_unicode;
297 #endif
298
299 extern Lisp_Object Qtop;
300 extern Lisp_Object Qdisplay;
301 extern Lisp_Object Qtool_bar_lines;
302
303 /* State variables for emulating a three button mouse. */
304 #define LMOUSE 1
305 #define MMOUSE 2
306 #define RMOUSE 4
307
308 static int button_state = 0;
309 static W32Msg saved_mouse_button_msg;
310 static unsigned mouse_button_timer; /* non-zero when timer is active */
311 static W32Msg saved_mouse_move_msg;
312 static unsigned mouse_move_timer;
313
314 /* W95 mousewheel handler */
315 unsigned int msh_mousewheel = 0;
316
317 #define MOUSE_BUTTON_ID 1
318 #define MOUSE_MOVE_ID 2
319
320 /* The below are defined in frame.c. */
321
322 extern Lisp_Object Qheight, Qminibuffer, Qname, Qonly, Qwidth;
323 extern Lisp_Object Qunsplittable, Qmenu_bar_lines, Qbuffer_predicate, Qtitle;
324 extern Lisp_Object Qtool_bar_lines;
325
326 extern Lisp_Object Vwindow_system_version;
327
328 Lisp_Object Qface_set_after_frame_default;
329
330 /* From w32term.c. */
331 extern Lisp_Object Vw32_num_mouse_buttons;
332 extern Lisp_Object Vw32_recognize_altgr;
333
334 \f
335 /* Error if we are not connected to MS-Windows. */
336 void
337 check_w32 ()
338 {
339 if (! w32_in_use)
340 error ("MS-Windows not in use or not initialized");
341 }
342
343 /* Nonzero if we can use mouse menus.
344 You should not call this unless HAVE_MENUS is defined. */
345
346 int
347 have_menus_p ()
348 {
349 return w32_in_use;
350 }
351
352 /* Extract a frame as a FRAME_PTR, defaulting to the selected frame
353 and checking validity for W32. */
354
355 FRAME_PTR
356 check_x_frame (frame)
357 Lisp_Object frame;
358 {
359 FRAME_PTR f;
360
361 if (NILP (frame))
362 frame = selected_frame;
363 CHECK_LIVE_FRAME (frame, 0);
364 f = XFRAME (frame);
365 if (! FRAME_W32_P (f))
366 error ("non-w32 frame used");
367 return f;
368 }
369
370 /* Let the user specify an display with a frame.
371 nil stands for the selected frame--or, if that is not a w32 frame,
372 the first display on the list. */
373
374 static struct w32_display_info *
375 check_x_display_info (frame)
376 Lisp_Object frame;
377 {
378 if (NILP (frame))
379 {
380 struct frame *sf = XFRAME (selected_frame);
381
382 if (FRAME_W32_P (sf) && FRAME_LIVE_P (sf))
383 return FRAME_W32_DISPLAY_INFO (sf);
384 else
385 return &one_w32_display_info;
386 }
387 else if (STRINGP (frame))
388 return x_display_info_for_name (frame);
389 else
390 {
391 FRAME_PTR f;
392
393 CHECK_LIVE_FRAME (frame, 0);
394 f = XFRAME (frame);
395 if (! FRAME_W32_P (f))
396 error ("non-w32 frame used");
397 return FRAME_W32_DISPLAY_INFO (f);
398 }
399 }
400 \f
401 /* Return the Emacs frame-object corresponding to an w32 window.
402 It could be the frame's main window or an icon window. */
403
404 /* This function can be called during GC, so use GC_xxx type test macros. */
405
406 struct frame *
407 x_window_to_frame (dpyinfo, wdesc)
408 struct w32_display_info *dpyinfo;
409 HWND wdesc;
410 {
411 Lisp_Object tail, frame;
412 struct frame *f;
413
414 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
415 {
416 frame = XCAR (tail);
417 if (!GC_FRAMEP (frame))
418 continue;
419 f = XFRAME (frame);
420 if (!FRAME_W32_P (f) || FRAME_W32_DISPLAY_INFO (f) != dpyinfo)
421 continue;
422 if (f->output_data.w32->busy_window == wdesc)
423 return f;
424
425 /* NTEMACS_TODO: Check tooltips when supported. */
426 if (FRAME_W32_WINDOW (f) == wdesc)
427 return f;
428 }
429 return 0;
430 }
431
432 \f
433
434 /* Code to deal with bitmaps. Bitmaps are referenced by their bitmap
435 id, which is just an int that this section returns. Bitmaps are
436 reference counted so they can be shared among frames.
437
438 Bitmap indices are guaranteed to be > 0, so a negative number can
439 be used to indicate no bitmap.
440
441 If you use x_create_bitmap_from_data, then you must keep track of
442 the bitmaps yourself. That is, creating a bitmap from the same
443 data more than once will not be caught. */
444
445
446 /* Functions to access the contents of a bitmap, given an id. */
447
448 int
449 x_bitmap_height (f, id)
450 FRAME_PTR f;
451 int id;
452 {
453 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].height;
454 }
455
456 int
457 x_bitmap_width (f, id)
458 FRAME_PTR f;
459 int id;
460 {
461 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].width;
462 }
463
464 int
465 x_bitmap_pixmap (f, id)
466 FRAME_PTR f;
467 int id;
468 {
469 return (int) FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
470 }
471
472
473 /* Allocate a new bitmap record. Returns index of new record. */
474
475 static int
476 x_allocate_bitmap_record (f)
477 FRAME_PTR f;
478 {
479 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
480 int i;
481
482 if (dpyinfo->bitmaps == NULL)
483 {
484 dpyinfo->bitmaps_size = 10;
485 dpyinfo->bitmaps
486 = (struct w32_bitmap_record *) xmalloc (dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
487 dpyinfo->bitmaps_last = 1;
488 return 1;
489 }
490
491 if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size)
492 return ++dpyinfo->bitmaps_last;
493
494 for (i = 0; i < dpyinfo->bitmaps_size; ++i)
495 if (dpyinfo->bitmaps[i].refcount == 0)
496 return i + 1;
497
498 dpyinfo->bitmaps_size *= 2;
499 dpyinfo->bitmaps
500 = (struct w32_bitmap_record *) xrealloc (dpyinfo->bitmaps,
501 dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
502 return ++dpyinfo->bitmaps_last;
503 }
504
505 /* Add one reference to the reference count of the bitmap with id ID. */
506
507 void
508 x_reference_bitmap (f, id)
509 FRAME_PTR f;
510 int id;
511 {
512 ++FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
513 }
514
515 /* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at BITS. */
516
517 int
518 x_create_bitmap_from_data (f, bits, width, height)
519 struct frame *f;
520 char *bits;
521 unsigned int width, height;
522 {
523 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
524 Pixmap bitmap;
525 int id;
526
527 bitmap = CreateBitmap (width, height,
528 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_planes,
529 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_cbits,
530 bits);
531
532 if (! bitmap)
533 return -1;
534
535 id = x_allocate_bitmap_record (f);
536 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
537 dpyinfo->bitmaps[id - 1].file = NULL;
538 dpyinfo->bitmaps[id - 1].hinst = NULL;
539 dpyinfo->bitmaps[id - 1].refcount = 1;
540 dpyinfo->bitmaps[id - 1].depth = 1;
541 dpyinfo->bitmaps[id - 1].height = height;
542 dpyinfo->bitmaps[id - 1].width = width;
543
544 return id;
545 }
546
547 /* Create bitmap from file FILE for frame F. */
548
549 int
550 x_create_bitmap_from_file (f, file)
551 struct frame *f;
552 Lisp_Object file;
553 {
554 return -1;
555 #if 0 /* NTEMACS_TODO : bitmap support */
556 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
557 unsigned int width, height;
558 HBITMAP bitmap;
559 int xhot, yhot, result, id;
560 Lisp_Object found;
561 int fd;
562 char *filename;
563 HINSTANCE hinst;
564
565 /* Look for an existing bitmap with the same name. */
566 for (id = 0; id < dpyinfo->bitmaps_last; ++id)
567 {
568 if (dpyinfo->bitmaps[id].refcount
569 && dpyinfo->bitmaps[id].file
570 && !strcmp (dpyinfo->bitmaps[id].file, (char *) XSTRING (file)->data))
571 {
572 ++dpyinfo->bitmaps[id].refcount;
573 return id + 1;
574 }
575 }
576
577 /* Search bitmap-file-path for the file, if appropriate. */
578 fd = openp (Vx_bitmap_file_path, file, "", &found, 0);
579 if (fd < 0)
580 return -1;
581 /* LoadLibraryEx won't handle special files handled by Emacs handler. */
582 if (fd == 0)
583 return -1;
584 emacs_close (fd);
585
586 filename = (char *) XSTRING (found)->data;
587
588 hinst = LoadLibraryEx (filename, NULL, LOAD_LIBRARY_AS_DATAFILE);
589
590 if (hinst == NULL)
591 return -1;
592
593
594 result = XReadBitmapFile (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
595 filename, &width, &height, &bitmap, &xhot, &yhot);
596 if (result != BitmapSuccess)
597 return -1;
598
599 id = x_allocate_bitmap_record (f);
600 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
601 dpyinfo->bitmaps[id - 1].refcount = 1;
602 dpyinfo->bitmaps[id - 1].file = (char *) xmalloc (XSTRING (file)->size + 1);
603 dpyinfo->bitmaps[id - 1].depth = 1;
604 dpyinfo->bitmaps[id - 1].height = height;
605 dpyinfo->bitmaps[id - 1].width = width;
606 strcpy (dpyinfo->bitmaps[id - 1].file, XSTRING (file)->data);
607
608 return id;
609 #endif /* NTEMACS_TODO */
610 }
611
612 /* Remove reference to bitmap with id number ID. */
613
614 void
615 x_destroy_bitmap (f, id)
616 FRAME_PTR f;
617 int id;
618 {
619 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
620
621 if (id > 0)
622 {
623 --dpyinfo->bitmaps[id - 1].refcount;
624 if (dpyinfo->bitmaps[id - 1].refcount == 0)
625 {
626 BLOCK_INPUT;
627 DeleteObject (dpyinfo->bitmaps[id - 1].pixmap);
628 if (dpyinfo->bitmaps[id - 1].file)
629 {
630 xfree (dpyinfo->bitmaps[id - 1].file);
631 dpyinfo->bitmaps[id - 1].file = NULL;
632 }
633 UNBLOCK_INPUT;
634 }
635 }
636 }
637
638 /* Free all the bitmaps for the display specified by DPYINFO. */
639
640 static void
641 x_destroy_all_bitmaps (dpyinfo)
642 struct w32_display_info *dpyinfo;
643 {
644 int i;
645 for (i = 0; i < dpyinfo->bitmaps_last; i++)
646 if (dpyinfo->bitmaps[i].refcount > 0)
647 {
648 DeleteObject (dpyinfo->bitmaps[i].pixmap);
649 if (dpyinfo->bitmaps[i].file)
650 xfree (dpyinfo->bitmaps[i].file);
651 }
652 dpyinfo->bitmaps_last = 0;
653 }
654 \f
655 /* Connect the frame-parameter names for W32 frames
656 to the ways of passing the parameter values to the window system.
657
658 The name of a parameter, as a Lisp symbol,
659 has an `x-frame-parameter' property which is an integer in Lisp
660 but can be interpreted as an `enum x_frame_parm' in C. */
661
662 enum x_frame_parm
663 {
664 X_PARM_FOREGROUND_COLOR,
665 X_PARM_BACKGROUND_COLOR,
666 X_PARM_MOUSE_COLOR,
667 X_PARM_CURSOR_COLOR,
668 X_PARM_BORDER_COLOR,
669 X_PARM_ICON_TYPE,
670 X_PARM_FONT,
671 X_PARM_BORDER_WIDTH,
672 X_PARM_INTERNAL_BORDER_WIDTH,
673 X_PARM_NAME,
674 X_PARM_AUTORAISE,
675 X_PARM_AUTOLOWER,
676 X_PARM_VERT_SCROLL_BAR,
677 X_PARM_VISIBILITY,
678 X_PARM_MENU_BAR_LINES
679 };
680
681
682 struct x_frame_parm_table
683 {
684 char *name;
685 void (*setter) P_ ((struct frame *, Lisp_Object, Lisp_Object));
686 };
687
688 /* NTEMACS_TODO: Native Input Method support; see x_create_im. */
689 void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
690 static void x_set_line_spacing P_ ((struct frame *, Lisp_Object, Lisp_Object));
691 void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
692 void x_set_mouse_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
693 void x_set_cursor_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
694 void x_set_border_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
695 void x_set_cursor_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
696 void x_set_icon_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
697 void x_set_icon_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
698 void x_set_font P_ ((struct frame *, Lisp_Object, Lisp_Object));
699 void x_set_border_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
700 void x_set_internal_border_width P_ ((struct frame *, Lisp_Object,
701 Lisp_Object));
702 void x_explicitly_set_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
703 void x_set_autoraise P_ ((struct frame *, Lisp_Object, Lisp_Object));
704 void x_set_autolower P_ ((struct frame *, Lisp_Object, Lisp_Object));
705 void x_set_vertical_scroll_bars P_ ((struct frame *, Lisp_Object,
706 Lisp_Object));
707 void x_set_visibility P_ ((struct frame *, Lisp_Object, Lisp_Object));
708 void x_set_menu_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
709 void x_set_scroll_bar_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
710 void x_set_title P_ ((struct frame *, Lisp_Object, Lisp_Object));
711 void x_set_unsplittable P_ ((struct frame *, Lisp_Object, Lisp_Object));
712 void x_set_tool_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
713 static void x_set_screen_gamma P_ ((struct frame *, Lisp_Object, Lisp_Object));
714
715 static struct x_frame_parm_table x_frame_parms[] =
716 {
717 "auto-raise", x_set_autoraise,
718 "auto-lower", x_set_autolower,
719 "background-color", x_set_background_color,
720 "border-color", x_set_border_color,
721 "border-width", x_set_border_width,
722 "cursor-color", x_set_cursor_color,
723 "cursor-type", x_set_cursor_type,
724 "font", x_set_font,
725 "foreground-color", x_set_foreground_color,
726 "icon-name", x_set_icon_name,
727 "icon-type", x_set_icon_type,
728 "internal-border-width", x_set_internal_border_width,
729 "menu-bar-lines", x_set_menu_bar_lines,
730 "mouse-color", x_set_mouse_color,
731 "name", x_explicitly_set_name,
732 "scroll-bar-width", x_set_scroll_bar_width,
733 "title", x_set_title,
734 "unsplittable", x_set_unsplittable,
735 "vertical-scroll-bars", x_set_vertical_scroll_bars,
736 "visibility", x_set_visibility,
737 "tool-bar-lines", x_set_tool_bar_lines,
738 "screen-gamma", x_set_screen_gamma,
739 "line-spacing", x_set_line_spacing
740 };
741
742 /* Attach the `x-frame-parameter' properties to
743 the Lisp symbol names of parameters relevant to W32. */
744
745 void
746 init_x_parm_symbols ()
747 {
748 int i;
749
750 for (i = 0; i < sizeof (x_frame_parms) / sizeof (x_frame_parms[0]); i++)
751 Fput (intern (x_frame_parms[i].name), Qx_frame_parameter,
752 make_number (i));
753 }
754 \f
755 /* Change the parameters of frame F as specified by ALIST.
756 If a parameter is not specially recognized, do nothing;
757 otherwise call the `x_set_...' function for that parameter. */
758
759 void
760 x_set_frame_parameters (f, alist)
761 FRAME_PTR f;
762 Lisp_Object alist;
763 {
764 Lisp_Object tail;
765
766 /* If both of these parameters are present, it's more efficient to
767 set them both at once. So we wait until we've looked at the
768 entire list before we set them. */
769 int width, height;
770
771 /* Same here. */
772 Lisp_Object left, top;
773
774 /* Same with these. */
775 Lisp_Object icon_left, icon_top;
776
777 /* Record in these vectors all the parms specified. */
778 Lisp_Object *parms;
779 Lisp_Object *values;
780 int i, p;
781 int left_no_change = 0, top_no_change = 0;
782 int icon_left_no_change = 0, icon_top_no_change = 0;
783
784 struct gcpro gcpro1, gcpro2;
785
786 i = 0;
787 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
788 i++;
789
790 parms = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
791 values = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
792
793 /* Extract parm names and values into those vectors. */
794
795 i = 0;
796 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
797 {
798 Lisp_Object elt;
799
800 elt = Fcar (tail);
801 parms[i] = Fcar (elt);
802 values[i] = Fcdr (elt);
803 i++;
804 }
805 /* TAIL and ALIST are not used again below here. */
806 alist = tail = Qnil;
807
808 GCPRO2 (*parms, *values);
809 gcpro1.nvars = i;
810 gcpro2.nvars = i;
811
812 /* There is no need to gcpro LEFT, TOP, ICON_LEFT, or ICON_TOP,
813 because their values appear in VALUES and strings are not valid. */
814 top = left = Qunbound;
815 icon_left = icon_top = Qunbound;
816
817 /* Provide default values for HEIGHT and WIDTH. */
818 if (FRAME_NEW_WIDTH (f))
819 width = FRAME_NEW_WIDTH (f);
820 else
821 width = FRAME_WIDTH (f);
822
823 if (FRAME_NEW_HEIGHT (f))
824 height = FRAME_NEW_HEIGHT (f);
825 else
826 height = FRAME_HEIGHT (f);
827
828 /* Process foreground_color and background_color before anything else.
829 They are independent of other properties, but other properties (e.g.,
830 cursor_color) are dependent upon them. */
831 for (p = 0; p < i; p++)
832 {
833 Lisp_Object prop, val;
834
835 prop = parms[p];
836 val = values[p];
837 if (EQ (prop, Qforeground_color) || EQ (prop, Qbackground_color))
838 {
839 register Lisp_Object param_index, old_value;
840
841 param_index = Fget (prop, Qx_frame_parameter);
842 old_value = get_frame_param (f, prop);
843 store_frame_param (f, prop, val);
844 if (NATNUMP (param_index)
845 && (XFASTINT (param_index)
846 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
847 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
848 }
849 }
850
851 /* Now process them in reverse of specified order. */
852 for (i--; i >= 0; i--)
853 {
854 Lisp_Object prop, val;
855
856 prop = parms[i];
857 val = values[i];
858
859 if (EQ (prop, Qwidth) && NUMBERP (val))
860 width = XFASTINT (val);
861 else if (EQ (prop, Qheight) && NUMBERP (val))
862 height = XFASTINT (val);
863 else if (EQ (prop, Qtop))
864 top = val;
865 else if (EQ (prop, Qleft))
866 left = val;
867 else if (EQ (prop, Qicon_top))
868 icon_top = val;
869 else if (EQ (prop, Qicon_left))
870 icon_left = val;
871 else if (EQ (prop, Qforeground_color) || EQ (prop, Qbackground_color))
872 /* Processed above. */
873 continue;
874 else
875 {
876 register Lisp_Object param_index, old_value;
877
878 param_index = Fget (prop, Qx_frame_parameter);
879 old_value = get_frame_param (f, prop);
880 store_frame_param (f, prop, val);
881 if (NATNUMP (param_index)
882 && (XFASTINT (param_index)
883 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
884 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
885 }
886 }
887
888 /* Don't die if just one of these was set. */
889 if (EQ (left, Qunbound))
890 {
891 left_no_change = 1;
892 if (f->output_data.w32->left_pos < 0)
893 left = Fcons (Qplus, Fcons (make_number (f->output_data.w32->left_pos), Qnil));
894 else
895 XSETINT (left, f->output_data.w32->left_pos);
896 }
897 if (EQ (top, Qunbound))
898 {
899 top_no_change = 1;
900 if (f->output_data.w32->top_pos < 0)
901 top = Fcons (Qplus, Fcons (make_number (f->output_data.w32->top_pos), Qnil));
902 else
903 XSETINT (top, f->output_data.w32->top_pos);
904 }
905
906 /* If one of the icon positions was not set, preserve or default it. */
907 if (EQ (icon_left, Qunbound) || ! INTEGERP (icon_left))
908 {
909 icon_left_no_change = 1;
910 icon_left = Fcdr (Fassq (Qicon_left, f->param_alist));
911 if (NILP (icon_left))
912 XSETINT (icon_left, 0);
913 }
914 if (EQ (icon_top, Qunbound) || ! INTEGERP (icon_top))
915 {
916 icon_top_no_change = 1;
917 icon_top = Fcdr (Fassq (Qicon_top, f->param_alist));
918 if (NILP (icon_top))
919 XSETINT (icon_top, 0);
920 }
921
922 /* Don't set these parameters unless they've been explicitly
923 specified. The window might be mapped or resized while we're in
924 this function, and we don't want to override that unless the lisp
925 code has asked for it.
926
927 Don't set these parameters unless they actually differ from the
928 window's current parameters; the window may not actually exist
929 yet. */
930 {
931 Lisp_Object frame;
932
933 check_frame_size (f, &height, &width);
934
935 XSETFRAME (frame, f);
936
937 if (width != FRAME_WIDTH (f)
938 || height != FRAME_HEIGHT (f)
939 || FRAME_NEW_HEIGHT (f) || FRAME_NEW_WIDTH (f))
940 Fset_frame_size (frame, make_number (width), make_number (height));
941
942 if ((!NILP (left) || !NILP (top))
943 && ! (left_no_change && top_no_change)
944 && ! (NUMBERP (left) && XINT (left) == f->output_data.w32->left_pos
945 && NUMBERP (top) && XINT (top) == f->output_data.w32->top_pos))
946 {
947 int leftpos = 0;
948 int toppos = 0;
949
950 /* Record the signs. */
951 f->output_data.w32->size_hint_flags &= ~ (XNegative | YNegative);
952 if (EQ (left, Qminus))
953 f->output_data.w32->size_hint_flags |= XNegative;
954 else if (INTEGERP (left))
955 {
956 leftpos = XINT (left);
957 if (leftpos < 0)
958 f->output_data.w32->size_hint_flags |= XNegative;
959 }
960 else if (CONSP (left) && EQ (XCAR (left), Qminus)
961 && CONSP (XCDR (left))
962 && INTEGERP (XCAR (XCDR (left))))
963 {
964 leftpos = - XINT (XCAR (XCDR (left)));
965 f->output_data.w32->size_hint_flags |= XNegative;
966 }
967 else if (CONSP (left) && EQ (XCAR (left), Qplus)
968 && CONSP (XCDR (left))
969 && INTEGERP (XCAR (XCDR (left))))
970 {
971 leftpos = XINT (XCAR (XCDR (left)));
972 }
973
974 if (EQ (top, Qminus))
975 f->output_data.w32->size_hint_flags |= YNegative;
976 else if (INTEGERP (top))
977 {
978 toppos = XINT (top);
979 if (toppos < 0)
980 f->output_data.w32->size_hint_flags |= YNegative;
981 }
982 else if (CONSP (top) && EQ (XCAR (top), Qminus)
983 && CONSP (XCDR (top))
984 && INTEGERP (XCAR (XCDR (top))))
985 {
986 toppos = - XINT (XCAR (XCDR (top)));
987 f->output_data.w32->size_hint_flags |= YNegative;
988 }
989 else if (CONSP (top) && EQ (XCAR (top), Qplus)
990 && CONSP (XCDR (top))
991 && INTEGERP (XCAR (XCDR (top))))
992 {
993 toppos = XINT (XCAR (XCDR (top)));
994 }
995
996
997 /* Store the numeric value of the position. */
998 f->output_data.w32->top_pos = toppos;
999 f->output_data.w32->left_pos = leftpos;
1000
1001 f->output_data.w32->win_gravity = NorthWestGravity;
1002
1003 /* Actually set that position, and convert to absolute. */
1004 x_set_offset (f, leftpos, toppos, -1);
1005 }
1006
1007 if ((!NILP (icon_left) || !NILP (icon_top))
1008 && ! (icon_left_no_change && icon_top_no_change))
1009 x_wm_set_icon_position (f, XINT (icon_left), XINT (icon_top));
1010 }
1011
1012 UNGCPRO;
1013 }
1014
1015 /* Store the screen positions of frame F into XPTR and YPTR.
1016 These are the positions of the containing window manager window,
1017 not Emacs's own window. */
1018
1019 void
1020 x_real_positions (f, xptr, yptr)
1021 FRAME_PTR f;
1022 int *xptr, *yptr;
1023 {
1024 POINT pt;
1025
1026 {
1027 RECT rect;
1028
1029 GetClientRect(FRAME_W32_WINDOW(f), &rect);
1030 AdjustWindowRect(&rect, f->output_data.w32->dwStyle, FRAME_EXTERNAL_MENU_BAR(f));
1031
1032 pt.x = rect.left;
1033 pt.y = rect.top;
1034 }
1035
1036 ClientToScreen (FRAME_W32_WINDOW(f), &pt);
1037
1038 *xptr = pt.x;
1039 *yptr = pt.y;
1040 }
1041
1042 /* Insert a description of internally-recorded parameters of frame X
1043 into the parameter alist *ALISTPTR that is to be given to the user.
1044 Only parameters that are specific to W32
1045 and whose values are not correctly recorded in the frame's
1046 param_alist need to be considered here. */
1047
1048 void
1049 x_report_frame_params (f, alistptr)
1050 struct frame *f;
1051 Lisp_Object *alistptr;
1052 {
1053 char buf[16];
1054 Lisp_Object tem;
1055
1056 /* Represent negative positions (off the top or left screen edge)
1057 in a way that Fmodify_frame_parameters will understand correctly. */
1058 XSETINT (tem, f->output_data.w32->left_pos);
1059 if (f->output_data.w32->left_pos >= 0)
1060 store_in_alist (alistptr, Qleft, tem);
1061 else
1062 store_in_alist (alistptr, Qleft, Fcons (Qplus, Fcons (tem, Qnil)));
1063
1064 XSETINT (tem, f->output_data.w32->top_pos);
1065 if (f->output_data.w32->top_pos >= 0)
1066 store_in_alist (alistptr, Qtop, tem);
1067 else
1068 store_in_alist (alistptr, Qtop, Fcons (Qplus, Fcons (tem, Qnil)));
1069
1070 store_in_alist (alistptr, Qborder_width,
1071 make_number (f->output_data.w32->border_width));
1072 store_in_alist (alistptr, Qinternal_border_width,
1073 make_number (f->output_data.w32->internal_border_width));
1074 sprintf (buf, "%ld", (long) FRAME_W32_WINDOW (f));
1075 store_in_alist (alistptr, Qwindow_id,
1076 build_string (buf));
1077 store_in_alist (alistptr, Qicon_name, f->icon_name);
1078 FRAME_SAMPLE_VISIBILITY (f);
1079 store_in_alist (alistptr, Qvisibility,
1080 (FRAME_VISIBLE_P (f) ? Qt
1081 : FRAME_ICONIFIED_P (f) ? Qicon : Qnil));
1082 store_in_alist (alistptr, Qdisplay,
1083 XCAR (FRAME_W32_DISPLAY_INFO (f)->name_list_element));
1084 }
1085 \f
1086
1087 DEFUN ("w32-define-rgb-color", Fw32_define_rgb_color, Sw32_define_rgb_color, 4, 4, 0,
1088 "Convert RGB numbers to a windows color reference and associate with NAME (a string).\n\
1089 This adds or updates a named color to w32-color-map, making it available for use.\n\
1090 The original entry's RGB ref is returned, or nil if the entry is new.")
1091 (red, green, blue, name)
1092 Lisp_Object red, green, blue, name;
1093 {
1094 Lisp_Object rgb;
1095 Lisp_Object oldrgb = Qnil;
1096 Lisp_Object entry;
1097
1098 CHECK_NUMBER (red, 0);
1099 CHECK_NUMBER (green, 0);
1100 CHECK_NUMBER (blue, 0);
1101 CHECK_STRING (name, 0);
1102
1103 XSET (rgb, Lisp_Int, RGB(XUINT (red), XUINT (green), XUINT (blue)));
1104
1105 BLOCK_INPUT;
1106
1107 /* replace existing entry in w32-color-map or add new entry. */
1108 entry = Fassoc (name, Vw32_color_map);
1109 if (NILP (entry))
1110 {
1111 entry = Fcons (name, rgb);
1112 Vw32_color_map = Fcons (entry, Vw32_color_map);
1113 }
1114 else
1115 {
1116 oldrgb = Fcdr (entry);
1117 Fsetcdr (entry, rgb);
1118 }
1119
1120 UNBLOCK_INPUT;
1121
1122 return (oldrgb);
1123 }
1124
1125 DEFUN ("w32-load-color-file", Fw32_load_color_file, Sw32_load_color_file, 1, 1, 0,
1126 "Create an alist of color entries from an external file (ie. rgb.txt).\n\
1127 Assign this value to w32-color-map to replace the existing color map.\n\
1128 \
1129 The file should define one named RGB color per line like so:\
1130 R G B name\n\
1131 where R,G,B are numbers between 0 and 255 and name is an arbitrary string.")
1132 (filename)
1133 Lisp_Object filename;
1134 {
1135 FILE *fp;
1136 Lisp_Object cmap = Qnil;
1137 Lisp_Object abspath;
1138
1139 CHECK_STRING (filename, 0);
1140 abspath = Fexpand_file_name (filename, Qnil);
1141
1142 fp = fopen (XSTRING (filename)->data, "rt");
1143 if (fp)
1144 {
1145 char buf[512];
1146 int red, green, blue;
1147 int num;
1148
1149 BLOCK_INPUT;
1150
1151 while (fgets (buf, sizeof (buf), fp) != NULL) {
1152 if (sscanf (buf, "%u %u %u %n", &red, &green, &blue, &num) == 3)
1153 {
1154 char *name = buf + num;
1155 num = strlen (name) - 1;
1156 if (name[num] == '\n')
1157 name[num] = 0;
1158 cmap = Fcons (Fcons (build_string (name),
1159 make_number (RGB (red, green, blue))),
1160 cmap);
1161 }
1162 }
1163 fclose (fp);
1164
1165 UNBLOCK_INPUT;
1166 }
1167
1168 return cmap;
1169 }
1170
1171 /* The default colors for the w32 color map */
1172 typedef struct colormap_t
1173 {
1174 char *name;
1175 COLORREF colorref;
1176 } colormap_t;
1177
1178 colormap_t w32_color_map[] =
1179 {
1180 {"snow" , PALETTERGB (255,250,250)},
1181 {"ghost white" , PALETTERGB (248,248,255)},
1182 {"GhostWhite" , PALETTERGB (248,248,255)},
1183 {"white smoke" , PALETTERGB (245,245,245)},
1184 {"WhiteSmoke" , PALETTERGB (245,245,245)},
1185 {"gainsboro" , PALETTERGB (220,220,220)},
1186 {"floral white" , PALETTERGB (255,250,240)},
1187 {"FloralWhite" , PALETTERGB (255,250,240)},
1188 {"old lace" , PALETTERGB (253,245,230)},
1189 {"OldLace" , PALETTERGB (253,245,230)},
1190 {"linen" , PALETTERGB (250,240,230)},
1191 {"antique white" , PALETTERGB (250,235,215)},
1192 {"AntiqueWhite" , PALETTERGB (250,235,215)},
1193 {"papaya whip" , PALETTERGB (255,239,213)},
1194 {"PapayaWhip" , PALETTERGB (255,239,213)},
1195 {"blanched almond" , PALETTERGB (255,235,205)},
1196 {"BlanchedAlmond" , PALETTERGB (255,235,205)},
1197 {"bisque" , PALETTERGB (255,228,196)},
1198 {"peach puff" , PALETTERGB (255,218,185)},
1199 {"PeachPuff" , PALETTERGB (255,218,185)},
1200 {"navajo white" , PALETTERGB (255,222,173)},
1201 {"NavajoWhite" , PALETTERGB (255,222,173)},
1202 {"moccasin" , PALETTERGB (255,228,181)},
1203 {"cornsilk" , PALETTERGB (255,248,220)},
1204 {"ivory" , PALETTERGB (255,255,240)},
1205 {"lemon chiffon" , PALETTERGB (255,250,205)},
1206 {"LemonChiffon" , PALETTERGB (255,250,205)},
1207 {"seashell" , PALETTERGB (255,245,238)},
1208 {"honeydew" , PALETTERGB (240,255,240)},
1209 {"mint cream" , PALETTERGB (245,255,250)},
1210 {"MintCream" , PALETTERGB (245,255,250)},
1211 {"azure" , PALETTERGB (240,255,255)},
1212 {"alice blue" , PALETTERGB (240,248,255)},
1213 {"AliceBlue" , PALETTERGB (240,248,255)},
1214 {"lavender" , PALETTERGB (230,230,250)},
1215 {"lavender blush" , PALETTERGB (255,240,245)},
1216 {"LavenderBlush" , PALETTERGB (255,240,245)},
1217 {"misty rose" , PALETTERGB (255,228,225)},
1218 {"MistyRose" , PALETTERGB (255,228,225)},
1219 {"white" , PALETTERGB (255,255,255)},
1220 {"black" , PALETTERGB ( 0, 0, 0)},
1221 {"dark slate gray" , PALETTERGB ( 47, 79, 79)},
1222 {"DarkSlateGray" , PALETTERGB ( 47, 79, 79)},
1223 {"dark slate grey" , PALETTERGB ( 47, 79, 79)},
1224 {"DarkSlateGrey" , PALETTERGB ( 47, 79, 79)},
1225 {"dim gray" , PALETTERGB (105,105,105)},
1226 {"DimGray" , PALETTERGB (105,105,105)},
1227 {"dim grey" , PALETTERGB (105,105,105)},
1228 {"DimGrey" , PALETTERGB (105,105,105)},
1229 {"slate gray" , PALETTERGB (112,128,144)},
1230 {"SlateGray" , PALETTERGB (112,128,144)},
1231 {"slate grey" , PALETTERGB (112,128,144)},
1232 {"SlateGrey" , PALETTERGB (112,128,144)},
1233 {"light slate gray" , PALETTERGB (119,136,153)},
1234 {"LightSlateGray" , PALETTERGB (119,136,153)},
1235 {"light slate grey" , PALETTERGB (119,136,153)},
1236 {"LightSlateGrey" , PALETTERGB (119,136,153)},
1237 {"gray" , PALETTERGB (190,190,190)},
1238 {"grey" , PALETTERGB (190,190,190)},
1239 {"light grey" , PALETTERGB (211,211,211)},
1240 {"LightGrey" , PALETTERGB (211,211,211)},
1241 {"light gray" , PALETTERGB (211,211,211)},
1242 {"LightGray" , PALETTERGB (211,211,211)},
1243 {"midnight blue" , PALETTERGB ( 25, 25,112)},
1244 {"MidnightBlue" , PALETTERGB ( 25, 25,112)},
1245 {"navy" , PALETTERGB ( 0, 0,128)},
1246 {"navy blue" , PALETTERGB ( 0, 0,128)},
1247 {"NavyBlue" , PALETTERGB ( 0, 0,128)},
1248 {"cornflower blue" , PALETTERGB (100,149,237)},
1249 {"CornflowerBlue" , PALETTERGB (100,149,237)},
1250 {"dark slate blue" , PALETTERGB ( 72, 61,139)},
1251 {"DarkSlateBlue" , PALETTERGB ( 72, 61,139)},
1252 {"slate blue" , PALETTERGB (106, 90,205)},
1253 {"SlateBlue" , PALETTERGB (106, 90,205)},
1254 {"medium slate blue" , PALETTERGB (123,104,238)},
1255 {"MediumSlateBlue" , PALETTERGB (123,104,238)},
1256 {"light slate blue" , PALETTERGB (132,112,255)},
1257 {"LightSlateBlue" , PALETTERGB (132,112,255)},
1258 {"medium blue" , PALETTERGB ( 0, 0,205)},
1259 {"MediumBlue" , PALETTERGB ( 0, 0,205)},
1260 {"royal blue" , PALETTERGB ( 65,105,225)},
1261 {"RoyalBlue" , PALETTERGB ( 65,105,225)},
1262 {"blue" , PALETTERGB ( 0, 0,255)},
1263 {"dodger blue" , PALETTERGB ( 30,144,255)},
1264 {"DodgerBlue" , PALETTERGB ( 30,144,255)},
1265 {"deep sky blue" , PALETTERGB ( 0,191,255)},
1266 {"DeepSkyBlue" , PALETTERGB ( 0,191,255)},
1267 {"sky blue" , PALETTERGB (135,206,235)},
1268 {"SkyBlue" , PALETTERGB (135,206,235)},
1269 {"light sky blue" , PALETTERGB (135,206,250)},
1270 {"LightSkyBlue" , PALETTERGB (135,206,250)},
1271 {"steel blue" , PALETTERGB ( 70,130,180)},
1272 {"SteelBlue" , PALETTERGB ( 70,130,180)},
1273 {"light steel blue" , PALETTERGB (176,196,222)},
1274 {"LightSteelBlue" , PALETTERGB (176,196,222)},
1275 {"light blue" , PALETTERGB (173,216,230)},
1276 {"LightBlue" , PALETTERGB (173,216,230)},
1277 {"powder blue" , PALETTERGB (176,224,230)},
1278 {"PowderBlue" , PALETTERGB (176,224,230)},
1279 {"pale turquoise" , PALETTERGB (175,238,238)},
1280 {"PaleTurquoise" , PALETTERGB (175,238,238)},
1281 {"dark turquoise" , PALETTERGB ( 0,206,209)},
1282 {"DarkTurquoise" , PALETTERGB ( 0,206,209)},
1283 {"medium turquoise" , PALETTERGB ( 72,209,204)},
1284 {"MediumTurquoise" , PALETTERGB ( 72,209,204)},
1285 {"turquoise" , PALETTERGB ( 64,224,208)},
1286 {"cyan" , PALETTERGB ( 0,255,255)},
1287 {"light cyan" , PALETTERGB (224,255,255)},
1288 {"LightCyan" , PALETTERGB (224,255,255)},
1289 {"cadet blue" , PALETTERGB ( 95,158,160)},
1290 {"CadetBlue" , PALETTERGB ( 95,158,160)},
1291 {"medium aquamarine" , PALETTERGB (102,205,170)},
1292 {"MediumAquamarine" , PALETTERGB (102,205,170)},
1293 {"aquamarine" , PALETTERGB (127,255,212)},
1294 {"dark green" , PALETTERGB ( 0,100, 0)},
1295 {"DarkGreen" , PALETTERGB ( 0,100, 0)},
1296 {"dark olive green" , PALETTERGB ( 85,107, 47)},
1297 {"DarkOliveGreen" , PALETTERGB ( 85,107, 47)},
1298 {"dark sea green" , PALETTERGB (143,188,143)},
1299 {"DarkSeaGreen" , PALETTERGB (143,188,143)},
1300 {"sea green" , PALETTERGB ( 46,139, 87)},
1301 {"SeaGreen" , PALETTERGB ( 46,139, 87)},
1302 {"medium sea green" , PALETTERGB ( 60,179,113)},
1303 {"MediumSeaGreen" , PALETTERGB ( 60,179,113)},
1304 {"light sea green" , PALETTERGB ( 32,178,170)},
1305 {"LightSeaGreen" , PALETTERGB ( 32,178,170)},
1306 {"pale green" , PALETTERGB (152,251,152)},
1307 {"PaleGreen" , PALETTERGB (152,251,152)},
1308 {"spring green" , PALETTERGB ( 0,255,127)},
1309 {"SpringGreen" , PALETTERGB ( 0,255,127)},
1310 {"lawn green" , PALETTERGB (124,252, 0)},
1311 {"LawnGreen" , PALETTERGB (124,252, 0)},
1312 {"green" , PALETTERGB ( 0,255, 0)},
1313 {"chartreuse" , PALETTERGB (127,255, 0)},
1314 {"medium spring green" , PALETTERGB ( 0,250,154)},
1315 {"MediumSpringGreen" , PALETTERGB ( 0,250,154)},
1316 {"green yellow" , PALETTERGB (173,255, 47)},
1317 {"GreenYellow" , PALETTERGB (173,255, 47)},
1318 {"lime green" , PALETTERGB ( 50,205, 50)},
1319 {"LimeGreen" , PALETTERGB ( 50,205, 50)},
1320 {"yellow green" , PALETTERGB (154,205, 50)},
1321 {"YellowGreen" , PALETTERGB (154,205, 50)},
1322 {"forest green" , PALETTERGB ( 34,139, 34)},
1323 {"ForestGreen" , PALETTERGB ( 34,139, 34)},
1324 {"olive drab" , PALETTERGB (107,142, 35)},
1325 {"OliveDrab" , PALETTERGB (107,142, 35)},
1326 {"dark khaki" , PALETTERGB (189,183,107)},
1327 {"DarkKhaki" , PALETTERGB (189,183,107)},
1328 {"khaki" , PALETTERGB (240,230,140)},
1329 {"pale goldenrod" , PALETTERGB (238,232,170)},
1330 {"PaleGoldenrod" , PALETTERGB (238,232,170)},
1331 {"light goldenrod yellow" , PALETTERGB (250,250,210)},
1332 {"LightGoldenrodYellow" , PALETTERGB (250,250,210)},
1333 {"light yellow" , PALETTERGB (255,255,224)},
1334 {"LightYellow" , PALETTERGB (255,255,224)},
1335 {"yellow" , PALETTERGB (255,255, 0)},
1336 {"gold" , PALETTERGB (255,215, 0)},
1337 {"light goldenrod" , PALETTERGB (238,221,130)},
1338 {"LightGoldenrod" , PALETTERGB (238,221,130)},
1339 {"goldenrod" , PALETTERGB (218,165, 32)},
1340 {"dark goldenrod" , PALETTERGB (184,134, 11)},
1341 {"DarkGoldenrod" , PALETTERGB (184,134, 11)},
1342 {"rosy brown" , PALETTERGB (188,143,143)},
1343 {"RosyBrown" , PALETTERGB (188,143,143)},
1344 {"indian red" , PALETTERGB (205, 92, 92)},
1345 {"IndianRed" , PALETTERGB (205, 92, 92)},
1346 {"saddle brown" , PALETTERGB (139, 69, 19)},
1347 {"SaddleBrown" , PALETTERGB (139, 69, 19)},
1348 {"sienna" , PALETTERGB (160, 82, 45)},
1349 {"peru" , PALETTERGB (205,133, 63)},
1350 {"burlywood" , PALETTERGB (222,184,135)},
1351 {"beige" , PALETTERGB (245,245,220)},
1352 {"wheat" , PALETTERGB (245,222,179)},
1353 {"sandy brown" , PALETTERGB (244,164, 96)},
1354 {"SandyBrown" , PALETTERGB (244,164, 96)},
1355 {"tan" , PALETTERGB (210,180,140)},
1356 {"chocolate" , PALETTERGB (210,105, 30)},
1357 {"firebrick" , PALETTERGB (178,34, 34)},
1358 {"brown" , PALETTERGB (165,42, 42)},
1359 {"dark salmon" , PALETTERGB (233,150,122)},
1360 {"DarkSalmon" , PALETTERGB (233,150,122)},
1361 {"salmon" , PALETTERGB (250,128,114)},
1362 {"light salmon" , PALETTERGB (255,160,122)},
1363 {"LightSalmon" , PALETTERGB (255,160,122)},
1364 {"orange" , PALETTERGB (255,165, 0)},
1365 {"dark orange" , PALETTERGB (255,140, 0)},
1366 {"DarkOrange" , PALETTERGB (255,140, 0)},
1367 {"coral" , PALETTERGB (255,127, 80)},
1368 {"light coral" , PALETTERGB (240,128,128)},
1369 {"LightCoral" , PALETTERGB (240,128,128)},
1370 {"tomato" , PALETTERGB (255, 99, 71)},
1371 {"orange red" , PALETTERGB (255, 69, 0)},
1372 {"OrangeRed" , PALETTERGB (255, 69, 0)},
1373 {"red" , PALETTERGB (255, 0, 0)},
1374 {"hot pink" , PALETTERGB (255,105,180)},
1375 {"HotPink" , PALETTERGB (255,105,180)},
1376 {"deep pink" , PALETTERGB (255, 20,147)},
1377 {"DeepPink" , PALETTERGB (255, 20,147)},
1378 {"pink" , PALETTERGB (255,192,203)},
1379 {"light pink" , PALETTERGB (255,182,193)},
1380 {"LightPink" , PALETTERGB (255,182,193)},
1381 {"pale violet red" , PALETTERGB (219,112,147)},
1382 {"PaleVioletRed" , PALETTERGB (219,112,147)},
1383 {"maroon" , PALETTERGB (176, 48, 96)},
1384 {"medium violet red" , PALETTERGB (199, 21,133)},
1385 {"MediumVioletRed" , PALETTERGB (199, 21,133)},
1386 {"violet red" , PALETTERGB (208, 32,144)},
1387 {"VioletRed" , PALETTERGB (208, 32,144)},
1388 {"magenta" , PALETTERGB (255, 0,255)},
1389 {"violet" , PALETTERGB (238,130,238)},
1390 {"plum" , PALETTERGB (221,160,221)},
1391 {"orchid" , PALETTERGB (218,112,214)},
1392 {"medium orchid" , PALETTERGB (186, 85,211)},
1393 {"MediumOrchid" , PALETTERGB (186, 85,211)},
1394 {"dark orchid" , PALETTERGB (153, 50,204)},
1395 {"DarkOrchid" , PALETTERGB (153, 50,204)},
1396 {"dark violet" , PALETTERGB (148, 0,211)},
1397 {"DarkViolet" , PALETTERGB (148, 0,211)},
1398 {"blue violet" , PALETTERGB (138, 43,226)},
1399 {"BlueViolet" , PALETTERGB (138, 43,226)},
1400 {"purple" , PALETTERGB (160, 32,240)},
1401 {"medium purple" , PALETTERGB (147,112,219)},
1402 {"MediumPurple" , PALETTERGB (147,112,219)},
1403 {"thistle" , PALETTERGB (216,191,216)},
1404 {"gray0" , PALETTERGB ( 0, 0, 0)},
1405 {"grey0" , PALETTERGB ( 0, 0, 0)},
1406 {"dark grey" , PALETTERGB (169,169,169)},
1407 {"DarkGrey" , PALETTERGB (169,169,169)},
1408 {"dark gray" , PALETTERGB (169,169,169)},
1409 {"DarkGray" , PALETTERGB (169,169,169)},
1410 {"dark blue" , PALETTERGB ( 0, 0,139)},
1411 {"DarkBlue" , PALETTERGB ( 0, 0,139)},
1412 {"dark cyan" , PALETTERGB ( 0,139,139)},
1413 {"DarkCyan" , PALETTERGB ( 0,139,139)},
1414 {"dark magenta" , PALETTERGB (139, 0,139)},
1415 {"DarkMagenta" , PALETTERGB (139, 0,139)},
1416 {"dark red" , PALETTERGB (139, 0, 0)},
1417 {"DarkRed" , PALETTERGB (139, 0, 0)},
1418 {"light green" , PALETTERGB (144,238,144)},
1419 {"LightGreen" , PALETTERGB (144,238,144)},
1420 };
1421
1422 DEFUN ("w32-default-color-map", Fw32_default_color_map, Sw32_default_color_map,
1423 0, 0, 0, "Return the default color map.")
1424 ()
1425 {
1426 int i;
1427 colormap_t *pc = w32_color_map;
1428 Lisp_Object cmap;
1429
1430 BLOCK_INPUT;
1431
1432 cmap = Qnil;
1433
1434 for (i = 0; i < sizeof (w32_color_map) / sizeof (w32_color_map[0]);
1435 pc++, i++)
1436 cmap = Fcons (Fcons (build_string (pc->name),
1437 make_number (pc->colorref)),
1438 cmap);
1439
1440 UNBLOCK_INPUT;
1441
1442 return (cmap);
1443 }
1444
1445 Lisp_Object
1446 w32_to_x_color (rgb)
1447 Lisp_Object rgb;
1448 {
1449 Lisp_Object color;
1450
1451 CHECK_NUMBER (rgb, 0);
1452
1453 BLOCK_INPUT;
1454
1455 color = Frassq (rgb, Vw32_color_map);
1456
1457 UNBLOCK_INPUT;
1458
1459 if (!NILP (color))
1460 return (Fcar (color));
1461 else
1462 return Qnil;
1463 }
1464
1465 COLORREF
1466 w32_color_map_lookup (colorname)
1467 char *colorname;
1468 {
1469 Lisp_Object tail, ret = Qnil;
1470
1471 BLOCK_INPUT;
1472
1473 for (tail = Vw32_color_map; !NILP (tail); tail = Fcdr (tail))
1474 {
1475 register Lisp_Object elt, tem;
1476
1477 elt = Fcar (tail);
1478 if (!CONSP (elt)) continue;
1479
1480 tem = Fcar (elt);
1481
1482 if (lstrcmpi (XSTRING (tem)->data, colorname) == 0)
1483 {
1484 ret = XUINT (Fcdr (elt));
1485 break;
1486 }
1487
1488 QUIT;
1489 }
1490
1491
1492 UNBLOCK_INPUT;
1493
1494 return ret;
1495 }
1496
1497 COLORREF
1498 x_to_w32_color (colorname)
1499 char * colorname;
1500 {
1501 register Lisp_Object tail, ret = Qnil;
1502
1503 BLOCK_INPUT;
1504
1505 if (colorname[0] == '#')
1506 {
1507 /* Could be an old-style RGB Device specification. */
1508 char *color;
1509 int size;
1510 color = colorname + 1;
1511
1512 size = strlen(color);
1513 if (size == 3 || size == 6 || size == 9 || size == 12)
1514 {
1515 UINT colorval;
1516 int i, pos;
1517 pos = 0;
1518 size /= 3;
1519 colorval = 0;
1520
1521 for (i = 0; i < 3; i++)
1522 {
1523 char *end;
1524 char t;
1525 unsigned long value;
1526
1527 /* The check for 'x' in the following conditional takes into
1528 account the fact that strtol allows a "0x" in front of
1529 our numbers, and we don't. */
1530 if (!isxdigit(color[0]) || color[1] == 'x')
1531 break;
1532 t = color[size];
1533 color[size] = '\0';
1534 value = strtoul(color, &end, 16);
1535 color[size] = t;
1536 if (errno == ERANGE || end - color != size)
1537 break;
1538 switch (size)
1539 {
1540 case 1:
1541 value = value * 0x10;
1542 break;
1543 case 2:
1544 break;
1545 case 3:
1546 value /= 0x10;
1547 break;
1548 case 4:
1549 value /= 0x100;
1550 break;
1551 }
1552 colorval |= (value << pos);
1553 pos += 0x8;
1554 if (i == 2)
1555 {
1556 UNBLOCK_INPUT;
1557 return (colorval);
1558 }
1559 color = end;
1560 }
1561 }
1562 }
1563 else if (strnicmp(colorname, "rgb:", 4) == 0)
1564 {
1565 char *color;
1566 UINT colorval;
1567 int i, pos;
1568 pos = 0;
1569
1570 colorval = 0;
1571 color = colorname + 4;
1572 for (i = 0; i < 3; i++)
1573 {
1574 char *end;
1575 unsigned long value;
1576
1577 /* The check for 'x' in the following conditional takes into
1578 account the fact that strtol allows a "0x" in front of
1579 our numbers, and we don't. */
1580 if (!isxdigit(color[0]) || color[1] == 'x')
1581 break;
1582 value = strtoul(color, &end, 16);
1583 if (errno == ERANGE)
1584 break;
1585 switch (end - color)
1586 {
1587 case 1:
1588 value = value * 0x10 + value;
1589 break;
1590 case 2:
1591 break;
1592 case 3:
1593 value /= 0x10;
1594 break;
1595 case 4:
1596 value /= 0x100;
1597 break;
1598 default:
1599 value = ULONG_MAX;
1600 }
1601 if (value == ULONG_MAX)
1602 break;
1603 colorval |= (value << pos);
1604 pos += 0x8;
1605 if (i == 2)
1606 {
1607 if (*end != '\0')
1608 break;
1609 UNBLOCK_INPUT;
1610 return (colorval);
1611 }
1612 if (*end != '/')
1613 break;
1614 color = end + 1;
1615 }
1616 }
1617 else if (strnicmp(colorname, "rgbi:", 5) == 0)
1618 {
1619 /* This is an RGB Intensity specification. */
1620 char *color;
1621 UINT colorval;
1622 int i, pos;
1623 pos = 0;
1624
1625 colorval = 0;
1626 color = colorname + 5;
1627 for (i = 0; i < 3; i++)
1628 {
1629 char *end;
1630 double value;
1631 UINT val;
1632
1633 value = strtod(color, &end);
1634 if (errno == ERANGE)
1635 break;
1636 if (value < 0.0 || value > 1.0)
1637 break;
1638 val = (UINT)(0x100 * value);
1639 /* We used 0x100 instead of 0xFF to give an continuous
1640 range between 0.0 and 1.0 inclusive. The next statement
1641 fixes the 1.0 case. */
1642 if (val == 0x100)
1643 val = 0xFF;
1644 colorval |= (val << pos);
1645 pos += 0x8;
1646 if (i == 2)
1647 {
1648 if (*end != '\0')
1649 break;
1650 UNBLOCK_INPUT;
1651 return (colorval);
1652 }
1653 if (*end != '/')
1654 break;
1655 color = end + 1;
1656 }
1657 }
1658 /* I am not going to attempt to handle any of the CIE color schemes
1659 or TekHVC, since I don't know the algorithms for conversion to
1660 RGB. */
1661
1662 /* If we fail to lookup the color name in w32_color_map, then check the
1663 colorname to see if it can be crudely approximated: If the X color
1664 ends in a number (e.g., "darkseagreen2"), strip the number and
1665 return the result of looking up the base color name. */
1666 ret = w32_color_map_lookup (colorname);
1667 if (NILP (ret))
1668 {
1669 int len = strlen (colorname);
1670
1671 if (isdigit (colorname[len - 1]))
1672 {
1673 char *ptr, *approx = alloca (len);
1674
1675 strcpy (approx, colorname);
1676 ptr = &approx[len - 1];
1677 while (ptr > approx && isdigit (*ptr))
1678 *ptr-- = '\0';
1679
1680 ret = w32_color_map_lookup (approx);
1681 }
1682 }
1683
1684 UNBLOCK_INPUT;
1685 return ret;
1686 }
1687
1688
1689 void
1690 w32_regenerate_palette (FRAME_PTR f)
1691 {
1692 struct w32_palette_entry * list;
1693 LOGPALETTE * log_palette;
1694 HPALETTE new_palette;
1695 int i;
1696
1697 /* don't bother trying to create palette if not supported */
1698 if (! FRAME_W32_DISPLAY_INFO (f)->has_palette)
1699 return;
1700
1701 log_palette = (LOGPALETTE *)
1702 alloca (sizeof (LOGPALETTE) +
1703 FRAME_W32_DISPLAY_INFO (f)->num_colors * sizeof (PALETTEENTRY));
1704 log_palette->palVersion = 0x300;
1705 log_palette->palNumEntries = FRAME_W32_DISPLAY_INFO (f)->num_colors;
1706
1707 list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1708 for (i = 0;
1709 i < FRAME_W32_DISPLAY_INFO (f)->num_colors;
1710 i++, list = list->next)
1711 log_palette->palPalEntry[i] = list->entry;
1712
1713 new_palette = CreatePalette (log_palette);
1714
1715 enter_crit ();
1716
1717 if (FRAME_W32_DISPLAY_INFO (f)->palette)
1718 DeleteObject (FRAME_W32_DISPLAY_INFO (f)->palette);
1719 FRAME_W32_DISPLAY_INFO (f)->palette = new_palette;
1720
1721 /* Realize display palette and garbage all frames. */
1722 release_frame_dc (f, get_frame_dc (f));
1723
1724 leave_crit ();
1725 }
1726
1727 #define W32_COLOR(pe) RGB (pe.peRed, pe.peGreen, pe.peBlue)
1728 #define SET_W32_COLOR(pe, color) \
1729 do \
1730 { \
1731 pe.peRed = GetRValue (color); \
1732 pe.peGreen = GetGValue (color); \
1733 pe.peBlue = GetBValue (color); \
1734 pe.peFlags = 0; \
1735 } while (0)
1736
1737 #if 0
1738 /* Keep these around in case we ever want to track color usage. */
1739 void
1740 w32_map_color (FRAME_PTR f, COLORREF color)
1741 {
1742 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1743
1744 if (NILP (Vw32_enable_palette))
1745 return;
1746
1747 /* check if color is already mapped */
1748 while (list)
1749 {
1750 if (W32_COLOR (list->entry) == color)
1751 {
1752 ++list->refcount;
1753 return;
1754 }
1755 list = list->next;
1756 }
1757
1758 /* not already mapped, so add to list and recreate Windows palette */
1759 list = (struct w32_palette_entry *)
1760 xmalloc (sizeof (struct w32_palette_entry));
1761 SET_W32_COLOR (list->entry, color);
1762 list->refcount = 1;
1763 list->next = FRAME_W32_DISPLAY_INFO (f)->color_list;
1764 FRAME_W32_DISPLAY_INFO (f)->color_list = list;
1765 FRAME_W32_DISPLAY_INFO (f)->num_colors++;
1766
1767 /* set flag that palette must be regenerated */
1768 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
1769 }
1770
1771 void
1772 w32_unmap_color (FRAME_PTR f, COLORREF color)
1773 {
1774 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1775 struct w32_palette_entry **prev = &FRAME_W32_DISPLAY_INFO (f)->color_list;
1776
1777 if (NILP (Vw32_enable_palette))
1778 return;
1779
1780 /* check if color is already mapped */
1781 while (list)
1782 {
1783 if (W32_COLOR (list->entry) == color)
1784 {
1785 if (--list->refcount == 0)
1786 {
1787 *prev = list->next;
1788 xfree (list);
1789 FRAME_W32_DISPLAY_INFO (f)->num_colors--;
1790 break;
1791 }
1792 else
1793 return;
1794 }
1795 prev = &list->next;
1796 list = list->next;
1797 }
1798
1799 /* set flag that palette must be regenerated */
1800 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
1801 }
1802 #endif
1803
1804
1805 /* Gamma-correct COLOR on frame F. */
1806
1807 void
1808 gamma_correct (f, color)
1809 struct frame *f;
1810 COLORREF *color;
1811 {
1812 if (f->gamma)
1813 {
1814 *color = PALETTERGB (
1815 pow (GetRValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1816 pow (GetGValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1817 pow (GetBValue (*color) / 255.0, f->gamma) * 255.0 + 0.5);
1818 }
1819 }
1820
1821
1822 /* Decide if color named COLOR is valid for the display associated with
1823 the selected frame; if so, return the rgb values in COLOR_DEF.
1824 If ALLOC is nonzero, allocate a new colormap cell. */
1825
1826 int
1827 w32_defined_color (f, color, color_def, alloc)
1828 FRAME_PTR f;
1829 char *color;
1830 XColor *color_def;
1831 int alloc;
1832 {
1833 register Lisp_Object tem;
1834 COLORREF w32_color_ref;
1835
1836 tem = x_to_w32_color (color);
1837
1838 if (!NILP (tem))
1839 {
1840 if (f)
1841 {
1842 /* Apply gamma correction. */
1843 w32_color_ref = XUINT (tem);
1844 gamma_correct (f, &w32_color_ref);
1845 XSETINT (tem, w32_color_ref);
1846 }
1847
1848 /* Map this color to the palette if it is enabled. */
1849 if (!NILP (Vw32_enable_palette))
1850 {
1851 struct w32_palette_entry * entry =
1852 one_w32_display_info.color_list;
1853 struct w32_palette_entry ** prev =
1854 &one_w32_display_info.color_list;
1855
1856 /* check if color is already mapped */
1857 while (entry)
1858 {
1859 if (W32_COLOR (entry->entry) == XUINT (tem))
1860 break;
1861 prev = &entry->next;
1862 entry = entry->next;
1863 }
1864
1865 if (entry == NULL && alloc)
1866 {
1867 /* not already mapped, so add to list */
1868 entry = (struct w32_palette_entry *)
1869 xmalloc (sizeof (struct w32_palette_entry));
1870 SET_W32_COLOR (entry->entry, XUINT (tem));
1871 entry->next = NULL;
1872 *prev = entry;
1873 one_w32_display_info.num_colors++;
1874
1875 /* set flag that palette must be regenerated */
1876 one_w32_display_info.regen_palette = TRUE;
1877 }
1878 }
1879 /* Ensure COLORREF value is snapped to nearest color in (default)
1880 palette by simulating the PALETTERGB macro. This works whether
1881 or not the display device has a palette. */
1882 w32_color_ref = XUINT (tem) | 0x2000000;
1883
1884 color_def->pixel = w32_color_ref;
1885 color_def->red = GetRValue (w32_color_ref);
1886 color_def->green = GetGValue (w32_color_ref);
1887 color_def->blue = GetBValue (w32_color_ref);
1888
1889 return 1;
1890 }
1891 else
1892 {
1893 return 0;
1894 }
1895 }
1896
1897 /* Given a string ARG naming a color, compute a pixel value from it
1898 suitable for screen F.
1899 If F is not a color screen, return DEF (default) regardless of what
1900 ARG says. */
1901
1902 int
1903 x_decode_color (f, arg, def)
1904 FRAME_PTR f;
1905 Lisp_Object arg;
1906 int def;
1907 {
1908 XColor cdef;
1909
1910 CHECK_STRING (arg, 0);
1911
1912 if (strcmp (XSTRING (arg)->data, "black") == 0)
1913 return BLACK_PIX_DEFAULT (f);
1914 else if (strcmp (XSTRING (arg)->data, "white") == 0)
1915 return WHITE_PIX_DEFAULT (f);
1916
1917 if ((FRAME_W32_DISPLAY_INFO (f)->n_planes * FRAME_W32_DISPLAY_INFO (f)->n_cbits) == 1)
1918 return def;
1919
1920 /* w32_defined_color is responsible for coping with failures
1921 by looking for a near-miss. */
1922 if (w32_defined_color (f, XSTRING (arg)->data, &cdef, 1))
1923 return cdef.pixel;
1924
1925 /* defined_color failed; return an ultimate default. */
1926 return def;
1927 }
1928 \f
1929 /* Change the `line-spacing' frame parameter of frame F. OLD_VALUE is
1930 the previous value of that parameter, NEW_VALUE is the new value. */
1931
1932 static void
1933 x_set_line_spacing (f, new_value, old_value)
1934 struct frame *f;
1935 Lisp_Object new_value, old_value;
1936 {
1937 if (NILP (new_value))
1938 f->extra_line_spacing = 0;
1939 else if (NATNUMP (new_value))
1940 f->extra_line_spacing = XFASTINT (new_value);
1941 else
1942 Fsignal (Qerror, Fcons (build_string ("Illegal line-spacing"),
1943 Fcons (new_value, Qnil)));
1944 if (FRAME_VISIBLE_P (f))
1945 redraw_frame (f);
1946 }
1947
1948
1949 /* Change the `screen-gamma' frame parameter of frame F. OLD_VALUE is
1950 the previous value of that parameter, NEW_VALUE is the new value. */
1951
1952 static void
1953 x_set_screen_gamma (f, new_value, old_value)
1954 struct frame *f;
1955 Lisp_Object new_value, old_value;
1956 {
1957 if (NILP (new_value))
1958 f->gamma = 0;
1959 else if (NUMBERP (new_value) && XFLOATINT (new_value) > 0)
1960 /* The value 0.4545 is the normal viewing gamma. */
1961 f->gamma = 1.0 / (0.4545 * XFLOATINT (new_value));
1962 else
1963 Fsignal (Qerror, Fcons (build_string ("Illegal screen-gamma"),
1964 Fcons (new_value, Qnil)));
1965
1966 clear_face_cache (0);
1967 }
1968
1969
1970 /* Functions called only from `x_set_frame_param'
1971 to set individual parameters.
1972
1973 If FRAME_W32_WINDOW (f) is 0,
1974 the frame is being created and its window does not exist yet.
1975 In that case, just record the parameter's new value
1976 in the standard place; do not attempt to change the window. */
1977
1978 void
1979 x_set_foreground_color (f, arg, oldval)
1980 struct frame *f;
1981 Lisp_Object arg, oldval;
1982 {
1983 FRAME_FOREGROUND_PIXEL (f)
1984 = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
1985
1986 if (FRAME_W32_WINDOW (f) != 0)
1987 {
1988 update_face_from_frame_parameter (f, Qforeground_color, arg);
1989 if (FRAME_VISIBLE_P (f))
1990 redraw_frame (f);
1991 }
1992 }
1993
1994 void
1995 x_set_background_color (f, arg, oldval)
1996 struct frame *f;
1997 Lisp_Object arg, oldval;
1998 {
1999 FRAME_BACKGROUND_PIXEL (f)
2000 = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
2001
2002 if (FRAME_W32_WINDOW (f) != 0)
2003 {
2004 SetWindowLong (FRAME_W32_WINDOW (f), WND_BACKGROUND_INDEX,
2005 FRAME_BACKGROUND_PIXEL (f));
2006
2007 update_face_from_frame_parameter (f, Qbackground_color, arg);
2008
2009 if (FRAME_VISIBLE_P (f))
2010 redraw_frame (f);
2011 }
2012 }
2013
2014 void
2015 x_set_mouse_color (f, arg, oldval)
2016 struct frame *f;
2017 Lisp_Object arg, oldval;
2018 {
2019
2020 Cursor cursor, nontext_cursor, mode_cursor, cross_cursor;
2021 int count;
2022 int mask_color;
2023
2024 if (!EQ (Qnil, arg))
2025 f->output_data.w32->mouse_pixel
2026 = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2027 mask_color = FRAME_BACKGROUND_PIXEL (f);
2028
2029 /* Don't let pointers be invisible. */
2030 if (mask_color == f->output_data.w32->mouse_pixel
2031 && mask_color == FRAME_BACKGROUND_PIXEL (f))
2032 f->output_data.w32->mouse_pixel = FRAME_FOREGROUND_PIXEL (f);
2033
2034 #if 0 /* NTEMACS_TODO : cursor changes */
2035 BLOCK_INPUT;
2036
2037 /* It's not okay to crash if the user selects a screwy cursor. */
2038 count = x_catch_errors (FRAME_W32_DISPLAY (f));
2039
2040 if (!EQ (Qnil, Vx_pointer_shape))
2041 {
2042 CHECK_NUMBER (Vx_pointer_shape, 0);
2043 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XINT (Vx_pointer_shape));
2044 }
2045 else
2046 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2047 x_check_errors (FRAME_W32_DISPLAY (f), "bad text pointer cursor: %s");
2048
2049 if (!EQ (Qnil, Vx_nontext_pointer_shape))
2050 {
2051 CHECK_NUMBER (Vx_nontext_pointer_shape, 0);
2052 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2053 XINT (Vx_nontext_pointer_shape));
2054 }
2055 else
2056 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_left_ptr);
2057 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
2058
2059 if (!EQ (Qnil, Vx_busy_pointer_shape))
2060 {
2061 CHECK_NUMBER (Vx_busy_pointer_shape, 0);
2062 busy_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2063 XINT (Vx_busy_pointer_shape));
2064 }
2065 else
2066 busy_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_watch);
2067 x_check_errors (FRAME_W32_DISPLAY (f), "bad busy pointer cursor: %s");
2068
2069 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
2070 if (!EQ (Qnil, Vx_mode_pointer_shape))
2071 {
2072 CHECK_NUMBER (Vx_mode_pointer_shape, 0);
2073 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2074 XINT (Vx_mode_pointer_shape));
2075 }
2076 else
2077 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2078 x_check_errors (FRAME_W32_DISPLAY (f), "bad modeline pointer cursor: %s");
2079
2080 if (!EQ (Qnil, Vx_sensitive_text_pointer_shape))
2081 {
2082 CHECK_NUMBER (Vx_sensitive_text_pointer_shape, 0);
2083 cross_cursor
2084 = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2085 XINT (Vx_sensitive_text_pointer_shape));
2086 }
2087 else
2088 cross_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_crosshair);
2089
2090 /* Check and report errors with the above calls. */
2091 x_check_errors (FRAME_W32_DISPLAY (f), "can't set cursor shape: %s");
2092 x_uncatch_errors (FRAME_W32_DISPLAY (f), count);
2093
2094 {
2095 XColor fore_color, back_color;
2096
2097 fore_color.pixel = f->output_data.w32->mouse_pixel;
2098 back_color.pixel = mask_color;
2099 XQueryColor (FRAME_W32_DISPLAY (f),
2100 DefaultColormap (FRAME_W32_DISPLAY (f),
2101 DefaultScreen (FRAME_W32_DISPLAY (f))),
2102 &fore_color);
2103 XQueryColor (FRAME_W32_DISPLAY (f),
2104 DefaultColormap (FRAME_W32_DISPLAY (f),
2105 DefaultScreen (FRAME_W32_DISPLAY (f))),
2106 &back_color);
2107 XRecolorCursor (FRAME_W32_DISPLAY (f), cursor,
2108 &fore_color, &back_color);
2109 XRecolorCursor (FRAME_W32_DISPLAY (f), nontext_cursor,
2110 &fore_color, &back_color);
2111 XRecolorCursor (FRAME_W32_DISPLAY (f), mode_cursor,
2112 &fore_color, &back_color);
2113 XRecolorCursor (FRAME_W32_DISPLAY (f), cross_cursor,
2114 &fore_color, &back_color);
2115 XRecolorCursor (FRAME_W32_DISPLAY (f), busy_cursor,
2116 &fore_color, &back_color);
2117 }
2118
2119 if (FRAME_W32_WINDOW (f) != 0)
2120 XDefineCursor (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), cursor);
2121
2122 if (cursor != f->output_data.w32->text_cursor && f->output_data.w32->text_cursor != 0)
2123 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->text_cursor);
2124 f->output_data.w32->text_cursor = cursor;
2125
2126 if (nontext_cursor != f->output_data.w32->nontext_cursor
2127 && f->output_data.w32->nontext_cursor != 0)
2128 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->nontext_cursor);
2129 f->output_data.w32->nontext_cursor = nontext_cursor;
2130
2131 if (busy_cursor != f->output_data.w32->busy_cursor
2132 && f->output_data.w32->busy_cursor != 0)
2133 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->busy_cursor);
2134 f->output_data.w32->busy_cursor = busy_cursor;
2135
2136 if (mode_cursor != f->output_data.w32->modeline_cursor
2137 && f->output_data.w32->modeline_cursor != 0)
2138 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->modeline_cursor);
2139 f->output_data.w32->modeline_cursor = mode_cursor;
2140
2141 if (cross_cursor != f->output_data.w32->cross_cursor
2142 && f->output_data.w32->cross_cursor != 0)
2143 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->cross_cursor);
2144 f->output_data.w32->cross_cursor = cross_cursor;
2145
2146 XFlush (FRAME_W32_DISPLAY (f));
2147 UNBLOCK_INPUT;
2148
2149 update_face_from_frame_parameter (f, Qmouse_color, arg);
2150 #endif /* NTEMACS_TODO */
2151 }
2152
2153 void
2154 x_set_cursor_color (f, arg, oldval)
2155 struct frame *f;
2156 Lisp_Object arg, oldval;
2157 {
2158 unsigned long fore_pixel;
2159
2160 if (!NILP (Vx_cursor_fore_pixel))
2161 fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel,
2162 WHITE_PIX_DEFAULT (f));
2163 else
2164 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
2165 f->output_data.w32->cursor_pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2166
2167 /* Make sure that the cursor color differs from the background color. */
2168 if (f->output_data.w32->cursor_pixel == FRAME_BACKGROUND_PIXEL (f))
2169 {
2170 f->output_data.w32->cursor_pixel = f->output_data.w32->mouse_pixel;
2171 if (f->output_data.w32->cursor_pixel == fore_pixel)
2172 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
2173 }
2174 FRAME_FOREGROUND_PIXEL (f) = fore_pixel;
2175
2176 if (FRAME_W32_WINDOW (f) != 0)
2177 {
2178 if (FRAME_VISIBLE_P (f))
2179 {
2180 x_display_cursor (f, 0);
2181 x_display_cursor (f, 1);
2182 }
2183 }
2184
2185 update_face_from_frame_parameter (f, Qcursor_color, arg);
2186 }
2187
2188 /* Set the border-color of frame F to pixel value PIX.
2189 Note that this does not fully take effect if done before
2190 F has an window. */
2191 void
2192 x_set_border_pixel (f, pix)
2193 struct frame *f;
2194 int pix;
2195 {
2196 f->output_data.w32->border_pixel = pix;
2197
2198 if (FRAME_W32_WINDOW (f) != 0 && f->output_data.w32->border_width > 0)
2199 {
2200 if (FRAME_VISIBLE_P (f))
2201 redraw_frame (f);
2202 }
2203 }
2204
2205 /* Set the border-color of frame F to value described by ARG.
2206 ARG can be a string naming a color.
2207 The border-color is used for the border that is drawn by the server.
2208 Note that this does not fully take effect if done before
2209 F has a window; it must be redone when the window is created. */
2210
2211 void
2212 x_set_border_color (f, arg, oldval)
2213 struct frame *f;
2214 Lisp_Object arg, oldval;
2215 {
2216 int pix;
2217
2218 CHECK_STRING (arg, 0);
2219 pix = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2220 x_set_border_pixel (f, pix);
2221 update_face_from_frame_parameter (f, Qborder_color, arg);
2222 }
2223
2224 /* Value is the internal representation of the specified cursor type
2225 ARG. If type is BAR_CURSOR, return in *WIDTH the specified width
2226 of the bar cursor. */
2227
2228 enum text_cursor_kinds
2229 x_specified_cursor_type (arg, width)
2230 Lisp_Object arg;
2231 int *width;
2232 {
2233 enum text_cursor_kinds type;
2234
2235 if (EQ (arg, Qbar))
2236 {
2237 type = BAR_CURSOR;
2238 *width = 2;
2239 }
2240 else if (CONSP (arg)
2241 && EQ (XCAR (arg), Qbar)
2242 && INTEGERP (XCDR (arg))
2243 && XINT (XCDR (arg)) >= 0)
2244 {
2245 type = BAR_CURSOR;
2246 *width = XINT (XCDR (arg));
2247 }
2248 else if (NILP (arg))
2249 type = NO_CURSOR;
2250 else
2251 /* Treat anything unknown as "box cursor".
2252 It was bad to signal an error; people have trouble fixing
2253 .Xdefaults with Emacs, when it has something bad in it. */
2254 type = FILLED_BOX_CURSOR;
2255
2256 return type;
2257 }
2258
2259 void
2260 x_set_cursor_type (f, arg, oldval)
2261 FRAME_PTR f;
2262 Lisp_Object arg, oldval;
2263 {
2264 int width;
2265
2266 FRAME_DESIRED_CURSOR (f) = x_specified_cursor_type (arg, &width);
2267 f->output_data.w32->cursor_width = width;
2268
2269 /* Make sure the cursor gets redrawn. This is overkill, but how
2270 often do people change cursor types? */
2271 update_mode_lines++;
2272 }
2273 \f
2274 void
2275 x_set_icon_type (f, arg, oldval)
2276 struct frame *f;
2277 Lisp_Object arg, oldval;
2278 {
2279 int result;
2280
2281 if (NILP (arg) && NILP (oldval))
2282 return;
2283
2284 if (STRINGP (arg) && STRINGP (oldval)
2285 && EQ (Fstring_equal (oldval, arg), Qt))
2286 return;
2287
2288 if (SYMBOLP (arg) && SYMBOLP (oldval) && EQ (arg, oldval))
2289 return;
2290
2291 BLOCK_INPUT;
2292
2293 result = x_bitmap_icon (f, arg);
2294 if (result)
2295 {
2296 UNBLOCK_INPUT;
2297 error ("No icon window available");
2298 }
2299
2300 UNBLOCK_INPUT;
2301 }
2302
2303 /* Return non-nil if frame F wants a bitmap icon. */
2304
2305 Lisp_Object
2306 x_icon_type (f)
2307 FRAME_PTR f;
2308 {
2309 Lisp_Object tem;
2310
2311 tem = assq_no_quit (Qicon_type, f->param_alist);
2312 if (CONSP (tem))
2313 return XCDR (tem);
2314 else
2315 return Qnil;
2316 }
2317
2318 void
2319 x_set_icon_name (f, arg, oldval)
2320 struct frame *f;
2321 Lisp_Object arg, oldval;
2322 {
2323 int result;
2324
2325 if (STRINGP (arg))
2326 {
2327 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
2328 return;
2329 }
2330 else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
2331 return;
2332
2333 f->icon_name = arg;
2334
2335 #if 0
2336 if (f->output_data.w32->icon_bitmap != 0)
2337 return;
2338
2339 BLOCK_INPUT;
2340
2341 result = x_text_icon (f,
2342 (char *) XSTRING ((!NILP (f->icon_name)
2343 ? f->icon_name
2344 : !NILP (f->title)
2345 ? f->title
2346 : f->name))->data);
2347
2348 if (result)
2349 {
2350 UNBLOCK_INPUT;
2351 error ("No icon window available");
2352 }
2353
2354 /* If the window was unmapped (and its icon was mapped),
2355 the new icon is not mapped, so map the window in its stead. */
2356 if (FRAME_VISIBLE_P (f))
2357 {
2358 #ifdef USE_X_TOOLKIT
2359 XtPopup (f->output_data.w32->widget, XtGrabNone);
2360 #endif
2361 XMapWindow (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f));
2362 }
2363
2364 XFlush (FRAME_W32_DISPLAY (f));
2365 UNBLOCK_INPUT;
2366 #endif
2367 }
2368
2369 extern Lisp_Object x_new_font ();
2370 extern Lisp_Object x_new_fontset();
2371
2372 void
2373 x_set_font (f, arg, oldval)
2374 struct frame *f;
2375 Lisp_Object arg, oldval;
2376 {
2377 Lisp_Object result;
2378 Lisp_Object fontset_name;
2379 Lisp_Object frame;
2380
2381 CHECK_STRING (arg, 1);
2382
2383 fontset_name = Fquery_fontset (arg, Qnil);
2384
2385 BLOCK_INPUT;
2386 result = (STRINGP (fontset_name)
2387 ? x_new_fontset (f, XSTRING (fontset_name)->data)
2388 : x_new_font (f, XSTRING (arg)->data));
2389 UNBLOCK_INPUT;
2390
2391 if (EQ (result, Qnil))
2392 error ("Font `%s' is not defined", XSTRING (arg)->data);
2393 else if (EQ (result, Qt))
2394 error ("The characters of the given font have varying widths");
2395 else if (STRINGP (result))
2396 {
2397 store_frame_param (f, Qfont, result);
2398 recompute_basic_faces (f);
2399 }
2400 else
2401 abort ();
2402
2403 do_pending_window_change (0);
2404
2405 /* Don't call `face-set-after-frame-default' when faces haven't been
2406 initialized yet. This is the case when called from
2407 Fx_create_frame. In that case, the X widget or window doesn't
2408 exist either, and we can end up in x_report_frame_params with a
2409 null widget which gives a segfault. */
2410 if (FRAME_FACE_CACHE (f))
2411 {
2412 XSETFRAME (frame, f);
2413 call1 (Qface_set_after_frame_default, frame);
2414 }
2415 }
2416
2417 void
2418 x_set_border_width (f, arg, oldval)
2419 struct frame *f;
2420 Lisp_Object arg, oldval;
2421 {
2422 CHECK_NUMBER (arg, 0);
2423
2424 if (XINT (arg) == f->output_data.w32->border_width)
2425 return;
2426
2427 if (FRAME_W32_WINDOW (f) != 0)
2428 error ("Cannot change the border width of a window");
2429
2430 f->output_data.w32->border_width = XINT (arg);
2431 }
2432
2433 void
2434 x_set_internal_border_width (f, arg, oldval)
2435 struct frame *f;
2436 Lisp_Object arg, oldval;
2437 {
2438 int old = f->output_data.w32->internal_border_width;
2439
2440 CHECK_NUMBER (arg, 0);
2441 f->output_data.w32->internal_border_width = XINT (arg);
2442 if (f->output_data.w32->internal_border_width < 0)
2443 f->output_data.w32->internal_border_width = 0;
2444
2445 if (f->output_data.w32->internal_border_width == old)
2446 return;
2447
2448 if (FRAME_W32_WINDOW (f) != 0)
2449 {
2450 x_set_window_size (f, 0, f->width, f->height);
2451 SET_FRAME_GARBAGED (f);
2452 do_pending_window_change (0);
2453 }
2454 }
2455
2456 void
2457 x_set_visibility (f, value, oldval)
2458 struct frame *f;
2459 Lisp_Object value, oldval;
2460 {
2461 Lisp_Object frame;
2462 XSETFRAME (frame, f);
2463
2464 if (NILP (value))
2465 Fmake_frame_invisible (frame, Qt);
2466 else if (EQ (value, Qicon))
2467 Ficonify_frame (frame);
2468 else
2469 Fmake_frame_visible (frame);
2470 }
2471
2472 void
2473 x_set_menu_bar_lines (f, value, oldval)
2474 struct frame *f;
2475 Lisp_Object value, oldval;
2476 {
2477 int nlines;
2478 int olines = FRAME_MENU_BAR_LINES (f);
2479
2480 /* Right now, menu bars don't work properly in minibuf-only frames;
2481 most of the commands try to apply themselves to the minibuffer
2482 frame itself, and get an error because you can't switch buffers
2483 in or split the minibuffer window. */
2484 if (FRAME_MINIBUF_ONLY_P (f))
2485 return;
2486
2487 if (INTEGERP (value))
2488 nlines = XINT (value);
2489 else
2490 nlines = 0;
2491
2492 FRAME_MENU_BAR_LINES (f) = 0;
2493 if (nlines)
2494 FRAME_EXTERNAL_MENU_BAR (f) = 1;
2495 else
2496 {
2497 if (FRAME_EXTERNAL_MENU_BAR (f) == 1)
2498 free_frame_menubar (f);
2499 FRAME_EXTERNAL_MENU_BAR (f) = 0;
2500
2501 /* Adjust the frame size so that the client (text) dimensions
2502 remain the same. This depends on FRAME_EXTERNAL_MENU_BAR being
2503 set correctly. */
2504 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2505 do_pending_window_change (0);
2506 }
2507 adjust_glyphs (f);
2508 }
2509
2510
2511 /* Set the number of lines used for the tool bar of frame F to VALUE.
2512 VALUE not an integer, or < 0 means set the lines to zero. OLDVAL
2513 is the old number of tool bar lines. This function changes the
2514 height of all windows on frame F to match the new tool bar height.
2515 The frame's height doesn't change. */
2516
2517 void
2518 x_set_tool_bar_lines (f, value, oldval)
2519 struct frame *f;
2520 Lisp_Object value, oldval;
2521 {
2522 int delta, nlines;
2523
2524 /* Use VALUE only if an integer >= 0. */
2525 if (INTEGERP (value) && XINT (value) >= 0)
2526 nlines = XFASTINT (value);
2527 else
2528 nlines = 0;
2529
2530 /* Make sure we redisplay all windows in this frame. */
2531 ++windows_or_buffers_changed;
2532
2533 delta = nlines - FRAME_TOOL_BAR_LINES (f);
2534 FRAME_TOOL_BAR_LINES (f) = nlines;
2535 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2536 do_pending_window_change (0);
2537 adjust_glyphs (f);
2538 }
2539
2540
2541 /* Change the name of frame F to NAME. If NAME is nil, set F's name to
2542 w32_id_name.
2543
2544 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2545 name; if NAME is a string, set F's name to NAME and set
2546 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2547
2548 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2549 suggesting a new name, which lisp code should override; if
2550 F->explicit_name is set, ignore the new name; otherwise, set it. */
2551
2552 void
2553 x_set_name (f, name, explicit)
2554 struct frame *f;
2555 Lisp_Object name;
2556 int explicit;
2557 {
2558 /* Make sure that requests from lisp code override requests from
2559 Emacs redisplay code. */
2560 if (explicit)
2561 {
2562 /* If we're switching from explicit to implicit, we had better
2563 update the mode lines and thereby update the title. */
2564 if (f->explicit_name && NILP (name))
2565 update_mode_lines = 1;
2566
2567 f->explicit_name = ! NILP (name);
2568 }
2569 else if (f->explicit_name)
2570 return;
2571
2572 /* If NAME is nil, set the name to the w32_id_name. */
2573 if (NILP (name))
2574 {
2575 /* Check for no change needed in this very common case
2576 before we do any consing. */
2577 if (!strcmp (FRAME_W32_DISPLAY_INFO (f)->w32_id_name,
2578 XSTRING (f->name)->data))
2579 return;
2580 name = build_string (FRAME_W32_DISPLAY_INFO (f)->w32_id_name);
2581 }
2582 else
2583 CHECK_STRING (name, 0);
2584
2585 /* Don't change the name if it's already NAME. */
2586 if (! NILP (Fstring_equal (name, f->name)))
2587 return;
2588
2589 f->name = name;
2590
2591 /* For setting the frame title, the title parameter should override
2592 the name parameter. */
2593 if (! NILP (f->title))
2594 name = f->title;
2595
2596 if (FRAME_W32_WINDOW (f))
2597 {
2598 if (STRING_MULTIBYTE (name))
2599 name = ENCODE_SYSTEM (name);
2600
2601 BLOCK_INPUT;
2602 SetWindowText(FRAME_W32_WINDOW (f), XSTRING (name)->data);
2603 UNBLOCK_INPUT;
2604 }
2605 }
2606
2607 /* This function should be called when the user's lisp code has
2608 specified a name for the frame; the name will override any set by the
2609 redisplay code. */
2610 void
2611 x_explicitly_set_name (f, arg, oldval)
2612 FRAME_PTR f;
2613 Lisp_Object arg, oldval;
2614 {
2615 x_set_name (f, arg, 1);
2616 }
2617
2618 /* This function should be called by Emacs redisplay code to set the
2619 name; names set this way will never override names set by the user's
2620 lisp code. */
2621 void
2622 x_implicitly_set_name (f, arg, oldval)
2623 FRAME_PTR f;
2624 Lisp_Object arg, oldval;
2625 {
2626 x_set_name (f, arg, 0);
2627 }
2628 \f
2629 /* Change the title of frame F to NAME.
2630 If NAME is nil, use the frame name as the title.
2631
2632 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2633 name; if NAME is a string, set F's name to NAME and set
2634 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2635
2636 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2637 suggesting a new name, which lisp code should override; if
2638 F->explicit_name is set, ignore the new name; otherwise, set it. */
2639
2640 void
2641 x_set_title (f, name, old_name)
2642 struct frame *f;
2643 Lisp_Object name, old_name;
2644 {
2645 /* Don't change the title if it's already NAME. */
2646 if (EQ (name, f->title))
2647 return;
2648
2649 update_mode_lines = 1;
2650
2651 f->title = name;
2652
2653 if (NILP (name))
2654 name = f->name;
2655
2656 if (FRAME_W32_WINDOW (f))
2657 {
2658 if (STRING_MULTIBYTE (name))
2659 name = ENCODE_SYSTEM (name);
2660
2661 BLOCK_INPUT;
2662 SetWindowText(FRAME_W32_WINDOW (f), XSTRING (name)->data);
2663 UNBLOCK_INPUT;
2664 }
2665 }
2666 \f
2667 void
2668 x_set_autoraise (f, arg, oldval)
2669 struct frame *f;
2670 Lisp_Object arg, oldval;
2671 {
2672 f->auto_raise = !EQ (Qnil, arg);
2673 }
2674
2675 void
2676 x_set_autolower (f, arg, oldval)
2677 struct frame *f;
2678 Lisp_Object arg, oldval;
2679 {
2680 f->auto_lower = !EQ (Qnil, arg);
2681 }
2682
2683 void
2684 x_set_unsplittable (f, arg, oldval)
2685 struct frame *f;
2686 Lisp_Object arg, oldval;
2687 {
2688 f->no_split = !NILP (arg);
2689 }
2690
2691 void
2692 x_set_vertical_scroll_bars (f, arg, oldval)
2693 struct frame *f;
2694 Lisp_Object arg, oldval;
2695 {
2696 if ((EQ (arg, Qleft) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
2697 || (EQ (arg, Qright) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
2698 || (NILP (arg) && FRAME_HAS_VERTICAL_SCROLL_BARS (f))
2699 || (!NILP (arg) && ! FRAME_HAS_VERTICAL_SCROLL_BARS (f)))
2700 {
2701 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = NILP (arg) ?
2702 vertical_scroll_bar_none :
2703 /* Put scroll bars on the right by default, as is conventional
2704 on MS-Windows. */
2705 EQ (Qleft, arg)
2706 ? vertical_scroll_bar_left
2707 : vertical_scroll_bar_right;
2708
2709 /* We set this parameter before creating the window for the
2710 frame, so we can get the geometry right from the start.
2711 However, if the window hasn't been created yet, we shouldn't
2712 call x_set_window_size. */
2713 if (FRAME_W32_WINDOW (f))
2714 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2715 do_pending_window_change (0);
2716 }
2717 }
2718
2719 void
2720 x_set_scroll_bar_width (f, arg, oldval)
2721 struct frame *f;
2722 Lisp_Object arg, oldval;
2723 {
2724 int wid = FONT_WIDTH (f->output_data.w32->font);
2725
2726 if (NILP (arg))
2727 {
2728 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = GetSystemMetrics (SM_CXVSCROLL);
2729 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) +
2730 wid - 1) / wid;
2731 if (FRAME_W32_WINDOW (f))
2732 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2733 do_pending_window_change (0);
2734 }
2735 else if (INTEGERP (arg) && XINT (arg) > 0
2736 && XFASTINT (arg) != FRAME_SCROLL_BAR_PIXEL_WIDTH (f))
2737 {
2738 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = XFASTINT (arg);
2739 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
2740 + wid-1) / wid;
2741 if (FRAME_W32_WINDOW (f))
2742 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2743 do_pending_window_change (0);
2744 }
2745 change_frame_size (f, 0, FRAME_WIDTH (f), 0, 0, 0);
2746 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.hpos = 0;
2747 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.x = 0;
2748 }
2749 \f
2750 /* Subroutines of creating an frame. */
2751
2752 /* Make sure that Vx_resource_name is set to a reasonable value.
2753 Fix it up, or set it to `emacs' if it is too hopeless. */
2754
2755 static void
2756 validate_x_resource_name ()
2757 {
2758 int len = 0;
2759 /* Number of valid characters in the resource name. */
2760 int good_count = 0;
2761 /* Number of invalid characters in the resource name. */
2762 int bad_count = 0;
2763 Lisp_Object new;
2764 int i;
2765
2766 if (STRINGP (Vx_resource_name))
2767 {
2768 unsigned char *p = XSTRING (Vx_resource_name)->data;
2769 int i;
2770
2771 len = STRING_BYTES (XSTRING (Vx_resource_name));
2772
2773 /* Only letters, digits, - and _ are valid in resource names.
2774 Count the valid characters and count the invalid ones. */
2775 for (i = 0; i < len; i++)
2776 {
2777 int c = p[i];
2778 if (! ((c >= 'a' && c <= 'z')
2779 || (c >= 'A' && c <= 'Z')
2780 || (c >= '0' && c <= '9')
2781 || c == '-' || c == '_'))
2782 bad_count++;
2783 else
2784 good_count++;
2785 }
2786 }
2787 else
2788 /* Not a string => completely invalid. */
2789 bad_count = 5, good_count = 0;
2790
2791 /* If name is valid already, return. */
2792 if (bad_count == 0)
2793 return;
2794
2795 /* If name is entirely invalid, or nearly so, use `emacs'. */
2796 if (good_count == 0
2797 || (good_count == 1 && bad_count > 0))
2798 {
2799 Vx_resource_name = build_string ("emacs");
2800 return;
2801 }
2802
2803 /* Name is partly valid. Copy it and replace the invalid characters
2804 with underscores. */
2805
2806 Vx_resource_name = new = Fcopy_sequence (Vx_resource_name);
2807
2808 for (i = 0; i < len; i++)
2809 {
2810 int c = XSTRING (new)->data[i];
2811 if (! ((c >= 'a' && c <= 'z')
2812 || (c >= 'A' && c <= 'Z')
2813 || (c >= '0' && c <= '9')
2814 || c == '-' || c == '_'))
2815 XSTRING (new)->data[i] = '_';
2816 }
2817 }
2818
2819
2820 extern char *x_get_string_resource ();
2821
2822 DEFUN ("x-get-resource", Fx_get_resource, Sx_get_resource, 2, 4, 0,
2823 "Return the value of ATTRIBUTE, of class CLASS, from the X defaults database.\n\
2824 This uses `INSTANCE.ATTRIBUTE' as the key and `Emacs.CLASS' as the\n\
2825 class, where INSTANCE is the name under which Emacs was invoked, or\n\
2826 the name specified by the `-name' or `-rn' command-line arguments.\n\
2827 \n\
2828 The optional arguments COMPONENT and SUBCLASS add to the key and the\n\
2829 class, respectively. You must specify both of them or neither.\n\
2830 If you specify them, the key is `INSTANCE.COMPONENT.ATTRIBUTE'\n\
2831 and the class is `Emacs.CLASS.SUBCLASS'.")
2832 (attribute, class, component, subclass)
2833 Lisp_Object attribute, class, component, subclass;
2834 {
2835 register char *value;
2836 char *name_key;
2837 char *class_key;
2838
2839 CHECK_STRING (attribute, 0);
2840 CHECK_STRING (class, 0);
2841
2842 if (!NILP (component))
2843 CHECK_STRING (component, 1);
2844 if (!NILP (subclass))
2845 CHECK_STRING (subclass, 2);
2846 if (NILP (component) != NILP (subclass))
2847 error ("x-get-resource: must specify both COMPONENT and SUBCLASS or neither");
2848
2849 validate_x_resource_name ();
2850
2851 /* Allocate space for the components, the dots which separate them,
2852 and the final '\0'. Make them big enough for the worst case. */
2853 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vx_resource_name))
2854 + (STRINGP (component)
2855 ? STRING_BYTES (XSTRING (component)) : 0)
2856 + STRING_BYTES (XSTRING (attribute))
2857 + 3);
2858
2859 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
2860 + STRING_BYTES (XSTRING (class))
2861 + (STRINGP (subclass)
2862 ? STRING_BYTES (XSTRING (subclass)) : 0)
2863 + 3);
2864
2865 /* Start with emacs.FRAMENAME for the name (the specific one)
2866 and with `Emacs' for the class key (the general one). */
2867 strcpy (name_key, XSTRING (Vx_resource_name)->data);
2868 strcpy (class_key, EMACS_CLASS);
2869
2870 strcat (class_key, ".");
2871 strcat (class_key, XSTRING (class)->data);
2872
2873 if (!NILP (component))
2874 {
2875 strcat (class_key, ".");
2876 strcat (class_key, XSTRING (subclass)->data);
2877
2878 strcat (name_key, ".");
2879 strcat (name_key, XSTRING (component)->data);
2880 }
2881
2882 strcat (name_key, ".");
2883 strcat (name_key, XSTRING (attribute)->data);
2884
2885 value = x_get_string_resource (Qnil,
2886 name_key, class_key);
2887
2888 if (value != (char *) 0)
2889 return build_string (value);
2890 else
2891 return Qnil;
2892 }
2893
2894 /* Used when C code wants a resource value. */
2895
2896 char *
2897 x_get_resource_string (attribute, class)
2898 char *attribute, *class;
2899 {
2900 char *name_key;
2901 char *class_key;
2902 struct frame *sf = SELECTED_FRAME ();
2903
2904 /* Allocate space for the components, the dots which separate them,
2905 and the final '\0'. */
2906 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vinvocation_name))
2907 + strlen (attribute) + 2);
2908 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
2909 + strlen (class) + 2);
2910
2911 sprintf (name_key, "%s.%s",
2912 XSTRING (Vinvocation_name)->data,
2913 attribute);
2914 sprintf (class_key, "%s.%s", EMACS_CLASS, class);
2915
2916 return x_get_string_resource (sf, name_key, class_key);
2917 }
2918
2919 /* Types we might convert a resource string into. */
2920 enum resource_types
2921 {
2922 RES_TYPE_NUMBER,
2923 RES_TYPE_FLOAT,
2924 RES_TYPE_BOOLEAN,
2925 RES_TYPE_STRING,
2926 RES_TYPE_SYMBOL
2927 };
2928
2929 /* Return the value of parameter PARAM.
2930
2931 First search ALIST, then Vdefault_frame_alist, then the X defaults
2932 database, using ATTRIBUTE as the attribute name and CLASS as its class.
2933
2934 Convert the resource to the type specified by desired_type.
2935
2936 If no default is specified, return Qunbound. If you call
2937 w32_get_arg, make sure you deal with Qunbound in a reasonable way,
2938 and don't let it get stored in any Lisp-visible variables! */
2939
2940 static Lisp_Object
2941 w32_get_arg (alist, param, attribute, class, type)
2942 Lisp_Object alist, param;
2943 char *attribute;
2944 char *class;
2945 enum resource_types type;
2946 {
2947 register Lisp_Object tem;
2948
2949 tem = Fassq (param, alist);
2950 if (EQ (tem, Qnil))
2951 tem = Fassq (param, Vdefault_frame_alist);
2952 if (EQ (tem, Qnil))
2953 {
2954
2955 if (attribute)
2956 {
2957 tem = Fx_get_resource (build_string (attribute),
2958 build_string (class),
2959 Qnil, Qnil);
2960
2961 if (NILP (tem))
2962 return Qunbound;
2963
2964 switch (type)
2965 {
2966 case RES_TYPE_NUMBER:
2967 return make_number (atoi (XSTRING (tem)->data));
2968
2969 case RES_TYPE_FLOAT:
2970 return make_float (atof (XSTRING (tem)->data));
2971
2972 case RES_TYPE_BOOLEAN:
2973 tem = Fdowncase (tem);
2974 if (!strcmp (XSTRING (tem)->data, "on")
2975 || !strcmp (XSTRING (tem)->data, "true"))
2976 return Qt;
2977 else
2978 return Qnil;
2979
2980 case RES_TYPE_STRING:
2981 return tem;
2982
2983 case RES_TYPE_SYMBOL:
2984 /* As a special case, we map the values `true' and `on'
2985 to Qt, and `false' and `off' to Qnil. */
2986 {
2987 Lisp_Object lower;
2988 lower = Fdowncase (tem);
2989 if (!strcmp (XSTRING (lower)->data, "on")
2990 || !strcmp (XSTRING (lower)->data, "true"))
2991 return Qt;
2992 else if (!strcmp (XSTRING (lower)->data, "off")
2993 || !strcmp (XSTRING (lower)->data, "false"))
2994 return Qnil;
2995 else
2996 return Fintern (tem, Qnil);
2997 }
2998
2999 default:
3000 abort ();
3001 }
3002 }
3003 else
3004 return Qunbound;
3005 }
3006 return Fcdr (tem);
3007 }
3008
3009 /* Record in frame F the specified or default value according to ALIST
3010 of the parameter named PROP (a Lisp symbol).
3011 If no value is specified for PROP, look for an X default for XPROP
3012 on the frame named NAME.
3013 If that is not found either, use the value DEFLT. */
3014
3015 static Lisp_Object
3016 x_default_parameter (f, alist, prop, deflt, xprop, xclass, type)
3017 struct frame *f;
3018 Lisp_Object alist;
3019 Lisp_Object prop;
3020 Lisp_Object deflt;
3021 char *xprop;
3022 char *xclass;
3023 enum resource_types type;
3024 {
3025 Lisp_Object tem;
3026
3027 tem = w32_get_arg (alist, prop, xprop, xclass, type);
3028 if (EQ (tem, Qunbound))
3029 tem = deflt;
3030 x_set_frame_parameters (f, Fcons (Fcons (prop, tem), Qnil));
3031 return tem;
3032 }
3033 \f
3034 DEFUN ("x-parse-geometry", Fx_parse_geometry, Sx_parse_geometry, 1, 1, 0,
3035 "Parse an X-style geometry string STRING.\n\
3036 Returns an alist of the form ((top . TOP), (left . LEFT) ... ).\n\
3037 The properties returned may include `top', `left', `height', and `width'.\n\
3038 The value of `left' or `top' may be an integer,\n\
3039 or a list (+ N) meaning N pixels relative to top/left corner,\n\
3040 or a list (- N) meaning -N pixels relative to bottom/right corner.")
3041 (string)
3042 Lisp_Object string;
3043 {
3044 int geometry, x, y;
3045 unsigned int width, height;
3046 Lisp_Object result;
3047
3048 CHECK_STRING (string, 0);
3049
3050 geometry = XParseGeometry ((char *) XSTRING (string)->data,
3051 &x, &y, &width, &height);
3052
3053 result = Qnil;
3054 if (geometry & XValue)
3055 {
3056 Lisp_Object element;
3057
3058 if (x >= 0 && (geometry & XNegative))
3059 element = Fcons (Qleft, Fcons (Qminus, Fcons (make_number (-x), Qnil)));
3060 else if (x < 0 && ! (geometry & XNegative))
3061 element = Fcons (Qleft, Fcons (Qplus, Fcons (make_number (x), Qnil)));
3062 else
3063 element = Fcons (Qleft, make_number (x));
3064 result = Fcons (element, result);
3065 }
3066
3067 if (geometry & YValue)
3068 {
3069 Lisp_Object element;
3070
3071 if (y >= 0 && (geometry & YNegative))
3072 element = Fcons (Qtop, Fcons (Qminus, Fcons (make_number (-y), Qnil)));
3073 else if (y < 0 && ! (geometry & YNegative))
3074 element = Fcons (Qtop, Fcons (Qplus, Fcons (make_number (y), Qnil)));
3075 else
3076 element = Fcons (Qtop, make_number (y));
3077 result = Fcons (element, result);
3078 }
3079
3080 if (geometry & WidthValue)
3081 result = Fcons (Fcons (Qwidth, make_number (width)), result);
3082 if (geometry & HeightValue)
3083 result = Fcons (Fcons (Qheight, make_number (height)), result);
3084
3085 return result;
3086 }
3087
3088 /* Calculate the desired size and position of this window,
3089 and return the flags saying which aspects were specified.
3090
3091 This function does not make the coordinates positive. */
3092
3093 #define DEFAULT_ROWS 40
3094 #define DEFAULT_COLS 80
3095
3096 static int
3097 x_figure_window_size (f, parms)
3098 struct frame *f;
3099 Lisp_Object parms;
3100 {
3101 register Lisp_Object tem0, tem1, tem2;
3102 long window_prompting = 0;
3103
3104 /* Default values if we fall through.
3105 Actually, if that happens we should get
3106 window manager prompting. */
3107 SET_FRAME_WIDTH (f, DEFAULT_COLS);
3108 f->height = DEFAULT_ROWS;
3109 /* Window managers expect that if program-specified
3110 positions are not (0,0), they're intentional, not defaults. */
3111 f->output_data.w32->top_pos = 0;
3112 f->output_data.w32->left_pos = 0;
3113
3114 tem0 = w32_get_arg (parms, Qheight, 0, 0, RES_TYPE_NUMBER);
3115 tem1 = w32_get_arg (parms, Qwidth, 0, 0, RES_TYPE_NUMBER);
3116 tem2 = w32_get_arg (parms, Quser_size, 0, 0, RES_TYPE_NUMBER);
3117 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3118 {
3119 if (!EQ (tem0, Qunbound))
3120 {
3121 CHECK_NUMBER (tem0, 0);
3122 f->height = XINT (tem0);
3123 }
3124 if (!EQ (tem1, Qunbound))
3125 {
3126 CHECK_NUMBER (tem1, 0);
3127 SET_FRAME_WIDTH (f, XINT (tem1));
3128 }
3129 if (!NILP (tem2) && !EQ (tem2, Qunbound))
3130 window_prompting |= USSize;
3131 else
3132 window_prompting |= PSize;
3133 }
3134
3135 f->output_data.w32->vertical_scroll_bar_extra
3136 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
3137 ? 0
3138 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
3139 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
3140 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.w32->font)));
3141 f->output_data.w32->flags_areas_extra
3142 = FRAME_FLAGS_AREA_WIDTH (f);
3143 f->output_data.w32->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
3144 f->output_data.w32->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
3145
3146 tem0 = w32_get_arg (parms, Qtop, 0, 0, RES_TYPE_NUMBER);
3147 tem1 = w32_get_arg (parms, Qleft, 0, 0, RES_TYPE_NUMBER);
3148 tem2 = w32_get_arg (parms, Quser_position, 0, 0, RES_TYPE_NUMBER);
3149 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3150 {
3151 if (EQ (tem0, Qminus))
3152 {
3153 f->output_data.w32->top_pos = 0;
3154 window_prompting |= YNegative;
3155 }
3156 else if (CONSP (tem0) && EQ (XCAR (tem0), Qminus)
3157 && CONSP (XCDR (tem0))
3158 && INTEGERP (XCAR (XCDR (tem0))))
3159 {
3160 f->output_data.w32->top_pos = - XINT (XCAR (XCDR (tem0)));
3161 window_prompting |= YNegative;
3162 }
3163 else if (CONSP (tem0) && EQ (XCAR (tem0), Qplus)
3164 && CONSP (XCDR (tem0))
3165 && INTEGERP (XCAR (XCDR (tem0))))
3166 {
3167 f->output_data.w32->top_pos = XINT (XCAR (XCDR (tem0)));
3168 }
3169 else if (EQ (tem0, Qunbound))
3170 f->output_data.w32->top_pos = 0;
3171 else
3172 {
3173 CHECK_NUMBER (tem0, 0);
3174 f->output_data.w32->top_pos = XINT (tem0);
3175 if (f->output_data.w32->top_pos < 0)
3176 window_prompting |= YNegative;
3177 }
3178
3179 if (EQ (tem1, Qminus))
3180 {
3181 f->output_data.w32->left_pos = 0;
3182 window_prompting |= XNegative;
3183 }
3184 else if (CONSP (tem1) && EQ (XCAR (tem1), Qminus)
3185 && CONSP (XCDR (tem1))
3186 && INTEGERP (XCAR (XCDR (tem1))))
3187 {
3188 f->output_data.w32->left_pos = - XINT (XCAR (XCDR (tem1)));
3189 window_prompting |= XNegative;
3190 }
3191 else if (CONSP (tem1) && EQ (XCAR (tem1), Qplus)
3192 && CONSP (XCDR (tem1))
3193 && INTEGERP (XCAR (XCDR (tem1))))
3194 {
3195 f->output_data.w32->left_pos = XINT (XCAR (XCDR (tem1)));
3196 }
3197 else if (EQ (tem1, Qunbound))
3198 f->output_data.w32->left_pos = 0;
3199 else
3200 {
3201 CHECK_NUMBER (tem1, 0);
3202 f->output_data.w32->left_pos = XINT (tem1);
3203 if (f->output_data.w32->left_pos < 0)
3204 window_prompting |= XNegative;
3205 }
3206
3207 if (!NILP (tem2) && ! EQ (tem2, Qunbound))
3208 window_prompting |= USPosition;
3209 else
3210 window_prompting |= PPosition;
3211 }
3212
3213 return window_prompting;
3214 }
3215
3216 \f
3217
3218 extern LRESULT CALLBACK w32_wnd_proc ();
3219
3220 BOOL
3221 w32_init_class (hinst)
3222 HINSTANCE hinst;
3223 {
3224 WNDCLASS wc;
3225
3226 wc.style = CS_HREDRAW | CS_VREDRAW;
3227 wc.lpfnWndProc = (WNDPROC) w32_wnd_proc;
3228 wc.cbClsExtra = 0;
3229 wc.cbWndExtra = WND_EXTRA_BYTES;
3230 wc.hInstance = hinst;
3231 wc.hIcon = LoadIcon (hinst, EMACS_CLASS);
3232 wc.hCursor = LoadCursor (NULL, IDC_ARROW);
3233 wc.hbrBackground = NULL; /* GetStockObject (WHITE_BRUSH); */
3234 wc.lpszMenuName = NULL;
3235 wc.lpszClassName = EMACS_CLASS;
3236
3237 return (RegisterClass (&wc));
3238 }
3239
3240 HWND
3241 w32_createscrollbar (f, bar)
3242 struct frame *f;
3243 struct scroll_bar * bar;
3244 {
3245 return (CreateWindow ("SCROLLBAR", "", SBS_VERT | WS_CHILD | WS_VISIBLE,
3246 /* Position and size of scroll bar. */
3247 XINT(bar->left) + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
3248 XINT(bar->top),
3249 XINT(bar->width) - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
3250 XINT(bar->height),
3251 FRAME_W32_WINDOW (f),
3252 NULL,
3253 hinst,
3254 NULL));
3255 }
3256
3257 void
3258 w32_createwindow (f)
3259 struct frame *f;
3260 {
3261 HWND hwnd;
3262 RECT rect;
3263
3264 rect.left = rect.top = 0;
3265 rect.right = PIXEL_WIDTH (f);
3266 rect.bottom = PIXEL_HEIGHT (f);
3267
3268 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
3269 FRAME_EXTERNAL_MENU_BAR (f));
3270
3271 /* Do first time app init */
3272
3273 if (!hprevinst)
3274 {
3275 w32_init_class (hinst);
3276 }
3277
3278 FRAME_W32_WINDOW (f) = hwnd
3279 = CreateWindow (EMACS_CLASS,
3280 f->namebuf,
3281 f->output_data.w32->dwStyle | WS_CLIPCHILDREN,
3282 f->output_data.w32->left_pos,
3283 f->output_data.w32->top_pos,
3284 rect.right - rect.left,
3285 rect.bottom - rect.top,
3286 NULL,
3287 NULL,
3288 hinst,
3289 NULL);
3290
3291 if (hwnd)
3292 {
3293 SetWindowLong (hwnd, WND_FONTWIDTH_INDEX, FONT_WIDTH (f->output_data.w32->font));
3294 SetWindowLong (hwnd, WND_LINEHEIGHT_INDEX, f->output_data.w32->line_height);
3295 SetWindowLong (hwnd, WND_BORDER_INDEX, f->output_data.w32->internal_border_width);
3296 SetWindowLong (hwnd, WND_SCROLLBAR_INDEX, f->output_data.w32->vertical_scroll_bar_extra);
3297 SetWindowLong (hwnd, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f));
3298
3299 /* Enable drag-n-drop. */
3300 DragAcceptFiles (hwnd, TRUE);
3301
3302 /* Do this to discard the default setting specified by our parent. */
3303 ShowWindow (hwnd, SW_HIDE);
3304 }
3305 }
3306
3307 void
3308 my_post_msg (wmsg, hwnd, msg, wParam, lParam)
3309 W32Msg * wmsg;
3310 HWND hwnd;
3311 UINT msg;
3312 WPARAM wParam;
3313 LPARAM lParam;
3314 {
3315 wmsg->msg.hwnd = hwnd;
3316 wmsg->msg.message = msg;
3317 wmsg->msg.wParam = wParam;
3318 wmsg->msg.lParam = lParam;
3319 wmsg->msg.time = GetMessageTime ();
3320
3321 post_msg (wmsg);
3322 }
3323
3324 /* GetKeyState and MapVirtualKey on Windows 95 do not actually distinguish
3325 between left and right keys as advertised. We test for this
3326 support dynamically, and set a flag when the support is absent. If
3327 absent, we keep track of the left and right control and alt keys
3328 ourselves. This is particularly necessary on keyboards that rely
3329 upon the AltGr key, which is represented as having the left control
3330 and right alt keys pressed. For these keyboards, we need to know
3331 when the left alt key has been pressed in addition to the AltGr key
3332 so that we can properly support M-AltGr-key sequences (such as M-@
3333 on Swedish keyboards). */
3334
3335 #define EMACS_LCONTROL 0
3336 #define EMACS_RCONTROL 1
3337 #define EMACS_LMENU 2
3338 #define EMACS_RMENU 3
3339
3340 static int modifiers[4];
3341 static int modifiers_recorded;
3342 static int modifier_key_support_tested;
3343
3344 static void
3345 test_modifier_support (unsigned int wparam)
3346 {
3347 unsigned int l, r;
3348
3349 if (wparam != VK_CONTROL && wparam != VK_MENU)
3350 return;
3351 if (wparam == VK_CONTROL)
3352 {
3353 l = VK_LCONTROL;
3354 r = VK_RCONTROL;
3355 }
3356 else
3357 {
3358 l = VK_LMENU;
3359 r = VK_RMENU;
3360 }
3361 if (!(GetKeyState (l) & 0x8000) && !(GetKeyState (r) & 0x8000))
3362 modifiers_recorded = 1;
3363 else
3364 modifiers_recorded = 0;
3365 modifier_key_support_tested = 1;
3366 }
3367
3368 static void
3369 record_keydown (unsigned int wparam, unsigned int lparam)
3370 {
3371 int i;
3372
3373 if (!modifier_key_support_tested)
3374 test_modifier_support (wparam);
3375
3376 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3377 return;
3378
3379 if (wparam == VK_CONTROL)
3380 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3381 else
3382 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3383
3384 modifiers[i] = 1;
3385 }
3386
3387 static void
3388 record_keyup (unsigned int wparam, unsigned int lparam)
3389 {
3390 int i;
3391
3392 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3393 return;
3394
3395 if (wparam == VK_CONTROL)
3396 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3397 else
3398 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3399
3400 modifiers[i] = 0;
3401 }
3402
3403 /* Emacs can lose focus while a modifier key has been pressed. When
3404 it regains focus, be conservative and clear all modifiers since
3405 we cannot reconstruct the left and right modifier state. */
3406 static void
3407 reset_modifiers ()
3408 {
3409 SHORT ctrl, alt;
3410
3411 if (GetFocus () == NULL)
3412 /* Emacs doesn't have keyboard focus. Do nothing. */
3413 return;
3414
3415 ctrl = GetAsyncKeyState (VK_CONTROL);
3416 alt = GetAsyncKeyState (VK_MENU);
3417
3418 if (!(ctrl & 0x08000))
3419 /* Clear any recorded control modifier state. */
3420 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3421
3422 if (!(alt & 0x08000))
3423 /* Clear any recorded alt modifier state. */
3424 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3425
3426 /* Update the state of all modifier keys, because modifiers used in
3427 hot-key combinations can get stuck on if Emacs loses focus as a
3428 result of a hot-key being pressed. */
3429 {
3430 BYTE keystate[256];
3431
3432 #define CURRENT_STATE(key) ((GetAsyncKeyState (key) & 0x8000) >> 8)
3433
3434 GetKeyboardState (keystate);
3435 keystate[VK_SHIFT] = CURRENT_STATE (VK_SHIFT);
3436 keystate[VK_CONTROL] = CURRENT_STATE (VK_CONTROL);
3437 keystate[VK_LCONTROL] = CURRENT_STATE (VK_LCONTROL);
3438 keystate[VK_RCONTROL] = CURRENT_STATE (VK_RCONTROL);
3439 keystate[VK_MENU] = CURRENT_STATE (VK_MENU);
3440 keystate[VK_LMENU] = CURRENT_STATE (VK_LMENU);
3441 keystate[VK_RMENU] = CURRENT_STATE (VK_RMENU);
3442 keystate[VK_LWIN] = CURRENT_STATE (VK_LWIN);
3443 keystate[VK_RWIN] = CURRENT_STATE (VK_RWIN);
3444 keystate[VK_APPS] = CURRENT_STATE (VK_APPS);
3445 SetKeyboardState (keystate);
3446 }
3447 }
3448
3449 /* Synchronize modifier state with what is reported with the current
3450 keystroke. Even if we cannot distinguish between left and right
3451 modifier keys, we know that, if no modifiers are set, then neither
3452 the left or right modifier should be set. */
3453 static void
3454 sync_modifiers ()
3455 {
3456 if (!modifiers_recorded)
3457 return;
3458
3459 if (!(GetKeyState (VK_CONTROL) & 0x8000))
3460 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3461
3462 if (!(GetKeyState (VK_MENU) & 0x8000))
3463 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3464 }
3465
3466 static int
3467 modifier_set (int vkey)
3468 {
3469 if (vkey == VK_CAPITAL || vkey == VK_SCROLL)
3470 return (GetKeyState (vkey) & 0x1);
3471 if (!modifiers_recorded)
3472 return (GetKeyState (vkey) & 0x8000);
3473
3474 switch (vkey)
3475 {
3476 case VK_LCONTROL:
3477 return modifiers[EMACS_LCONTROL];
3478 case VK_RCONTROL:
3479 return modifiers[EMACS_RCONTROL];
3480 case VK_LMENU:
3481 return modifiers[EMACS_LMENU];
3482 case VK_RMENU:
3483 return modifiers[EMACS_RMENU];
3484 }
3485 return (GetKeyState (vkey) & 0x8000);
3486 }
3487
3488 /* Convert between the modifier bits W32 uses and the modifier bits
3489 Emacs uses. */
3490
3491 unsigned int
3492 w32_key_to_modifier (int key)
3493 {
3494 Lisp_Object key_mapping;
3495
3496 switch (key)
3497 {
3498 case VK_LWIN:
3499 key_mapping = Vw32_lwindow_modifier;
3500 break;
3501 case VK_RWIN:
3502 key_mapping = Vw32_rwindow_modifier;
3503 break;
3504 case VK_APPS:
3505 key_mapping = Vw32_apps_modifier;
3506 break;
3507 case VK_SCROLL:
3508 key_mapping = Vw32_scroll_lock_modifier;
3509 break;
3510 default:
3511 key_mapping = Qnil;
3512 }
3513
3514 /* NB. This code runs in the input thread, asychronously to the lisp
3515 thread, so we must be careful to ensure access to lisp data is
3516 thread-safe. The following code is safe because the modifier
3517 variable values are updated atomically from lisp and symbols are
3518 not relocated by GC. Also, we don't have to worry about seeing GC
3519 markbits here. */
3520 if (EQ (key_mapping, Qhyper))
3521 return hyper_modifier;
3522 if (EQ (key_mapping, Qsuper))
3523 return super_modifier;
3524 if (EQ (key_mapping, Qmeta))
3525 return meta_modifier;
3526 if (EQ (key_mapping, Qalt))
3527 return alt_modifier;
3528 if (EQ (key_mapping, Qctrl))
3529 return ctrl_modifier;
3530 if (EQ (key_mapping, Qcontrol)) /* synonym for ctrl */
3531 return ctrl_modifier;
3532 if (EQ (key_mapping, Qshift))
3533 return shift_modifier;
3534
3535 /* Don't generate any modifier if not explicitly requested. */
3536 return 0;
3537 }
3538
3539 unsigned int
3540 w32_get_modifiers ()
3541 {
3542 return ((modifier_set (VK_SHIFT) ? shift_modifier : 0) |
3543 (modifier_set (VK_CONTROL) ? ctrl_modifier : 0) |
3544 (modifier_set (VK_LWIN) ? w32_key_to_modifier (VK_LWIN) : 0) |
3545 (modifier_set (VK_RWIN) ? w32_key_to_modifier (VK_RWIN) : 0) |
3546 (modifier_set (VK_APPS) ? w32_key_to_modifier (VK_APPS) : 0) |
3547 (modifier_set (VK_SCROLL) ? w32_key_to_modifier (VK_SCROLL) : 0) |
3548 (modifier_set (VK_MENU) ?
3549 ((NILP (Vw32_alt_is_meta)) ? alt_modifier : meta_modifier) : 0));
3550 }
3551
3552 /* We map the VK_* modifiers into console modifier constants
3553 so that we can use the same routines to handle both console
3554 and window input. */
3555
3556 static int
3557 construct_console_modifiers ()
3558 {
3559 int mods;
3560
3561 mods = 0;
3562 mods |= (modifier_set (VK_SHIFT)) ? SHIFT_PRESSED : 0;
3563 mods |= (modifier_set (VK_CAPITAL)) ? CAPSLOCK_ON : 0;
3564 mods |= (modifier_set (VK_SCROLL)) ? SCROLLLOCK_ON : 0;
3565 mods |= (modifier_set (VK_NUMLOCK)) ? NUMLOCK_ON : 0;
3566 mods |= (modifier_set (VK_LCONTROL)) ? LEFT_CTRL_PRESSED : 0;
3567 mods |= (modifier_set (VK_RCONTROL)) ? RIGHT_CTRL_PRESSED : 0;
3568 mods |= (modifier_set (VK_LMENU)) ? LEFT_ALT_PRESSED : 0;
3569 mods |= (modifier_set (VK_RMENU)) ? RIGHT_ALT_PRESSED : 0;
3570 mods |= (modifier_set (VK_LWIN)) ? LEFT_WIN_PRESSED : 0;
3571 mods |= (modifier_set (VK_RWIN)) ? RIGHT_WIN_PRESSED : 0;
3572 mods |= (modifier_set (VK_APPS)) ? APPS_PRESSED : 0;
3573
3574 return mods;
3575 }
3576
3577 static int
3578 w32_get_key_modifiers (unsigned int wparam, unsigned int lparam)
3579 {
3580 int mods;
3581
3582 /* Convert to emacs modifiers. */
3583 mods = w32_kbd_mods_to_emacs (construct_console_modifiers (), wparam);
3584
3585 return mods;
3586 }
3587
3588 unsigned int
3589 map_keypad_keys (unsigned int virt_key, unsigned int extended)
3590 {
3591 if (virt_key < VK_CLEAR || virt_key > VK_DELETE)
3592 return virt_key;
3593
3594 if (virt_key == VK_RETURN)
3595 return (extended ? VK_NUMPAD_ENTER : VK_RETURN);
3596
3597 if (virt_key >= VK_PRIOR && virt_key <= VK_DOWN)
3598 return (!extended ? (VK_NUMPAD_PRIOR + (virt_key - VK_PRIOR)) : virt_key);
3599
3600 if (virt_key == VK_INSERT || virt_key == VK_DELETE)
3601 return (!extended ? (VK_NUMPAD_INSERT + (virt_key - VK_INSERT)) : virt_key);
3602
3603 if (virt_key == VK_CLEAR)
3604 return (!extended ? VK_NUMPAD_CLEAR : virt_key);
3605
3606 return virt_key;
3607 }
3608
3609 /* List of special key combinations which w32 would normally capture,
3610 but emacs should grab instead. Not directly visible to lisp, to
3611 simplify synchronization. Each item is an integer encoding a virtual
3612 key code and modifier combination to capture. */
3613 Lisp_Object w32_grabbed_keys;
3614
3615 #define HOTKEY(vk,mods) make_number (((vk) & 255) | ((mods) << 8))
3616 #define HOTKEY_ID(k) (XFASTINT (k) & 0xbfff)
3617 #define HOTKEY_VK_CODE(k) (XFASTINT (k) & 255)
3618 #define HOTKEY_MODIFIERS(k) (XFASTINT (k) >> 8)
3619
3620 /* Register hot-keys for reserved key combinations when Emacs has
3621 keyboard focus, since this is the only way Emacs can receive key
3622 combinations like Alt-Tab which are used by the system. */
3623
3624 static void
3625 register_hot_keys (hwnd)
3626 HWND hwnd;
3627 {
3628 Lisp_Object keylist;
3629
3630 /* Use GC_CONSP, since we are called asynchronously. */
3631 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3632 {
3633 Lisp_Object key = XCAR (keylist);
3634
3635 /* Deleted entries get set to nil. */
3636 if (!INTEGERP (key))
3637 continue;
3638
3639 RegisterHotKey (hwnd, HOTKEY_ID (key),
3640 HOTKEY_MODIFIERS (key), HOTKEY_VK_CODE (key));
3641 }
3642 }
3643
3644 static void
3645 unregister_hot_keys (hwnd)
3646 HWND hwnd;
3647 {
3648 Lisp_Object keylist;
3649
3650 /* Use GC_CONSP, since we are called asynchronously. */
3651 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3652 {
3653 Lisp_Object key = XCAR (keylist);
3654
3655 if (!INTEGERP (key))
3656 continue;
3657
3658 UnregisterHotKey (hwnd, HOTKEY_ID (key));
3659 }
3660 }
3661
3662 /* Main message dispatch loop. */
3663
3664 static void
3665 w32_msg_pump (deferred_msg * msg_buf)
3666 {
3667 MSG msg;
3668 int result;
3669 HWND focus_window;
3670
3671 msh_mousewheel = RegisterWindowMessage (MSH_MOUSEWHEEL);
3672
3673 while (GetMessage (&msg, NULL, 0, 0))
3674 {
3675 if (msg.hwnd == NULL)
3676 {
3677 switch (msg.message)
3678 {
3679 case WM_NULL:
3680 /* Produced by complete_deferred_msg; just ignore. */
3681 break;
3682 case WM_EMACS_CREATEWINDOW:
3683 w32_createwindow ((struct frame *) msg.wParam);
3684 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3685 abort ();
3686 break;
3687 case WM_EMACS_SETLOCALE:
3688 SetThreadLocale (msg.wParam);
3689 /* Reply is not expected. */
3690 break;
3691 case WM_EMACS_SETKEYBOARDLAYOUT:
3692 result = (int) ActivateKeyboardLayout ((HKL) msg.wParam, 0);
3693 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
3694 result, 0))
3695 abort ();
3696 break;
3697 case WM_EMACS_REGISTER_HOT_KEY:
3698 focus_window = GetFocus ();
3699 if (focus_window != NULL)
3700 RegisterHotKey (focus_window,
3701 HOTKEY_ID (msg.wParam),
3702 HOTKEY_MODIFIERS (msg.wParam),
3703 HOTKEY_VK_CODE (msg.wParam));
3704 /* Reply is not expected. */
3705 break;
3706 case WM_EMACS_UNREGISTER_HOT_KEY:
3707 focus_window = GetFocus ();
3708 if (focus_window != NULL)
3709 UnregisterHotKey (focus_window, HOTKEY_ID (msg.wParam));
3710 /* Mark item as erased. NB: this code must be
3711 thread-safe. The next line is okay because the cons
3712 cell is never made into garbage and is not relocated by
3713 GC. */
3714 XCAR ((Lisp_Object) msg.lParam) = Qnil;
3715 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3716 abort ();
3717 break;
3718 case WM_EMACS_TOGGLE_LOCK_KEY:
3719 {
3720 int vk_code = (int) msg.wParam;
3721 int cur_state = (GetKeyState (vk_code) & 1);
3722 Lisp_Object new_state = (Lisp_Object) msg.lParam;
3723
3724 /* NB: This code must be thread-safe. It is safe to
3725 call NILP because symbols are not relocated by GC,
3726 and pointer here is not touched by GC (so the markbit
3727 can't be set). Numbers are safe because they are
3728 immediate values. */
3729 if (NILP (new_state)
3730 || (NUMBERP (new_state)
3731 && (XUINT (new_state)) & 1 != cur_state))
3732 {
3733 one_w32_display_info.faked_key = vk_code;
3734
3735 keybd_event ((BYTE) vk_code,
3736 (BYTE) MapVirtualKey (vk_code, 0),
3737 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3738 keybd_event ((BYTE) vk_code,
3739 (BYTE) MapVirtualKey (vk_code, 0),
3740 KEYEVENTF_EXTENDEDKEY | 0, 0);
3741 keybd_event ((BYTE) vk_code,
3742 (BYTE) MapVirtualKey (vk_code, 0),
3743 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3744 cur_state = !cur_state;
3745 }
3746 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
3747 cur_state, 0))
3748 abort ();
3749 }
3750 break;
3751 default:
3752 DebPrint (("msg %x not expected by w32_msg_pump\n", msg.message));
3753 }
3754 }
3755 else
3756 {
3757 DispatchMessage (&msg);
3758 }
3759
3760 /* Exit nested loop when our deferred message has completed. */
3761 if (msg_buf->completed)
3762 break;
3763 }
3764 }
3765
3766 deferred_msg * deferred_msg_head;
3767
3768 static deferred_msg *
3769 find_deferred_msg (HWND hwnd, UINT msg)
3770 {
3771 deferred_msg * item;
3772
3773 /* Don't actually need synchronization for read access, since
3774 modification of single pointer is always atomic. */
3775 /* enter_crit (); */
3776
3777 for (item = deferred_msg_head; item != NULL; item = item->next)
3778 if (item->w32msg.msg.hwnd == hwnd
3779 && item->w32msg.msg.message == msg)
3780 break;
3781
3782 /* leave_crit (); */
3783
3784 return item;
3785 }
3786
3787 static LRESULT
3788 send_deferred_msg (deferred_msg * msg_buf,
3789 HWND hwnd,
3790 UINT msg,
3791 WPARAM wParam,
3792 LPARAM lParam)
3793 {
3794 /* Only input thread can send deferred messages. */
3795 if (GetCurrentThreadId () != dwWindowsThreadId)
3796 abort ();
3797
3798 /* It is an error to send a message that is already deferred. */
3799 if (find_deferred_msg (hwnd, msg) != NULL)
3800 abort ();
3801
3802 /* Enforced synchronization is not needed because this is the only
3803 function that alters deferred_msg_head, and the following critical
3804 section is guaranteed to only be serially reentered (since only the
3805 input thread can call us). */
3806
3807 /* enter_crit (); */
3808
3809 msg_buf->completed = 0;
3810 msg_buf->next = deferred_msg_head;
3811 deferred_msg_head = msg_buf;
3812 my_post_msg (&msg_buf->w32msg, hwnd, msg, wParam, lParam);
3813
3814 /* leave_crit (); */
3815
3816 /* Start a new nested message loop to process other messages until
3817 this one is completed. */
3818 w32_msg_pump (msg_buf);
3819
3820 deferred_msg_head = msg_buf->next;
3821
3822 return msg_buf->result;
3823 }
3824
3825 void
3826 complete_deferred_msg (HWND hwnd, UINT msg, LRESULT result)
3827 {
3828 deferred_msg * msg_buf = find_deferred_msg (hwnd, msg);
3829
3830 if (msg_buf == NULL)
3831 /* Message may have been cancelled, so don't abort(). */
3832 return;
3833
3834 msg_buf->result = result;
3835 msg_buf->completed = 1;
3836
3837 /* Ensure input thread is woken so it notices the completion. */
3838 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
3839 }
3840
3841 void
3842 cancel_all_deferred_msgs ()
3843 {
3844 deferred_msg * item;
3845
3846 /* Don't actually need synchronization for read access, since
3847 modification of single pointer is always atomic. */
3848 /* enter_crit (); */
3849
3850 for (item = deferred_msg_head; item != NULL; item = item->next)
3851 {
3852 item->result = 0;
3853 item->completed = 1;
3854 }
3855
3856 /* leave_crit (); */
3857
3858 /* Ensure input thread is woken so it notices the completion. */
3859 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
3860 }
3861
3862 DWORD
3863 w32_msg_worker (dw)
3864 DWORD dw;
3865 {
3866 MSG msg;
3867 deferred_msg dummy_buf;
3868
3869 /* Ensure our message queue is created */
3870
3871 PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
3872
3873 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3874 abort ();
3875
3876 memset (&dummy_buf, 0, sizeof (dummy_buf));
3877 dummy_buf.w32msg.msg.hwnd = NULL;
3878 dummy_buf.w32msg.msg.message = WM_NULL;
3879
3880 /* This is the inital message loop which should only exit when the
3881 application quits. */
3882 w32_msg_pump (&dummy_buf);
3883
3884 return 0;
3885 }
3886
3887 static void
3888 post_character_message (hwnd, msg, wParam, lParam, modifiers)
3889 HWND hwnd;
3890 UINT msg;
3891 WPARAM wParam;
3892 LPARAM lParam;
3893 DWORD modifiers;
3894
3895 {
3896 W32Msg wmsg;
3897
3898 wmsg.dwModifiers = modifiers;
3899
3900 /* Detect quit_char and set quit-flag directly. Note that we
3901 still need to post a message to ensure the main thread will be
3902 woken up if blocked in sys_select(), but we do NOT want to post
3903 the quit_char message itself (because it will usually be as if
3904 the user had typed quit_char twice). Instead, we post a dummy
3905 message that has no particular effect. */
3906 {
3907 int c = wParam;
3908 if (isalpha (c) && wmsg.dwModifiers == ctrl_modifier)
3909 c = make_ctrl_char (c) & 0377;
3910 if (c == quit_char
3911 || (wmsg.dwModifiers == 0 &&
3912 XFASTINT (Vw32_quit_key) && wParam == XFASTINT (Vw32_quit_key)))
3913 {
3914 Vquit_flag = Qt;
3915
3916 /* The choice of message is somewhat arbitrary, as long as
3917 the main thread handler just ignores it. */
3918 msg = WM_NULL;
3919
3920 /* Interrupt any blocking system calls. */
3921 signal_quit ();
3922
3923 /* As a safety precaution, forcibly complete any deferred
3924 messages. This is a kludge, but I don't see any particularly
3925 clean way to handle the situation where a deferred message is
3926 "dropped" in the lisp thread, and will thus never be
3927 completed, eg. by the user trying to activate the menubar
3928 when the lisp thread is busy, and then typing C-g when the
3929 menubar doesn't open promptly (with the result that the
3930 menubar never responds at all because the deferred
3931 WM_INITMENU message is never completed). Another problem
3932 situation is when the lisp thread calls SendMessage (to send
3933 a window manager command) when a message has been deferred;
3934 the lisp thread gets blocked indefinitely waiting for the
3935 deferred message to be completed, which itself is waiting for
3936 the lisp thread to respond.
3937
3938 Note that we don't want to block the input thread waiting for
3939 a reponse from the lisp thread (although that would at least
3940 solve the deadlock problem above), because we want to be able
3941 to receive C-g to interrupt the lisp thread. */
3942 cancel_all_deferred_msgs ();
3943 }
3944 }
3945
3946 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3947 }
3948
3949 /* Main window procedure */
3950
3951 LRESULT CALLBACK
3952 w32_wnd_proc (hwnd, msg, wParam, lParam)
3953 HWND hwnd;
3954 UINT msg;
3955 WPARAM wParam;
3956 LPARAM lParam;
3957 {
3958 struct frame *f;
3959 struct w32_display_info *dpyinfo = &one_w32_display_info;
3960 W32Msg wmsg;
3961 int windows_translate;
3962 int key;
3963
3964 /* Note that it is okay to call x_window_to_frame, even though we are
3965 not running in the main lisp thread, because frame deletion
3966 requires the lisp thread to synchronize with this thread. Thus, if
3967 a frame struct is returned, it can be used without concern that the
3968 lisp thread might make it disappear while we are using it.
3969
3970 NB. Walking the frame list in this thread is safe (as long as
3971 writes of Lisp_Object slots are atomic, which they are on Windows).
3972 Although delete-frame can destructively modify the frame list while
3973 we are walking it, a garbage collection cannot occur until after
3974 delete-frame has synchronized with this thread.
3975
3976 It is also safe to use functions that make GDI calls, such as
3977 w32_clear_rect, because these functions must obtain a DC handle
3978 from the frame struct using get_frame_dc which is thread-aware. */
3979
3980 switch (msg)
3981 {
3982 case WM_ERASEBKGND:
3983 f = x_window_to_frame (dpyinfo, hwnd);
3984 if (f)
3985 {
3986 HDC hdc = get_frame_dc (f);
3987 GetUpdateRect (hwnd, &wmsg.rect, FALSE);
3988 w32_clear_rect (f, hdc, &wmsg.rect);
3989 release_frame_dc (f, hdc);
3990
3991 #if defined (W32_DEBUG_DISPLAY)
3992 DebPrint (("WM_ERASEBKGND: erasing %d,%d-%d,%d\n",
3993 wmsg.rect.left, wmsg.rect.top, wmsg.rect.right,
3994 wmsg.rect.bottom));
3995 #endif /* W32_DEBUG_DISPLAY */
3996 }
3997 return 1;
3998 case WM_PALETTECHANGED:
3999 /* ignore our own changes */
4000 if ((HWND)wParam != hwnd)
4001 {
4002 f = x_window_to_frame (dpyinfo, hwnd);
4003 if (f)
4004 /* get_frame_dc will realize our palette and force all
4005 frames to be redrawn if needed. */
4006 release_frame_dc (f, get_frame_dc (f));
4007 }
4008 return 0;
4009 case WM_PAINT:
4010 {
4011 PAINTSTRUCT paintStruct;
4012 RECT update_rect;
4013
4014 /* MSDN Docs say not to call BeginPaint if GetUpdateRect
4015 fails. Apparently this can happen under some
4016 circumstances. */
4017 if (!w32_strict_painting || GetUpdateRect (hwnd, &update_rect, FALSE))
4018 {
4019 enter_crit ();
4020 BeginPaint (hwnd, &paintStruct);
4021
4022 if (w32_strict_painting)
4023 /* The rectangles returned by GetUpdateRect and BeginPaint
4024 do not always match. GetUpdateRect seems to be the
4025 more reliable of the two. */
4026 wmsg.rect = update_rect;
4027 else
4028 wmsg.rect = paintStruct.rcPaint;
4029
4030 #if defined (W32_DEBUG_DISPLAY)
4031 DebPrint (("WM_PAINT: painting %d,%d-%d,%d\n", wmsg.rect.left,
4032 wmsg.rect.top, wmsg.rect.right, wmsg.rect.bottom));
4033 DebPrint (("WM_PAINT: update region is %d,%d-%d,%d\n",
4034 update_rect.left, update_rect.top,
4035 update_rect.right, update_rect.bottom));
4036 #endif
4037 EndPaint (hwnd, &paintStruct);
4038 leave_crit ();
4039
4040 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4041
4042 return 0;
4043 }
4044
4045 /* If GetUpdateRect returns 0 (meaning there is no update
4046 region), assume the whole window needs to be repainted. */
4047 GetClientRect(hwnd, &wmsg.rect);
4048 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4049 return 0;
4050 }
4051
4052 case WM_INPUTLANGCHANGE:
4053 /* Inform lisp thread of keyboard layout changes. */
4054 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4055
4056 /* Clear dead keys in the keyboard state; for simplicity only
4057 preserve modifier key states. */
4058 {
4059 int i;
4060 BYTE keystate[256];
4061
4062 GetKeyboardState (keystate);
4063 for (i = 0; i < 256; i++)
4064 if (1
4065 && i != VK_SHIFT
4066 && i != VK_LSHIFT
4067 && i != VK_RSHIFT
4068 && i != VK_CAPITAL
4069 && i != VK_NUMLOCK
4070 && i != VK_SCROLL
4071 && i != VK_CONTROL
4072 && i != VK_LCONTROL
4073 && i != VK_RCONTROL
4074 && i != VK_MENU
4075 && i != VK_LMENU
4076 && i != VK_RMENU
4077 && i != VK_LWIN
4078 && i != VK_RWIN)
4079 keystate[i] = 0;
4080 SetKeyboardState (keystate);
4081 }
4082 goto dflt;
4083
4084 case WM_HOTKEY:
4085 /* Synchronize hot keys with normal input. */
4086 PostMessage (hwnd, WM_KEYDOWN, HIWORD (lParam), 0);
4087 return (0);
4088
4089 case WM_KEYUP:
4090 case WM_SYSKEYUP:
4091 record_keyup (wParam, lParam);
4092 goto dflt;
4093
4094 case WM_KEYDOWN:
4095 case WM_SYSKEYDOWN:
4096 /* Ignore keystrokes we fake ourself; see below. */
4097 if (dpyinfo->faked_key == wParam)
4098 {
4099 dpyinfo->faked_key = 0;
4100 /* Make sure TranslateMessage sees them though (as long as
4101 they don't produce WM_CHAR messages). This ensures that
4102 indicator lights are toggled promptly on Windows 9x, for
4103 example. */
4104 if (lispy_function_keys[wParam] != 0)
4105 {
4106 windows_translate = 1;
4107 goto translate;
4108 }
4109 return 0;
4110 }
4111
4112 /* Synchronize modifiers with current keystroke. */
4113 sync_modifiers ();
4114 record_keydown (wParam, lParam);
4115 wParam = map_keypad_keys (wParam, (lParam & 0x1000000L) != 0);
4116
4117 windows_translate = 0;
4118
4119 switch (wParam)
4120 {
4121 case VK_LWIN:
4122 if (NILP (Vw32_pass_lwindow_to_system))
4123 {
4124 /* Prevent system from acting on keyup (which opens the
4125 Start menu if no other key was pressed) by simulating a
4126 press of Space which we will ignore. */
4127 if (GetAsyncKeyState (wParam) & 1)
4128 {
4129 if (NUMBERP (Vw32_phantom_key_code))
4130 key = XUINT (Vw32_phantom_key_code) & 255;
4131 else
4132 key = VK_SPACE;
4133 dpyinfo->faked_key = key;
4134 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
4135 }
4136 }
4137 if (!NILP (Vw32_lwindow_modifier))
4138 return 0;
4139 break;
4140 case VK_RWIN:
4141 if (NILP (Vw32_pass_rwindow_to_system))
4142 {
4143 if (GetAsyncKeyState (wParam) & 1)
4144 {
4145 if (NUMBERP (Vw32_phantom_key_code))
4146 key = XUINT (Vw32_phantom_key_code) & 255;
4147 else
4148 key = VK_SPACE;
4149 dpyinfo->faked_key = key;
4150 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
4151 }
4152 }
4153 if (!NILP (Vw32_rwindow_modifier))
4154 return 0;
4155 break;
4156 case VK_APPS:
4157 if (!NILP (Vw32_apps_modifier))
4158 return 0;
4159 break;
4160 case VK_MENU:
4161 if (NILP (Vw32_pass_alt_to_system))
4162 /* Prevent DefWindowProc from activating the menu bar if an
4163 Alt key is pressed and released by itself. */
4164 return 0;
4165 windows_translate = 1;
4166 break;
4167 case VK_CAPITAL:
4168 /* Decide whether to treat as modifier or function key. */
4169 if (NILP (Vw32_enable_caps_lock))
4170 goto disable_lock_key;
4171 windows_translate = 1;
4172 break;
4173 case VK_NUMLOCK:
4174 /* Decide whether to treat as modifier or function key. */
4175 if (NILP (Vw32_enable_num_lock))
4176 goto disable_lock_key;
4177 windows_translate = 1;
4178 break;
4179 case VK_SCROLL:
4180 /* Decide whether to treat as modifier or function key. */
4181 if (NILP (Vw32_scroll_lock_modifier))
4182 goto disable_lock_key;
4183 windows_translate = 1;
4184 break;
4185 disable_lock_key:
4186 /* Ensure the appropriate lock key state (and indicator light)
4187 remains in the same state. We do this by faking another
4188 press of the relevant key. Apparently, this really is the
4189 only way to toggle the state of the indicator lights. */
4190 dpyinfo->faked_key = wParam;
4191 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4192 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4193 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4194 KEYEVENTF_EXTENDEDKEY | 0, 0);
4195 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4196 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4197 /* Ensure indicator lights are updated promptly on Windows 9x
4198 (TranslateMessage apparently does this), after forwarding
4199 input event. */
4200 post_character_message (hwnd, msg, wParam, lParam,
4201 w32_get_key_modifiers (wParam, lParam));
4202 windows_translate = 1;
4203 break;
4204 case VK_CONTROL:
4205 case VK_SHIFT:
4206 case VK_PROCESSKEY: /* Generated by IME. */
4207 windows_translate = 1;
4208 break;
4209 case VK_CANCEL:
4210 /* Windows maps Ctrl-Pause (aka Ctrl-Break) into VK_CANCEL,
4211 which is confusing for purposes of key binding; convert
4212 VK_CANCEL events into VK_PAUSE events. */
4213 wParam = VK_PAUSE;
4214 break;
4215 case VK_PAUSE:
4216 /* Windows maps Ctrl-NumLock into VK_PAUSE, which is confusing
4217 for purposes of key binding; convert these back into
4218 VK_NUMLOCK events, at least when we want to see NumLock key
4219 presses. (Note that there is never any possibility that
4220 VK_PAUSE with Ctrl really is C-Pause as per above.) */
4221 if (NILP (Vw32_enable_num_lock) && modifier_set (VK_CONTROL))
4222 wParam = VK_NUMLOCK;
4223 break;
4224 default:
4225 /* If not defined as a function key, change it to a WM_CHAR message. */
4226 if (lispy_function_keys[wParam] == 0)
4227 {
4228 DWORD modifiers = construct_console_modifiers ();
4229
4230 if (!NILP (Vw32_recognize_altgr)
4231 && modifier_set (VK_LCONTROL) && modifier_set (VK_RMENU))
4232 {
4233 /* Always let TranslateMessage handle AltGr key chords;
4234 for some reason, ToAscii doesn't always process AltGr
4235 chords correctly. */
4236 windows_translate = 1;
4237 }
4238 else if ((modifiers & (~SHIFT_PRESSED & ~CAPSLOCK_ON)) != 0)
4239 {
4240 /* Handle key chords including any modifiers other
4241 than shift directly, in order to preserve as much
4242 modifier information as possible. */
4243 if ('A' <= wParam && wParam <= 'Z')
4244 {
4245 /* Don't translate modified alphabetic keystrokes,
4246 so the user doesn't need to constantly switch
4247 layout to type control or meta keystrokes when
4248 the normal layout translates alphabetic
4249 characters to non-ascii characters. */
4250 if (!modifier_set (VK_SHIFT))
4251 wParam += ('a' - 'A');
4252 msg = WM_CHAR;
4253 }
4254 else
4255 {
4256 /* Try to handle other keystrokes by determining the
4257 base character (ie. translating the base key plus
4258 shift modifier). */
4259 int add;
4260 int isdead = 0;
4261 KEY_EVENT_RECORD key;
4262
4263 key.bKeyDown = TRUE;
4264 key.wRepeatCount = 1;
4265 key.wVirtualKeyCode = wParam;
4266 key.wVirtualScanCode = (lParam & 0xFF0000) >> 16;
4267 key.uChar.AsciiChar = 0;
4268 key.dwControlKeyState = modifiers;
4269
4270 add = w32_kbd_patch_key (&key);
4271 /* 0 means an unrecognised keycode, negative means
4272 dead key. Ignore both. */
4273 while (--add >= 0)
4274 {
4275 /* Forward asciified character sequence. */
4276 post_character_message
4277 (hwnd, WM_CHAR, key.uChar.AsciiChar, lParam,
4278 w32_get_key_modifiers (wParam, lParam));
4279 w32_kbd_patch_key (&key);
4280 }
4281 return 0;
4282 }
4283 }
4284 else
4285 {
4286 /* Let TranslateMessage handle everything else. */
4287 windows_translate = 1;
4288 }
4289 }
4290 }
4291
4292 translate:
4293 if (windows_translate)
4294 {
4295 MSG windows_msg = { hwnd, msg, wParam, lParam, 0, {0,0} };
4296
4297 windows_msg.time = GetMessageTime ();
4298 TranslateMessage (&windows_msg);
4299 goto dflt;
4300 }
4301
4302 /* Fall through */
4303
4304 case WM_SYSCHAR:
4305 case WM_CHAR:
4306 post_character_message (hwnd, msg, wParam, lParam,
4307 w32_get_key_modifiers (wParam, lParam));
4308 break;
4309
4310 /* Simulate middle mouse button events when left and right buttons
4311 are used together, but only if user has two button mouse. */
4312 case WM_LBUTTONDOWN:
4313 case WM_RBUTTONDOWN:
4314 if (XINT (Vw32_num_mouse_buttons) > 2)
4315 goto handle_plain_button;
4316
4317 {
4318 int this = (msg == WM_LBUTTONDOWN) ? LMOUSE : RMOUSE;
4319 int other = (msg == WM_LBUTTONDOWN) ? RMOUSE : LMOUSE;
4320
4321 if (button_state & this)
4322 return 0;
4323
4324 if (button_state == 0)
4325 SetCapture (hwnd);
4326
4327 button_state |= this;
4328
4329 if (button_state & other)
4330 {
4331 if (mouse_button_timer)
4332 {
4333 KillTimer (hwnd, mouse_button_timer);
4334 mouse_button_timer = 0;
4335
4336 /* Generate middle mouse event instead. */
4337 msg = WM_MBUTTONDOWN;
4338 button_state |= MMOUSE;
4339 }
4340 else if (button_state & MMOUSE)
4341 {
4342 /* Ignore button event if we've already generated a
4343 middle mouse down event. This happens if the
4344 user releases and press one of the two buttons
4345 after we've faked a middle mouse event. */
4346 return 0;
4347 }
4348 else
4349 {
4350 /* Flush out saved message. */
4351 post_msg (&saved_mouse_button_msg);
4352 }
4353 wmsg.dwModifiers = w32_get_modifiers ();
4354 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4355
4356 /* Clear message buffer. */
4357 saved_mouse_button_msg.msg.hwnd = 0;
4358 }
4359 else
4360 {
4361 /* Hold onto message for now. */
4362 mouse_button_timer =
4363 SetTimer (hwnd, MOUSE_BUTTON_ID,
4364 XINT (Vw32_mouse_button_tolerance), NULL);
4365 saved_mouse_button_msg.msg.hwnd = hwnd;
4366 saved_mouse_button_msg.msg.message = msg;
4367 saved_mouse_button_msg.msg.wParam = wParam;
4368 saved_mouse_button_msg.msg.lParam = lParam;
4369 saved_mouse_button_msg.msg.time = GetMessageTime ();
4370 saved_mouse_button_msg.dwModifiers = w32_get_modifiers ();
4371 }
4372 }
4373 return 0;
4374
4375 case WM_LBUTTONUP:
4376 case WM_RBUTTONUP:
4377 if (XINT (Vw32_num_mouse_buttons) > 2)
4378 goto handle_plain_button;
4379
4380 {
4381 int this = (msg == WM_LBUTTONUP) ? LMOUSE : RMOUSE;
4382 int other = (msg == WM_LBUTTONUP) ? RMOUSE : LMOUSE;
4383
4384 if ((button_state & this) == 0)
4385 return 0;
4386
4387 button_state &= ~this;
4388
4389 if (button_state & MMOUSE)
4390 {
4391 /* Only generate event when second button is released. */
4392 if ((button_state & other) == 0)
4393 {
4394 msg = WM_MBUTTONUP;
4395 button_state &= ~MMOUSE;
4396
4397 if (button_state) abort ();
4398 }
4399 else
4400 return 0;
4401 }
4402 else
4403 {
4404 /* Flush out saved message if necessary. */
4405 if (saved_mouse_button_msg.msg.hwnd)
4406 {
4407 post_msg (&saved_mouse_button_msg);
4408 }
4409 }
4410 wmsg.dwModifiers = w32_get_modifiers ();
4411 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4412
4413 /* Always clear message buffer and cancel timer. */
4414 saved_mouse_button_msg.msg.hwnd = 0;
4415 KillTimer (hwnd, mouse_button_timer);
4416 mouse_button_timer = 0;
4417
4418 if (button_state == 0)
4419 ReleaseCapture ();
4420 }
4421 return 0;
4422
4423 case WM_MBUTTONDOWN:
4424 case WM_MBUTTONUP:
4425 handle_plain_button:
4426 {
4427 BOOL up;
4428 int button;
4429
4430 if (parse_button (msg, &button, &up))
4431 {
4432 if (up) ReleaseCapture ();
4433 else SetCapture (hwnd);
4434 button = (button == 0) ? LMOUSE :
4435 ((button == 1) ? MMOUSE : RMOUSE);
4436 if (up)
4437 button_state &= ~button;
4438 else
4439 button_state |= button;
4440 }
4441 }
4442
4443 wmsg.dwModifiers = w32_get_modifiers ();
4444 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4445 return 0;
4446
4447 case WM_VSCROLL:
4448 case WM_MOUSEMOVE:
4449 if (XINT (Vw32_mouse_move_interval) <= 0
4450 || (msg == WM_MOUSEMOVE && button_state == 0))
4451 {
4452 wmsg.dwModifiers = w32_get_modifiers ();
4453 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4454 return 0;
4455 }
4456
4457 /* Hang onto mouse move and scroll messages for a bit, to avoid
4458 sending such events to Emacs faster than it can process them.
4459 If we get more events before the timer from the first message
4460 expires, we just replace the first message. */
4461
4462 if (saved_mouse_move_msg.msg.hwnd == 0)
4463 mouse_move_timer =
4464 SetTimer (hwnd, MOUSE_MOVE_ID,
4465 XINT (Vw32_mouse_move_interval), NULL);
4466
4467 /* Hold onto message for now. */
4468 saved_mouse_move_msg.msg.hwnd = hwnd;
4469 saved_mouse_move_msg.msg.message = msg;
4470 saved_mouse_move_msg.msg.wParam = wParam;
4471 saved_mouse_move_msg.msg.lParam = lParam;
4472 saved_mouse_move_msg.msg.time = GetMessageTime ();
4473 saved_mouse_move_msg.dwModifiers = w32_get_modifiers ();
4474
4475 return 0;
4476
4477 case WM_MOUSEWHEEL:
4478 wmsg.dwModifiers = w32_get_modifiers ();
4479 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4480 return 0;
4481
4482 case WM_DROPFILES:
4483 wmsg.dwModifiers = w32_get_modifiers ();
4484 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4485 return 0;
4486
4487 case WM_TIMER:
4488 /* Flush out saved messages if necessary. */
4489 if (wParam == mouse_button_timer)
4490 {
4491 if (saved_mouse_button_msg.msg.hwnd)
4492 {
4493 post_msg (&saved_mouse_button_msg);
4494 saved_mouse_button_msg.msg.hwnd = 0;
4495 }
4496 KillTimer (hwnd, mouse_button_timer);
4497 mouse_button_timer = 0;
4498 }
4499 else if (wParam == mouse_move_timer)
4500 {
4501 if (saved_mouse_move_msg.msg.hwnd)
4502 {
4503 post_msg (&saved_mouse_move_msg);
4504 saved_mouse_move_msg.msg.hwnd = 0;
4505 }
4506 KillTimer (hwnd, mouse_move_timer);
4507 mouse_move_timer = 0;
4508 }
4509 return 0;
4510
4511 case WM_NCACTIVATE:
4512 /* Windows doesn't send us focus messages when putting up and
4513 taking down a system popup dialog as for Ctrl-Alt-Del on Windows 95.
4514 The only indication we get that something happened is receiving
4515 this message afterwards. So this is a good time to reset our
4516 keyboard modifiers' state. */
4517 reset_modifiers ();
4518 goto dflt;
4519
4520 case WM_INITMENU:
4521 button_state = 0;
4522 ReleaseCapture ();
4523 /* We must ensure menu bar is fully constructed and up to date
4524 before allowing user interaction with it. To achieve this
4525 we send this message to the lisp thread and wait for a
4526 reply (whose value is not actually needed) to indicate that
4527 the menu bar is now ready for use, so we can now return.
4528
4529 To remain responsive in the meantime, we enter a nested message
4530 loop that can process all other messages.
4531
4532 However, we skip all this if the message results from calling
4533 TrackPopupMenu - in fact, we must NOT attempt to send the lisp
4534 thread a message because it is blocked on us at this point. We
4535 set menubar_active before calling TrackPopupMenu to indicate
4536 this (there is no possibility of confusion with real menubar
4537 being active). */
4538
4539 f = x_window_to_frame (dpyinfo, hwnd);
4540 if (f
4541 && (f->output_data.w32->menubar_active
4542 /* We can receive this message even in the absence of a
4543 menubar (ie. when the system menu is activated) - in this
4544 case we do NOT want to forward the message, otherwise it
4545 will cause the menubar to suddenly appear when the user
4546 had requested it to be turned off! */
4547 || f->output_data.w32->menubar_widget == NULL))
4548 return 0;
4549
4550 {
4551 deferred_msg msg_buf;
4552
4553 /* Detect if message has already been deferred; in this case
4554 we cannot return any sensible value to ignore this. */
4555 if (find_deferred_msg (hwnd, msg) != NULL)
4556 abort ();
4557
4558 return send_deferred_msg (&msg_buf, hwnd, msg, wParam, lParam);
4559 }
4560
4561 case WM_EXITMENULOOP:
4562 f = x_window_to_frame (dpyinfo, hwnd);
4563
4564 /* Indicate that menubar can be modified again. */
4565 if (f)
4566 f->output_data.w32->menubar_active = 0;
4567 goto dflt;
4568
4569 case WM_MENUSELECT:
4570 wmsg.dwModifiers = w32_get_modifiers ();
4571 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4572 return 0;
4573
4574 case WM_MEASUREITEM:
4575 f = x_window_to_frame (dpyinfo, hwnd);
4576 if (f)
4577 {
4578 MEASUREITEMSTRUCT * pMis = (MEASUREITEMSTRUCT *) lParam;
4579
4580 if (pMis->CtlType == ODT_MENU)
4581 {
4582 /* Work out dimensions for popup menu titles. */
4583 char * title = (char *) pMis->itemData;
4584 HDC hdc = GetDC (hwnd);
4585 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4586 LOGFONT menu_logfont;
4587 HFONT old_font;
4588 SIZE size;
4589
4590 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4591 menu_logfont.lfWeight = FW_BOLD;
4592 menu_font = CreateFontIndirect (&menu_logfont);
4593 old_font = SelectObject (hdc, menu_font);
4594
4595 pMis->itemHeight = GetSystemMetrics (SM_CYMENUSIZE);
4596 if (title)
4597 {
4598 GetTextExtentPoint32 (hdc, title, strlen (title), &size);
4599 pMis->itemWidth = size.cx;
4600 if (pMis->itemHeight < size.cy)
4601 pMis->itemHeight = size.cy;
4602 }
4603 else
4604 pMis->itemWidth = 0;
4605
4606 SelectObject (hdc, old_font);
4607 DeleteObject (menu_font);
4608 ReleaseDC (hwnd, hdc);
4609 return TRUE;
4610 }
4611 }
4612 return 0;
4613
4614 case WM_DRAWITEM:
4615 f = x_window_to_frame (dpyinfo, hwnd);
4616 if (f)
4617 {
4618 DRAWITEMSTRUCT * pDis = (DRAWITEMSTRUCT *) lParam;
4619
4620 if (pDis->CtlType == ODT_MENU)
4621 {
4622 /* Draw popup menu title. */
4623 char * title = (char *) pDis->itemData;
4624 HDC hdc = pDis->hDC;
4625 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4626 LOGFONT menu_logfont;
4627 HFONT old_font;
4628
4629 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4630 menu_logfont.lfWeight = FW_BOLD;
4631 menu_font = CreateFontIndirect (&menu_logfont);
4632 old_font = SelectObject (hdc, menu_font);
4633
4634 /* Always draw title as if not selected. */
4635 ExtTextOut (hdc,
4636 pDis->rcItem.left + GetSystemMetrics (SM_CXMENUCHECK),
4637 pDis->rcItem.top,
4638 ETO_OPAQUE, &pDis->rcItem,
4639 title, strlen (title), NULL);
4640
4641 SelectObject (hdc, old_font);
4642 DeleteObject (menu_font);
4643 return TRUE;
4644 }
4645 }
4646 return 0;
4647
4648 #if 0
4649 /* Still not right - can't distinguish between clicks in the
4650 client area of the frame from clicks forwarded from the scroll
4651 bars - may have to hook WM_NCHITTEST to remember the mouse
4652 position and then check if it is in the client area ourselves. */
4653 case WM_MOUSEACTIVATE:
4654 /* Discard the mouse click that activates a frame, allowing the
4655 user to click anywhere without changing point (or worse!).
4656 Don't eat mouse clicks on scrollbars though!! */
4657 if (LOWORD (lParam) == HTCLIENT )
4658 return MA_ACTIVATEANDEAT;
4659 goto dflt;
4660 #endif
4661
4662 case WM_ACTIVATEAPP:
4663 case WM_ACTIVATE:
4664 case WM_WINDOWPOSCHANGED:
4665 case WM_SHOWWINDOW:
4666 /* Inform lisp thread that a frame might have just been obscured
4667 or exposed, so should recheck visibility of all frames. */
4668 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4669 goto dflt;
4670
4671 case WM_SETFOCUS:
4672 dpyinfo->faked_key = 0;
4673 reset_modifiers ();
4674 register_hot_keys (hwnd);
4675 goto command;
4676 case WM_KILLFOCUS:
4677 unregister_hot_keys (hwnd);
4678 button_state = 0;
4679 ReleaseCapture ();
4680 case WM_MOVE:
4681 case WM_SIZE:
4682 case WM_COMMAND:
4683 command:
4684 wmsg.dwModifiers = w32_get_modifiers ();
4685 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4686 goto dflt;
4687
4688 case WM_CLOSE:
4689 wmsg.dwModifiers = w32_get_modifiers ();
4690 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4691 return 0;
4692
4693 case WM_WINDOWPOSCHANGING:
4694 {
4695 WINDOWPLACEMENT wp;
4696 LPWINDOWPOS lppos = (WINDOWPOS *) lParam;
4697
4698 wp.length = sizeof (WINDOWPLACEMENT);
4699 GetWindowPlacement (hwnd, &wp);
4700
4701 if (wp.showCmd != SW_SHOWMINIMIZED && (lppos->flags & SWP_NOSIZE) == 0)
4702 {
4703 RECT rect;
4704 int wdiff;
4705 int hdiff;
4706 DWORD font_width;
4707 DWORD line_height;
4708 DWORD internal_border;
4709 DWORD scrollbar_extra;
4710 RECT wr;
4711
4712 wp.length = sizeof(wp);
4713 GetWindowRect (hwnd, &wr);
4714
4715 enter_crit ();
4716
4717 font_width = GetWindowLong (hwnd, WND_FONTWIDTH_INDEX);
4718 line_height = GetWindowLong (hwnd, WND_LINEHEIGHT_INDEX);
4719 internal_border = GetWindowLong (hwnd, WND_BORDER_INDEX);
4720 scrollbar_extra = GetWindowLong (hwnd, WND_SCROLLBAR_INDEX);
4721
4722 leave_crit ();
4723
4724 memset (&rect, 0, sizeof (rect));
4725 AdjustWindowRect (&rect, GetWindowLong (hwnd, GWL_STYLE),
4726 GetMenu (hwnd) != NULL);
4727
4728 /* Force width and height of client area to be exact
4729 multiples of the character cell dimensions. */
4730 wdiff = (lppos->cx - (rect.right - rect.left)
4731 - 2 * internal_border - scrollbar_extra)
4732 % font_width;
4733 hdiff = (lppos->cy - (rect.bottom - rect.top)
4734 - 2 * internal_border)
4735 % line_height;
4736
4737 if (wdiff || hdiff)
4738 {
4739 /* For right/bottom sizing we can just fix the sizes.
4740 However for top/left sizing we will need to fix the X
4741 and Y positions as well. */
4742
4743 lppos->cx -= wdiff;
4744 lppos->cy -= hdiff;
4745
4746 if (wp.showCmd != SW_SHOWMAXIMIZED
4747 && (lppos->flags & SWP_NOMOVE) == 0)
4748 {
4749 if (lppos->x != wr.left || lppos->y != wr.top)
4750 {
4751 lppos->x += wdiff;
4752 lppos->y += hdiff;
4753 }
4754 else
4755 {
4756 lppos->flags |= SWP_NOMOVE;
4757 }
4758 }
4759
4760 return 0;
4761 }
4762 }
4763 }
4764
4765 goto dflt;
4766
4767 case WM_GETMINMAXINFO:
4768 /* Hack to correct bug that allows Emacs frames to be resized
4769 below the Minimum Tracking Size. */
4770 ((LPMINMAXINFO) lParam)->ptMinTrackSize.y++;
4771 return 0;
4772
4773 case WM_EMACS_CREATESCROLLBAR:
4774 return (LRESULT) w32_createscrollbar ((struct frame *) wParam,
4775 (struct scroll_bar *) lParam);
4776
4777 case WM_EMACS_SHOWWINDOW:
4778 return ShowWindow ((HWND) wParam, (WPARAM) lParam);
4779
4780 case WM_EMACS_SETFOREGROUND:
4781 {
4782 HWND foreground_window;
4783 DWORD foreground_thread, retval;
4784
4785 /* On NT 5.0, and apparently Windows 98, it is necessary to
4786 attach to the thread that currently has focus in order to
4787 pull the focus away from it. */
4788 foreground_window = GetForegroundWindow ();
4789 foreground_thread = GetWindowThreadProcessId (foreground_window, NULL);
4790 if (!foreground_window
4791 || foreground_thread == GetCurrentThreadId ()
4792 || !AttachThreadInput (GetCurrentThreadId (),
4793 foreground_thread, TRUE))
4794 foreground_thread = 0;
4795
4796 retval = SetForegroundWindow ((HWND) wParam);
4797
4798 /* Detach from the previous foreground thread. */
4799 if (foreground_thread)
4800 AttachThreadInput (GetCurrentThreadId (),
4801 foreground_thread, FALSE);
4802
4803 return retval;
4804 }
4805
4806 case WM_EMACS_SETWINDOWPOS:
4807 {
4808 WINDOWPOS * pos = (WINDOWPOS *) wParam;
4809 return SetWindowPos (hwnd, pos->hwndInsertAfter,
4810 pos->x, pos->y, pos->cx, pos->cy, pos->flags);
4811 }
4812
4813 case WM_EMACS_DESTROYWINDOW:
4814 DragAcceptFiles ((HWND) wParam, FALSE);
4815 return DestroyWindow ((HWND) wParam);
4816
4817 case WM_EMACS_TRACKPOPUPMENU:
4818 {
4819 UINT flags;
4820 POINT *pos;
4821 int retval;
4822 pos = (POINT *)lParam;
4823 flags = TPM_CENTERALIGN;
4824 if (button_state & LMOUSE)
4825 flags |= TPM_LEFTBUTTON;
4826 else if (button_state & RMOUSE)
4827 flags |= TPM_RIGHTBUTTON;
4828
4829 /* Remember we did a SetCapture on the initial mouse down event,
4830 so for safety, we make sure the capture is cancelled now. */
4831 ReleaseCapture ();
4832 button_state = 0;
4833
4834 /* Use menubar_active to indicate that WM_INITMENU is from
4835 TrackPopupMenu below, and should be ignored. */
4836 f = x_window_to_frame (dpyinfo, hwnd);
4837 if (f)
4838 f->output_data.w32->menubar_active = 1;
4839
4840 if (TrackPopupMenu ((HMENU)wParam, flags, pos->x, pos->y,
4841 0, hwnd, NULL))
4842 {
4843 MSG amsg;
4844 /* Eat any mouse messages during popupmenu */
4845 while (PeekMessage (&amsg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST,
4846 PM_REMOVE));
4847 /* Get the menu selection, if any */
4848 if (PeekMessage (&amsg, hwnd, WM_COMMAND, WM_COMMAND, PM_REMOVE))
4849 {
4850 retval = LOWORD (amsg.wParam);
4851 }
4852 else
4853 {
4854 retval = 0;
4855 }
4856 }
4857 else
4858 {
4859 retval = -1;
4860 }
4861
4862 return retval;
4863 }
4864
4865 default:
4866 /* Check for messages registered at runtime. */
4867 if (msg == msh_mousewheel)
4868 {
4869 wmsg.dwModifiers = w32_get_modifiers ();
4870 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4871 return 0;
4872 }
4873
4874 dflt:
4875 return DefWindowProc (hwnd, msg, wParam, lParam);
4876 }
4877
4878
4879 /* The most common default return code for handled messages is 0. */
4880 return 0;
4881 }
4882
4883 void
4884 my_create_window (f)
4885 struct frame * f;
4886 {
4887 MSG msg;
4888
4889 if (!PostThreadMessage (dwWindowsThreadId, WM_EMACS_CREATEWINDOW, (WPARAM)f, 0))
4890 abort ();
4891 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
4892 }
4893
4894 /* Create and set up the w32 window for frame F. */
4895
4896 static void
4897 w32_window (f, window_prompting, minibuffer_only)
4898 struct frame *f;
4899 long window_prompting;
4900 int minibuffer_only;
4901 {
4902 BLOCK_INPUT;
4903
4904 /* Use the resource name as the top-level window name
4905 for looking up resources. Make a non-Lisp copy
4906 for the window manager, so GC relocation won't bother it.
4907
4908 Elsewhere we specify the window name for the window manager. */
4909
4910 {
4911 char *str = (char *) XSTRING (Vx_resource_name)->data;
4912 f->namebuf = (char *) xmalloc (strlen (str) + 1);
4913 strcpy (f->namebuf, str);
4914 }
4915
4916 my_create_window (f);
4917
4918 validate_x_resource_name ();
4919
4920 /* x_set_name normally ignores requests to set the name if the
4921 requested name is the same as the current name. This is the one
4922 place where that assumption isn't correct; f->name is set, but
4923 the server hasn't been told. */
4924 {
4925 Lisp_Object name;
4926 int explicit = f->explicit_name;
4927
4928 f->explicit_name = 0;
4929 name = f->name;
4930 f->name = Qnil;
4931 x_set_name (f, name, explicit);
4932 }
4933
4934 UNBLOCK_INPUT;
4935
4936 if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f))
4937 initialize_frame_menubar (f);
4938
4939 if (FRAME_W32_WINDOW (f) == 0)
4940 error ("Unable to create window");
4941 }
4942
4943 /* Handle the icon stuff for this window. Perhaps later we might
4944 want an x_set_icon_position which can be called interactively as
4945 well. */
4946
4947 static void
4948 x_icon (f, parms)
4949 struct frame *f;
4950 Lisp_Object parms;
4951 {
4952 Lisp_Object icon_x, icon_y;
4953
4954 /* Set the position of the icon. Note that Windows 95 groups all
4955 icons in the tray. */
4956 icon_x = w32_get_arg (parms, Qicon_left, 0, 0, RES_TYPE_NUMBER);
4957 icon_y = w32_get_arg (parms, Qicon_top, 0, 0, RES_TYPE_NUMBER);
4958 if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
4959 {
4960 CHECK_NUMBER (icon_x, 0);
4961 CHECK_NUMBER (icon_y, 0);
4962 }
4963 else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
4964 error ("Both left and top icon corners of icon must be specified");
4965
4966 BLOCK_INPUT;
4967
4968 if (! EQ (icon_x, Qunbound))
4969 x_wm_set_icon_position (f, XINT (icon_x), XINT (icon_y));
4970
4971 #if 0 /* TODO */
4972 /* Start up iconic or window? */
4973 x_wm_set_window_state
4974 (f, (EQ (w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL), Qicon)
4975 ? IconicState
4976 : NormalState));
4977
4978 x_text_icon (f, (char *) XSTRING ((!NILP (f->icon_name)
4979 ? f->icon_name
4980 : f->name))->data);
4981 #endif
4982
4983 UNBLOCK_INPUT;
4984 }
4985
4986
4987 static void
4988 x_make_gc (f)
4989 struct frame *f;
4990 {
4991 XGCValues gc_values;
4992
4993 BLOCK_INPUT;
4994
4995 /* Create the GC's of this frame.
4996 Note that many default values are used. */
4997
4998 /* Normal video */
4999 gc_values.font = f->output_data.w32->font;
5000
5001 /* Cursor has cursor-color background, background-color foreground. */
5002 gc_values.foreground = FRAME_BACKGROUND_PIXEL (f);
5003 gc_values.background = f->output_data.w32->cursor_pixel;
5004 f->output_data.w32->cursor_gc
5005 = XCreateGC (NULL, FRAME_W32_WINDOW (f),
5006 (GCFont | GCForeground | GCBackground),
5007 &gc_values);
5008
5009 /* Reliefs. */
5010 f->output_data.w32->white_relief.gc = 0;
5011 f->output_data.w32->black_relief.gc = 0;
5012
5013 UNBLOCK_INPUT;
5014 }
5015
5016
5017 DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
5018 1, 1, 0,
5019 "Make a new window, which is called a \"frame\" in Emacs terms.\n\
5020 Returns an Emacs frame object.\n\
5021 ALIST is an alist of frame parameters.\n\
5022 If the parameters specify that the frame should not have a minibuffer,\n\
5023 and do not specify a specific minibuffer window to use,\n\
5024 then `default-minibuffer-frame' must be a frame whose minibuffer can\n\
5025 be shared by the new frame.\n\
5026 \n\
5027 This function is an internal primitive--use `make-frame' instead.")
5028 (parms)
5029 Lisp_Object parms;
5030 {
5031 struct frame *f;
5032 Lisp_Object frame, tem;
5033 Lisp_Object name;
5034 int minibuffer_only = 0;
5035 long window_prompting = 0;
5036 int width, height;
5037 int count = specpdl_ptr - specpdl;
5038 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
5039 Lisp_Object display;
5040 struct w32_display_info *dpyinfo = NULL;
5041 Lisp_Object parent;
5042 struct kboard *kb;
5043
5044 check_w32 ();
5045
5046 /* Use this general default value to start with
5047 until we know if this frame has a specified name. */
5048 Vx_resource_name = Vinvocation_name;
5049
5050 display = w32_get_arg (parms, Qdisplay, 0, 0, RES_TYPE_STRING);
5051 if (EQ (display, Qunbound))
5052 display = Qnil;
5053 dpyinfo = check_x_display_info (display);
5054 #ifdef MULTI_KBOARD
5055 kb = dpyinfo->kboard;
5056 #else
5057 kb = &the_only_kboard;
5058 #endif
5059
5060 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
5061 if (!STRINGP (name)
5062 && ! EQ (name, Qunbound)
5063 && ! NILP (name))
5064 error ("Invalid frame name--not a string or nil");
5065
5066 if (STRINGP (name))
5067 Vx_resource_name = name;
5068
5069 /* See if parent window is specified. */
5070 parent = w32_get_arg (parms, Qparent_id, NULL, NULL, RES_TYPE_NUMBER);
5071 if (EQ (parent, Qunbound))
5072 parent = Qnil;
5073 if (! NILP (parent))
5074 CHECK_NUMBER (parent, 0);
5075
5076 /* make_frame_without_minibuffer can run Lisp code and garbage collect. */
5077 /* No need to protect DISPLAY because that's not used after passing
5078 it to make_frame_without_minibuffer. */
5079 frame = Qnil;
5080 GCPRO4 (parms, parent, name, frame);
5081 tem = w32_get_arg (parms, Qminibuffer, 0, 0, RES_TYPE_SYMBOL);
5082 if (EQ (tem, Qnone) || NILP (tem))
5083 f = make_frame_without_minibuffer (Qnil, kb, display);
5084 else if (EQ (tem, Qonly))
5085 {
5086 f = make_minibuffer_frame ();
5087 minibuffer_only = 1;
5088 }
5089 else if (WINDOWP (tem))
5090 f = make_frame_without_minibuffer (tem, kb, display);
5091 else
5092 f = make_frame (1);
5093
5094 XSETFRAME (frame, f);
5095
5096 /* Note that Windows does support scroll bars. */
5097 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
5098 /* By default, make scrollbars the system standard width. */
5099 f->scroll_bar_pixel_width = GetSystemMetrics (SM_CXVSCROLL);
5100
5101 f->output_method = output_w32;
5102 f->output_data.w32 =
5103 (struct w32_output *) xmalloc (sizeof (struct w32_output));
5104 bzero (f->output_data.w32, sizeof (struct w32_output));
5105
5106 FRAME_FONTSET (f) = -1;
5107
5108 f->icon_name
5109 = w32_get_arg (parms, Qicon_name, "iconName", "Title", RES_TYPE_STRING);
5110 if (! STRINGP (f->icon_name))
5111 f->icon_name = Qnil;
5112
5113 /* FRAME_W32_DISPLAY_INFO (f) = dpyinfo; */
5114 #ifdef MULTI_KBOARD
5115 FRAME_KBOARD (f) = kb;
5116 #endif
5117
5118 /* Specify the parent under which to make this window. */
5119
5120 if (!NILP (parent))
5121 {
5122 f->output_data.w32->parent_desc = (Window) parent;
5123 f->output_data.w32->explicit_parent = 1;
5124 }
5125 else
5126 {
5127 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
5128 f->output_data.w32->explicit_parent = 0;
5129 }
5130
5131 /* Set the name; the functions to which we pass f expect the name to
5132 be set. */
5133 if (EQ (name, Qunbound) || NILP (name))
5134 {
5135 f->name = build_string (dpyinfo->w32_id_name);
5136 f->explicit_name = 0;
5137 }
5138 else
5139 {
5140 f->name = name;
5141 f->explicit_name = 1;
5142 /* use the frame's title when getting resources for this frame. */
5143 specbind (Qx_resource_name, name);
5144 }
5145
5146 /* Extract the window parameters from the supplied values
5147 that are needed to determine window geometry. */
5148 {
5149 Lisp_Object font;
5150
5151 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
5152
5153 BLOCK_INPUT;
5154 /* First, try whatever font the caller has specified. */
5155 if (STRINGP (font))
5156 {
5157 tem = Fquery_fontset (font, Qnil);
5158 if (STRINGP (tem))
5159 font = x_new_fontset (f, XSTRING (tem)->data);
5160 else
5161 font = x_new_font (f, XSTRING (font)->data);
5162 }
5163 /* Try out a font which we hope has bold and italic variations. */
5164 if (!STRINGP (font))
5165 font = x_new_font (f, "-*-Courier New-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
5166 if (! STRINGP (font))
5167 font = x_new_font (f, "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
5168 /* If those didn't work, look for something which will at least work. */
5169 if (! STRINGP (font))
5170 font = x_new_font (f, "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1");
5171 UNBLOCK_INPUT;
5172 if (! STRINGP (font))
5173 font = build_string ("Fixedsys");
5174
5175 x_default_parameter (f, parms, Qfont, font,
5176 "font", "Font", RES_TYPE_STRING);
5177 }
5178
5179 x_default_parameter (f, parms, Qborder_width, make_number (2),
5180 "borderwidth", "BorderWidth", RES_TYPE_NUMBER);
5181 /* This defaults to 2 in order to match xterm. We recognize either
5182 internalBorderWidth or internalBorder (which is what xterm calls
5183 it). */
5184 if (NILP (Fassq (Qinternal_border_width, parms)))
5185 {
5186 Lisp_Object value;
5187
5188 value = w32_get_arg (parms, Qinternal_border_width,
5189 "internalBorder", "BorderWidth", RES_TYPE_NUMBER);
5190 if (! EQ (value, Qunbound))
5191 parms = Fcons (Fcons (Qinternal_border_width, value),
5192 parms);
5193 }
5194 /* Default internalBorderWidth to 0 on Windows to match other programs. */
5195 x_default_parameter (f, parms, Qinternal_border_width, make_number (0),
5196 "internalBorderWidth", "BorderWidth", RES_TYPE_NUMBER);
5197 x_default_parameter (f, parms, Qvertical_scroll_bars, Qt,
5198 "verticalScrollBars", "ScrollBars", RES_TYPE_BOOLEAN);
5199
5200 /* Also do the stuff which must be set before the window exists. */
5201 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
5202 "foreground", "Foreground", RES_TYPE_STRING);
5203 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
5204 "background", "Background", RES_TYPE_STRING);
5205 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
5206 "pointerColor", "Foreground", RES_TYPE_STRING);
5207 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
5208 "cursorColor", "Foreground", RES_TYPE_STRING);
5209 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
5210 "borderColor", "BorderColor", RES_TYPE_STRING);
5211 x_default_parameter (f, parms, Qscreen_gamma, Qnil,
5212 "screenGamma", "ScreenGamma", RES_TYPE_FLOAT);
5213 x_default_parameter (f, parms, Qline_spacing, Qnil,
5214 "lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
5215
5216
5217 /* Init faces before x_default_parameter is called for scroll-bar
5218 parameters because that function calls x_set_scroll_bar_width,
5219 which calls change_frame_size, which calls Fset_window_buffer,
5220 which runs hooks, which call Fvertical_motion. At the end, we
5221 end up in init_iterator with a null face cache, which should not
5222 happen. */
5223 init_frame_faces (f);
5224
5225 x_default_parameter (f, parms, Qmenu_bar_lines, make_number (1),
5226 "menuBar", "MenuBar", RES_TYPE_NUMBER);
5227 x_default_parameter (f, parms, Qtool_bar_lines, make_number (0),
5228 "toolBar", "ToolBar", RES_TYPE_NUMBER);
5229 x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
5230 "bufferPredicate", "BufferPredicate", RES_TYPE_SYMBOL);
5231 x_default_parameter (f, parms, Qtitle, Qnil,
5232 "title", "Title", RES_TYPE_STRING);
5233
5234 f->output_data.w32->dwStyle = WS_OVERLAPPEDWINDOW;
5235 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
5236 window_prompting = x_figure_window_size (f, parms);
5237
5238 if (window_prompting & XNegative)
5239 {
5240 if (window_prompting & YNegative)
5241 f->output_data.w32->win_gravity = SouthEastGravity;
5242 else
5243 f->output_data.w32->win_gravity = NorthEastGravity;
5244 }
5245 else
5246 {
5247 if (window_prompting & YNegative)
5248 f->output_data.w32->win_gravity = SouthWestGravity;
5249 else
5250 f->output_data.w32->win_gravity = NorthWestGravity;
5251 }
5252
5253 f->output_data.w32->size_hint_flags = window_prompting;
5254
5255 tem = w32_get_arg (parms, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN);
5256 f->no_split = minibuffer_only || EQ (tem, Qt);
5257
5258 /* Create the window. Add the tool-bar height to the initial frame
5259 height so that the user gets a text display area of the size he
5260 specified with -g or via the registry. Later changes of the
5261 tool-bar height don't change the frame size. This is done so that
5262 users can create tall Emacs frames without having to guess how
5263 tall the tool-bar will get. */
5264 f->height += FRAME_TOOL_BAR_LINES (f);
5265 w32_window (f, window_prompting, minibuffer_only);
5266 x_icon (f, parms);
5267
5268 x_make_gc (f);
5269
5270 /* Now consider the frame official. */
5271 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
5272 Vframe_list = Fcons (frame, Vframe_list);
5273
5274 /* We need to do this after creating the window, so that the
5275 icon-creation functions can say whose icon they're describing. */
5276 x_default_parameter (f, parms, Qicon_type, Qnil,
5277 "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL);
5278
5279 x_default_parameter (f, parms, Qauto_raise, Qnil,
5280 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
5281 x_default_parameter (f, parms, Qauto_lower, Qnil,
5282 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
5283 x_default_parameter (f, parms, Qcursor_type, Qbox,
5284 "cursorType", "CursorType", RES_TYPE_SYMBOL);
5285 x_default_parameter (f, parms, Qscroll_bar_width, Qnil,
5286 "scrollBarWidth", "ScrollBarWidth", RES_TYPE_NUMBER);
5287
5288 /* Dimensions, especially f->height, must be done via change_frame_size.
5289 Change will not be effected unless different from the current
5290 f->height. */
5291 width = f->width;
5292 height = f->height;
5293 f->height = 0;
5294 SET_FRAME_WIDTH (f, 0);
5295 change_frame_size (f, height, width, 1, 0, 0);
5296
5297 /* Set up faces after all frame parameters are known. */
5298 call1 (Qface_set_after_frame_default, frame);
5299
5300 /* Tell the server what size and position, etc, we want, and how
5301 badly we want them. This should be done after we have the menu
5302 bar so that its size can be taken into account. */
5303 BLOCK_INPUT;
5304 x_wm_set_size_hint (f, window_prompting, 0);
5305 UNBLOCK_INPUT;
5306
5307 /* Make the window appear on the frame and enable display, unless
5308 the caller says not to. However, with explicit parent, Emacs
5309 cannot control visibility, so don't try. */
5310 if (! f->output_data.w32->explicit_parent)
5311 {
5312 Lisp_Object visibility;
5313
5314 visibility = w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL);
5315 if (EQ (visibility, Qunbound))
5316 visibility = Qt;
5317
5318 if (EQ (visibility, Qicon))
5319 x_iconify_frame (f);
5320 else if (! NILP (visibility))
5321 x_make_frame_visible (f);
5322 else
5323 /* Must have been Qnil. */
5324 ;
5325 }
5326 UNGCPRO;
5327 return unbind_to (count, frame);
5328 }
5329
5330 /* FRAME is used only to get a handle on the X display. We don't pass the
5331 display info directly because we're called from frame.c, which doesn't
5332 know about that structure. */
5333 Lisp_Object
5334 x_get_focus_frame (frame)
5335 struct frame *frame;
5336 {
5337 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (frame);
5338 Lisp_Object xfocus;
5339 if (! dpyinfo->w32_focus_frame)
5340 return Qnil;
5341
5342 XSETFRAME (xfocus, dpyinfo->w32_focus_frame);
5343 return xfocus;
5344 }
5345
5346 DEFUN ("w32-focus-frame", Fw32_focus_frame, Sw32_focus_frame, 1, 1, 0,
5347 "Give FRAME input focus, raising to foreground if necessary.")
5348 (frame)
5349 Lisp_Object frame;
5350 {
5351 x_focus_on_frame (check_x_frame (frame));
5352 return Qnil;
5353 }
5354
5355 \f
5356 struct font_info *w32_load_bdf_font (struct frame *f, char *fontname,
5357 int size, char* filename);
5358
5359 struct font_info *
5360 w32_load_system_font (f,fontname,size)
5361 struct frame *f;
5362 char * fontname;
5363 int size;
5364 {
5365 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
5366 Lisp_Object font_names;
5367
5368 /* Get a list of all the fonts that match this name. Once we
5369 have a list of matching fonts, we compare them against the fonts
5370 we already have loaded by comparing names. */
5371 font_names = w32_list_fonts (f, build_string (fontname), size, 100);
5372
5373 if (!NILP (font_names))
5374 {
5375 Lisp_Object tail;
5376 int i;
5377
5378 /* First check if any are already loaded, as that is cheaper
5379 than loading another one. */
5380 for (i = 0; i < dpyinfo->n_fonts; i++)
5381 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
5382 if (dpyinfo->font_table[i].name
5383 && (!strcmp (dpyinfo->font_table[i].name,
5384 XSTRING (XCAR (tail))->data)
5385 || !strcmp (dpyinfo->font_table[i].full_name,
5386 XSTRING (XCAR (tail))->data)))
5387 return (dpyinfo->font_table + i);
5388
5389 fontname = (char *) XSTRING (XCAR (font_names))->data;
5390 }
5391 else if (w32_strict_fontnames)
5392 {
5393 /* If EnumFontFamiliesEx was available, we got a full list of
5394 fonts back so stop now to avoid the possibility of loading a
5395 random font. If we had to fall back to EnumFontFamilies, the
5396 list is incomplete, so continue whether the font we want was
5397 listed or not. */
5398 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
5399 FARPROC enum_font_families_ex
5400 = GetProcAddress (gdi32, "EnumFontFamiliesExA");
5401 if (enum_font_families_ex)
5402 return NULL;
5403 }
5404
5405 /* Load the font and add it to the table. */
5406 {
5407 char *full_name, *encoding;
5408 XFontStruct *font;
5409 struct font_info *fontp;
5410 LOGFONT lf;
5411 BOOL ok;
5412 int i;
5413
5414 if (!fontname || !x_to_w32_font (fontname, &lf))
5415 return (NULL);
5416
5417 if (!*lf.lfFaceName)
5418 /* If no name was specified for the font, we get a random font
5419 from CreateFontIndirect - this is not particularly
5420 desirable, especially since CreateFontIndirect does not
5421 fill out the missing name in lf, so we never know what we
5422 ended up with. */
5423 return NULL;
5424
5425 font = (XFontStruct *) xmalloc (sizeof (XFontStruct));
5426
5427 /* Set bdf to NULL to indicate that this is a Windows font. */
5428 font->bdf = NULL;
5429
5430 BLOCK_INPUT;
5431
5432 font->hfont = CreateFontIndirect (&lf);
5433
5434 if (font->hfont == NULL)
5435 {
5436 ok = FALSE;
5437 }
5438 else
5439 {
5440 HDC hdc;
5441 HANDLE oldobj;
5442
5443 hdc = GetDC (dpyinfo->root_window);
5444 oldobj = SelectObject (hdc, font->hfont);
5445 ok = GetTextMetrics (hdc, &font->tm);
5446 font->double_byte_p = GetFontLanguageInfo(hdc) & GCP_DBCS;
5447 SelectObject (hdc, oldobj);
5448 ReleaseDC (dpyinfo->root_window, hdc);
5449 /* Fill out details in lf according to the font that was
5450 actually loaded. */
5451 lf.lfHeight = font->tm.tmInternalLeading - font->tm.tmHeight;
5452 lf.lfWidth = font->tm.tmAveCharWidth;
5453 lf.lfWeight = font->tm.tmWeight;
5454 lf.lfItalic = font->tm.tmItalic;
5455 lf.lfCharSet = font->tm.tmCharSet;
5456 lf.lfPitchAndFamily = ((font->tm.tmPitchAndFamily & TMPF_FIXED_PITCH)
5457 ? VARIABLE_PITCH : FIXED_PITCH);
5458 lf.lfOutPrecision = ((font->tm.tmPitchAndFamily & TMPF_VECTOR)
5459 ? OUT_STROKE_PRECIS : OUT_STRING_PRECIS);
5460 }
5461
5462 UNBLOCK_INPUT;
5463
5464 if (!ok)
5465 {
5466 w32_unload_font (dpyinfo, font);
5467 return (NULL);
5468 }
5469
5470 /* Find a free slot in the font table. */
5471 for (i = 0; i < dpyinfo->n_fonts; ++i)
5472 if (dpyinfo->font_table[i].name == NULL)
5473 break;
5474
5475 /* If no free slot found, maybe enlarge the font table. */
5476 if (i == dpyinfo->n_fonts
5477 && dpyinfo->n_fonts == dpyinfo->font_table_size)
5478 {
5479 int sz;
5480 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
5481 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
5482 dpyinfo->font_table
5483 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
5484 }
5485
5486 fontp = dpyinfo->font_table + i;
5487 if (i == dpyinfo->n_fonts)
5488 ++dpyinfo->n_fonts;
5489
5490 /* Now fill in the slots of *FONTP. */
5491 BLOCK_INPUT;
5492 fontp->font = font;
5493 fontp->font_idx = i;
5494 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
5495 bcopy (fontname, fontp->name, strlen (fontname) + 1);
5496
5497 /* Work out the font's full name. */
5498 full_name = (char *)xmalloc (100);
5499 if (full_name && w32_to_x_font (&lf, full_name, 100))
5500 fontp->full_name = full_name;
5501 else
5502 {
5503 /* If all else fails - just use the name we used to load it. */
5504 xfree (full_name);
5505 fontp->full_name = fontp->name;
5506 }
5507
5508 fontp->size = FONT_WIDTH (font);
5509 fontp->height = FONT_HEIGHT (font);
5510
5511 /* The slot `encoding' specifies how to map a character
5512 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
5513 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
5514 (0:0x20..0x7F, 1:0xA0..0xFF,
5515 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
5516 2:0xA020..0xFF7F). For the moment, we don't know which charset
5517 uses this font. So, we set information in fontp->encoding[1]
5518 which is never used by any charset. If mapping can't be
5519 decided, set FONT_ENCODING_NOT_DECIDED. */
5520
5521 /* SJIS fonts need to be set to type 4, all others seem to work as
5522 type FONT_ENCODING_NOT_DECIDED. */
5523 encoding = strrchr (fontp->name, '-');
5524 if (encoding && stricmp (encoding+1, "sjis") == 0)
5525 fontp->encoding[1] = 4;
5526 else
5527 fontp->encoding[1] = FONT_ENCODING_NOT_DECIDED;
5528
5529 /* The following three values are set to 0 under W32, which is
5530 what they get set to if XGetFontProperty fails under X. */
5531 fontp->baseline_offset = 0;
5532 fontp->relative_compose = 0;
5533 fontp->default_ascent = 0;
5534
5535 /* Set global flag fonts_changed_p to non-zero if the font loaded
5536 has a character with a smaller width than any other character
5537 before, or if the font loaded has a smalle>r height than any
5538 other font loaded before. If this happens, it will make a
5539 glyph matrix reallocation necessary. */
5540 fonts_changed_p = x_compute_min_glyph_bounds (f);
5541 UNBLOCK_INPUT;
5542 return fontp;
5543 }
5544 }
5545
5546 /* Load font named FONTNAME of size SIZE for frame F, and return a
5547 pointer to the structure font_info while allocating it dynamically.
5548 If loading fails, return NULL. */
5549 struct font_info *
5550 w32_load_font (f,fontname,size)
5551 struct frame *f;
5552 char * fontname;
5553 int size;
5554 {
5555 Lisp_Object bdf_fonts;
5556 struct font_info *retval = NULL;
5557
5558 bdf_fonts = w32_list_bdf_fonts (build_string (fontname));
5559
5560 while (!retval && CONSP (bdf_fonts))
5561 {
5562 char *bdf_name, *bdf_file;
5563 Lisp_Object bdf_pair;
5564
5565 bdf_name = XSTRING (XCAR (bdf_fonts))->data;
5566 bdf_pair = Fassoc (XCAR (bdf_fonts), Vw32_bdf_filename_alist);
5567 bdf_file = XSTRING (XCDR (bdf_pair))->data;
5568
5569 retval = w32_load_bdf_font (f, bdf_name, size, bdf_file);
5570
5571 bdf_fonts = XCDR (bdf_fonts);
5572 }
5573
5574 if (retval)
5575 return retval;
5576
5577 return w32_load_system_font(f, fontname, size);
5578 }
5579
5580
5581 void
5582 w32_unload_font (dpyinfo, font)
5583 struct w32_display_info *dpyinfo;
5584 XFontStruct * font;
5585 {
5586 if (font)
5587 {
5588 if (font->bdf) w32_free_bdf_font (font->bdf);
5589
5590 if (font->hfont) DeleteObject(font->hfont);
5591 xfree (font);
5592 }
5593 }
5594
5595 /* The font conversion stuff between x and w32 */
5596
5597 /* X font string is as follows (from faces.el)
5598 * (let ((- "[-?]")
5599 * (foundry "[^-]+")
5600 * (family "[^-]+")
5601 * (weight "\\(bold\\|demibold\\|medium\\)") ; 1
5602 * (weight\? "\\([^-]*\\)") ; 1
5603 * (slant "\\([ior]\\)") ; 2
5604 * (slant\? "\\([^-]?\\)") ; 2
5605 * (swidth "\\([^-]*\\)") ; 3
5606 * (adstyle "[^-]*") ; 4
5607 * (pixelsize "[0-9]+")
5608 * (pointsize "[0-9][0-9]+")
5609 * (resx "[0-9][0-9]+")
5610 * (resy "[0-9][0-9]+")
5611 * (spacing "[cmp?*]")
5612 * (avgwidth "[0-9]+")
5613 * (registry "[^-]+")
5614 * (encoding "[^-]+")
5615 * )
5616 * (setq x-font-regexp
5617 * (concat "\\`\\*?[-?*]"
5618 * foundry - family - weight\? - slant\? - swidth - adstyle -
5619 * pixelsize - pointsize - resx - resy - spacing - registry -
5620 * encoding "[-?*]\\*?\\'"
5621 * ))
5622 * (setq x-font-regexp-head
5623 * (concat "\\`[-?*]" foundry - family - weight\? - slant\?
5624 * "\\([-*?]\\|\\'\\)"))
5625 * (setq x-font-regexp-slant (concat - slant -))
5626 * (setq x-font-regexp-weight (concat - weight -))
5627 * nil)
5628 */
5629
5630 #define FONT_START "[-?]"
5631 #define FONT_FOUNDRY "[^-]+"
5632 #define FONT_FAMILY "\\([^-]+\\)" /* 1 */
5633 #define FONT_WEIGHT "\\(bold\\|demibold\\|medium\\)" /* 2 */
5634 #define FONT_WEIGHT_Q "\\([^-]*\\)" /* 2 */
5635 #define FONT_SLANT "\\([ior]\\)" /* 3 */
5636 #define FONT_SLANT_Q "\\([^-]?\\)" /* 3 */
5637 #define FONT_SWIDTH "\\([^-]*\\)" /* 4 */
5638 #define FONT_ADSTYLE "[^-]*"
5639 #define FONT_PIXELSIZE "[^-]*"
5640 #define FONT_POINTSIZE "\\([0-9][0-9]+\\|\\*\\)" /* 5 */
5641 #define FONT_RESX "[0-9][0-9]+"
5642 #define FONT_RESY "[0-9][0-9]+"
5643 #define FONT_SPACING "[cmp?*]"
5644 #define FONT_AVGWIDTH "[0-9]+"
5645 #define FONT_REGISTRY "[^-]+"
5646 #define FONT_ENCODING "[^-]+"
5647
5648 #define FONT_REGEXP ("\\`\\*?[-?*]" \
5649 FONT_FOUNDRY "-" \
5650 FONT_FAMILY "-" \
5651 FONT_WEIGHT_Q "-" \
5652 FONT_SLANT_Q "-" \
5653 FONT_SWIDTH "-" \
5654 FONT_ADSTYLE "-" \
5655 FONT_PIXELSIZE "-" \
5656 FONT_POINTSIZE "-" \
5657 "[-?*]\\|\\'")
5658
5659 #define FONT_REGEXP_HEAD ("\\`[-?*]" \
5660 FONT_FOUNDRY "-" \
5661 FONT_FAMILY "-" \
5662 FONT_WEIGHT_Q "-" \
5663 FONT_SLANT_Q \
5664 "\\([-*?]\\|\\'\\)")
5665
5666 #define FONT_REGEXP_SLANT "-" FONT_SLANT "-"
5667 #define FONT_REGEXP_WEIGHT "-" FONT_WEIGHT "-"
5668
5669 LONG
5670 x_to_w32_weight (lpw)
5671 char * lpw;
5672 {
5673 if (!lpw) return (FW_DONTCARE);
5674
5675 if (stricmp (lpw,"heavy") == 0) return FW_HEAVY;
5676 else if (stricmp (lpw,"extrabold") == 0) return FW_EXTRABOLD;
5677 else if (stricmp (lpw,"bold") == 0) return FW_BOLD;
5678 else if (stricmp (lpw,"demibold") == 0) return FW_SEMIBOLD;
5679 else if (stricmp (lpw,"semibold") == 0) return FW_SEMIBOLD;
5680 else if (stricmp (lpw,"medium") == 0) return FW_MEDIUM;
5681 else if (stricmp (lpw,"normal") == 0) return FW_NORMAL;
5682 else if (stricmp (lpw,"light") == 0) return FW_LIGHT;
5683 else if (stricmp (lpw,"extralight") == 0) return FW_EXTRALIGHT;
5684 else if (stricmp (lpw,"thin") == 0) return FW_THIN;
5685 else
5686 return FW_DONTCARE;
5687 }
5688
5689
5690 char *
5691 w32_to_x_weight (fnweight)
5692 int fnweight;
5693 {
5694 if (fnweight >= FW_HEAVY) return "heavy";
5695 if (fnweight >= FW_EXTRABOLD) return "extrabold";
5696 if (fnweight >= FW_BOLD) return "bold";
5697 if (fnweight >= FW_SEMIBOLD) return "demibold";
5698 if (fnweight >= FW_MEDIUM) return "medium";
5699 if (fnweight >= FW_NORMAL) return "normal";
5700 if (fnweight >= FW_LIGHT) return "light";
5701 if (fnweight >= FW_EXTRALIGHT) return "extralight";
5702 if (fnweight >= FW_THIN) return "thin";
5703 else
5704 return "*";
5705 }
5706
5707 LONG
5708 x_to_w32_charset (lpcs)
5709 char * lpcs;
5710 {
5711 Lisp_Object rest;
5712
5713 /* Look through w32-charset-info-alist for the character set.
5714 Format of each entry is
5715 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
5716 */
5717 for (rest = Vw32_charset_info_alist; CONSP (rest); rest = XCDR (rest))
5718 {
5719 Lisp_Object this_entry = XCAR (rest);
5720 char * x_charset = XSTRING (XCAR (this_entry))->data;
5721
5722 if (strnicmp (lpcs, x_charset, strlen(x_charset)) == 0)
5723 {
5724 Lisp_Object w32_charset = XCAR (XCDR (this_entry));
5725 // Translate Lisp symbol to number.
5726 if (w32_charset == Qw32_charset_ansi)
5727 return ANSI_CHARSET;
5728 if (w32_charset == Qw32_charset_symbol)
5729 return SYMBOL_CHARSET;
5730 if (w32_charset == Qw32_charset_shiftjis)
5731 return SHIFTJIS_CHARSET;
5732 if (w32_charset == Qw32_charset_hangul)
5733 return HANGEUL_CHARSET;
5734 if (w32_charset == Qw32_charset_chinesebig5)
5735 return CHINESEBIG5_CHARSET;
5736 if (w32_charset == Qw32_charset_gb2312)
5737 return GB2312_CHARSET;
5738 if (w32_charset == Qw32_charset_oem)
5739 return OEM_CHARSET;
5740 #ifdef JOHAB_CHARSET
5741 if (w32_charset == Qw32_charset_johab)
5742 return JOHAB_CHARSET;
5743 if (w32_charset == Qw32_charset_easteurope)
5744 return EASTEUROPE_CHARSET;
5745 if (w32_charset == Qw32_charset_turkish)
5746 return TURKISH_CHARSET;
5747 if (w32_charset == Qw32_charset_baltic)
5748 return BALTIC_CHARSET;
5749 if (w32_charset == Qw32_charset_russian)
5750 return RUSSIAN_CHARSET;
5751 if (w32_charset == Qw32_charset_arabic)
5752 return ARABIC_CHARSET;
5753 if (w32_charset == Qw32_charset_greek)
5754 return GREEK_CHARSET;
5755 if (w32_charset == Qw32_charset_hebrew)
5756 return HEBREW_CHARSET;
5757 if (w32_charset == Qw32_charset_thai)
5758 return THAI_CHARSET;
5759 if (w32_charset == Qw32_charset_mac)
5760 return MAC_CHARSET;
5761 #endif /* JOHAB_CHARSET */
5762 #ifdef UNICODE_CHARSET
5763 if (w32_charset == Qw32_charset_unicode)
5764 return UNICODE_CHARSET;
5765 #endif
5766 }
5767 }
5768
5769 return DEFAULT_CHARSET;
5770 }
5771
5772
5773 char *
5774 w32_to_x_charset (fncharset)
5775 int fncharset;
5776 {
5777 static char buf[16];
5778
5779 /* NTEMACS_TODO: use w32-charset-info-alist. Multiple matches
5780 are possible, so this will require more than just a rewrite of
5781 this function. w32_to_x_font is the only user of this function,
5782 and that will require rewriting too, and its users. */
5783 switch (fncharset)
5784 {
5785 /* ansi is considered iso8859-1, as most modern ansi fonts are. */
5786 case ANSI_CHARSET: return "iso8859-1";
5787 case DEFAULT_CHARSET: return "ascii-*";
5788 case SYMBOL_CHARSET: return "ms-symbol";
5789 case SHIFTJIS_CHARSET: return "jisx0208-sjis";
5790 case HANGEUL_CHARSET: return "ksc5601.1987-*";
5791 case GB2312_CHARSET: return "gb2312-*";
5792 case CHINESEBIG5_CHARSET: return "big5-*";
5793 case OEM_CHARSET: return "ms-oem";
5794
5795 /* More recent versions of Windows (95 and NT4.0) define more
5796 character sets. */
5797 #ifdef EASTEUROPE_CHARSET
5798 case EASTEUROPE_CHARSET: return "iso8859-2";
5799 case TURKISH_CHARSET: return "iso8859-9";
5800 case BALTIC_CHARSET: return "iso8859-4";
5801
5802 /* W95 with international support but not IE4 often has the
5803 KOI8-R codepage but not ISO8859-5. */
5804 case RUSSIAN_CHARSET:
5805 if (!IsValidCodePage(28595) && IsValidCodePage(20886))
5806 return "koi8-r";
5807 else
5808 return "iso8859-5";
5809 case ARABIC_CHARSET: return "iso8859-6";
5810 case GREEK_CHARSET: return "iso8859-7";
5811 case HEBREW_CHARSET: return "iso8859-8";
5812 case VIETNAMESE_CHARSET: return "viscii1.1-*";
5813 case THAI_CHARSET: return "tis620-*";
5814 case MAC_CHARSET: return "mac-*";
5815 case JOHAB_CHARSET: return "ksc5601.1992-*";
5816
5817 #endif
5818
5819 #ifdef UNICODE_CHARSET
5820 case UNICODE_CHARSET: return "iso10646-unicode";
5821 #endif
5822 }
5823 /* Encode numerical value of unknown charset. */
5824 sprintf (buf, "*-#%u", fncharset);
5825 return buf;
5826 }
5827
5828
5829 /* Get the Windows codepage corresponding to the specified font. The
5830 charset info in the font name is used to look up
5831 w32-charset-to-codepage-alist. */
5832 int
5833 w32_codepage_for_font (char *fontname)
5834 {
5835 Lisp_Object codepage;
5836 char charset_str[20], *charset, *end;
5837
5838 /* Extract charset part of font string. */
5839 if (sscanf (fontname,
5840 "-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%19s",
5841 charset_str) == EOF)
5842 return CP_DEFAULT;
5843
5844 /* Remove leading "*-". */
5845 if (strncmp ("*-", charset_str, 2) == 0)
5846 charset = charset_str + 2;
5847 else
5848 charset = charset_str;
5849
5850 /* Stop match at wildcard (including preceding '-'). */
5851 if (end = strchr (charset, '*'))
5852 {
5853 if (end > charset && *(end-1) == '-')
5854 end--;
5855 *end = '\0';
5856 }
5857
5858 codepage = Fcdr (Fcdr (Fassoc (build_string(charset),
5859 Vw32_charset_info_alist)));
5860 if (INTEGERP (codepage))
5861 return XINT (codepage);
5862 else
5863 return CP_DEFAULT;
5864 }
5865
5866
5867 BOOL
5868 w32_to_x_font (lplogfont, lpxstr, len)
5869 LOGFONT * lplogfont;
5870 char * lpxstr;
5871 int len;
5872 {
5873 char* fonttype;
5874 char *fontname;
5875 char height_pixels[8];
5876 char height_dpi[8];
5877 char width_pixels[8];
5878 char *fontname_dash;
5879 int display_resy = one_w32_display_info.resy;
5880 int display_resx = one_w32_display_info.resx;
5881 int bufsz;
5882 struct coding_system coding;
5883
5884 if (!lpxstr) abort ();
5885
5886 if (!lplogfont)
5887 return FALSE;
5888
5889 if (lplogfont->lfOutPrecision == OUT_STRING_PRECIS)
5890 fonttype = "raster";
5891 else if (lplogfont->lfOutPrecision == OUT_STROKE_PRECIS)
5892 fonttype = "outline";
5893 else
5894 fonttype = "unknown";
5895
5896 setup_coding_system (Fcheck_coding_system (Vw32_system_coding_system),
5897 &coding);
5898 coding.src_multibyte = 0;
5899 coding.dst_multibyte = 1;
5900 coding.mode |= CODING_MODE_LAST_BLOCK;
5901 bufsz = decoding_buffer_size (&coding, LF_FACESIZE);
5902
5903 fontname = alloca(sizeof(*fontname) * bufsz);
5904 decode_coding (&coding, lplogfont->lfFaceName, fontname,
5905 strlen(lplogfont->lfFaceName), bufsz - 1);
5906 *(fontname + coding.produced) = '\0';
5907
5908 /* Replace dashes with underscores so the dashes are not
5909 misinterpreted. */
5910 fontname_dash = fontname;
5911 while (fontname_dash = strchr (fontname_dash, '-'))
5912 *fontname_dash = '_';
5913
5914 if (lplogfont->lfHeight)
5915 {
5916 sprintf (height_pixels, "%u", abs (lplogfont->lfHeight));
5917 sprintf (height_dpi, "%u",
5918 abs (lplogfont->lfHeight) * 720 / display_resy);
5919 }
5920 else
5921 {
5922 strcpy (height_pixels, "*");
5923 strcpy (height_dpi, "*");
5924 }
5925 if (lplogfont->lfWidth)
5926 sprintf (width_pixels, "%u", lplogfont->lfWidth * 10);
5927 else
5928 strcpy (width_pixels, "*");
5929
5930 _snprintf (lpxstr, len - 1,
5931 "-%s-%s-%s-%c-normal-normal-%s-%s-%d-%d-%c-%s-%s",
5932 fonttype, /* foundry */
5933 fontname, /* family */
5934 w32_to_x_weight (lplogfont->lfWeight), /* weight */
5935 lplogfont->lfItalic?'i':'r', /* slant */
5936 /* setwidth name */
5937 /* add style name */
5938 height_pixels, /* pixel size */
5939 height_dpi, /* point size */
5940 display_resx, /* resx */
5941 display_resy, /* resy */
5942 ((lplogfont->lfPitchAndFamily & 0x3) == VARIABLE_PITCH)
5943 ? 'p' : 'c', /* spacing */
5944 width_pixels, /* avg width */
5945 w32_to_x_charset (lplogfont->lfCharSet) /* charset registry
5946 and encoding*/
5947 );
5948
5949 lpxstr[len - 1] = 0; /* just to be sure */
5950 return (TRUE);
5951 }
5952
5953 BOOL
5954 x_to_w32_font (lpxstr, lplogfont)
5955 char * lpxstr;
5956 LOGFONT * lplogfont;
5957 {
5958 struct coding_system coding;
5959
5960 if (!lplogfont) return (FALSE);
5961
5962 memset (lplogfont, 0, sizeof (*lplogfont));
5963
5964 /* Set default value for each field. */
5965 #if 1
5966 lplogfont->lfOutPrecision = OUT_DEFAULT_PRECIS;
5967 lplogfont->lfClipPrecision = CLIP_DEFAULT_PRECIS;
5968 lplogfont->lfQuality = DEFAULT_QUALITY;
5969 #else
5970 /* go for maximum quality */
5971 lplogfont->lfOutPrecision = OUT_STROKE_PRECIS;
5972 lplogfont->lfClipPrecision = CLIP_STROKE_PRECIS;
5973 lplogfont->lfQuality = PROOF_QUALITY;
5974 #endif
5975
5976 lplogfont->lfCharSet = DEFAULT_CHARSET;
5977 lplogfont->lfWeight = FW_DONTCARE;
5978 lplogfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
5979
5980 if (!lpxstr)
5981 return FALSE;
5982
5983 /* Provide a simple escape mechanism for specifying Windows font names
5984 * directly -- if font spec does not beginning with '-', assume this
5985 * format:
5986 * "<font name>[:height in pixels[:width in pixels[:weight]]]"
5987 */
5988
5989 if (*lpxstr == '-')
5990 {
5991 int fields, tem;
5992 char name[50], weight[20], slant, pitch, pixels[10], height[10],
5993 width[10], resy[10], remainder[20];
5994 char * encoding;
5995 int dpi = one_w32_display_info.height_in;
5996
5997 fields = sscanf (lpxstr,
5998 "-%*[^-]-%49[^-]-%19[^-]-%c-%*[^-]-%*[^-]-%9[^-]-%9[^-]-%*[^-]-%9[^-]-%c-%9[^-]-%19s",
5999 name, weight, &slant, pixels, height, resy, &pitch, width, remainder);
6000 if (fields == EOF) return (FALSE);
6001
6002 /* If wildcards cover more than one field, we don't know which
6003 field is which, so don't fill any in. */
6004
6005 if (fields < 9)
6006 fields = 0;
6007
6008 if (fields > 0 && name[0] != '*')
6009 {
6010 int bufsize;
6011 unsigned char *buf;
6012
6013 setup_coding_system
6014 (Fcheck_coding_system (Vw32_system_coding_system), &coding);
6015 coding.src_multibyte = 1;
6016 coding.dst_multibyte = 1;
6017 bufsize = encoding_buffer_size (&coding, strlen (name));
6018 buf = (unsigned char *) alloca (bufsize);
6019 coding.mode |= CODING_MODE_LAST_BLOCK;
6020 encode_coding (&coding, name, buf, strlen (name), bufsize);
6021 if (coding.produced >= LF_FACESIZE)
6022 coding.produced = LF_FACESIZE - 1;
6023 buf[coding.produced] = 0;
6024 strcpy (lplogfont->lfFaceName, buf);
6025 }
6026 else
6027 {
6028 lplogfont->lfFaceName[0] = '\0';
6029 }
6030
6031 fields--;
6032
6033 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
6034
6035 fields--;
6036
6037 if (!NILP (Vw32_enable_synthesized_fonts))
6038 lplogfont->lfItalic = (fields > 0 && slant == 'i');
6039
6040 fields--;
6041
6042 if (fields > 0 && pixels[0] != '*')
6043 lplogfont->lfHeight = atoi (pixels);
6044
6045 fields--;
6046 fields--;
6047 if (fields > 0 && resy[0] != '*')
6048 {
6049 tem = atoi (resy);
6050 if (tem > 0) dpi = tem;
6051 }
6052
6053 if (fields > -1 && lplogfont->lfHeight == 0 && height[0] != '*')
6054 lplogfont->lfHeight = atoi (height) * dpi / 720;
6055
6056 if (fields > 0)
6057 lplogfont->lfPitchAndFamily =
6058 (fields > 0 && pitch == 'p') ? VARIABLE_PITCH : FIXED_PITCH;
6059
6060 fields--;
6061
6062 if (fields > 0 && width[0] != '*')
6063 lplogfont->lfWidth = atoi (width) / 10;
6064
6065 fields--;
6066
6067 /* Strip the trailing '-' if present. (it shouldn't be, as it
6068 fails the test against xlfd-tight-regexp in fontset.el). */
6069 {
6070 int len = strlen (remainder);
6071 if (len > 0 && remainder[len-1] == '-')
6072 remainder[len-1] = 0;
6073 }
6074 encoding = remainder;
6075 if (strncmp (encoding, "*-", 2) == 0)
6076 encoding += 2;
6077 lplogfont->lfCharSet = x_to_w32_charset (fields > 0 ? encoding : "");
6078 }
6079 else
6080 {
6081 int fields;
6082 char name[100], height[10], width[10], weight[20];
6083
6084 fields = sscanf (lpxstr,
6085 "%99[^:]:%9[^:]:%9[^:]:%19s",
6086 name, height, width, weight);
6087
6088 if (fields == EOF) return (FALSE);
6089
6090 if (fields > 0)
6091 {
6092 strncpy (lplogfont->lfFaceName,name, LF_FACESIZE);
6093 lplogfont->lfFaceName[LF_FACESIZE-1] = 0;
6094 }
6095 else
6096 {
6097 lplogfont->lfFaceName[0] = 0;
6098 }
6099
6100 fields--;
6101
6102 if (fields > 0)
6103 lplogfont->lfHeight = atoi (height);
6104
6105 fields--;
6106
6107 if (fields > 0)
6108 lplogfont->lfWidth = atoi (width);
6109
6110 fields--;
6111
6112 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
6113 }
6114
6115 /* This makes TrueType fonts work better. */
6116 lplogfont->lfHeight = - abs (lplogfont->lfHeight);
6117
6118 return (TRUE);
6119 }
6120
6121 /* Strip the pixel height and point height from the given xlfd, and
6122 return the pixel height. If no pixel height is specified, calculate
6123 one from the point height, or if that isn't defined either, return
6124 0 (which usually signifies a scalable font).
6125 */
6126 int xlfd_strip_height (char *fontname)
6127 {
6128 int pixel_height, point_height, dpi, field_number;
6129 char *read_from, *write_to;
6130
6131 xassert (fontname);
6132
6133 pixel_height = field_number = 0;
6134 write_to = NULL;
6135
6136 /* Look for height fields. */
6137 for (read_from = fontname; *read_from; read_from++)
6138 {
6139 if (*read_from == '-')
6140 {
6141 field_number++;
6142 if (field_number == 7) /* Pixel height. */
6143 {
6144 read_from++;
6145 write_to = read_from;
6146
6147 /* Find end of field. */
6148 for (;*read_from && *read_from != '-'; read_from++)
6149 ;
6150
6151 /* Split the fontname at end of field. */
6152 if (*read_from)
6153 {
6154 *read_from = '\0';
6155 read_from++;
6156 }
6157 pixel_height = atoi (write_to);
6158 /* Blank out field. */
6159 if (read_from > write_to)
6160 {
6161 *write_to = '-';
6162 write_to++;
6163 }
6164 /* If the pixel height field is at the end (partial xfld),
6165 return now. */
6166 else
6167 return pixel_height;
6168
6169 /* If we got a pixel height, the point height can be
6170 ignored. Just blank it out and break now. */
6171 if (pixel_height)
6172 {
6173 /* Find end of point size field. */
6174 for (; *read_from && *read_from != '-'; read_from++)
6175 ;
6176
6177 if (*read_from)
6178 read_from++;
6179
6180 /* Blank out the point size field. */
6181 if (read_from > write_to)
6182 {
6183 *write_to = '-';
6184 write_to++;
6185 }
6186 else
6187 return pixel_height;
6188
6189 break;
6190 }
6191 /* If the point height is already blank, break now. */
6192 if (*read_from == '-')
6193 {
6194 read_from++;
6195 break;
6196 }
6197 }
6198 else if (field_number == 8)
6199 {
6200 /* If we didn't get a pixel height, try to get the point
6201 height and convert that. */
6202 int point_size;
6203 char *point_size_start = read_from++;
6204
6205 /* Find end of field. */
6206 for (; *read_from && *read_from != '-'; read_from++)
6207 ;
6208
6209 if (*read_from)
6210 {
6211 *read_from = '\0';
6212 read_from++;
6213 }
6214
6215 point_size = atoi (point_size_start);
6216
6217 /* Convert to pixel height. */
6218 pixel_height = point_size
6219 * one_w32_display_info.height_in / 720;
6220
6221 /* Blank out this field and break. */
6222 *write_to = '-';
6223 write_to++;
6224 break;
6225 }
6226 }
6227 }
6228
6229 /* Shift the rest of the font spec into place. */
6230 if (write_to && read_from > write_to)
6231 {
6232 for (; *read_from; read_from++, write_to++)
6233 *write_to = *read_from;
6234 *write_to = '\0';
6235 }
6236
6237 return pixel_height;
6238 }
6239
6240 /* Assume parameter 1 is fully qualified, no wildcards. */
6241 BOOL
6242 w32_font_match (fontname, pattern)
6243 char * fontname;
6244 char * pattern;
6245 {
6246 char *regex = alloca (strlen (pattern) * 2);
6247 char *font_name_copy = alloca (strlen (fontname) + 1);
6248 char *ptr;
6249
6250 /* Copy fontname so we can modify it during comparison. */
6251 strcpy (font_name_copy, fontname);
6252
6253 ptr = regex;
6254 *ptr++ = '^';
6255
6256 /* Turn pattern into a regexp and do a regexp match. */
6257 for (; *pattern; pattern++)
6258 {
6259 if (*pattern == '?')
6260 *ptr++ = '.';
6261 else if (*pattern == '*')
6262 {
6263 *ptr++ = '.';
6264 *ptr++ = '*';
6265 }
6266 else
6267 *ptr++ = *pattern;
6268 }
6269 *ptr = '$';
6270 *(ptr + 1) = '\0';
6271
6272 /* Strip out font heights and compare them seperately, since
6273 rounding error can cause mismatches. This also allows a
6274 comparison between a font that declares only a pixel height and a
6275 pattern that declares the point height.
6276 */
6277 {
6278 int font_height, pattern_height;
6279
6280 font_height = xlfd_strip_height (font_name_copy);
6281 pattern_height = xlfd_strip_height (regex);
6282
6283 /* Compare now, and don't bother doing expensive regexp matching
6284 if the heights differ. */
6285 if (font_height && pattern_height && (font_height != pattern_height))
6286 return FALSE;
6287 }
6288
6289 return (fast_c_string_match_ignore_case (build_string (regex),
6290 font_name_copy) >= 0);
6291 }
6292
6293 /* Callback functions, and a structure holding info they need, for
6294 listing system fonts on W32. We need one set of functions to do the
6295 job properly, but these don't work on NT 3.51 and earlier, so we
6296 have a second set which don't handle character sets properly to
6297 fall back on.
6298
6299 In both cases, there are two passes made. The first pass gets one
6300 font from each family, the second pass lists all the fonts from
6301 each family. */
6302
6303 typedef struct enumfont_t
6304 {
6305 HDC hdc;
6306 int numFonts;
6307 LOGFONT logfont;
6308 XFontStruct *size_ref;
6309 Lisp_Object *pattern;
6310 Lisp_Object *tail;
6311 } enumfont_t;
6312
6313 int CALLBACK
6314 enum_font_cb2 (lplf, lptm, FontType, lpef)
6315 ENUMLOGFONT * lplf;
6316 NEWTEXTMETRIC * lptm;
6317 int FontType;
6318 enumfont_t * lpef;
6319 {
6320 if (lplf->elfLogFont.lfStrikeOut || lplf->elfLogFont.lfUnderline)
6321 return (1);
6322
6323 /* Check that the character set matches if it was specified */
6324 if (lpef->logfont.lfCharSet != DEFAULT_CHARSET &&
6325 lplf->elfLogFont.lfCharSet != lpef->logfont.lfCharSet)
6326 return (1);
6327
6328 {
6329 char buf[100];
6330 Lisp_Object width = Qnil;
6331
6332 /* Truetype fonts do not report their true metrics until loaded */
6333 if (FontType != RASTER_FONTTYPE)
6334 {
6335 if (!NILP (*(lpef->pattern)))
6336 {
6337 /* Scalable fonts are as big as you want them to be. */
6338 lplf->elfLogFont.lfHeight = lpef->logfont.lfHeight;
6339 lplf->elfLogFont.lfWidth = lpef->logfont.lfWidth;
6340 width = make_number (lpef->logfont.lfWidth);
6341 }
6342 else
6343 {
6344 lplf->elfLogFont.lfHeight = 0;
6345 lplf->elfLogFont.lfWidth = 0;
6346 }
6347 }
6348
6349 /* Make sure the height used here is the same as everywhere
6350 else (ie character height, not cell height). */
6351 if (lplf->elfLogFont.lfHeight > 0)
6352 {
6353 /* lptm can be trusted for RASTER fonts, but not scalable ones. */
6354 if (FontType == RASTER_FONTTYPE)
6355 lplf->elfLogFont.lfHeight = lptm->tmInternalLeading - lptm->tmHeight;
6356 else
6357 lplf->elfLogFont.lfHeight = -lplf->elfLogFont.lfHeight;
6358 }
6359
6360 if (!w32_to_x_font (&(lplf->elfLogFont), buf, 100))
6361 return (0);
6362
6363 if (NILP (*(lpef->pattern))
6364 || w32_font_match (buf, XSTRING (*(lpef->pattern))->data))
6365 {
6366 *lpef->tail = Fcons (Fcons (build_string (buf), width), Qnil);
6367 lpef->tail = &(XCDR (*lpef->tail));
6368 lpef->numFonts++;
6369 }
6370 }
6371
6372 return (1);
6373 }
6374
6375 int CALLBACK
6376 enum_font_cb1 (lplf, lptm, FontType, lpef)
6377 ENUMLOGFONT * lplf;
6378 NEWTEXTMETRIC * lptm;
6379 int FontType;
6380 enumfont_t * lpef;
6381 {
6382 return EnumFontFamilies (lpef->hdc,
6383 lplf->elfLogFont.lfFaceName,
6384 (FONTENUMPROC) enum_font_cb2,
6385 (LPARAM) lpef);
6386 }
6387
6388
6389 int CALLBACK
6390 enum_fontex_cb2 (lplf, lptm, font_type, lpef)
6391 ENUMLOGFONTEX * lplf;
6392 NEWTEXTMETRICEX * lptm;
6393 int font_type;
6394 enumfont_t * lpef;
6395 {
6396 /* We are not interested in the extra info we get back from the 'Ex
6397 version - only the fact that we get character set variations
6398 enumerated seperately. */
6399 return enum_font_cb2 ((ENUMLOGFONT *) lplf, (NEWTEXTMETRIC *) lptm,
6400 font_type, lpef);
6401 }
6402
6403 int CALLBACK
6404 enum_fontex_cb1 (lplf, lptm, font_type, lpef)
6405 ENUMLOGFONTEX * lplf;
6406 NEWTEXTMETRICEX * lptm;
6407 int font_type;
6408 enumfont_t * lpef;
6409 {
6410 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
6411 FARPROC enum_font_families_ex
6412 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
6413 /* We don't really expect EnumFontFamiliesEx to disappear once we
6414 get here, so don't bother handling it gracefully. */
6415 if (enum_font_families_ex == NULL)
6416 error ("gdi32.dll has disappeared!");
6417 return enum_font_families_ex (lpef->hdc,
6418 &lplf->elfLogFont,
6419 (FONTENUMPROC) enum_fontex_cb2,
6420 (LPARAM) lpef, 0);
6421 }
6422
6423 /* Interface to fontset handler. (adapted from mw32font.c in Meadow
6424 and xterm.c in Emacs 20.3) */
6425
6426 Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names)
6427 {
6428 char *fontname, *ptnstr;
6429 Lisp_Object list, tem, newlist = Qnil;
6430 int n_fonts = 0;
6431
6432 list = Vw32_bdf_filename_alist;
6433 ptnstr = XSTRING (pattern)->data;
6434
6435 for ( ; CONSP (list); list = XCDR (list))
6436 {
6437 tem = XCAR (list);
6438 if (CONSP (tem))
6439 fontname = XSTRING (XCAR (tem))->data;
6440 else if (STRINGP (tem))
6441 fontname = XSTRING (tem)->data;
6442 else
6443 continue;
6444
6445 if (w32_font_match (fontname, ptnstr))
6446 {
6447 newlist = Fcons (XCAR (tem), newlist);
6448 n_fonts++;
6449 if (n_fonts >= max_names)
6450 break;
6451 }
6452 }
6453
6454 return newlist;
6455 }
6456
6457 Lisp_Object w32_list_synthesized_fonts (FRAME_PTR f, Lisp_Object pattern,
6458 int size, int max_names);
6459
6460 /* Return a list of names of available fonts matching PATTERN on frame
6461 F. If SIZE is not 0, it is the size (maximum bound width) of fonts
6462 to be listed. Frame F NULL means we have not yet created any
6463 frame, which means we can't get proper size info, as we don't have
6464 a device context to use for GetTextMetrics.
6465 MAXNAMES sets a limit on how many fonts to match. */
6466
6467 Lisp_Object
6468 w32_list_fonts (FRAME_PTR f, Lisp_Object pattern, int size, int maxnames )
6469 {
6470 Lisp_Object patterns, key = Qnil, tem, tpat;
6471 Lisp_Object list = Qnil, newlist = Qnil, second_best = Qnil;
6472 struct w32_display_info *dpyinfo = &one_w32_display_info;
6473 int n_fonts = 0;
6474
6475 patterns = Fassoc (pattern, Valternate_fontname_alist);
6476 if (NILP (patterns))
6477 patterns = Fcons (pattern, Qnil);
6478
6479 for (; CONSP (patterns); patterns = XCDR (patterns))
6480 {
6481 enumfont_t ef;
6482
6483 tpat = XCAR (patterns);
6484
6485 /* See if we cached the result for this particular query.
6486 The cache is an alist of the form:
6487 ((PATTERN (FONTNAME . WIDTH) ...) ...)
6488 */
6489 if (tem = XCDR (dpyinfo->name_list_element),
6490 !NILP (list = Fassoc (tpat, tem)))
6491 {
6492 list = Fcdr_safe (list);
6493 /* We have a cached list. Don't have to get the list again. */
6494 goto label_cached;
6495 }
6496
6497 BLOCK_INPUT;
6498 /* At first, put PATTERN in the cache. */
6499 list = Qnil;
6500 ef.pattern = &tpat;
6501 ef.tail = &list;
6502 ef.numFonts = 0;
6503
6504 /* Use EnumFontFamiliesEx where it is available, as it knows
6505 about character sets. Fall back to EnumFontFamilies for
6506 older versions of NT that don't support the 'Ex function. */
6507 x_to_w32_font (STRINGP (tpat) ? XSTRING (tpat)->data :
6508 NULL, &ef.logfont);
6509 {
6510 LOGFONT font_match_pattern;
6511 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
6512 FARPROC enum_font_families_ex
6513 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
6514
6515 /* We do our own pattern matching so we can handle wildcards. */
6516 font_match_pattern.lfFaceName[0] = 0;
6517 font_match_pattern.lfPitchAndFamily = 0;
6518 /* We can use the charset, because if it is a wildcard it will
6519 be DEFAULT_CHARSET anyway. */
6520 font_match_pattern.lfCharSet = ef.logfont.lfCharSet;
6521
6522 ef.hdc = GetDC (dpyinfo->root_window);
6523
6524 if (enum_font_families_ex)
6525 enum_font_families_ex (ef.hdc,
6526 &font_match_pattern,
6527 (FONTENUMPROC) enum_fontex_cb1,
6528 (LPARAM) &ef, 0);
6529 else
6530 EnumFontFamilies (ef.hdc, NULL, (FONTENUMPROC) enum_font_cb1,
6531 (LPARAM)&ef);
6532
6533 ReleaseDC (dpyinfo->root_window, ef.hdc);
6534 }
6535
6536 UNBLOCK_INPUT;
6537
6538 /* Make a list of the fonts we got back.
6539 Store that in the font cache for the display. */
6540 XCDR (dpyinfo->name_list_element)
6541 = Fcons (Fcons (tpat, list),
6542 XCDR (dpyinfo->name_list_element));
6543
6544 label_cached:
6545 if (NILP (list)) continue; /* Try the remaining alternatives. */
6546
6547 newlist = second_best = Qnil;
6548
6549 /* Make a list of the fonts that have the right width. */
6550 for (; CONSP (list); list = XCDR (list))
6551 {
6552 int found_size;
6553 tem = XCAR (list);
6554
6555 if (!CONSP (tem))
6556 continue;
6557 if (NILP (XCAR (tem)))
6558 continue;
6559 if (!size)
6560 {
6561 newlist = Fcons (XCAR (tem), newlist);
6562 n_fonts++;
6563 if (n_fonts >= maxnames)
6564 break;
6565 else
6566 continue;
6567 }
6568 if (!INTEGERP (XCDR (tem)))
6569 {
6570 /* Since we don't yet know the size of the font, we must
6571 load it and try GetTextMetrics. */
6572 W32FontStruct thisinfo;
6573 LOGFONT lf;
6574 HDC hdc;
6575 HANDLE oldobj;
6576
6577 if (!x_to_w32_font (XSTRING (XCAR (tem))->data, &lf))
6578 continue;
6579
6580 BLOCK_INPUT;
6581 thisinfo.bdf = NULL;
6582 thisinfo.hfont = CreateFontIndirect (&lf);
6583 if (thisinfo.hfont == NULL)
6584 continue;
6585
6586 hdc = GetDC (dpyinfo->root_window);
6587 oldobj = SelectObject (hdc, thisinfo.hfont);
6588 if (GetTextMetrics (hdc, &thisinfo.tm))
6589 XCDR (tem) = make_number (FONT_WIDTH (&thisinfo));
6590 else
6591 XCDR (tem) = make_number (0);
6592 SelectObject (hdc, oldobj);
6593 ReleaseDC (dpyinfo->root_window, hdc);
6594 DeleteObject(thisinfo.hfont);
6595 UNBLOCK_INPUT;
6596 }
6597 found_size = XINT (XCDR (tem));
6598 if (found_size == size)
6599 {
6600 newlist = Fcons (XCAR (tem), newlist);
6601 n_fonts++;
6602 if (n_fonts >= maxnames)
6603 break;
6604 }
6605 /* keep track of the closest matching size in case
6606 no exact match is found. */
6607 else if (found_size > 0)
6608 {
6609 if (NILP (second_best))
6610 second_best = tem;
6611
6612 else if (found_size < size)
6613 {
6614 if (XINT (XCDR (second_best)) > size
6615 || XINT (XCDR (second_best)) < found_size)
6616 second_best = tem;
6617 }
6618 else
6619 {
6620 if (XINT (XCDR (second_best)) > size
6621 && XINT (XCDR (second_best)) >
6622 found_size)
6623 second_best = tem;
6624 }
6625 }
6626 }
6627
6628 if (!NILP (newlist))
6629 break;
6630 else if (!NILP (second_best))
6631 {
6632 newlist = Fcons (XCAR (second_best), Qnil);
6633 break;
6634 }
6635 }
6636
6637 /* Include any bdf fonts. */
6638 if (n_fonts < maxnames)
6639 {
6640 Lisp_Object combined[2];
6641 combined[0] = w32_list_bdf_fonts (pattern, maxnames - n_fonts);
6642 combined[1] = newlist;
6643 newlist = Fnconc(2, combined);
6644 }
6645
6646 /* If we can't find a font that matches, check if Windows would be
6647 able to synthesize it from a different style. */
6648 if (NILP (newlist) && !NILP (Vw32_enable_synthesized_fonts))
6649 newlist = w32_list_synthesized_fonts (f, pattern, size, maxnames);
6650
6651 return newlist;
6652 }
6653
6654 Lisp_Object
6655 w32_list_synthesized_fonts (f, pattern, size, max_names)
6656 FRAME_PTR f;
6657 Lisp_Object pattern;
6658 int size;
6659 int max_names;
6660 {
6661 int fields;
6662 char *full_pattn, *new_pattn, foundary[50], family[50], *pattn_part2;
6663 char style[20], slant;
6664 Lisp_Object matches, match, tem, synthed_matches = Qnil;
6665
6666 full_pattn = XSTRING (pattern)->data;
6667
6668 pattn_part2 = alloca (XSTRING (pattern)->size);
6669 /* Allow some space for wildcard expansion. */
6670 new_pattn = alloca (XSTRING (pattern)->size + 100);
6671
6672 fields = sscanf (full_pattn, "-%49[^-]-%49[^-]-%19[^-]-%c-%s",
6673 foundary, family, style, &slant, pattn_part2);
6674 if (fields == EOF || fields < 5)
6675 return Qnil;
6676
6677 /* If the style and slant are wildcards already there is no point
6678 checking again (and we don't want to keep recursing). */
6679 if (*style == '*' && slant == '*')
6680 return Qnil;
6681
6682 sprintf (new_pattn, "-%s-%s-*-*-%s", foundary, family, pattn_part2);
6683
6684 matches = w32_list_fonts (f, build_string (new_pattn), size, max_names);
6685
6686 for ( ; CONSP (matches); matches = XCDR (matches))
6687 {
6688 tem = XCAR (matches);
6689 if (!STRINGP (tem))
6690 continue;
6691
6692 full_pattn = XSTRING (tem)->data;
6693 fields = sscanf (full_pattn, "-%49[^-]-%49[^-]-%*[^-]-%*c-%s",
6694 foundary, family, pattn_part2);
6695 if (fields == EOF || fields < 3)
6696 continue;
6697
6698 sprintf (new_pattn, "-%s-%s-%s-%c-%s", foundary, family, style,
6699 slant, pattn_part2);
6700
6701 synthed_matches = Fcons (build_string (new_pattn),
6702 synthed_matches);
6703 }
6704
6705 return synthed_matches;
6706 }
6707
6708
6709 /* Return a pointer to struct font_info of font FONT_IDX of frame F. */
6710 struct font_info *
6711 w32_get_font_info (f, font_idx)
6712 FRAME_PTR f;
6713 int font_idx;
6714 {
6715 return (FRAME_W32_FONT_TABLE (f) + font_idx);
6716 }
6717
6718
6719 struct font_info*
6720 w32_query_font (struct frame *f, char *fontname)
6721 {
6722 int i;
6723 struct font_info *pfi;
6724
6725 pfi = FRAME_W32_FONT_TABLE (f);
6726
6727 for (i = 0; i < one_w32_display_info.n_fonts ;i++, pfi++)
6728 {
6729 if (strcmp(pfi->name, fontname) == 0) return pfi;
6730 }
6731
6732 return NULL;
6733 }
6734
6735 /* Find a CCL program for a font specified by FONTP, and set the member
6736 `encoder' of the structure. */
6737
6738 void
6739 w32_find_ccl_program (fontp)
6740 struct font_info *fontp;
6741 {
6742 Lisp_Object list, elt;
6743
6744 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
6745 {
6746 elt = XCAR (list);
6747 if (CONSP (elt)
6748 && STRINGP (XCAR (elt))
6749 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
6750 >= 0))
6751 break;
6752 }
6753 if (! NILP (list))
6754 {
6755 struct ccl_program *ccl
6756 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
6757
6758 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
6759 xfree (ccl);
6760 else
6761 fontp->font_encoder = ccl;
6762 }
6763 }
6764
6765 \f
6766 DEFUN ("w32-find-bdf-fonts", Fw32_find_bdf_fonts, Sw32_find_bdf_fonts,
6767 1, 1, 0,
6768 "Return a list of BDF fonts in DIR, suitable for appending to\n\
6769 w32-bdf-filename-alist. Fonts which do not contain an xfld description\n\
6770 will not be included in the list. DIR may be a list of directories.")
6771 (directory)
6772 Lisp_Object directory;
6773 {
6774 Lisp_Object list = Qnil;
6775 struct gcpro gcpro1, gcpro2;
6776
6777 if (!CONSP (directory))
6778 return w32_find_bdf_fonts_in_dir (directory);
6779
6780 for ( ; CONSP (directory); directory = XCDR (directory))
6781 {
6782 Lisp_Object pair[2];
6783 pair[0] = list;
6784 pair[1] = Qnil;
6785 GCPRO2 (directory, list);
6786 pair[1] = w32_find_bdf_fonts_in_dir( XCAR (directory) );
6787 list = Fnconc( 2, pair );
6788 UNGCPRO;
6789 }
6790 return list;
6791 }
6792
6793 /* Find BDF files in a specified directory. (use GCPRO when calling,
6794 as this calls lisp to get a directory listing). */
6795 Lisp_Object w32_find_bdf_fonts_in_dir( Lisp_Object directory )
6796 {
6797 Lisp_Object filelist, list = Qnil;
6798 char fontname[100];
6799
6800 if (!STRINGP(directory))
6801 return Qnil;
6802
6803 filelist = Fdirectory_files (directory, Qt,
6804 build_string (".*\\.[bB][dD][fF]"), Qt);
6805
6806 for ( ; CONSP(filelist); filelist = XCDR (filelist))
6807 {
6808 Lisp_Object filename = XCAR (filelist);
6809 if (w32_BDF_to_x_font (XSTRING (filename)->data, fontname, 100))
6810 store_in_alist (&list, build_string (fontname), filename);
6811 }
6812 return list;
6813 }
6814
6815 \f
6816 DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
6817 "Internal function called by `color-defined-p', which see.")
6818 (color, frame)
6819 Lisp_Object color, frame;
6820 {
6821 XColor foo;
6822 FRAME_PTR f = check_x_frame (frame);
6823
6824 CHECK_STRING (color, 1);
6825
6826 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
6827 return Qt;
6828 else
6829 return Qnil;
6830 }
6831
6832 DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
6833 "Internal function called by `color-values', which see.")
6834 (color, frame)
6835 Lisp_Object color, frame;
6836 {
6837 XColor foo;
6838 FRAME_PTR f = check_x_frame (frame);
6839
6840 CHECK_STRING (color, 1);
6841
6842 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
6843 {
6844 Lisp_Object rgb[3];
6845
6846 rgb[0] = make_number ((GetRValue (foo.pixel) << 8)
6847 | GetRValue (foo.pixel));
6848 rgb[1] = make_number ((GetGValue (foo.pixel) << 8)
6849 | GetGValue (foo.pixel));
6850 rgb[2] = make_number ((GetBValue (foo.pixel) << 8)
6851 | GetBValue (foo.pixel));
6852 return Flist (3, rgb);
6853 }
6854 else
6855 return Qnil;
6856 }
6857
6858 DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
6859 "Internal function called by `display-color-p', which see.")
6860 (display)
6861 Lisp_Object display;
6862 {
6863 struct w32_display_info *dpyinfo = check_x_display_info (display);
6864
6865 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 2)
6866 return Qnil;
6867
6868 return Qt;
6869 }
6870
6871 DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p, Sx_display_grayscale_p,
6872 0, 1, 0,
6873 "Return t if the X display supports shades of gray.\n\
6874 Note that color displays do support shades of gray.\n\
6875 The optional argument DISPLAY specifies which display to ask about.\n\
6876 DISPLAY should be either a frame or a display name (a string).\n\
6877 If omitted or nil, that stands for the selected frame's display.")
6878 (display)
6879 Lisp_Object display;
6880 {
6881 struct w32_display_info *dpyinfo = check_x_display_info (display);
6882
6883 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 1)
6884 return Qnil;
6885
6886 return Qt;
6887 }
6888
6889 DEFUN ("x-display-pixel-width", Fx_display_pixel_width, Sx_display_pixel_width,
6890 0, 1, 0,
6891 "Returns the width in pixels of the X display DISPLAY.\n\
6892 The optional argument DISPLAY specifies which display to ask about.\n\
6893 DISPLAY should be either a frame or a display name (a string).\n\
6894 If omitted or nil, that stands for the selected frame's display.")
6895 (display)
6896 Lisp_Object display;
6897 {
6898 struct w32_display_info *dpyinfo = check_x_display_info (display);
6899
6900 return make_number (dpyinfo->width);
6901 }
6902
6903 DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
6904 Sx_display_pixel_height, 0, 1, 0,
6905 "Returns the height in pixels of the X display DISPLAY.\n\
6906 The optional argument DISPLAY specifies which display to ask about.\n\
6907 DISPLAY should be either a frame or a display name (a string).\n\
6908 If omitted or nil, that stands for the selected frame's display.")
6909 (display)
6910 Lisp_Object display;
6911 {
6912 struct w32_display_info *dpyinfo = check_x_display_info (display);
6913
6914 return make_number (dpyinfo->height);
6915 }
6916
6917 DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
6918 0, 1, 0,
6919 "Returns the number of bitplanes of the display DISPLAY.\n\
6920 The optional argument DISPLAY specifies which display to ask about.\n\
6921 DISPLAY should be either a frame or a display name (a string).\n\
6922 If omitted or nil, that stands for the selected frame's display.")
6923 (display)
6924 Lisp_Object display;
6925 {
6926 struct w32_display_info *dpyinfo = check_x_display_info (display);
6927
6928 return make_number (dpyinfo->n_planes * dpyinfo->n_cbits);
6929 }
6930
6931 DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
6932 0, 1, 0,
6933 "Returns the number of color cells of the display DISPLAY.\n\
6934 The optional argument DISPLAY specifies which display to ask about.\n\
6935 DISPLAY should be either a frame or a display name (a string).\n\
6936 If omitted or nil, that stands for the selected frame's display.")
6937 (display)
6938 Lisp_Object display;
6939 {
6940 struct w32_display_info *dpyinfo = check_x_display_info (display);
6941 HDC hdc;
6942 int cap;
6943
6944 hdc = GetDC (dpyinfo->root_window);
6945 if (dpyinfo->has_palette)
6946 cap = GetDeviceCaps (hdc,SIZEPALETTE);
6947 else
6948 cap = GetDeviceCaps (hdc,NUMCOLORS);
6949
6950 ReleaseDC (dpyinfo->root_window, hdc);
6951
6952 return make_number (cap);
6953 }
6954
6955 DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
6956 Sx_server_max_request_size,
6957 0, 1, 0,
6958 "Returns the maximum request size of the server of display DISPLAY.\n\
6959 The optional argument DISPLAY specifies which display to ask about.\n\
6960 DISPLAY should be either a frame or a display name (a string).\n\
6961 If omitted or nil, that stands for the selected frame's display.")
6962 (display)
6963 Lisp_Object display;
6964 {
6965 struct w32_display_info *dpyinfo = check_x_display_info (display);
6966
6967 return make_number (1);
6968 }
6969
6970 DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
6971 "Returns the vendor ID string of the W32 system (Microsoft).\n\
6972 The optional argument DISPLAY specifies which display to ask about.\n\
6973 DISPLAY should be either a frame or a display name (a string).\n\
6974 If omitted or nil, that stands for the selected frame's display.")
6975 (display)
6976 Lisp_Object display;
6977 {
6978 return build_string ("Microsoft Corp.");
6979 }
6980
6981 DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
6982 "Returns the version numbers of the server of display DISPLAY.\n\
6983 The value is a list of three integers: the major and minor\n\
6984 version numbers, and the vendor-specific release\n\
6985 number. See also the function `x-server-vendor'.\n\n\
6986 The optional argument DISPLAY specifies which display to ask about.\n\
6987 DISPLAY should be either a frame or a display name (a string).\n\
6988 If omitted or nil, that stands for the selected frame's display.")
6989 (display)
6990 Lisp_Object display;
6991 {
6992 return Fcons (make_number (w32_major_version),
6993 Fcons (make_number (w32_minor_version), Qnil));
6994 }
6995
6996 DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
6997 "Returns the number of screens on the server of display DISPLAY.\n\
6998 The optional argument DISPLAY specifies which display to ask about.\n\
6999 DISPLAY should be either a frame or a display name (a string).\n\
7000 If omitted or nil, that stands for the selected frame's display.")
7001 (display)
7002 Lisp_Object display;
7003 {
7004 return make_number (1);
7005 }
7006
7007 DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height, 0, 1, 0,
7008 "Returns the height in millimeters of the X display DISPLAY.\n\
7009 The optional argument DISPLAY specifies which display to ask about.\n\
7010 DISPLAY should be either a frame or a display name (a string).\n\
7011 If omitted or nil, that stands for the selected frame's display.")
7012 (display)
7013 Lisp_Object display;
7014 {
7015 struct w32_display_info *dpyinfo = check_x_display_info (display);
7016 HDC hdc;
7017 int cap;
7018
7019 hdc = GetDC (dpyinfo->root_window);
7020
7021 cap = GetDeviceCaps (hdc, VERTSIZE);
7022
7023 ReleaseDC (dpyinfo->root_window, hdc);
7024
7025 return make_number (cap);
7026 }
7027
7028 DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
7029 "Returns the width in millimeters of the X display DISPLAY.\n\
7030 The optional argument DISPLAY specifies which display to ask about.\n\
7031 DISPLAY should be either a frame or a display name (a string).\n\
7032 If omitted or nil, that stands for the selected frame's display.")
7033 (display)
7034 Lisp_Object display;
7035 {
7036 struct w32_display_info *dpyinfo = check_x_display_info (display);
7037
7038 HDC hdc;
7039 int cap;
7040
7041 hdc = GetDC (dpyinfo->root_window);
7042
7043 cap = GetDeviceCaps (hdc, HORZSIZE);
7044
7045 ReleaseDC (dpyinfo->root_window, hdc);
7046
7047 return make_number (cap);
7048 }
7049
7050 DEFUN ("x-display-backing-store", Fx_display_backing_store,
7051 Sx_display_backing_store, 0, 1, 0,
7052 "Returns an indication of whether display DISPLAY does backing store.\n\
7053 The value may be `always', `when-mapped', or `not-useful'.\n\
7054 The optional argument DISPLAY specifies which display to ask about.\n\
7055 DISPLAY should be either a frame or a display name (a string).\n\
7056 If omitted or nil, that stands for the selected frame's display.")
7057 (display)
7058 Lisp_Object display;
7059 {
7060 return intern ("not-useful");
7061 }
7062
7063 DEFUN ("x-display-visual-class", Fx_display_visual_class,
7064 Sx_display_visual_class, 0, 1, 0,
7065 "Returns the visual class of the display DISPLAY.\n\
7066 The value is one of the symbols `static-gray', `gray-scale',\n\
7067 `static-color', `pseudo-color', `true-color', or `direct-color'.\n\n\
7068 The optional argument DISPLAY specifies which display to ask about.\n\
7069 DISPLAY should be either a frame or a display name (a string).\n\
7070 If omitted or nil, that stands for the selected frame's display.")
7071 (display)
7072 Lisp_Object display;
7073 {
7074 struct w32_display_info *dpyinfo = check_x_display_info (display);
7075
7076 #if 0
7077 switch (dpyinfo->visual->class)
7078 {
7079 case StaticGray: return (intern ("static-gray"));
7080 case GrayScale: return (intern ("gray-scale"));
7081 case StaticColor: return (intern ("static-color"));
7082 case PseudoColor: return (intern ("pseudo-color"));
7083 case TrueColor: return (intern ("true-color"));
7084 case DirectColor: return (intern ("direct-color"));
7085 default:
7086 error ("Display has an unknown visual class");
7087 }
7088 #endif
7089
7090 error ("Display has an unknown visual class");
7091 }
7092
7093 DEFUN ("x-display-save-under", Fx_display_save_under,
7094 Sx_display_save_under, 0, 1, 0,
7095 "Returns t if the display DISPLAY supports the save-under feature.\n\
7096 The optional argument DISPLAY specifies which display to ask about.\n\
7097 DISPLAY should be either a frame or a display name (a string).\n\
7098 If omitted or nil, that stands for the selected frame's display.")
7099 (display)
7100 Lisp_Object display;
7101 {
7102 return Qnil;
7103 }
7104 \f
7105 int
7106 x_pixel_width (f)
7107 register struct frame *f;
7108 {
7109 return PIXEL_WIDTH (f);
7110 }
7111
7112 int
7113 x_pixel_height (f)
7114 register struct frame *f;
7115 {
7116 return PIXEL_HEIGHT (f);
7117 }
7118
7119 int
7120 x_char_width (f)
7121 register struct frame *f;
7122 {
7123 return FONT_WIDTH (f->output_data.w32->font);
7124 }
7125
7126 int
7127 x_char_height (f)
7128 register struct frame *f;
7129 {
7130 return f->output_data.w32->line_height;
7131 }
7132
7133 int
7134 x_screen_planes (f)
7135 register struct frame *f;
7136 {
7137 return FRAME_W32_DISPLAY_INFO (f)->n_planes;
7138 }
7139 \f
7140 /* Return the display structure for the display named NAME.
7141 Open a new connection if necessary. */
7142
7143 struct w32_display_info *
7144 x_display_info_for_name (name)
7145 Lisp_Object name;
7146 {
7147 Lisp_Object names;
7148 struct w32_display_info *dpyinfo;
7149
7150 CHECK_STRING (name, 0);
7151
7152 for (dpyinfo = &one_w32_display_info, names = w32_display_name_list;
7153 dpyinfo;
7154 dpyinfo = dpyinfo->next, names = XCDR (names))
7155 {
7156 Lisp_Object tem;
7157 tem = Fstring_equal (XCAR (XCAR (names)), name);
7158 if (!NILP (tem))
7159 return dpyinfo;
7160 }
7161
7162 /* Use this general default value to start with. */
7163 Vx_resource_name = Vinvocation_name;
7164
7165 validate_x_resource_name ();
7166
7167 dpyinfo = w32_term_init (name, (unsigned char *)0,
7168 (char *) XSTRING (Vx_resource_name)->data);
7169
7170 if (dpyinfo == 0)
7171 error ("Cannot connect to server %s", XSTRING (name)->data);
7172
7173 w32_in_use = 1;
7174 XSETFASTINT (Vwindow_system_version, 3);
7175
7176 return dpyinfo;
7177 }
7178
7179 DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
7180 1, 3, 0, "Open a connection to a server.\n\
7181 DISPLAY is the name of the display to connect to.\n\
7182 Optional second arg XRM-STRING is a string of resources in xrdb format.\n\
7183 If the optional third arg MUST-SUCCEED is non-nil,\n\
7184 terminate Emacs if we can't open the connection.")
7185 (display, xrm_string, must_succeed)
7186 Lisp_Object display, xrm_string, must_succeed;
7187 {
7188 unsigned char *xrm_option;
7189 struct w32_display_info *dpyinfo;
7190
7191 CHECK_STRING (display, 0);
7192 if (! NILP (xrm_string))
7193 CHECK_STRING (xrm_string, 1);
7194
7195 if (! EQ (Vwindow_system, intern ("w32")))
7196 error ("Not using Microsoft Windows");
7197
7198 /* Allow color mapping to be defined externally; first look in user's
7199 HOME directory, then in Emacs etc dir for a file called rgb.txt. */
7200 {
7201 Lisp_Object color_file;
7202 struct gcpro gcpro1;
7203
7204 color_file = build_string("~/rgb.txt");
7205
7206 GCPRO1 (color_file);
7207
7208 if (NILP (Ffile_readable_p (color_file)))
7209 color_file =
7210 Fexpand_file_name (build_string ("rgb.txt"),
7211 Fsymbol_value (intern ("data-directory")));
7212
7213 Vw32_color_map = Fw32_load_color_file (color_file);
7214
7215 UNGCPRO;
7216 }
7217 if (NILP (Vw32_color_map))
7218 Vw32_color_map = Fw32_default_color_map ();
7219
7220 if (! NILP (xrm_string))
7221 xrm_option = (unsigned char *) XSTRING (xrm_string)->data;
7222 else
7223 xrm_option = (unsigned char *) 0;
7224
7225 /* Use this general default value to start with. */
7226 /* First remove .exe suffix from invocation-name - it looks ugly. */
7227 {
7228 char basename[ MAX_PATH ], *str;
7229
7230 strcpy (basename, XSTRING (Vinvocation_name)->data);
7231 str = strrchr (basename, '.');
7232 if (str) *str = 0;
7233 Vinvocation_name = build_string (basename);
7234 }
7235 Vx_resource_name = Vinvocation_name;
7236
7237 validate_x_resource_name ();
7238
7239 /* This is what opens the connection and sets x_current_display.
7240 This also initializes many symbols, such as those used for input. */
7241 dpyinfo = w32_term_init (display, xrm_option,
7242 (char *) XSTRING (Vx_resource_name)->data);
7243
7244 if (dpyinfo == 0)
7245 {
7246 if (!NILP (must_succeed))
7247 fatal ("Cannot connect to server %s.\n",
7248 XSTRING (display)->data);
7249 else
7250 error ("Cannot connect to server %s", XSTRING (display)->data);
7251 }
7252
7253 w32_in_use = 1;
7254
7255 XSETFASTINT (Vwindow_system_version, 3);
7256 return Qnil;
7257 }
7258
7259 DEFUN ("x-close-connection", Fx_close_connection,
7260 Sx_close_connection, 1, 1, 0,
7261 "Close the connection to DISPLAY's server.\n\
7262 For DISPLAY, specify either a frame or a display name (a string).\n\
7263 If DISPLAY is nil, that stands for the selected frame's display.")
7264 (display)
7265 Lisp_Object display;
7266 {
7267 struct w32_display_info *dpyinfo = check_x_display_info (display);
7268 int i;
7269
7270 if (dpyinfo->reference_count > 0)
7271 error ("Display still has frames on it");
7272
7273 BLOCK_INPUT;
7274 /* Free the fonts in the font table. */
7275 for (i = 0; i < dpyinfo->n_fonts; i++)
7276 if (dpyinfo->font_table[i].name)
7277 {
7278 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
7279 xfree (dpyinfo->font_table[i].full_name);
7280 xfree (dpyinfo->font_table[i].name);
7281 w32_unload_font (dpyinfo, dpyinfo->font_table[i].font);
7282 }
7283 x_destroy_all_bitmaps (dpyinfo);
7284
7285 x_delete_display (dpyinfo);
7286 UNBLOCK_INPUT;
7287
7288 return Qnil;
7289 }
7290
7291 DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
7292 "Return the list of display names that Emacs has connections to.")
7293 ()
7294 {
7295 Lisp_Object tail, result;
7296
7297 result = Qnil;
7298 for (tail = w32_display_name_list; ! NILP (tail); tail = XCDR (tail))
7299 result = Fcons (XCAR (XCAR (tail)), result);
7300
7301 return result;
7302 }
7303
7304 DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0,
7305 "If ON is non-nil, report errors as soon as the erring request is made.\n\
7306 If ON is nil, allow buffering of requests.\n\
7307 This is a noop on W32 systems.\n\
7308 The optional second argument DISPLAY specifies which display to act on.\n\
7309 DISPLAY should be either a frame or a display name (a string).\n\
7310 If DISPLAY is omitted or nil, that stands for the selected frame's display.")
7311 (on, display)
7312 Lisp_Object display, on;
7313 {
7314 return Qnil;
7315 }
7316
7317 \f
7318 \f
7319 /***********************************************************************
7320 Image types
7321 ***********************************************************************/
7322
7323 /* Value is the number of elements of vector VECTOR. */
7324
7325 #define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))
7326
7327 /* List of supported image types. Use define_image_type to add new
7328 types. Use lookup_image_type to find a type for a given symbol. */
7329
7330 static struct image_type *image_types;
7331
7332 /* The symbol `image' which is the car of the lists used to represent
7333 images in Lisp. */
7334
7335 extern Lisp_Object Qimage;
7336
7337 /* The symbol `xbm' which is used as the type symbol for XBM images. */
7338
7339 Lisp_Object Qxbm;
7340
7341 /* Keywords. */
7342
7343 extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
7344 extern Lisp_Object QCdata;
7345 Lisp_Object QCtype, QCascent, QCmargin, QCrelief;
7346 Lisp_Object QCalgorithm, QCcolor_symbols, QCheuristic_mask;
7347 Lisp_Object QCindex;
7348
7349 /* Other symbols. */
7350
7351 Lisp_Object Qlaplace;
7352
7353 /* Time in seconds after which images should be removed from the cache
7354 if not displayed. */
7355
7356 Lisp_Object Vimage_cache_eviction_delay;
7357
7358 /* Function prototypes. */
7359
7360 static void define_image_type P_ ((struct image_type *type));
7361 static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
7362 static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
7363 static void x_laplace P_ ((struct frame *, struct image *));
7364 static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
7365 Lisp_Object));
7366
7367
7368 /* Define a new image type from TYPE. This adds a copy of TYPE to
7369 image_types and adds the symbol *TYPE->type to Vimage_types. */
7370
7371 static void
7372 define_image_type (type)
7373 struct image_type *type;
7374 {
7375 /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
7376 The initialized data segment is read-only. */
7377 struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
7378 bcopy (type, p, sizeof *p);
7379 p->next = image_types;
7380 image_types = p;
7381 Vimage_types = Fcons (*p->type, Vimage_types);
7382 }
7383
7384
7385 /* Look up image type SYMBOL, and return a pointer to its image_type
7386 structure. Value is null if SYMBOL is not a known image type. */
7387
7388 static INLINE struct image_type *
7389 lookup_image_type (symbol)
7390 Lisp_Object symbol;
7391 {
7392 struct image_type *type;
7393
7394 for (type = image_types; type; type = type->next)
7395 if (EQ (symbol, *type->type))
7396 break;
7397
7398 return type;
7399 }
7400
7401
7402 /* Value is non-zero if OBJECT is a valid Lisp image specification. A
7403 valid image specification is a list whose car is the symbol
7404 `image', and whose rest is a property list. The property list must
7405 contain a value for key `:type'. That value must be the name of a
7406 supported image type. The rest of the property list depends on the
7407 image type. */
7408
7409 int
7410 valid_image_p (object)
7411 Lisp_Object object;
7412 {
7413 int valid_p = 0;
7414
7415 if (CONSP (object) && EQ (XCAR (object), Qimage))
7416 {
7417 Lisp_Object symbol = Fplist_get (XCDR (object), QCtype);
7418 struct image_type *type = lookup_image_type (symbol);
7419
7420 if (type)
7421 valid_p = type->valid_p (object);
7422 }
7423
7424 return valid_p;
7425 }
7426
7427
7428 /* Log error message with format string FORMAT and argument ARG.
7429 Signaling an error, e.g. when an image cannot be loaded, is not a
7430 good idea because this would interrupt redisplay, and the error
7431 message display would lead to another redisplay. This function
7432 therefore simply displays a message. */
7433
7434 static void
7435 image_error (format, arg1, arg2)
7436 char *format;
7437 Lisp_Object arg1, arg2;
7438 {
7439 add_to_log (format, arg1, arg2);
7440 }
7441
7442
7443 \f
7444 /***********************************************************************
7445 Image specifications
7446 ***********************************************************************/
7447
7448 enum image_value_type
7449 {
7450 IMAGE_DONT_CHECK_VALUE_TYPE,
7451 IMAGE_STRING_VALUE,
7452 IMAGE_SYMBOL_VALUE,
7453 IMAGE_POSITIVE_INTEGER_VALUE,
7454 IMAGE_NON_NEGATIVE_INTEGER_VALUE,
7455 IMAGE_ASCENT_VALUE,
7456 IMAGE_INTEGER_VALUE,
7457 IMAGE_FUNCTION_VALUE,
7458 IMAGE_NUMBER_VALUE,
7459 IMAGE_BOOL_VALUE
7460 };
7461
7462 /* Structure used when parsing image specifications. */
7463
7464 struct image_keyword
7465 {
7466 /* Name of keyword. */
7467 char *name;
7468
7469 /* The type of value allowed. */
7470 enum image_value_type type;
7471
7472 /* Non-zero means key must be present. */
7473 int mandatory_p;
7474
7475 /* Used to recognize duplicate keywords in a property list. */
7476 int count;
7477
7478 /* The value that was found. */
7479 Lisp_Object value;
7480 };
7481
7482
7483 static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
7484 int, Lisp_Object));
7485 static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
7486
7487
7488 /* Parse image spec SPEC according to KEYWORDS. A valid image spec
7489 has the format (image KEYWORD VALUE ...). One of the keyword/
7490 value pairs must be `:type TYPE'. KEYWORDS is a vector of
7491 image_keywords structures of size NKEYWORDS describing other
7492 allowed keyword/value pairs. Value is non-zero if SPEC is valid. */
7493
7494 static int
7495 parse_image_spec (spec, keywords, nkeywords, type)
7496 Lisp_Object spec;
7497 struct image_keyword *keywords;
7498 int nkeywords;
7499 Lisp_Object type;
7500 {
7501 int i;
7502 Lisp_Object plist;
7503
7504 if (!CONSP (spec) || !EQ (XCAR (spec), Qimage))
7505 return 0;
7506
7507 plist = XCDR (spec);
7508 while (CONSP (plist))
7509 {
7510 Lisp_Object key, value;
7511
7512 /* First element of a pair must be a symbol. */
7513 key = XCAR (plist);
7514 plist = XCDR (plist);
7515 if (!SYMBOLP (key))
7516 return 0;
7517
7518 /* There must follow a value. */
7519 if (!CONSP (plist))
7520 return 0;
7521 value = XCAR (plist);
7522 plist = XCDR (plist);
7523
7524 /* Find key in KEYWORDS. Error if not found. */
7525 for (i = 0; i < nkeywords; ++i)
7526 if (strcmp (keywords[i].name, XSYMBOL (key)->name->data) == 0)
7527 break;
7528
7529 if (i == nkeywords)
7530 continue;
7531
7532 /* Record that we recognized the keyword. If a keywords
7533 was found more than once, it's an error. */
7534 keywords[i].value = value;
7535 ++keywords[i].count;
7536
7537 if (keywords[i].count > 1)
7538 return 0;
7539
7540 /* Check type of value against allowed type. */
7541 switch (keywords[i].type)
7542 {
7543 case IMAGE_STRING_VALUE:
7544 if (!STRINGP (value))
7545 return 0;
7546 break;
7547
7548 case IMAGE_SYMBOL_VALUE:
7549 if (!SYMBOLP (value))
7550 return 0;
7551 break;
7552
7553 case IMAGE_POSITIVE_INTEGER_VALUE:
7554 if (!INTEGERP (value) || XINT (value) <= 0)
7555 return 0;
7556 break;
7557
7558 case IMAGE_ASCENT_VALUE:
7559 if (SYMBOLP (value) && EQ (value, Qcenter))
7560 break;
7561 else if (INTEGERP (value)
7562 && XINT (value) >= 0
7563 && XINT (value) <= 100)
7564 break;
7565 return 0;
7566
7567 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
7568 if (!INTEGERP (value) || XINT (value) < 0)
7569 return 0;
7570 break;
7571
7572 case IMAGE_DONT_CHECK_VALUE_TYPE:
7573 break;
7574
7575 case IMAGE_FUNCTION_VALUE:
7576 value = indirect_function (value);
7577 if (SUBRP (value)
7578 || COMPILEDP (value)
7579 || (CONSP (value) && EQ (XCAR (value), Qlambda)))
7580 break;
7581 return 0;
7582
7583 case IMAGE_NUMBER_VALUE:
7584 if (!INTEGERP (value) && !FLOATP (value))
7585 return 0;
7586 break;
7587
7588 case IMAGE_INTEGER_VALUE:
7589 if (!INTEGERP (value))
7590 return 0;
7591 break;
7592
7593 case IMAGE_BOOL_VALUE:
7594 if (!NILP (value) && !EQ (value, Qt))
7595 return 0;
7596 break;
7597
7598 default:
7599 abort ();
7600 break;
7601 }
7602
7603 if (EQ (key, QCtype) && !EQ (type, value))
7604 return 0;
7605 }
7606
7607 /* Check that all mandatory fields are present. */
7608 for (i = 0; i < nkeywords; ++i)
7609 if (keywords[i].mandatory_p && keywords[i].count == 0)
7610 return 0;
7611
7612 return NILP (plist);
7613 }
7614
7615
7616 /* Return the value of KEY in image specification SPEC. Value is nil
7617 if KEY is not present in SPEC. if FOUND is not null, set *FOUND
7618 to 1 if KEY was found in SPEC, set it to 0 otherwise. */
7619
7620 static Lisp_Object
7621 image_spec_value (spec, key, found)
7622 Lisp_Object spec, key;
7623 int *found;
7624 {
7625 Lisp_Object tail;
7626
7627 xassert (valid_image_p (spec));
7628
7629 for (tail = XCDR (spec);
7630 CONSP (tail) && CONSP (XCDR (tail));
7631 tail = XCDR (XCDR (tail)))
7632 {
7633 if (EQ (XCAR (tail), key))
7634 {
7635 if (found)
7636 *found = 1;
7637 return XCAR (XCDR (tail));
7638 }
7639 }
7640
7641 if (found)
7642 *found = 0;
7643 return Qnil;
7644 }
7645
7646
7647
7648 \f
7649 /***********************************************************************
7650 Image type independent image structures
7651 ***********************************************************************/
7652
7653 static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
7654 static void free_image P_ ((struct frame *f, struct image *img));
7655
7656
7657 /* Allocate and return a new image structure for image specification
7658 SPEC. SPEC has a hash value of HASH. */
7659
7660 static struct image *
7661 make_image (spec, hash)
7662 Lisp_Object spec;
7663 unsigned hash;
7664 {
7665 struct image *img = (struct image *) xmalloc (sizeof *img);
7666
7667 xassert (valid_image_p (spec));
7668 bzero (img, sizeof *img);
7669 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
7670 xassert (img->type != NULL);
7671 img->spec = spec;
7672 img->data.lisp_val = Qnil;
7673 img->ascent = DEFAULT_IMAGE_ASCENT;
7674 img->hash = hash;
7675 return img;
7676 }
7677
7678
7679 /* Free image IMG which was used on frame F, including its resources. */
7680
7681 static void
7682 free_image (f, img)
7683 struct frame *f;
7684 struct image *img;
7685 {
7686 if (img)
7687 {
7688 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
7689
7690 /* Remove IMG from the hash table of its cache. */
7691 if (img->prev)
7692 img->prev->next = img->next;
7693 else
7694 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
7695
7696 if (img->next)
7697 img->next->prev = img->prev;
7698
7699 c->images[img->id] = NULL;
7700
7701 /* Free resources, then free IMG. */
7702 img->type->free (f, img);
7703 xfree (img);
7704 }
7705 }
7706
7707
7708 /* Prepare image IMG for display on frame F. Must be called before
7709 drawing an image. */
7710
7711 void
7712 prepare_image_for_display (f, img)
7713 struct frame *f;
7714 struct image *img;
7715 {
7716 EMACS_TIME t;
7717
7718 /* We're about to display IMG, so set its timestamp to `now'. */
7719 EMACS_GET_TIME (t);
7720 img->timestamp = EMACS_SECS (t);
7721
7722 /* If IMG doesn't have a pixmap yet, load it now, using the image
7723 type dependent loader function. */
7724 if (img->pixmap == 0 && !img->load_failed_p)
7725 img->load_failed_p = img->type->load (f, img) == 0;
7726 }
7727
7728
7729 /* Value is the number of pixels for the ascent of image IMG when
7730 drawn in face FACE. */
7731
7732 int
7733 image_ascent (img, face)
7734 struct image *img;
7735 struct face *face;
7736 {
7737 int height = img->height + img->margin;
7738 int ascent;
7739
7740 if (img->ascent == CENTERED_IMAGE_ASCENT)
7741 {
7742 if (face->font)
7743 ascent = height / 2 - (FONT_DESCENT(face->font)
7744 - FONT_BASE(face->font)) / 2;
7745 else
7746 ascent = height / 2;
7747 }
7748 else
7749 ascent = height * img->ascent / 100.0;
7750
7751 return ascent;
7752 }
7753
7754
7755 \f
7756 /***********************************************************************
7757 Helper functions for X image types
7758 ***********************************************************************/
7759
7760 static void x_clear_image P_ ((struct frame *f, struct image *img));
7761 static unsigned long x_alloc_image_color P_ ((struct frame *f,
7762 struct image *img,
7763 Lisp_Object color_name,
7764 unsigned long dflt));
7765
7766 /* Free X resources of image IMG which is used on frame F. */
7767
7768 static void
7769 x_clear_image (f, img)
7770 struct frame *f;
7771 struct image *img;
7772 {
7773 #if 0 /* NTEMACS_TODO: W32 image support */
7774
7775 if (img->pixmap)
7776 {
7777 BLOCK_INPUT;
7778 XFreePixmap (NULL, img->pixmap);
7779 img->pixmap = 0;
7780 UNBLOCK_INPUT;
7781 }
7782
7783 if (img->ncolors)
7784 {
7785 int class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
7786
7787 /* If display has an immutable color map, freeing colors is not
7788 necessary and some servers don't allow it. So don't do it. */
7789 if (class != StaticColor
7790 && class != StaticGray
7791 && class != TrueColor)
7792 {
7793 Colormap cmap;
7794 BLOCK_INPUT;
7795 cmap = DefaultColormapOfScreen (FRAME_W32_DISPLAY_INFO (f)->screen);
7796 XFreeColors (FRAME_W32_DISPLAY (f), cmap, img->colors,
7797 img->ncolors, 0);
7798 UNBLOCK_INPUT;
7799 }
7800
7801 xfree (img->colors);
7802 img->colors = NULL;
7803 img->ncolors = 0;
7804 }
7805 #endif
7806 }
7807
7808
7809 /* Allocate color COLOR_NAME for image IMG on frame F. If color
7810 cannot be allocated, use DFLT. Add a newly allocated color to
7811 IMG->colors, so that it can be freed again. Value is the pixel
7812 color. */
7813
7814 static unsigned long
7815 x_alloc_image_color (f, img, color_name, dflt)
7816 struct frame *f;
7817 struct image *img;
7818 Lisp_Object color_name;
7819 unsigned long dflt;
7820 {
7821 #if 0 /* NTEMACS_TODO: allocing colors. */
7822 XColor color;
7823 unsigned long result;
7824
7825 xassert (STRINGP (color_name));
7826
7827 if (w32_defined_color (f, XSTRING (color_name)->data, &color, 1))
7828 {
7829 /* This isn't called frequently so we get away with simply
7830 reallocating the color vector to the needed size, here. */
7831 ++img->ncolors;
7832 img->colors =
7833 (unsigned long *) xrealloc (img->colors,
7834 img->ncolors * sizeof *img->colors);
7835 img->colors[img->ncolors - 1] = color.pixel;
7836 result = color.pixel;
7837 }
7838 else
7839 result = dflt;
7840 return result;
7841 #endif
7842 return 0;
7843 }
7844
7845
7846 \f
7847 /***********************************************************************
7848 Image Cache
7849 ***********************************************************************/
7850
7851 static void cache_image P_ ((struct frame *f, struct image *img));
7852
7853
7854 /* Return a new, initialized image cache that is allocated from the
7855 heap. Call free_image_cache to free an image cache. */
7856
7857 struct image_cache *
7858 make_image_cache ()
7859 {
7860 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
7861 int size;
7862
7863 bzero (c, sizeof *c);
7864 c->size = 50;
7865 c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
7866 size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
7867 c->buckets = (struct image **) xmalloc (size);
7868 bzero (c->buckets, size);
7869 return c;
7870 }
7871
7872
7873 /* Free image cache of frame F. Be aware that X frames share images
7874 caches. */
7875
7876 void
7877 free_image_cache (f)
7878 struct frame *f;
7879 {
7880 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
7881 if (c)
7882 {
7883 int i;
7884
7885 /* Cache should not be referenced by any frame when freed. */
7886 xassert (c->refcount == 0);
7887
7888 for (i = 0; i < c->used; ++i)
7889 free_image (f, c->images[i]);
7890 xfree (c->images);
7891 xfree (c);
7892 xfree (c->buckets);
7893 FRAME_X_IMAGE_CACHE (f) = NULL;
7894 }
7895 }
7896
7897
7898 /* Clear image cache of frame F. FORCE_P non-zero means free all
7899 images. FORCE_P zero means clear only images that haven't been
7900 displayed for some time. Should be called from time to time to
7901 reduce the number of loaded images. If image-eviction-seconds is
7902 non-nil, this frees images in the cache which weren't displayed for
7903 at least that many seconds. */
7904
7905 void
7906 clear_image_cache (f, force_p)
7907 struct frame *f;
7908 int force_p;
7909 {
7910 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
7911
7912 if (c && INTEGERP (Vimage_cache_eviction_delay))
7913 {
7914 EMACS_TIME t;
7915 unsigned long old;
7916 int i, any_freed_p = 0;
7917
7918 EMACS_GET_TIME (t);
7919 old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
7920
7921 for (i = 0; i < c->used; ++i)
7922 {
7923 struct image *img = c->images[i];
7924 if (img != NULL
7925 && (force_p
7926 || (img->timestamp > old)))
7927 {
7928 free_image (f, img);
7929 any_freed_p = 1;
7930 }
7931 }
7932
7933 /* We may be clearing the image cache because, for example,
7934 Emacs was iconified for a longer period of time. In that
7935 case, current matrices may still contain references to
7936 images freed above. So, clear these matrices. */
7937 if (any_freed_p)
7938 {
7939 clear_current_matrices (f);
7940 ++windows_or_buffers_changed;
7941 }
7942 }
7943 }
7944
7945
7946 DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
7947 0, 1, 0,
7948 "Clear the image cache of FRAME.\n\
7949 FRAME nil or omitted means use the selected frame.\n\
7950 FRAME t means clear the image caches of all frames.")
7951 (frame)
7952 Lisp_Object frame;
7953 {
7954 if (EQ (frame, Qt))
7955 {
7956 Lisp_Object tail;
7957
7958 FOR_EACH_FRAME (tail, frame)
7959 if (FRAME_W32_P (XFRAME (frame)))
7960 clear_image_cache (XFRAME (frame), 1);
7961 }
7962 else
7963 clear_image_cache (check_x_frame (frame), 1);
7964
7965 return Qnil;
7966 }
7967
7968
7969 /* Return the id of image with Lisp specification SPEC on frame F.
7970 SPEC must be a valid Lisp image specification (see valid_image_p). */
7971
7972 int
7973 lookup_image (f, spec)
7974 struct frame *f;
7975 Lisp_Object spec;
7976 {
7977 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
7978 struct image *img;
7979 int i;
7980 unsigned hash;
7981 struct gcpro gcpro1;
7982 EMACS_TIME now;
7983
7984 /* F must be a window-system frame, and SPEC must be a valid image
7985 specification. */
7986 xassert (FRAME_WINDOW_P (f));
7987 xassert (valid_image_p (spec));
7988
7989 GCPRO1 (spec);
7990
7991 /* Look up SPEC in the hash table of the image cache. */
7992 hash = sxhash (spec, 0);
7993 i = hash % IMAGE_CACHE_BUCKETS_SIZE;
7994
7995 for (img = c->buckets[i]; img; img = img->next)
7996 if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
7997 break;
7998
7999 /* If not found, create a new image and cache it. */
8000 if (img == NULL)
8001 {
8002 img = make_image (spec, hash);
8003 cache_image (f, img);
8004 img->load_failed_p = img->type->load (f, img) == 0;
8005 xassert (!interrupt_input_blocked);
8006
8007 /* If we can't load the image, and we don't have a width and
8008 height, use some arbitrary width and height so that we can
8009 draw a rectangle for it. */
8010 if (img->load_failed_p)
8011 {
8012 Lisp_Object value;
8013
8014 value = image_spec_value (spec, QCwidth, NULL);
8015 img->width = (INTEGERP (value)
8016 ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH);
8017 value = image_spec_value (spec, QCheight, NULL);
8018 img->height = (INTEGERP (value)
8019 ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT);
8020 }
8021 else
8022 {
8023 /* Handle image type independent image attributes
8024 `:ascent PERCENT', `:margin MARGIN', `:relief RELIEF'. */
8025 Lisp_Object ascent, margin, relief, algorithm, heuristic_mask;
8026 Lisp_Object file;
8027
8028 ascent = image_spec_value (spec, QCascent, NULL);
8029 if (INTEGERP (ascent))
8030 img->ascent = XFASTINT (ascent);
8031 else if (EQ (ascent, Qcenter))
8032 img->ascent = CENTERED_IMAGE_ASCENT;
8033
8034 margin = image_spec_value (spec, QCmargin, NULL);
8035 if (INTEGERP (margin) && XINT (margin) >= 0)
8036 img->margin = XFASTINT (margin);
8037
8038 relief = image_spec_value (spec, QCrelief, NULL);
8039 if (INTEGERP (relief))
8040 {
8041 img->relief = XINT (relief);
8042 img->margin += abs (img->relief);
8043 }
8044
8045 /* Should we apply a Laplace edge-detection algorithm? */
8046 algorithm = image_spec_value (spec, QCalgorithm, NULL);
8047 if (img->pixmap && EQ (algorithm, Qlaplace))
8048 x_laplace (f, img);
8049
8050 /* Should we built a mask heuristically? */
8051 heuristic_mask = image_spec_value (spec, QCheuristic_mask, NULL);
8052 if (img->pixmap && !img->mask && !NILP (heuristic_mask))
8053 x_build_heuristic_mask (f, img, heuristic_mask);
8054 }
8055 }
8056
8057 /* We're using IMG, so set its timestamp to `now'. */
8058 EMACS_GET_TIME (now);
8059 img->timestamp = EMACS_SECS (now);
8060
8061 UNGCPRO;
8062
8063 /* Value is the image id. */
8064 return img->id;
8065 }
8066
8067
8068 /* Cache image IMG in the image cache of frame F. */
8069
8070 static void
8071 cache_image (f, img)
8072 struct frame *f;
8073 struct image *img;
8074 {
8075 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8076 int i;
8077
8078 /* Find a free slot in c->images. */
8079 for (i = 0; i < c->used; ++i)
8080 if (c->images[i] == NULL)
8081 break;
8082
8083 /* If no free slot found, maybe enlarge c->images. */
8084 if (i == c->used && c->used == c->size)
8085 {
8086 c->size *= 2;
8087 c->images = (struct image **) xrealloc (c->images,
8088 c->size * sizeof *c->images);
8089 }
8090
8091 /* Add IMG to c->images, and assign IMG an id. */
8092 c->images[i] = img;
8093 img->id = i;
8094 if (i == c->used)
8095 ++c->used;
8096
8097 /* Add IMG to the cache's hash table. */
8098 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
8099 img->next = c->buckets[i];
8100 if (img->next)
8101 img->next->prev = img;
8102 img->prev = NULL;
8103 c->buckets[i] = img;
8104 }
8105
8106
8107 /* Call FN on every image in the image cache of frame F. Used to mark
8108 Lisp Objects in the image cache. */
8109
8110 void
8111 forall_images_in_image_cache (f, fn)
8112 struct frame *f;
8113 void (*fn) P_ ((struct image *img));
8114 {
8115 if (FRAME_LIVE_P (f) && FRAME_W32_P (f))
8116 {
8117 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8118 if (c)
8119 {
8120 int i;
8121 for (i = 0; i < c->used; ++i)
8122 if (c->images[i])
8123 fn (c->images[i]);
8124 }
8125 }
8126 }
8127
8128
8129 \f
8130 /***********************************************************************
8131 W32 support code
8132 ***********************************************************************/
8133
8134 #if 0 /* NTEMACS_TODO: W32 specific image code. */
8135
8136 static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
8137 XImage **, Pixmap *));
8138 static void x_destroy_x_image P_ ((XImage *));
8139 static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
8140
8141
8142 /* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
8143 frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created.
8144 Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
8145 via xmalloc. Print error messages via image_error if an error
8146 occurs. Value is non-zero if successful. */
8147
8148 static int
8149 x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
8150 struct frame *f;
8151 int width, height, depth;
8152 XImage **ximg;
8153 Pixmap *pixmap;
8154 {
8155 #if 0 /* NTEMACS_TODO: Image support for W32 */
8156 Display *display = FRAME_W32_DISPLAY (f);
8157 Screen *screen = FRAME_X_SCREEN (f);
8158 Window window = FRAME_W32_WINDOW (f);
8159
8160 xassert (interrupt_input_blocked);
8161
8162 if (depth <= 0)
8163 depth = DefaultDepthOfScreen (screen);
8164 *ximg = XCreateImage (display, DefaultVisualOfScreen (screen),
8165 depth, ZPixmap, 0, NULL, width, height,
8166 depth > 16 ? 32 : depth > 8 ? 16 : 8, 0);
8167 if (*ximg == NULL)
8168 {
8169 image_error ("Unable to allocate X image", Qnil, Qnil);
8170 return 0;
8171 }
8172
8173 /* Allocate image raster. */
8174 (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height);
8175
8176 /* Allocate a pixmap of the same size. */
8177 *pixmap = XCreatePixmap (display, window, width, height, depth);
8178 if (*pixmap == 0)
8179 {
8180 x_destroy_x_image (*ximg);
8181 *ximg = NULL;
8182 image_error ("Unable to create X pixmap", Qnil, Qnil);
8183 return 0;
8184 }
8185 #endif
8186 return 1;
8187 }
8188
8189
8190 /* Destroy XImage XIMG. Free XIMG->data. */
8191
8192 static void
8193 x_destroy_x_image (ximg)
8194 XImage *ximg;
8195 {
8196 xassert (interrupt_input_blocked);
8197 if (ximg)
8198 {
8199 xfree (ximg->data);
8200 ximg->data = NULL;
8201 XDestroyImage (ximg);
8202 }
8203 }
8204
8205
8206 /* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT
8207 are width and height of both the image and pixmap. */
8208
8209 static void
8210 x_put_x_image (f, ximg, pixmap, width, height)
8211 struct frame *f;
8212 XImage *ximg;
8213 Pixmap pixmap;
8214 {
8215 GC gc;
8216
8217 xassert (interrupt_input_blocked);
8218 gc = XCreateGC (NULL, pixmap, 0, NULL);
8219 XPutImage (NULL, pixmap, gc, ximg, 0, 0, 0, 0, width, height);
8220 XFreeGC (NULL, gc);
8221 }
8222
8223 #endif
8224
8225 \f
8226 /***********************************************************************
8227 Searching files
8228 ***********************************************************************/
8229
8230 static Lisp_Object x_find_image_file P_ ((Lisp_Object));
8231
8232 /* Find image file FILE. Look in data-directory, then
8233 x-bitmap-file-path. Value is the full name of the file found, or
8234 nil if not found. */
8235
8236 static Lisp_Object
8237 x_find_image_file (file)
8238 Lisp_Object file;
8239 {
8240 Lisp_Object file_found, search_path;
8241 struct gcpro gcpro1, gcpro2;
8242 int fd;
8243
8244 file_found = Qnil;
8245 search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
8246 GCPRO2 (file_found, search_path);
8247
8248 /* Try to find FILE in data-directory, then x-bitmap-file-path. */
8249 fd = openp (search_path, file, "", &file_found, 0);
8250
8251 if (fd < 0)
8252 file_found = Qnil;
8253 else
8254 close (fd);
8255
8256 UNGCPRO;
8257 return file_found;
8258 }
8259
8260
8261 \f
8262 /***********************************************************************
8263 XBM images
8264 ***********************************************************************/
8265
8266 static int xbm_load P_ ((struct frame *f, struct image *img));
8267 static int xbm_load_image_from_file P_ ((struct frame *f, struct image *img,
8268 Lisp_Object file));
8269 static int xbm_image_p P_ ((Lisp_Object object));
8270 static int xbm_read_bitmap_file_data P_ ((char *, int *, int *,
8271 unsigned char **));
8272
8273
8274 /* Indices of image specification fields in xbm_format, below. */
8275
8276 enum xbm_keyword_index
8277 {
8278 XBM_TYPE,
8279 XBM_FILE,
8280 XBM_WIDTH,
8281 XBM_HEIGHT,
8282 XBM_DATA,
8283 XBM_FOREGROUND,
8284 XBM_BACKGROUND,
8285 XBM_ASCENT,
8286 XBM_MARGIN,
8287 XBM_RELIEF,
8288 XBM_ALGORITHM,
8289 XBM_HEURISTIC_MASK,
8290 XBM_LAST
8291 };
8292
8293 /* Vector of image_keyword structures describing the format
8294 of valid XBM image specifications. */
8295
8296 static struct image_keyword xbm_format[XBM_LAST] =
8297 {
8298 {":type", IMAGE_SYMBOL_VALUE, 1},
8299 {":file", IMAGE_STRING_VALUE, 0},
8300 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
8301 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
8302 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8303 {":foreground", IMAGE_STRING_VALUE, 0},
8304 {":background", IMAGE_STRING_VALUE, 0},
8305 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8306 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
8307 {":relief", IMAGE_INTEGER_VALUE, 0},
8308 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8309 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
8310 };
8311
8312 /* Structure describing the image type XBM. */
8313
8314 static struct image_type xbm_type =
8315 {
8316 &Qxbm,
8317 xbm_image_p,
8318 xbm_load,
8319 x_clear_image,
8320 NULL
8321 };
8322
8323 /* Tokens returned from xbm_scan. */
8324
8325 enum xbm_token
8326 {
8327 XBM_TK_IDENT = 256,
8328 XBM_TK_NUMBER
8329 };
8330
8331
8332 /* Return non-zero if OBJECT is a valid XBM-type image specification.
8333 A valid specification is a list starting with the symbol `image'
8334 The rest of the list is a property list which must contain an
8335 entry `:type xbm..
8336
8337 If the specification specifies a file to load, it must contain
8338 an entry `:file FILENAME' where FILENAME is a string.
8339
8340 If the specification is for a bitmap loaded from memory it must
8341 contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
8342 WIDTH and HEIGHT are integers > 0. DATA may be:
8343
8344 1. a string large enough to hold the bitmap data, i.e. it must
8345 have a size >= (WIDTH + 7) / 8 * HEIGHT
8346
8347 2. a bool-vector of size >= WIDTH * HEIGHT
8348
8349 3. a vector of strings or bool-vectors, one for each line of the
8350 bitmap.
8351
8352 Both the file and data forms may contain the additional entries
8353 `:background COLOR' and `:foreground COLOR'. If not present,
8354 foreground and background of the frame on which the image is
8355 displayed, is used. */
8356
8357 static int
8358 xbm_image_p (object)
8359 Lisp_Object object;
8360 {
8361 struct image_keyword kw[XBM_LAST];
8362
8363 bcopy (xbm_format, kw, sizeof kw);
8364 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
8365 return 0;
8366
8367 xassert (EQ (kw[XBM_TYPE].value, Qxbm));
8368
8369 if (kw[XBM_FILE].count)
8370 {
8371 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
8372 return 0;
8373 }
8374 else
8375 {
8376 Lisp_Object data;
8377 int width, height;
8378
8379 /* Entries for `:width', `:height' and `:data' must be present. */
8380 if (!kw[XBM_WIDTH].count
8381 || !kw[XBM_HEIGHT].count
8382 || !kw[XBM_DATA].count)
8383 return 0;
8384
8385 data = kw[XBM_DATA].value;
8386 width = XFASTINT (kw[XBM_WIDTH].value);
8387 height = XFASTINT (kw[XBM_HEIGHT].value);
8388
8389 /* Check type of data, and width and height against contents of
8390 data. */
8391 if (VECTORP (data))
8392 {
8393 int i;
8394
8395 /* Number of elements of the vector must be >= height. */
8396 if (XVECTOR (data)->size < height)
8397 return 0;
8398
8399 /* Each string or bool-vector in data must be large enough
8400 for one line of the image. */
8401 for (i = 0; i < height; ++i)
8402 {
8403 Lisp_Object elt = XVECTOR (data)->contents[i];
8404
8405 if (STRINGP (elt))
8406 {
8407 if (XSTRING (elt)->size
8408 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
8409 return 0;
8410 }
8411 else if (BOOL_VECTOR_P (elt))
8412 {
8413 if (XBOOL_VECTOR (elt)->size < width)
8414 return 0;
8415 }
8416 else
8417 return 0;
8418 }
8419 }
8420 else if (STRINGP (data))
8421 {
8422 if (XSTRING (data)->size
8423 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
8424 return 0;
8425 }
8426 else if (BOOL_VECTOR_P (data))
8427 {
8428 if (XBOOL_VECTOR (data)->size < width * height)
8429 return 0;
8430 }
8431 else
8432 return 0;
8433 }
8434
8435 /* Baseline must be a value between 0 and 100 (a percentage). */
8436 if (kw[XBM_ASCENT].count
8437 && XFASTINT (kw[XBM_ASCENT].value) > 100)
8438 return 0;
8439
8440 return 1;
8441 }
8442
8443
8444 /* Scan a bitmap file. FP is the stream to read from. Value is
8445 either an enumerator from enum xbm_token, or a character for a
8446 single-character token, or 0 at end of file. If scanning an
8447 identifier, store the lexeme of the identifier in SVAL. If
8448 scanning a number, store its value in *IVAL. */
8449
8450 static int
8451 xbm_scan (fp, sval, ival)
8452 FILE *fp;
8453 char *sval;
8454 int *ival;
8455 {
8456 int c;
8457
8458 /* Skip white space. */
8459 while ((c = fgetc (fp)) != EOF && isspace (c))
8460 ;
8461
8462 if (c == EOF)
8463 c = 0;
8464 else if (isdigit (c))
8465 {
8466 int value = 0, digit;
8467
8468 if (c == '0')
8469 {
8470 c = fgetc (fp);
8471 if (c == 'x' || c == 'X')
8472 {
8473 while ((c = fgetc (fp)) != EOF)
8474 {
8475 if (isdigit (c))
8476 digit = c - '0';
8477 else if (c >= 'a' && c <= 'f')
8478 digit = c - 'a' + 10;
8479 else if (c >= 'A' && c <= 'F')
8480 digit = c - 'A' + 10;
8481 else
8482 break;
8483 value = 16 * value + digit;
8484 }
8485 }
8486 else if (isdigit (c))
8487 {
8488 value = c - '0';
8489 while ((c = fgetc (fp)) != EOF
8490 && isdigit (c))
8491 value = 8 * value + c - '0';
8492 }
8493 }
8494 else
8495 {
8496 value = c - '0';
8497 while ((c = fgetc (fp)) != EOF
8498 && isdigit (c))
8499 value = 10 * value + c - '0';
8500 }
8501
8502 if (c != EOF)
8503 ungetc (c, fp);
8504 *ival = value;
8505 c = XBM_TK_NUMBER;
8506 }
8507 else if (isalpha (c) || c == '_')
8508 {
8509 *sval++ = c;
8510 while ((c = fgetc (fp)) != EOF
8511 && (isalnum (c) || c == '_'))
8512 *sval++ = c;
8513 *sval = 0;
8514 if (c != EOF)
8515 ungetc (c, fp);
8516 c = XBM_TK_IDENT;
8517 }
8518
8519 return c;
8520 }
8521
8522
8523 /* Replacement for XReadBitmapFileData which isn't available under old
8524 X versions. FILE is the name of the bitmap file to read. Set
8525 *WIDTH and *HEIGHT to the width and height of the image. Return in
8526 *DATA the bitmap data allocated with xmalloc. Value is non-zero if
8527 successful. */
8528
8529 static int
8530 xbm_read_bitmap_file_data (file, width, height, data)
8531 char *file;
8532 int *width, *height;
8533 unsigned char **data;
8534 {
8535 FILE *fp;
8536 char buffer[BUFSIZ];
8537 int padding_p = 0;
8538 int v10 = 0;
8539 int bytes_per_line, i, nbytes;
8540 unsigned char *p;
8541 int value;
8542 int LA1;
8543
8544 #define match() \
8545 LA1 = xbm_scan (fp, buffer, &value)
8546
8547 #define expect(TOKEN) \
8548 if (LA1 != (TOKEN)) \
8549 goto failure; \
8550 else \
8551 match ()
8552
8553 #define expect_ident(IDENT) \
8554 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
8555 match (); \
8556 else \
8557 goto failure
8558
8559 fp = fopen (file, "r");
8560 if (fp == NULL)
8561 return 0;
8562
8563 *width = *height = -1;
8564 *data = NULL;
8565 LA1 = xbm_scan (fp, buffer, &value);
8566
8567 /* Parse defines for width, height and hot-spots. */
8568 while (LA1 == '#')
8569 {
8570 match ();
8571 expect_ident ("define");
8572 expect (XBM_TK_IDENT);
8573
8574 if (LA1 == XBM_TK_NUMBER);
8575 {
8576 char *p = strrchr (buffer, '_');
8577 p = p ? p + 1 : buffer;
8578 if (strcmp (p, "width") == 0)
8579 *width = value;
8580 else if (strcmp (p, "height") == 0)
8581 *height = value;
8582 }
8583 expect (XBM_TK_NUMBER);
8584 }
8585
8586 if (*width < 0 || *height < 0)
8587 goto failure;
8588
8589 /* Parse bits. Must start with `static'. */
8590 expect_ident ("static");
8591 if (LA1 == XBM_TK_IDENT)
8592 {
8593 if (strcmp (buffer, "unsigned") == 0)
8594 {
8595 match ();
8596 expect_ident ("char");
8597 }
8598 else if (strcmp (buffer, "short") == 0)
8599 {
8600 match ();
8601 v10 = 1;
8602 if (*width % 16 && *width % 16 < 9)
8603 padding_p = 1;
8604 }
8605 else if (strcmp (buffer, "char") == 0)
8606 match ();
8607 else
8608 goto failure;
8609 }
8610 else
8611 goto failure;
8612
8613 expect (XBM_TK_IDENT);
8614 expect ('[');
8615 expect (']');
8616 expect ('=');
8617 expect ('{');
8618
8619 bytes_per_line = (*width + 7) / 8 + padding_p;
8620 nbytes = bytes_per_line * *height;
8621 p = *data = (char *) xmalloc (nbytes);
8622
8623 if (v10)
8624 {
8625
8626 for (i = 0; i < nbytes; i += 2)
8627 {
8628 int val = value;
8629 expect (XBM_TK_NUMBER);
8630
8631 *p++ = val;
8632 if (!padding_p || ((i + 2) % bytes_per_line))
8633 *p++ = value >> 8;
8634
8635 if (LA1 == ',' || LA1 == '}')
8636 match ();
8637 else
8638 goto failure;
8639 }
8640 }
8641 else
8642 {
8643 for (i = 0; i < nbytes; ++i)
8644 {
8645 int val = value;
8646 expect (XBM_TK_NUMBER);
8647
8648 *p++ = val;
8649
8650 if (LA1 == ',' || LA1 == '}')
8651 match ();
8652 else
8653 goto failure;
8654 }
8655 }
8656
8657 fclose (fp);
8658 return 1;
8659
8660 failure:
8661
8662 fclose (fp);
8663 if (*data)
8664 {
8665 xfree (*data);
8666 *data = NULL;
8667 }
8668 return 0;
8669
8670 #undef match
8671 #undef expect
8672 #undef expect_ident
8673 }
8674
8675
8676 /* Load XBM image IMG which will be displayed on frame F from file
8677 SPECIFIED_FILE. Value is non-zero if successful. */
8678
8679 static int
8680 xbm_load_image_from_file (f, img, specified_file)
8681 struct frame *f;
8682 struct image *img;
8683 Lisp_Object specified_file;
8684 {
8685 int rc;
8686 unsigned char *data;
8687 int success_p = 0;
8688 Lisp_Object file;
8689 struct gcpro gcpro1;
8690
8691 xassert (STRINGP (specified_file));
8692 file = Qnil;
8693 GCPRO1 (file);
8694
8695 file = x_find_image_file (specified_file);
8696 if (!STRINGP (file))
8697 {
8698 image_error ("Cannot find image file `%s'", specified_file, Qnil);
8699 UNGCPRO;
8700 return 0;
8701 }
8702
8703 rc = xbm_read_bitmap_file_data (XSTRING (file)->data, &img->width,
8704 &img->height, &data);
8705 if (rc)
8706 {
8707 int depth = one_w32_display_info.n_cbits;
8708 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
8709 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
8710 Lisp_Object value;
8711
8712 xassert (img->width > 0 && img->height > 0);
8713
8714 /* Get foreground and background colors, maybe allocate colors. */
8715 value = image_spec_value (img->spec, QCforeground, NULL);
8716 if (!NILP (value))
8717 foreground = x_alloc_image_color (f, img, value, foreground);
8718
8719 value = image_spec_value (img->spec, QCbackground, NULL);
8720 if (!NILP (value))
8721 background = x_alloc_image_color (f, img, value, background);
8722
8723 #if 0 /* NTEMACS_TODO : Port image display to W32 */
8724 BLOCK_INPUT;
8725 img->pixmap
8726 = XCreatePixmapFromBitmapData (FRAME_W32_DISPLAY (f),
8727 FRAME_W32_WINDOW (f),
8728 data,
8729 img->width, img->height,
8730 foreground, background,
8731 depth);
8732 xfree (data);
8733
8734 if (img->pixmap == 0)
8735 {
8736 x_clear_image (f, img);
8737 image_error ("Unable to create X pixmap for `%s'", file, Qnil);
8738 }
8739 else
8740 success_p = 1;
8741
8742 UNBLOCK_INPUT;
8743 #endif
8744 }
8745 else
8746 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
8747
8748 UNGCPRO;
8749 return success_p;
8750 }
8751
8752
8753 /* Fill image IMG which is used on frame F with pixmap data. Value is
8754 non-zero if successful. */
8755
8756 static int
8757 xbm_load (f, img)
8758 struct frame *f;
8759 struct image *img;
8760 {
8761 int success_p = 0;
8762 Lisp_Object file_name;
8763
8764 xassert (xbm_image_p (img->spec));
8765
8766 /* If IMG->spec specifies a file name, create a non-file spec from it. */
8767 file_name = image_spec_value (img->spec, QCfile, NULL);
8768 if (STRINGP (file_name))
8769 success_p = xbm_load_image_from_file (f, img, file_name);
8770 else
8771 {
8772 struct image_keyword fmt[XBM_LAST];
8773 Lisp_Object data;
8774 int depth;
8775 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
8776 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
8777 char *bits;
8778 int parsed_p;
8779
8780 /* Parse the list specification. */
8781 bcopy (xbm_format, fmt, sizeof fmt);
8782 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
8783 xassert (parsed_p);
8784
8785 /* Get specified width, and height. */
8786 img->width = XFASTINT (fmt[XBM_WIDTH].value);
8787 img->height = XFASTINT (fmt[XBM_HEIGHT].value);
8788 xassert (img->width > 0 && img->height > 0);
8789
8790 BLOCK_INPUT;
8791
8792 if (fmt[XBM_ASCENT].count)
8793 img->ascent = XFASTINT (fmt[XBM_ASCENT].value);
8794
8795 /* Get foreground and background colors, maybe allocate colors. */
8796 if (fmt[XBM_FOREGROUND].count)
8797 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
8798 foreground);
8799 if (fmt[XBM_BACKGROUND].count)
8800 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
8801 background);
8802
8803 /* Set bits to the bitmap image data. */
8804 data = fmt[XBM_DATA].value;
8805 if (VECTORP (data))
8806 {
8807 int i;
8808 char *p;
8809 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
8810
8811 p = bits = (char *) alloca (nbytes * img->height);
8812 for (i = 0; i < img->height; ++i, p += nbytes)
8813 {
8814 Lisp_Object line = XVECTOR (data)->contents[i];
8815 if (STRINGP (line))
8816 bcopy (XSTRING (line)->data, p, nbytes);
8817 else
8818 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
8819 }
8820 }
8821 else if (STRINGP (data))
8822 bits = XSTRING (data)->data;
8823 else
8824 bits = XBOOL_VECTOR (data)->data;
8825
8826 #if 0 /* NTEMACS_TODO : W32 XPM code */
8827 /* Create the pixmap. */
8828 depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
8829 img->pixmap
8830 = XCreatePixmapFromBitmapData (FRAME_W32_DISPLAY (f),
8831 FRAME_W32_WINDOW (f),
8832 bits,
8833 img->width, img->height,
8834 foreground, background,
8835 depth);
8836 #endif /* NTEMACS_TODO */
8837
8838 if (img->pixmap)
8839 success_p = 1;
8840 else
8841 {
8842 image_error ("Unable to create pixmap for XBM image `%s'",
8843 img->spec, Qnil);
8844 x_clear_image (f, img);
8845 }
8846
8847 UNBLOCK_INPUT;
8848 }
8849
8850 return success_p;
8851 }
8852
8853
8854 \f
8855 /***********************************************************************
8856 XPM images
8857 ***********************************************************************/
8858
8859 #if HAVE_XPM
8860
8861 static int xpm_image_p P_ ((Lisp_Object object));
8862 static int xpm_load P_ ((struct frame *f, struct image *img));
8863 static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
8864
8865 #include "X11/xpm.h"
8866
8867 /* The symbol `xpm' identifying XPM-format images. */
8868
8869 Lisp_Object Qxpm;
8870
8871 /* Indices of image specification fields in xpm_format, below. */
8872
8873 enum xpm_keyword_index
8874 {
8875 XPM_TYPE,
8876 XPM_FILE,
8877 XPM_DATA,
8878 XPM_ASCENT,
8879 XPM_MARGIN,
8880 XPM_RELIEF,
8881 XPM_ALGORITHM,
8882 XPM_HEURISTIC_MASK,
8883 XPM_COLOR_SYMBOLS,
8884 XPM_LAST
8885 };
8886
8887 /* Vector of image_keyword structures describing the format
8888 of valid XPM image specifications. */
8889
8890 static struct image_keyword xpm_format[XPM_LAST] =
8891 {
8892 {":type", IMAGE_SYMBOL_VALUE, 1},
8893 {":file", IMAGE_STRING_VALUE, 0},
8894 {":data", IMAGE_STRING_VALUE, 0},
8895 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8896 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
8897 {":relief", IMAGE_INTEGER_VALUE, 0},
8898 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8899 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8900 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
8901 };
8902
8903 /* Structure describing the image type XBM. */
8904
8905 static struct image_type xpm_type =
8906 {
8907 &Qxpm,
8908 xpm_image_p,
8909 xpm_load,
8910 x_clear_image,
8911 NULL
8912 };
8913
8914
8915 /* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
8916 for XPM images. Such a list must consist of conses whose car and
8917 cdr are strings. */
8918
8919 static int
8920 xpm_valid_color_symbols_p (color_symbols)
8921 Lisp_Object color_symbols;
8922 {
8923 while (CONSP (color_symbols))
8924 {
8925 Lisp_Object sym = XCAR (color_symbols);
8926 if (!CONSP (sym)
8927 || !STRINGP (XCAR (sym))
8928 || !STRINGP (XCDR (sym)))
8929 break;
8930 color_symbols = XCDR (color_symbols);
8931 }
8932
8933 return NILP (color_symbols);
8934 }
8935
8936
8937 /* Value is non-zero if OBJECT is a valid XPM image specification. */
8938
8939 static int
8940 xpm_image_p (object)
8941 Lisp_Object object;
8942 {
8943 struct image_keyword fmt[XPM_LAST];
8944 bcopy (xpm_format, fmt, sizeof fmt);
8945 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
8946 /* Either `:file' or `:data' must be present. */
8947 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
8948 /* Either no `:color-symbols' or it's a list of conses
8949 whose car and cdr are strings. */
8950 && (fmt[XPM_COLOR_SYMBOLS].count == 0
8951 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value))
8952 && (fmt[XPM_ASCENT].count == 0
8953 || XFASTINT (fmt[XPM_ASCENT].value) < 100));
8954 }
8955
8956
8957 /* Load image IMG which will be displayed on frame F. Value is
8958 non-zero if successful. */
8959
8960 static int
8961 xpm_load (f, img)
8962 struct frame *f;
8963 struct image *img;
8964 {
8965 int rc, i;
8966 XpmAttributes attrs;
8967 Lisp_Object specified_file, color_symbols;
8968
8969 /* Configure the XPM lib. Use the visual of frame F. Allocate
8970 close colors. Return colors allocated. */
8971 bzero (&attrs, sizeof attrs);
8972 attrs.visual = FRAME_X_VISUAL (f);
8973 attrs.colormap = FRAME_X_COLORMAP (f);
8974 attrs.valuemask |= XpmVisual;
8975 attrs.valuemask |= XpmColormap;
8976 attrs.valuemask |= XpmReturnAllocPixels;
8977 #ifdef XpmAllocCloseColors
8978 attrs.alloc_close_colors = 1;
8979 attrs.valuemask |= XpmAllocCloseColors;
8980 #else
8981 attrs.closeness = 600;
8982 attrs.valuemask |= XpmCloseness;
8983 #endif
8984
8985 /* If image specification contains symbolic color definitions, add
8986 these to `attrs'. */
8987 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
8988 if (CONSP (color_symbols))
8989 {
8990 Lisp_Object tail;
8991 XpmColorSymbol *xpm_syms;
8992 int i, size;
8993
8994 attrs.valuemask |= XpmColorSymbols;
8995
8996 /* Count number of symbols. */
8997 attrs.numsymbols = 0;
8998 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
8999 ++attrs.numsymbols;
9000
9001 /* Allocate an XpmColorSymbol array. */
9002 size = attrs.numsymbols * sizeof *xpm_syms;
9003 xpm_syms = (XpmColorSymbol *) alloca (size);
9004 bzero (xpm_syms, size);
9005 attrs.colorsymbols = xpm_syms;
9006
9007 /* Fill the color symbol array. */
9008 for (tail = color_symbols, i = 0;
9009 CONSP (tail);
9010 ++i, tail = XCDR (tail))
9011 {
9012 Lisp_Object name = XCAR (XCAR (tail));
9013 Lisp_Object color = XCDR (XCAR (tail));
9014 xpm_syms[i].name = (char *) alloca (XSTRING (name)->size + 1);
9015 strcpy (xpm_syms[i].name, XSTRING (name)->data);
9016 xpm_syms[i].value = (char *) alloca (XSTRING (color)->size + 1);
9017 strcpy (xpm_syms[i].value, XSTRING (color)->data);
9018 }
9019 }
9020
9021 /* Create a pixmap for the image, either from a file, or from a
9022 string buffer containing data in the same format as an XPM file. */
9023 BLOCK_INPUT;
9024 specified_file = image_spec_value (img->spec, QCfile, NULL);
9025 if (STRINGP (specified_file))
9026 {
9027 Lisp_Object file = x_find_image_file (specified_file);
9028 if (!STRINGP (file))
9029 {
9030 image_error ("Cannot find image file `%s'", specified_file, Qnil);
9031 UNBLOCK_INPUT;
9032 return 0;
9033 }
9034
9035 rc = XpmReadFileToPixmap (NULL, FRAME_W32_WINDOW (f),
9036 XSTRING (file)->data, &img->pixmap, &img->mask,
9037 &attrs);
9038 }
9039 else
9040 {
9041 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
9042 rc = XpmCreatePixmapFromBuffer (NULL, FRAME_W32_WINDOW (f),
9043 XSTRING (buffer)->data,
9044 &img->pixmap, &img->mask,
9045 &attrs);
9046 }
9047 UNBLOCK_INPUT;
9048
9049 if (rc == XpmSuccess)
9050 {
9051 /* Remember allocated colors. */
9052 img->ncolors = attrs.nalloc_pixels;
9053 img->colors = (unsigned long *) xmalloc (img->ncolors
9054 * sizeof *img->colors);
9055 for (i = 0; i < attrs.nalloc_pixels; ++i)
9056 img->colors[i] = attrs.alloc_pixels[i];
9057
9058 img->width = attrs.width;
9059 img->height = attrs.height;
9060 xassert (img->width > 0 && img->height > 0);
9061
9062 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
9063 BLOCK_INPUT;
9064 XpmFreeAttributes (&attrs);
9065 UNBLOCK_INPUT;
9066 }
9067 else
9068 {
9069 switch (rc)
9070 {
9071 case XpmOpenFailed:
9072 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
9073 break;
9074
9075 case XpmFileInvalid:
9076 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
9077 break;
9078
9079 case XpmNoMemory:
9080 image_error ("Out of memory (%s)", img->spec, Qnil);
9081 break;
9082
9083 case XpmColorFailed:
9084 image_error ("Color allocation error (%s)", img->spec, Qnil);
9085 break;
9086
9087 default:
9088 image_error ("Unknown error (%s)", img->spec, Qnil);
9089 break;
9090 }
9091 }
9092
9093 return rc == XpmSuccess;
9094 }
9095
9096 #endif /* HAVE_XPM != 0 */
9097
9098 \f
9099 #if 0 /* NTEMACS_TODO : Color tables on W32. */
9100 /***********************************************************************
9101 Color table
9102 ***********************************************************************/
9103
9104 /* An entry in the color table mapping an RGB color to a pixel color. */
9105
9106 struct ct_color
9107 {
9108 int r, g, b;
9109 unsigned long pixel;
9110
9111 /* Next in color table collision list. */
9112 struct ct_color *next;
9113 };
9114
9115 /* The bucket vector size to use. Must be prime. */
9116
9117 #define CT_SIZE 101
9118
9119 /* Value is a hash of the RGB color given by R, G, and B. */
9120
9121 #define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
9122
9123 /* The color hash table. */
9124
9125 struct ct_color **ct_table;
9126
9127 /* Number of entries in the color table. */
9128
9129 int ct_colors_allocated;
9130
9131 /* Function prototypes. */
9132
9133 static void init_color_table P_ ((void));
9134 static void free_color_table P_ ((void));
9135 static unsigned long *colors_in_color_table P_ ((int *n));
9136 static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
9137 static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
9138
9139
9140 /* Initialize the color table. */
9141
9142 static void
9143 init_color_table ()
9144 {
9145 int size = CT_SIZE * sizeof (*ct_table);
9146 ct_table = (struct ct_color **) xmalloc (size);
9147 bzero (ct_table, size);
9148 ct_colors_allocated = 0;
9149 }
9150
9151
9152 /* Free memory associated with the color table. */
9153
9154 static void
9155 free_color_table ()
9156 {
9157 int i;
9158 struct ct_color *p, *next;
9159
9160 for (i = 0; i < CT_SIZE; ++i)
9161 for (p = ct_table[i]; p; p = next)
9162 {
9163 next = p->next;
9164 xfree (p);
9165 }
9166
9167 xfree (ct_table);
9168 ct_table = NULL;
9169 }
9170
9171
9172 /* Value is a pixel color for RGB color R, G, B on frame F. If an
9173 entry for that color already is in the color table, return the
9174 pixel color of that entry. Otherwise, allocate a new color for R,
9175 G, B, and make an entry in the color table. */
9176
9177 static unsigned long
9178 lookup_rgb_color (f, r, g, b)
9179 struct frame *f;
9180 int r, g, b;
9181 {
9182 unsigned hash = CT_HASH_RGB (r, g, b);
9183 int i = hash % CT_SIZE;
9184 struct ct_color *p;
9185
9186 for (p = ct_table[i]; p; p = p->next)
9187 if (p->r == r && p->g == g && p->b == b)
9188 break;
9189
9190 if (p == NULL)
9191 {
9192 COLORREF color;
9193 Colormap cmap;
9194 int rc;
9195
9196 color = PALETTERGB (r, g, b);
9197
9198 ++ct_colors_allocated;
9199
9200 p = (struct ct_color *) xmalloc (sizeof *p);
9201 p->r = r;
9202 p->g = g;
9203 p->b = b;
9204 p->pixel = color;
9205 p->next = ct_table[i];
9206 ct_table[i] = p;
9207 }
9208
9209 return p->pixel;
9210 }
9211
9212
9213 /* Look up pixel color PIXEL which is used on frame F in the color
9214 table. If not already present, allocate it. Value is PIXEL. */
9215
9216 static unsigned long
9217 lookup_pixel_color (f, pixel)
9218 struct frame *f;
9219 unsigned long pixel;
9220 {
9221 int i = pixel % CT_SIZE;
9222 struct ct_color *p;
9223
9224 for (p = ct_table[i]; p; p = p->next)
9225 if (p->pixel == pixel)
9226 break;
9227
9228 if (p == NULL)
9229 {
9230 XColor color;
9231 Colormap cmap;
9232 int rc;
9233
9234 BLOCK_INPUT;
9235
9236 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
9237 color.pixel = pixel;
9238 XQueryColor (NULL, cmap, &color);
9239 rc = x_alloc_nearest_color (f, cmap, &color);
9240 UNBLOCK_INPUT;
9241
9242 if (rc)
9243 {
9244 ++ct_colors_allocated;
9245
9246 p = (struct ct_color *) xmalloc (sizeof *p);
9247 p->r = color.red;
9248 p->g = color.green;
9249 p->b = color.blue;
9250 p->pixel = pixel;
9251 p->next = ct_table[i];
9252 ct_table[i] = p;
9253 }
9254 else
9255 return FRAME_FOREGROUND_PIXEL (f);
9256 }
9257 return p->pixel;
9258 }
9259
9260
9261 /* Value is a vector of all pixel colors contained in the color table,
9262 allocated via xmalloc. Set *N to the number of colors. */
9263
9264 static unsigned long *
9265 colors_in_color_table (n)
9266 int *n;
9267 {
9268 int i, j;
9269 struct ct_color *p;
9270 unsigned long *colors;
9271
9272 if (ct_colors_allocated == 0)
9273 {
9274 *n = 0;
9275 colors = NULL;
9276 }
9277 else
9278 {
9279 colors = (unsigned long *) xmalloc (ct_colors_allocated
9280 * sizeof *colors);
9281 *n = ct_colors_allocated;
9282
9283 for (i = j = 0; i < CT_SIZE; ++i)
9284 for (p = ct_table[i]; p; p = p->next)
9285 colors[j++] = p->pixel;
9286 }
9287
9288 return colors;
9289 }
9290
9291 #endif /* NTEMACS_TODO */
9292
9293 \f
9294 /***********************************************************************
9295 Algorithms
9296 ***********************************************************************/
9297
9298 #if 0 /* NTEMACS_TODO : W32 versions of low level algorithms */
9299 static void x_laplace_write_row P_ ((struct frame *, long *,
9300 int, XImage *, int));
9301 static void x_laplace_read_row P_ ((struct frame *, Colormap,
9302 XColor *, int, XImage *, int));
9303
9304
9305 /* Fill COLORS with RGB colors from row Y of image XIMG. F is the
9306 frame we operate on, CMAP is the color-map in effect, and WIDTH is
9307 the width of one row in the image. */
9308
9309 static void
9310 x_laplace_read_row (f, cmap, colors, width, ximg, y)
9311 struct frame *f;
9312 Colormap cmap;
9313 XColor *colors;
9314 int width;
9315 XImage *ximg;
9316 int y;
9317 {
9318 int x;
9319
9320 for (x = 0; x < width; ++x)
9321 colors[x].pixel = XGetPixel (ximg, x, y);
9322
9323 XQueryColors (NULL, cmap, colors, width);
9324 }
9325
9326
9327 /* Write row Y of image XIMG. PIXELS is an array of WIDTH longs
9328 containing the pixel colors to write. F is the frame we are
9329 working on. */
9330
9331 static void
9332 x_laplace_write_row (f, pixels, width, ximg, y)
9333 struct frame *f;
9334 long *pixels;
9335 int width;
9336 XImage *ximg;
9337 int y;
9338 {
9339 int x;
9340
9341 for (x = 0; x < width; ++x)
9342 XPutPixel (ximg, x, y, pixels[x]);
9343 }
9344 #endif
9345
9346 /* Transform image IMG which is used on frame F with a Laplace
9347 edge-detection algorithm. The result is an image that can be used
9348 to draw disabled buttons, for example. */
9349
9350 static void
9351 x_laplace (f, img)
9352 struct frame *f;
9353 struct image *img;
9354 {
9355 #if 0 /* NTEMACS_TODO : W32 version */
9356 Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
9357 XImage *ximg, *oimg;
9358 XColor *in[3];
9359 long *out;
9360 Pixmap pixmap;
9361 int x, y, i;
9362 long pixel;
9363 int in_y, out_y, rc;
9364 int mv2 = 45000;
9365
9366 BLOCK_INPUT;
9367
9368 /* Get the X image IMG->pixmap. */
9369 ximg = XGetImage (NULL, img->pixmap,
9370 0, 0, img->width, img->height, ~0, ZPixmap);
9371
9372 /* Allocate 3 input rows, and one output row of colors. */
9373 for (i = 0; i < 3; ++i)
9374 in[i] = (XColor *) alloca (img->width * sizeof (XColor));
9375 out = (long *) alloca (img->width * sizeof (long));
9376
9377 /* Create an X image for output. */
9378 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 0,
9379 &oimg, &pixmap);
9380
9381 /* Fill first two rows. */
9382 x_laplace_read_row (f, cmap, in[0], img->width, ximg, 0);
9383 x_laplace_read_row (f, cmap, in[1], img->width, ximg, 1);
9384 in_y = 2;
9385
9386 /* Write first row, all zeros. */
9387 init_color_table ();
9388 pixel = lookup_rgb_color (f, 0, 0, 0);
9389 for (x = 0; x < img->width; ++x)
9390 out[x] = pixel;
9391 x_laplace_write_row (f, out, img->width, oimg, 0);
9392 out_y = 1;
9393
9394 for (y = 2; y < img->height; ++y)
9395 {
9396 int rowa = y % 3;
9397 int rowb = (y + 2) % 3;
9398
9399 x_laplace_read_row (f, cmap, in[rowa], img->width, ximg, in_y++);
9400
9401 for (x = 0; x < img->width - 2; ++x)
9402 {
9403 int r = in[rowa][x].red + mv2 - in[rowb][x + 2].red;
9404 int g = in[rowa][x].green + mv2 - in[rowb][x + 2].green;
9405 int b = in[rowa][x].blue + mv2 - in[rowb][x + 2].blue;
9406
9407 out[x + 1] = lookup_rgb_color (f, r & 0xffff, g & 0xffff,
9408 b & 0xffff);
9409 }
9410
9411 x_laplace_write_row (f, out, img->width, oimg, out_y++);
9412 }
9413
9414 /* Write last line, all zeros. */
9415 for (x = 0; x < img->width; ++x)
9416 out[x] = pixel;
9417 x_laplace_write_row (f, out, img->width, oimg, out_y);
9418
9419 /* Free the input image, and free resources of IMG. */
9420 XDestroyImage (ximg);
9421 x_clear_image (f, img);
9422
9423 /* Put the output image into pixmap, and destroy it. */
9424 x_put_x_image (f, oimg, pixmap, img->width, img->height);
9425 x_destroy_x_image (oimg);
9426
9427 /* Remember new pixmap and colors in IMG. */
9428 img->pixmap = pixmap;
9429 img->colors = colors_in_color_table (&img->ncolors);
9430 free_color_table ();
9431
9432 UNBLOCK_INPUT;
9433 #endif /* NTEMACS_TODO */
9434 }
9435
9436
9437 /* Build a mask for image IMG which is used on frame F. FILE is the
9438 name of an image file, for error messages. HOW determines how to
9439 determine the background color of IMG. If it is a list '(R G B)',
9440 with R, G, and B being integers >= 0, take that as the color of the
9441 background. Otherwise, determine the background color of IMG
9442 heuristically. Value is non-zero if successful. */
9443
9444 static int
9445 x_build_heuristic_mask (f, img, how)
9446 struct frame *f;
9447 struct image *img;
9448 Lisp_Object how;
9449 {
9450 #if 0 /* NTEMACS_TODO : W32 version */
9451 Display *dpy = FRAME_W32_DISPLAY (f);
9452 XImage *ximg, *mask_img;
9453 int x, y, rc, look_at_corners_p;
9454 unsigned long bg;
9455
9456 BLOCK_INPUT;
9457
9458 /* Create an image and pixmap serving as mask. */
9459 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
9460 &mask_img, &img->mask);
9461 if (!rc)
9462 {
9463 UNBLOCK_INPUT;
9464 return 0;
9465 }
9466
9467 /* Get the X image of IMG->pixmap. */
9468 ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height,
9469 ~0, ZPixmap);
9470
9471 /* Determine the background color of ximg. If HOW is `(R G B)'
9472 take that as color. Otherwise, try to determine the color
9473 heuristically. */
9474 look_at_corners_p = 1;
9475
9476 if (CONSP (how))
9477 {
9478 int rgb[3], i = 0;
9479
9480 while (i < 3
9481 && CONSP (how)
9482 && NATNUMP (XCAR (how)))
9483 {
9484 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
9485 how = XCDR (how);
9486 }
9487
9488 if (i == 3 && NILP (how))
9489 {
9490 char color_name[30];
9491 XColor exact, color;
9492 Colormap cmap;
9493
9494 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
9495
9496 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
9497 if (XLookupColor (dpy, cmap, color_name, &exact, &color))
9498 {
9499 bg = color.pixel;
9500 look_at_corners_p = 0;
9501 }
9502 }
9503 }
9504
9505 if (look_at_corners_p)
9506 {
9507 unsigned long corners[4];
9508 int i, best_count;
9509
9510 /* Get the colors at the corners of ximg. */
9511 corners[0] = XGetPixel (ximg, 0, 0);
9512 corners[1] = XGetPixel (ximg, img->width - 1, 0);
9513 corners[2] = XGetPixel (ximg, img->width - 1, img->height - 1);
9514 corners[3] = XGetPixel (ximg, 0, img->height - 1);
9515
9516 /* Choose the most frequently found color as background. */
9517 for (i = best_count = 0; i < 4; ++i)
9518 {
9519 int j, n;
9520
9521 for (j = n = 0; j < 4; ++j)
9522 if (corners[i] == corners[j])
9523 ++n;
9524
9525 if (n > best_count)
9526 bg = corners[i], best_count = n;
9527 }
9528 }
9529
9530 /* Set all bits in mask_img to 1 whose color in ximg is different
9531 from the background color bg. */
9532 for (y = 0; y < img->height; ++y)
9533 for (x = 0; x < img->width; ++x)
9534 XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg);
9535
9536 /* Put mask_img into img->mask. */
9537 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
9538 x_destroy_x_image (mask_img);
9539 XDestroyImage (ximg);
9540
9541 UNBLOCK_INPUT;
9542 #endif /* NTEMACS_TODO */
9543
9544 return 1;
9545 }
9546
9547
9548 \f
9549 /***********************************************************************
9550 PBM (mono, gray, color)
9551 ***********************************************************************/
9552 #ifdef HAVE_PBM
9553
9554 static int pbm_image_p P_ ((Lisp_Object object));
9555 static int pbm_load P_ ((struct frame *f, struct image *img));
9556 static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
9557
9558 /* The symbol `pbm' identifying images of this type. */
9559
9560 Lisp_Object Qpbm;
9561
9562 /* Indices of image specification fields in gs_format, below. */
9563
9564 enum pbm_keyword_index
9565 {
9566 PBM_TYPE,
9567 PBM_FILE,
9568 PBM_DATA,
9569 PBM_ASCENT,
9570 PBM_MARGIN,
9571 PBM_RELIEF,
9572 PBM_ALGORITHM,
9573 PBM_HEURISTIC_MASK,
9574 PBM_LAST
9575 };
9576
9577 /* Vector of image_keyword structures describing the format
9578 of valid user-defined image specifications. */
9579
9580 static struct image_keyword pbm_format[PBM_LAST] =
9581 {
9582 {":type", IMAGE_SYMBOL_VALUE, 1},
9583 {":file", IMAGE_STRING_VALUE, 0},
9584 {":data", IMAGE_STRING_VALUE, 0},
9585 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
9586 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9587 {":relief", IMAGE_INTEGER_VALUE, 0},
9588 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9589 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
9590 };
9591
9592 /* Structure describing the image type `pbm'. */
9593
9594 static struct image_type pbm_type =
9595 {
9596 &Qpbm,
9597 pbm_image_p,
9598 pbm_load,
9599 x_clear_image,
9600 NULL
9601 };
9602
9603
9604 /* Return non-zero if OBJECT is a valid PBM image specification. */
9605
9606 static int
9607 pbm_image_p (object)
9608 Lisp_Object object;
9609 {
9610 struct image_keyword fmt[PBM_LAST];
9611
9612 bcopy (pbm_format, fmt, sizeof fmt);
9613
9614 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm)
9615 || (fmt[PBM_ASCENT].count
9616 && XFASTINT (fmt[PBM_ASCENT].value) > 100))
9617 return 0;
9618
9619 /* Must specify either :data or :file. */
9620 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
9621 }
9622
9623
9624 /* Scan a decimal number from *S and return it. Advance *S while
9625 reading the number. END is the end of the string. Value is -1 at
9626 end of input. */
9627
9628 static int
9629 pbm_scan_number (s, end)
9630 unsigned char **s, *end;
9631 {
9632 int c, val = -1;
9633
9634 while (*s < end)
9635 {
9636 /* Skip white-space. */
9637 while (*s < end && (c = *(*s)++, isspace (c)))
9638 ;
9639
9640 if (c == '#')
9641 {
9642 /* Skip comment to end of line. */
9643 while (*s < end && (c = *(*s)++, c != '\n'))
9644 ;
9645 }
9646 else if (isdigit (c))
9647 {
9648 /* Read decimal number. */
9649 val = c - '0';
9650 while (*s < end && (c = *(*s)++, isdigit (c)))
9651 val = 10 * val + c - '0';
9652 break;
9653 }
9654 else
9655 break;
9656 }
9657
9658 return val;
9659 }
9660
9661
9662 /* Read FILE into memory. Value is a pointer to a buffer allocated
9663 with xmalloc holding FILE's contents. Value is null if an error
9664 occured. *SIZE is set to the size of the file. */
9665
9666 static char *
9667 pbm_read_file (file, size)
9668 Lisp_Object file;
9669 int *size;
9670 {
9671 FILE *fp = NULL;
9672 char *buf = NULL;
9673 struct stat st;
9674
9675 if (stat (XSTRING (file)->data, &st) == 0
9676 && (fp = fopen (XSTRING (file)->data, "r")) != NULL
9677 && (buf = (char *) xmalloc (st.st_size),
9678 fread (buf, 1, st.st_size, fp) == st.st_size))
9679 {
9680 *size = st.st_size;
9681 fclose (fp);
9682 }
9683 else
9684 {
9685 if (fp)
9686 fclose (fp);
9687 if (buf)
9688 {
9689 xfree (buf);
9690 buf = NULL;
9691 }
9692 }
9693
9694 return buf;
9695 }
9696
9697
9698 /* Load PBM image IMG for use on frame F. */
9699
9700 static int
9701 pbm_load (f, img)
9702 struct frame *f;
9703 struct image *img;
9704 {
9705 int raw_p, x, y;
9706 int width, height, max_color_idx = 0;
9707 XImage *ximg;
9708 Lisp_Object file, specified_file;
9709 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
9710 struct gcpro gcpro1;
9711 unsigned char *contents = NULL;
9712 unsigned char *end, *p;
9713 int size;
9714
9715 specified_file = image_spec_value (img->spec, QCfile, NULL);
9716 file = Qnil;
9717 GCPRO1 (file);
9718
9719 if (STRINGP (specified_file))
9720 {
9721 file = x_find_image_file (specified_file);
9722 if (!STRINGP (file))
9723 {
9724 image_error ("Cannot find image file `%s'", specified_file, Qnil);
9725 UNGCPRO;
9726 return 0;
9727 }
9728
9729 contents = pbm_read_file (file, &size);
9730 if (contents == NULL)
9731 {
9732 image_error ("Error reading `%s'", file, Qnil);
9733 UNGCPRO;
9734 return 0;
9735 }
9736
9737 p = contents;
9738 end = contents + size;
9739 }
9740 else
9741 {
9742 Lisp_Object data;
9743 data = image_spec_value (img->spec, QCdata, NULL);
9744 p = XSTRING (data)->data;
9745 end = p + STRING_BYTES (XSTRING (data));
9746 }
9747
9748 /* Check magic number. */
9749 if (end - p < 2 || *p++ != 'P')
9750 {
9751 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
9752 error:
9753 xfree (contents);
9754 UNGCPRO;
9755 return 0;
9756 }
9757
9758 switch (*p++)
9759 {
9760 case '1':
9761 raw_p = 0, type = PBM_MONO;
9762 break;
9763
9764 case '2':
9765 raw_p = 0, type = PBM_GRAY;
9766 break;
9767
9768 case '3':
9769 raw_p = 0, type = PBM_COLOR;
9770 break;
9771
9772 case '4':
9773 raw_p = 1, type = PBM_MONO;
9774 break;
9775
9776 case '5':
9777 raw_p = 1, type = PBM_GRAY;
9778 break;
9779
9780 case '6':
9781 raw_p = 1, type = PBM_COLOR;
9782 break;
9783
9784 default:
9785 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
9786 goto error;
9787 }
9788
9789 /* Read width, height, maximum color-component. Characters
9790 starting with `#' up to the end of a line are ignored. */
9791 width = pbm_scan_number (&p, end);
9792 height = pbm_scan_number (&p, end);
9793
9794 if (type != PBM_MONO)
9795 {
9796 max_color_idx = pbm_scan_number (&p, end);
9797 if (raw_p && max_color_idx > 255)
9798 max_color_idx = 255;
9799 }
9800
9801 if (width < 0
9802 || height < 0
9803 || (type != PBM_MONO && max_color_idx < 0))
9804 goto error;
9805
9806 BLOCK_INPUT;
9807 if (!x_create_x_image_and_pixmap (f, width, height, 0,
9808 &ximg, &img->pixmap))
9809 {
9810 UNBLOCK_INPUT;
9811 goto error;
9812 }
9813
9814 /* Initialize the color hash table. */
9815 init_color_table ();
9816
9817 if (type == PBM_MONO)
9818 {
9819 int c = 0, g;
9820
9821 for (y = 0; y < height; ++y)
9822 for (x = 0; x < width; ++x)
9823 {
9824 if (raw_p)
9825 {
9826 if ((x & 7) == 0)
9827 c = *p++;
9828 g = c & 0x80;
9829 c <<= 1;
9830 }
9831 else
9832 g = pbm_scan_number (&p, end);
9833
9834 XPutPixel (ximg, x, y, (g
9835 ? FRAME_FOREGROUND_PIXEL (f)
9836 : FRAME_BACKGROUND_PIXEL (f)));
9837 }
9838 }
9839 else
9840 {
9841 for (y = 0; y < height; ++y)
9842 for (x = 0; x < width; ++x)
9843 {
9844 int r, g, b;
9845
9846 if (type == PBM_GRAY)
9847 r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
9848 else if (raw_p)
9849 {
9850 r = *p++;
9851 g = *p++;
9852 b = *p++;
9853 }
9854 else
9855 {
9856 r = pbm_scan_number (&p, end);
9857 g = pbm_scan_number (&p, end);
9858 b = pbm_scan_number (&p, end);
9859 }
9860
9861 if (r < 0 || g < 0 || b < 0)
9862 {
9863 xfree (ximg->data);
9864 ximg->data = NULL;
9865 XDestroyImage (ximg);
9866 UNBLOCK_INPUT;
9867 image_error ("Invalid pixel value in image `%s'",
9868 img->spec, Qnil);
9869 goto error;
9870 }
9871
9872 /* RGB values are now in the range 0..max_color_idx.
9873 Scale this to the range 0..0xffff supported by X. */
9874 r = (double) r * 65535 / max_color_idx;
9875 g = (double) g * 65535 / max_color_idx;
9876 b = (double) b * 65535 / max_color_idx;
9877 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
9878 }
9879 }
9880
9881 /* Store in IMG->colors the colors allocated for the image, and
9882 free the color table. */
9883 img->colors = colors_in_color_table (&img->ncolors);
9884 free_color_table ();
9885
9886 /* Put the image into a pixmap. */
9887 x_put_x_image (f, ximg, img->pixmap, width, height);
9888 x_destroy_x_image (ximg);
9889 UNBLOCK_INPUT;
9890
9891 img->width = width;
9892 img->height = height;
9893
9894 UNGCPRO;
9895 xfree (contents);
9896 return 1;
9897 }
9898 #endif /* HAVE_PBM */
9899
9900 \f
9901 /***********************************************************************
9902 PNG
9903 ***********************************************************************/
9904
9905 #if HAVE_PNG
9906
9907 #include <png.h>
9908
9909 /* Function prototypes. */
9910
9911 static int png_image_p P_ ((Lisp_Object object));
9912 static int png_load P_ ((struct frame *f, struct image *img));
9913
9914 /* The symbol `png' identifying images of this type. */
9915
9916 Lisp_Object Qpng;
9917
9918 /* Indices of image specification fields in png_format, below. */
9919
9920 enum png_keyword_index
9921 {
9922 PNG_TYPE,
9923 PNG_DATA,
9924 PNG_FILE,
9925 PNG_ASCENT,
9926 PNG_MARGIN,
9927 PNG_RELIEF,
9928 PNG_ALGORITHM,
9929 PNG_HEURISTIC_MASK,
9930 PNG_LAST
9931 };
9932
9933 /* Vector of image_keyword structures describing the format
9934 of valid user-defined image specifications. */
9935
9936 static struct image_keyword png_format[PNG_LAST] =
9937 {
9938 {":type", IMAGE_SYMBOL_VALUE, 1},
9939 {":data", IMAGE_STRING_VALUE, 0},
9940 {":file", IMAGE_STRING_VALUE, 0},
9941 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
9942 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9943 {":relief", IMAGE_INTEGER_VALUE, 0},
9944 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9945 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
9946 };
9947
9948 /* Structure describing the image type `png'. */
9949
9950 static struct image_type png_type =
9951 {
9952 &Qpng,
9953 png_image_p,
9954 png_load,
9955 x_clear_image,
9956 NULL
9957 };
9958
9959
9960 /* Return non-zero if OBJECT is a valid PNG image specification. */
9961
9962 static int
9963 png_image_p (object)
9964 Lisp_Object object;
9965 {
9966 struct image_keyword fmt[PNG_LAST];
9967 bcopy (png_format, fmt, sizeof fmt);
9968
9969 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng)
9970 || (fmt[PNG_ASCENT].count
9971 && XFASTINT (fmt[PNG_ASCENT].value) > 100))
9972 return 0;
9973
9974 /* Must specify either the :data or :file keyword. */
9975 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
9976 }
9977
9978
9979 /* Error and warning handlers installed when the PNG library
9980 is initialized. */
9981
9982 static void
9983 my_png_error (png_ptr, msg)
9984 png_struct *png_ptr;
9985 char *msg;
9986 {
9987 xassert (png_ptr != NULL);
9988 image_error ("PNG error: %s", build_string (msg), Qnil);
9989 longjmp (png_ptr->jmpbuf, 1);
9990 }
9991
9992
9993 static void
9994 my_png_warning (png_ptr, msg)
9995 png_struct *png_ptr;
9996 char *msg;
9997 {
9998 xassert (png_ptr != NULL);
9999 image_error ("PNG warning: %s", build_string (msg), Qnil);
10000 }
10001
10002 /* Memory source for PNG decoding. */
10003
10004 struct png_memory_storage
10005 {
10006 unsigned char *bytes; /* The data */
10007 size_t len; /* How big is it? */
10008 int index; /* Where are we? */
10009 };
10010
10011
10012 /* Function set as reader function when reading PNG image from memory.
10013 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
10014 bytes from the input to DATA. */
10015
10016 static void
10017 png_read_from_memory (png_ptr, data, length)
10018 png_structp png_ptr;
10019 png_bytep data;
10020 png_size_t length;
10021 {
10022 struct png_memory_storage *tbr
10023 = (struct png_memory_storage *) png_get_io_ptr (png_ptr);
10024
10025 if (length > tbr->len - tbr->index)
10026 png_error (png_ptr, "Read error");
10027
10028 bcopy (tbr->bytes + tbr->index, data, length);
10029 tbr->index = tbr->index + length;
10030 }
10031
10032 /* Load PNG image IMG for use on frame F. Value is non-zero if
10033 successful. */
10034
10035 static int
10036 png_load (f, img)
10037 struct frame *f;
10038 struct image *img;
10039 {
10040 Lisp_Object file, specified_file;
10041 Lisp_Object specified_data;
10042 int x, y, i;
10043 XImage *ximg, *mask_img = NULL;
10044 struct gcpro gcpro1;
10045 png_struct *png_ptr = NULL;
10046 png_info *info_ptr = NULL, *end_info = NULL;
10047 FILE *fp = NULL;
10048 png_byte sig[8];
10049 png_byte *pixels = NULL;
10050 png_byte **rows = NULL;
10051 png_uint_32 width, height;
10052 int bit_depth, color_type, interlace_type;
10053 png_byte channels;
10054 png_uint_32 row_bytes;
10055 int transparent_p;
10056 char *gamma_str;
10057 double screen_gamma, image_gamma;
10058 int intent;
10059 struct png_memory_storage tbr; /* Data to be read */
10060
10061 /* Find out what file to load. */
10062 specified_file = image_spec_value (img->spec, QCfile, NULL);
10063 specified_data = image_spec_value (img->spec, QCdata, NULL);
10064 file = Qnil;
10065 GCPRO1 (file);
10066
10067 if (NILP (specified_data))
10068 {
10069 file = x_find_image_file (specified_file);
10070 if (!STRINGP (file))
10071 {
10072 image_error ("Cannot find image file `%s'", specified_file, Qnil);
10073 UNGCPRO;
10074 return 0;
10075 }
10076
10077 /* Open the image file. */
10078 fp = fopen (XSTRING (file)->data, "rb");
10079 if (!fp)
10080 {
10081 image_error ("Cannot open image file `%s'", file, Qnil);
10082 UNGCPRO;
10083 fclose (fp);
10084 return 0;
10085 }
10086
10087 /* Check PNG signature. */
10088 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
10089 || !png_check_sig (sig, sizeof sig))
10090 {
10091 image_error ("Not a PNG file:` %s'", file, Qnil);
10092 UNGCPRO;
10093 fclose (fp);
10094 return 0;
10095 }
10096 }
10097 else
10098 {
10099 /* Read from memory. */
10100 tbr.bytes = XSTRING (specified_data)->data;
10101 tbr.len = STRING_BYTES (XSTRING (specified_data));
10102 tbr.index = 0;
10103
10104 /* Check PNG signature. */
10105 if (tbr.len < sizeof sig
10106 || !png_check_sig (tbr.bytes, sizeof sig))
10107 {
10108 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
10109 UNGCPRO;
10110 return 0;
10111 }
10112
10113 /* Need to skip past the signature. */
10114 tbr.bytes += sizeof (sig);
10115 }
10116
10117 /* Initialize read and info structs for PNG lib. */
10118 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
10119 my_png_error, my_png_warning);
10120 if (!png_ptr)
10121 {
10122 if (fp) fclose (fp);
10123 UNGCPRO;
10124 return 0;
10125 }
10126
10127 info_ptr = png_create_info_struct (png_ptr);
10128 if (!info_ptr)
10129 {
10130 png_destroy_read_struct (&png_ptr, NULL, NULL);
10131 if (fp) fclose (fp);
10132 UNGCPRO;
10133 return 0;
10134 }
10135
10136 end_info = png_create_info_struct (png_ptr);
10137 if (!end_info)
10138 {
10139 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
10140 if (fp) fclose (fp);
10141 UNGCPRO;
10142 return 0;
10143 }
10144
10145 /* Set error jump-back. We come back here when the PNG library
10146 detects an error. */
10147 if (setjmp (png_ptr->jmpbuf))
10148 {
10149 error:
10150 if (png_ptr)
10151 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
10152 xfree (pixels);
10153 xfree (rows);
10154 if (fp) fclose (fp);
10155 UNGCPRO;
10156 return 0;
10157 }
10158
10159 /* Read image info. */
10160 if (!NILP (specified_data))
10161 png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
10162 else
10163 png_init_io (png_ptr, fp);
10164
10165 png_set_sig_bytes (png_ptr, sizeof sig);
10166 png_read_info (png_ptr, info_ptr);
10167 png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
10168 &interlace_type, NULL, NULL);
10169
10170 /* If image contains simply transparency data, we prefer to
10171 construct a clipping mask. */
10172 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
10173 transparent_p = 1;
10174 else
10175 transparent_p = 0;
10176
10177 /* This function is easier to write if we only have to handle
10178 one data format: RGB or RGBA with 8 bits per channel. Let's
10179 transform other formats into that format. */
10180
10181 /* Strip more than 8 bits per channel. */
10182 if (bit_depth == 16)
10183 png_set_strip_16 (png_ptr);
10184
10185 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
10186 if available. */
10187 png_set_expand (png_ptr);
10188
10189 /* Convert grayscale images to RGB. */
10190 if (color_type == PNG_COLOR_TYPE_GRAY
10191 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
10192 png_set_gray_to_rgb (png_ptr);
10193
10194 /* The value 2.2 is a guess for PC monitors from PNG example.c. */
10195 gamma_str = getenv ("SCREEN_GAMMA");
10196 screen_gamma = gamma_str ? atof (gamma_str) : 2.2;
10197
10198 /* Tell the PNG lib to handle gamma correction for us. */
10199
10200 #if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
10201 if (png_get_sRGB (png_ptr, info_ptr, &intent))
10202 /* There is a special chunk in the image specifying the gamma. */
10203 png_set_sRGB (png_ptr, info_ptr, intent);
10204 else
10205 #endif
10206 if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
10207 /* Image contains gamma information. */
10208 png_set_gamma (png_ptr, screen_gamma, image_gamma);
10209 else
10210 /* Use a default of 0.5 for the image gamma. */
10211 png_set_gamma (png_ptr, screen_gamma, 0.5);
10212
10213 /* Handle alpha channel by combining the image with a background
10214 color. Do this only if a real alpha channel is supplied. For
10215 simple transparency, we prefer a clipping mask. */
10216 if (!transparent_p)
10217 {
10218 png_color_16 *image_background;
10219
10220 if (png_get_bKGD (png_ptr, info_ptr, &image_background))
10221 /* Image contains a background color with which to
10222 combine the image. */
10223 png_set_background (png_ptr, image_background,
10224 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
10225 else
10226 {
10227 /* Image does not contain a background color with which
10228 to combine the image data via an alpha channel. Use
10229 the frame's background instead. */
10230 XColor color;
10231 Colormap cmap;
10232 png_color_16 frame_background;
10233
10234 BLOCK_INPUT;
10235 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
10236 color.pixel = FRAME_BACKGROUND_PIXEL (f);
10237 XQueryColor (FRAME_W32_DISPLAY (f), cmap, &color);
10238 UNBLOCK_INPUT;
10239
10240 bzero (&frame_background, sizeof frame_background);
10241 frame_background.red = color.red;
10242 frame_background.green = color.green;
10243 frame_background.blue = color.blue;
10244
10245 png_set_background (png_ptr, &frame_background,
10246 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
10247 }
10248 }
10249
10250 /* Update info structure. */
10251 png_read_update_info (png_ptr, info_ptr);
10252
10253 /* Get number of channels. Valid values are 1 for grayscale images
10254 and images with a palette, 2 for grayscale images with transparency
10255 information (alpha channel), 3 for RGB images, and 4 for RGB
10256 images with alpha channel, i.e. RGBA. If conversions above were
10257 sufficient we should only have 3 or 4 channels here. */
10258 channels = png_get_channels (png_ptr, info_ptr);
10259 xassert (channels == 3 || channels == 4);
10260
10261 /* Number of bytes needed for one row of the image. */
10262 row_bytes = png_get_rowbytes (png_ptr, info_ptr);
10263
10264 /* Allocate memory for the image. */
10265 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
10266 rows = (png_byte **) xmalloc (height * sizeof *rows);
10267 for (i = 0; i < height; ++i)
10268 rows[i] = pixels + i * row_bytes;
10269
10270 /* Read the entire image. */
10271 png_read_image (png_ptr, rows);
10272 png_read_end (png_ptr, info_ptr);
10273 if (fp)
10274 {
10275 fclose (fp);
10276 fp = NULL;
10277 }
10278
10279 BLOCK_INPUT;
10280
10281 /* Create the X image and pixmap. */
10282 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
10283 &img->pixmap))
10284 {
10285 UNBLOCK_INPUT;
10286 goto error;
10287 }
10288
10289 /* Create an image and pixmap serving as mask if the PNG image
10290 contains an alpha channel. */
10291 if (channels == 4
10292 && !transparent_p
10293 && !x_create_x_image_and_pixmap (f, width, height, 1,
10294 &mask_img, &img->mask))
10295 {
10296 x_destroy_x_image (ximg);
10297 XFreePixmap (FRAME_W32_DISPLAY (f), img->pixmap);
10298 img->pixmap = 0;
10299 UNBLOCK_INPUT;
10300 goto error;
10301 }
10302
10303 /* Fill the X image and mask from PNG data. */
10304 init_color_table ();
10305
10306 for (y = 0; y < height; ++y)
10307 {
10308 png_byte *p = rows[y];
10309
10310 for (x = 0; x < width; ++x)
10311 {
10312 unsigned r, g, b;
10313
10314 r = *p++ << 8;
10315 g = *p++ << 8;
10316 b = *p++ << 8;
10317 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
10318
10319 /* An alpha channel, aka mask channel, associates variable
10320 transparency with an image. Where other image formats
10321 support binary transparency---fully transparent or fully
10322 opaque---PNG allows up to 254 levels of partial transparency.
10323 The PNG library implements partial transparency by combining
10324 the image with a specified background color.
10325
10326 I'm not sure how to handle this here nicely: because the
10327 background on which the image is displayed may change, for
10328 real alpha channel support, it would be necessary to create
10329 a new image for each possible background.
10330
10331 What I'm doing now is that a mask is created if we have
10332 boolean transparency information. Otherwise I'm using
10333 the frame's background color to combine the image with. */
10334
10335 if (channels == 4)
10336 {
10337 if (mask_img)
10338 XPutPixel (mask_img, x, y, *p > 0);
10339 ++p;
10340 }
10341 }
10342 }
10343
10344 /* Remember colors allocated for this image. */
10345 img->colors = colors_in_color_table (&img->ncolors);
10346 free_color_table ();
10347
10348 /* Clean up. */
10349 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
10350 xfree (rows);
10351 xfree (pixels);
10352
10353 img->width = width;
10354 img->height = height;
10355
10356 /* Put the image into the pixmap, then free the X image and its buffer. */
10357 x_put_x_image (f, ximg, img->pixmap, width, height);
10358 x_destroy_x_image (ximg);
10359
10360 /* Same for the mask. */
10361 if (mask_img)
10362 {
10363 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
10364 x_destroy_x_image (mask_img);
10365 }
10366
10367 UNBLOCK_INPUT;
10368 UNGCPRO;
10369 return 1;
10370 }
10371
10372 #endif /* HAVE_PNG != 0 */
10373
10374
10375 \f
10376 /***********************************************************************
10377 JPEG
10378 ***********************************************************************/
10379
10380 #if HAVE_JPEG
10381
10382 /* Work around a warning about HAVE_STDLIB_H being redefined in
10383 jconfig.h. */
10384 #ifdef HAVE_STDLIB_H
10385 #define HAVE_STDLIB_H_1
10386 #undef HAVE_STDLIB_H
10387 #endif /* HAVE_STLIB_H */
10388
10389 #include <jpeglib.h>
10390 #include <jerror.h>
10391 #include <setjmp.h>
10392
10393 #ifdef HAVE_STLIB_H_1
10394 #define HAVE_STDLIB_H 1
10395 #endif
10396
10397 static int jpeg_image_p P_ ((Lisp_Object object));
10398 static int jpeg_load P_ ((struct frame *f, struct image *img));
10399
10400 /* The symbol `jpeg' identifying images of this type. */
10401
10402 Lisp_Object Qjpeg;
10403
10404 /* Indices of image specification fields in gs_format, below. */
10405
10406 enum jpeg_keyword_index
10407 {
10408 JPEG_TYPE,
10409 JPEG_DATA,
10410 JPEG_FILE,
10411 JPEG_ASCENT,
10412 JPEG_MARGIN,
10413 JPEG_RELIEF,
10414 JPEG_ALGORITHM,
10415 JPEG_HEURISTIC_MASK,
10416 JPEG_LAST
10417 };
10418
10419 /* Vector of image_keyword structures describing the format
10420 of valid user-defined image specifications. */
10421
10422 static struct image_keyword jpeg_format[JPEG_LAST] =
10423 {
10424 {":type", IMAGE_SYMBOL_VALUE, 1},
10425 {":data", IMAGE_STRING_VALUE, 0},
10426 {":file", IMAGE_STRING_VALUE, 0},
10427 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
10428 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
10429 {":relief", IMAGE_INTEGER_VALUE, 0},
10430 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10431 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
10432 };
10433
10434 /* Structure describing the image type `jpeg'. */
10435
10436 static struct image_type jpeg_type =
10437 {
10438 &Qjpeg,
10439 jpeg_image_p,
10440 jpeg_load,
10441 x_clear_image,
10442 NULL
10443 };
10444
10445
10446 /* Return non-zero if OBJECT is a valid JPEG image specification. */
10447
10448 static int
10449 jpeg_image_p (object)
10450 Lisp_Object object;
10451 {
10452 struct image_keyword fmt[JPEG_LAST];
10453
10454 bcopy (jpeg_format, fmt, sizeof fmt);
10455
10456 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg)
10457 || (fmt[JPEG_ASCENT].count
10458 && XFASTINT (fmt[JPEG_ASCENT].value) > 100))
10459 return 0;
10460
10461 /* Must specify either the :data or :file keyword. */
10462 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
10463 }
10464
10465
10466 struct my_jpeg_error_mgr
10467 {
10468 struct jpeg_error_mgr pub;
10469 jmp_buf setjmp_buffer;
10470 };
10471
10472 static void
10473 my_error_exit (cinfo)
10474 j_common_ptr cinfo;
10475 {
10476 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
10477 longjmp (mgr->setjmp_buffer, 1);
10478 }
10479
10480 /* Init source method for JPEG data source manager. Called by
10481 jpeg_read_header() before any data is actually read. See
10482 libjpeg.doc from the JPEG lib distribution. */
10483
10484 static void
10485 our_init_source (cinfo)
10486 j_decompress_ptr cinfo;
10487 {
10488 }
10489
10490
10491 /* Fill input buffer method for JPEG data source manager. Called
10492 whenever more data is needed. We read the whole image in one step,
10493 so this only adds a fake end of input marker at the end. */
10494
10495 static boolean
10496 our_fill_input_buffer (cinfo)
10497 j_decompress_ptr cinfo;
10498 {
10499 /* Insert a fake EOI marker. */
10500 struct jpeg_source_mgr *src = cinfo->src;
10501 static JOCTET buffer[2];
10502
10503 buffer[0] = (JOCTET) 0xFF;
10504 buffer[1] = (JOCTET) JPEG_EOI;
10505
10506 src->next_input_byte = buffer;
10507 src->bytes_in_buffer = 2;
10508 return TRUE;
10509 }
10510
10511
10512 /* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
10513 is the JPEG data source manager. */
10514
10515 static void
10516 our_skip_input_data (cinfo, num_bytes)
10517 j_decompress_ptr cinfo;
10518 long num_bytes;
10519 {
10520 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
10521
10522 if (src)
10523 {
10524 if (num_bytes > src->bytes_in_buffer)
10525 ERREXIT (cinfo, JERR_INPUT_EOF);
10526
10527 src->bytes_in_buffer -= num_bytes;
10528 src->next_input_byte += num_bytes;
10529 }
10530 }
10531
10532
10533 /* Method to terminate data source. Called by
10534 jpeg_finish_decompress() after all data has been processed. */
10535
10536 static void
10537 our_term_source (cinfo)
10538 j_decompress_ptr cinfo;
10539 {
10540 }
10541
10542
10543 /* Set up the JPEG lib for reading an image from DATA which contains
10544 LEN bytes. CINFO is the decompression info structure created for
10545 reading the image. */
10546
10547 static void
10548 jpeg_memory_src (cinfo, data, len)
10549 j_decompress_ptr cinfo;
10550 JOCTET *data;
10551 unsigned int len;
10552 {
10553 struct jpeg_source_mgr *src;
10554
10555 if (cinfo->src == NULL)
10556 {
10557 /* First time for this JPEG object? */
10558 cinfo->src = (struct jpeg_source_mgr *)
10559 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
10560 sizeof (struct jpeg_source_mgr));
10561 src = (struct jpeg_source_mgr *) cinfo->src;
10562 src->next_input_byte = data;
10563 }
10564
10565 src = (struct jpeg_source_mgr *) cinfo->src;
10566 src->init_source = our_init_source;
10567 src->fill_input_buffer = our_fill_input_buffer;
10568 src->skip_input_data = our_skip_input_data;
10569 src->resync_to_restart = jpeg_resync_to_restart; /* Use default method. */
10570 src->term_source = our_term_source;
10571 src->bytes_in_buffer = len;
10572 src->next_input_byte = data;
10573 }
10574
10575
10576 /* Load image IMG for use on frame F. Patterned after example.c
10577 from the JPEG lib. */
10578
10579 static int
10580 jpeg_load (f, img)
10581 struct frame *f;
10582 struct image *img;
10583 {
10584 struct jpeg_decompress_struct cinfo;
10585 struct my_jpeg_error_mgr mgr;
10586 Lisp_Object file, specified_file;
10587 Lisp_Object specified_data;
10588 FILE *fp = NULL;
10589 JSAMPARRAY buffer;
10590 int row_stride, x, y;
10591 XImage *ximg = NULL;
10592 int rc;
10593 unsigned long *colors;
10594 int width, height;
10595 struct gcpro gcpro1;
10596
10597 /* Open the JPEG file. */
10598 specified_file = image_spec_value (img->spec, QCfile, NULL);
10599 specified_data = image_spec_value (img->spec, QCdata, NULL);
10600 file = Qnil;
10601 GCPRO1 (file);
10602
10603 if (NILP (specified_data))
10604 {
10605 file = x_find_image_file (specified_file);
10606 if (!STRINGP (file))
10607 {
10608 image_error ("Cannot find image file `%s'", specified_file, Qnil);
10609 UNGCPRO;
10610 return 0;
10611 }
10612
10613 fp = fopen (XSTRING (file)->data, "r");
10614 if (fp == NULL)
10615 {
10616 image_error ("Cannot open `%s'", file, Qnil);
10617 UNGCPRO;
10618 return 0;
10619 }
10620 }
10621
10622 /* Customize libjpeg's error handling to call my_error_exit when an
10623 error is detected. This function will perform a longjmp. */
10624 mgr.pub.error_exit = my_error_exit;
10625 cinfo.err = jpeg_std_error (&mgr.pub);
10626
10627 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
10628 {
10629 if (rc == 1)
10630 {
10631 /* Called from my_error_exit. Display a JPEG error. */
10632 char buffer[JMSG_LENGTH_MAX];
10633 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
10634 image_error ("Error reading JPEG image `%s': %s", img->spec,
10635 build_string (buffer));
10636 }
10637
10638 /* Close the input file and destroy the JPEG object. */
10639 if (fp)
10640 fclose (fp);
10641 jpeg_destroy_decompress (&cinfo);
10642
10643 BLOCK_INPUT;
10644
10645 /* If we already have an XImage, free that. */
10646 x_destroy_x_image (ximg);
10647
10648 /* Free pixmap and colors. */
10649 x_clear_image (f, img);
10650
10651 UNBLOCK_INPUT;
10652 UNGCPRO;
10653 return 0;
10654 }
10655
10656 /* Create the JPEG decompression object. Let it read from fp.
10657 Read the JPEG image header. */
10658 jpeg_create_decompress (&cinfo);
10659
10660 if (NILP (specified_data))
10661 jpeg_stdio_src (&cinfo, fp);
10662 else
10663 jpeg_memory_src (&cinfo, XSTRING (specified_data)->data,
10664 STRING_BYTES (XSTRING (specified_data)));
10665
10666 jpeg_read_header (&cinfo, TRUE);
10667
10668 /* Customize decompression so that color quantization will be used.
10669 Start decompression. */
10670 cinfo.quantize_colors = TRUE;
10671 jpeg_start_decompress (&cinfo);
10672 width = img->width = cinfo.output_width;
10673 height = img->height = cinfo.output_height;
10674
10675 BLOCK_INPUT;
10676
10677 /* Create X image and pixmap. */
10678 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
10679 &img->pixmap))
10680 {
10681 UNBLOCK_INPUT;
10682 longjmp (mgr.setjmp_buffer, 2);
10683 }
10684
10685 /* Allocate colors. When color quantization is used,
10686 cinfo.actual_number_of_colors has been set with the number of
10687 colors generated, and cinfo.colormap is a two-dimensional array
10688 of color indices in the range 0..cinfo.actual_number_of_colors.
10689 No more than 255 colors will be generated. */
10690 {
10691 int i, ir, ig, ib;
10692
10693 if (cinfo.out_color_components > 2)
10694 ir = 0, ig = 1, ib = 2;
10695 else if (cinfo.out_color_components > 1)
10696 ir = 0, ig = 1, ib = 0;
10697 else
10698 ir = 0, ig = 0, ib = 0;
10699
10700 /* Use the color table mechanism because it handles colors that
10701 cannot be allocated nicely. Such colors will be replaced with
10702 a default color, and we don't have to care about which colors
10703 can be freed safely, and which can't. */
10704 init_color_table ();
10705 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
10706 * sizeof *colors);
10707
10708 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
10709 {
10710 /* Multiply RGB values with 255 because X expects RGB values
10711 in the range 0..0xffff. */
10712 int r = cinfo.colormap[ir][i] << 8;
10713 int g = cinfo.colormap[ig][i] << 8;
10714 int b = cinfo.colormap[ib][i] << 8;
10715 colors[i] = lookup_rgb_color (f, r, g, b);
10716 }
10717
10718 /* Remember those colors actually allocated. */
10719 img->colors = colors_in_color_table (&img->ncolors);
10720 free_color_table ();
10721 }
10722
10723 /* Read pixels. */
10724 row_stride = width * cinfo.output_components;
10725 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
10726 row_stride, 1);
10727 for (y = 0; y < height; ++y)
10728 {
10729 jpeg_read_scanlines (&cinfo, buffer, 1);
10730 for (x = 0; x < cinfo.output_width; ++x)
10731 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
10732 }
10733
10734 /* Clean up. */
10735 jpeg_finish_decompress (&cinfo);
10736 jpeg_destroy_decompress (&cinfo);
10737 if (fp)
10738 fclose (fp);
10739
10740 /* Put the image into the pixmap. */
10741 x_put_x_image (f, ximg, img->pixmap, width, height);
10742 x_destroy_x_image (ximg);
10743 UNBLOCK_INPUT;
10744 UNGCPRO;
10745 return 1;
10746 }
10747
10748 #endif /* HAVE_JPEG */
10749
10750
10751 \f
10752 /***********************************************************************
10753 TIFF
10754 ***********************************************************************/
10755
10756 #if HAVE_TIFF
10757
10758 #include <tiffio.h>
10759
10760 static int tiff_image_p P_ ((Lisp_Object object));
10761 static int tiff_load P_ ((struct frame *f, struct image *img));
10762
10763 /* The symbol `tiff' identifying images of this type. */
10764
10765 Lisp_Object Qtiff;
10766
10767 /* Indices of image specification fields in tiff_format, below. */
10768
10769 enum tiff_keyword_index
10770 {
10771 TIFF_TYPE,
10772 TIFF_DATA,
10773 TIFF_FILE,
10774 TIFF_ASCENT,
10775 TIFF_MARGIN,
10776 TIFF_RELIEF,
10777 TIFF_ALGORITHM,
10778 TIFF_HEURISTIC_MASK,
10779 TIFF_LAST
10780 };
10781
10782 /* Vector of image_keyword structures describing the format
10783 of valid user-defined image specifications. */
10784
10785 static struct image_keyword tiff_format[TIFF_LAST] =
10786 {
10787 {":type", IMAGE_SYMBOL_VALUE, 1},
10788 {":data", IMAGE_STRING_VALUE, 0},
10789 {":file", IMAGE_STRING_VALUE, 0},
10790 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
10791 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
10792 {":relief", IMAGE_INTEGER_VALUE, 0},
10793 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10794 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
10795 };
10796
10797 /* Structure describing the image type `tiff'. */
10798
10799 static struct image_type tiff_type =
10800 {
10801 &Qtiff,
10802 tiff_image_p,
10803 tiff_load,
10804 x_clear_image,
10805 NULL
10806 };
10807
10808
10809 /* Return non-zero if OBJECT is a valid TIFF image specification. */
10810
10811 static int
10812 tiff_image_p (object)
10813 Lisp_Object object;
10814 {
10815 struct image_keyword fmt[TIFF_LAST];
10816 bcopy (tiff_format, fmt, sizeof fmt);
10817
10818 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff)
10819 || (fmt[TIFF_ASCENT].count
10820 && XFASTINT (fmt[TIFF_ASCENT].value) > 100))
10821 return 0;
10822
10823 /* Must specify either the :data or :file keyword. */
10824 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
10825 }
10826
10827
10828 /* Reading from a memory buffer for TIFF images Based on the PNG
10829 memory source, but we have to provide a lot of extra functions.
10830 Blah.
10831
10832 We really only need to implement read and seek, but I am not
10833 convinced that the TIFF library is smart enough not to destroy
10834 itself if we only hand it the function pointers we need to
10835 override. */
10836
10837 typedef struct
10838 {
10839 unsigned char *bytes;
10840 size_t len;
10841 int index;
10842 }
10843 tiff_memory_source;
10844
10845 static size_t
10846 tiff_read_from_memory (data, buf, size)
10847 thandle_t data;
10848 tdata_t buf;
10849 tsize_t size;
10850 {
10851 tiff_memory_source *src = (tiff_memory_source *) data;
10852
10853 if (size > src->len - src->index)
10854 return (size_t) -1;
10855 bcopy (src->bytes + src->index, buf, size);
10856 src->index += size;
10857 return size;
10858 }
10859
10860 static size_t
10861 tiff_write_from_memory (data, buf, size)
10862 thandle_t data;
10863 tdata_t buf;
10864 tsize_t size;
10865 {
10866 return (size_t) -1;
10867 }
10868
10869 static toff_t
10870 tiff_seek_in_memory (data, off, whence)
10871 thandle_t data;
10872 toff_t off;
10873 int whence;
10874 {
10875 tiff_memory_source *src = (tiff_memory_source *) data;
10876 int idx;
10877
10878 switch (whence)
10879 {
10880 case SEEK_SET: /* Go from beginning of source. */
10881 idx = off;
10882 break;
10883
10884 case SEEK_END: /* Go from end of source. */
10885 idx = src->len + off;
10886 break;
10887
10888 case SEEK_CUR: /* Go from current position. */
10889 idx = src->index + off;
10890 break;
10891
10892 default: /* Invalid `whence'. */
10893 return -1;
10894 }
10895
10896 if (idx > src->len || idx < 0)
10897 return -1;
10898
10899 src->index = idx;
10900 return src->index;
10901 }
10902
10903 static int
10904 tiff_close_memory (data)
10905 thandle_t data;
10906 {
10907 /* NOOP */
10908 return 0;
10909 }
10910
10911 static int
10912 tiff_mmap_memory (data, pbase, psize)
10913 thandle_t data;
10914 tdata_t *pbase;
10915 toff_t *psize;
10916 {
10917 /* It is already _IN_ memory. */
10918 return 0;
10919 }
10920
10921 static void
10922 tiff_unmap_memory (data, base, size)
10923 thandle_t data;
10924 tdata_t base;
10925 toff_t size;
10926 {
10927 /* We don't need to do this. */
10928 }
10929
10930 static toff_t
10931 tiff_size_of_memory (data)
10932 thandle_t data;
10933 {
10934 return ((tiff_memory_source *) data)->len;
10935 }
10936
10937 /* Load TIFF image IMG for use on frame F. Value is non-zero if
10938 successful. */
10939
10940 static int
10941 tiff_load (f, img)
10942 struct frame *f;
10943 struct image *img;
10944 {
10945 Lisp_Object file, specified_file;
10946 Lisp_Object specified_data;
10947 TIFF *tiff;
10948 int width, height, x, y;
10949 uint32 *buf;
10950 int rc;
10951 XImage *ximg;
10952 struct gcpro gcpro1;
10953 tiff_memory_source memsrc;
10954
10955 specified_file = image_spec_value (img->spec, QCfile, NULL);
10956 specified_data = image_spec_value (img->spec, QCdata, NULL);
10957 file = Qnil;
10958 GCPRO1 (file);
10959
10960 if (NILP (specified_data))
10961 {
10962 /* Read from a file */
10963 file = x_find_image_file (specified_file);
10964 if (!STRINGP (file))
10965 {
10966 image_error ("Cannot find image file `%s'", file, Qnil);
10967 UNGCPRO;
10968 return 0;
10969 }
10970
10971 /* Try to open the image file. */
10972 tiff = TIFFOpen (XSTRING (file)->data, "r");
10973 if (tiff == NULL)
10974 {
10975 image_error ("Cannot open `%s'", file, Qnil);
10976 UNGCPRO;
10977 return 0;
10978 }
10979 }
10980 else
10981 {
10982 /* Memory source! */
10983 memsrc.bytes = XSTRING (specified_data)->data;
10984 memsrc.len = STRING_BYTES (XSTRING (specified_data));
10985 memsrc.index = 0;
10986
10987 tiff = TIFFClientOpen ("memory_source", "r", &memsrc,
10988 (TIFFReadWriteProc) tiff_read_from_memory,
10989 (TIFFReadWriteProc) tiff_write_from_memory,
10990 tiff_seek_in_memory,
10991 tiff_close_memory,
10992 tiff_size_of_memory,
10993 tiff_mmap_memory,
10994 tiff_unmap_memory);
10995
10996 if (!tiff)
10997 {
10998 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
10999 UNGCPRO;
11000 return 0;
11001 }
11002 }
11003
11004 /* Get width and height of the image, and allocate a raster buffer
11005 of width x height 32-bit values. */
11006 TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
11007 TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
11008 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
11009
11010 rc = TIFFReadRGBAImage (tiff, width, height, buf, 0);
11011 TIFFClose (tiff);
11012 if (!rc)
11013 {
11014 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
11015 xfree (buf);
11016 UNGCPRO;
11017 return 0;
11018 }
11019
11020 BLOCK_INPUT;
11021
11022 /* Create the X image and pixmap. */
11023 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
11024 {
11025 UNBLOCK_INPUT;
11026 xfree (buf);
11027 UNGCPRO;
11028 return 0;
11029 }
11030
11031 /* Initialize the color table. */
11032 init_color_table ();
11033
11034 /* Process the pixel raster. Origin is in the lower-left corner. */
11035 for (y = 0; y < height; ++y)
11036 {
11037 uint32 *row = buf + y * width;
11038
11039 for (x = 0; x < width; ++x)
11040 {
11041 uint32 abgr = row[x];
11042 int r = TIFFGetR (abgr) << 8;
11043 int g = TIFFGetG (abgr) << 8;
11044 int b = TIFFGetB (abgr) << 8;
11045 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
11046 }
11047 }
11048
11049 /* Remember the colors allocated for the image. Free the color table. */
11050 img->colors = colors_in_color_table (&img->ncolors);
11051 free_color_table ();
11052
11053 /* Put the image into the pixmap, then free the X image and its buffer. */
11054 x_put_x_image (f, ximg, img->pixmap, width, height);
11055 x_destroy_x_image (ximg);
11056 xfree (buf);
11057 UNBLOCK_INPUT;
11058
11059 img->width = width;
11060 img->height = height;
11061
11062 UNGCPRO;
11063 return 1;
11064 }
11065
11066 #endif /* HAVE_TIFF != 0 */
11067
11068
11069 \f
11070 /***********************************************************************
11071 GIF
11072 ***********************************************************************/
11073
11074 #if HAVE_GIF
11075
11076 #include <gif_lib.h>
11077
11078 static int gif_image_p P_ ((Lisp_Object object));
11079 static int gif_load P_ ((struct frame *f, struct image *img));
11080
11081 /* The symbol `gif' identifying images of this type. */
11082
11083 Lisp_Object Qgif;
11084
11085 /* Indices of image specification fields in gif_format, below. */
11086
11087 enum gif_keyword_index
11088 {
11089 GIF_TYPE,
11090 GIF_DATA,
11091 GIF_FILE,
11092 GIF_ASCENT,
11093 GIF_MARGIN,
11094 GIF_RELIEF,
11095 GIF_ALGORITHM,
11096 GIF_HEURISTIC_MASK,
11097 GIF_IMAGE,
11098 GIF_LAST
11099 };
11100
11101 /* Vector of image_keyword structures describing the format
11102 of valid user-defined image specifications. */
11103
11104 static struct image_keyword gif_format[GIF_LAST] =
11105 {
11106 {":type", IMAGE_SYMBOL_VALUE, 1},
11107 {":data", IMAGE_STRING_VALUE, 0},
11108 {":file", IMAGE_STRING_VALUE, 0},
11109 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
11110 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
11111 {":relief", IMAGE_INTEGER_VALUE, 0},
11112 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11113 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11114 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}
11115 };
11116
11117 /* Structure describing the image type `gif'. */
11118
11119 static struct image_type gif_type =
11120 {
11121 &Qgif,
11122 gif_image_p,
11123 gif_load,
11124 x_clear_image,
11125 NULL
11126 };
11127
11128 /* Return non-zero if OBJECT is a valid GIF image specification. */
11129
11130 static int
11131 gif_image_p (object)
11132 Lisp_Object object;
11133 {
11134 struct image_keyword fmt[GIF_LAST];
11135 bcopy (gif_format, fmt, sizeof fmt);
11136
11137 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif)
11138 || (fmt[GIF_ASCENT].count
11139 && XFASTINT (fmt[GIF_ASCENT].value) > 100))
11140 return 0;
11141
11142 /* Must specify either the :data or :file keyword. */
11143 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
11144 }
11145
11146 /* Reading a GIF image from memory
11147 Based on the PNG memory stuff to a certain extent. */
11148
11149 typedef struct
11150 {
11151 unsigned char *bytes;
11152 size_t len;
11153 int index;
11154 }
11155 gif_memory_source;
11156
11157 /* Make the current memory source available to gif_read_from_memory.
11158 It's done this way because not all versions of libungif support
11159 a UserData field in the GifFileType structure. */
11160 static gif_memory_source *current_gif_memory_src;
11161
11162 static int
11163 gif_read_from_memory (file, buf, len)
11164 GifFileType *file;
11165 GifByteType *buf;
11166 int len;
11167 {
11168 gif_memory_source *src = current_gif_memory_src;
11169
11170 if (len > src->len - src->index)
11171 return -1;
11172
11173 bcopy (src->bytes + src->index, buf, len);
11174 src->index += len;
11175 return len;
11176 }
11177
11178
11179 /* Load GIF image IMG for use on frame F. Value is non-zero if
11180 successful. */
11181
11182 static int
11183 gif_load (f, img)
11184 struct frame *f;
11185 struct image *img;
11186 {
11187 Lisp_Object file, specified_file;
11188 Lisp_Object specified_data;
11189 int rc, width, height, x, y, i;
11190 XImage *ximg;
11191 ColorMapObject *gif_color_map;
11192 unsigned long pixel_colors[256];
11193 GifFileType *gif;
11194 struct gcpro gcpro1;
11195 Lisp_Object image;
11196 int ino, image_left, image_top, image_width, image_height;
11197 gif_memory_source memsrc;
11198 unsigned char *raster;
11199
11200 specified_file = image_spec_value (img->spec, QCfile, NULL);
11201 specified_data = image_spec_value (img->spec, QCdata, NULL);
11202 file = Qnil;
11203 GCPRO1 (file);
11204
11205 if (NILP (specified_data))
11206 {
11207 file = x_find_image_file (specified_file);
11208 if (!STRINGP (file))
11209 {
11210 image_error ("Cannot find image file `%s'", specified_file, Qnil);
11211 UNGCPRO;
11212 return 0;
11213 }
11214
11215 /* Open the GIF file. */
11216 gif = DGifOpenFileName (XSTRING (file)->data);
11217 if (gif == NULL)
11218 {
11219 image_error ("Cannot open `%s'", file, Qnil);
11220 UNGCPRO;
11221 return 0;
11222 }
11223 }
11224 else
11225 {
11226 /* Read from memory! */
11227 current_gif_memory_src = &memsrc;
11228 memsrc.bytes = XSTRING (specified_data)->data;
11229 memsrc.len = STRING_BYTES (XSTRING (specified_data));
11230 memsrc.index = 0;
11231
11232 gif = DGifOpen(&memsrc, gif_read_from_memory);
11233 if (!gif)
11234 {
11235 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
11236 UNGCPRO;
11237 return 0;
11238 }
11239 }
11240
11241 /* Read entire contents. */
11242 rc = DGifSlurp (gif);
11243 if (rc == GIF_ERROR)
11244 {
11245 image_error ("Error reading `%s'", img->spec, Qnil);
11246 DGifCloseFile (gif);
11247 UNGCPRO;
11248 return 0;
11249 }
11250
11251 image = image_spec_value (img->spec, QCindex, NULL);
11252 ino = INTEGERP (image) ? XFASTINT (image) : 0;
11253 if (ino >= gif->ImageCount)
11254 {
11255 image_error ("Invalid image number `%s' in image `%s'",
11256 image, img->spec);
11257 DGifCloseFile (gif);
11258 UNGCPRO;
11259 return 0;
11260 }
11261
11262 width = img->width = gif->SWidth;
11263 height = img->height = gif->SHeight;
11264
11265 BLOCK_INPUT;
11266
11267 /* Create the X image and pixmap. */
11268 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
11269 {
11270 UNBLOCK_INPUT;
11271 DGifCloseFile (gif);
11272 UNGCPRO;
11273 return 0;
11274 }
11275
11276 /* Allocate colors. */
11277 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
11278 if (!gif_color_map)
11279 gif_color_map = gif->SColorMap;
11280 init_color_table ();
11281 bzero (pixel_colors, sizeof pixel_colors);
11282
11283 for (i = 0; i < gif_color_map->ColorCount; ++i)
11284 {
11285 int r = gif_color_map->Colors[i].Red << 8;
11286 int g = gif_color_map->Colors[i].Green << 8;
11287 int b = gif_color_map->Colors[i].Blue << 8;
11288 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
11289 }
11290
11291 img->colors = colors_in_color_table (&img->ncolors);
11292 free_color_table ();
11293
11294 /* Clear the part of the screen image that are not covered by
11295 the image from the GIF file. Full animated GIF support
11296 requires more than can be done here (see the gif89 spec,
11297 disposal methods). Let's simply assume that the part
11298 not covered by a sub-image is in the frame's background color. */
11299 image_top = gif->SavedImages[ino].ImageDesc.Top;
11300 image_left = gif->SavedImages[ino].ImageDesc.Left;
11301 image_width = gif->SavedImages[ino].ImageDesc.Width;
11302 image_height = gif->SavedImages[ino].ImageDesc.Height;
11303
11304 for (y = 0; y < image_top; ++y)
11305 for (x = 0; x < width; ++x)
11306 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
11307
11308 for (y = image_top + image_height; y < height; ++y)
11309 for (x = 0; x < width; ++x)
11310 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
11311
11312 for (y = image_top; y < image_top + image_height; ++y)
11313 {
11314 for (x = 0; x < image_left; ++x)
11315 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
11316 for (x = image_left + image_width; x < width; ++x)
11317 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
11318 }
11319
11320 /* Read the GIF image into the X image. We use a local variable
11321 `raster' here because RasterBits below is a char *, and invites
11322 problems with bytes >= 0x80. */
11323 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
11324
11325 if (gif->SavedImages[ino].ImageDesc.Interlace)
11326 {
11327 static int interlace_start[] = {0, 4, 2, 1};
11328 static int interlace_increment[] = {8, 8, 4, 2};
11329 int pass, inc;
11330 int row = interlace_start[0];
11331
11332 pass = 0;
11333
11334 for (y = 0; y < image_height; y++)
11335 {
11336 if (row >= image_height)
11337 {
11338 row = interlace_start[++pass];
11339 while (row >= image_height)
11340 row = interlace_start[++pass];
11341 }
11342
11343 for (x = 0; x < image_width; x++)
11344 {
11345 int i = raster[(y * image_width) + x];
11346 XPutPixel (ximg, x + image_left, row + image_top,
11347 pixel_colors[i]);
11348 }
11349
11350 row += interlace_increment[pass];
11351 }
11352 }
11353 else
11354 {
11355 for (y = 0; y < image_height; ++y)
11356 for (x = 0; x < image_width; ++x)
11357 {
11358 int i = raster[y* image_width + x];
11359 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
11360 }
11361 }
11362
11363 DGifCloseFile (gif);
11364
11365 /* Put the image into the pixmap, then free the X image and its buffer. */
11366 x_put_x_image (f, ximg, img->pixmap, width, height);
11367 x_destroy_x_image (ximg);
11368 UNBLOCK_INPUT;
11369
11370 UNGCPRO;
11371 return 1;
11372 }
11373
11374 #endif /* HAVE_GIF != 0 */
11375
11376
11377 \f
11378 /***********************************************************************
11379 Ghostscript
11380 ***********************************************************************/
11381
11382 #ifdef HAVE_GHOSTSCRIPT
11383 static int gs_image_p P_ ((Lisp_Object object));
11384 static int gs_load P_ ((struct frame *f, struct image *img));
11385 static void gs_clear_image P_ ((struct frame *f, struct image *img));
11386
11387 /* The symbol `postscript' identifying images of this type. */
11388
11389 Lisp_Object Qpostscript;
11390
11391 /* Keyword symbols. */
11392
11393 Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
11394
11395 /* Indices of image specification fields in gs_format, below. */
11396
11397 enum gs_keyword_index
11398 {
11399 GS_TYPE,
11400 GS_PT_WIDTH,
11401 GS_PT_HEIGHT,
11402 GS_FILE,
11403 GS_LOADER,
11404 GS_BOUNDING_BOX,
11405 GS_ASCENT,
11406 GS_MARGIN,
11407 GS_RELIEF,
11408 GS_ALGORITHM,
11409 GS_HEURISTIC_MASK,
11410 GS_LAST
11411 };
11412
11413 /* Vector of image_keyword structures describing the format
11414 of valid user-defined image specifications. */
11415
11416 static struct image_keyword gs_format[GS_LAST] =
11417 {
11418 {":type", IMAGE_SYMBOL_VALUE, 1},
11419 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
11420 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
11421 {":file", IMAGE_STRING_VALUE, 1},
11422 {":loader", IMAGE_FUNCTION_VALUE, 0},
11423 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
11424 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
11425 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
11426 {":relief", IMAGE_INTEGER_VALUE, 0},
11427 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11428 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
11429 };
11430
11431 /* Structure describing the image type `ghostscript'. */
11432
11433 static struct image_type gs_type =
11434 {
11435 &Qpostscript,
11436 gs_image_p,
11437 gs_load,
11438 gs_clear_image,
11439 NULL
11440 };
11441
11442
11443 /* Free X resources of Ghostscript image IMG which is used on frame F. */
11444
11445 static void
11446 gs_clear_image (f, img)
11447 struct frame *f;
11448 struct image *img;
11449 {
11450 /* IMG->data.ptr_val may contain a recorded colormap. */
11451 xfree (img->data.ptr_val);
11452 x_clear_image (f, img);
11453 }
11454
11455
11456 /* Return non-zero if OBJECT is a valid Ghostscript image
11457 specification. */
11458
11459 static int
11460 gs_image_p (object)
11461 Lisp_Object object;
11462 {
11463 struct image_keyword fmt[GS_LAST];
11464 Lisp_Object tem;
11465 int i;
11466
11467 bcopy (gs_format, fmt, sizeof fmt);
11468
11469 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript)
11470 || (fmt[GS_ASCENT].count
11471 && XFASTINT (fmt[GS_ASCENT].value) > 100))
11472 return 0;
11473
11474 /* Bounding box must be a list or vector containing 4 integers. */
11475 tem = fmt[GS_BOUNDING_BOX].value;
11476 if (CONSP (tem))
11477 {
11478 for (i = 0; i < 4; ++i, tem = XCDR (tem))
11479 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
11480 return 0;
11481 if (!NILP (tem))
11482 return 0;
11483 }
11484 else if (VECTORP (tem))
11485 {
11486 if (XVECTOR (tem)->size != 4)
11487 return 0;
11488 for (i = 0; i < 4; ++i)
11489 if (!INTEGERP (XVECTOR (tem)->contents[i]))
11490 return 0;
11491 }
11492 else
11493 return 0;
11494
11495 return 1;
11496 }
11497
11498
11499 /* Load Ghostscript image IMG for use on frame F. Value is non-zero
11500 if successful. */
11501
11502 static int
11503 gs_load (f, img)
11504 struct frame *f;
11505 struct image *img;
11506 {
11507 char buffer[100];
11508 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
11509 struct gcpro gcpro1, gcpro2;
11510 Lisp_Object frame;
11511 double in_width, in_height;
11512 Lisp_Object pixel_colors = Qnil;
11513
11514 /* Compute pixel size of pixmap needed from the given size in the
11515 image specification. Sizes in the specification are in pt. 1 pt
11516 = 1/72 in, xdpi and ydpi are stored in the frame's X display
11517 info. */
11518 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
11519 in_width = XFASTINT (pt_width) / 72.0;
11520 img->width = in_width * FRAME_W32_DISPLAY_INFO (f)->resx;
11521 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
11522 in_height = XFASTINT (pt_height) / 72.0;
11523 img->height = in_height * FRAME_W32_DISPLAY_INFO (f)->resy;
11524
11525 /* Create the pixmap. */
11526 BLOCK_INPUT;
11527 xassert (img->pixmap == 0);
11528 img->pixmap = XCreatePixmap (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
11529 img->width, img->height,
11530 DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
11531 UNBLOCK_INPUT;
11532
11533 if (!img->pixmap)
11534 {
11535 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
11536 return 0;
11537 }
11538
11539 /* Call the loader to fill the pixmap. It returns a process object
11540 if successful. We do not record_unwind_protect here because
11541 other places in redisplay like calling window scroll functions
11542 don't either. Let the Lisp loader use `unwind-protect' instead. */
11543 GCPRO2 (window_and_pixmap_id, pixel_colors);
11544
11545 sprintf (buffer, "%lu %lu",
11546 (unsigned long) FRAME_W32_WINDOW (f),
11547 (unsigned long) img->pixmap);
11548 window_and_pixmap_id = build_string (buffer);
11549
11550 sprintf (buffer, "%lu %lu",
11551 FRAME_FOREGROUND_PIXEL (f),
11552 FRAME_BACKGROUND_PIXEL (f));
11553 pixel_colors = build_string (buffer);
11554
11555 XSETFRAME (frame, f);
11556 loader = image_spec_value (img->spec, QCloader, NULL);
11557 if (NILP (loader))
11558 loader = intern ("gs-load-image");
11559
11560 img->data.lisp_val = call6 (loader, frame, img->spec,
11561 make_number (img->width),
11562 make_number (img->height),
11563 window_and_pixmap_id,
11564 pixel_colors);
11565 UNGCPRO;
11566 return PROCESSP (img->data.lisp_val);
11567 }
11568
11569
11570 /* Kill the Ghostscript process that was started to fill PIXMAP on
11571 frame F. Called from XTread_socket when receiving an event
11572 telling Emacs that Ghostscript has finished drawing. */
11573
11574 void
11575 x_kill_gs_process (pixmap, f)
11576 Pixmap pixmap;
11577 struct frame *f;
11578 {
11579 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
11580 int class, i;
11581 struct image *img;
11582
11583 /* Find the image containing PIXMAP. */
11584 for (i = 0; i < c->used; ++i)
11585 if (c->images[i]->pixmap == pixmap)
11586 break;
11587
11588 /* Kill the GS process. We should have found PIXMAP in the image
11589 cache and its image should contain a process object. */
11590 xassert (i < c->used);
11591 img = c->images[i];
11592 xassert (PROCESSP (img->data.lisp_val));
11593 Fkill_process (img->data.lisp_val, Qnil);
11594 img->data.lisp_val = Qnil;
11595
11596 /* On displays with a mutable colormap, figure out the colors
11597 allocated for the image by looking at the pixels of an XImage for
11598 img->pixmap. */
11599 class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
11600 if (class != StaticColor && class != StaticGray && class != TrueColor)
11601 {
11602 XImage *ximg;
11603
11604 BLOCK_INPUT;
11605
11606 /* Try to get an XImage for img->pixmep. */
11607 ximg = XGetImage (FRAME_W32_DISPLAY (f), img->pixmap,
11608 0, 0, img->width, img->height, ~0, ZPixmap);
11609 if (ximg)
11610 {
11611 int x, y;
11612
11613 /* Initialize the color table. */
11614 init_color_table ();
11615
11616 /* For each pixel of the image, look its color up in the
11617 color table. After having done so, the color table will
11618 contain an entry for each color used by the image. */
11619 for (y = 0; y < img->height; ++y)
11620 for (x = 0; x < img->width; ++x)
11621 {
11622 unsigned long pixel = XGetPixel (ximg, x, y);
11623 lookup_pixel_color (f, pixel);
11624 }
11625
11626 /* Record colors in the image. Free color table and XImage. */
11627 img->colors = colors_in_color_table (&img->ncolors);
11628 free_color_table ();
11629 XDestroyImage (ximg);
11630
11631 #if 0 /* This doesn't seem to be the case. If we free the colors
11632 here, we get a BadAccess later in x_clear_image when
11633 freeing the colors. */
11634 /* We have allocated colors once, but Ghostscript has also
11635 allocated colors on behalf of us. So, to get the
11636 reference counts right, free them once. */
11637 if (img->ncolors)
11638 {
11639 Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
11640 XFreeColors (FRAME_W32_DISPLAY (f), cmap,
11641 img->colors, img->ncolors, 0);
11642 }
11643 #endif
11644 }
11645 else
11646 image_error ("Cannot get X image of `%s'; colors will not be freed",
11647 img->spec, Qnil);
11648
11649 UNBLOCK_INPUT;
11650 }
11651 }
11652
11653 #endif /* HAVE_GHOSTSCRIPT */
11654
11655 \f
11656 /***********************************************************************
11657 Window properties
11658 ***********************************************************************/
11659
11660 DEFUN ("x-change-window-property", Fx_change_window_property,
11661 Sx_change_window_property, 2, 3, 0,
11662 "Change window property PROP to VALUE on the X window of FRAME.\n\
11663 PROP and VALUE must be strings. FRAME nil or omitted means use the\n\
11664 selected frame. Value is VALUE.")
11665 (prop, value, frame)
11666 Lisp_Object frame, prop, value;
11667 {
11668 #if 0 /* NTEMACS_TODO : port window properties to W32 */
11669 struct frame *f = check_x_frame (frame);
11670 Atom prop_atom;
11671
11672 CHECK_STRING (prop, 1);
11673 CHECK_STRING (value, 2);
11674
11675 BLOCK_INPUT;
11676 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
11677 XChangeProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
11678 prop_atom, XA_STRING, 8, PropModeReplace,
11679 XSTRING (value)->data, XSTRING (value)->size);
11680
11681 /* Make sure the property is set when we return. */
11682 XFlush (FRAME_W32_DISPLAY (f));
11683 UNBLOCK_INPUT;
11684
11685 #endif /* NTEMACS_TODO */
11686
11687 return value;
11688 }
11689
11690
11691 DEFUN ("x-delete-window-property", Fx_delete_window_property,
11692 Sx_delete_window_property, 1, 2, 0,
11693 "Remove window property PROP from X window of FRAME.\n\
11694 FRAME nil or omitted means use the selected frame. Value is PROP.")
11695 (prop, frame)
11696 Lisp_Object prop, frame;
11697 {
11698 #if 0 /* NTEMACS_TODO : port window properties to W32 */
11699
11700 struct frame *f = check_x_frame (frame);
11701 Atom prop_atom;
11702
11703 CHECK_STRING (prop, 1);
11704 BLOCK_INPUT;
11705 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
11706 XDeleteProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), prop_atom);
11707
11708 /* Make sure the property is removed when we return. */
11709 XFlush (FRAME_W32_DISPLAY (f));
11710 UNBLOCK_INPUT;
11711 #endif /* NTEMACS_TODO */
11712
11713 return prop;
11714 }
11715
11716
11717 DEFUN ("x-window-property", Fx_window_property, Sx_window_property,
11718 1, 2, 0,
11719 "Value is the value of window property PROP on FRAME.\n\
11720 If FRAME is nil or omitted, use the selected frame. Value is nil\n\
11721 if FRAME hasn't a property with name PROP or if PROP has no string\n\
11722 value.")
11723 (prop, frame)
11724 Lisp_Object prop, frame;
11725 {
11726 #if 0 /* NTEMACS_TODO : port window properties to W32 */
11727
11728 struct frame *f = check_x_frame (frame);
11729 Atom prop_atom;
11730 int rc;
11731 Lisp_Object prop_value = Qnil;
11732 char *tmp_data = NULL;
11733 Atom actual_type;
11734 int actual_format;
11735 unsigned long actual_size, bytes_remaining;
11736
11737 CHECK_STRING (prop, 1);
11738 BLOCK_INPUT;
11739 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
11740 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
11741 prop_atom, 0, 0, False, XA_STRING,
11742 &actual_type, &actual_format, &actual_size,
11743 &bytes_remaining, (unsigned char **) &tmp_data);
11744 if (rc == Success)
11745 {
11746 int size = bytes_remaining;
11747
11748 XFree (tmp_data);
11749 tmp_data = NULL;
11750
11751 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
11752 prop_atom, 0, bytes_remaining,
11753 False, XA_STRING,
11754 &actual_type, &actual_format,
11755 &actual_size, &bytes_remaining,
11756 (unsigned char **) &tmp_data);
11757 if (rc == Success)
11758 prop_value = make_string (tmp_data, size);
11759
11760 XFree (tmp_data);
11761 }
11762
11763 UNBLOCK_INPUT;
11764
11765 return prop_value;
11766
11767 #endif /* NTEMACS_TODO */
11768 return Qnil;
11769 }
11770
11771
11772 \f
11773 /***********************************************************************
11774 Busy cursor
11775 ***********************************************************************/
11776
11777 /* If non-null, an asynchronous timer that, when it expires, displays
11778 a busy cursor on all frames. */
11779
11780 static struct atimer *busy_cursor_atimer;
11781
11782 /* Non-zero means a busy cursor is currently shown. */
11783
11784 static int busy_cursor_shown_p;
11785
11786 /* Number of seconds to wait before displaying a busy cursor. */
11787
11788 static Lisp_Object Vbusy_cursor_delay;
11789
11790 /* Default number of seconds to wait before displaying a busy
11791 cursor. */
11792
11793 #define DEFAULT_BUSY_CURSOR_DELAY 1
11794
11795 /* Function prototypes. */
11796
11797 static void show_busy_cursor P_ ((struct atimer *));
11798 static void hide_busy_cursor P_ ((void));
11799
11800
11801 /* Cancel a currently active busy-cursor timer, and start a new one. */
11802
11803 void
11804 start_busy_cursor ()
11805 {
11806 #if 0 /* NTEMACS_TODO: cursor shape changes. */
11807 EMACS_TIME delay;
11808 int secs, usecs = 0;
11809
11810 cancel_busy_cursor ();
11811
11812 if (INTEGERP (Vbusy_cursor_delay)
11813 && XINT (Vbusy_cursor_delay) > 0)
11814 secs = XFASTINT (Vbusy_cursor_delay);
11815 else if (FLOATP (Vbusy_cursor_delay)
11816 && XFLOAT_DATA (Vbusy_cursor_delay) > 0)
11817 {
11818 Lisp_Object tem;
11819 tem = Ftruncate (Vbusy_cursor_delay, Qnil);
11820 secs = XFASTINT (tem);
11821 usecs = (XFLOAT_DATA (Vbusy_cursor_delay) - secs) * 1000000;
11822 }
11823 else
11824 secs = DEFAULT_BUSY_CURSOR_DELAY;
11825
11826 EMACS_SET_SECS_USECS (delay, secs, usecs);
11827 busy_cursor_atimer = start_atimer (ATIMER_RELATIVE, delay,
11828 show_busy_cursor, NULL);
11829 #endif
11830 }
11831
11832
11833 /* Cancel the busy cursor timer if active, hide a busy cursor if
11834 shown. */
11835
11836 void
11837 cancel_busy_cursor ()
11838 {
11839 if (busy_cursor_atimer)
11840 {
11841 cancel_atimer (busy_cursor_atimer);
11842 busy_cursor_atimer = NULL;
11843 }
11844
11845 if (busy_cursor_shown_p)
11846 hide_busy_cursor ();
11847 }
11848
11849
11850 /* Timer function of busy_cursor_atimer. TIMER is equal to
11851 busy_cursor_atimer.
11852
11853 Display a busy cursor on all frames by mapping the frames'
11854 busy_window. Set the busy_p flag in the frames' output_data.x
11855 structure to indicate that a busy cursor is shown on the
11856 frames. */
11857
11858 static void
11859 show_busy_cursor (timer)
11860 struct atimer *timer;
11861 {
11862 #if 0 /* NTEMACS_TODO: cursor shape changes. */
11863 /* The timer implementation will cancel this timer automatically
11864 after this function has run. Set busy_cursor_atimer to null
11865 so that we know the timer doesn't have to be canceled. */
11866 busy_cursor_atimer = NULL;
11867
11868 if (!busy_cursor_shown_p)
11869 {
11870 Lisp_Object rest, frame;
11871
11872 BLOCK_INPUT;
11873
11874 FOR_EACH_FRAME (rest, frame)
11875 if (FRAME_X_P (XFRAME (frame)))
11876 {
11877 struct frame *f = XFRAME (frame);
11878
11879 f->output_data.w32->busy_p = 1;
11880
11881 if (!f->output_data.w32->busy_window)
11882 {
11883 unsigned long mask = CWCursor;
11884 XSetWindowAttributes attrs;
11885
11886 attrs.cursor = f->output_data.w32->busy_cursor;
11887
11888 f->output_data.w32->busy_window
11889 = XCreateWindow (FRAME_X_DISPLAY (f),
11890 FRAME_OUTER_WINDOW (f),
11891 0, 0, 32000, 32000, 0, 0,
11892 InputOnly,
11893 CopyFromParent,
11894 mask, &attrs);
11895 }
11896
11897 XMapRaised (FRAME_X_DISPLAY (f), f->output_data.w32->busy_window);
11898 XFlush (FRAME_X_DISPLAY (f));
11899 }
11900
11901 busy_cursor_shown_p = 1;
11902 UNBLOCK_INPUT;
11903 }
11904 #endif
11905 }
11906
11907
11908 /* Hide the busy cursor on all frames, if it is currently shown. */
11909
11910 static void
11911 hide_busy_cursor ()
11912 {
11913 #if 0 /* NTEMACS_TODO: cursor shape changes. */
11914 if (busy_cursor_shown_p)
11915 {
11916 Lisp_Object rest, frame;
11917
11918 BLOCK_INPUT;
11919 FOR_EACH_FRAME (rest, frame)
11920 {
11921 struct frame *f = XFRAME (frame);
11922
11923 if (FRAME_X_P (f)
11924 /* Watch out for newly created frames. */
11925 && f->output_data.x->busy_window)
11926 {
11927 XUnmapWindow (FRAME_X_DISPLAY (f), f->output_data.x->busy_window);
11928 /* Sync here because XTread_socket looks at the busy_p flag
11929 that is reset to zero below. */
11930 XSync (FRAME_X_DISPLAY (f), False);
11931 f->output_data.x->busy_p = 0;
11932 }
11933 }
11934
11935 busy_cursor_shown_p = 0;
11936 UNBLOCK_INPUT;
11937 }
11938 #endif
11939 }
11940
11941
11942 \f
11943 /***********************************************************************
11944 Tool tips
11945 ***********************************************************************/
11946
11947 static Lisp_Object x_create_tip_frame P_ ((struct w32_display_info *,
11948 Lisp_Object));
11949
11950 /* The frame of a currently visible tooltip, or null. */
11951
11952 struct frame *tip_frame;
11953
11954 /* If non-nil, a timer started that hides the last tooltip when it
11955 fires. */
11956
11957 Lisp_Object tip_timer;
11958 Window tip_window;
11959
11960 /* Create a frame for a tooltip on the display described by DPYINFO.
11961 PARMS is a list of frame parameters. Value is the frame. */
11962
11963 static Lisp_Object
11964 x_create_tip_frame (dpyinfo, parms)
11965 struct w32_display_info *dpyinfo;
11966 Lisp_Object parms;
11967 {
11968 #if 0 /* NTEMACS_TODO : w32 version */
11969 struct frame *f;
11970 Lisp_Object frame, tem;
11971 Lisp_Object name;
11972 long window_prompting = 0;
11973 int width, height;
11974 int count = specpdl_ptr - specpdl;
11975 struct gcpro gcpro1, gcpro2, gcpro3;
11976 struct kboard *kb;
11977
11978 check_x ();
11979
11980 /* Use this general default value to start with until we know if
11981 this frame has a specified name. */
11982 Vx_resource_name = Vinvocation_name;
11983
11984 #ifdef MULTI_KBOARD
11985 kb = dpyinfo->kboard;
11986 #else
11987 kb = &the_only_kboard;
11988 #endif
11989
11990 /* Get the name of the frame to use for resource lookup. */
11991 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
11992 if (!STRINGP (name)
11993 && !EQ (name, Qunbound)
11994 && !NILP (name))
11995 error ("Invalid frame name--not a string or nil");
11996 Vx_resource_name = name;
11997
11998 frame = Qnil;
11999 GCPRO3 (parms, name, frame);
12000 tip_frame = f = make_frame (1);
12001 XSETFRAME (frame, f);
12002 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
12003
12004 f->output_method = output_w32;
12005 f->output_data.w32 =
12006 (struct w32_output *) xmalloc (sizeof (struct w32_output));
12007 bzero (f->output_data.w32, sizeof (struct w32_output));
12008 #if 0
12009 f->output_data.w32->icon_bitmap = -1;
12010 #endif
12011 f->output_data.w32->fontset = -1;
12012 f->icon_name = Qnil;
12013
12014 #ifdef MULTI_KBOARD
12015 FRAME_KBOARD (f) = kb;
12016 #endif
12017 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
12018 f->output_data.w32->explicit_parent = 0;
12019
12020 /* Set the name; the functions to which we pass f expect the name to
12021 be set. */
12022 if (EQ (name, Qunbound) || NILP (name))
12023 {
12024 f->name = build_string (dpyinfo->x_id_name);
12025 f->explicit_name = 0;
12026 }
12027 else
12028 {
12029 f->name = name;
12030 f->explicit_name = 1;
12031 /* use the frame's title when getting resources for this frame. */
12032 specbind (Qx_resource_name, name);
12033 }
12034
12035 /* Extract the window parameters from the supplied values
12036 that are needed to determine window geometry. */
12037 {
12038 Lisp_Object font;
12039
12040 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
12041
12042 BLOCK_INPUT;
12043 /* First, try whatever font the caller has specified. */
12044 if (STRINGP (font))
12045 {
12046 tem = Fquery_fontset (font, Qnil);
12047 if (STRINGP (tem))
12048 font = x_new_fontset (f, XSTRING (tem)->data);
12049 else
12050 font = x_new_font (f, XSTRING (font)->data);
12051 }
12052
12053 /* Try out a font which we hope has bold and italic variations. */
12054 if (!STRINGP (font))
12055 font = x_new_font (f, "-adobe-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-1");
12056 if (!STRINGP (font))
12057 font = x_new_font (f, "-misc-fixed-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
12058 if (! STRINGP (font))
12059 font = x_new_font (f, "-*-*-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
12060 if (! STRINGP (font))
12061 /* This was formerly the first thing tried, but it finds too many fonts
12062 and takes too long. */
12063 font = x_new_font (f, "-*-*-medium-r-*-*-*-*-*-*-c-*-iso8859-1");
12064 /* If those didn't work, look for something which will at least work. */
12065 if (! STRINGP (font))
12066 font = x_new_font (f, "-*-fixed-*-*-*-*-*-140-*-*-c-*-iso8859-1");
12067 UNBLOCK_INPUT;
12068 if (! STRINGP (font))
12069 font = build_string ("fixed");
12070
12071 x_default_parameter (f, parms, Qfont, font,
12072 "font", "Font", RES_TYPE_STRING);
12073 }
12074
12075 x_default_parameter (f, parms, Qborder_width, make_number (2),
12076 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
12077
12078 /* This defaults to 2 in order to match xterm. We recognize either
12079 internalBorderWidth or internalBorder (which is what xterm calls
12080 it). */
12081 if (NILP (Fassq (Qinternal_border_width, parms)))
12082 {
12083 Lisp_Object value;
12084
12085 value = w32_get_arg (parms, Qinternal_border_width,
12086 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
12087 if (! EQ (value, Qunbound))
12088 parms = Fcons (Fcons (Qinternal_border_width, value),
12089 parms);
12090 }
12091
12092 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
12093 "internalBorderWidth", "internalBorderWidth",
12094 RES_TYPE_NUMBER);
12095
12096 /* Also do the stuff which must be set before the window exists. */
12097 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
12098 "foreground", "Foreground", RES_TYPE_STRING);
12099 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
12100 "background", "Background", RES_TYPE_STRING);
12101 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
12102 "pointerColor", "Foreground", RES_TYPE_STRING);
12103 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
12104 "cursorColor", "Foreground", RES_TYPE_STRING);
12105 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
12106 "borderColor", "BorderColor", RES_TYPE_STRING);
12107
12108 /* Init faces before x_default_parameter is called for scroll-bar
12109 parameters because that function calls x_set_scroll_bar_width,
12110 which calls change_frame_size, which calls Fset_window_buffer,
12111 which runs hooks, which call Fvertical_motion. At the end, we
12112 end up in init_iterator with a null face cache, which should not
12113 happen. */
12114 init_frame_faces (f);
12115
12116 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
12117 window_prompting = x_figure_window_size (f, parms);
12118
12119 if (window_prompting & XNegative)
12120 {
12121 if (window_prompting & YNegative)
12122 f->output_data.w32->win_gravity = SouthEastGravity;
12123 else
12124 f->output_data.w32->win_gravity = NorthEastGravity;
12125 }
12126 else
12127 {
12128 if (window_prompting & YNegative)
12129 f->output_data.w32->win_gravity = SouthWestGravity;
12130 else
12131 f->output_data.w32->win_gravity = NorthWestGravity;
12132 }
12133
12134 f->output_data.w32->size_hint_flags = window_prompting;
12135 {
12136 XSetWindowAttributes attrs;
12137 unsigned long mask;
12138
12139 BLOCK_INPUT;
12140 mask = CWBackPixel | CWOverrideRedirect | CWSaveUnder | CWEventMask;
12141 /* Window managers looks at the override-redirect flag to
12142 determine whether or net to give windows a decoration (Xlib
12143 3.2.8). */
12144 attrs.override_redirect = True;
12145 attrs.save_under = True;
12146 attrs.background_pixel = FRAME_BACKGROUND_PIXEL (f);
12147 /* Arrange for getting MapNotify and UnmapNotify events. */
12148 attrs.event_mask = StructureNotifyMask;
12149 tip_window
12150 = FRAME_W32_WINDOW (f)
12151 = XCreateWindow (FRAME_W32_DISPLAY (f),
12152 FRAME_W32_DISPLAY_INFO (f)->root_window,
12153 /* x, y, width, height */
12154 0, 0, 1, 1,
12155 /* Border. */
12156 1,
12157 CopyFromParent, InputOutput, CopyFromParent,
12158 mask, &attrs);
12159 UNBLOCK_INPUT;
12160 }
12161
12162 x_make_gc (f);
12163
12164 x_default_parameter (f, parms, Qauto_raise, Qnil,
12165 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
12166 x_default_parameter (f, parms, Qauto_lower, Qnil,
12167 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
12168 x_default_parameter (f, parms, Qcursor_type, Qbox,
12169 "cursorType", "CursorType", RES_TYPE_SYMBOL);
12170
12171 /* Dimensions, especially f->height, must be done via change_frame_size.
12172 Change will not be effected unless different from the current
12173 f->height. */
12174 width = f->width;
12175 height = f->height;
12176 f->height = 0;
12177 SET_FRAME_WIDTH (f, 0);
12178 change_frame_size (f, height, width, 1, 0, 0);
12179
12180 f->no_split = 1;
12181
12182 UNGCPRO;
12183
12184 /* It is now ok to make the frame official even if we get an error
12185 below. And the frame needs to be on Vframe_list or making it
12186 visible won't work. */
12187 Vframe_list = Fcons (frame, Vframe_list);
12188
12189 /* Now that the frame is official, it counts as a reference to
12190 its display. */
12191 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
12192
12193 return unbind_to (count, frame);
12194 #endif /* NTEMACS_TODO */
12195 return Qnil;
12196 }
12197
12198
12199 DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 4, 0,
12200 "Show STRING in a \"tooltip\" window on frame FRAME.\n\
12201 A tooltip window is a small X window displaying STRING at\n\
12202 the current mouse position.\n\
12203 FRAME nil or omitted means use the selected frame.\n\
12204 PARMS is an optional list of frame parameters which can be\n\
12205 used to change the tooltip's appearance.\n\
12206 Automatically hide the tooltip after TIMEOUT seconds.\n\
12207 TIMEOUT nil means use the default timeout of 5 seconds.")
12208 (string, frame, parms, timeout)
12209 Lisp_Object string, frame, parms, timeout;
12210 {
12211 struct frame *f;
12212 struct window *w;
12213 Window root, child;
12214 Lisp_Object buffer;
12215 struct buffer *old_buffer;
12216 struct text_pos pos;
12217 int i, width, height;
12218 int root_x, root_y, win_x, win_y;
12219 unsigned pmask;
12220 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
12221 int old_windows_or_buffers_changed = windows_or_buffers_changed;
12222 int count = specpdl_ptr - specpdl;
12223
12224 specbind (Qinhibit_redisplay, Qt);
12225
12226 GCPRO4 (string, parms, frame, timeout);
12227
12228 CHECK_STRING (string, 0);
12229 f = check_x_frame (frame);
12230 if (NILP (timeout))
12231 timeout = make_number (5);
12232 else
12233 CHECK_NATNUM (timeout, 2);
12234
12235 /* Hide a previous tip, if any. */
12236 Fx_hide_tip ();
12237
12238 /* Add default values to frame parameters. */
12239 if (NILP (Fassq (Qname, parms)))
12240 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
12241 if (NILP (Fassq (Qinternal_border_width, parms)))
12242 parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
12243 if (NILP (Fassq (Qborder_width, parms)))
12244 parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
12245 if (NILP (Fassq (Qborder_color, parms)))
12246 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
12247 if (NILP (Fassq (Qbackground_color, parms)))
12248 parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
12249 parms);
12250
12251 /* Create a frame for the tooltip, and record it in the global
12252 variable tip_frame. */
12253 frame = x_create_tip_frame (FRAME_W32_DISPLAY_INFO (f), parms);
12254 tip_frame = f = XFRAME (frame);
12255
12256 /* Set up the frame's root window. Currently we use a size of 80
12257 columns x 40 lines. If someone wants to show a larger tip, he
12258 will loose. I don't think this is a realistic case. */
12259 w = XWINDOW (FRAME_ROOT_WINDOW (f));
12260 w->left = w->top = make_number (0);
12261 w->width = 80;
12262 w->height = 40;
12263 adjust_glyphs (f);
12264 w->pseudo_window_p = 1;
12265
12266 /* Display the tooltip text in a temporary buffer. */
12267 buffer = Fget_buffer_create (build_string (" *tip*"));
12268 Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer);
12269 old_buffer = current_buffer;
12270 set_buffer_internal_1 (XBUFFER (buffer));
12271 Ferase_buffer ();
12272 Finsert (make_number (1), &string);
12273 clear_glyph_matrix (w->desired_matrix);
12274 clear_glyph_matrix (w->current_matrix);
12275 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
12276 try_window (FRAME_ROOT_WINDOW (f), pos);
12277
12278 /* Compute width and height of the tooltip. */
12279 width = height = 0;
12280 for (i = 0; i < w->desired_matrix->nrows; ++i)
12281 {
12282 struct glyph_row *row = &w->desired_matrix->rows[i];
12283 struct glyph *last;
12284 int row_width;
12285
12286 /* Stop at the first empty row at the end. */
12287 if (!row->enabled_p || !row->displays_text_p)
12288 break;
12289
12290 /* Let the row go over the full width of the frame. */
12291 row->full_width_p = 1;
12292
12293 /* There's a glyph at the end of rows that is use to place
12294 the cursor there. Don't include the width of this glyph. */
12295 if (row->used[TEXT_AREA])
12296 {
12297 last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
12298 row_width = row->pixel_width - last->pixel_width;
12299 }
12300 else
12301 row_width = row->pixel_width;
12302
12303 height += row->height;
12304 width = max (width, row_width);
12305 }
12306
12307 /* Add the frame's internal border to the width and height the X
12308 window should have. */
12309 height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
12310 width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
12311
12312 /* Move the tooltip window where the mouse pointer is. Resize and
12313 show it. */
12314 #if 0 /* NTEMACS_TODO : W32 specifics */
12315 BLOCK_INPUT;
12316 XQueryPointer (FRAME_W32_DISPLAY (f), FRAME_W32_DISPLAY_INFO (f)->root_window,
12317 &root, &child, &root_x, &root_y, &win_x, &win_y, &pmask);
12318 XMoveResizeWindow (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
12319 root_x + 5, root_y - height - 5, width, height);
12320 XMapRaised (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f));
12321 UNBLOCK_INPUT;
12322 #endif /* NTEMACS_TODO */
12323
12324 /* Draw into the window. */
12325 w->must_be_updated_p = 1;
12326 update_single_window (w, 1);
12327
12328 /* Restore original current buffer. */
12329 set_buffer_internal_1 (old_buffer);
12330 windows_or_buffers_changed = old_windows_or_buffers_changed;
12331
12332 /* Let the tip disappear after timeout seconds. */
12333 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
12334 intern ("x-hide-tip"));
12335
12336 UNGCPRO;
12337 return unbind_to (count, Qnil);
12338 }
12339
12340
12341 DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
12342 "Hide the current tooltip window, if there is any.\n\
12343 Value is t is tooltip was open, nil otherwise.")
12344 ()
12345 {
12346 int count = specpdl_ptr - specpdl;
12347 int deleted_p = 0;
12348
12349 specbind (Qinhibit_redisplay, Qt);
12350
12351 if (!NILP (tip_timer))
12352 {
12353 call1 (intern ("cancel-timer"), tip_timer);
12354 tip_timer = Qnil;
12355 }
12356
12357 if (tip_frame)
12358 {
12359 Lisp_Object frame;
12360
12361 XSETFRAME (frame, tip_frame);
12362 Fdelete_frame (frame, Qt);
12363 tip_frame = NULL;
12364 deleted_p = 1;
12365 }
12366
12367 return unbind_to (count, deleted_p ? Qt : Qnil);
12368 }
12369
12370
12371 \f
12372 /***********************************************************************
12373 File selection dialog
12374 ***********************************************************************/
12375
12376 extern Lisp_Object Qfile_name_history;
12377
12378 DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0,
12379 "Read file name, prompting with PROMPT in directory DIR.\n\
12380 Use a file selection dialog.\n\
12381 Select DEFAULT-FILENAME in the dialog's file selection box, if\n\
12382 specified. Don't let the user enter a file name in the file\n\
12383 selection dialog's entry field, if MUSTMATCH is non-nil.")
12384 (prompt, dir, default_filename, mustmatch)
12385 Lisp_Object prompt, dir, default_filename, mustmatch;
12386 {
12387 struct frame *f = SELECTED_FRAME ();
12388 Lisp_Object file = Qnil;
12389 int count = specpdl_ptr - specpdl;
12390 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
12391 char filename[MAX_PATH + 1];
12392 char init_dir[MAX_PATH + 1];
12393 int use_dialog_p = 1;
12394
12395 GCPRO5 (prompt, dir, default_filename, mustmatch, file);
12396 CHECK_STRING (prompt, 0);
12397 CHECK_STRING (dir, 1);
12398
12399 /* Create the dialog with PROMPT as title, using DIR as initial
12400 directory and using "*" as pattern. */
12401 dir = Fexpand_file_name (dir, Qnil);
12402 strncpy (init_dir, XSTRING (dir)->data, MAX_PATH);
12403 init_dir[MAX_PATH] = '\0';
12404 unixtodos_filename (init_dir);
12405
12406 if (STRINGP (default_filename))
12407 {
12408 char *file_name_only;
12409 char *full_path_name = XSTRING (default_filename)->data;
12410
12411 unixtodos_filename (full_path_name);
12412
12413 file_name_only = strrchr (full_path_name, '\\');
12414 if (!file_name_only)
12415 file_name_only = full_path_name;
12416 else
12417 {
12418 file_name_only++;
12419
12420 /* If default_file_name is a directory, don't use the open
12421 file dialog, as it does not support selecting
12422 directories. */
12423 if (!(*file_name_only))
12424 use_dialog_p = 0;
12425 }
12426
12427 strncpy (filename, file_name_only, MAX_PATH);
12428 filename[MAX_PATH] = '\0';
12429 }
12430 else
12431 filename[0] = '\0';
12432
12433 if (use_dialog_p)
12434 {
12435 OPENFILENAME file_details;
12436 char *filename_file;
12437
12438 /* Prevent redisplay. */
12439 specbind (Qinhibit_redisplay, Qt);
12440 BLOCK_INPUT;
12441
12442 bzero (&file_details, sizeof (file_details));
12443 file_details.lStructSize = sizeof (file_details);
12444 file_details.hwndOwner = FRAME_W32_WINDOW (f);
12445 file_details.lpstrFile = filename;
12446 file_details.nMaxFile = sizeof (filename);
12447 file_details.lpstrInitialDir = init_dir;
12448 file_details.lpstrTitle = XSTRING (prompt)->data;
12449 file_details.Flags = OFN_HIDEREADONLY | OFN_NOCHANGEDIR;
12450
12451 if (!NILP (mustmatch))
12452 file_details.Flags |= OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
12453
12454 if (GetOpenFileName (&file_details))
12455 {
12456 dostounix_filename (filename);
12457 file = build_string (filename);
12458 }
12459 else
12460 file = Qnil;
12461
12462 UNBLOCK_INPUT;
12463 file = unbind_to (count, file);
12464 }
12465 /* Open File dialog will not allow folders to be selected, so resort
12466 to minibuffer completing reads for directories. */
12467 else
12468 file = Fcompleting_read (prompt, intern ("read-file-name-internal"),
12469 dir, mustmatch, dir, Qfile_name_history,
12470 default_filename, Qnil);
12471
12472 UNGCPRO;
12473
12474 /* Make "Cancel" equivalent to C-g. */
12475 if (NILP (file))
12476 Fsignal (Qquit, Qnil);
12477
12478 return unbind_to (count, file);
12479 }
12480
12481
12482 \f
12483 /***********************************************************************
12484 Tests
12485 ***********************************************************************/
12486
12487 #if GLYPH_DEBUG
12488
12489 DEFUN ("imagep", Fimagep, Simagep, 1, 1, 0,
12490 "Value is non-nil if SPEC is a valid image specification.")
12491 (spec)
12492 Lisp_Object spec;
12493 {
12494 return valid_image_p (spec) ? Qt : Qnil;
12495 }
12496
12497
12498 DEFUN ("lookup-image", Flookup_image, Slookup_image, 1, 1, 0, "")
12499 (spec)
12500 Lisp_Object spec;
12501 {
12502 int id = -1;
12503
12504 if (valid_image_p (spec))
12505 id = lookup_image (SELECTED_FRAME (), spec);
12506
12507 debug_print (spec);
12508 return make_number (id);
12509 }
12510
12511 #endif /* GLYPH_DEBUG != 0 */
12512
12513
12514 \f
12515 /***********************************************************************
12516 w32 specialized functions
12517 ***********************************************************************/
12518
12519 DEFUN ("w32-select-font", Fw32_select_font, Sw32_select_font, 0, 1, 0,
12520 "This will display the W32 font dialog and return an X font string corresponding to the selection.")
12521 (frame)
12522 Lisp_Object frame;
12523 {
12524 FRAME_PTR f = check_x_frame (frame);
12525 CHOOSEFONT cf;
12526 LOGFONT lf;
12527 TEXTMETRIC tm;
12528 HDC hdc;
12529 HANDLE oldobj;
12530 char buf[100];
12531
12532 bzero (&cf, sizeof (cf));
12533 bzero (&lf, sizeof (lf));
12534
12535 cf.lStructSize = sizeof (cf);
12536 cf.hwndOwner = FRAME_W32_WINDOW (f);
12537 cf.Flags = CF_FORCEFONTEXIST | CF_SCREENFONTS;
12538 cf.lpLogFont = &lf;
12539
12540 /* Initialize as much of the font details as we can from the current
12541 default font. */
12542 hdc = GetDC (FRAME_W32_WINDOW (f));
12543 oldobj = SelectObject (hdc, FRAME_FONT (f)->hfont);
12544 GetTextFace (hdc, LF_FACESIZE, lf.lfFaceName);
12545 if (GetTextMetrics (hdc, &tm))
12546 {
12547 lf.lfHeight = tm.tmInternalLeading - tm.tmHeight;
12548 lf.lfWeight = tm.tmWeight;
12549 lf.lfItalic = tm.tmItalic;
12550 lf.lfUnderline = tm.tmUnderlined;
12551 lf.lfStrikeOut = tm.tmStruckOut;
12552 lf.lfCharSet = tm.tmCharSet;
12553 cf.Flags |= CF_INITTOLOGFONTSTRUCT;
12554 }
12555 SelectObject (hdc, oldobj);
12556 ReleaseDC (FRAME_W32_WINDOW (f), hdc);
12557
12558 if (!ChooseFont (&cf) || !w32_to_x_font (&lf, buf, 100))
12559 return Qnil;
12560
12561 return build_string (buf);
12562 }
12563
12564 DEFUN ("w32-send-sys-command", Fw32_send_sys_command, Sw32_send_sys_command, 1, 2, 0,
12565 "Send frame a Windows WM_SYSCOMMAND message of type COMMAND.\n\
12566 Some useful values for command are 0xf030 to maximise frame (0xf020\n\
12567 to minimize), 0xf120 to restore frame to original size, and 0xf100\n\
12568 to activate the menubar for keyboard access. 0xf140 activates the\n\
12569 screen saver if defined.\n\
12570 \n\
12571 If optional parameter FRAME is not specified, use selected frame.")
12572 (command, frame)
12573 Lisp_Object command, frame;
12574 {
12575 WPARAM code;
12576 FRAME_PTR f = check_x_frame (frame);
12577
12578 CHECK_NUMBER (command, 0);
12579
12580 PostMessage (FRAME_W32_WINDOW (f), WM_SYSCOMMAND, XINT (command), 0);
12581
12582 return Qnil;
12583 }
12584
12585 DEFUN ("w32-shell-execute", Fw32_shell_execute, Sw32_shell_execute, 2, 4, 0,
12586 "Get Windows to perform OPERATION on DOCUMENT.\n\
12587 This is a wrapper around the ShellExecute system function, which\n\
12588 invokes the application registered to handle OPERATION for DOCUMENT.\n\
12589 OPERATION is typically \"open\", \"print\" or \"explore\" (but can be\n\
12590 nil for the default action), and DOCUMENT is typically the name of a\n\
12591 document file or URL, but can also be a program executable to run or\n\
12592 a directory to open in the Windows Explorer.\n\
12593 \n\
12594 If DOCUMENT is a program executable, PARAMETERS can be a string\n\
12595 containing command line parameters, but otherwise should be nil.\n\
12596 \n\
12597 SHOW-FLAG can be used to control whether the invoked application is hidden\n\
12598 or minimized. If SHOW-FLAG is nil, the application is displayed normally,\n\
12599 otherwise it is an integer representing a ShowWindow flag:\n\
12600 \n\
12601 0 - start hidden\n\
12602 1 - start normally\n\
12603 3 - start maximized\n\
12604 6 - start minimized")
12605 (operation, document, parameters, show_flag)
12606 Lisp_Object operation, document, parameters, show_flag;
12607 {
12608 Lisp_Object current_dir;
12609
12610 CHECK_STRING (document, 0);
12611
12612 /* Encode filename and current directory. */
12613 current_dir = ENCODE_FILE (current_buffer->directory);
12614 document = ENCODE_FILE (document);
12615 if ((int) ShellExecute (NULL,
12616 (STRINGP (operation) ?
12617 XSTRING (operation)->data : NULL),
12618 XSTRING (document)->data,
12619 (STRINGP (parameters) ?
12620 XSTRING (parameters)->data : NULL),
12621 XSTRING (current_dir)->data,
12622 (INTEGERP (show_flag) ?
12623 XINT (show_flag) : SW_SHOWDEFAULT))
12624 > 32)
12625 return Qt;
12626 error ("ShellExecute failed");
12627 }
12628
12629 /* Lookup virtual keycode from string representing the name of a
12630 non-ascii keystroke into the corresponding virtual key, using
12631 lispy_function_keys. */
12632 static int
12633 lookup_vk_code (char *key)
12634 {
12635 int i;
12636
12637 for (i = 0; i < 256; i++)
12638 if (lispy_function_keys[i] != 0
12639 && strcmp (lispy_function_keys[i], key) == 0)
12640 return i;
12641
12642 return -1;
12643 }
12644
12645 /* Convert a one-element vector style key sequence to a hot key
12646 definition. */
12647 static int
12648 w32_parse_hot_key (key)
12649 Lisp_Object key;
12650 {
12651 /* Copied from Fdefine_key and store_in_keymap. */
12652 register Lisp_Object c;
12653 int vk_code;
12654 int lisp_modifiers;
12655 int w32_modifiers;
12656 struct gcpro gcpro1;
12657
12658 CHECK_VECTOR (key, 0);
12659
12660 if (XFASTINT (Flength (key)) != 1)
12661 return Qnil;
12662
12663 GCPRO1 (key);
12664
12665 c = Faref (key, make_number (0));
12666
12667 if (CONSP (c) && lucid_event_type_list_p (c))
12668 c = Fevent_convert_list (c);
12669
12670 UNGCPRO;
12671
12672 if (! INTEGERP (c) && ! SYMBOLP (c))
12673 error ("Key definition is invalid");
12674
12675 /* Work out the base key and the modifiers. */
12676 if (SYMBOLP (c))
12677 {
12678 c = parse_modifiers (c);
12679 lisp_modifiers = Fcar (Fcdr (c));
12680 c = Fcar (c);
12681 if (!SYMBOLP (c))
12682 abort ();
12683 vk_code = lookup_vk_code (XSYMBOL (c)->name->data);
12684 }
12685 else if (INTEGERP (c))
12686 {
12687 lisp_modifiers = XINT (c) & ~CHARACTERBITS;
12688 /* Many ascii characters are their own virtual key code. */
12689 vk_code = XINT (c) & CHARACTERBITS;
12690 }
12691
12692 if (vk_code < 0 || vk_code > 255)
12693 return Qnil;
12694
12695 if ((lisp_modifiers & meta_modifier) != 0
12696 && !NILP (Vw32_alt_is_meta))
12697 lisp_modifiers |= alt_modifier;
12698
12699 /* Convert lisp modifiers to Windows hot-key form. */
12700 w32_modifiers = (lisp_modifiers & hyper_modifier) ? MOD_WIN : 0;
12701 w32_modifiers |= (lisp_modifiers & alt_modifier) ? MOD_ALT : 0;
12702 w32_modifiers |= (lisp_modifiers & ctrl_modifier) ? MOD_CONTROL : 0;
12703 w32_modifiers |= (lisp_modifiers & shift_modifier) ? MOD_SHIFT : 0;
12704
12705 return HOTKEY (vk_code, w32_modifiers);
12706 }
12707
12708 DEFUN ("w32-register-hot-key", Fw32_register_hot_key, Sw32_register_hot_key, 1, 1, 0,
12709 "Register KEY as a hot-key combination.\n\
12710 Certain key combinations like Alt-Tab are reserved for system use on\n\
12711 Windows, and therefore are normally intercepted by the system. However,\n\
12712 most of these key combinations can be received by registering them as\n\
12713 hot-keys, overriding their special meaning.\n\
12714 \n\
12715 KEY must be a one element key definition in vector form that would be\n\
12716 acceptable to `define-key' (e.g. [A-tab] for Alt-Tab). The meta\n\
12717 modifier is interpreted as Alt if `w32-alt-is-meta' is t, and hyper\n\
12718 is always interpreted as the Windows modifier keys.\n\
12719 \n\
12720 The return value is the hotkey-id if registered, otherwise nil.")
12721 (key)
12722 Lisp_Object key;
12723 {
12724 key = w32_parse_hot_key (key);
12725
12726 if (NILP (Fmemq (key, w32_grabbed_keys)))
12727 {
12728 /* Reuse an empty slot if possible. */
12729 Lisp_Object item = Fmemq (Qnil, w32_grabbed_keys);
12730
12731 /* Safe to add new key to list, even if we have focus. */
12732 if (NILP (item))
12733 w32_grabbed_keys = Fcons (key, w32_grabbed_keys);
12734 else
12735 XCAR (item) = key;
12736
12737 /* Notify input thread about new hot-key definition, so that it
12738 takes effect without needing to switch focus. */
12739 PostThreadMessage (dwWindowsThreadId, WM_EMACS_REGISTER_HOT_KEY,
12740 (WPARAM) key, 0);
12741 }
12742
12743 return key;
12744 }
12745
12746 DEFUN ("w32-unregister-hot-key", Fw32_unregister_hot_key, Sw32_unregister_hot_key, 1, 1, 0,
12747 "Unregister HOTKEY as a hot-key combination.")
12748 (key)
12749 Lisp_Object key;
12750 {
12751 Lisp_Object item;
12752
12753 if (!INTEGERP (key))
12754 key = w32_parse_hot_key (key);
12755
12756 item = Fmemq (key, w32_grabbed_keys);
12757
12758 if (!NILP (item))
12759 {
12760 /* Notify input thread about hot-key definition being removed, so
12761 that it takes effect without needing focus switch. */
12762 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_UNREGISTER_HOT_KEY,
12763 (WPARAM) XINT (XCAR (item)), (LPARAM) item))
12764 {
12765 MSG msg;
12766 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
12767 }
12768 return Qt;
12769 }
12770 return Qnil;
12771 }
12772
12773 DEFUN ("w32-registered-hot-keys", Fw32_registered_hot_keys, Sw32_registered_hot_keys, 0, 0, 0,
12774 "Return list of registered hot-key IDs.")
12775 ()
12776 {
12777 return Fcopy_sequence (w32_grabbed_keys);
12778 }
12779
12780 DEFUN ("w32-reconstruct-hot-key", Fw32_reconstruct_hot_key, Sw32_reconstruct_hot_key, 1, 1, 0,
12781 "Convert hot-key ID to a lisp key combination.")
12782 (hotkeyid)
12783 Lisp_Object hotkeyid;
12784 {
12785 int vk_code, w32_modifiers;
12786 Lisp_Object key;
12787
12788 CHECK_NUMBER (hotkeyid, 0);
12789
12790 vk_code = HOTKEY_VK_CODE (hotkeyid);
12791 w32_modifiers = HOTKEY_MODIFIERS (hotkeyid);
12792
12793 if (lispy_function_keys[vk_code])
12794 key = intern (lispy_function_keys[vk_code]);
12795 else
12796 key = make_number (vk_code);
12797
12798 key = Fcons (key, Qnil);
12799 if (w32_modifiers & MOD_SHIFT)
12800 key = Fcons (Qshift, key);
12801 if (w32_modifiers & MOD_CONTROL)
12802 key = Fcons (Qctrl, key);
12803 if (w32_modifiers & MOD_ALT)
12804 key = Fcons (NILP (Vw32_alt_is_meta) ? Qalt : Qmeta, key);
12805 if (w32_modifiers & MOD_WIN)
12806 key = Fcons (Qhyper, key);
12807
12808 return key;
12809 }
12810
12811 DEFUN ("w32-toggle-lock-key", Fw32_toggle_lock_key, Sw32_toggle_lock_key, 1, 2, 0,
12812 "Toggle the state of the lock key KEY.\n\
12813 KEY can be `capslock', `kp-numlock', or `scroll'.\n\
12814 If the optional parameter NEW-STATE is a number, then the state of KEY\n\
12815 is set to off if the low bit of NEW-STATE is zero, otherwise on.")
12816 (key, new_state)
12817 Lisp_Object key, new_state;
12818 {
12819 int vk_code;
12820 int cur_state;
12821
12822 if (EQ (key, intern ("capslock")))
12823 vk_code = VK_CAPITAL;
12824 else if (EQ (key, intern ("kp-numlock")))
12825 vk_code = VK_NUMLOCK;
12826 else if (EQ (key, intern ("scroll")))
12827 vk_code = VK_SCROLL;
12828 else
12829 return Qnil;
12830
12831 if (!dwWindowsThreadId)
12832 return make_number (w32_console_toggle_lock_key (vk_code, new_state));
12833
12834 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_TOGGLE_LOCK_KEY,
12835 (WPARAM) vk_code, (LPARAM) new_state))
12836 {
12837 MSG msg;
12838 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
12839 return make_number (msg.wParam);
12840 }
12841 return Qnil;
12842 }
12843 \f
12844 syms_of_w32fns ()
12845 {
12846 /* This is zero if not using MS-Windows. */
12847 w32_in_use = 0;
12848
12849 /* The section below is built by the lisp expression at the top of the file,
12850 just above where these variables are declared. */
12851 /*&&& init symbols here &&&*/
12852 Qauto_raise = intern ("auto-raise");
12853 staticpro (&Qauto_raise);
12854 Qauto_lower = intern ("auto-lower");
12855 staticpro (&Qauto_lower);
12856 Qbar = intern ("bar");
12857 staticpro (&Qbar);
12858 Qborder_color = intern ("border-color");
12859 staticpro (&Qborder_color);
12860 Qborder_width = intern ("border-width");
12861 staticpro (&Qborder_width);
12862 Qbox = intern ("box");
12863 staticpro (&Qbox);
12864 Qcursor_color = intern ("cursor-color");
12865 staticpro (&Qcursor_color);
12866 Qcursor_type = intern ("cursor-type");
12867 staticpro (&Qcursor_type);
12868 Qgeometry = intern ("geometry");
12869 staticpro (&Qgeometry);
12870 Qicon_left = intern ("icon-left");
12871 staticpro (&Qicon_left);
12872 Qicon_top = intern ("icon-top");
12873 staticpro (&Qicon_top);
12874 Qicon_type = intern ("icon-type");
12875 staticpro (&Qicon_type);
12876 Qicon_name = intern ("icon-name");
12877 staticpro (&Qicon_name);
12878 Qinternal_border_width = intern ("internal-border-width");
12879 staticpro (&Qinternal_border_width);
12880 Qleft = intern ("left");
12881 staticpro (&Qleft);
12882 Qright = intern ("right");
12883 staticpro (&Qright);
12884 Qmouse_color = intern ("mouse-color");
12885 staticpro (&Qmouse_color);
12886 Qnone = intern ("none");
12887 staticpro (&Qnone);
12888 Qparent_id = intern ("parent-id");
12889 staticpro (&Qparent_id);
12890 Qscroll_bar_width = intern ("scroll-bar-width");
12891 staticpro (&Qscroll_bar_width);
12892 Qsuppress_icon = intern ("suppress-icon");
12893 staticpro (&Qsuppress_icon);
12894 Qundefined_color = intern ("undefined-color");
12895 staticpro (&Qundefined_color);
12896 Qvertical_scroll_bars = intern ("vertical-scroll-bars");
12897 staticpro (&Qvertical_scroll_bars);
12898 Qvisibility = intern ("visibility");
12899 staticpro (&Qvisibility);
12900 Qwindow_id = intern ("window-id");
12901 staticpro (&Qwindow_id);
12902 Qx_frame_parameter = intern ("x-frame-parameter");
12903 staticpro (&Qx_frame_parameter);
12904 Qx_resource_name = intern ("x-resource-name");
12905 staticpro (&Qx_resource_name);
12906 Quser_position = intern ("user-position");
12907 staticpro (&Quser_position);
12908 Quser_size = intern ("user-size");
12909 staticpro (&Quser_size);
12910 Qscreen_gamma = intern ("screen-gamma");
12911 staticpro (&Qscreen_gamma);
12912 Qline_spacing = intern ("line-spacing");
12913 staticpro (&Qline_spacing);
12914 Qcenter = intern ("center");
12915 staticpro (&Qcenter);
12916 /* This is the end of symbol initialization. */
12917
12918 Qhyper = intern ("hyper");
12919 staticpro (&Qhyper);
12920 Qsuper = intern ("super");
12921 staticpro (&Qsuper);
12922 Qmeta = intern ("meta");
12923 staticpro (&Qmeta);
12924 Qalt = intern ("alt");
12925 staticpro (&Qalt);
12926 Qctrl = intern ("ctrl");
12927 staticpro (&Qctrl);
12928 Qcontrol = intern ("control");
12929 staticpro (&Qcontrol);
12930 Qshift = intern ("shift");
12931 staticpro (&Qshift);
12932
12933 /* Text property `display' should be nonsticky by default. */
12934 Vtext_property_default_nonsticky
12935 = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky);
12936
12937
12938 Qlaplace = intern ("laplace");
12939 staticpro (&Qlaplace);
12940
12941 Qface_set_after_frame_default = intern ("face-set-after-frame-default");
12942 staticpro (&Qface_set_after_frame_default);
12943
12944 Fput (Qundefined_color, Qerror_conditions,
12945 Fcons (Qundefined_color, Fcons (Qerror, Qnil)));
12946 Fput (Qundefined_color, Qerror_message,
12947 build_string ("Undefined color"));
12948
12949 staticpro (&w32_grabbed_keys);
12950 w32_grabbed_keys = Qnil;
12951
12952 DEFVAR_LISP ("w32-color-map", &Vw32_color_map,
12953 "An array of color name mappings for windows.");
12954 Vw32_color_map = Qnil;
12955
12956 DEFVAR_LISP ("w32-pass-alt-to-system", &Vw32_pass_alt_to_system,
12957 "Non-nil if alt key presses are passed on to Windows.\n\
12958 When non-nil, for example, alt pressed and released and then space will\n\
12959 open the System menu. When nil, Emacs silently swallows alt key events.");
12960 Vw32_pass_alt_to_system = Qnil;
12961
12962 DEFVAR_LISP ("w32-alt-is-meta", &Vw32_alt_is_meta,
12963 "Non-nil if the alt key is to be considered the same as the meta key.\n\
12964 When nil, Emacs will translate the alt key to the Alt modifier, and not Meta.");
12965 Vw32_alt_is_meta = Qt;
12966
12967 DEFVAR_INT ("w32-quit-key", &Vw32_quit_key,
12968 "If non-zero, the virtual key code for an alternative quit key.");
12969 XSETINT (Vw32_quit_key, 0);
12970
12971 DEFVAR_LISP ("w32-pass-lwindow-to-system",
12972 &Vw32_pass_lwindow_to_system,
12973 "Non-nil if the left \"Windows\" key is passed on to Windows.\n\
12974 When non-nil, the Start menu is opened by tapping the key.");
12975 Vw32_pass_lwindow_to_system = Qt;
12976
12977 DEFVAR_LISP ("w32-pass-rwindow-to-system",
12978 &Vw32_pass_rwindow_to_system,
12979 "Non-nil if the right \"Windows\" key is passed on to Windows.\n\
12980 When non-nil, the Start menu is opened by tapping the key.");
12981 Vw32_pass_rwindow_to_system = Qt;
12982
12983 DEFVAR_INT ("w32-phantom-key-code",
12984 &Vw32_phantom_key_code,
12985 "Virtual key code used to generate \"phantom\" key presses.\n\
12986 Value is a number between 0 and 255.\n\
12987 \n\
12988 Phantom key presses are generated in order to stop the system from\n\
12989 acting on \"Windows\" key events when `w32-pass-lwindow-to-system' or\n\
12990 `w32-pass-rwindow-to-system' is nil.");
12991 /* Although 255 is technically not a valid key code, it works and
12992 means that this hack won't interfere with any real key code. */
12993 Vw32_phantom_key_code = 255;
12994
12995 DEFVAR_LISP ("w32-enable-num-lock",
12996 &Vw32_enable_num_lock,
12997 "Non-nil if Num Lock should act normally.\n\
12998 Set to nil to see Num Lock as the key `kp-numlock'.");
12999 Vw32_enable_num_lock = Qt;
13000
13001 DEFVAR_LISP ("w32-enable-caps-lock",
13002 &Vw32_enable_caps_lock,
13003 "Non-nil if Caps Lock should act normally.\n\
13004 Set to nil to see Caps Lock as the key `capslock'.");
13005 Vw32_enable_caps_lock = Qt;
13006
13007 DEFVAR_LISP ("w32-scroll-lock-modifier",
13008 &Vw32_scroll_lock_modifier,
13009 "Modifier to use for the Scroll Lock on state.\n\
13010 The value can be hyper, super, meta, alt, control or shift for the\n\
13011 respective modifier, or nil to see Scroll Lock as the key `scroll'.\n\
13012 Any other value will cause the key to be ignored.");
13013 Vw32_scroll_lock_modifier = Qt;
13014
13015 DEFVAR_LISP ("w32-lwindow-modifier",
13016 &Vw32_lwindow_modifier,
13017 "Modifier to use for the left \"Windows\" key.\n\
13018 The value can be hyper, super, meta, alt, control or shift for the\n\
13019 respective modifier, or nil to appear as the key `lwindow'.\n\
13020 Any other value will cause the key to be ignored.");
13021 Vw32_lwindow_modifier = Qnil;
13022
13023 DEFVAR_LISP ("w32-rwindow-modifier",
13024 &Vw32_rwindow_modifier,
13025 "Modifier to use for the right \"Windows\" key.\n\
13026 The value can be hyper, super, meta, alt, control or shift for the\n\
13027 respective modifier, or nil to appear as the key `rwindow'.\n\
13028 Any other value will cause the key to be ignored.");
13029 Vw32_rwindow_modifier = Qnil;
13030
13031 DEFVAR_LISP ("w32-apps-modifier",
13032 &Vw32_apps_modifier,
13033 "Modifier to use for the \"Apps\" key.\n\
13034 The value can be hyper, super, meta, alt, control or shift for the\n\
13035 respective modifier, or nil to appear as the key `apps'.\n\
13036 Any other value will cause the key to be ignored.");
13037 Vw32_apps_modifier = Qnil;
13038
13039 DEFVAR_LISP ("w32-enable-synthesized_fonts", &Vw32_enable_synthesized_fonts,
13040 "Non-nil enables selection of artificially italicized and bold fonts.");
13041 Vw32_enable_synthesized_fonts = Qnil;
13042
13043 DEFVAR_LISP ("w32-enable-palette", &Vw32_enable_palette,
13044 "Non-nil enables Windows palette management to map colors exactly.");
13045 Vw32_enable_palette = Qt;
13046
13047 DEFVAR_INT ("w32-mouse-button-tolerance",
13048 &Vw32_mouse_button_tolerance,
13049 "Analogue of double click interval for faking middle mouse events.\n\
13050 The value is the minimum time in milliseconds that must elapse between\n\
13051 left/right button down events before they are considered distinct events.\n\
13052 If both mouse buttons are depressed within this interval, a middle mouse\n\
13053 button down event is generated instead.");
13054 XSETINT (Vw32_mouse_button_tolerance, GetDoubleClickTime () / 2);
13055
13056 DEFVAR_INT ("w32-mouse-move-interval",
13057 &Vw32_mouse_move_interval,
13058 "Minimum interval between mouse move events.\n\
13059 The value is the minimum time in milliseconds that must elapse between\n\
13060 successive mouse move (or scroll bar drag) events before they are\n\
13061 reported as lisp events.");
13062 XSETINT (Vw32_mouse_move_interval, 0);
13063
13064 init_x_parm_symbols ();
13065
13066 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
13067 "List of directories to search for bitmap files for w32.");
13068 Vx_bitmap_file_path = decode_env_path ((char *) 0, "PATH");
13069
13070 DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
13071 "The shape of the pointer when over text.\n\
13072 Changing the value does not affect existing frames\n\
13073 unless you set the mouse color.");
13074 Vx_pointer_shape = Qnil;
13075
13076 DEFVAR_LISP ("x-resource-name", &Vx_resource_name,
13077 "The name Emacs uses to look up resources; for internal use only.\n\
13078 `x-get-resource' uses this as the first component of the instance name\n\
13079 when requesting resource values.\n\
13080 Emacs initially sets `x-resource-name' to the name under which Emacs\n\
13081 was invoked, or to the value specified with the `-name' or `-rn'\n\
13082 switches, if present.");
13083 Vx_resource_name = Qnil;
13084
13085 Vx_nontext_pointer_shape = Qnil;
13086
13087 Vx_mode_pointer_shape = Qnil;
13088
13089 DEFVAR_LISP ("x-busy-pointer-shape", &Vx_busy_pointer_shape,
13090 "The shape of the pointer when Emacs is busy.\n\
13091 This variable takes effect when you create a new frame\n\
13092 or when you set the mouse color.");
13093 Vx_busy_pointer_shape = Qnil;
13094
13095 DEFVAR_BOOL ("display-busy-cursor", &display_busy_cursor_p,
13096 "Non-zero means Emacs displays a busy cursor on window systems.");
13097 display_busy_cursor_p = 1;
13098
13099 DEFVAR_LISP ("busy-cursor-delay", &Vbusy_cursor_delay,
13100 "*Seconds to wait before displaying a busy-cursor.\n\
13101 Value must be an integer or float.");
13102 Vbusy_cursor_delay = make_number (DEFAULT_BUSY_CURSOR_DELAY);
13103
13104 DEFVAR_LISP ("x-sensitive-text-pointer-shape",
13105 &Vx_sensitive_text_pointer_shape,
13106 "The shape of the pointer when over mouse-sensitive text.\n\
13107 This variable takes effect when you create a new frame\n\
13108 or when you set the mouse color.");
13109 Vx_sensitive_text_pointer_shape = Qnil;
13110
13111 DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
13112 "A string indicating the foreground color of the cursor box.");
13113 Vx_cursor_fore_pixel = Qnil;
13114
13115 DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
13116 "Non-nil if no window manager is in use.\n\
13117 Emacs doesn't try to figure this out; this is always nil\n\
13118 unless you set it to something else.");
13119 /* We don't have any way to find this out, so set it to nil
13120 and maybe the user would like to set it to t. */
13121 Vx_no_window_manager = Qnil;
13122
13123 DEFVAR_LISP ("x-pixel-size-width-font-regexp",
13124 &Vx_pixel_size_width_font_regexp,
13125 "Regexp matching a font name whose width is the same as `PIXEL_SIZE'.\n\
13126 \n\
13127 Since Emacs gets width of a font matching with this regexp from\n\
13128 PIXEL_SIZE field of the name, font finding mechanism gets faster for\n\
13129 such a font. This is especially effective for such large fonts as\n\
13130 Chinese, Japanese, and Korean.");
13131 Vx_pixel_size_width_font_regexp = Qnil;
13132
13133 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
13134 "Time after which cached images are removed from the cache.\n\
13135 When an image has not been displayed this many seconds, remove it\n\
13136 from the image cache. Value must be an integer or nil with nil\n\
13137 meaning don't clear the cache.");
13138 Vimage_cache_eviction_delay = make_number (30 * 60);
13139
13140 DEFVAR_LISP ("w32-bdf-filename-alist",
13141 &Vw32_bdf_filename_alist,
13142 "List of bdf fonts and their corresponding filenames.");
13143 Vw32_bdf_filename_alist = Qnil;
13144
13145 DEFVAR_BOOL ("w32-strict-fontnames",
13146 &w32_strict_fontnames,
13147 "Non-nil means only use fonts that are exact matches for those requested.\n\
13148 Default is nil, which allows old fontnames that are not XLFD compliant,\n\
13149 and allows third-party CJK display to work by specifying false charset\n\
13150 fields to trick Emacs into translating to Big5, SJIS etc.\n\
13151 Setting this to t will prevent wrong fonts being selected when\n\
13152 fontsets are automatically created.");
13153 w32_strict_fontnames = 0;
13154
13155 DEFVAR_BOOL ("w32-strict-painting",
13156 &w32_strict_painting,
13157 "Non-nil means use strict rules for repainting frames.\n\
13158 Set this to nil to get the old behaviour for repainting; this should\n\
13159 only be necessary if the default setting causes problems.");
13160 w32_strict_painting = 1;
13161
13162 DEFVAR_LISP ("w32-system-coding-system",
13163 &Vw32_system_coding_system,
13164 "Coding system used by Windows system functions, such as for font names.");
13165 Vw32_system_coding_system = Qnil;
13166
13167 DEFVAR_LISP ("w32-charset-info-alist",
13168 &Vw32_charset_info_alist,
13169 "Alist linking Emacs character sets to Windows fonts\n\
13170 and codepages. Each entry should be of the form:\n\
13171 \n\
13172 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE))\n\
13173 \n\
13174 where CHARSET_NAME is a string used in font names to identify the charset,\n\
13175 WINDOWS_CHARSET is a symbol that can be one of:\n\
13176 w32-charset-ansi, w32-charset-default, w32-charset-symbol,\n\
13177 w32-charset-shiftjis, w32-charset-hangul, w32-charset-gb2312,\n\
13178 w32-charset-chinesebig5, "
13179 #ifdef JOHAB_CHARSET
13180 "w32-charset-johab, w32-charset-hebrew,\n\
13181 w32-charset-arabic, w32-charset-greek, w32-charset-turkish,\n\
13182 w32-charset-vietnamese, w32-charset-thai, w32-charset-easteurope,\n\
13183 w32-charset-russian, w32-charset-mac, w32-charset-baltic,\n"
13184 #endif
13185 #ifdef UNICODE_CHARSET
13186 "w32-charset-unicode, "
13187 #endif
13188 "or w32-charset-oem.\n\
13189 CODEPAGE should be an integer specifying the codepage that should be used\n\
13190 to display the character set, t to do no translation and output as Unicode,\n\
13191 or nil to do no translation and output as 8 bit (or multibyte on far-east\n\
13192 versions of Windows) characters.");
13193 Vw32_charset_info_alist = Qnil;
13194
13195 staticpro (&Qw32_charset_ansi);
13196 Qw32_charset_ansi = intern ("w32-charset-ansi");
13197 staticpro (&Qw32_charset_symbol);
13198 Qw32_charset_symbol = intern ("w32-charset-symbol");
13199 staticpro (&Qw32_charset_shiftjis);
13200 Qw32_charset_shiftjis = intern ("w32-charset-shiftjis");
13201 staticpro (&Qw32_charset_hangul);
13202 Qw32_charset_hangul = intern ("w32-charset-hangul");
13203 staticpro (&Qw32_charset_chinesebig5);
13204 Qw32_charset_chinesebig5 = intern ("w32-charset-chinesebig5");
13205 staticpro (&Qw32_charset_gb2312);
13206 Qw32_charset_gb2312 = intern ("w32-charset-gb2312");
13207 staticpro (&Qw32_charset_oem);
13208 Qw32_charset_oem = intern ("w32-charset-oem");
13209
13210 #ifdef JOHAB_CHARSET
13211 {
13212 static int w32_extra_charsets_defined = 1;
13213 DEFVAR_BOOL ("w32-extra-charsets-defined", w32_extra_charsets_defined, "");
13214
13215 staticpro (&Qw32_charset_johab);
13216 Qw32_charset_johab = intern ("w32-charset-johab");
13217 staticpro (&Qw32_charset_easteurope);
13218 Qw32_charset_easteurope = intern ("w32-charset-easteurope");
13219 staticpro (&Qw32_charset_turkish);
13220 Qw32_charset_turkish = intern ("w32-charset-turkish");
13221 staticpro (&Qw32_charset_baltic);
13222 Qw32_charset_baltic = intern ("w32-charset-baltic");
13223 staticpro (&Qw32_charset_russian);
13224 Qw32_charset_russian = intern ("w32-charset-russian");
13225 staticpro (&Qw32_charset_arabic);
13226 Qw32_charset_arabic = intern ("w32-charset-arabic");
13227 staticpro (&Qw32_charset_greek);
13228 Qw32_charset_greek = intern ("w32-charset-greek");
13229 staticpro (&Qw32_charset_hebrew);
13230 Qw32_charset_hebrew = intern ("w32-charset-hebrew");
13231 staticpro (&Qw32_charset_thai);
13232 Qw32_charset_thai = intern ("w32-charset-thai");
13233 staticpro (&Qw32_charset_mac);
13234 Qw32_charset_mac = intern ("w32-charset-mac");
13235 }
13236 #endif
13237
13238 #ifdef UNICODE_CHARSET
13239 {
13240 static int w32_unicode_charset_defined = 1;
13241 DEFVAR_BOOL ("w32-unicode-charset-defined",
13242 w32_unicode_charset_defined, "");
13243
13244 staticpro (&Qw32_charset_unicode);
13245 Qw32_charset_unicode = intern ("w32-charset-unicode");
13246 #endif
13247
13248 defsubr (&Sx_get_resource);
13249 #if 0 /* NTEMACS_TODO: Port to W32 */
13250 defsubr (&Sx_change_window_property);
13251 defsubr (&Sx_delete_window_property);
13252 defsubr (&Sx_window_property);
13253 #endif
13254 defsubr (&Sxw_display_color_p);
13255 defsubr (&Sx_display_grayscale_p);
13256 defsubr (&Sxw_color_defined_p);
13257 defsubr (&Sxw_color_values);
13258 defsubr (&Sx_server_max_request_size);
13259 defsubr (&Sx_server_vendor);
13260 defsubr (&Sx_server_version);
13261 defsubr (&Sx_display_pixel_width);
13262 defsubr (&Sx_display_pixel_height);
13263 defsubr (&Sx_display_mm_width);
13264 defsubr (&Sx_display_mm_height);
13265 defsubr (&Sx_display_screens);
13266 defsubr (&Sx_display_planes);
13267 defsubr (&Sx_display_color_cells);
13268 defsubr (&Sx_display_visual_class);
13269 defsubr (&Sx_display_backing_store);
13270 defsubr (&Sx_display_save_under);
13271 defsubr (&Sx_parse_geometry);
13272 defsubr (&Sx_create_frame);
13273 defsubr (&Sx_open_connection);
13274 defsubr (&Sx_close_connection);
13275 defsubr (&Sx_display_list);
13276 defsubr (&Sx_synchronize);
13277
13278 /* W32 specific functions */
13279
13280 defsubr (&Sw32_focus_frame);
13281 defsubr (&Sw32_select_font);
13282 defsubr (&Sw32_define_rgb_color);
13283 defsubr (&Sw32_default_color_map);
13284 defsubr (&Sw32_load_color_file);
13285 defsubr (&Sw32_send_sys_command);
13286 defsubr (&Sw32_shell_execute);
13287 defsubr (&Sw32_register_hot_key);
13288 defsubr (&Sw32_unregister_hot_key);
13289 defsubr (&Sw32_registered_hot_keys);
13290 defsubr (&Sw32_reconstruct_hot_key);
13291 defsubr (&Sw32_toggle_lock_key);
13292 defsubr (&Sw32_find_bdf_fonts);
13293
13294 /* Setting callback functions for fontset handler. */
13295 get_font_info_func = w32_get_font_info;
13296
13297 #if 0 /* This function pointer doesn't seem to be used anywhere.
13298 And the pointer assigned has the wrong type, anyway. */
13299 list_fonts_func = w32_list_fonts;
13300 #endif
13301
13302 load_font_func = w32_load_font;
13303 find_ccl_program_func = w32_find_ccl_program;
13304 query_font_func = w32_query_font;
13305 set_frame_fontset_func = x_set_font;
13306 check_window_system_func = check_w32;
13307
13308 #if 0 /* NTEMACS_TODO Image support for W32 */
13309 /* Images. */
13310 Qxbm = intern ("xbm");
13311 staticpro (&Qxbm);
13312 QCtype = intern (":type");
13313 staticpro (&QCtype);
13314 QCalgorithm = intern (":algorithm");
13315 staticpro (&QCalgorithm);
13316 QCheuristic_mask = intern (":heuristic-mask");
13317 staticpro (&QCheuristic_mask);
13318 QCcolor_symbols = intern (":color-symbols");
13319 staticpro (&QCcolor_symbols);
13320 QCascent = intern (":ascent");
13321 staticpro (&QCascent);
13322 QCmargin = intern (":margin");
13323 staticpro (&QCmargin);
13324 QCrelief = intern (":relief");
13325 staticpro (&QCrelief);
13326 Qpostscript = intern ("postscript");
13327 staticpro (&Qpostscript);
13328 QCloader = intern (":loader");
13329 staticpro (&QCloader);
13330 QCbounding_box = intern (":bounding-box");
13331 staticpro (&QCbounding_box);
13332 QCpt_width = intern (":pt-width");
13333 staticpro (&QCpt_width);
13334 QCpt_height = intern (":pt-height");
13335 staticpro (&QCpt_height);
13336 QCindex = intern (":index");
13337 staticpro (&QCindex);
13338 Qpbm = intern ("pbm");
13339 staticpro (&Qpbm);
13340
13341 #if HAVE_XPM
13342 Qxpm = intern ("xpm");
13343 staticpro (&Qxpm);
13344 #endif
13345
13346 #if HAVE_JPEG
13347 Qjpeg = intern ("jpeg");
13348 staticpro (&Qjpeg);
13349 #endif
13350
13351 #if HAVE_TIFF
13352 Qtiff = intern ("tiff");
13353 staticpro (&Qtiff);
13354 #endif
13355
13356 #if HAVE_GIF
13357 Qgif = intern ("gif");
13358 staticpro (&Qgif);
13359 #endif
13360
13361 #if HAVE_PNG
13362 Qpng = intern ("png");
13363 staticpro (&Qpng);
13364 #endif
13365
13366 defsubr (&Sclear_image_cache);
13367
13368 #if GLYPH_DEBUG
13369 defsubr (&Simagep);
13370 defsubr (&Slookup_image);
13371 #endif
13372 #endif /* NTEMACS_TODO */
13373
13374 busy_cursor_atimer = NULL;
13375 busy_cursor_shown_p = 0;
13376
13377 defsubr (&Sx_show_tip);
13378 defsubr (&Sx_hide_tip);
13379 staticpro (&tip_timer);
13380 tip_timer = Qnil;
13381
13382 defsubr (&Sx_file_dialog);
13383 }
13384
13385
13386 void
13387 init_xfns ()
13388 {
13389 image_types = NULL;
13390 Vimage_types = Qnil;
13391
13392 #if 0 /* NTEMACS_TODO : Image support for W32 */
13393 define_image_type (&xbm_type);
13394 define_image_type (&gs_type);
13395 define_image_type (&pbm_type);
13396
13397 #if HAVE_XPM
13398 define_image_type (&xpm_type);
13399 #endif
13400
13401 #if HAVE_JPEG
13402 define_image_type (&jpeg_type);
13403 #endif
13404
13405 #if HAVE_TIFF
13406 define_image_type (&tiff_type);
13407 #endif
13408
13409 #if HAVE_GIF
13410 define_image_type (&gif_type);
13411 #endif
13412
13413 #if HAVE_PNG
13414 define_image_type (&png_type);
13415 #endif
13416 #endif /* NTEMACS_TODO */
13417 }
13418
13419 #undef abort
13420
13421 void
13422 w32_abort()
13423 {
13424 int button;
13425 button = MessageBox (NULL,
13426 "A fatal error has occurred!\n\n"
13427 "Select Abort to exit, Retry to debug, Ignore to continue",
13428 "Emacs Abort Dialog",
13429 MB_ICONEXCLAMATION | MB_TASKMODAL
13430 | MB_SETFOREGROUND | MB_ABORTRETRYIGNORE);
13431 switch (button)
13432 {
13433 case IDRETRY:
13434 DebugBreak ();
13435 break;
13436 case IDIGNORE:
13437 break;
13438 case IDABORT:
13439 default:
13440 abort ();
13441 break;
13442 }
13443 }
13444
13445 /* For convenience when debugging. */
13446 int
13447 w32_last_error()
13448 {
13449 return GetLastError ();
13450 }