]> code.delx.au - gnu-emacs/blob - src/w32fns.c
*** empty log message ***
[gnu-emacs] / 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 "fontset.h"
34 #include "w32term.h"
35 #include "frame.h"
36 #include "window.h"
37 #include "buffer.h"
38 #include "dispextern.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 struct scroll_bar *x_window_to_scroll_bar ();
58 extern int w32_console_toggle_lock_key (int vk_code, Lisp_Object new_state);
59 extern int quit_char;
60
61 /* A definition of XColor for non-X frames. */
62 #ifndef HAVE_X_WINDOWS
63 typedef struct {
64 unsigned long pixel;
65 unsigned short red, green, blue;
66 char flags;
67 char pad;
68 } XColor;
69 #endif
70
71 extern char *lispy_function_keys[];
72
73 /* The gray bitmap `bitmaps/gray'. This is done because w32term.c uses
74 it, and including `bitmaps/gray' more than once is a problem when
75 config.h defines `static' as an empty replacement string. */
76
77 int gray_bitmap_width = gray_width;
78 int gray_bitmap_height = gray_height;
79 unsigned char *gray_bitmap_bits = gray_bits;
80
81 /* The colormap for converting color names to RGB values */
82 Lisp_Object Vw32_color_map;
83
84 /* Non nil if alt key presses are passed on to Windows. */
85 Lisp_Object Vw32_pass_alt_to_system;
86
87 /* Non nil if alt key is translated to meta_modifier, nil if it is translated
88 to alt_modifier. */
89 Lisp_Object Vw32_alt_is_meta;
90
91 /* If non-zero, the windows virtual key code for an alternative quit key. */
92 Lisp_Object Vw32_quit_key;
93
94 /* Non nil if left window key events are passed on to Windows (this only
95 affects whether "tapping" the key opens the Start menu). */
96 Lisp_Object Vw32_pass_lwindow_to_system;
97
98 /* Non nil if right window key events are passed on to Windows (this
99 only affects whether "tapping" the key opens the Start menu). */
100 Lisp_Object Vw32_pass_rwindow_to_system;
101
102 /* Virtual key code used to generate "phantom" key presses in order
103 to stop system from acting on Windows key events. */
104 Lisp_Object Vw32_phantom_key_code;
105
106 /* Modifier associated with the left "Windows" key, or nil to act as a
107 normal key. */
108 Lisp_Object Vw32_lwindow_modifier;
109
110 /* Modifier associated with the right "Windows" key, or nil to act as a
111 normal key. */
112 Lisp_Object Vw32_rwindow_modifier;
113
114 /* Modifier associated with the "Apps" key, or nil to act as a normal
115 key. */
116 Lisp_Object Vw32_apps_modifier;
117
118 /* Value is nil if Num Lock acts as a function key. */
119 Lisp_Object Vw32_enable_num_lock;
120
121 /* Value is nil if Caps Lock acts as a function key. */
122 Lisp_Object Vw32_enable_caps_lock;
123
124 /* Modifier associated with Scroll Lock, or nil to act as a normal key. */
125 Lisp_Object Vw32_scroll_lock_modifier;
126
127 /* Switch to control whether we inhibit requests for synthesyzed bold
128 and italic versions of fonts. */
129 Lisp_Object Vw32_enable_synthesized_fonts;
130
131 /* Enable palette management. */
132 Lisp_Object Vw32_enable_palette;
133
134 /* Control how close left/right button down events must be to
135 be converted to a middle button down event. */
136 Lisp_Object Vw32_mouse_button_tolerance;
137
138 /* Minimum interval between mouse movement (and scroll bar drag)
139 events that are passed on to the event loop. */
140 Lisp_Object Vw32_mouse_move_interval;
141
142 /* The name we're using in resource queries. */
143 Lisp_Object Vx_resource_name;
144
145 /* Non nil if no window manager is in use. */
146 Lisp_Object Vx_no_window_manager;
147
148 /* Non-zero means we're allowed to display a busy cursor. */
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 Lisp_Object Vx_pointer_shape, Vx_nontext_pointer_shape, Vx_mode_pointer_shape;
154 Lisp_Object Vx_busy_pointer_shape;
155
156 /* The shape when over mouse-sensitive text. */
157 Lisp_Object Vx_sensitive_text_pointer_shape;
158
159 /* Color of chars displayed in cursor box. */
160 Lisp_Object Vx_cursor_fore_pixel;
161
162 /* Nonzero if using Windows. */
163 static int w32_in_use;
164
165 /* Search path for bitmap files. */
166 Lisp_Object Vx_bitmap_file_path;
167
168 /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'. */
169 Lisp_Object Vx_pixel_size_width_font_regexp;
170
171 /* Alist of bdf fonts and the files that define them. */
172 Lisp_Object Vw32_bdf_filename_alist;
173
174 Lisp_Object Vw32_system_coding_system;
175
176 /* A flag to control whether fonts are matched strictly or not. */
177 int w32_strict_fontnames;
178
179 /* A flag to control whether we should only repaint if GetUpdateRect
180 indicates there is an update region. */
181 int w32_strict_painting;
182
183 /* Evaluate this expression to rebuild the section of syms_of_w32fns
184 that initializes and staticpros the symbols declared below. Note
185 that Emacs 18 has a bug that keeps C-x C-e from being able to
186 evaluate this expression.
187
188 (progn
189 ;; Accumulate a list of the symbols we want to initialize from the
190 ;; declarations at the top of the file.
191 (goto-char (point-min))
192 (search-forward "/\*&&& symbols declared here &&&*\/\n")
193 (let (symbol-list)
194 (while (looking-at "Lisp_Object \\(Q[a-z_]+\\)")
195 (setq symbol-list
196 (cons (buffer-substring (match-beginning 1) (match-end 1))
197 symbol-list))
198 (forward-line 1))
199 (setq symbol-list (nreverse symbol-list))
200 ;; Delete the section of syms_of_... where we initialize the symbols.
201 (search-forward "\n /\*&&& init symbols here &&&*\/\n")
202 (let ((start (point)))
203 (while (looking-at "^ Q")
204 (forward-line 2))
205 (kill-region start (point)))
206 ;; Write a new symbol initialization section.
207 (while symbol-list
208 (insert (format " %s = intern (\"" (car symbol-list)))
209 (let ((start (point)))
210 (insert (substring (car symbol-list) 1))
211 (subst-char-in-region start (point) ?_ ?-))
212 (insert (format "\");\n staticpro (&%s);\n" (car symbol-list)))
213 (setq symbol-list (cdr symbol-list)))))
214
215 */
216
217 /*&&& symbols declared here &&&*/
218 Lisp_Object Qauto_raise;
219 Lisp_Object Qauto_lower;
220 Lisp_Object Qbar;
221 Lisp_Object Qborder_color;
222 Lisp_Object Qborder_width;
223 Lisp_Object Qbox;
224 Lisp_Object Qcursor_color;
225 Lisp_Object Qcursor_type;
226 Lisp_Object Qgeometry;
227 Lisp_Object Qicon_left;
228 Lisp_Object Qicon_top;
229 Lisp_Object Qicon_type;
230 Lisp_Object Qicon_name;
231 Lisp_Object Qinternal_border_width;
232 Lisp_Object Qleft;
233 Lisp_Object Qright;
234 Lisp_Object Qmouse_color;
235 Lisp_Object Qnone;
236 Lisp_Object Qparent_id;
237 Lisp_Object Qscroll_bar_width;
238 Lisp_Object Qsuppress_icon;
239 Lisp_Object Qundefined_color;
240 Lisp_Object Qvertical_scroll_bars;
241 Lisp_Object Qvisibility;
242 Lisp_Object Qwindow_id;
243 Lisp_Object Qx_frame_parameter;
244 Lisp_Object Qx_resource_name;
245 Lisp_Object Quser_position;
246 Lisp_Object Quser_size;
247 Lisp_Object Qscreen_gamma;
248 Lisp_Object Qhyper;
249 Lisp_Object Qsuper;
250 Lisp_Object Qmeta;
251 Lisp_Object Qalt;
252 Lisp_Object Qctrl;
253 Lisp_Object Qcontrol;
254 Lisp_Object Qshift;
255
256 extern Lisp_Object Qtop;
257 extern Lisp_Object Qdisplay;
258 extern Lisp_Object Qtool_bar_lines;
259
260 /* State variables for emulating a three button mouse. */
261 #define LMOUSE 1
262 #define MMOUSE 2
263 #define RMOUSE 4
264
265 static int button_state = 0;
266 static W32Msg saved_mouse_button_msg;
267 static unsigned mouse_button_timer; /* non-zero when timer is active */
268 static W32Msg saved_mouse_move_msg;
269 static unsigned mouse_move_timer;
270
271 /* W95 mousewheel handler */
272 unsigned int msh_mousewheel = 0;
273
274 #define MOUSE_BUTTON_ID 1
275 #define MOUSE_MOVE_ID 2
276
277 /* The below are defined in frame.c. */
278 extern Lisp_Object Qheight, Qminibuffer, Qname, Qonly, Qwidth;
279 extern Lisp_Object Qunsplittable, Qmenu_bar_lines, Qbuffer_predicate, Qtitle;
280 extern Lisp_Object Qtool_bar_lines;
281
282 extern Lisp_Object Vwindow_system_version;
283
284 Lisp_Object Qface_set_after_frame_default;
285
286 extern Lisp_Object last_mouse_scroll_bar;
287 extern int last_mouse_scroll_bar_pos;
288
289 /* From w32term.c. */
290 extern Lisp_Object Vw32_num_mouse_buttons;
291 extern Lisp_Object Vw32_recognize_altgr;
292
293 \f
294 /* Error if we are not connected to MS-Windows. */
295 void
296 check_w32 ()
297 {
298 if (! w32_in_use)
299 error ("MS-Windows not in use or not initialized");
300 }
301
302 /* Nonzero if we can use mouse menus.
303 You should not call this unless HAVE_MENUS is defined. */
304
305 int
306 have_menus_p ()
307 {
308 return w32_in_use;
309 }
310
311 /* Extract a frame as a FRAME_PTR, defaulting to the selected frame
312 and checking validity for W32. */
313
314 FRAME_PTR
315 check_x_frame (frame)
316 Lisp_Object frame;
317 {
318 FRAME_PTR f;
319
320 if (NILP (frame))
321 frame = selected_frame;
322 CHECK_LIVE_FRAME (frame, 0);
323 f = XFRAME (frame);
324 if (! FRAME_W32_P (f))
325 error ("non-w32 frame used");
326 return f;
327 }
328
329 /* Let the user specify an display with a frame.
330 nil stands for the selected frame--or, if that is not a w32 frame,
331 the first display on the list. */
332
333 static struct w32_display_info *
334 check_x_display_info (frame)
335 Lisp_Object frame;
336 {
337 if (NILP (frame))
338 {
339 struct frame *sf = XFRAME (selected_frame);
340
341 if (FRAME_W32_P (sf) && FRAME_LIVE_P (sf))
342 return FRAME_W32_DISPLAY_INFO (sf);
343 else
344 return &one_w32_display_info;
345 }
346 else if (STRINGP (frame))
347 return x_display_info_for_name (frame);
348 else
349 {
350 FRAME_PTR f;
351
352 CHECK_LIVE_FRAME (frame, 0);
353 f = XFRAME (frame);
354 if (! FRAME_W32_P (f))
355 error ("non-w32 frame used");
356 return FRAME_W32_DISPLAY_INFO (f);
357 }
358 }
359 \f
360 /* Return the Emacs frame-object corresponding to an w32 window.
361 It could be the frame's main window or an icon window. */
362
363 /* This function can be called during GC, so use GC_xxx type test macros. */
364
365 struct frame *
366 x_window_to_frame (dpyinfo, wdesc)
367 struct w32_display_info *dpyinfo;
368 HWND wdesc;
369 {
370 Lisp_Object tail, frame;
371 struct frame *f;
372
373 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
374 {
375 frame = XCAR (tail);
376 if (!GC_FRAMEP (frame))
377 continue;
378 f = XFRAME (frame);
379 if (!FRAME_W32_P (f) || FRAME_W32_DISPLAY_INFO (f) != dpyinfo)
380 continue;
381 if (FRAME_W32_WINDOW (f) == wdesc)
382 return f;
383 }
384 return 0;
385 }
386
387 \f
388
389 /* Code to deal with bitmaps. Bitmaps are referenced by their bitmap
390 id, which is just an int that this section returns. Bitmaps are
391 reference counted so they can be shared among frames.
392
393 Bitmap indices are guaranteed to be > 0, so a negative number can
394 be used to indicate no bitmap.
395
396 If you use x_create_bitmap_from_data, then you must keep track of
397 the bitmaps yourself. That is, creating a bitmap from the same
398 data more than once will not be caught. */
399
400
401 /* Functions to access the contents of a bitmap, given an id. */
402
403 int
404 x_bitmap_height (f, id)
405 FRAME_PTR f;
406 int id;
407 {
408 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].height;
409 }
410
411 int
412 x_bitmap_width (f, id)
413 FRAME_PTR f;
414 int id;
415 {
416 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].width;
417 }
418
419 int
420 x_bitmap_pixmap (f, id)
421 FRAME_PTR f;
422 int id;
423 {
424 return (int) FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
425 }
426
427
428 /* Allocate a new bitmap record. Returns index of new record. */
429
430 static int
431 x_allocate_bitmap_record (f)
432 FRAME_PTR f;
433 {
434 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
435 int i;
436
437 if (dpyinfo->bitmaps == NULL)
438 {
439 dpyinfo->bitmaps_size = 10;
440 dpyinfo->bitmaps
441 = (struct w32_bitmap_record *) xmalloc (dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
442 dpyinfo->bitmaps_last = 1;
443 return 1;
444 }
445
446 if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size)
447 return ++dpyinfo->bitmaps_last;
448
449 for (i = 0; i < dpyinfo->bitmaps_size; ++i)
450 if (dpyinfo->bitmaps[i].refcount == 0)
451 return i + 1;
452
453 dpyinfo->bitmaps_size *= 2;
454 dpyinfo->bitmaps
455 = (struct w32_bitmap_record *) xrealloc (dpyinfo->bitmaps,
456 dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
457 return ++dpyinfo->bitmaps_last;
458 }
459
460 /* Add one reference to the reference count of the bitmap with id ID. */
461
462 void
463 x_reference_bitmap (f, id)
464 FRAME_PTR f;
465 int id;
466 {
467 ++FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
468 }
469
470 /* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at BITS. */
471
472 int
473 x_create_bitmap_from_data (f, bits, width, height)
474 struct frame *f;
475 char *bits;
476 unsigned int width, height;
477 {
478 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
479 Pixmap bitmap;
480 int id;
481
482 bitmap = CreateBitmap (width, height,
483 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_planes,
484 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_cbits,
485 bits);
486
487 if (! bitmap)
488 return -1;
489
490 id = x_allocate_bitmap_record (f);
491 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
492 dpyinfo->bitmaps[id - 1].file = NULL;
493 dpyinfo->bitmaps[id - 1].hinst = NULL;
494 dpyinfo->bitmaps[id - 1].refcount = 1;
495 dpyinfo->bitmaps[id - 1].depth = 1;
496 dpyinfo->bitmaps[id - 1].height = height;
497 dpyinfo->bitmaps[id - 1].width = width;
498
499 return id;
500 }
501
502 /* Create bitmap from file FILE for frame F. */
503
504 int
505 x_create_bitmap_from_file (f, file)
506 struct frame *f;
507 Lisp_Object file;
508 {
509 return -1;
510 #if 0 /* NTEMACS_TODO : bitmap support */
511 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
512 unsigned int width, height;
513 HBITMAP bitmap;
514 int xhot, yhot, result, id;
515 Lisp_Object found;
516 int fd;
517 char *filename;
518 HINSTANCE hinst;
519
520 /* Look for an existing bitmap with the same name. */
521 for (id = 0; id < dpyinfo->bitmaps_last; ++id)
522 {
523 if (dpyinfo->bitmaps[id].refcount
524 && dpyinfo->bitmaps[id].file
525 && !strcmp (dpyinfo->bitmaps[id].file, (char *) XSTRING (file)->data))
526 {
527 ++dpyinfo->bitmaps[id].refcount;
528 return id + 1;
529 }
530 }
531
532 /* Search bitmap-file-path for the file, if appropriate. */
533 fd = openp (Vx_bitmap_file_path, file, "", &found, 0);
534 if (fd < 0)
535 return -1;
536 /* LoadLibraryEx won't handle special files handled by Emacs handler. */
537 if (fd == 0)
538 return -1;
539 emacs_close (fd);
540
541 filename = (char *) XSTRING (found)->data;
542
543 hinst = LoadLibraryEx (filename, NULL, LOAD_LIBRARY_AS_DATAFILE);
544
545 if (hinst == NULL)
546 return -1;
547
548
549 result = XReadBitmapFile (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
550 filename, &width, &height, &bitmap, &xhot, &yhot);
551 if (result != BitmapSuccess)
552 return -1;
553
554 id = x_allocate_bitmap_record (f);
555 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
556 dpyinfo->bitmaps[id - 1].refcount = 1;
557 dpyinfo->bitmaps[id - 1].file = (char *) xmalloc (XSTRING (file)->size + 1);
558 dpyinfo->bitmaps[id - 1].depth = 1;
559 dpyinfo->bitmaps[id - 1].height = height;
560 dpyinfo->bitmaps[id - 1].width = width;
561 strcpy (dpyinfo->bitmaps[id - 1].file, XSTRING (file)->data);
562
563 return id;
564 #endif /* NTEMACS_TODO */
565 }
566
567 /* Remove reference to bitmap with id number ID. */
568
569 void
570 x_destroy_bitmap (f, id)
571 FRAME_PTR f;
572 int id;
573 {
574 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
575
576 if (id > 0)
577 {
578 --dpyinfo->bitmaps[id - 1].refcount;
579 if (dpyinfo->bitmaps[id - 1].refcount == 0)
580 {
581 BLOCK_INPUT;
582 DeleteObject (dpyinfo->bitmaps[id - 1].pixmap);
583 if (dpyinfo->bitmaps[id - 1].file)
584 {
585 xfree (dpyinfo->bitmaps[id - 1].file);
586 dpyinfo->bitmaps[id - 1].file = NULL;
587 }
588 UNBLOCK_INPUT;
589 }
590 }
591 }
592
593 /* Free all the bitmaps for the display specified by DPYINFO. */
594
595 static void
596 x_destroy_all_bitmaps (dpyinfo)
597 struct w32_display_info *dpyinfo;
598 {
599 int i;
600 for (i = 0; i < dpyinfo->bitmaps_last; i++)
601 if (dpyinfo->bitmaps[i].refcount > 0)
602 {
603 DeleteObject (dpyinfo->bitmaps[i].pixmap);
604 if (dpyinfo->bitmaps[i].file)
605 xfree (dpyinfo->bitmaps[i].file);
606 }
607 dpyinfo->bitmaps_last = 0;
608 }
609 \f
610 /* Connect the frame-parameter names for W32 frames
611 to the ways of passing the parameter values to the window system.
612
613 The name of a parameter, as a Lisp symbol,
614 has an `x-frame-parameter' property which is an integer in Lisp
615 but can be interpreted as an `enum x_frame_parm' in C. */
616
617 enum x_frame_parm
618 {
619 X_PARM_FOREGROUND_COLOR,
620 X_PARM_BACKGROUND_COLOR,
621 X_PARM_MOUSE_COLOR,
622 X_PARM_CURSOR_COLOR,
623 X_PARM_BORDER_COLOR,
624 X_PARM_ICON_TYPE,
625 X_PARM_FONT,
626 X_PARM_BORDER_WIDTH,
627 X_PARM_INTERNAL_BORDER_WIDTH,
628 X_PARM_NAME,
629 X_PARM_AUTORAISE,
630 X_PARM_AUTOLOWER,
631 X_PARM_VERT_SCROLL_BAR,
632 X_PARM_VISIBILITY,
633 X_PARM_MENU_BAR_LINES
634 };
635
636
637 struct x_frame_parm_table
638 {
639 char *name;
640 void (*setter) P_ ((struct frame *, Lisp_Object, Lisp_Object));
641 };
642
643 /* NTEMACS_TODO: Native Input Method support; see x_create_im. */
644 void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
645 void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
646 void x_set_mouse_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
647 void x_set_cursor_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
648 void x_set_border_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
649 void x_set_cursor_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
650 void x_set_icon_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
651 void x_set_icon_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
652 void x_set_font P_ ((struct frame *, Lisp_Object, Lisp_Object));
653 void x_set_border_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
654 void x_set_internal_border_width P_ ((struct frame *, Lisp_Object,
655 Lisp_Object));
656 void x_explicitly_set_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
657 void x_set_autoraise P_ ((struct frame *, Lisp_Object, Lisp_Object));
658 void x_set_autolower P_ ((struct frame *, Lisp_Object, Lisp_Object));
659 void x_set_vertical_scroll_bars P_ ((struct frame *, Lisp_Object,
660 Lisp_Object));
661 void x_set_visibility P_ ((struct frame *, Lisp_Object, Lisp_Object));
662 void x_set_menu_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
663 void x_set_scroll_bar_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
664 void x_set_title P_ ((struct frame *, Lisp_Object, Lisp_Object));
665 void x_set_unsplittable P_ ((struct frame *, Lisp_Object, Lisp_Object));
666 void x_set_tool_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
667 static void x_set_screen_gamma P_ ((struct frame *, Lisp_Object, Lisp_Object));
668
669 static struct x_frame_parm_table x_frame_parms[] =
670 {
671 "auto-raise", x_set_autoraise,
672 "auto-lower", x_set_autolower,
673 "background-color", x_set_background_color,
674 "border-color", x_set_border_color,
675 "border-width", x_set_border_width,
676 "cursor-color", x_set_cursor_color,
677 "cursor-type", x_set_cursor_type,
678 "font", x_set_font,
679 "foreground-color", x_set_foreground_color,
680 "icon-name", x_set_icon_name,
681 "icon-type", x_set_icon_type,
682 "internal-border-width", x_set_internal_border_width,
683 "menu-bar-lines", x_set_menu_bar_lines,
684 "mouse-color", x_set_mouse_color,
685 "name", x_explicitly_set_name,
686 "scroll-bar-width", x_set_scroll_bar_width,
687 "title", x_set_title,
688 "unsplittable", x_set_unsplittable,
689 "vertical-scroll-bars", x_set_vertical_scroll_bars,
690 "visibility", x_set_visibility,
691 "tool-bar-lines", x_set_tool_bar_lines,
692 "screen-gamma", x_set_screen_gamma
693 };
694
695 /* Attach the `x-frame-parameter' properties to
696 the Lisp symbol names of parameters relevant to W32. */
697
698 init_x_parm_symbols ()
699 {
700 int i;
701
702 for (i = 0; i < sizeof (x_frame_parms) / sizeof (x_frame_parms[0]); i++)
703 Fput (intern (x_frame_parms[i].name), Qx_frame_parameter,
704 make_number (i));
705 }
706 \f
707 /* Change the parameters of FRAME as specified by ALIST.
708 If a parameter is not specially recognized, do nothing;
709 otherwise call the `x_set_...' function for that parameter. */
710
711 void
712 x_set_frame_parameters (f, alist)
713 FRAME_PTR f;
714 Lisp_Object alist;
715 {
716 Lisp_Object tail;
717
718 /* If both of these parameters are present, it's more efficient to
719 set them both at once. So we wait until we've looked at the
720 entire list before we set them. */
721 int width, height;
722
723 /* Same here. */
724 Lisp_Object left, top;
725
726 /* Same with these. */
727 Lisp_Object icon_left, icon_top;
728
729 /* Record in these vectors all the parms specified. */
730 Lisp_Object *parms;
731 Lisp_Object *values;
732 int i, p;
733 int left_no_change = 0, top_no_change = 0;
734 int icon_left_no_change = 0, icon_top_no_change = 0;
735
736 struct gcpro gcpro1, gcpro2;
737
738 i = 0;
739 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
740 i++;
741
742 parms = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
743 values = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
744
745 /* Extract parm names and values into those vectors. */
746
747 i = 0;
748 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
749 {
750 Lisp_Object elt;
751
752 elt = Fcar (tail);
753 parms[i] = Fcar (elt);
754 values[i] = Fcdr (elt);
755 i++;
756 }
757
758 /* TAIL and ALIST are not used again below here. */
759 alist = tail = Qnil;
760
761 GCPRO2 (*parms, *values);
762 gcpro1.nvars = i;
763 gcpro2.nvars = i;
764
765 /* There is no need to gcpro LEFT, TOP, ICON_LEFT, or ICON_TOP,
766 because their values appear in VALUES and strings are not valid. */
767 top = left = Qunbound;
768 icon_left = icon_top = Qunbound;
769
770 /* Provide default values for HEIGHT and WIDTH. */
771 width = FRAME_WIDTH (f);
772 height = FRAME_HEIGHT (f);
773
774 /* Process foreground_color and background_color before anything else.
775 They are independent of other properties, but other properties (e.g.,
776 cursor_color) are dependent upon them. */
777 for (p = 0; p < i; p++)
778 {
779 Lisp_Object prop, val;
780
781 prop = parms[p];
782 val = values[p];
783 if (EQ (prop, Qforeground_color) || EQ (prop, Qbackground_color))
784 {
785 register Lisp_Object param_index, old_value;
786
787 param_index = Fget (prop, Qx_frame_parameter);
788 old_value = get_frame_param (f, prop);
789 store_frame_param (f, prop, val);
790 if (NATNUMP (param_index)
791 && (XFASTINT (param_index)
792 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
793 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
794 }
795 }
796
797 /* Now process them in reverse of specified order. */
798 for (i--; i >= 0; i--)
799 {
800 Lisp_Object prop, val;
801
802 prop = parms[i];
803 val = values[i];
804
805 if (EQ (prop, Qwidth) && NUMBERP (val))
806 width = XFASTINT (val);
807 else if (EQ (prop, Qheight) && NUMBERP (val))
808 height = XFASTINT (val);
809 else if (EQ (prop, Qtop))
810 top = val;
811 else if (EQ (prop, Qleft))
812 left = val;
813 else if (EQ (prop, Qicon_top))
814 icon_top = val;
815 else if (EQ (prop, Qicon_left))
816 icon_left = val;
817 else if (EQ (prop, Qforeground_color) || EQ (prop, Qbackground_color))
818 /* Processed above. */
819 continue;
820 else
821 {
822 register Lisp_Object param_index, old_value;
823
824 param_index = Fget (prop, Qx_frame_parameter);
825 old_value = get_frame_param (f, prop);
826 store_frame_param (f, prop, val);
827 if (NATNUMP (param_index)
828 && (XFASTINT (param_index)
829 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
830 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
831 }
832 }
833
834 /* Don't die if just one of these was set. */
835 if (EQ (left, Qunbound))
836 {
837 left_no_change = 1;
838 if (f->output_data.w32->left_pos < 0)
839 left = Fcons (Qplus, Fcons (make_number (f->output_data.w32->left_pos), Qnil));
840 else
841 XSETINT (left, f->output_data.w32->left_pos);
842 }
843 if (EQ (top, Qunbound))
844 {
845 top_no_change = 1;
846 if (f->output_data.w32->top_pos < 0)
847 top = Fcons (Qplus, Fcons (make_number (f->output_data.w32->top_pos), Qnil));
848 else
849 XSETINT (top, f->output_data.w32->top_pos);
850 }
851
852 /* If one of the icon positions was not set, preserve or default it. */
853 if (EQ (icon_left, Qunbound) || ! INTEGERP (icon_left))
854 {
855 icon_left_no_change = 1;
856 icon_left = Fcdr (Fassq (Qicon_left, f->param_alist));
857 if (NILP (icon_left))
858 XSETINT (icon_left, 0);
859 }
860 if (EQ (icon_top, Qunbound) || ! INTEGERP (icon_top))
861 {
862 icon_top_no_change = 1;
863 icon_top = Fcdr (Fassq (Qicon_top, f->param_alist));
864 if (NILP (icon_top))
865 XSETINT (icon_top, 0);
866 }
867
868 /* Don't set these parameters unless they've been explicitly
869 specified. The window might be mapped or resized while we're in
870 this function, and we don't want to override that unless the lisp
871 code has asked for it.
872
873 Don't set these parameters unless they actually differ from the
874 window's current parameters; the window may not actually exist
875 yet. */
876 {
877 Lisp_Object frame;
878
879 check_frame_size (f, &height, &width);
880
881 XSETFRAME (frame, f);
882
883 if (XINT (width) != FRAME_WIDTH (f)
884 || XINT (height) != FRAME_HEIGHT (f))
885 Fset_frame_size (frame, make_number (width), make_number (height));
886
887 if ((!NILP (left) || !NILP (top))
888 && ! (left_no_change && top_no_change)
889 && ! (NUMBERP (left) && XINT (left) == f->output_data.w32->left_pos
890 && NUMBERP (top) && XINT (top) == f->output_data.w32->top_pos))
891 {
892 int leftpos = 0;
893 int toppos = 0;
894
895 /* Record the signs. */
896 f->output_data.w32->size_hint_flags &= ~ (XNegative | YNegative);
897 if (EQ (left, Qminus))
898 f->output_data.w32->size_hint_flags |= XNegative;
899 else if (INTEGERP (left))
900 {
901 leftpos = XINT (left);
902 if (leftpos < 0)
903 f->output_data.w32->size_hint_flags |= XNegative;
904 }
905 else if (CONSP (left) && EQ (XCAR (left), Qminus)
906 && CONSP (XCDR (left))
907 && INTEGERP (XCAR (XCDR (left))))
908 {
909 leftpos = - XINT (XCAR (XCDR (left)));
910 f->output_data.w32->size_hint_flags |= XNegative;
911 }
912 else if (CONSP (left) && EQ (XCAR (left), Qplus)
913 && CONSP (XCDR (left))
914 && INTEGERP (XCAR (XCDR (left))))
915 {
916 leftpos = XINT (XCAR (XCDR (left)));
917 }
918
919 if (EQ (top, Qminus))
920 f->output_data.w32->size_hint_flags |= YNegative;
921 else if (INTEGERP (top))
922 {
923 toppos = XINT (top);
924 if (toppos < 0)
925 f->output_data.w32->size_hint_flags |= YNegative;
926 }
927 else if (CONSP (top) && EQ (XCAR (top), Qminus)
928 && CONSP (XCDR (top))
929 && INTEGERP (XCAR (XCDR (top))))
930 {
931 toppos = - XINT (XCAR (XCDR (top)));
932 f->output_data.w32->size_hint_flags |= YNegative;
933 }
934 else if (CONSP (top) && EQ (XCAR (top), Qplus)
935 && CONSP (XCDR (top))
936 && INTEGERP (XCAR (XCDR (top))))
937 {
938 toppos = XINT (XCAR (XCDR (top)));
939 }
940
941
942 /* Store the numeric value of the position. */
943 f->output_data.w32->top_pos = toppos;
944 f->output_data.w32->left_pos = leftpos;
945
946 f->output_data.w32->win_gravity = NorthWestGravity;
947
948 /* Actually set that position, and convert to absolute. */
949 x_set_offset (f, leftpos, toppos, -1);
950 }
951
952 if ((!NILP (icon_left) || !NILP (icon_top))
953 && ! (icon_left_no_change && icon_top_no_change))
954 x_wm_set_icon_position (f, XINT (icon_left), XINT (icon_top));
955 }
956
957 UNGCPRO;
958 }
959
960 /* Store the screen positions of frame F into XPTR and YPTR.
961 These are the positions of the containing window manager window,
962 not Emacs's own window. */
963
964 void
965 x_real_positions (f, xptr, yptr)
966 FRAME_PTR f;
967 int *xptr, *yptr;
968 {
969 POINT pt;
970
971 {
972 RECT rect;
973
974 GetClientRect(FRAME_W32_WINDOW(f), &rect);
975 AdjustWindowRect(&rect, f->output_data.w32->dwStyle, FRAME_EXTERNAL_MENU_BAR(f));
976
977 pt.x = rect.left;
978 pt.y = rect.top;
979 }
980
981 ClientToScreen (FRAME_W32_WINDOW(f), &pt);
982
983 *xptr = pt.x;
984 *yptr = pt.y;
985 }
986
987 /* Insert a description of internally-recorded parameters of frame X
988 into the parameter alist *ALISTPTR that is to be given to the user.
989 Only parameters that are specific to W32
990 and whose values are not correctly recorded in the frame's
991 param_alist need to be considered here. */
992
993 x_report_frame_params (f, alistptr)
994 struct frame *f;
995 Lisp_Object *alistptr;
996 {
997 char buf[16];
998 Lisp_Object tem;
999
1000 /* Represent negative positions (off the top or left screen edge)
1001 in a way that Fmodify_frame_parameters will understand correctly. */
1002 XSETINT (tem, f->output_data.w32->left_pos);
1003 if (f->output_data.w32->left_pos >= 0)
1004 store_in_alist (alistptr, Qleft, tem);
1005 else
1006 store_in_alist (alistptr, Qleft, Fcons (Qplus, Fcons (tem, Qnil)));
1007
1008 XSETINT (tem, f->output_data.w32->top_pos);
1009 if (f->output_data.w32->top_pos >= 0)
1010 store_in_alist (alistptr, Qtop, tem);
1011 else
1012 store_in_alist (alistptr, Qtop, Fcons (Qplus, Fcons (tem, Qnil)));
1013
1014 store_in_alist (alistptr, Qborder_width,
1015 make_number (f->output_data.w32->border_width));
1016 store_in_alist (alistptr, Qinternal_border_width,
1017 make_number (f->output_data.w32->internal_border_width));
1018 sprintf (buf, "%ld", (long) FRAME_W32_WINDOW (f));
1019 store_in_alist (alistptr, Qwindow_id,
1020 build_string (buf));
1021 store_in_alist (alistptr, Qicon_name, f->icon_name);
1022 FRAME_SAMPLE_VISIBILITY (f);
1023 store_in_alist (alistptr, Qvisibility,
1024 (FRAME_VISIBLE_P (f) ? Qt
1025 : FRAME_ICONIFIED_P (f) ? Qicon : Qnil));
1026 store_in_alist (alistptr, Qdisplay,
1027 XCAR (FRAME_W32_DISPLAY_INFO (f)->name_list_element));
1028 }
1029 \f
1030
1031 DEFUN ("w32-define-rgb-color", Fw32_define_rgb_color, Sw32_define_rgb_color, 4, 4, 0,
1032 "Convert RGB numbers to a windows color reference and associate with NAME (a string).\n\
1033 This adds or updates a named color to w32-color-map, making it available for use.\n\
1034 The original entry's RGB ref is returned, or nil if the entry is new.")
1035 (red, green, blue, name)
1036 Lisp_Object red, green, blue, name;
1037 {
1038 Lisp_Object rgb;
1039 Lisp_Object oldrgb = Qnil;
1040 Lisp_Object entry;
1041
1042 CHECK_NUMBER (red, 0);
1043 CHECK_NUMBER (green, 0);
1044 CHECK_NUMBER (blue, 0);
1045 CHECK_STRING (name, 0);
1046
1047 XSET (rgb, Lisp_Int, RGB(XUINT (red), XUINT (green), XUINT (blue)));
1048
1049 BLOCK_INPUT;
1050
1051 /* replace existing entry in w32-color-map or add new entry. */
1052 entry = Fassoc (name, Vw32_color_map);
1053 if (NILP (entry))
1054 {
1055 entry = Fcons (name, rgb);
1056 Vw32_color_map = Fcons (entry, Vw32_color_map);
1057 }
1058 else
1059 {
1060 oldrgb = Fcdr (entry);
1061 Fsetcdr (entry, rgb);
1062 }
1063
1064 UNBLOCK_INPUT;
1065
1066 return (oldrgb);
1067 }
1068
1069 DEFUN ("w32-load-color-file", Fw32_load_color_file, Sw32_load_color_file, 1, 1, 0,
1070 "Create an alist of color entries from an external file (ie. rgb.txt).\n\
1071 Assign this value to w32-color-map to replace the existing color map.\n\
1072 \
1073 The file should define one named RGB color per line like so:\
1074 R G B name\n\
1075 where R,G,B are numbers between 0 and 255 and name is an arbitrary string.")
1076 (filename)
1077 Lisp_Object filename;
1078 {
1079 FILE *fp;
1080 Lisp_Object cmap = Qnil;
1081 Lisp_Object abspath;
1082
1083 CHECK_STRING (filename, 0);
1084 abspath = Fexpand_file_name (filename, Qnil);
1085
1086 fp = fopen (XSTRING (filename)->data, "rt");
1087 if (fp)
1088 {
1089 char buf[512];
1090 int red, green, blue;
1091 int num;
1092
1093 BLOCK_INPUT;
1094
1095 while (fgets (buf, sizeof (buf), fp) != NULL) {
1096 if (sscanf (buf, "%u %u %u %n", &red, &green, &blue, &num) == 3)
1097 {
1098 char *name = buf + num;
1099 num = strlen (name) - 1;
1100 if (name[num] == '\n')
1101 name[num] = 0;
1102 cmap = Fcons (Fcons (build_string (name),
1103 make_number (RGB (red, green, blue))),
1104 cmap);
1105 }
1106 }
1107 fclose (fp);
1108
1109 UNBLOCK_INPUT;
1110 }
1111
1112 return cmap;
1113 }
1114
1115 /* The default colors for the w32 color map */
1116 typedef struct colormap_t
1117 {
1118 char *name;
1119 COLORREF colorref;
1120 } colormap_t;
1121
1122 colormap_t w32_color_map[] =
1123 {
1124 {"snow" , PALETTERGB (255,250,250)},
1125 {"ghost white" , PALETTERGB (248,248,255)},
1126 {"GhostWhite" , PALETTERGB (248,248,255)},
1127 {"white smoke" , PALETTERGB (245,245,245)},
1128 {"WhiteSmoke" , PALETTERGB (245,245,245)},
1129 {"gainsboro" , PALETTERGB (220,220,220)},
1130 {"floral white" , PALETTERGB (255,250,240)},
1131 {"FloralWhite" , PALETTERGB (255,250,240)},
1132 {"old lace" , PALETTERGB (253,245,230)},
1133 {"OldLace" , PALETTERGB (253,245,230)},
1134 {"linen" , PALETTERGB (250,240,230)},
1135 {"antique white" , PALETTERGB (250,235,215)},
1136 {"AntiqueWhite" , PALETTERGB (250,235,215)},
1137 {"papaya whip" , PALETTERGB (255,239,213)},
1138 {"PapayaWhip" , PALETTERGB (255,239,213)},
1139 {"blanched almond" , PALETTERGB (255,235,205)},
1140 {"BlanchedAlmond" , PALETTERGB (255,235,205)},
1141 {"bisque" , PALETTERGB (255,228,196)},
1142 {"peach puff" , PALETTERGB (255,218,185)},
1143 {"PeachPuff" , PALETTERGB (255,218,185)},
1144 {"navajo white" , PALETTERGB (255,222,173)},
1145 {"NavajoWhite" , PALETTERGB (255,222,173)},
1146 {"moccasin" , PALETTERGB (255,228,181)},
1147 {"cornsilk" , PALETTERGB (255,248,220)},
1148 {"ivory" , PALETTERGB (255,255,240)},
1149 {"lemon chiffon" , PALETTERGB (255,250,205)},
1150 {"LemonChiffon" , PALETTERGB (255,250,205)},
1151 {"seashell" , PALETTERGB (255,245,238)},
1152 {"honeydew" , PALETTERGB (240,255,240)},
1153 {"mint cream" , PALETTERGB (245,255,250)},
1154 {"MintCream" , PALETTERGB (245,255,250)},
1155 {"azure" , PALETTERGB (240,255,255)},
1156 {"alice blue" , PALETTERGB (240,248,255)},
1157 {"AliceBlue" , PALETTERGB (240,248,255)},
1158 {"lavender" , PALETTERGB (230,230,250)},
1159 {"lavender blush" , PALETTERGB (255,240,245)},
1160 {"LavenderBlush" , PALETTERGB (255,240,245)},
1161 {"misty rose" , PALETTERGB (255,228,225)},
1162 {"MistyRose" , PALETTERGB (255,228,225)},
1163 {"white" , PALETTERGB (255,255,255)},
1164 {"black" , PALETTERGB ( 0, 0, 0)},
1165 {"dark slate gray" , PALETTERGB ( 47, 79, 79)},
1166 {"DarkSlateGray" , PALETTERGB ( 47, 79, 79)},
1167 {"dark slate grey" , PALETTERGB ( 47, 79, 79)},
1168 {"DarkSlateGrey" , PALETTERGB ( 47, 79, 79)},
1169 {"dim gray" , PALETTERGB (105,105,105)},
1170 {"DimGray" , PALETTERGB (105,105,105)},
1171 {"dim grey" , PALETTERGB (105,105,105)},
1172 {"DimGrey" , PALETTERGB (105,105,105)},
1173 {"slate gray" , PALETTERGB (112,128,144)},
1174 {"SlateGray" , PALETTERGB (112,128,144)},
1175 {"slate grey" , PALETTERGB (112,128,144)},
1176 {"SlateGrey" , PALETTERGB (112,128,144)},
1177 {"light slate gray" , PALETTERGB (119,136,153)},
1178 {"LightSlateGray" , PALETTERGB (119,136,153)},
1179 {"light slate grey" , PALETTERGB (119,136,153)},
1180 {"LightSlateGrey" , PALETTERGB (119,136,153)},
1181 {"gray" , PALETTERGB (190,190,190)},
1182 {"grey" , PALETTERGB (190,190,190)},
1183 {"light grey" , PALETTERGB (211,211,211)},
1184 {"LightGrey" , PALETTERGB (211,211,211)},
1185 {"light gray" , PALETTERGB (211,211,211)},
1186 {"LightGray" , PALETTERGB (211,211,211)},
1187 {"midnight blue" , PALETTERGB ( 25, 25,112)},
1188 {"MidnightBlue" , PALETTERGB ( 25, 25,112)},
1189 {"navy" , PALETTERGB ( 0, 0,128)},
1190 {"navy blue" , PALETTERGB ( 0, 0,128)},
1191 {"NavyBlue" , PALETTERGB ( 0, 0,128)},
1192 {"cornflower blue" , PALETTERGB (100,149,237)},
1193 {"CornflowerBlue" , PALETTERGB (100,149,237)},
1194 {"dark slate blue" , PALETTERGB ( 72, 61,139)},
1195 {"DarkSlateBlue" , PALETTERGB ( 72, 61,139)},
1196 {"slate blue" , PALETTERGB (106, 90,205)},
1197 {"SlateBlue" , PALETTERGB (106, 90,205)},
1198 {"medium slate blue" , PALETTERGB (123,104,238)},
1199 {"MediumSlateBlue" , PALETTERGB (123,104,238)},
1200 {"light slate blue" , PALETTERGB (132,112,255)},
1201 {"LightSlateBlue" , PALETTERGB (132,112,255)},
1202 {"medium blue" , PALETTERGB ( 0, 0,205)},
1203 {"MediumBlue" , PALETTERGB ( 0, 0,205)},
1204 {"royal blue" , PALETTERGB ( 65,105,225)},
1205 {"RoyalBlue" , PALETTERGB ( 65,105,225)},
1206 {"blue" , PALETTERGB ( 0, 0,255)},
1207 {"dodger blue" , PALETTERGB ( 30,144,255)},
1208 {"DodgerBlue" , PALETTERGB ( 30,144,255)},
1209 {"deep sky blue" , PALETTERGB ( 0,191,255)},
1210 {"DeepSkyBlue" , PALETTERGB ( 0,191,255)},
1211 {"sky blue" , PALETTERGB (135,206,235)},
1212 {"SkyBlue" , PALETTERGB (135,206,235)},
1213 {"light sky blue" , PALETTERGB (135,206,250)},
1214 {"LightSkyBlue" , PALETTERGB (135,206,250)},
1215 {"steel blue" , PALETTERGB ( 70,130,180)},
1216 {"SteelBlue" , PALETTERGB ( 70,130,180)},
1217 {"light steel blue" , PALETTERGB (176,196,222)},
1218 {"LightSteelBlue" , PALETTERGB (176,196,222)},
1219 {"light blue" , PALETTERGB (173,216,230)},
1220 {"LightBlue" , PALETTERGB (173,216,230)},
1221 {"powder blue" , PALETTERGB (176,224,230)},
1222 {"PowderBlue" , PALETTERGB (176,224,230)},
1223 {"pale turquoise" , PALETTERGB (175,238,238)},
1224 {"PaleTurquoise" , PALETTERGB (175,238,238)},
1225 {"dark turquoise" , PALETTERGB ( 0,206,209)},
1226 {"DarkTurquoise" , PALETTERGB ( 0,206,209)},
1227 {"medium turquoise" , PALETTERGB ( 72,209,204)},
1228 {"MediumTurquoise" , PALETTERGB ( 72,209,204)},
1229 {"turquoise" , PALETTERGB ( 64,224,208)},
1230 {"cyan" , PALETTERGB ( 0,255,255)},
1231 {"light cyan" , PALETTERGB (224,255,255)},
1232 {"LightCyan" , PALETTERGB (224,255,255)},
1233 {"cadet blue" , PALETTERGB ( 95,158,160)},
1234 {"CadetBlue" , PALETTERGB ( 95,158,160)},
1235 {"medium aquamarine" , PALETTERGB (102,205,170)},
1236 {"MediumAquamarine" , PALETTERGB (102,205,170)},
1237 {"aquamarine" , PALETTERGB (127,255,212)},
1238 {"dark green" , PALETTERGB ( 0,100, 0)},
1239 {"DarkGreen" , PALETTERGB ( 0,100, 0)},
1240 {"dark olive green" , PALETTERGB ( 85,107, 47)},
1241 {"DarkOliveGreen" , PALETTERGB ( 85,107, 47)},
1242 {"dark sea green" , PALETTERGB (143,188,143)},
1243 {"DarkSeaGreen" , PALETTERGB (143,188,143)},
1244 {"sea green" , PALETTERGB ( 46,139, 87)},
1245 {"SeaGreen" , PALETTERGB ( 46,139, 87)},
1246 {"medium sea green" , PALETTERGB ( 60,179,113)},
1247 {"MediumSeaGreen" , PALETTERGB ( 60,179,113)},
1248 {"light sea green" , PALETTERGB ( 32,178,170)},
1249 {"LightSeaGreen" , PALETTERGB ( 32,178,170)},
1250 {"pale green" , PALETTERGB (152,251,152)},
1251 {"PaleGreen" , PALETTERGB (152,251,152)},
1252 {"spring green" , PALETTERGB ( 0,255,127)},
1253 {"SpringGreen" , PALETTERGB ( 0,255,127)},
1254 {"lawn green" , PALETTERGB (124,252, 0)},
1255 {"LawnGreen" , PALETTERGB (124,252, 0)},
1256 {"green" , PALETTERGB ( 0,255, 0)},
1257 {"chartreuse" , PALETTERGB (127,255, 0)},
1258 {"medium spring green" , PALETTERGB ( 0,250,154)},
1259 {"MediumSpringGreen" , PALETTERGB ( 0,250,154)},
1260 {"green yellow" , PALETTERGB (173,255, 47)},
1261 {"GreenYellow" , PALETTERGB (173,255, 47)},
1262 {"lime green" , PALETTERGB ( 50,205, 50)},
1263 {"LimeGreen" , PALETTERGB ( 50,205, 50)},
1264 {"yellow green" , PALETTERGB (154,205, 50)},
1265 {"YellowGreen" , PALETTERGB (154,205, 50)},
1266 {"forest green" , PALETTERGB ( 34,139, 34)},
1267 {"ForestGreen" , PALETTERGB ( 34,139, 34)},
1268 {"olive drab" , PALETTERGB (107,142, 35)},
1269 {"OliveDrab" , PALETTERGB (107,142, 35)},
1270 {"dark khaki" , PALETTERGB (189,183,107)},
1271 {"DarkKhaki" , PALETTERGB (189,183,107)},
1272 {"khaki" , PALETTERGB (240,230,140)},
1273 {"pale goldenrod" , PALETTERGB (238,232,170)},
1274 {"PaleGoldenrod" , PALETTERGB (238,232,170)},
1275 {"light goldenrod yellow" , PALETTERGB (250,250,210)},
1276 {"LightGoldenrodYellow" , PALETTERGB (250,250,210)},
1277 {"light yellow" , PALETTERGB (255,255,224)},
1278 {"LightYellow" , PALETTERGB (255,255,224)},
1279 {"yellow" , PALETTERGB (255,255, 0)},
1280 {"gold" , PALETTERGB (255,215, 0)},
1281 {"light goldenrod" , PALETTERGB (238,221,130)},
1282 {"LightGoldenrod" , PALETTERGB (238,221,130)},
1283 {"goldenrod" , PALETTERGB (218,165, 32)},
1284 {"dark goldenrod" , PALETTERGB (184,134, 11)},
1285 {"DarkGoldenrod" , PALETTERGB (184,134, 11)},
1286 {"rosy brown" , PALETTERGB (188,143,143)},
1287 {"RosyBrown" , PALETTERGB (188,143,143)},
1288 {"indian red" , PALETTERGB (205, 92, 92)},
1289 {"IndianRed" , PALETTERGB (205, 92, 92)},
1290 {"saddle brown" , PALETTERGB (139, 69, 19)},
1291 {"SaddleBrown" , PALETTERGB (139, 69, 19)},
1292 {"sienna" , PALETTERGB (160, 82, 45)},
1293 {"peru" , PALETTERGB (205,133, 63)},
1294 {"burlywood" , PALETTERGB (222,184,135)},
1295 {"beige" , PALETTERGB (245,245,220)},
1296 {"wheat" , PALETTERGB (245,222,179)},
1297 {"sandy brown" , PALETTERGB (244,164, 96)},
1298 {"SandyBrown" , PALETTERGB (244,164, 96)},
1299 {"tan" , PALETTERGB (210,180,140)},
1300 {"chocolate" , PALETTERGB (210,105, 30)},
1301 {"firebrick" , PALETTERGB (178,34, 34)},
1302 {"brown" , PALETTERGB (165,42, 42)},
1303 {"dark salmon" , PALETTERGB (233,150,122)},
1304 {"DarkSalmon" , PALETTERGB (233,150,122)},
1305 {"salmon" , PALETTERGB (250,128,114)},
1306 {"light salmon" , PALETTERGB (255,160,122)},
1307 {"LightSalmon" , PALETTERGB (255,160,122)},
1308 {"orange" , PALETTERGB (255,165, 0)},
1309 {"dark orange" , PALETTERGB (255,140, 0)},
1310 {"DarkOrange" , PALETTERGB (255,140, 0)},
1311 {"coral" , PALETTERGB (255,127, 80)},
1312 {"light coral" , PALETTERGB (240,128,128)},
1313 {"LightCoral" , PALETTERGB (240,128,128)},
1314 {"tomato" , PALETTERGB (255, 99, 71)},
1315 {"orange red" , PALETTERGB (255, 69, 0)},
1316 {"OrangeRed" , PALETTERGB (255, 69, 0)},
1317 {"red" , PALETTERGB (255, 0, 0)},
1318 {"hot pink" , PALETTERGB (255,105,180)},
1319 {"HotPink" , PALETTERGB (255,105,180)},
1320 {"deep pink" , PALETTERGB (255, 20,147)},
1321 {"DeepPink" , PALETTERGB (255, 20,147)},
1322 {"pink" , PALETTERGB (255,192,203)},
1323 {"light pink" , PALETTERGB (255,182,193)},
1324 {"LightPink" , PALETTERGB (255,182,193)},
1325 {"pale violet red" , PALETTERGB (219,112,147)},
1326 {"PaleVioletRed" , PALETTERGB (219,112,147)},
1327 {"maroon" , PALETTERGB (176, 48, 96)},
1328 {"medium violet red" , PALETTERGB (199, 21,133)},
1329 {"MediumVioletRed" , PALETTERGB (199, 21,133)},
1330 {"violet red" , PALETTERGB (208, 32,144)},
1331 {"VioletRed" , PALETTERGB (208, 32,144)},
1332 {"magenta" , PALETTERGB (255, 0,255)},
1333 {"violet" , PALETTERGB (238,130,238)},
1334 {"plum" , PALETTERGB (221,160,221)},
1335 {"orchid" , PALETTERGB (218,112,214)},
1336 {"medium orchid" , PALETTERGB (186, 85,211)},
1337 {"MediumOrchid" , PALETTERGB (186, 85,211)},
1338 {"dark orchid" , PALETTERGB (153, 50,204)},
1339 {"DarkOrchid" , PALETTERGB (153, 50,204)},
1340 {"dark violet" , PALETTERGB (148, 0,211)},
1341 {"DarkViolet" , PALETTERGB (148, 0,211)},
1342 {"blue violet" , PALETTERGB (138, 43,226)},
1343 {"BlueViolet" , PALETTERGB (138, 43,226)},
1344 {"purple" , PALETTERGB (160, 32,240)},
1345 {"medium purple" , PALETTERGB (147,112,219)},
1346 {"MediumPurple" , PALETTERGB (147,112,219)},
1347 {"thistle" , PALETTERGB (216,191,216)},
1348 {"gray0" , PALETTERGB ( 0, 0, 0)},
1349 {"grey0" , PALETTERGB ( 0, 0, 0)},
1350 {"dark grey" , PALETTERGB (169,169,169)},
1351 {"DarkGrey" , PALETTERGB (169,169,169)},
1352 {"dark gray" , PALETTERGB (169,169,169)},
1353 {"DarkGray" , PALETTERGB (169,169,169)},
1354 {"dark blue" , PALETTERGB ( 0, 0,139)},
1355 {"DarkBlue" , PALETTERGB ( 0, 0,139)},
1356 {"dark cyan" , PALETTERGB ( 0,139,139)},
1357 {"DarkCyan" , PALETTERGB ( 0,139,139)},
1358 {"dark magenta" , PALETTERGB (139, 0,139)},
1359 {"DarkMagenta" , PALETTERGB (139, 0,139)},
1360 {"dark red" , PALETTERGB (139, 0, 0)},
1361 {"DarkRed" , PALETTERGB (139, 0, 0)},
1362 {"light green" , PALETTERGB (144,238,144)},
1363 {"LightGreen" , PALETTERGB (144,238,144)},
1364 };
1365
1366 DEFUN ("w32-default-color-map", Fw32_default_color_map, Sw32_default_color_map,
1367 0, 0, 0, "Return the default color map.")
1368 ()
1369 {
1370 int i;
1371 colormap_t *pc = w32_color_map;
1372 Lisp_Object cmap;
1373
1374 BLOCK_INPUT;
1375
1376 cmap = Qnil;
1377
1378 for (i = 0; i < sizeof (w32_color_map) / sizeof (w32_color_map[0]);
1379 pc++, i++)
1380 cmap = Fcons (Fcons (build_string (pc->name),
1381 make_number (pc->colorref)),
1382 cmap);
1383
1384 UNBLOCK_INPUT;
1385
1386 return (cmap);
1387 }
1388
1389 Lisp_Object
1390 w32_to_x_color (rgb)
1391 Lisp_Object rgb;
1392 {
1393 Lisp_Object color;
1394
1395 CHECK_NUMBER (rgb, 0);
1396
1397 BLOCK_INPUT;
1398
1399 color = Frassq (rgb, Vw32_color_map);
1400
1401 UNBLOCK_INPUT;
1402
1403 if (!NILP (color))
1404 return (Fcar (color));
1405 else
1406 return Qnil;
1407 }
1408
1409 COLORREF
1410 w32_color_map_lookup (colorname)
1411 char *colorname;
1412 {
1413 Lisp_Object tail, ret = Qnil;
1414
1415 BLOCK_INPUT;
1416
1417 for (tail = Vw32_color_map; !NILP (tail); tail = Fcdr (tail))
1418 {
1419 register Lisp_Object elt, tem;
1420
1421 elt = Fcar (tail);
1422 if (!CONSP (elt)) continue;
1423
1424 tem = Fcar (elt);
1425
1426 if (lstrcmpi (XSTRING (tem)->data, colorname) == 0)
1427 {
1428 ret = XUINT (Fcdr (elt));
1429 break;
1430 }
1431
1432 QUIT;
1433 }
1434
1435
1436 UNBLOCK_INPUT;
1437
1438 return ret;
1439 }
1440
1441 COLORREF
1442 x_to_w32_color (colorname)
1443 char * colorname;
1444 {
1445 register Lisp_Object tail, ret = Qnil;
1446
1447 BLOCK_INPUT;
1448
1449 if (colorname[0] == '#')
1450 {
1451 /* Could be an old-style RGB Device specification. */
1452 char *color;
1453 int size;
1454 color = colorname + 1;
1455
1456 size = strlen(color);
1457 if (size == 3 || size == 6 || size == 9 || size == 12)
1458 {
1459 UINT colorval;
1460 int i, pos;
1461 pos = 0;
1462 size /= 3;
1463 colorval = 0;
1464
1465 for (i = 0; i < 3; i++)
1466 {
1467 char *end;
1468 char t;
1469 unsigned long value;
1470
1471 /* The check for 'x' in the following conditional takes into
1472 account the fact that strtol allows a "0x" in front of
1473 our numbers, and we don't. */
1474 if (!isxdigit(color[0]) || color[1] == 'x')
1475 break;
1476 t = color[size];
1477 color[size] = '\0';
1478 value = strtoul(color, &end, 16);
1479 color[size] = t;
1480 if (errno == ERANGE || end - color != size)
1481 break;
1482 switch (size)
1483 {
1484 case 1:
1485 value = value * 0x10;
1486 break;
1487 case 2:
1488 break;
1489 case 3:
1490 value /= 0x10;
1491 break;
1492 case 4:
1493 value /= 0x100;
1494 break;
1495 }
1496 colorval |= (value << pos);
1497 pos += 0x8;
1498 if (i == 2)
1499 {
1500 UNBLOCK_INPUT;
1501 return (colorval);
1502 }
1503 color = end;
1504 }
1505 }
1506 }
1507 else if (strnicmp(colorname, "rgb:", 4) == 0)
1508 {
1509 char *color;
1510 UINT colorval;
1511 int i, pos;
1512 pos = 0;
1513
1514 colorval = 0;
1515 color = colorname + 4;
1516 for (i = 0; i < 3; i++)
1517 {
1518 char *end;
1519 unsigned long value;
1520
1521 /* The check for 'x' in the following conditional takes into
1522 account the fact that strtol allows a "0x" in front of
1523 our numbers, and we don't. */
1524 if (!isxdigit(color[0]) || color[1] == 'x')
1525 break;
1526 value = strtoul(color, &end, 16);
1527 if (errno == ERANGE)
1528 break;
1529 switch (end - color)
1530 {
1531 case 1:
1532 value = value * 0x10 + value;
1533 break;
1534 case 2:
1535 break;
1536 case 3:
1537 value /= 0x10;
1538 break;
1539 case 4:
1540 value /= 0x100;
1541 break;
1542 default:
1543 value = ULONG_MAX;
1544 }
1545 if (value == ULONG_MAX)
1546 break;
1547 colorval |= (value << pos);
1548 pos += 0x8;
1549 if (i == 2)
1550 {
1551 if (*end != '\0')
1552 break;
1553 UNBLOCK_INPUT;
1554 return (colorval);
1555 }
1556 if (*end != '/')
1557 break;
1558 color = end + 1;
1559 }
1560 }
1561 else if (strnicmp(colorname, "rgbi:", 5) == 0)
1562 {
1563 /* This is an RGB Intensity specification. */
1564 char *color;
1565 UINT colorval;
1566 int i, pos;
1567 pos = 0;
1568
1569 colorval = 0;
1570 color = colorname + 5;
1571 for (i = 0; i < 3; i++)
1572 {
1573 char *end;
1574 double value;
1575 UINT val;
1576
1577 value = strtod(color, &end);
1578 if (errno == ERANGE)
1579 break;
1580 if (value < 0.0 || value > 1.0)
1581 break;
1582 val = (UINT)(0x100 * value);
1583 /* We used 0x100 instead of 0xFF to give an continuous
1584 range between 0.0 and 1.0 inclusive. The next statement
1585 fixes the 1.0 case. */
1586 if (val == 0x100)
1587 val = 0xFF;
1588 colorval |= (val << pos);
1589 pos += 0x8;
1590 if (i == 2)
1591 {
1592 if (*end != '\0')
1593 break;
1594 UNBLOCK_INPUT;
1595 return (colorval);
1596 }
1597 if (*end != '/')
1598 break;
1599 color = end + 1;
1600 }
1601 }
1602 /* I am not going to attempt to handle any of the CIE color schemes
1603 or TekHVC, since I don't know the algorithms for conversion to
1604 RGB. */
1605
1606 /* If we fail to lookup the color name in w32_color_map, then check the
1607 colorname to see if it can be crudely approximated: If the X color
1608 ends in a number (e.g., "darkseagreen2"), strip the number and
1609 return the result of looking up the base color name. */
1610 ret = w32_color_map_lookup (colorname);
1611 if (NILP (ret))
1612 {
1613 int len = strlen (colorname);
1614
1615 if (isdigit (colorname[len - 1]))
1616 {
1617 char *ptr, *approx = alloca (len);
1618
1619 strcpy (approx, colorname);
1620 ptr = &approx[len - 1];
1621 while (ptr > approx && isdigit (*ptr))
1622 *ptr-- = '\0';
1623
1624 ret = w32_color_map_lookup (approx);
1625 }
1626 }
1627
1628 UNBLOCK_INPUT;
1629 return ret;
1630 }
1631
1632
1633 void
1634 w32_regenerate_palette (FRAME_PTR f)
1635 {
1636 struct w32_palette_entry * list;
1637 LOGPALETTE * log_palette;
1638 HPALETTE new_palette;
1639 int i;
1640
1641 /* don't bother trying to create palette if not supported */
1642 if (! FRAME_W32_DISPLAY_INFO (f)->has_palette)
1643 return;
1644
1645 log_palette = (LOGPALETTE *)
1646 alloca (sizeof (LOGPALETTE) +
1647 FRAME_W32_DISPLAY_INFO (f)->num_colors * sizeof (PALETTEENTRY));
1648 log_palette->palVersion = 0x300;
1649 log_palette->palNumEntries = FRAME_W32_DISPLAY_INFO (f)->num_colors;
1650
1651 list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1652 for (i = 0;
1653 i < FRAME_W32_DISPLAY_INFO (f)->num_colors;
1654 i++, list = list->next)
1655 log_palette->palPalEntry[i] = list->entry;
1656
1657 new_palette = CreatePalette (log_palette);
1658
1659 enter_crit ();
1660
1661 if (FRAME_W32_DISPLAY_INFO (f)->palette)
1662 DeleteObject (FRAME_W32_DISPLAY_INFO (f)->palette);
1663 FRAME_W32_DISPLAY_INFO (f)->palette = new_palette;
1664
1665 /* Realize display palette and garbage all frames. */
1666 release_frame_dc (f, get_frame_dc (f));
1667
1668 leave_crit ();
1669 }
1670
1671 #define W32_COLOR(pe) RGB (pe.peRed, pe.peGreen, pe.peBlue)
1672 #define SET_W32_COLOR(pe, color) \
1673 do \
1674 { \
1675 pe.peRed = GetRValue (color); \
1676 pe.peGreen = GetGValue (color); \
1677 pe.peBlue = GetBValue (color); \
1678 pe.peFlags = 0; \
1679 } while (0)
1680
1681 #if 0
1682 /* Keep these around in case we ever want to track color usage. */
1683 void
1684 w32_map_color (FRAME_PTR f, COLORREF color)
1685 {
1686 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1687
1688 if (NILP (Vw32_enable_palette))
1689 return;
1690
1691 /* check if color is already mapped */
1692 while (list)
1693 {
1694 if (W32_COLOR (list->entry) == color)
1695 {
1696 ++list->refcount;
1697 return;
1698 }
1699 list = list->next;
1700 }
1701
1702 /* not already mapped, so add to list and recreate Windows palette */
1703 list = (struct w32_palette_entry *)
1704 xmalloc (sizeof (struct w32_palette_entry));
1705 SET_W32_COLOR (list->entry, color);
1706 list->refcount = 1;
1707 list->next = FRAME_W32_DISPLAY_INFO (f)->color_list;
1708 FRAME_W32_DISPLAY_INFO (f)->color_list = list;
1709 FRAME_W32_DISPLAY_INFO (f)->num_colors++;
1710
1711 /* set flag that palette must be regenerated */
1712 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
1713 }
1714
1715 void
1716 w32_unmap_color (FRAME_PTR f, COLORREF color)
1717 {
1718 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1719 struct w32_palette_entry **prev = &FRAME_W32_DISPLAY_INFO (f)->color_list;
1720
1721 if (NILP (Vw32_enable_palette))
1722 return;
1723
1724 /* check if color is already mapped */
1725 while (list)
1726 {
1727 if (W32_COLOR (list->entry) == color)
1728 {
1729 if (--list->refcount == 0)
1730 {
1731 *prev = list->next;
1732 xfree (list);
1733 FRAME_W32_DISPLAY_INFO (f)->num_colors--;
1734 break;
1735 }
1736 else
1737 return;
1738 }
1739 prev = &list->next;
1740 list = list->next;
1741 }
1742
1743 /* set flag that palette must be regenerated */
1744 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
1745 }
1746 #endif
1747
1748
1749 /* Gamma-correct COLOR on frame F. */
1750
1751 void
1752 gamma_correct (f, color)
1753 struct frame *f;
1754 COLORREF *color;
1755 {
1756 if (f->gamma)
1757 {
1758 *color = PALETTERGB (
1759 pow (GetRValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1760 pow (GetGValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1761 pow (GetBValue (*color) / 255.0, f->gamma) * 255.0 + 0.5);
1762 }
1763 }
1764
1765
1766 /* Decide if color named COLOR is valid for the display associated with
1767 the selected frame; if so, return the rgb values in COLOR_DEF.
1768 If ALLOC is nonzero, allocate a new colormap cell. */
1769
1770 int
1771 w32_defined_color (f, color, color_def, alloc)
1772 FRAME_PTR f;
1773 char *color;
1774 XColor *color_def;
1775 int alloc;
1776 {
1777 register Lisp_Object tem;
1778 COLORREF w32_color_ref;
1779
1780 tem = x_to_w32_color (color);
1781
1782 if (!NILP (tem))
1783 {
1784 /* Apply gamma correction. */
1785 w32_color_ref = XUINT (tem);
1786 gamma_correct (f, &w32_color_ref);
1787 XSETINT (tem, w32_color_ref);
1788
1789 /* Map this color to the palette if it is enabled. */
1790 if (!NILP (Vw32_enable_palette))
1791 {
1792 struct w32_palette_entry * entry =
1793 FRAME_W32_DISPLAY_INFO (f)->color_list;
1794 struct w32_palette_entry ** prev =
1795 &FRAME_W32_DISPLAY_INFO (f)->color_list;
1796
1797 /* check if color is already mapped */
1798 while (entry)
1799 {
1800 if (W32_COLOR (entry->entry) == XUINT (tem))
1801 break;
1802 prev = &entry->next;
1803 entry = entry->next;
1804 }
1805
1806 if (entry == NULL && alloc)
1807 {
1808 /* not already mapped, so add to list */
1809 entry = (struct w32_palette_entry *)
1810 xmalloc (sizeof (struct w32_palette_entry));
1811 SET_W32_COLOR (entry->entry, XUINT (tem));
1812 entry->next = NULL;
1813 *prev = entry;
1814 FRAME_W32_DISPLAY_INFO (f)->num_colors++;
1815
1816 /* set flag that palette must be regenerated */
1817 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
1818 }
1819 }
1820 /* Ensure COLORREF value is snapped to nearest color in (default)
1821 palette by simulating the PALETTERGB macro. This works whether
1822 or not the display device has a palette. */
1823 w32_color_ref = XUINT (tem) | 0x2000000;
1824
1825 color_def->pixel = w32_color_ref;
1826 color_def->red = GetRValue (w32_color_ref);
1827 color_def->green = GetGValue (w32_color_ref);
1828 color_def->blue = GetBValue (w32_color_ref);
1829
1830 return 1;
1831 }
1832 else
1833 {
1834 return 0;
1835 }
1836 }
1837
1838 /* Given a string ARG naming a color, compute a pixel value from it
1839 suitable for screen F.
1840 If F is not a color screen, return DEF (default) regardless of what
1841 ARG says. */
1842
1843 int
1844 x_decode_color (f, arg, def)
1845 FRAME_PTR f;
1846 Lisp_Object arg;
1847 int def;
1848 {
1849 XColor cdef;
1850
1851 CHECK_STRING (arg, 0);
1852
1853 if (strcmp (XSTRING (arg)->data, "black") == 0)
1854 return BLACK_PIX_DEFAULT (f);
1855 else if (strcmp (XSTRING (arg)->data, "white") == 0)
1856 return WHITE_PIX_DEFAULT (f);
1857
1858 if ((FRAME_W32_DISPLAY_INFO (f)->n_planes * FRAME_W32_DISPLAY_INFO (f)->n_cbits) == 1)
1859 return def;
1860
1861 /* w32_defined_color is responsible for coping with failures
1862 by looking for a near-miss. */
1863 if (w32_defined_color (f, XSTRING (arg)->data, &cdef, 1))
1864 return cdef.pixel;
1865
1866 /* defined_color failed; return an ultimate default. */
1867 return def;
1868 }
1869 \f
1870 /* Change the `screen-gamma' frame parameter of frame F. OLD_VALUE is
1871 the previous value of that parameter, NEW_VALUE is the new value. */
1872
1873 static void
1874 x_set_screen_gamma (f, new_value, old_value)
1875 struct frame *f;
1876 Lisp_Object new_value, old_value;
1877 {
1878 if (NILP (new_value))
1879 f->gamma = 0;
1880 else if (NUMBERP (new_value) && XFLOATINT (new_value) > 0)
1881 /* The value 0.4545 is the normal viewing gamma. */
1882 f->gamma = 1.0 / (0.4545 * XFLOATINT (new_value));
1883 else
1884 Fsignal (Qerror, Fcons (build_string ("Illegal screen-gamma"),
1885 Fcons (new_value, Qnil)));
1886
1887 clear_face_cache (0);
1888 }
1889
1890
1891 /* Functions called only from `x_set_frame_param'
1892 to set individual parameters.
1893
1894 If FRAME_W32_WINDOW (f) is 0,
1895 the frame is being created and its window does not exist yet.
1896 In that case, just record the parameter's new value
1897 in the standard place; do not attempt to change the window. */
1898
1899 void
1900 x_set_foreground_color (f, arg, oldval)
1901 struct frame *f;
1902 Lisp_Object arg, oldval;
1903 {
1904 FRAME_FOREGROUND_PIXEL (f)
1905 = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
1906
1907 if (FRAME_W32_WINDOW (f) != 0)
1908 {
1909 update_face_from_frame_parameter (f, Qforeground_color, arg);
1910 if (FRAME_VISIBLE_P (f))
1911 redraw_frame (f);
1912 }
1913 }
1914
1915 void
1916 x_set_background_color (f, arg, oldval)
1917 struct frame *f;
1918 Lisp_Object arg, oldval;
1919 {
1920 FRAME_BACKGROUND_PIXEL (f)
1921 = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
1922
1923 if (FRAME_W32_WINDOW (f) != 0)
1924 {
1925 SetWindowLong (FRAME_W32_WINDOW (f), WND_BACKGROUND_INDEX,
1926 FRAME_BACKGROUND_PIXEL (f));
1927
1928 update_face_from_frame_parameter (f, Qbackground_color, arg);
1929
1930 if (FRAME_VISIBLE_P (f))
1931 redraw_frame (f);
1932 }
1933 }
1934
1935 void
1936 x_set_mouse_color (f, arg, oldval)
1937 struct frame *f;
1938 Lisp_Object arg, oldval;
1939 {
1940
1941 Cursor cursor, nontext_cursor, mode_cursor, cross_cursor;
1942 int count;
1943 int mask_color;
1944
1945 if (!EQ (Qnil, arg))
1946 f->output_data.w32->mouse_pixel
1947 = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
1948 mask_color = FRAME_BACKGROUND_PIXEL (f);
1949
1950 /* Don't let pointers be invisible. */
1951 if (mask_color == f->output_data.w32->mouse_pixel
1952 && mask_color == FRAME_BACKGROUND_PIXEL (f))
1953 f->output_data.w32->mouse_pixel = FRAME_FOREGROUND_PIXEL (f);
1954
1955 #if 0 /* NTEMACS_TODO : cursor changes */
1956 BLOCK_INPUT;
1957
1958 /* It's not okay to crash if the user selects a screwy cursor. */
1959 count = x_catch_errors (FRAME_W32_DISPLAY (f));
1960
1961 if (!EQ (Qnil, Vx_pointer_shape))
1962 {
1963 CHECK_NUMBER (Vx_pointer_shape, 0);
1964 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XINT (Vx_pointer_shape));
1965 }
1966 else
1967 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
1968 x_check_errors (FRAME_W32_DISPLAY (f), "bad text pointer cursor: %s");
1969
1970 if (!EQ (Qnil, Vx_nontext_pointer_shape))
1971 {
1972 CHECK_NUMBER (Vx_nontext_pointer_shape, 0);
1973 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
1974 XINT (Vx_nontext_pointer_shape));
1975 }
1976 else
1977 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_left_ptr);
1978 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
1979
1980 if (!EQ (Qnil, Vx_busy_pointer_shape))
1981 {
1982 CHECK_NUMBER (Vx_busy_pointer_shape, 0);
1983 busy_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
1984 XINT (Vx_busy_pointer_shape));
1985 }
1986 else
1987 busy_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_watch);
1988 x_check_errors (FRAME_W32_DISPLAY (f), "bad busy pointer cursor: %s");
1989
1990 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
1991 if (!EQ (Qnil, Vx_mode_pointer_shape))
1992 {
1993 CHECK_NUMBER (Vx_mode_pointer_shape, 0);
1994 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
1995 XINT (Vx_mode_pointer_shape));
1996 }
1997 else
1998 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
1999 x_check_errors (FRAME_W32_DISPLAY (f), "bad modeline pointer cursor: %s");
2000
2001 if (!EQ (Qnil, Vx_sensitive_text_pointer_shape))
2002 {
2003 CHECK_NUMBER (Vx_sensitive_text_pointer_shape, 0);
2004 cross_cursor
2005 = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2006 XINT (Vx_sensitive_text_pointer_shape));
2007 }
2008 else
2009 cross_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_crosshair);
2010
2011 /* Check and report errors with the above calls. */
2012 x_check_errors (FRAME_W32_DISPLAY (f), "can't set cursor shape: %s");
2013 x_uncatch_errors (FRAME_W32_DISPLAY (f), count);
2014
2015 {
2016 XColor fore_color, back_color;
2017
2018 fore_color.pixel = f->output_data.w32->mouse_pixel;
2019 back_color.pixel = mask_color;
2020 XQueryColor (FRAME_W32_DISPLAY (f),
2021 DefaultColormap (FRAME_W32_DISPLAY (f),
2022 DefaultScreen (FRAME_W32_DISPLAY (f))),
2023 &fore_color);
2024 XQueryColor (FRAME_W32_DISPLAY (f),
2025 DefaultColormap (FRAME_W32_DISPLAY (f),
2026 DefaultScreen (FRAME_W32_DISPLAY (f))),
2027 &back_color);
2028 XRecolorCursor (FRAME_W32_DISPLAY (f), cursor,
2029 &fore_color, &back_color);
2030 XRecolorCursor (FRAME_W32_DISPLAY (f), nontext_cursor,
2031 &fore_color, &back_color);
2032 XRecolorCursor (FRAME_W32_DISPLAY (f), mode_cursor,
2033 &fore_color, &back_color);
2034 XRecolorCursor (FRAME_W32_DISPLAY (f), cross_cursor,
2035 &fore_color, &back_color);
2036 XRecolorCursor (FRAME_W32_DISPLAY (f), busy_cursor,
2037 &fore_color, &back_color);
2038 }
2039
2040 if (FRAME_W32_WINDOW (f) != 0)
2041 XDefineCursor (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), cursor);
2042
2043 if (cursor != f->output_data.w32->text_cursor && f->output_data.w32->text_cursor != 0)
2044 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->text_cursor);
2045 f->output_data.w32->text_cursor = cursor;
2046
2047 if (nontext_cursor != f->output_data.w32->nontext_cursor
2048 && f->output_data.w32->nontext_cursor != 0)
2049 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->nontext_cursor);
2050 f->output_data.w32->nontext_cursor = nontext_cursor;
2051
2052 if (busy_cursor != f->output_data.w32->busy_cursor
2053 && f->output_data.w32->busy_cursor != 0)
2054 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->busy_cursor);
2055 f->output_data.w32->busy_cursor = busy_cursor;
2056
2057 if (mode_cursor != f->output_data.w32->modeline_cursor
2058 && f->output_data.w32->modeline_cursor != 0)
2059 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->modeline_cursor);
2060 f->output_data.w32->modeline_cursor = mode_cursor;
2061
2062 if (cross_cursor != f->output_data.w32->cross_cursor
2063 && f->output_data.w32->cross_cursor != 0)
2064 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->cross_cursor);
2065 f->output_data.w32->cross_cursor = cross_cursor;
2066
2067 XFlush (FRAME_W32_DISPLAY (f));
2068 UNBLOCK_INPUT;
2069
2070 update_face_from_frame_parameter (f, Qmouse_color, arg);
2071 #endif /* NTEMACS_TODO */
2072 }
2073
2074 void
2075 x_set_cursor_color (f, arg, oldval)
2076 struct frame *f;
2077 Lisp_Object arg, oldval;
2078 {
2079 unsigned long fore_pixel;
2080
2081 if (!EQ (Vx_cursor_fore_pixel, Qnil))
2082 fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel,
2083 WHITE_PIX_DEFAULT (f));
2084 else
2085 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
2086 f->output_data.w32->cursor_pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2087
2088 /* Make sure that the cursor color differs from the background color. */
2089 if (f->output_data.w32->cursor_pixel == FRAME_BACKGROUND_PIXEL (f))
2090 {
2091 f->output_data.w32->cursor_pixel = f->output_data.w32->mouse_pixel;
2092 if (f->output_data.w32->cursor_pixel == fore_pixel)
2093 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
2094 }
2095 FRAME_FOREGROUND_PIXEL (f) = fore_pixel;
2096
2097 if (FRAME_W32_WINDOW (f) != 0)
2098 {
2099 if (FRAME_VISIBLE_P (f))
2100 {
2101 x_display_cursor (f, 0);
2102 x_display_cursor (f, 1);
2103 }
2104 }
2105
2106 update_face_from_frame_parameter (f, Qcursor_color, arg);
2107 }
2108
2109 /* Set the border-color of frame F to pixel value PIX.
2110 Note that this does not fully take effect if done before
2111 F has an window. */
2112 void
2113 x_set_border_pixel (f, pix)
2114 struct frame *f;
2115 int pix;
2116 {
2117 f->output_data.w32->border_pixel = pix;
2118
2119 if (FRAME_W32_WINDOW (f) != 0 && f->output_data.w32->border_width > 0)
2120 {
2121 if (FRAME_VISIBLE_P (f))
2122 redraw_frame (f);
2123 }
2124 }
2125
2126 /* Set the border-color of frame F to value described by ARG.
2127 ARG can be a string naming a color.
2128 The border-color is used for the border that is drawn by the server.
2129 Note that this does not fully take effect if done before
2130 F has a window; it must be redone when the window is created. */
2131
2132 void
2133 x_set_border_color (f, arg, oldval)
2134 struct frame *f;
2135 Lisp_Object arg, oldval;
2136 {
2137 int pix;
2138
2139 CHECK_STRING (arg, 0);
2140 pix = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2141 x_set_border_pixel (f, pix);
2142 update_face_from_frame_parameter (f, Qborder_color, arg);
2143 }
2144
2145 void
2146 x_set_cursor_type (f, arg, oldval)
2147 FRAME_PTR f;
2148 Lisp_Object arg, oldval;
2149 {
2150 if (EQ (arg, Qbar))
2151 {
2152 FRAME_DESIRED_CURSOR (f) = BAR_CURSOR;
2153 f->output_data.w32->cursor_width = 2;
2154 }
2155 else if (CONSP (arg) && EQ (XCAR (arg), Qbar)
2156 && INTEGERP (XCDR (arg)))
2157 {
2158 FRAME_DESIRED_CURSOR (f) = BAR_CURSOR;
2159 f->output_data.w32->cursor_width = XINT (XCDR (arg));
2160 }
2161 else
2162 /* Treat anything unknown as "box cursor".
2163 It was bad to signal an error; people have trouble fixing
2164 .Xdefaults with Emacs, when it has something bad in it. */
2165 FRAME_DESIRED_CURSOR (f) = FILLED_BOX_CURSOR;
2166
2167 /* Make sure the cursor gets redrawn. This is overkill, but how
2168 often do people change cursor types? */
2169 update_mode_lines++;
2170 }
2171
2172 void
2173 x_set_icon_type (f, arg, oldval)
2174 struct frame *f;
2175 Lisp_Object arg, oldval;
2176 {
2177 int result;
2178
2179 if (NILP (arg) && NILP (oldval))
2180 return;
2181
2182 if (STRINGP (arg) && STRINGP (oldval)
2183 && EQ (Fstring_equal (oldval, arg), Qt))
2184 return;
2185
2186 if (SYMBOLP (arg) && SYMBOLP (oldval) && EQ (arg, oldval))
2187 return;
2188
2189 BLOCK_INPUT;
2190
2191 result = x_bitmap_icon (f, arg);
2192 if (result)
2193 {
2194 UNBLOCK_INPUT;
2195 error ("No icon window available");
2196 }
2197
2198 UNBLOCK_INPUT;
2199 }
2200
2201 /* Return non-nil if frame F wants a bitmap icon. */
2202
2203 Lisp_Object
2204 x_icon_type (f)
2205 FRAME_PTR f;
2206 {
2207 Lisp_Object tem;
2208
2209 tem = assq_no_quit (Qicon_type, f->param_alist);
2210 if (CONSP (tem))
2211 return XCDR (tem);
2212 else
2213 return Qnil;
2214 }
2215
2216 void
2217 x_set_icon_name (f, arg, oldval)
2218 struct frame *f;
2219 Lisp_Object arg, oldval;
2220 {
2221 int result;
2222
2223 if (STRINGP (arg))
2224 {
2225 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
2226 return;
2227 }
2228 else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
2229 return;
2230
2231 f->icon_name = arg;
2232
2233 #if 0
2234 if (f->output_data.w32->icon_bitmap != 0)
2235 return;
2236
2237 BLOCK_INPUT;
2238
2239 result = x_text_icon (f,
2240 (char *) XSTRING ((!NILP (f->icon_name)
2241 ? f->icon_name
2242 : !NILP (f->title)
2243 ? f->title
2244 : f->name))->data);
2245
2246 if (result)
2247 {
2248 UNBLOCK_INPUT;
2249 error ("No icon window available");
2250 }
2251
2252 /* If the window was unmapped (and its icon was mapped),
2253 the new icon is not mapped, so map the window in its stead. */
2254 if (FRAME_VISIBLE_P (f))
2255 {
2256 #ifdef USE_X_TOOLKIT
2257 XtPopup (f->output_data.w32->widget, XtGrabNone);
2258 #endif
2259 XMapWindow (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f));
2260 }
2261
2262 XFlush (FRAME_W32_DISPLAY (f));
2263 UNBLOCK_INPUT;
2264 #endif
2265 }
2266
2267 extern Lisp_Object x_new_font ();
2268 extern Lisp_Object x_new_fontset();
2269
2270 void
2271 x_set_font (f, arg, oldval)
2272 struct frame *f;
2273 Lisp_Object arg, oldval;
2274 {
2275 Lisp_Object result;
2276 Lisp_Object fontset_name;
2277 Lisp_Object frame;
2278
2279 CHECK_STRING (arg, 1);
2280
2281 fontset_name = Fquery_fontset (arg, Qnil);
2282
2283 BLOCK_INPUT;
2284 result = (STRINGP (fontset_name)
2285 ? x_new_fontset (f, XSTRING (fontset_name)->data)
2286 : x_new_font (f, XSTRING (arg)->data));
2287 UNBLOCK_INPUT;
2288
2289 if (EQ (result, Qnil))
2290 error ("Font \"%s\" is not defined", XSTRING (arg)->data);
2291 else if (EQ (result, Qt))
2292 error ("the characters of the given font have varying widths");
2293 else if (STRINGP (result))
2294 {
2295 store_frame_param (f, Qfont, result);
2296 recompute_basic_faces (f);
2297 }
2298 else
2299 abort ();
2300
2301 do_pending_window_change (0);
2302
2303 /* Don't call `face-set-after-frame-default' when faces haven't been
2304 initialized yet. This is the case when called from
2305 Fx_create_frame. In that case, the X widget or window doesn't
2306 exist either, and we can end up in x_report_frame_params with a
2307 null widget which gives a segfault. */
2308 if (FRAME_FACE_CACHE (f))
2309 {
2310 XSETFRAME (frame, f);
2311 call1 (Qface_set_after_frame_default, frame);
2312 }
2313 }
2314
2315 void
2316 x_set_border_width (f, arg, oldval)
2317 struct frame *f;
2318 Lisp_Object arg, oldval;
2319 {
2320 CHECK_NUMBER (arg, 0);
2321
2322 if (XINT (arg) == f->output_data.w32->border_width)
2323 return;
2324
2325 if (FRAME_W32_WINDOW (f) != 0)
2326 error ("Cannot change the border width of a window");
2327
2328 f->output_data.w32->border_width = XINT (arg);
2329 }
2330
2331 void
2332 x_set_internal_border_width (f, arg, oldval)
2333 struct frame *f;
2334 Lisp_Object arg, oldval;
2335 {
2336 int old = f->output_data.w32->internal_border_width;
2337
2338 CHECK_NUMBER (arg, 0);
2339 f->output_data.w32->internal_border_width = XINT (arg);
2340 if (f->output_data.w32->internal_border_width < 0)
2341 f->output_data.w32->internal_border_width = 0;
2342
2343 if (f->output_data.w32->internal_border_width == old)
2344 return;
2345
2346 if (FRAME_W32_WINDOW (f) != 0)
2347 {
2348 x_set_window_size (f, 0, f->width, f->height);
2349 SET_FRAME_GARBAGED (f);
2350 do_pending_window_change (0);
2351 }
2352 }
2353
2354 void
2355 x_set_visibility (f, value, oldval)
2356 struct frame *f;
2357 Lisp_Object value, oldval;
2358 {
2359 Lisp_Object frame;
2360 XSETFRAME (frame, f);
2361
2362 if (NILP (value))
2363 Fmake_frame_invisible (frame, Qt);
2364 else if (EQ (value, Qicon))
2365 Ficonify_frame (frame);
2366 else
2367 Fmake_frame_visible (frame);
2368 }
2369
2370 void
2371 x_set_menu_bar_lines (f, value, oldval)
2372 struct frame *f;
2373 Lisp_Object value, oldval;
2374 {
2375 int nlines;
2376 int olines = FRAME_MENU_BAR_LINES (f);
2377
2378 /* Right now, menu bars don't work properly in minibuf-only frames;
2379 most of the commands try to apply themselves to the minibuffer
2380 frame itself, and get an error because you can't switch buffers
2381 in or split the minibuffer window. */
2382 if (FRAME_MINIBUF_ONLY_P (f))
2383 return;
2384
2385 if (INTEGERP (value))
2386 nlines = XINT (value);
2387 else
2388 nlines = 0;
2389
2390 FRAME_MENU_BAR_LINES (f) = 0;
2391 if (nlines)
2392 FRAME_EXTERNAL_MENU_BAR (f) = 1;
2393 else
2394 {
2395 if (FRAME_EXTERNAL_MENU_BAR (f) == 1)
2396 free_frame_menubar (f);
2397 FRAME_EXTERNAL_MENU_BAR (f) = 0;
2398
2399 /* Adjust the frame size so that the client (text) dimensions
2400 remain the same. This depends on FRAME_EXTERNAL_MENU_BAR being
2401 set correctly. */
2402 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2403 do_pending_window_change (0);
2404 }
2405 adjust_glyphs (f);
2406 }
2407
2408
2409 /* Set the number of lines used for the tool bar of frame F to VALUE.
2410 VALUE not an integer, or < 0 means set the lines to zero. OLDVAL
2411 is the old number of tool bar lines. This function changes the
2412 height of all windows on frame F to match the new tool bar height.
2413 The frame's height doesn't change. */
2414
2415 void
2416 x_set_tool_bar_lines (f, value, oldval)
2417 struct frame *f;
2418 Lisp_Object value, oldval;
2419 {
2420 int delta, nlines;
2421
2422 /* Use VALUE only if an integer >= 0. */
2423 if (INTEGERP (value) && XINT (value) >= 0)
2424 nlines = XFASTINT (value);
2425 else
2426 nlines = 0;
2427
2428 /* Make sure we redisplay all windows in this frame. */
2429 ++windows_or_buffers_changed;
2430
2431 delta = nlines - FRAME_TOOL_BAR_LINES (f);
2432 FRAME_TOOL_BAR_LINES (f) = nlines;
2433 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2434 do_pending_window_change (0);
2435 adjust_glyphs (f);
2436 }
2437
2438
2439 /* Change the name of frame F to NAME. If NAME is nil, set F's name to
2440 w32_id_name.
2441
2442 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2443 name; if NAME is a string, set F's name to NAME and set
2444 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2445
2446 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2447 suggesting a new name, which lisp code should override; if
2448 F->explicit_name is set, ignore the new name; otherwise, set it. */
2449
2450 void
2451 x_set_name (f, name, explicit)
2452 struct frame *f;
2453 Lisp_Object name;
2454 int explicit;
2455 {
2456 /* Make sure that requests from lisp code override requests from
2457 Emacs redisplay code. */
2458 if (explicit)
2459 {
2460 /* If we're switching from explicit to implicit, we had better
2461 update the mode lines and thereby update the title. */
2462 if (f->explicit_name && NILP (name))
2463 update_mode_lines = 1;
2464
2465 f->explicit_name = ! NILP (name);
2466 }
2467 else if (f->explicit_name)
2468 return;
2469
2470 /* If NAME is nil, set the name to the w32_id_name. */
2471 if (NILP (name))
2472 {
2473 /* Check for no change needed in this very common case
2474 before we do any consing. */
2475 if (!strcmp (FRAME_W32_DISPLAY_INFO (f)->w32_id_name,
2476 XSTRING (f->name)->data))
2477 return;
2478 name = build_string (FRAME_W32_DISPLAY_INFO (f)->w32_id_name);
2479 }
2480 else
2481 CHECK_STRING (name, 0);
2482
2483 /* Don't change the name if it's already NAME. */
2484 if (! NILP (Fstring_equal (name, f->name)))
2485 return;
2486
2487 f->name = name;
2488
2489 /* For setting the frame title, the title parameter should override
2490 the name parameter. */
2491 if (! NILP (f->title))
2492 name = f->title;
2493
2494 if (FRAME_W32_WINDOW (f))
2495 {
2496 if (STRING_MULTIBYTE (name))
2497 name = string_make_unibyte (name);
2498
2499 BLOCK_INPUT;
2500 SetWindowText(FRAME_W32_WINDOW (f), XSTRING (name)->data);
2501 UNBLOCK_INPUT;
2502 }
2503 }
2504
2505 /* This function should be called when the user's lisp code has
2506 specified a name for the frame; the name will override any set by the
2507 redisplay code. */
2508 void
2509 x_explicitly_set_name (f, arg, oldval)
2510 FRAME_PTR f;
2511 Lisp_Object arg, oldval;
2512 {
2513 x_set_name (f, arg, 1);
2514 }
2515
2516 /* This function should be called by Emacs redisplay code to set the
2517 name; names set this way will never override names set by the user's
2518 lisp code. */
2519 void
2520 x_implicitly_set_name (f, arg, oldval)
2521 FRAME_PTR f;
2522 Lisp_Object arg, oldval;
2523 {
2524 x_set_name (f, arg, 0);
2525 }
2526 \f
2527 /* Change the title of frame F to NAME.
2528 If NAME is nil, use the frame name as the title.
2529
2530 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2531 name; if NAME is a string, set F's name to NAME and set
2532 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2533
2534 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2535 suggesting a new name, which lisp code should override; if
2536 F->explicit_name is set, ignore the new name; otherwise, set it. */
2537
2538 void
2539 x_set_title (f, name, old_name)
2540 struct frame *f;
2541 Lisp_Object name, old_name;
2542 {
2543 /* Don't change the title if it's already NAME. */
2544 if (EQ (name, f->title))
2545 return;
2546
2547 update_mode_lines = 1;
2548
2549 f->title = name;
2550
2551 if (NILP (name))
2552 name = f->name;
2553
2554 if (FRAME_W32_WINDOW (f))
2555 {
2556 if (STRING_MULTIBYTE (name))
2557 name = string_make_unibyte (name);
2558
2559 BLOCK_INPUT;
2560 SetWindowText(FRAME_W32_WINDOW (f), XSTRING (name)->data);
2561 UNBLOCK_INPUT;
2562 }
2563 }
2564 \f
2565 void
2566 x_set_autoraise (f, arg, oldval)
2567 struct frame *f;
2568 Lisp_Object arg, oldval;
2569 {
2570 f->auto_raise = !EQ (Qnil, arg);
2571 }
2572
2573 void
2574 x_set_autolower (f, arg, oldval)
2575 struct frame *f;
2576 Lisp_Object arg, oldval;
2577 {
2578 f->auto_lower = !EQ (Qnil, arg);
2579 }
2580
2581 void
2582 x_set_unsplittable (f, arg, oldval)
2583 struct frame *f;
2584 Lisp_Object arg, oldval;
2585 {
2586 f->no_split = !NILP (arg);
2587 }
2588
2589 void
2590 x_set_vertical_scroll_bars (f, arg, oldval)
2591 struct frame *f;
2592 Lisp_Object arg, oldval;
2593 {
2594 if ((EQ (arg, Qleft) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
2595 || (EQ (arg, Qright) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
2596 || (NILP (arg) && FRAME_HAS_VERTICAL_SCROLL_BARS (f))
2597 || (!NILP (arg) && ! FRAME_HAS_VERTICAL_SCROLL_BARS (f)))
2598 {
2599 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = NILP (arg) ?
2600 vertical_scroll_bar_none :
2601 /* Put scroll bars on the right by default, as is conventional
2602 on MS-Windows. */
2603 EQ (Qleft, arg)
2604 ? vertical_scroll_bar_left
2605 : vertical_scroll_bar_right;
2606
2607 /* We set this parameter before creating the window for the
2608 frame, so we can get the geometry right from the start.
2609 However, if the window hasn't been created yet, we shouldn't
2610 call x_set_window_size. */
2611 if (FRAME_W32_WINDOW (f))
2612 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2613 do_pending_window_change (0);
2614 }
2615 }
2616
2617 void
2618 x_set_scroll_bar_width (f, arg, oldval)
2619 struct frame *f;
2620 Lisp_Object arg, oldval;
2621 {
2622 int wid = FONT_WIDTH (f->output_data.w32->font);
2623
2624 if (NILP (arg))
2625 {
2626 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = GetSystemMetrics (SM_CXVSCROLL);
2627 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) +
2628 wid - 1) / wid;
2629 if (FRAME_W32_WINDOW (f))
2630 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2631 do_pending_window_change (0);
2632 }
2633 else if (INTEGERP (arg) && XINT (arg) > 0
2634 && XFASTINT (arg) != FRAME_SCROLL_BAR_PIXEL_WIDTH (f))
2635 {
2636 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = XFASTINT (arg);
2637 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
2638 + wid-1) / wid;
2639 if (FRAME_W32_WINDOW (f))
2640 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2641 do_pending_window_change (0);
2642 }
2643 change_frame_size (f, 0, FRAME_WIDTH (f), 0, 0, 0);
2644 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.hpos = 0;
2645 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.x = 0;
2646 }
2647 \f
2648 /* Subroutines of creating an frame. */
2649
2650 /* Make sure that Vx_resource_name is set to a reasonable value.
2651 Fix it up, or set it to `emacs' if it is too hopeless. */
2652
2653 static void
2654 validate_x_resource_name ()
2655 {
2656 int len = 0;
2657 /* Number of valid characters in the resource name. */
2658 int good_count = 0;
2659 /* Number of invalid characters in the resource name. */
2660 int bad_count = 0;
2661 Lisp_Object new;
2662 int i;
2663
2664 if (STRINGP (Vx_resource_name))
2665 {
2666 unsigned char *p = XSTRING (Vx_resource_name)->data;
2667 int i;
2668
2669 len = XSTRING (Vx_resource_name)->size;
2670
2671 /* Only letters, digits, - and _ are valid in resource names.
2672 Count the valid characters and count the invalid ones. */
2673 for (i = 0; i < len; i++)
2674 {
2675 int c = p[i];
2676 if (! ((c >= 'a' && c <= 'z')
2677 || (c >= 'A' && c <= 'Z')
2678 || (c >= '0' && c <= '9')
2679 || c == '-' || c == '_'))
2680 bad_count++;
2681 else
2682 good_count++;
2683 }
2684 }
2685 else
2686 /* Not a string => completely invalid. */
2687 bad_count = 5, good_count = 0;
2688
2689 /* If name is valid already, return. */
2690 if (bad_count == 0)
2691 return;
2692
2693 /* If name is entirely invalid, or nearly so, use `emacs'. */
2694 if (good_count == 0
2695 || (good_count == 1 && bad_count > 0))
2696 {
2697 Vx_resource_name = build_string ("emacs");
2698 return;
2699 }
2700
2701 /* Name is partly valid. Copy it and replace the invalid characters
2702 with underscores. */
2703
2704 Vx_resource_name = new = Fcopy_sequence (Vx_resource_name);
2705
2706 for (i = 0; i < len; i++)
2707 {
2708 int c = XSTRING (new)->data[i];
2709 if (! ((c >= 'a' && c <= 'z')
2710 || (c >= 'A' && c <= 'Z')
2711 || (c >= '0' && c <= '9')
2712 || c == '-' || c == '_'))
2713 XSTRING (new)->data[i] = '_';
2714 }
2715 }
2716
2717
2718 extern char *x_get_string_resource ();
2719
2720 DEFUN ("x-get-resource", Fx_get_resource, Sx_get_resource, 2, 4, 0,
2721 "Return the value of ATTRIBUTE, of class CLASS, from the X defaults database.\n\
2722 This uses `INSTANCE.ATTRIBUTE' as the key and `Emacs.CLASS' as the\n\
2723 class, where INSTANCE is the name under which Emacs was invoked, or\n\
2724 the name specified by the `-name' or `-rn' command-line arguments.\n\
2725 \n\
2726 The optional arguments COMPONENT and SUBCLASS add to the key and the\n\
2727 class, respectively. You must specify both of them or neither.\n\
2728 If you specify them, the key is `INSTANCE.COMPONENT.ATTRIBUTE'\n\
2729 and the class is `Emacs.CLASS.SUBCLASS'.")
2730 (attribute, class, component, subclass)
2731 Lisp_Object attribute, class, component, subclass;
2732 {
2733 register char *value;
2734 char *name_key;
2735 char *class_key;
2736
2737 CHECK_STRING (attribute, 0);
2738 CHECK_STRING (class, 0);
2739
2740 if (!NILP (component))
2741 CHECK_STRING (component, 1);
2742 if (!NILP (subclass))
2743 CHECK_STRING (subclass, 2);
2744 if (NILP (component) != NILP (subclass))
2745 error ("x-get-resource: must specify both COMPONENT and SUBCLASS or neither");
2746
2747 validate_x_resource_name ();
2748
2749 /* Allocate space for the components, the dots which separate them,
2750 and the final '\0'. Make them big enough for the worst case. */
2751 name_key = (char *) alloca (XSTRING (Vx_resource_name)->size
2752 + (STRINGP (component)
2753 ? XSTRING (component)->size : 0)
2754 + XSTRING (attribute)->size
2755 + 3);
2756
2757 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
2758 + XSTRING (class)->size
2759 + (STRINGP (subclass)
2760 ? XSTRING (subclass)->size : 0)
2761 + 3);
2762
2763 /* Start with emacs.FRAMENAME for the name (the specific one)
2764 and with `Emacs' for the class key (the general one). */
2765 strcpy (name_key, XSTRING (Vx_resource_name)->data);
2766 strcpy (class_key, EMACS_CLASS);
2767
2768 strcat (class_key, ".");
2769 strcat (class_key, XSTRING (class)->data);
2770
2771 if (!NILP (component))
2772 {
2773 strcat (class_key, ".");
2774 strcat (class_key, XSTRING (subclass)->data);
2775
2776 strcat (name_key, ".");
2777 strcat (name_key, XSTRING (component)->data);
2778 }
2779
2780 strcat (name_key, ".");
2781 strcat (name_key, XSTRING (attribute)->data);
2782
2783 value = x_get_string_resource (Qnil,
2784 name_key, class_key);
2785
2786 if (value != (char *) 0)
2787 return build_string (value);
2788 else
2789 return Qnil;
2790 }
2791
2792 /* Used when C code wants a resource value. */
2793
2794 char *
2795 x_get_resource_string (attribute, class)
2796 char *attribute, *class;
2797 {
2798 char *name_key;
2799 char *class_key;
2800 struct frame *sf = SELECTED_FRAME ();
2801
2802 /* Allocate space for the components, the dots which separate them,
2803 and the final '\0'. */
2804 name_key = (char *) alloca (XSTRING (Vinvocation_name)->size
2805 + strlen (attribute) + 2);
2806 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
2807 + strlen (class) + 2);
2808
2809 sprintf (name_key, "%s.%s",
2810 XSTRING (Vinvocation_name)->data,
2811 attribute);
2812 sprintf (class_key, "%s.%s", EMACS_CLASS, class);
2813
2814 return x_get_string_resource (sf, name_key, class_key);
2815 }
2816
2817 /* Types we might convert a resource string into. */
2818 enum resource_types
2819 {
2820 RES_TYPE_NUMBER,
2821 RES_TYPE_FLOAT,
2822 RES_TYPE_BOOLEAN,
2823 RES_TYPE_STRING,
2824 RES_TYPE_SYMBOL
2825 };
2826
2827 /* Return the value of parameter PARAM.
2828
2829 First search ALIST, then Vdefault_frame_alist, then the X defaults
2830 database, using ATTRIBUTE as the attribute name and CLASS as its class.
2831
2832 Convert the resource to the type specified by desired_type.
2833
2834 If no default is specified, return Qunbound. If you call
2835 w32_get_arg, make sure you deal with Qunbound in a reasonable way,
2836 and don't let it get stored in any Lisp-visible variables! */
2837
2838 static Lisp_Object
2839 w32_get_arg (alist, param, attribute, class, type)
2840 Lisp_Object alist, param;
2841 char *attribute;
2842 char *class;
2843 enum resource_types type;
2844 {
2845 register Lisp_Object tem;
2846
2847 tem = Fassq (param, alist);
2848 if (EQ (tem, Qnil))
2849 tem = Fassq (param, Vdefault_frame_alist);
2850 if (EQ (tem, Qnil))
2851 {
2852
2853 if (attribute)
2854 {
2855 tem = Fx_get_resource (build_string (attribute),
2856 build_string (class),
2857 Qnil, Qnil);
2858
2859 if (NILP (tem))
2860 return Qunbound;
2861
2862 switch (type)
2863 {
2864 case RES_TYPE_NUMBER:
2865 return make_number (atoi (XSTRING (tem)->data));
2866
2867 case RES_TYPE_FLOAT:
2868 return make_float (atof (XSTRING (tem)->data));
2869
2870 case RES_TYPE_BOOLEAN:
2871 tem = Fdowncase (tem);
2872 if (!strcmp (XSTRING (tem)->data, "on")
2873 || !strcmp (XSTRING (tem)->data, "true"))
2874 return Qt;
2875 else
2876 return Qnil;
2877
2878 case RES_TYPE_STRING:
2879 return tem;
2880
2881 case RES_TYPE_SYMBOL:
2882 /* As a special case, we map the values `true' and `on'
2883 to Qt, and `false' and `off' to Qnil. */
2884 {
2885 Lisp_Object lower;
2886 lower = Fdowncase (tem);
2887 if (!strcmp (XSTRING (lower)->data, "on")
2888 || !strcmp (XSTRING (lower)->data, "true"))
2889 return Qt;
2890 else if (!strcmp (XSTRING (lower)->data, "off")
2891 || !strcmp (XSTRING (lower)->data, "false"))
2892 return Qnil;
2893 else
2894 return Fintern (tem, Qnil);
2895 }
2896
2897 default:
2898 abort ();
2899 }
2900 }
2901 else
2902 return Qunbound;
2903 }
2904 return Fcdr (tem);
2905 }
2906
2907 /* Record in frame F the specified or default value according to ALIST
2908 of the parameter named PARAM (a Lisp symbol).
2909 If no value is specified for PARAM, look for an X default for XPROP
2910 on the frame named NAME.
2911 If that is not found either, use the value DEFLT. */
2912
2913 static Lisp_Object
2914 x_default_parameter (f, alist, prop, deflt, xprop, xclass, type)
2915 struct frame *f;
2916 Lisp_Object alist;
2917 Lisp_Object prop;
2918 Lisp_Object deflt;
2919 char *xprop;
2920 char *xclass;
2921 enum resource_types type;
2922 {
2923 Lisp_Object tem;
2924
2925 tem = w32_get_arg (alist, prop, xprop, xclass, type);
2926 if (EQ (tem, Qunbound))
2927 tem = deflt;
2928 x_set_frame_parameters (f, Fcons (Fcons (prop, tem), Qnil));
2929 return tem;
2930 }
2931 \f
2932 DEFUN ("x-parse-geometry", Fx_parse_geometry, Sx_parse_geometry, 1, 1, 0,
2933 "Parse an X-style geometry string STRING.\n\
2934 Returns an alist of the form ((top . TOP), (left . LEFT) ... ).\n\
2935 The properties returned may include `top', `left', `height', and `width'.\n\
2936 The value of `left' or `top' may be an integer,\n\
2937 or a list (+ N) meaning N pixels relative to top/left corner,\n\
2938 or a list (- N) meaning -N pixels relative to bottom/right corner.")
2939 (string)
2940 Lisp_Object string;
2941 {
2942 int geometry, x, y;
2943 unsigned int width, height;
2944 Lisp_Object result;
2945
2946 CHECK_STRING (string, 0);
2947
2948 geometry = XParseGeometry ((char *) XSTRING (string)->data,
2949 &x, &y, &width, &height);
2950
2951 result = Qnil;
2952 if (geometry & XValue)
2953 {
2954 Lisp_Object element;
2955
2956 if (x >= 0 && (geometry & XNegative))
2957 element = Fcons (Qleft, Fcons (Qminus, Fcons (make_number (-x), Qnil)));
2958 else if (x < 0 && ! (geometry & XNegative))
2959 element = Fcons (Qleft, Fcons (Qplus, Fcons (make_number (x), Qnil)));
2960 else
2961 element = Fcons (Qleft, make_number (x));
2962 result = Fcons (element, result);
2963 }
2964
2965 if (geometry & YValue)
2966 {
2967 Lisp_Object element;
2968
2969 if (y >= 0 && (geometry & YNegative))
2970 element = Fcons (Qtop, Fcons (Qminus, Fcons (make_number (-y), Qnil)));
2971 else if (y < 0 && ! (geometry & YNegative))
2972 element = Fcons (Qtop, Fcons (Qplus, Fcons (make_number (y), Qnil)));
2973 else
2974 element = Fcons (Qtop, make_number (y));
2975 result = Fcons (element, result);
2976 }
2977
2978 if (geometry & WidthValue)
2979 result = Fcons (Fcons (Qwidth, make_number (width)), result);
2980 if (geometry & HeightValue)
2981 result = Fcons (Fcons (Qheight, make_number (height)), result);
2982
2983 return result;
2984 }
2985
2986 /* Calculate the desired size and position of this window,
2987 and return the flags saying which aspects were specified.
2988
2989 This function does not make the coordinates positive. */
2990
2991 #define DEFAULT_ROWS 40
2992 #define DEFAULT_COLS 80
2993
2994 static int
2995 x_figure_window_size (f, parms)
2996 struct frame *f;
2997 Lisp_Object parms;
2998 {
2999 register Lisp_Object tem0, tem1, tem2;
3000 long window_prompting = 0;
3001
3002 /* Default values if we fall through.
3003 Actually, if that happens we should get
3004 window manager prompting. */
3005 SET_FRAME_WIDTH (f, DEFAULT_COLS);
3006 f->height = DEFAULT_ROWS;
3007 /* Window managers expect that if program-specified
3008 positions are not (0,0), they're intentional, not defaults. */
3009 f->output_data.w32->top_pos = 0;
3010 f->output_data.w32->left_pos = 0;
3011
3012 tem0 = w32_get_arg (parms, Qheight, 0, 0, RES_TYPE_NUMBER);
3013 tem1 = w32_get_arg (parms, Qwidth, 0, 0, RES_TYPE_NUMBER);
3014 tem2 = w32_get_arg (parms, Quser_size, 0, 0, RES_TYPE_NUMBER);
3015 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3016 {
3017 if (!EQ (tem0, Qunbound))
3018 {
3019 CHECK_NUMBER (tem0, 0);
3020 f->height = XINT (tem0);
3021 }
3022 if (!EQ (tem1, Qunbound))
3023 {
3024 CHECK_NUMBER (tem1, 0);
3025 SET_FRAME_WIDTH (f, XINT (tem1));
3026 }
3027 if (!NILP (tem2) && !EQ (tem2, Qunbound))
3028 window_prompting |= USSize;
3029 else
3030 window_prompting |= PSize;
3031 }
3032
3033 f->output_data.w32->vertical_scroll_bar_extra
3034 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
3035 ? 0
3036 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
3037 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
3038 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.w32->font)));
3039 f->output_data.w32->flags_areas_extra
3040 = FRAME_FLAGS_AREA_WIDTH (f);
3041 f->output_data.w32->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
3042 f->output_data.w32->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
3043
3044 tem0 = w32_get_arg (parms, Qtop, 0, 0, RES_TYPE_NUMBER);
3045 tem1 = w32_get_arg (parms, Qleft, 0, 0, RES_TYPE_NUMBER);
3046 tem2 = w32_get_arg (parms, Quser_position, 0, 0, RES_TYPE_NUMBER);
3047 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3048 {
3049 if (EQ (tem0, Qminus))
3050 {
3051 f->output_data.w32->top_pos = 0;
3052 window_prompting |= YNegative;
3053 }
3054 else if (CONSP (tem0) && EQ (XCAR (tem0), Qminus)
3055 && CONSP (XCDR (tem0))
3056 && INTEGERP (XCAR (XCDR (tem0))))
3057 {
3058 f->output_data.w32->top_pos = - XINT (XCAR (XCDR (tem0)));
3059 window_prompting |= YNegative;
3060 }
3061 else if (CONSP (tem0) && EQ (XCAR (tem0), Qplus)
3062 && CONSP (XCDR (tem0))
3063 && INTEGERP (XCAR (XCDR (tem0))))
3064 {
3065 f->output_data.w32->top_pos = XINT (XCAR (XCDR (tem0)));
3066 }
3067 else if (EQ (tem0, Qunbound))
3068 f->output_data.w32->top_pos = 0;
3069 else
3070 {
3071 CHECK_NUMBER (tem0, 0);
3072 f->output_data.w32->top_pos = XINT (tem0);
3073 if (f->output_data.w32->top_pos < 0)
3074 window_prompting |= YNegative;
3075 }
3076
3077 if (EQ (tem1, Qminus))
3078 {
3079 f->output_data.w32->left_pos = 0;
3080 window_prompting |= XNegative;
3081 }
3082 else if (CONSP (tem1) && EQ (XCAR (tem1), Qminus)
3083 && CONSP (XCDR (tem1))
3084 && INTEGERP (XCAR (XCDR (tem1))))
3085 {
3086 f->output_data.w32->left_pos = - XINT (XCAR (XCDR (tem1)));
3087 window_prompting |= XNegative;
3088 }
3089 else if (CONSP (tem1) && EQ (XCAR (tem1), Qplus)
3090 && CONSP (XCDR (tem1))
3091 && INTEGERP (XCAR (XCDR (tem1))))
3092 {
3093 f->output_data.w32->left_pos = XINT (XCAR (XCDR (tem1)));
3094 }
3095 else if (EQ (tem1, Qunbound))
3096 f->output_data.w32->left_pos = 0;
3097 else
3098 {
3099 CHECK_NUMBER (tem1, 0);
3100 f->output_data.w32->left_pos = XINT (tem1);
3101 if (f->output_data.w32->left_pos < 0)
3102 window_prompting |= XNegative;
3103 }
3104
3105 if (!NILP (tem2) && ! EQ (tem2, Qunbound))
3106 window_prompting |= USPosition;
3107 else
3108 window_prompting |= PPosition;
3109 }
3110
3111 return window_prompting;
3112 }
3113
3114 \f
3115
3116 extern LRESULT CALLBACK w32_wnd_proc ();
3117
3118 BOOL
3119 w32_init_class (hinst)
3120 HINSTANCE hinst;
3121 {
3122 WNDCLASS wc;
3123
3124 wc.style = CS_HREDRAW | CS_VREDRAW;
3125 wc.lpfnWndProc = (WNDPROC) w32_wnd_proc;
3126 wc.cbClsExtra = 0;
3127 wc.cbWndExtra = WND_EXTRA_BYTES;
3128 wc.hInstance = hinst;
3129 wc.hIcon = LoadIcon (hinst, EMACS_CLASS);
3130 wc.hCursor = LoadCursor (NULL, IDC_ARROW);
3131 wc.hbrBackground = NULL; /* GetStockObject (WHITE_BRUSH); */
3132 wc.lpszMenuName = NULL;
3133 wc.lpszClassName = EMACS_CLASS;
3134
3135 return (RegisterClass (&wc));
3136 }
3137
3138 HWND
3139 w32_createscrollbar (f, bar)
3140 struct frame *f;
3141 struct scroll_bar * bar;
3142 {
3143 return (CreateWindow ("SCROLLBAR", "", SBS_VERT | WS_CHILD | WS_VISIBLE,
3144 /* Position and size of scroll bar. */
3145 XINT(bar->left) + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
3146 XINT(bar->top),
3147 XINT(bar->width) - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
3148 XINT(bar->height),
3149 FRAME_W32_WINDOW (f),
3150 NULL,
3151 hinst,
3152 NULL));
3153 }
3154
3155 void
3156 w32_createwindow (f)
3157 struct frame *f;
3158 {
3159 HWND hwnd;
3160 RECT rect;
3161
3162 rect.left = rect.top = 0;
3163 rect.right = PIXEL_WIDTH (f);
3164 rect.bottom = PIXEL_HEIGHT (f);
3165
3166 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
3167 FRAME_EXTERNAL_MENU_BAR (f));
3168
3169 /* Do first time app init */
3170
3171 if (!hprevinst)
3172 {
3173 w32_init_class (hinst);
3174 }
3175
3176 FRAME_W32_WINDOW (f) = hwnd
3177 = CreateWindow (EMACS_CLASS,
3178 f->namebuf,
3179 f->output_data.w32->dwStyle | WS_CLIPCHILDREN,
3180 f->output_data.w32->left_pos,
3181 f->output_data.w32->top_pos,
3182 rect.right - rect.left,
3183 rect.bottom - rect.top,
3184 NULL,
3185 NULL,
3186 hinst,
3187 NULL);
3188
3189 if (hwnd)
3190 {
3191 SetWindowLong (hwnd, WND_FONTWIDTH_INDEX, FONT_WIDTH (f->output_data.w32->font));
3192 SetWindowLong (hwnd, WND_LINEHEIGHT_INDEX, f->output_data.w32->line_height);
3193 SetWindowLong (hwnd, WND_BORDER_INDEX, f->output_data.w32->internal_border_width);
3194 SetWindowLong (hwnd, WND_SCROLLBAR_INDEX, f->output_data.w32->vertical_scroll_bar_extra);
3195 SetWindowLong (hwnd, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f));
3196
3197 /* Enable drag-n-drop. */
3198 DragAcceptFiles (hwnd, TRUE);
3199
3200 /* Do this to discard the default setting specified by our parent. */
3201 ShowWindow (hwnd, SW_HIDE);
3202 }
3203 }
3204
3205 void
3206 my_post_msg (wmsg, hwnd, msg, wParam, lParam)
3207 W32Msg * wmsg;
3208 HWND hwnd;
3209 UINT msg;
3210 WPARAM wParam;
3211 LPARAM lParam;
3212 {
3213 wmsg->msg.hwnd = hwnd;
3214 wmsg->msg.message = msg;
3215 wmsg->msg.wParam = wParam;
3216 wmsg->msg.lParam = lParam;
3217 wmsg->msg.time = GetMessageTime ();
3218
3219 post_msg (wmsg);
3220 }
3221
3222 /* GetKeyState and MapVirtualKey on Windows 95 do not actually distinguish
3223 between left and right keys as advertised. We test for this
3224 support dynamically, and set a flag when the support is absent. If
3225 absent, we keep track of the left and right control and alt keys
3226 ourselves. This is particularly necessary on keyboards that rely
3227 upon the AltGr key, which is represented as having the left control
3228 and right alt keys pressed. For these keyboards, we need to know
3229 when the left alt key has been pressed in addition to the AltGr key
3230 so that we can properly support M-AltGr-key sequences (such as M-@
3231 on Swedish keyboards). */
3232
3233 #define EMACS_LCONTROL 0
3234 #define EMACS_RCONTROL 1
3235 #define EMACS_LMENU 2
3236 #define EMACS_RMENU 3
3237
3238 static int modifiers[4];
3239 static int modifiers_recorded;
3240 static int modifier_key_support_tested;
3241
3242 static void
3243 test_modifier_support (unsigned int wparam)
3244 {
3245 unsigned int l, r;
3246
3247 if (wparam != VK_CONTROL && wparam != VK_MENU)
3248 return;
3249 if (wparam == VK_CONTROL)
3250 {
3251 l = VK_LCONTROL;
3252 r = VK_RCONTROL;
3253 }
3254 else
3255 {
3256 l = VK_LMENU;
3257 r = VK_RMENU;
3258 }
3259 if (!(GetKeyState (l) & 0x8000) && !(GetKeyState (r) & 0x8000))
3260 modifiers_recorded = 1;
3261 else
3262 modifiers_recorded = 0;
3263 modifier_key_support_tested = 1;
3264 }
3265
3266 static void
3267 record_keydown (unsigned int wparam, unsigned int lparam)
3268 {
3269 int i;
3270
3271 if (!modifier_key_support_tested)
3272 test_modifier_support (wparam);
3273
3274 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3275 return;
3276
3277 if (wparam == VK_CONTROL)
3278 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3279 else
3280 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3281
3282 modifiers[i] = 1;
3283 }
3284
3285 static void
3286 record_keyup (unsigned int wparam, unsigned int lparam)
3287 {
3288 int i;
3289
3290 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3291 return;
3292
3293 if (wparam == VK_CONTROL)
3294 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3295 else
3296 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3297
3298 modifiers[i] = 0;
3299 }
3300
3301 /* Emacs can lose focus while a modifier key has been pressed. When
3302 it regains focus, be conservative and clear all modifiers since
3303 we cannot reconstruct the left and right modifier state. */
3304 static void
3305 reset_modifiers ()
3306 {
3307 SHORT ctrl, alt;
3308
3309 if (GetFocus () == NULL)
3310 /* Emacs doesn't have keyboard focus. Do nothing. */
3311 return;
3312
3313 ctrl = GetAsyncKeyState (VK_CONTROL);
3314 alt = GetAsyncKeyState (VK_MENU);
3315
3316 if (!(ctrl & 0x08000))
3317 /* Clear any recorded control modifier state. */
3318 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3319
3320 if (!(alt & 0x08000))
3321 /* Clear any recorded alt modifier state. */
3322 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3323
3324 /* Update the state of all modifier keys, because modifiers used in
3325 hot-key combinations can get stuck on if Emacs loses focus as a
3326 result of a hot-key being pressed. */
3327 {
3328 BYTE keystate[256];
3329
3330 #define CURRENT_STATE(key) ((GetAsyncKeyState (key) & 0x8000) >> 8)
3331
3332 GetKeyboardState (keystate);
3333 keystate[VK_SHIFT] = CURRENT_STATE (VK_SHIFT);
3334 keystate[VK_CONTROL] = CURRENT_STATE (VK_CONTROL);
3335 keystate[VK_LCONTROL] = CURRENT_STATE (VK_LCONTROL);
3336 keystate[VK_RCONTROL] = CURRENT_STATE (VK_RCONTROL);
3337 keystate[VK_MENU] = CURRENT_STATE (VK_MENU);
3338 keystate[VK_LMENU] = CURRENT_STATE (VK_LMENU);
3339 keystate[VK_RMENU] = CURRENT_STATE (VK_RMENU);
3340 keystate[VK_LWIN] = CURRENT_STATE (VK_LWIN);
3341 keystate[VK_RWIN] = CURRENT_STATE (VK_RWIN);
3342 keystate[VK_APPS] = CURRENT_STATE (VK_APPS);
3343 SetKeyboardState (keystate);
3344 }
3345 }
3346
3347 /* Synchronize modifier state with what is reported with the current
3348 keystroke. Even if we cannot distinguish between left and right
3349 modifier keys, we know that, if no modifiers are set, then neither
3350 the left or right modifier should be set. */
3351 static void
3352 sync_modifiers ()
3353 {
3354 if (!modifiers_recorded)
3355 return;
3356
3357 if (!(GetKeyState (VK_CONTROL) & 0x8000))
3358 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3359
3360 if (!(GetKeyState (VK_MENU) & 0x8000))
3361 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3362 }
3363
3364 static int
3365 modifier_set (int vkey)
3366 {
3367 if (vkey == VK_CAPITAL || vkey == VK_SCROLL)
3368 return (GetKeyState (vkey) & 0x1);
3369 if (!modifiers_recorded)
3370 return (GetKeyState (vkey) & 0x8000);
3371
3372 switch (vkey)
3373 {
3374 case VK_LCONTROL:
3375 return modifiers[EMACS_LCONTROL];
3376 case VK_RCONTROL:
3377 return modifiers[EMACS_RCONTROL];
3378 case VK_LMENU:
3379 return modifiers[EMACS_LMENU];
3380 case VK_RMENU:
3381 return modifiers[EMACS_RMENU];
3382 }
3383 return (GetKeyState (vkey) & 0x8000);
3384 }
3385
3386 /* Convert between the modifier bits W32 uses and the modifier bits
3387 Emacs uses. */
3388
3389 unsigned int
3390 w32_key_to_modifier (int key)
3391 {
3392 Lisp_Object key_mapping;
3393
3394 switch (key)
3395 {
3396 case VK_LWIN:
3397 key_mapping = Vw32_lwindow_modifier;
3398 break;
3399 case VK_RWIN:
3400 key_mapping = Vw32_rwindow_modifier;
3401 break;
3402 case VK_APPS:
3403 key_mapping = Vw32_apps_modifier;
3404 break;
3405 case VK_SCROLL:
3406 key_mapping = Vw32_scroll_lock_modifier;
3407 break;
3408 default:
3409 key_mapping = Qnil;
3410 }
3411
3412 /* NB. This code runs in the input thread, asychronously to the lisp
3413 thread, so we must be careful to ensure access to lisp data is
3414 thread-safe. The following code is safe because the modifier
3415 variable values are updated atomically from lisp and symbols are
3416 not relocated by GC. Also, we don't have to worry about seeing GC
3417 markbits here. */
3418 if (EQ (key_mapping, Qhyper))
3419 return hyper_modifier;
3420 if (EQ (key_mapping, Qsuper))
3421 return super_modifier;
3422 if (EQ (key_mapping, Qmeta))
3423 return meta_modifier;
3424 if (EQ (key_mapping, Qalt))
3425 return alt_modifier;
3426 if (EQ (key_mapping, Qctrl))
3427 return ctrl_modifier;
3428 if (EQ (key_mapping, Qcontrol)) /* synonym for ctrl */
3429 return ctrl_modifier;
3430 if (EQ (key_mapping, Qshift))
3431 return shift_modifier;
3432
3433 /* Don't generate any modifier if not explicitly requested. */
3434 return 0;
3435 }
3436
3437 unsigned int
3438 w32_get_modifiers ()
3439 {
3440 return ((modifier_set (VK_SHIFT) ? shift_modifier : 0) |
3441 (modifier_set (VK_CONTROL) ? ctrl_modifier : 0) |
3442 (modifier_set (VK_LWIN) ? w32_key_to_modifier (VK_LWIN) : 0) |
3443 (modifier_set (VK_RWIN) ? w32_key_to_modifier (VK_RWIN) : 0) |
3444 (modifier_set (VK_APPS) ? w32_key_to_modifier (VK_APPS) : 0) |
3445 (modifier_set (VK_SCROLL) ? w32_key_to_modifier (VK_SCROLL) : 0) |
3446 (modifier_set (VK_MENU) ?
3447 ((NILP (Vw32_alt_is_meta)) ? alt_modifier : meta_modifier) : 0));
3448 }
3449
3450 /* We map the VK_* modifiers into console modifier constants
3451 so that we can use the same routines to handle both console
3452 and window input. */
3453
3454 static int
3455 construct_console_modifiers ()
3456 {
3457 int mods;
3458
3459 mods = 0;
3460 mods |= (modifier_set (VK_SHIFT)) ? SHIFT_PRESSED : 0;
3461 mods |= (modifier_set (VK_CAPITAL)) ? CAPSLOCK_ON : 0;
3462 mods |= (modifier_set (VK_SCROLL)) ? SCROLLLOCK_ON : 0;
3463 mods |= (modifier_set (VK_NUMLOCK)) ? NUMLOCK_ON : 0;
3464 mods |= (modifier_set (VK_LCONTROL)) ? LEFT_CTRL_PRESSED : 0;
3465 mods |= (modifier_set (VK_RCONTROL)) ? RIGHT_CTRL_PRESSED : 0;
3466 mods |= (modifier_set (VK_LMENU)) ? LEFT_ALT_PRESSED : 0;
3467 mods |= (modifier_set (VK_RMENU)) ? RIGHT_ALT_PRESSED : 0;
3468 mods |= (modifier_set (VK_LWIN)) ? LEFT_WIN_PRESSED : 0;
3469 mods |= (modifier_set (VK_RWIN)) ? RIGHT_WIN_PRESSED : 0;
3470 mods |= (modifier_set (VK_APPS)) ? APPS_PRESSED : 0;
3471
3472 return mods;
3473 }
3474
3475 static int
3476 w32_get_key_modifiers (unsigned int wparam, unsigned int lparam)
3477 {
3478 int mods;
3479
3480 /* Convert to emacs modifiers. */
3481 mods = w32_kbd_mods_to_emacs (construct_console_modifiers (), wparam);
3482
3483 return mods;
3484 }
3485
3486 unsigned int
3487 map_keypad_keys (unsigned int virt_key, unsigned int extended)
3488 {
3489 if (virt_key < VK_CLEAR || virt_key > VK_DELETE)
3490 return virt_key;
3491
3492 if (virt_key == VK_RETURN)
3493 return (extended ? VK_NUMPAD_ENTER : VK_RETURN);
3494
3495 if (virt_key >= VK_PRIOR && virt_key <= VK_DOWN)
3496 return (!extended ? (VK_NUMPAD_PRIOR + (virt_key - VK_PRIOR)) : virt_key);
3497
3498 if (virt_key == VK_INSERT || virt_key == VK_DELETE)
3499 return (!extended ? (VK_NUMPAD_INSERT + (virt_key - VK_INSERT)) : virt_key);
3500
3501 if (virt_key == VK_CLEAR)
3502 return (!extended ? VK_NUMPAD_CLEAR : virt_key);
3503
3504 return virt_key;
3505 }
3506
3507 /* List of special key combinations which w32 would normally capture,
3508 but emacs should grab instead. Not directly visible to lisp, to
3509 simplify synchronization. Each item is an integer encoding a virtual
3510 key code and modifier combination to capture. */
3511 Lisp_Object w32_grabbed_keys;
3512
3513 #define HOTKEY(vk,mods) make_number (((vk) & 255) | ((mods) << 8))
3514 #define HOTKEY_ID(k) (XFASTINT (k) & 0xbfff)
3515 #define HOTKEY_VK_CODE(k) (XFASTINT (k) & 255)
3516 #define HOTKEY_MODIFIERS(k) (XFASTINT (k) >> 8)
3517
3518 /* Register hot-keys for reserved key combinations when Emacs has
3519 keyboard focus, since this is the only way Emacs can receive key
3520 combinations like Alt-Tab which are used by the system. */
3521
3522 static void
3523 register_hot_keys (hwnd)
3524 HWND hwnd;
3525 {
3526 Lisp_Object keylist;
3527
3528 /* Use GC_CONSP, since we are called asynchronously. */
3529 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3530 {
3531 Lisp_Object key = XCAR (keylist);
3532
3533 /* Deleted entries get set to nil. */
3534 if (!INTEGERP (key))
3535 continue;
3536
3537 RegisterHotKey (hwnd, HOTKEY_ID (key),
3538 HOTKEY_MODIFIERS (key), HOTKEY_VK_CODE (key));
3539 }
3540 }
3541
3542 static void
3543 unregister_hot_keys (hwnd)
3544 HWND hwnd;
3545 {
3546 Lisp_Object keylist;
3547
3548 /* Use GC_CONSP, since we are called asynchronously. */
3549 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3550 {
3551 Lisp_Object key = XCAR (keylist);
3552
3553 if (!INTEGERP (key))
3554 continue;
3555
3556 UnregisterHotKey (hwnd, HOTKEY_ID (key));
3557 }
3558 }
3559
3560 /* Main message dispatch loop. */
3561
3562 static void
3563 w32_msg_pump (deferred_msg * msg_buf)
3564 {
3565 MSG msg;
3566 int result;
3567 HWND focus_window;
3568
3569 msh_mousewheel = RegisterWindowMessage (MSH_MOUSEWHEEL);
3570
3571 while (GetMessage (&msg, NULL, 0, 0))
3572 {
3573 if (msg.hwnd == NULL)
3574 {
3575 switch (msg.message)
3576 {
3577 case WM_NULL:
3578 /* Produced by complete_deferred_msg; just ignore. */
3579 break;
3580 case WM_EMACS_CREATEWINDOW:
3581 w32_createwindow ((struct frame *) msg.wParam);
3582 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3583 abort ();
3584 break;
3585 case WM_EMACS_SETLOCALE:
3586 SetThreadLocale (msg.wParam);
3587 /* Reply is not expected. */
3588 break;
3589 case WM_EMACS_SETKEYBOARDLAYOUT:
3590 result = (int) ActivateKeyboardLayout ((HKL) msg.wParam, 0);
3591 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
3592 result, 0))
3593 abort ();
3594 break;
3595 case WM_EMACS_REGISTER_HOT_KEY:
3596 focus_window = GetFocus ();
3597 if (focus_window != NULL)
3598 RegisterHotKey (focus_window,
3599 HOTKEY_ID (msg.wParam),
3600 HOTKEY_MODIFIERS (msg.wParam),
3601 HOTKEY_VK_CODE (msg.wParam));
3602 /* Reply is not expected. */
3603 break;
3604 case WM_EMACS_UNREGISTER_HOT_KEY:
3605 focus_window = GetFocus ();
3606 if (focus_window != NULL)
3607 UnregisterHotKey (focus_window, HOTKEY_ID (msg.wParam));
3608 /* Mark item as erased. NB: this code must be
3609 thread-safe. The next line is okay because the cons
3610 cell is never made into garbage and is not relocated by
3611 GC. */
3612 XCAR ((Lisp_Object) msg.lParam) = Qnil;
3613 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3614 abort ();
3615 break;
3616 case WM_EMACS_TOGGLE_LOCK_KEY:
3617 {
3618 int vk_code = (int) msg.wParam;
3619 int cur_state = (GetKeyState (vk_code) & 1);
3620 Lisp_Object new_state = (Lisp_Object) msg.lParam;
3621
3622 /* NB: This code must be thread-safe. It is safe to
3623 call NILP because symbols are not relocated by GC,
3624 and pointer here is not touched by GC (so the markbit
3625 can't be set). Numbers are safe because they are
3626 immediate values. */
3627 if (NILP (new_state)
3628 || (NUMBERP (new_state)
3629 && (XUINT (new_state)) & 1 != cur_state))
3630 {
3631 one_w32_display_info.faked_key = vk_code;
3632
3633 keybd_event ((BYTE) vk_code,
3634 (BYTE) MapVirtualKey (vk_code, 0),
3635 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3636 keybd_event ((BYTE) vk_code,
3637 (BYTE) MapVirtualKey (vk_code, 0),
3638 KEYEVENTF_EXTENDEDKEY | 0, 0);
3639 keybd_event ((BYTE) vk_code,
3640 (BYTE) MapVirtualKey (vk_code, 0),
3641 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3642 cur_state = !cur_state;
3643 }
3644 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
3645 cur_state, 0))
3646 abort ();
3647 }
3648 break;
3649 default:
3650 DebPrint (("msg %x not expected by w32_msg_pump\n", msg.message));
3651 }
3652 }
3653 else
3654 {
3655 DispatchMessage (&msg);
3656 }
3657
3658 /* Exit nested loop when our deferred message has completed. */
3659 if (msg_buf->completed)
3660 break;
3661 }
3662 }
3663
3664 deferred_msg * deferred_msg_head;
3665
3666 static deferred_msg *
3667 find_deferred_msg (HWND hwnd, UINT msg)
3668 {
3669 deferred_msg * item;
3670
3671 /* Don't actually need synchronization for read access, since
3672 modification of single pointer is always atomic. */
3673 /* enter_crit (); */
3674
3675 for (item = deferred_msg_head; item != NULL; item = item->next)
3676 if (item->w32msg.msg.hwnd == hwnd
3677 && item->w32msg.msg.message == msg)
3678 break;
3679
3680 /* leave_crit (); */
3681
3682 return item;
3683 }
3684
3685 static LRESULT
3686 send_deferred_msg (deferred_msg * msg_buf,
3687 HWND hwnd,
3688 UINT msg,
3689 WPARAM wParam,
3690 LPARAM lParam)
3691 {
3692 /* Only input thread can send deferred messages. */
3693 if (GetCurrentThreadId () != dwWindowsThreadId)
3694 abort ();
3695
3696 /* It is an error to send a message that is already deferred. */
3697 if (find_deferred_msg (hwnd, msg) != NULL)
3698 abort ();
3699
3700 /* Enforced synchronization is not needed because this is the only
3701 function that alters deferred_msg_head, and the following critical
3702 section is guaranteed to only be serially reentered (since only the
3703 input thread can call us). */
3704
3705 /* enter_crit (); */
3706
3707 msg_buf->completed = 0;
3708 msg_buf->next = deferred_msg_head;
3709 deferred_msg_head = msg_buf;
3710 my_post_msg (&msg_buf->w32msg, hwnd, msg, wParam, lParam);
3711
3712 /* leave_crit (); */
3713
3714 /* Start a new nested message loop to process other messages until
3715 this one is completed. */
3716 w32_msg_pump (msg_buf);
3717
3718 deferred_msg_head = msg_buf->next;
3719
3720 return msg_buf->result;
3721 }
3722
3723 void
3724 complete_deferred_msg (HWND hwnd, UINT msg, LRESULT result)
3725 {
3726 deferred_msg * msg_buf = find_deferred_msg (hwnd, msg);
3727
3728 if (msg_buf == NULL)
3729 /* Message may have been cancelled, so don't abort(). */
3730 return;
3731
3732 msg_buf->result = result;
3733 msg_buf->completed = 1;
3734
3735 /* Ensure input thread is woken so it notices the completion. */
3736 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
3737 }
3738
3739 void
3740 cancel_all_deferred_msgs ()
3741 {
3742 deferred_msg * item;
3743
3744 /* Don't actually need synchronization for read access, since
3745 modification of single pointer is always atomic. */
3746 /* enter_crit (); */
3747
3748 for (item = deferred_msg_head; item != NULL; item = item->next)
3749 {
3750 item->result = 0;
3751 item->completed = 1;
3752 }
3753
3754 /* leave_crit (); */
3755
3756 /* Ensure input thread is woken so it notices the completion. */
3757 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
3758 }
3759
3760 DWORD
3761 w32_msg_worker (dw)
3762 DWORD dw;
3763 {
3764 MSG msg;
3765 deferred_msg dummy_buf;
3766
3767 /* Ensure our message queue is created */
3768
3769 PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
3770
3771 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3772 abort ();
3773
3774 memset (&dummy_buf, 0, sizeof (dummy_buf));
3775 dummy_buf.w32msg.msg.hwnd = NULL;
3776 dummy_buf.w32msg.msg.message = WM_NULL;
3777
3778 /* This is the inital message loop which should only exit when the
3779 application quits. */
3780 w32_msg_pump (&dummy_buf);
3781
3782 return 0;
3783 }
3784
3785 static void
3786 post_character_message (hwnd, msg, wParam, lParam, modifiers)
3787 HWND hwnd;
3788 UINT msg;
3789 WPARAM wParam;
3790 LPARAM lParam;
3791 DWORD modifiers;
3792
3793 {
3794 W32Msg wmsg;
3795
3796 wmsg.dwModifiers = modifiers;
3797
3798 /* Detect quit_char and set quit-flag directly. Note that we
3799 still need to post a message to ensure the main thread will be
3800 woken up if blocked in sys_select(), but we do NOT want to post
3801 the quit_char message itself (because it will usually be as if
3802 the user had typed quit_char twice). Instead, we post a dummy
3803 message that has no particular effect. */
3804 {
3805 int c = wParam;
3806 if (isalpha (c) && wmsg.dwModifiers == ctrl_modifier)
3807 c = make_ctrl_char (c) & 0377;
3808 if (c == quit_char
3809 || (wmsg.dwModifiers == 0 &&
3810 XFASTINT (Vw32_quit_key) && wParam == XFASTINT (Vw32_quit_key)))
3811 {
3812 Vquit_flag = Qt;
3813
3814 /* The choice of message is somewhat arbitrary, as long as
3815 the main thread handler just ignores it. */
3816 msg = WM_NULL;
3817
3818 /* Interrupt any blocking system calls. */
3819 signal_quit ();
3820
3821 /* As a safety precaution, forcibly complete any deferred
3822 messages. This is a kludge, but I don't see any particularly
3823 clean way to handle the situation where a deferred message is
3824 "dropped" in the lisp thread, and will thus never be
3825 completed, eg. by the user trying to activate the menubar
3826 when the lisp thread is busy, and then typing C-g when the
3827 menubar doesn't open promptly (with the result that the
3828 menubar never responds at all because the deferred
3829 WM_INITMENU message is never completed). Another problem
3830 situation is when the lisp thread calls SendMessage (to send
3831 a window manager command) when a message has been deferred;
3832 the lisp thread gets blocked indefinitely waiting for the
3833 deferred message to be completed, which itself is waiting for
3834 the lisp thread to respond.
3835
3836 Note that we don't want to block the input thread waiting for
3837 a reponse from the lisp thread (although that would at least
3838 solve the deadlock problem above), because we want to be able
3839 to receive C-g to interrupt the lisp thread. */
3840 cancel_all_deferred_msgs ();
3841 }
3842 }
3843
3844 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3845 }
3846
3847 /* Main window procedure */
3848
3849 LRESULT CALLBACK
3850 w32_wnd_proc (hwnd, msg, wParam, lParam)
3851 HWND hwnd;
3852 UINT msg;
3853 WPARAM wParam;
3854 LPARAM lParam;
3855 {
3856 struct frame *f;
3857 struct w32_display_info *dpyinfo = &one_w32_display_info;
3858 W32Msg wmsg;
3859 int windows_translate;
3860 int key;
3861
3862 /* Note that it is okay to call x_window_to_frame, even though we are
3863 not running in the main lisp thread, because frame deletion
3864 requires the lisp thread to synchronize with this thread. Thus, if
3865 a frame struct is returned, it can be used without concern that the
3866 lisp thread might make it disappear while we are using it.
3867
3868 NB. Walking the frame list in this thread is safe (as long as
3869 writes of Lisp_Object slots are atomic, which they are on Windows).
3870 Although delete-frame can destructively modify the frame list while
3871 we are walking it, a garbage collection cannot occur until after
3872 delete-frame has synchronized with this thread.
3873
3874 It is also safe to use functions that make GDI calls, such as
3875 w32_clear_rect, because these functions must obtain a DC handle
3876 from the frame struct using get_frame_dc which is thread-aware. */
3877
3878 switch (msg)
3879 {
3880 case WM_ERASEBKGND:
3881 f = x_window_to_frame (dpyinfo, hwnd);
3882 if (f)
3883 {
3884 HDC hdc = get_frame_dc (f);
3885 GetUpdateRect (hwnd, &wmsg.rect, FALSE);
3886 w32_clear_rect (f, hdc, &wmsg.rect);
3887 release_frame_dc (f, hdc);
3888
3889 #if defined (W32_DEBUG_DISPLAY)
3890 DebPrint (("WM_ERASEBKGND: erasing %d,%d-%d,%d\n",
3891 wmsg.rect.left, wmsg.rect.top, wmsg.rect.right,
3892 wmsg.rect.bottom));
3893 #endif /* W32_DEBUG_DISPLAY */
3894 }
3895 return 1;
3896 case WM_PALETTECHANGED:
3897 /* ignore our own changes */
3898 if ((HWND)wParam != hwnd)
3899 {
3900 f = x_window_to_frame (dpyinfo, hwnd);
3901 if (f)
3902 /* get_frame_dc will realize our palette and force all
3903 frames to be redrawn if needed. */
3904 release_frame_dc (f, get_frame_dc (f));
3905 }
3906 return 0;
3907 case WM_PAINT:
3908 {
3909 PAINTSTRUCT paintStruct;
3910 RECT update_rect;
3911
3912 /* MSDN Docs say not to call BeginPaint if GetUpdateRect
3913 fails. Apparently this can happen under some
3914 circumstances. */
3915 if (!w32_strict_painting || GetUpdateRect (hwnd, &update_rect, FALSE))
3916 {
3917 enter_crit ();
3918 BeginPaint (hwnd, &paintStruct);
3919
3920 if (w32_strict_painting)
3921 /* The rectangles returned by GetUpdateRect and BeginPaint
3922 do not always match. GetUpdateRect seems to be the
3923 more reliable of the two. */
3924 wmsg.rect = update_rect;
3925 else
3926 wmsg.rect = paintStruct.rcPaint;
3927
3928 #if defined (W32_DEBUG_DISPLAY)
3929 DebPrint (("WM_PAINT: painting %d,%d-%d,%d\n", wmsg.rect.left,
3930 wmsg.rect.top, wmsg.rect.right, wmsg.rect.bottom));
3931 DebPrint (("WM_PAINT: update region is %d,%d-%d,%d\n",
3932 update_rect.left, update_rect.top,
3933 update_rect.right, update_rect.bottom));
3934 #endif
3935 EndPaint (hwnd, &paintStruct);
3936 leave_crit ();
3937
3938 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3939
3940 return 0;
3941 }
3942
3943 /* If GetUpdateRect returns 0 (meaning there is no update
3944 region), assume the whole window needs to be repainted. */
3945 GetClientRect(hwnd, &wmsg.rect);
3946 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3947 return 0;
3948 }
3949
3950 case WM_INPUTLANGCHANGE:
3951 /* Inform lisp thread of keyboard layout changes. */
3952 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3953
3954 /* Clear dead keys in the keyboard state; for simplicity only
3955 preserve modifier key states. */
3956 {
3957 int i;
3958 BYTE keystate[256];
3959
3960 GetKeyboardState (keystate);
3961 for (i = 0; i < 256; i++)
3962 if (1
3963 && i != VK_SHIFT
3964 && i != VK_LSHIFT
3965 && i != VK_RSHIFT
3966 && i != VK_CAPITAL
3967 && i != VK_NUMLOCK
3968 && i != VK_SCROLL
3969 && i != VK_CONTROL
3970 && i != VK_LCONTROL
3971 && i != VK_RCONTROL
3972 && i != VK_MENU
3973 && i != VK_LMENU
3974 && i != VK_RMENU
3975 && i != VK_LWIN
3976 && i != VK_RWIN)
3977 keystate[i] = 0;
3978 SetKeyboardState (keystate);
3979 }
3980 goto dflt;
3981
3982 case WM_HOTKEY:
3983 /* Synchronize hot keys with normal input. */
3984 PostMessage (hwnd, WM_KEYDOWN, HIWORD (lParam), 0);
3985 return (0);
3986
3987 case WM_KEYUP:
3988 case WM_SYSKEYUP:
3989 record_keyup (wParam, lParam);
3990 goto dflt;
3991
3992 case WM_KEYDOWN:
3993 case WM_SYSKEYDOWN:
3994 /* Ignore keystrokes we fake ourself; see below. */
3995 if (dpyinfo->faked_key == wParam)
3996 {
3997 dpyinfo->faked_key = 0;
3998 /* Make sure TranslateMessage sees them though (as long as
3999 they don't produce WM_CHAR messages). This ensures that
4000 indicator lights are toggled promptly on Windows 9x, for
4001 example. */
4002 if (lispy_function_keys[wParam] != 0)
4003 {
4004 windows_translate = 1;
4005 goto translate;
4006 }
4007 return 0;
4008 }
4009
4010 /* Synchronize modifiers with current keystroke. */
4011 sync_modifiers ();
4012 record_keydown (wParam, lParam);
4013 wParam = map_keypad_keys (wParam, (lParam & 0x1000000L) != 0);
4014
4015 windows_translate = 0;
4016
4017 switch (wParam)
4018 {
4019 case VK_LWIN:
4020 if (NILP (Vw32_pass_lwindow_to_system))
4021 {
4022 /* Prevent system from acting on keyup (which opens the
4023 Start menu if no other key was pressed) by simulating a
4024 press of Space which we will ignore. */
4025 if (GetAsyncKeyState (wParam) & 1)
4026 {
4027 if (NUMBERP (Vw32_phantom_key_code))
4028 key = XUINT (Vw32_phantom_key_code) & 255;
4029 else
4030 key = VK_SPACE;
4031 dpyinfo->faked_key = key;
4032 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
4033 }
4034 }
4035 if (!NILP (Vw32_lwindow_modifier))
4036 return 0;
4037 break;
4038 case VK_RWIN:
4039 if (NILP (Vw32_pass_rwindow_to_system))
4040 {
4041 if (GetAsyncKeyState (wParam) & 1)
4042 {
4043 if (NUMBERP (Vw32_phantom_key_code))
4044 key = XUINT (Vw32_phantom_key_code) & 255;
4045 else
4046 key = VK_SPACE;
4047 dpyinfo->faked_key = key;
4048 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
4049 }
4050 }
4051 if (!NILP (Vw32_rwindow_modifier))
4052 return 0;
4053 break;
4054 case VK_APPS:
4055 if (!NILP (Vw32_apps_modifier))
4056 return 0;
4057 break;
4058 case VK_MENU:
4059 if (NILP (Vw32_pass_alt_to_system))
4060 /* Prevent DefWindowProc from activating the menu bar if an
4061 Alt key is pressed and released by itself. */
4062 return 0;
4063 windows_translate = 1;
4064 break;
4065 case VK_CAPITAL:
4066 /* Decide whether to treat as modifier or function key. */
4067 if (NILP (Vw32_enable_caps_lock))
4068 goto disable_lock_key;
4069 windows_translate = 1;
4070 break;
4071 case VK_NUMLOCK:
4072 /* Decide whether to treat as modifier or function key. */
4073 if (NILP (Vw32_enable_num_lock))
4074 goto disable_lock_key;
4075 windows_translate = 1;
4076 break;
4077 case VK_SCROLL:
4078 /* Decide whether to treat as modifier or function key. */
4079 if (NILP (Vw32_scroll_lock_modifier))
4080 goto disable_lock_key;
4081 windows_translate = 1;
4082 break;
4083 disable_lock_key:
4084 /* Ensure the appropriate lock key state (and indicator light)
4085 remains in the same state. We do this by faking another
4086 press of the relevant key. Apparently, this really is the
4087 only way to toggle the state of the indicator lights. */
4088 dpyinfo->faked_key = wParam;
4089 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4090 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4091 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4092 KEYEVENTF_EXTENDEDKEY | 0, 0);
4093 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4094 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4095 /* Ensure indicator lights are updated promptly on Windows 9x
4096 (TranslateMessage apparently does this), after forwarding
4097 input event. */
4098 post_character_message (hwnd, msg, wParam, lParam,
4099 w32_get_key_modifiers (wParam, lParam));
4100 windows_translate = 1;
4101 break;
4102 case VK_CONTROL:
4103 case VK_SHIFT:
4104 case VK_PROCESSKEY: /* Generated by IME. */
4105 windows_translate = 1;
4106 break;
4107 case VK_CANCEL:
4108 /* Windows maps Ctrl-Pause (aka Ctrl-Break) into VK_CANCEL,
4109 which is confusing for purposes of key binding; convert
4110 VK_CANCEL events into VK_PAUSE events. */
4111 wParam = VK_PAUSE;
4112 break;
4113 case VK_PAUSE:
4114 /* Windows maps Ctrl-NumLock into VK_PAUSE, which is confusing
4115 for purposes of key binding; convert these back into
4116 VK_NUMLOCK events, at least when we want to see NumLock key
4117 presses. (Note that there is never any possibility that
4118 VK_PAUSE with Ctrl really is C-Pause as per above.) */
4119 if (NILP (Vw32_enable_num_lock) && modifier_set (VK_CONTROL))
4120 wParam = VK_NUMLOCK;
4121 break;
4122 default:
4123 /* If not defined as a function key, change it to a WM_CHAR message. */
4124 if (lispy_function_keys[wParam] == 0)
4125 {
4126 DWORD modifiers = construct_console_modifiers ();
4127
4128 if (!NILP (Vw32_recognize_altgr)
4129 && modifier_set (VK_LCONTROL) && modifier_set (VK_RMENU))
4130 {
4131 /* Always let TranslateMessage handle AltGr key chords;
4132 for some reason, ToAscii doesn't always process AltGr
4133 chords correctly. */
4134 windows_translate = 1;
4135 }
4136 else if ((modifiers & (~SHIFT_PRESSED & ~CAPSLOCK_ON)) != 0)
4137 {
4138 /* Handle key chords including any modifiers other
4139 than shift directly, in order to preserve as much
4140 modifier information as possible. */
4141 if ('A' <= wParam && wParam <= 'Z')
4142 {
4143 /* Don't translate modified alphabetic keystrokes,
4144 so the user doesn't need to constantly switch
4145 layout to type control or meta keystrokes when
4146 the normal layout translates alphabetic
4147 characters to non-ascii characters. */
4148 if (!modifier_set (VK_SHIFT))
4149 wParam += ('a' - 'A');
4150 msg = WM_CHAR;
4151 }
4152 else
4153 {
4154 /* Try to handle other keystrokes by determining the
4155 base character (ie. translating the base key plus
4156 shift modifier). */
4157 int add;
4158 int isdead = 0;
4159 KEY_EVENT_RECORD key;
4160
4161 key.bKeyDown = TRUE;
4162 key.wRepeatCount = 1;
4163 key.wVirtualKeyCode = wParam;
4164 key.wVirtualScanCode = (lParam & 0xFF0000) >> 16;
4165 key.uChar.AsciiChar = 0;
4166 key.dwControlKeyState = modifiers;
4167
4168 add = w32_kbd_patch_key (&key);
4169 /* 0 means an unrecognised keycode, negative means
4170 dead key. Ignore both. */
4171 while (--add >= 0)
4172 {
4173 /* Forward asciified character sequence. */
4174 post_character_message
4175 (hwnd, WM_CHAR, key.uChar.AsciiChar, lParam,
4176 w32_get_key_modifiers (wParam, lParam));
4177 w32_kbd_patch_key (&key);
4178 }
4179 return 0;
4180 }
4181 }
4182 else
4183 {
4184 /* Let TranslateMessage handle everything else. */
4185 windows_translate = 1;
4186 }
4187 }
4188 }
4189
4190 translate:
4191 if (windows_translate)
4192 {
4193 MSG windows_msg = { hwnd, msg, wParam, lParam, 0, {0,0} };
4194
4195 windows_msg.time = GetMessageTime ();
4196 TranslateMessage (&windows_msg);
4197 goto dflt;
4198 }
4199
4200 /* Fall through */
4201
4202 case WM_SYSCHAR:
4203 case WM_CHAR:
4204 post_character_message (hwnd, msg, wParam, lParam,
4205 w32_get_key_modifiers (wParam, lParam));
4206 break;
4207
4208 /* Simulate middle mouse button events when left and right buttons
4209 are used together, but only if user has two button mouse. */
4210 case WM_LBUTTONDOWN:
4211 case WM_RBUTTONDOWN:
4212 if (XINT (Vw32_num_mouse_buttons) == 3)
4213 goto handle_plain_button;
4214
4215 {
4216 int this = (msg == WM_LBUTTONDOWN) ? LMOUSE : RMOUSE;
4217 int other = (msg == WM_LBUTTONDOWN) ? RMOUSE : LMOUSE;
4218
4219 if (button_state & this)
4220 return 0;
4221
4222 if (button_state == 0)
4223 SetCapture (hwnd);
4224
4225 button_state |= this;
4226
4227 if (button_state & other)
4228 {
4229 if (mouse_button_timer)
4230 {
4231 KillTimer (hwnd, mouse_button_timer);
4232 mouse_button_timer = 0;
4233
4234 /* Generate middle mouse event instead. */
4235 msg = WM_MBUTTONDOWN;
4236 button_state |= MMOUSE;
4237 }
4238 else if (button_state & MMOUSE)
4239 {
4240 /* Ignore button event if we've already generated a
4241 middle mouse down event. This happens if the
4242 user releases and press one of the two buttons
4243 after we've faked a middle mouse event. */
4244 return 0;
4245 }
4246 else
4247 {
4248 /* Flush out saved message. */
4249 post_msg (&saved_mouse_button_msg);
4250 }
4251 wmsg.dwModifiers = w32_get_modifiers ();
4252 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4253
4254 /* Clear message buffer. */
4255 saved_mouse_button_msg.msg.hwnd = 0;
4256 }
4257 else
4258 {
4259 /* Hold onto message for now. */
4260 mouse_button_timer =
4261 SetTimer (hwnd, MOUSE_BUTTON_ID,
4262 XINT (Vw32_mouse_button_tolerance), NULL);
4263 saved_mouse_button_msg.msg.hwnd = hwnd;
4264 saved_mouse_button_msg.msg.message = msg;
4265 saved_mouse_button_msg.msg.wParam = wParam;
4266 saved_mouse_button_msg.msg.lParam = lParam;
4267 saved_mouse_button_msg.msg.time = GetMessageTime ();
4268 saved_mouse_button_msg.dwModifiers = w32_get_modifiers ();
4269 }
4270 }
4271 return 0;
4272
4273 case WM_LBUTTONUP:
4274 case WM_RBUTTONUP:
4275 if (XINT (Vw32_num_mouse_buttons) == 3)
4276 goto handle_plain_button;
4277
4278 {
4279 int this = (msg == WM_LBUTTONUP) ? LMOUSE : RMOUSE;
4280 int other = (msg == WM_LBUTTONUP) ? RMOUSE : LMOUSE;
4281
4282 if ((button_state & this) == 0)
4283 return 0;
4284
4285 button_state &= ~this;
4286
4287 if (button_state & MMOUSE)
4288 {
4289 /* Only generate event when second button is released. */
4290 if ((button_state & other) == 0)
4291 {
4292 msg = WM_MBUTTONUP;
4293 button_state &= ~MMOUSE;
4294
4295 if (button_state) abort ();
4296 }
4297 else
4298 return 0;
4299 }
4300 else
4301 {
4302 /* Flush out saved message if necessary. */
4303 if (saved_mouse_button_msg.msg.hwnd)
4304 {
4305 post_msg (&saved_mouse_button_msg);
4306 }
4307 }
4308 wmsg.dwModifiers = w32_get_modifiers ();
4309 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4310
4311 /* Always clear message buffer and cancel timer. */
4312 saved_mouse_button_msg.msg.hwnd = 0;
4313 KillTimer (hwnd, mouse_button_timer);
4314 mouse_button_timer = 0;
4315
4316 if (button_state == 0)
4317 ReleaseCapture ();
4318 }
4319 return 0;
4320
4321 case WM_MBUTTONDOWN:
4322 case WM_MBUTTONUP:
4323 handle_plain_button:
4324 {
4325 BOOL up;
4326 int button;
4327
4328 if (parse_button (msg, &button, &up))
4329 {
4330 if (up) ReleaseCapture ();
4331 else SetCapture (hwnd);
4332 button = (button == 0) ? LMOUSE :
4333 ((button == 1) ? MMOUSE : RMOUSE);
4334 if (up)
4335 button_state &= ~button;
4336 else
4337 button_state |= button;
4338 }
4339 }
4340
4341 wmsg.dwModifiers = w32_get_modifiers ();
4342 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4343 return 0;
4344
4345 case WM_VSCROLL:
4346 case WM_MOUSEMOVE:
4347 if (XINT (Vw32_mouse_move_interval) <= 0
4348 || (msg == WM_MOUSEMOVE && button_state == 0))
4349 {
4350 wmsg.dwModifiers = w32_get_modifiers ();
4351 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4352 return 0;
4353 }
4354
4355 /* Hang onto mouse move and scroll messages for a bit, to avoid
4356 sending such events to Emacs faster than it can process them.
4357 If we get more events before the timer from the first message
4358 expires, we just replace the first message. */
4359
4360 if (saved_mouse_move_msg.msg.hwnd == 0)
4361 mouse_move_timer =
4362 SetTimer (hwnd, MOUSE_MOVE_ID,
4363 XINT (Vw32_mouse_move_interval), NULL);
4364
4365 /* Hold onto message for now. */
4366 saved_mouse_move_msg.msg.hwnd = hwnd;
4367 saved_mouse_move_msg.msg.message = msg;
4368 saved_mouse_move_msg.msg.wParam = wParam;
4369 saved_mouse_move_msg.msg.lParam = lParam;
4370 saved_mouse_move_msg.msg.time = GetMessageTime ();
4371 saved_mouse_move_msg.dwModifiers = w32_get_modifiers ();
4372
4373 return 0;
4374
4375 case WM_MOUSEWHEEL:
4376 wmsg.dwModifiers = w32_get_modifiers ();
4377 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4378 return 0;
4379
4380 case WM_DROPFILES:
4381 wmsg.dwModifiers = w32_get_modifiers ();
4382 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4383 return 0;
4384
4385 case WM_TIMER:
4386 /* Flush out saved messages if necessary. */
4387 if (wParam == mouse_button_timer)
4388 {
4389 if (saved_mouse_button_msg.msg.hwnd)
4390 {
4391 post_msg (&saved_mouse_button_msg);
4392 saved_mouse_button_msg.msg.hwnd = 0;
4393 }
4394 KillTimer (hwnd, mouse_button_timer);
4395 mouse_button_timer = 0;
4396 }
4397 else if (wParam == mouse_move_timer)
4398 {
4399 if (saved_mouse_move_msg.msg.hwnd)
4400 {
4401 post_msg (&saved_mouse_move_msg);
4402 saved_mouse_move_msg.msg.hwnd = 0;
4403 }
4404 KillTimer (hwnd, mouse_move_timer);
4405 mouse_move_timer = 0;
4406 }
4407 return 0;
4408
4409 case WM_NCACTIVATE:
4410 /* Windows doesn't send us focus messages when putting up and
4411 taking down a system popup dialog as for Ctrl-Alt-Del on Windows 95.
4412 The only indication we get that something happened is receiving
4413 this message afterwards. So this is a good time to reset our
4414 keyboard modifiers' state. */
4415 reset_modifiers ();
4416 goto dflt;
4417
4418 case WM_INITMENU:
4419 button_state = 0;
4420 ReleaseCapture ();
4421 /* We must ensure menu bar is fully constructed and up to date
4422 before allowing user interaction with it. To achieve this
4423 we send this message to the lisp thread and wait for a
4424 reply (whose value is not actually needed) to indicate that
4425 the menu bar is now ready for use, so we can now return.
4426
4427 To remain responsive in the meantime, we enter a nested message
4428 loop that can process all other messages.
4429
4430 However, we skip all this if the message results from calling
4431 TrackPopupMenu - in fact, we must NOT attempt to send the lisp
4432 thread a message because it is blocked on us at this point. We
4433 set menubar_active before calling TrackPopupMenu to indicate
4434 this (there is no possibility of confusion with real menubar
4435 being active). */
4436
4437 f = x_window_to_frame (dpyinfo, hwnd);
4438 if (f
4439 && (f->output_data.w32->menubar_active
4440 /* We can receive this message even in the absence of a
4441 menubar (ie. when the system menu is activated) - in this
4442 case we do NOT want to forward the message, otherwise it
4443 will cause the menubar to suddenly appear when the user
4444 had requested it to be turned off! */
4445 || f->output_data.w32->menubar_widget == NULL))
4446 return 0;
4447
4448 {
4449 deferred_msg msg_buf;
4450
4451 /* Detect if message has already been deferred; in this case
4452 we cannot return any sensible value to ignore this. */
4453 if (find_deferred_msg (hwnd, msg) != NULL)
4454 abort ();
4455
4456 return send_deferred_msg (&msg_buf, hwnd, msg, wParam, lParam);
4457 }
4458
4459 case WM_EXITMENULOOP:
4460 f = x_window_to_frame (dpyinfo, hwnd);
4461
4462 /* Indicate that menubar can be modified again. */
4463 if (f)
4464 f->output_data.w32->menubar_active = 0;
4465 goto dflt;
4466
4467 case WM_MEASUREITEM:
4468 f = x_window_to_frame (dpyinfo, hwnd);
4469 if (f)
4470 {
4471 MEASUREITEMSTRUCT * pMis = (MEASUREITEMSTRUCT *) lParam;
4472
4473 if (pMis->CtlType == ODT_MENU)
4474 {
4475 /* Work out dimensions for popup menu titles. */
4476 char * title = (char *) pMis->itemData;
4477 HDC hdc = GetDC (hwnd);
4478 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4479 LOGFONT menu_logfont;
4480 HFONT old_font;
4481 SIZE size;
4482
4483 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4484 menu_logfont.lfWeight = FW_BOLD;
4485 menu_font = CreateFontIndirect (&menu_logfont);
4486 old_font = SelectObject (hdc, menu_font);
4487
4488 GetTextExtentPoint32 (hdc, title, strlen (title), &size);
4489 pMis->itemWidth = size.cx;
4490 pMis->itemHeight = GetSystemMetrics (SM_CYMENUSIZE);
4491 if (pMis->itemHeight < size.cy)
4492 pMis->itemHeight = size.cy;
4493
4494 SelectObject (hdc, old_font);
4495 DeleteObject (menu_font);
4496 ReleaseDC (hwnd, hdc);
4497 return TRUE;
4498 }
4499 }
4500 return 0;
4501
4502 case WM_DRAWITEM:
4503 f = x_window_to_frame (dpyinfo, hwnd);
4504 if (f)
4505 {
4506 DRAWITEMSTRUCT * pDis = (DRAWITEMSTRUCT *) lParam;
4507
4508 if (pDis->CtlType == ODT_MENU)
4509 {
4510 /* Draw popup menu title. */
4511 char * title = (char *) pDis->itemData;
4512 HDC hdc = pDis->hDC;
4513 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4514 LOGFONT menu_logfont;
4515 HFONT old_font;
4516
4517 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4518 menu_logfont.lfWeight = FW_BOLD;
4519 menu_font = CreateFontIndirect (&menu_logfont);
4520 old_font = SelectObject (hdc, menu_font);
4521
4522 /* Always draw title as if not selected. */
4523 ExtTextOut (hdc,
4524 pDis->rcItem.left + GetSystemMetrics (SM_CXMENUCHECK),
4525 pDis->rcItem.top,
4526 ETO_OPAQUE, &pDis->rcItem,
4527 title, strlen (title), NULL);
4528
4529 SelectObject (hdc, old_font);
4530 DeleteObject (menu_font);
4531 return TRUE;
4532 }
4533 }
4534 return 0;
4535
4536 #if 0
4537 /* Still not right - can't distinguish between clicks in the
4538 client area of the frame from clicks forwarded from the scroll
4539 bars - may have to hook WM_NCHITTEST to remember the mouse
4540 position and then check if it is in the client area ourselves. */
4541 case WM_MOUSEACTIVATE:
4542 /* Discard the mouse click that activates a frame, allowing the
4543 user to click anywhere without changing point (or worse!).
4544 Don't eat mouse clicks on scrollbars though!! */
4545 if (LOWORD (lParam) == HTCLIENT )
4546 return MA_ACTIVATEANDEAT;
4547 goto dflt;
4548 #endif
4549
4550 case WM_ACTIVATEAPP:
4551 case WM_ACTIVATE:
4552 case WM_WINDOWPOSCHANGED:
4553 case WM_SHOWWINDOW:
4554 /* Inform lisp thread that a frame might have just been obscured
4555 or exposed, so should recheck visibility of all frames. */
4556 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4557 goto dflt;
4558
4559 case WM_SETFOCUS:
4560 dpyinfo->faked_key = 0;
4561 reset_modifiers ();
4562 register_hot_keys (hwnd);
4563 goto command;
4564 case WM_KILLFOCUS:
4565 unregister_hot_keys (hwnd);
4566 button_state = 0;
4567 ReleaseCapture ();
4568 case WM_MOVE:
4569 case WM_SIZE:
4570 case WM_COMMAND:
4571 command:
4572 wmsg.dwModifiers = w32_get_modifiers ();
4573 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4574 goto dflt;
4575
4576 case WM_CLOSE:
4577 wmsg.dwModifiers = w32_get_modifiers ();
4578 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4579 return 0;
4580
4581 case WM_WINDOWPOSCHANGING:
4582 {
4583 WINDOWPLACEMENT wp;
4584 LPWINDOWPOS lppos = (WINDOWPOS *) lParam;
4585
4586 wp.length = sizeof (WINDOWPLACEMENT);
4587 GetWindowPlacement (hwnd, &wp);
4588
4589 if (wp.showCmd != SW_SHOWMINIMIZED && (lppos->flags & SWP_NOSIZE) == 0)
4590 {
4591 RECT rect;
4592 int wdiff;
4593 int hdiff;
4594 DWORD font_width;
4595 DWORD line_height;
4596 DWORD internal_border;
4597 DWORD scrollbar_extra;
4598 RECT wr;
4599
4600 wp.length = sizeof(wp);
4601 GetWindowRect (hwnd, &wr);
4602
4603 enter_crit ();
4604
4605 font_width = GetWindowLong (hwnd, WND_FONTWIDTH_INDEX);
4606 line_height = GetWindowLong (hwnd, WND_LINEHEIGHT_INDEX);
4607 internal_border = GetWindowLong (hwnd, WND_BORDER_INDEX);
4608 scrollbar_extra = GetWindowLong (hwnd, WND_SCROLLBAR_INDEX);
4609
4610 leave_crit ();
4611
4612 memset (&rect, 0, sizeof (rect));
4613 AdjustWindowRect (&rect, GetWindowLong (hwnd, GWL_STYLE),
4614 GetMenu (hwnd) != NULL);
4615
4616 /* Force width and height of client area to be exact
4617 multiples of the character cell dimensions. */
4618 wdiff = (lppos->cx - (rect.right - rect.left)
4619 - 2 * internal_border - scrollbar_extra)
4620 % font_width;
4621 hdiff = (lppos->cy - (rect.bottom - rect.top)
4622 - 2 * internal_border)
4623 % line_height;
4624
4625 if (wdiff || hdiff)
4626 {
4627 /* For right/bottom sizing we can just fix the sizes.
4628 However for top/left sizing we will need to fix the X
4629 and Y positions as well. */
4630
4631 lppos->cx -= wdiff;
4632 lppos->cy -= hdiff;
4633
4634 if (wp.showCmd != SW_SHOWMAXIMIZED
4635 && (lppos->flags & SWP_NOMOVE) == 0)
4636 {
4637 if (lppos->x != wr.left || lppos->y != wr.top)
4638 {
4639 lppos->x += wdiff;
4640 lppos->y += hdiff;
4641 }
4642 else
4643 {
4644 lppos->flags |= SWP_NOMOVE;
4645 }
4646 }
4647
4648 return 0;
4649 }
4650 }
4651 }
4652
4653 goto dflt;
4654
4655 case WM_GETMINMAXINFO:
4656 /* Hack to correct bug that allows Emacs frames to be resized
4657 below the Minimum Tracking Size. */
4658 ((LPMINMAXINFO) lParam)->ptMinTrackSize.y++;
4659 return 0;
4660
4661 case WM_EMACS_CREATESCROLLBAR:
4662 return (LRESULT) w32_createscrollbar ((struct frame *) wParam,
4663 (struct scroll_bar *) lParam);
4664
4665 case WM_EMACS_SHOWWINDOW:
4666 return ShowWindow ((HWND) wParam, (WPARAM) lParam);
4667
4668 case WM_EMACS_SETFOREGROUND:
4669 {
4670 HWND foreground_window;
4671 DWORD foreground_thread, retval;
4672
4673 /* On NT 5.0, and apparently Windows 98, it is necessary to
4674 attach to the thread that currently has focus in order to
4675 pull the focus away from it. */
4676 foreground_window = GetForegroundWindow ();
4677 foreground_thread = GetWindowThreadProcessId (foreground_window, NULL);
4678 if (!foreground_window
4679 || foreground_thread == GetCurrentThreadId ()
4680 || !AttachThreadInput (GetCurrentThreadId (),
4681 foreground_thread, TRUE))
4682 foreground_thread = 0;
4683
4684 retval = SetForegroundWindow ((HWND) wParam);
4685
4686 /* Detach from the previous foreground thread. */
4687 if (foreground_thread)
4688 AttachThreadInput (GetCurrentThreadId (),
4689 foreground_thread, FALSE);
4690
4691 return retval;
4692 }
4693
4694 case WM_EMACS_SETWINDOWPOS:
4695 {
4696 WINDOWPOS * pos = (WINDOWPOS *) wParam;
4697 return SetWindowPos (hwnd, pos->hwndInsertAfter,
4698 pos->x, pos->y, pos->cx, pos->cy, pos->flags);
4699 }
4700
4701 case WM_EMACS_DESTROYWINDOW:
4702 DragAcceptFiles ((HWND) wParam, FALSE);
4703 return DestroyWindow ((HWND) wParam);
4704
4705 case WM_EMACS_TRACKPOPUPMENU:
4706 {
4707 UINT flags;
4708 POINT *pos;
4709 int retval;
4710 pos = (POINT *)lParam;
4711 flags = TPM_CENTERALIGN;
4712 if (button_state & LMOUSE)
4713 flags |= TPM_LEFTBUTTON;
4714 else if (button_state & RMOUSE)
4715 flags |= TPM_RIGHTBUTTON;
4716
4717 /* Remember we did a SetCapture on the initial mouse down event,
4718 so for safety, we make sure the capture is cancelled now. */
4719 ReleaseCapture ();
4720 button_state = 0;
4721
4722 /* Use menubar_active to indicate that WM_INITMENU is from
4723 TrackPopupMenu below, and should be ignored. */
4724 f = x_window_to_frame (dpyinfo, hwnd);
4725 if (f)
4726 f->output_data.w32->menubar_active = 1;
4727
4728 if (TrackPopupMenu ((HMENU)wParam, flags, pos->x, pos->y,
4729 0, hwnd, NULL))
4730 {
4731 MSG amsg;
4732 /* Eat any mouse messages during popupmenu */
4733 while (PeekMessage (&amsg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST,
4734 PM_REMOVE));
4735 /* Get the menu selection, if any */
4736 if (PeekMessage (&amsg, hwnd, WM_COMMAND, WM_COMMAND, PM_REMOVE))
4737 {
4738 retval = LOWORD (amsg.wParam);
4739 }
4740 else
4741 {
4742 retval = 0;
4743 }
4744 }
4745 else
4746 {
4747 retval = -1;
4748 }
4749
4750 return retval;
4751 }
4752
4753 default:
4754 /* Check for messages registered at runtime. */
4755 if (msg == msh_mousewheel)
4756 {
4757 wmsg.dwModifiers = w32_get_modifiers ();
4758 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4759 return 0;
4760 }
4761
4762 dflt:
4763 return DefWindowProc (hwnd, msg, wParam, lParam);
4764 }
4765
4766
4767 /* The most common default return code for handled messages is 0. */
4768 return 0;
4769 }
4770
4771 void
4772 my_create_window (f)
4773 struct frame * f;
4774 {
4775 MSG msg;
4776
4777 if (!PostThreadMessage (dwWindowsThreadId, WM_EMACS_CREATEWINDOW, (WPARAM)f, 0))
4778 abort ();
4779 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
4780 }
4781
4782 /* Create and set up the w32 window for frame F. */
4783
4784 static void
4785 w32_window (f, window_prompting, minibuffer_only)
4786 struct frame *f;
4787 long window_prompting;
4788 int minibuffer_only;
4789 {
4790 BLOCK_INPUT;
4791
4792 /* Use the resource name as the top-level window name
4793 for looking up resources. Make a non-Lisp copy
4794 for the window manager, so GC relocation won't bother it.
4795
4796 Elsewhere we specify the window name for the window manager. */
4797
4798 {
4799 char *str = (char *) XSTRING (Vx_resource_name)->data;
4800 f->namebuf = (char *) xmalloc (strlen (str) + 1);
4801 strcpy (f->namebuf, str);
4802 }
4803
4804 my_create_window (f);
4805
4806 validate_x_resource_name ();
4807
4808 /* x_set_name normally ignores requests to set the name if the
4809 requested name is the same as the current name. This is the one
4810 place where that assumption isn't correct; f->name is set, but
4811 the server hasn't been told. */
4812 {
4813 Lisp_Object name;
4814 int explicit = f->explicit_name;
4815
4816 f->explicit_name = 0;
4817 name = f->name;
4818 f->name = Qnil;
4819 x_set_name (f, name, explicit);
4820 }
4821
4822 UNBLOCK_INPUT;
4823
4824 if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f))
4825 initialize_frame_menubar (f);
4826
4827 if (FRAME_W32_WINDOW (f) == 0)
4828 error ("Unable to create window");
4829 }
4830
4831 /* Handle the icon stuff for this window. Perhaps later we might
4832 want an x_set_icon_position which can be called interactively as
4833 well. */
4834
4835 static void
4836 x_icon (f, parms)
4837 struct frame *f;
4838 Lisp_Object parms;
4839 {
4840 Lisp_Object icon_x, icon_y;
4841
4842 /* Set the position of the icon. Note that Windows 95 groups all
4843 icons in the tray. */
4844 icon_x = w32_get_arg (parms, Qicon_left, 0, 0, RES_TYPE_NUMBER);
4845 icon_y = w32_get_arg (parms, Qicon_top, 0, 0, RES_TYPE_NUMBER);
4846 if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
4847 {
4848 CHECK_NUMBER (icon_x, 0);
4849 CHECK_NUMBER (icon_y, 0);
4850 }
4851 else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
4852 error ("Both left and top icon corners of icon must be specified");
4853
4854 BLOCK_INPUT;
4855
4856 if (! EQ (icon_x, Qunbound))
4857 x_wm_set_icon_position (f, XINT (icon_x), XINT (icon_y));
4858
4859 #if 0 /* TODO */
4860 /* Start up iconic or window? */
4861 x_wm_set_window_state
4862 (f, (EQ (w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL), Qicon)
4863 ? IconicState
4864 : NormalState));
4865
4866 x_text_icon (f, (char *) XSTRING ((!NILP (f->icon_name)
4867 ? f->icon_name
4868 : f->name))->data);
4869 #endif
4870
4871 UNBLOCK_INPUT;
4872 }
4873
4874
4875 static void
4876 x_make_gc (f)
4877 struct frame *f;
4878 {
4879 XGCValues gc_values;
4880
4881 BLOCK_INPUT;
4882
4883 /* Create the GC's of this frame.
4884 Note that many default values are used. */
4885
4886 /* Normal video */
4887 gc_values.font = f->output_data.w32->font;
4888
4889 /* Cursor has cursor-color background, background-color foreground. */
4890 gc_values.foreground = FRAME_BACKGROUND_PIXEL (f);
4891 gc_values.background = f->output_data.w32->cursor_pixel;
4892 f->output_data.w32->cursor_gc
4893 = XCreateGC (NULL, FRAME_W32_WINDOW (f),
4894 (GCFont | GCForeground | GCBackground),
4895 &gc_values);
4896
4897 /* Reliefs. */
4898 f->output_data.w32->white_relief.gc = 0;
4899 f->output_data.w32->black_relief.gc = 0;
4900
4901 UNBLOCK_INPUT;
4902 }
4903
4904
4905 DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
4906 1, 1, 0,
4907 "Make a new window, which is called a \"frame\" in Emacs terms.\n\
4908 Returns an Emacs frame object.\n\
4909 ALIST is an alist of frame parameters.\n\
4910 If the parameters specify that the frame should not have a minibuffer,\n\
4911 and do not specify a specific minibuffer window to use,\n\
4912 then `default-minibuffer-frame' must be a frame whose minibuffer can\n\
4913 be shared by the new frame.\n\
4914 \n\
4915 This function is an internal primitive--use `make-frame' instead.")
4916 (parms)
4917 Lisp_Object parms;
4918 {
4919 struct frame *f;
4920 Lisp_Object frame, tem;
4921 Lisp_Object name;
4922 int minibuffer_only = 0;
4923 long window_prompting = 0;
4924 int width, height;
4925 int count = specpdl_ptr - specpdl;
4926 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
4927 Lisp_Object display;
4928 struct w32_display_info *dpyinfo = NULL;
4929 Lisp_Object parent;
4930 struct kboard *kb;
4931
4932 check_w32 ();
4933
4934 /* Use this general default value to start with
4935 until we know if this frame has a specified name. */
4936 Vx_resource_name = Vinvocation_name;
4937
4938 display = w32_get_arg (parms, Qdisplay, 0, 0, RES_TYPE_STRING);
4939 if (EQ (display, Qunbound))
4940 display = Qnil;
4941 dpyinfo = check_x_display_info (display);
4942 #ifdef MULTI_KBOARD
4943 kb = dpyinfo->kboard;
4944 #else
4945 kb = &the_only_kboard;
4946 #endif
4947
4948 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
4949 if (!STRINGP (name)
4950 && ! EQ (name, Qunbound)
4951 && ! NILP (name))
4952 error ("Invalid frame name--not a string or nil");
4953
4954 if (STRINGP (name))
4955 Vx_resource_name = name;
4956
4957 /* See if parent window is specified. */
4958 parent = w32_get_arg (parms, Qparent_id, NULL, NULL, RES_TYPE_NUMBER);
4959 if (EQ (parent, Qunbound))
4960 parent = Qnil;
4961 if (! NILP (parent))
4962 CHECK_NUMBER (parent, 0);
4963
4964 /* make_frame_without_minibuffer can run Lisp code and garbage collect. */
4965 /* No need to protect DISPLAY because that's not used after passing
4966 it to make_frame_without_minibuffer. */
4967 frame = Qnil;
4968 GCPRO4 (parms, parent, name, frame);
4969 tem = w32_get_arg (parms, Qminibuffer, 0, 0, RES_TYPE_SYMBOL);
4970 if (EQ (tem, Qnone) || NILP (tem))
4971 f = make_frame_without_minibuffer (Qnil, kb, display);
4972 else if (EQ (tem, Qonly))
4973 {
4974 f = make_minibuffer_frame ();
4975 minibuffer_only = 1;
4976 }
4977 else if (WINDOWP (tem))
4978 f = make_frame_without_minibuffer (tem, kb, display);
4979 else
4980 f = make_frame (1);
4981
4982 XSETFRAME (frame, f);
4983
4984 /* Note that Windows does support scroll bars. */
4985 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
4986 /* By default, make scrollbars the system standard width. */
4987 f->scroll_bar_pixel_width = GetSystemMetrics (SM_CXVSCROLL);
4988
4989 f->output_method = output_w32;
4990 f->output_data.w32 =
4991 (struct w32_output *) xmalloc (sizeof (struct w32_output));
4992 bzero (f->output_data.w32, sizeof (struct w32_output));
4993
4994 FRAME_FONTSET (f) = -1;
4995
4996 f->icon_name
4997 = w32_get_arg (parms, Qicon_name, "iconName", "Title", RES_TYPE_STRING);
4998 if (! STRINGP (f->icon_name))
4999 f->icon_name = Qnil;
5000
5001 /* FRAME_W32_DISPLAY_INFO (f) = dpyinfo; */
5002 #ifdef MULTI_KBOARD
5003 FRAME_KBOARD (f) = kb;
5004 #endif
5005
5006 /* Specify the parent under which to make this window. */
5007
5008 if (!NILP (parent))
5009 {
5010 f->output_data.w32->parent_desc = (Window) parent;
5011 f->output_data.w32->explicit_parent = 1;
5012 }
5013 else
5014 {
5015 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
5016 f->output_data.w32->explicit_parent = 0;
5017 }
5018
5019 /* Set the name; the functions to which we pass f expect the name to
5020 be set. */
5021 if (EQ (name, Qunbound) || NILP (name))
5022 {
5023 f->name = build_string (dpyinfo->w32_id_name);
5024 f->explicit_name = 0;
5025 }
5026 else
5027 {
5028 f->name = name;
5029 f->explicit_name = 1;
5030 /* use the frame's title when getting resources for this frame. */
5031 specbind (Qx_resource_name, name);
5032 }
5033
5034 /* Create fontsets from `global_fontset_alist' before handling fonts. */
5035 for (tem = Vglobal_fontset_alist; CONSP (tem); tem = XCDR (tem))
5036 fs_register_fontset (f, XCAR (tem));
5037
5038 /* Extract the window parameters from the supplied values
5039 that are needed to determine window geometry. */
5040 {
5041 Lisp_Object font;
5042
5043 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
5044
5045 BLOCK_INPUT;
5046 /* First, try whatever font the caller has specified. */
5047 if (STRINGP (font))
5048 {
5049 tem = Fquery_fontset (font, Qnil);
5050 if (STRINGP (tem))
5051 font = x_new_fontset (f, XSTRING (tem)->data);
5052 else
5053 font = x_new_font (f, XSTRING (font)->data);
5054 }
5055 /* Try out a font which we hope has bold and italic variations. */
5056 if (!STRINGP (font))
5057 font = x_new_font (f, "-*-Courier New-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
5058 if (! STRINGP (font))
5059 font = x_new_font (f, "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
5060 /* If those didn't work, look for something which will at least work. */
5061 if (! STRINGP (font))
5062 font = x_new_font (f, "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1");
5063 UNBLOCK_INPUT;
5064 if (! STRINGP (font))
5065 font = build_string ("Fixedsys");
5066
5067 x_default_parameter (f, parms, Qfont, font,
5068 "font", "Font", RES_TYPE_STRING);
5069 }
5070
5071 x_default_parameter (f, parms, Qborder_width, make_number (2),
5072 "borderwidth", "BorderWidth", RES_TYPE_NUMBER);
5073 /* This defaults to 2 in order to match xterm. We recognize either
5074 internalBorderWidth or internalBorder (which is what xterm calls
5075 it). */
5076 if (NILP (Fassq (Qinternal_border_width, parms)))
5077 {
5078 Lisp_Object value;
5079
5080 value = w32_get_arg (parms, Qinternal_border_width,
5081 "internalBorder", "BorderWidth", RES_TYPE_NUMBER);
5082 if (! EQ (value, Qunbound))
5083 parms = Fcons (Fcons (Qinternal_border_width, value),
5084 parms);
5085 }
5086 /* Default internalBorderWidth to 0 on Windows to match other programs. */
5087 x_default_parameter (f, parms, Qinternal_border_width, make_number (0),
5088 "internalBorderWidth", "BorderWidth", RES_TYPE_NUMBER);
5089 x_default_parameter (f, parms, Qvertical_scroll_bars, Qt,
5090 "verticalScrollBars", "ScrollBars", RES_TYPE_BOOLEAN);
5091
5092 /* Also do the stuff which must be set before the window exists. */
5093 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
5094 "foreground", "Foreground", RES_TYPE_STRING);
5095 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
5096 "background", "Background", RES_TYPE_STRING);
5097 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
5098 "pointerColor", "Foreground", RES_TYPE_STRING);
5099 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
5100 "cursorColor", "Foreground", RES_TYPE_STRING);
5101 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
5102 "borderColor", "BorderColor", RES_TYPE_STRING);
5103 x_default_parameter (f, parms, Qscreen_gamma, Qnil,
5104 "screenGamma", "ScreenGamma", RES_TYPE_FLOAT);
5105
5106
5107 /* Init faces before x_default_parameter is called for scroll-bar
5108 parameters because that function calls x_set_scroll_bar_width,
5109 which calls change_frame_size, which calls Fset_window_buffer,
5110 which runs hooks, which call Fvertical_motion. At the end, we
5111 end up in init_iterator with a null face cache, which should not
5112 happen. */
5113 init_frame_faces (f);
5114
5115 x_default_parameter (f, parms, Qmenu_bar_lines, make_number (1),
5116 "menuBar", "MenuBar", RES_TYPE_NUMBER);
5117 x_default_parameter (f, parms, Qtool_bar_lines, make_number (0),
5118 "toolBar", "ToolBar", RES_TYPE_NUMBER);
5119 x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
5120 "bufferPredicate", "BufferPredicate", RES_TYPE_SYMBOL);
5121 x_default_parameter (f, parms, Qtitle, Qnil,
5122 "title", "Title", RES_TYPE_STRING);
5123
5124 f->output_data.w32->dwStyle = WS_OVERLAPPEDWINDOW;
5125 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
5126 window_prompting = x_figure_window_size (f, parms);
5127
5128 if (window_prompting & XNegative)
5129 {
5130 if (window_prompting & YNegative)
5131 f->output_data.w32->win_gravity = SouthEastGravity;
5132 else
5133 f->output_data.w32->win_gravity = NorthEastGravity;
5134 }
5135 else
5136 {
5137 if (window_prompting & YNegative)
5138 f->output_data.w32->win_gravity = SouthWestGravity;
5139 else
5140 f->output_data.w32->win_gravity = NorthWestGravity;
5141 }
5142
5143 f->output_data.w32->size_hint_flags = window_prompting;
5144
5145 tem = w32_get_arg (parms, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN);
5146 f->no_split = minibuffer_only || EQ (tem, Qt);
5147
5148 /* Create the window. Add the tool-bar height to the initial frame
5149 height so that the user gets a text display area of the size he
5150 specified with -g or via the registry. Later changes of the
5151 tool-bar height don't change the frame size. This is done so that
5152 users can create tall Emacs frames without having to guess how
5153 tall the tool-bar will get. */
5154 f->height += FRAME_TOOL_BAR_LINES (f);
5155 w32_window (f, window_prompting, minibuffer_only);
5156 x_icon (f, parms);
5157
5158 x_make_gc (f);
5159
5160 /* Now consider the frame official. */
5161 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
5162 Vframe_list = Fcons (frame, Vframe_list);
5163
5164 /* We need to do this after creating the window, so that the
5165 icon-creation functions can say whose icon they're describing. */
5166 x_default_parameter (f, parms, Qicon_type, Qnil,
5167 "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL);
5168
5169 x_default_parameter (f, parms, Qauto_raise, Qnil,
5170 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
5171 x_default_parameter (f, parms, Qauto_lower, Qnil,
5172 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
5173 x_default_parameter (f, parms, Qcursor_type, Qbox,
5174 "cursorType", "CursorType", RES_TYPE_SYMBOL);
5175 x_default_parameter (f, parms, Qscroll_bar_width, Qnil,
5176 "scrollBarWidth", "ScrollBarWidth", RES_TYPE_NUMBER);
5177
5178 /* Dimensions, especially f->height, must be done via change_frame_size.
5179 Change will not be effected unless different from the current
5180 f->height. */
5181 width = f->width;
5182 height = f->height;
5183 f->height = 0;
5184 SET_FRAME_WIDTH (f, 0);
5185 change_frame_size (f, height, width, 1, 0, 0);
5186
5187 /* Set up faces after all frame parameters are known. */
5188 call1 (Qface_set_after_frame_default, frame);
5189
5190 /* Tell the server what size and position, etc, we want, and how
5191 badly we want them. This should be done after we have the menu
5192 bar so that its size can be taken into account. */
5193 BLOCK_INPUT;
5194 x_wm_set_size_hint (f, window_prompting, 0);
5195 UNBLOCK_INPUT;
5196
5197 /* Make the window appear on the frame and enable display, unless
5198 the caller says not to. However, with explicit parent, Emacs
5199 cannot control visibility, so don't try. */
5200 if (! f->output_data.w32->explicit_parent)
5201 {
5202 Lisp_Object visibility;
5203
5204 visibility = w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL);
5205 if (EQ (visibility, Qunbound))
5206 visibility = Qt;
5207
5208 if (EQ (visibility, Qicon))
5209 x_iconify_frame (f);
5210 else if (! NILP (visibility))
5211 x_make_frame_visible (f);
5212 else
5213 /* Must have been Qnil. */
5214 ;
5215 }
5216 UNGCPRO;
5217 return unbind_to (count, frame);
5218 }
5219
5220 /* FRAME is used only to get a handle on the X display. We don't pass the
5221 display info directly because we're called from frame.c, which doesn't
5222 know about that structure. */
5223 Lisp_Object
5224 x_get_focus_frame (frame)
5225 struct frame *frame;
5226 {
5227 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (frame);
5228 Lisp_Object xfocus;
5229 if (! dpyinfo->w32_focus_frame)
5230 return Qnil;
5231
5232 XSETFRAME (xfocus, dpyinfo->w32_focus_frame);
5233 return xfocus;
5234 }
5235
5236 DEFUN ("w32-focus-frame", Fw32_focus_frame, Sw32_focus_frame, 1, 1, 0,
5237 "Give FRAME input focus, raising to foreground if necessary.")
5238 (frame)
5239 Lisp_Object frame;
5240 {
5241 x_focus_on_frame (check_x_frame (frame));
5242 return Qnil;
5243 }
5244
5245 \f
5246 struct font_info *w32_load_bdf_font (struct frame *f, char *fontname,
5247 int size, char* filename);
5248
5249 struct font_info *
5250 w32_load_system_font (f,fontname,size)
5251 struct frame *f;
5252 char * fontname;
5253 int size;
5254 {
5255 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
5256 Lisp_Object font_names;
5257
5258 /* Get a list of all the fonts that match this name. Once we
5259 have a list of matching fonts, we compare them against the fonts
5260 we already have loaded by comparing names. */
5261 font_names = w32_list_fonts (f, build_string (fontname), size, 100);
5262
5263 if (!NILP (font_names))
5264 {
5265 Lisp_Object tail;
5266 int i;
5267
5268 /* First check if any are already loaded, as that is cheaper
5269 than loading another one. */
5270 for (i = 0; i < dpyinfo->n_fonts; i++)
5271 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
5272 if (dpyinfo->font_table[i].name
5273 && (!strcmp (dpyinfo->font_table[i].name,
5274 XSTRING (XCAR (tail))->data)
5275 || !strcmp (dpyinfo->font_table[i].full_name,
5276 XSTRING (XCAR (tail))->data)))
5277 return (dpyinfo->font_table + i);
5278
5279 fontname = (char *) XSTRING (XCAR (font_names))->data;
5280 }
5281 else if (w32_strict_fontnames)
5282 {
5283 /* If EnumFontFamiliesEx was available, we got a full list of
5284 fonts back so stop now to avoid the possibility of loading a
5285 random font. If we had to fall back to EnumFontFamilies, the
5286 list is incomplete, so continue whether the font we want was
5287 listed or not. */
5288 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
5289 FARPROC enum_font_families_ex
5290 = GetProcAddress (gdi32, "EnumFontFamiliesExA");
5291 if (enum_font_families_ex)
5292 return NULL;
5293 }
5294
5295 /* Load the font and add it to the table. */
5296 {
5297 char *full_name, *encoding;
5298 XFontStruct *font;
5299 struct font_info *fontp;
5300 LOGFONT lf;
5301 BOOL ok;
5302 int i;
5303
5304 if (!fontname || !x_to_w32_font (fontname, &lf))
5305 return (NULL);
5306
5307 if (!*lf.lfFaceName)
5308 /* If no name was specified for the font, we get a random font
5309 from CreateFontIndirect - this is not particularly
5310 desirable, especially since CreateFontIndirect does not
5311 fill out the missing name in lf, so we never know what we
5312 ended up with. */
5313 return NULL;
5314
5315 font = (XFontStruct *) xmalloc (sizeof (XFontStruct));
5316
5317 /* Set bdf to NULL to indicate that this is a Windows font. */
5318 font->bdf = NULL;
5319
5320 BLOCK_INPUT;
5321
5322 font->hfont = CreateFontIndirect (&lf);
5323
5324 if (font->hfont == NULL)
5325 {
5326 ok = FALSE;
5327 }
5328 else
5329 {
5330 HDC hdc;
5331 HANDLE oldobj;
5332
5333 hdc = GetDC (dpyinfo->root_window);
5334 oldobj = SelectObject (hdc, font->hfont);
5335 ok = GetTextMetrics (hdc, &font->tm);
5336 SelectObject (hdc, oldobj);
5337 ReleaseDC (dpyinfo->root_window, hdc);
5338 /* Fill out details in lf according to the font that was
5339 actually loaded. */
5340 lf.lfHeight = font->tm.tmInternalLeading - font->tm.tmHeight;
5341 lf.lfWidth = font->tm.tmAveCharWidth;
5342 lf.lfWeight = font->tm.tmWeight;
5343 lf.lfItalic = font->tm.tmItalic;
5344 lf.lfCharSet = font->tm.tmCharSet;
5345 lf.lfPitchAndFamily = ((font->tm.tmPitchAndFamily & TMPF_FIXED_PITCH)
5346 ? FIXED_PITCH : VARIABLE_PITCH);
5347 lf.lfOutPrecision = ((font->tm.tmPitchAndFamily & TMPF_VECTOR)
5348 ? OUT_STROKE_PRECIS : OUT_STRING_PRECIS);
5349 }
5350
5351 UNBLOCK_INPUT;
5352
5353 if (!ok)
5354 {
5355 w32_unload_font (dpyinfo, font);
5356 return (NULL);
5357 }
5358
5359 /* Find a free slot in the font table. */
5360 for (i = 0; i < dpyinfo->n_fonts; ++i)
5361 if (dpyinfo->font_table[i].name == NULL)
5362 break;
5363
5364 /* If no free slot found, maybe enlarge the font table. */
5365 if (i == dpyinfo->n_fonts
5366 && dpyinfo->n_fonts == dpyinfo->font_table_size)
5367 {
5368 int sz;
5369 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
5370 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
5371 dpyinfo->font_table
5372 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
5373 }
5374
5375 fontp = dpyinfo->font_table + i;
5376 if (i == dpyinfo->n_fonts)
5377 ++dpyinfo->n_fonts;
5378
5379 /* Now fill in the slots of *FONTP. */
5380 BLOCK_INPUT;
5381 fontp->font = font;
5382 fontp->font_idx = i;
5383 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
5384 bcopy (fontname, fontp->name, strlen (fontname) + 1);
5385
5386 /* Work out the font's full name. */
5387 full_name = (char *)xmalloc (100);
5388 if (full_name && w32_to_x_font (&lf, full_name, 100))
5389 fontp->full_name = full_name;
5390 else
5391 {
5392 /* If all else fails - just use the name we used to load it. */
5393 xfree (full_name);
5394 fontp->full_name = fontp->name;
5395 }
5396
5397 fontp->size = FONT_WIDTH (font);
5398 fontp->height = FONT_HEIGHT (font);
5399
5400 /* The slot `encoding' specifies how to map a character
5401 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
5402 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF, 0:0x2020..0x7F7F,
5403 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF,
5404 0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF, or
5405 2:0xA020..0xFF7F). For the moment, we don't know which charset
5406 uses this font. So, we set information in fontp->encoding[1]
5407 which is never used by any charset. If mapping can't be
5408 decided, set FONT_ENCODING_NOT_DECIDED. */
5409
5410 /* SJIS fonts need to be set to type 4, all others seem to work as
5411 type FONT_ENCODING_NOT_DECIDED. */
5412 encoding = strrchr (fontp->name, '-');
5413 if (encoding && stricmp (encoding+1, "sjis") == 0)
5414 fontp->encoding[1] = 4;
5415 else
5416 fontp->encoding[1] = FONT_ENCODING_NOT_DECIDED;
5417
5418 /* The following three values are set to 0 under W32, which is
5419 what they get set to if XGetFontProperty fails under X. */
5420 fontp->baseline_offset = 0;
5421 fontp->relative_compose = 0;
5422 fontp->default_ascent = 0;
5423
5424 /* Set global flag fonts_changed_p to non-zero if the font loaded
5425 has a character with a smaller width than any other character
5426 before, or if the font loaded has a smalle>r height than any
5427 other font loaded before. If this happens, it will make a
5428 glyph matrix reallocation necessary. */
5429 fonts_changed_p = x_compute_min_glyph_bounds (f);
5430 UNBLOCK_INPUT;
5431 return fontp;
5432 }
5433 }
5434
5435 /* Load font named FONTNAME of size SIZE for frame F, and return a
5436 pointer to the structure font_info while allocating it dynamically.
5437 If loading fails, return NULL. */
5438 struct font_info *
5439 w32_load_font (f,fontname,size)
5440 struct frame *f;
5441 char * fontname;
5442 int size;
5443 {
5444 Lisp_Object bdf_fonts;
5445 struct font_info *retval = NULL;
5446
5447 bdf_fonts = w32_list_bdf_fonts (build_string (fontname));
5448
5449 while (!retval && CONSP (bdf_fonts))
5450 {
5451 char *bdf_name, *bdf_file;
5452 Lisp_Object bdf_pair;
5453
5454 bdf_name = XSTRING (XCAR (bdf_fonts))->data;
5455 bdf_pair = Fassoc (XCAR (bdf_fonts), Vw32_bdf_filename_alist);
5456 bdf_file = XSTRING (XCDR (bdf_pair))->data;
5457
5458 retval = w32_load_bdf_font (f, bdf_name, size, bdf_file);
5459
5460 bdf_fonts = XCDR (bdf_fonts);
5461 }
5462
5463 if (retval)
5464 return retval;
5465
5466 return w32_load_system_font(f, fontname, size);
5467 }
5468
5469
5470 void
5471 w32_unload_font (dpyinfo, font)
5472 struct w32_display_info *dpyinfo;
5473 XFontStruct * font;
5474 {
5475 if (font)
5476 {
5477 if (font->bdf) w32_free_bdf_font (font->bdf);
5478
5479 if (font->hfont) DeleteObject(font->hfont);
5480 xfree (font);
5481 }
5482 }
5483
5484 /* The font conversion stuff between x and w32 */
5485
5486 /* X font string is as follows (from faces.el)
5487 * (let ((- "[-?]")
5488 * (foundry "[^-]+")
5489 * (family "[^-]+")
5490 * (weight "\\(bold\\|demibold\\|medium\\)") ; 1
5491 * (weight\? "\\([^-]*\\)") ; 1
5492 * (slant "\\([ior]\\)") ; 2
5493 * (slant\? "\\([^-]?\\)") ; 2
5494 * (swidth "\\([^-]*\\)") ; 3
5495 * (adstyle "[^-]*") ; 4
5496 * (pixelsize "[0-9]+")
5497 * (pointsize "[0-9][0-9]+")
5498 * (resx "[0-9][0-9]+")
5499 * (resy "[0-9][0-9]+")
5500 * (spacing "[cmp?*]")
5501 * (avgwidth "[0-9]+")
5502 * (registry "[^-]+")
5503 * (encoding "[^-]+")
5504 * )
5505 * (setq x-font-regexp
5506 * (concat "\\`\\*?[-?*]"
5507 * foundry - family - weight\? - slant\? - swidth - adstyle -
5508 * pixelsize - pointsize - resx - resy - spacing - registry -
5509 * encoding "[-?*]\\*?\\'"
5510 * ))
5511 * (setq x-font-regexp-head
5512 * (concat "\\`[-?*]" foundry - family - weight\? - slant\?
5513 * "\\([-*?]\\|\\'\\)"))
5514 * (setq x-font-regexp-slant (concat - slant -))
5515 * (setq x-font-regexp-weight (concat - weight -))
5516 * nil)
5517 */
5518
5519 #define FONT_START "[-?]"
5520 #define FONT_FOUNDRY "[^-]+"
5521 #define FONT_FAMILY "\\([^-]+\\)" /* 1 */
5522 #define FONT_WEIGHT "\\(bold\\|demibold\\|medium\\)" /* 2 */
5523 #define FONT_WEIGHT_Q "\\([^-]*\\)" /* 2 */
5524 #define FONT_SLANT "\\([ior]\\)" /* 3 */
5525 #define FONT_SLANT_Q "\\([^-]?\\)" /* 3 */
5526 #define FONT_SWIDTH "\\([^-]*\\)" /* 4 */
5527 #define FONT_ADSTYLE "[^-]*"
5528 #define FONT_PIXELSIZE "[^-]*"
5529 #define FONT_POINTSIZE "\\([0-9][0-9]+\\|\\*\\)" /* 5 */
5530 #define FONT_RESX "[0-9][0-9]+"
5531 #define FONT_RESY "[0-9][0-9]+"
5532 #define FONT_SPACING "[cmp?*]"
5533 #define FONT_AVGWIDTH "[0-9]+"
5534 #define FONT_REGISTRY "[^-]+"
5535 #define FONT_ENCODING "[^-]+"
5536
5537 #define FONT_REGEXP ("\\`\\*?[-?*]" \
5538 FONT_FOUNDRY "-" \
5539 FONT_FAMILY "-" \
5540 FONT_WEIGHT_Q "-" \
5541 FONT_SLANT_Q "-" \
5542 FONT_SWIDTH "-" \
5543 FONT_ADSTYLE "-" \
5544 FONT_PIXELSIZE "-" \
5545 FONT_POINTSIZE "-" \
5546 "[-?*]\\|\\'")
5547
5548 #define FONT_REGEXP_HEAD ("\\`[-?*]" \
5549 FONT_FOUNDRY "-" \
5550 FONT_FAMILY "-" \
5551 FONT_WEIGHT_Q "-" \
5552 FONT_SLANT_Q \
5553 "\\([-*?]\\|\\'\\)")
5554
5555 #define FONT_REGEXP_SLANT "-" FONT_SLANT "-"
5556 #define FONT_REGEXP_WEIGHT "-" FONT_WEIGHT "-"
5557
5558 LONG
5559 x_to_w32_weight (lpw)
5560 char * lpw;
5561 {
5562 if (!lpw) return (FW_DONTCARE);
5563
5564 if (stricmp (lpw,"heavy") == 0) return FW_HEAVY;
5565 else if (stricmp (lpw,"extrabold") == 0) return FW_EXTRABOLD;
5566 else if (stricmp (lpw,"bold") == 0) return FW_BOLD;
5567 else if (stricmp (lpw,"demibold") == 0) return FW_SEMIBOLD;
5568 else if (stricmp (lpw,"semibold") == 0) return FW_SEMIBOLD;
5569 else if (stricmp (lpw,"medium") == 0) return FW_MEDIUM;
5570 else if (stricmp (lpw,"normal") == 0) return FW_NORMAL;
5571 else if (stricmp (lpw,"light") == 0) return FW_LIGHT;
5572 else if (stricmp (lpw,"extralight") == 0) return FW_EXTRALIGHT;
5573 else if (stricmp (lpw,"thin") == 0) return FW_THIN;
5574 else
5575 return FW_DONTCARE;
5576 }
5577
5578
5579 char *
5580 w32_to_x_weight (fnweight)
5581 int fnweight;
5582 {
5583 if (fnweight >= FW_HEAVY) return "heavy";
5584 if (fnweight >= FW_EXTRABOLD) return "extrabold";
5585 if (fnweight >= FW_BOLD) return "bold";
5586 if (fnweight >= FW_SEMIBOLD) return "demibold";
5587 if (fnweight >= FW_MEDIUM) return "medium";
5588 if (fnweight >= FW_NORMAL) return "normal";
5589 if (fnweight >= FW_LIGHT) return "light";
5590 if (fnweight >= FW_EXTRALIGHT) return "extralight";
5591 if (fnweight >= FW_THIN) return "thin";
5592 else
5593 return "*";
5594 }
5595
5596 LONG
5597 x_to_w32_charset (lpcs)
5598 char * lpcs;
5599 {
5600 if (!lpcs) return (0);
5601
5602 if (stricmp (lpcs,"ansi") == 0) return ANSI_CHARSET;
5603 else if (stricmp (lpcs,"iso8859-1") == 0) return ANSI_CHARSET;
5604 else if (stricmp (lpcs, "ms-symbol") == 0) return SYMBOL_CHARSET;
5605 /* Map all Japanese charsets to the Windows Shift-JIS charset. */
5606 else if (strnicmp (lpcs, "jis", 3) == 0) return SHIFTJIS_CHARSET;
5607 /* Map all GB charsets to the Windows GB2312 charset. */
5608 else if (strnicmp (lpcs, "gb2312", 6) == 0) return GB2312_CHARSET;
5609 /* Map all Big5 charsets to the Windows Big5 charset. */
5610 else if (strnicmp (lpcs, "big5", 4) == 0) return CHINESEBIG5_CHARSET;
5611 else if (stricmp (lpcs, "ksc5601.1987") == 0) return HANGEUL_CHARSET;
5612 else if (stricmp (lpcs, "ms-oem") == 0) return OEM_CHARSET;
5613
5614 #ifdef EASTEUROPE_CHARSET
5615 else if (stricmp (lpcs, "iso8859-2") == 0) return EASTEUROPE_CHARSET;
5616 else if (stricmp (lpcs, "iso8859-3") == 0) return TURKISH_CHARSET;
5617 else if (stricmp (lpcs, "iso8859-4") == 0) return BALTIC_CHARSET;
5618 else if (stricmp (lpcs, "iso8859-5") == 0) return RUSSIAN_CHARSET;
5619 else if (stricmp (lpcs, "koi8") == 0) return RUSSIAN_CHARSET;
5620 else if (stricmp (lpcs, "iso8859-6") == 0) return ARABIC_CHARSET;
5621 else if (stricmp (lpcs, "iso8859-7") == 0) return GREEK_CHARSET;
5622 else if (stricmp (lpcs, "iso8859-8") == 0) return HEBREW_CHARSET;
5623 else if (stricmp (lpcs, "iso8859-9") == 0) return TURKISH_CHARSET;
5624 #ifndef VIETNAMESE_CHARSET
5625 #define VIETNAMESE_CHARSET 163
5626 #endif
5627 /* Map all Viscii charsets to the Windows Vietnamese charset. */
5628 else if (strnicmp (lpcs, "viscii", 6) == 0) return VIETNAMESE_CHARSET;
5629 else if (strnicmp (lpcs, "vscii", 5) == 0) return VIETNAMESE_CHARSET;
5630 /* Map all TIS charsets to the Windows Thai charset. */
5631 else if (strnicmp (lpcs, "tis620", 6) == 0) return THAI_CHARSET;
5632 else if (stricmp (lpcs, "mac") == 0) return MAC_CHARSET;
5633 else if (stricmp (lpcs, "ksc5601.1992") == 0) return JOHAB_CHARSET;
5634 /* For backwards compatibility with previous 20.4 pretests, map
5635 non-specific KSC charsets to the Windows Hangeul charset. */
5636 else if (strnicmp (lpcs, "ksc5601", 7) == 0) return HANGEUL_CHARSET;
5637 else if (stricmp (lpcs, "johab") == 0) return JOHAB_CHARSET;
5638 #endif
5639
5640 #ifdef UNICODE_CHARSET
5641 else if (stricmp (lpcs,"iso10646") == 0) return UNICODE_CHARSET;
5642 else if (stricmp (lpcs, "unicode") == 0) return UNICODE_CHARSET;
5643 #endif
5644 else if (lpcs[0] == '#') return atoi (lpcs + 1);
5645 else
5646 return DEFAULT_CHARSET;
5647 }
5648
5649 char *
5650 w32_to_x_charset (fncharset)
5651 int fncharset;
5652 {
5653 static char buf[16];
5654
5655 switch (fncharset)
5656 {
5657 /* ansi is considered iso8859-1, as most modern ansi fonts are. */
5658 case ANSI_CHARSET: return "iso8859-1";
5659 case DEFAULT_CHARSET: return "ascii-*";
5660 case SYMBOL_CHARSET: return "ms-symbol";
5661 case SHIFTJIS_CHARSET: return "jisx0208-sjis";
5662 case HANGEUL_CHARSET: return "ksc5601.1987-*";
5663 case GB2312_CHARSET: return "gb2312-*";
5664 case CHINESEBIG5_CHARSET: return "big5-*";
5665 case OEM_CHARSET: return "ms-oem";
5666
5667 /* More recent versions of Windows (95 and NT4.0) define more
5668 character sets. */
5669 #ifdef EASTEUROPE_CHARSET
5670 case EASTEUROPE_CHARSET: return "iso8859-2";
5671 case TURKISH_CHARSET: return "iso8859-9";
5672 case BALTIC_CHARSET: return "iso8859-4";
5673
5674 /* W95 with international support but not IE4 often has the
5675 KOI8-R codepage but not ISO8859-5. */
5676 case RUSSIAN_CHARSET:
5677 if (!IsValidCodePage(28595) && IsValidCodePage(20886))
5678 return "koi8-r";
5679 else
5680 return "iso8859-5";
5681 case ARABIC_CHARSET: return "iso8859-6";
5682 case GREEK_CHARSET: return "iso8859-7";
5683 case HEBREW_CHARSET: return "iso8859-8";
5684 case VIETNAMESE_CHARSET: return "viscii1.1-*";
5685 case THAI_CHARSET: return "tis620-*";
5686 case MAC_CHARSET: return "mac-*";
5687 case JOHAB_CHARSET: return "ksc5601.1992-*";
5688
5689 #endif
5690
5691 #ifdef UNICODE_CHARSET
5692 case UNICODE_CHARSET: return "iso10646-unicode";
5693 #endif
5694 }
5695 /* Encode numerical value of unknown charset. */
5696 sprintf (buf, "*-#%u", fncharset);
5697 return buf;
5698 }
5699
5700 BOOL
5701 w32_to_x_font (lplogfont, lpxstr, len)
5702 LOGFONT * lplogfont;
5703 char * lpxstr;
5704 int len;
5705 {
5706 char* fonttype;
5707 char *fontname;
5708 char height_pixels[8];
5709 char height_dpi[8];
5710 char width_pixels[8];
5711 char *fontname_dash;
5712 int display_resy = one_w32_display_info.height_in;
5713 int display_resx = one_w32_display_info.width_in;
5714 int bufsz;
5715 struct coding_system coding;
5716
5717 if (!lpxstr) abort ();
5718
5719 if (!lplogfont)
5720 return FALSE;
5721
5722 if (lplogfont->lfOutPrecision == OUT_STRING_PRECIS)
5723 fonttype = "raster";
5724 else if (lplogfont->lfOutPrecision == OUT_STROKE_PRECIS)
5725 fonttype = "outline";
5726 else
5727 fonttype = "unknown";
5728
5729 setup_coding_system (Fcheck_coding_system (Vw32_system_coding_system),
5730 &coding);
5731 coding.mode |= CODING_MODE_LAST_BLOCK;
5732 bufsz = decoding_buffer_size (&coding, LF_FACESIZE);
5733
5734 fontname = alloca(sizeof(*fontname) * bufsz);
5735 decode_coding (&coding, lplogfont->lfFaceName, fontname,
5736 strlen(lplogfont->lfFaceName), bufsz - 1);
5737 *(fontname + coding.produced) = '\0';
5738
5739 /* Replace dashes with underscores so the dashes are not
5740 misinterpreted. */
5741 fontname_dash = fontname;
5742 while (fontname_dash = strchr (fontname_dash, '-'))
5743 *fontname_dash = '_';
5744
5745 if (lplogfont->lfHeight)
5746 {
5747 sprintf (height_pixels, "%u", abs (lplogfont->lfHeight));
5748 sprintf (height_dpi, "%u",
5749 abs (lplogfont->lfHeight) * 720 / display_resy);
5750 }
5751 else
5752 {
5753 strcpy (height_pixels, "*");
5754 strcpy (height_dpi, "*");
5755 }
5756 if (lplogfont->lfWidth)
5757 sprintf (width_pixels, "%u", lplogfont->lfWidth * 10);
5758 else
5759 strcpy (width_pixels, "*");
5760
5761 _snprintf (lpxstr, len - 1,
5762 "-%s-%s-%s-%c-normal-normal-%s-%s-%d-%d-%c-%s-%s",
5763 fonttype, /* foundry */
5764 fontname, /* family */
5765 w32_to_x_weight (lplogfont->lfWeight), /* weight */
5766 lplogfont->lfItalic?'i':'r', /* slant */
5767 /* setwidth name */
5768 /* add style name */
5769 height_pixels, /* pixel size */
5770 height_dpi, /* point size */
5771 display_resx, /* resx */
5772 display_resy, /* resy */
5773 ((lplogfont->lfPitchAndFamily & 0x3) == VARIABLE_PITCH)
5774 ? 'p' : 'c', /* spacing */
5775 width_pixels, /* avg width */
5776 w32_to_x_charset (lplogfont->lfCharSet) /* charset registry
5777 and encoding*/
5778 );
5779
5780 lpxstr[len - 1] = 0; /* just to be sure */
5781 return (TRUE);
5782 }
5783
5784 BOOL
5785 x_to_w32_font (lpxstr, lplogfont)
5786 char * lpxstr;
5787 LOGFONT * lplogfont;
5788 {
5789 struct coding_system coding;
5790
5791 if (!lplogfont) return (FALSE);
5792
5793 memset (lplogfont, 0, sizeof (*lplogfont));
5794
5795 /* Set default value for each field. */
5796 #if 1
5797 lplogfont->lfOutPrecision = OUT_DEFAULT_PRECIS;
5798 lplogfont->lfClipPrecision = CLIP_DEFAULT_PRECIS;
5799 lplogfont->lfQuality = DEFAULT_QUALITY;
5800 #else
5801 /* go for maximum quality */
5802 lplogfont->lfOutPrecision = OUT_STROKE_PRECIS;
5803 lplogfont->lfClipPrecision = CLIP_STROKE_PRECIS;
5804 lplogfont->lfQuality = PROOF_QUALITY;
5805 #endif
5806
5807 lplogfont->lfCharSet = DEFAULT_CHARSET;
5808 lplogfont->lfWeight = FW_DONTCARE;
5809 lplogfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
5810
5811 if (!lpxstr)
5812 return FALSE;
5813
5814 /* Provide a simple escape mechanism for specifying Windows font names
5815 * directly -- if font spec does not beginning with '-', assume this
5816 * format:
5817 * "<font name>[:height in pixels[:width in pixels[:weight]]]"
5818 */
5819
5820 if (*lpxstr == '-')
5821 {
5822 int fields, tem;
5823 char name[50], weight[20], slant, pitch, pixels[10], height[10],
5824 width[10], resy[10], remainder[20];
5825 char * encoding;
5826 int dpi = one_w32_display_info.height_in;
5827
5828 fields = sscanf (lpxstr,
5829 "-%*[^-]-%49[^-]-%19[^-]-%c-%*[^-]-%*[^-]-%9[^-]-%9[^-]-%*[^-]-%9[^-]-%c-%9[^-]-%19s",
5830 name, weight, &slant, pixels, height, resy, &pitch, width, remainder);
5831 if (fields == EOF) return (FALSE);
5832
5833 /* If wildcards cover more than one field, we don't know which
5834 field is which, so don't fill any in. */
5835
5836 if (fields < 9)
5837 fields = 0;
5838
5839 if (fields > 0 && name[0] != '*')
5840 {
5841 int bufsize;
5842 unsigned char *buf;
5843
5844 setup_coding_system
5845 (Fcheck_coding_system (Vw32_system_coding_system), &coding);
5846 bufsize = encoding_buffer_size (&coding, strlen (name));
5847 buf = (unsigned char *) alloca (bufsize);
5848 coding.mode |= CODING_MODE_LAST_BLOCK;
5849 encode_coding (&coding, name, buf, strlen (name), bufsize);
5850 if (coding.produced >= LF_FACESIZE)
5851 coding.produced = LF_FACESIZE - 1;
5852 buf[coding.produced] = 0;
5853 strcpy (lplogfont->lfFaceName, buf);
5854 }
5855 else
5856 {
5857 lplogfont->lfFaceName[0] = '\0';
5858 }
5859
5860 fields--;
5861
5862 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
5863
5864 fields--;
5865
5866 if (!NILP (Vw32_enable_synthesized_fonts))
5867 lplogfont->lfItalic = (fields > 0 && slant == 'i');
5868
5869 fields--;
5870
5871 if (fields > 0 && pixels[0] != '*')
5872 lplogfont->lfHeight = atoi (pixels);
5873
5874 fields--;
5875 fields--;
5876 if (fields > 0 && resy[0] != '*')
5877 {
5878 tem = atoi (resy);
5879 if (tem > 0) dpi = tem;
5880 }
5881
5882 if (fields > -1 && lplogfont->lfHeight == 0 && height[0] != '*')
5883 lplogfont->lfHeight = atoi (height) * dpi / 720;
5884
5885 if (fields > 0)
5886 lplogfont->lfPitchAndFamily =
5887 (fields > 0 && pitch == 'p') ? VARIABLE_PITCH : FIXED_PITCH;
5888
5889 fields--;
5890
5891 if (fields > 0 && width[0] != '*')
5892 lplogfont->lfWidth = atoi (width) / 10;
5893
5894 fields--;
5895
5896 /* Strip the trailing '-' if present. (it shouldn't be, as it
5897 fails the test against xlfn-tight-regexp in fontset.el). */
5898 {
5899 int len = strlen (remainder);
5900 if (len > 0 && remainder[len-1] == '-')
5901 remainder[len-1] = 0;
5902 }
5903 encoding = remainder;
5904 if (strncmp (encoding, "*-", 2) == 0)
5905 encoding += 2;
5906 lplogfont->lfCharSet = x_to_w32_charset (fields > 0 ? encoding : "");
5907 }
5908 else
5909 {
5910 int fields;
5911 char name[100], height[10], width[10], weight[20];
5912
5913 fields = sscanf (lpxstr,
5914 "%99[^:]:%9[^:]:%9[^:]:%19s",
5915 name, height, width, weight);
5916
5917 if (fields == EOF) return (FALSE);
5918
5919 if (fields > 0)
5920 {
5921 strncpy (lplogfont->lfFaceName,name, LF_FACESIZE);
5922 lplogfont->lfFaceName[LF_FACESIZE-1] = 0;
5923 }
5924 else
5925 {
5926 lplogfont->lfFaceName[0] = 0;
5927 }
5928
5929 fields--;
5930
5931 if (fields > 0)
5932 lplogfont->lfHeight = atoi (height);
5933
5934 fields--;
5935
5936 if (fields > 0)
5937 lplogfont->lfWidth = atoi (width);
5938
5939 fields--;
5940
5941 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
5942 }
5943
5944 /* This makes TrueType fonts work better. */
5945 lplogfont->lfHeight = - abs (lplogfont->lfHeight);
5946
5947 return (TRUE);
5948 }
5949
5950 /* Assume parameter 1 is fully qualified, no wildcards. */
5951 BOOL
5952 w32_font_match (fontname, pattern)
5953 char * fontname;
5954 char * pattern;
5955 {
5956 char *regex = alloca (strlen (pattern) * 2);
5957 char *ptr;
5958
5959 ptr = regex;
5960 *ptr++ = '^';
5961
5962 /* Turn pattern into a regexp and do a regexp match. */
5963 for (; *pattern; pattern++)
5964 {
5965 if (*pattern == '?')
5966 *ptr++ = '.';
5967 else if (*pattern == '*')
5968 {
5969 *ptr++ = '.';
5970 *ptr++ = '*';
5971 }
5972 else
5973 *ptr++ = *pattern;
5974 }
5975 *ptr = '$';
5976 *(ptr + 1) = '\0';
5977
5978 return (fast_c_string_match_ignore_case (build_string (regex),
5979 fontname) >= 0);
5980 }
5981
5982 /* Callback functions, and a structure holding info they need, for
5983 listing system fonts on W32. We need one set of functions to do the
5984 job properly, but these don't work on NT 3.51 and earlier, so we
5985 have a second set which don't handle character sets properly to
5986 fall back on.
5987
5988 In both cases, there are two passes made. The first pass gets one
5989 font from each family, the second pass lists all the fonts from
5990 each family. */
5991
5992 typedef struct enumfont_t
5993 {
5994 HDC hdc;
5995 int numFonts;
5996 LOGFONT logfont;
5997 XFontStruct *size_ref;
5998 Lisp_Object *pattern;
5999 Lisp_Object *tail;
6000 } enumfont_t;
6001
6002 int CALLBACK
6003 enum_font_cb2 (lplf, lptm, FontType, lpef)
6004 ENUMLOGFONT * lplf;
6005 NEWTEXTMETRIC * lptm;
6006 int FontType;
6007 enumfont_t * lpef;
6008 {
6009 if (lplf->elfLogFont.lfStrikeOut || lplf->elfLogFont.lfUnderline)
6010 return (1);
6011
6012 /* Check that the character set matches if it was specified */
6013 if (lpef->logfont.lfCharSet != DEFAULT_CHARSET &&
6014 lplf->elfLogFont.lfCharSet != lpef->logfont.lfCharSet)
6015 return (1);
6016
6017 {
6018 char buf[100];
6019 Lisp_Object width = Qnil;
6020
6021 /* Truetype fonts do not report their true metrics until loaded */
6022 if (FontType != RASTER_FONTTYPE)
6023 {
6024 if (!NILP (*(lpef->pattern)))
6025 {
6026 /* Scalable fonts are as big as you want them to be. */
6027 lplf->elfLogFont.lfHeight = lpef->logfont.lfHeight;
6028 lplf->elfLogFont.lfWidth = lpef->logfont.lfWidth;
6029 width = make_number (lpef->logfont.lfWidth);
6030 }
6031 else
6032 {
6033 lplf->elfLogFont.lfHeight = 0;
6034 lplf->elfLogFont.lfWidth = 0;
6035 }
6036 }
6037
6038 /* Make sure the height used here is the same as everywhere
6039 else (ie character height, not cell height). */
6040 if (lplf->elfLogFont.lfHeight > 0)
6041 {
6042 /* lptm can be trusted for RASTER fonts, but not scalable ones. */
6043 if (FontType == RASTER_FONTTYPE)
6044 lplf->elfLogFont.lfHeight = lptm->tmInternalLeading - lptm->tmHeight;
6045 else
6046 lplf->elfLogFont.lfHeight = -lplf->elfLogFont.lfHeight;
6047 }
6048
6049 if (!w32_to_x_font (&(lplf->elfLogFont), buf, 100))
6050 return (0);
6051
6052 if (NILP (*(lpef->pattern))
6053 || w32_font_match (buf, XSTRING (*(lpef->pattern))->data))
6054 {
6055 *lpef->tail = Fcons (Fcons (build_string (buf), width), Qnil);
6056 lpef->tail = &(XCDR (*lpef->tail));
6057 lpef->numFonts++;
6058 }
6059 }
6060
6061 return (1);
6062 }
6063
6064 int CALLBACK
6065 enum_font_cb1 (lplf, lptm, FontType, lpef)
6066 ENUMLOGFONT * lplf;
6067 NEWTEXTMETRIC * lptm;
6068 int FontType;
6069 enumfont_t * lpef;
6070 {
6071 return EnumFontFamilies (lpef->hdc,
6072 lplf->elfLogFont.lfFaceName,
6073 (FONTENUMPROC) enum_font_cb2,
6074 (LPARAM) lpef);
6075 }
6076
6077
6078 int CALLBACK
6079 enum_fontex_cb2 (lplf, lptm, font_type, lpef)
6080 ENUMLOGFONTEX * lplf;
6081 NEWTEXTMETRICEX * lptm;
6082 int font_type;
6083 enumfont_t * lpef;
6084 {
6085 /* We are not interested in the extra info we get back from the 'Ex
6086 version - only the fact that we get character set variations
6087 enumerated seperately. */
6088 return enum_font_cb2 ((ENUMLOGFONT *) lplf, (NEWTEXTMETRIC *) lptm,
6089 font_type, lpef);
6090 }
6091
6092 int CALLBACK
6093 enum_fontex_cb1 (lplf, lptm, font_type, lpef)
6094 ENUMLOGFONTEX * lplf;
6095 NEWTEXTMETRICEX * lptm;
6096 int font_type;
6097 enumfont_t * lpef;
6098 {
6099 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
6100 FARPROC enum_font_families_ex
6101 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
6102 /* We don't really expect EnumFontFamiliesEx to disappear once we
6103 get here, so don't bother handling it gracefully. */
6104 if (enum_font_families_ex == NULL)
6105 error ("gdi32.dll has disappeared!");
6106 return enum_font_families_ex (lpef->hdc,
6107 &lplf->elfLogFont,
6108 (FONTENUMPROC) enum_fontex_cb2,
6109 (LPARAM) lpef, 0);
6110 }
6111
6112 /* Interface to fontset handler. (adapted from mw32font.c in Meadow
6113 and xterm.c in Emacs 20.3) */
6114
6115 Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names)
6116 {
6117 char *fontname, *ptnstr;
6118 Lisp_Object list, tem, newlist = Qnil;
6119 int n_fonts = 0;
6120
6121 list = Vw32_bdf_filename_alist;
6122 ptnstr = XSTRING (pattern)->data;
6123
6124 for ( ; CONSP (list); list = XCDR (list))
6125 {
6126 tem = XCAR (list);
6127 if (CONSP (tem))
6128 fontname = XSTRING (XCAR (tem))->data;
6129 else if (STRINGP (tem))
6130 fontname = XSTRING (tem)->data;
6131 else
6132 continue;
6133
6134 if (w32_font_match (fontname, ptnstr))
6135 {
6136 newlist = Fcons (XCAR (tem), newlist);
6137 n_fonts++;
6138 if (n_fonts >= max_names)
6139 break;
6140 }
6141 }
6142
6143 return newlist;
6144 }
6145
6146 Lisp_Object w32_list_synthesized_fonts (FRAME_PTR f, Lisp_Object pattern,
6147 int size, int max_names);
6148
6149 /* Return a list of names of available fonts matching PATTERN on frame
6150 F. If SIZE is not 0, it is the size (maximum bound width) of fonts
6151 to be listed. Frame F NULL means we have not yet created any
6152 frame, which means we can't get proper size info, as we don't have
6153 a device context to use for GetTextMetrics.
6154 MAXNAMES sets a limit on how many fonts to match. */
6155
6156 Lisp_Object
6157 w32_list_fonts (FRAME_PTR f, Lisp_Object pattern, int size, int maxnames )
6158 {
6159 Lisp_Object patterns, key = Qnil, tem, tpat;
6160 Lisp_Object list = Qnil, newlist = Qnil, second_best = Qnil;
6161 struct w32_display_info *dpyinfo = &one_w32_display_info;
6162 int n_fonts = 0;
6163
6164 patterns = Fassoc (pattern, Valternate_fontname_alist);
6165 if (NILP (patterns))
6166 patterns = Fcons (pattern, Qnil);
6167
6168 for (; CONSP (patterns); patterns = XCDR (patterns))
6169 {
6170 enumfont_t ef;
6171
6172 tpat = XCAR (patterns);
6173
6174 /* See if we cached the result for this particular query.
6175 The cache is an alist of the form:
6176 ((PATTERN (FONTNAME . WIDTH) ...) ...)
6177 */
6178 if (tem = XCDR (dpyinfo->name_list_element),
6179 !NILP (list = Fassoc (tpat, tem)))
6180 {
6181 list = Fcdr_safe (list);
6182 /* We have a cached list. Don't have to get the list again. */
6183 goto label_cached;
6184 }
6185
6186 BLOCK_INPUT;
6187 /* At first, put PATTERN in the cache. */
6188 list = Qnil;
6189 ef.pattern = &tpat;
6190 ef.tail = &list;
6191 ef.numFonts = 0;
6192
6193 /* Use EnumFontFamiliesEx where it is available, as it knows
6194 about character sets. Fall back to EnumFontFamilies for
6195 older versions of NT that don't support the 'Ex function. */
6196 x_to_w32_font (STRINGP (tpat) ? XSTRING (tpat)->data :
6197 NULL, &ef.logfont);
6198 {
6199 LOGFONT font_match_pattern;
6200 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
6201 FARPROC enum_font_families_ex
6202 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
6203
6204 /* We do our own pattern matching so we can handle wildcards. */
6205 font_match_pattern.lfFaceName[0] = 0;
6206 font_match_pattern.lfPitchAndFamily = 0;
6207 /* We can use the charset, because if it is a wildcard it will
6208 be DEFAULT_CHARSET anyway. */
6209 font_match_pattern.lfCharSet = ef.logfont.lfCharSet;
6210
6211 ef.hdc = GetDC (dpyinfo->root_window);
6212
6213 if (enum_font_families_ex)
6214 enum_font_families_ex (ef.hdc,
6215 &font_match_pattern,
6216 (FONTENUMPROC) enum_fontex_cb1,
6217 (LPARAM) &ef, 0);
6218 else
6219 EnumFontFamilies (ef.hdc, NULL, (FONTENUMPROC) enum_font_cb1,
6220 (LPARAM)&ef);
6221
6222 ReleaseDC (dpyinfo->root_window, ef.hdc);
6223 }
6224
6225 UNBLOCK_INPUT;
6226
6227 /* Make a list of the fonts we got back.
6228 Store that in the font cache for the display. */
6229 XCDR (dpyinfo->name_list_element)
6230 = Fcons (Fcons (tpat, list),
6231 XCDR (dpyinfo->name_list_element));
6232
6233 label_cached:
6234 if (NILP (list)) continue; /* Try the remaining alternatives. */
6235
6236 newlist = second_best = Qnil;
6237
6238 /* Make a list of the fonts that have the right width. */
6239 for (; CONSP (list); list = XCDR (list))
6240 {
6241 int found_size;
6242 tem = XCAR (list);
6243
6244 if (!CONSP (tem))
6245 continue;
6246 if (NILP (XCAR (tem)))
6247 continue;
6248 if (!size)
6249 {
6250 newlist = Fcons (XCAR (tem), newlist);
6251 n_fonts++;
6252 if (n_fonts >= maxnames)
6253 break;
6254 else
6255 continue;
6256 }
6257 if (!INTEGERP (XCDR (tem)))
6258 {
6259 /* Since we don't yet know the size of the font, we must
6260 load it and try GetTextMetrics. */
6261 W32FontStruct thisinfo;
6262 LOGFONT lf;
6263 HDC hdc;
6264 HANDLE oldobj;
6265
6266 if (!x_to_w32_font (XSTRING (XCAR (tem))->data, &lf))
6267 continue;
6268
6269 BLOCK_INPUT;
6270 thisinfo.bdf = NULL;
6271 thisinfo.hfont = CreateFontIndirect (&lf);
6272 if (thisinfo.hfont == NULL)
6273 continue;
6274
6275 hdc = GetDC (dpyinfo->root_window);
6276 oldobj = SelectObject (hdc, thisinfo.hfont);
6277 if (GetTextMetrics (hdc, &thisinfo.tm))
6278 XCDR (tem) = make_number (FONT_WIDTH (&thisinfo));
6279 else
6280 XCDR (tem) = make_number (0);
6281 SelectObject (hdc, oldobj);
6282 ReleaseDC (dpyinfo->root_window, hdc);
6283 DeleteObject(thisinfo.hfont);
6284 UNBLOCK_INPUT;
6285 }
6286 found_size = XINT (XCDR (tem));
6287 if (found_size == size)
6288 {
6289 newlist = Fcons (XCAR (tem), newlist);
6290 n_fonts++;
6291 if (n_fonts >= maxnames)
6292 break;
6293 }
6294 /* keep track of the closest matching size in case
6295 no exact match is found. */
6296 else if (found_size > 0)
6297 {
6298 if (NILP (second_best))
6299 second_best = tem;
6300
6301 else if (found_size < size)
6302 {
6303 if (XINT (XCDR (second_best)) > size
6304 || XINT (XCDR (second_best)) < found_size)
6305 second_best = tem;
6306 }
6307 else
6308 {
6309 if (XINT (XCDR (second_best)) > size
6310 && XINT (XCDR (second_best)) >
6311 found_size)
6312 second_best = tem;
6313 }
6314 }
6315 }
6316
6317 if (!NILP (newlist))
6318 break;
6319 else if (!NILP (second_best))
6320 {
6321 newlist = Fcons (XCAR (second_best), Qnil);
6322 break;
6323 }
6324 }
6325
6326 /* Include any bdf fonts. */
6327 if (n_fonts < maxnames)
6328 {
6329 Lisp_Object combined[2];
6330 combined[0] = w32_list_bdf_fonts (pattern, maxnames - n_fonts);
6331 combined[1] = newlist;
6332 newlist = Fnconc(2, combined);
6333 }
6334
6335 /* If we can't find a font that matches, check if Windows would be
6336 able to synthesize it from a different style. */
6337 if (NILP (newlist) && !NILP (Vw32_enable_synthesized_fonts))
6338 newlist = w32_list_synthesized_fonts (f, pattern, size, maxnames);
6339
6340 return newlist;
6341 }
6342
6343 Lisp_Object
6344 w32_list_synthesized_fonts (f, pattern, size, max_names)
6345 FRAME_PTR f;
6346 Lisp_Object pattern;
6347 int size;
6348 int max_names;
6349 {
6350 int fields;
6351 char *full_pattn, *new_pattn, foundary[50], family[50], *pattn_part2;
6352 char style[20], slant;
6353 Lisp_Object matches, match, tem, synthed_matches = Qnil;
6354
6355 full_pattn = XSTRING (pattern)->data;
6356
6357 pattn_part2 = alloca (XSTRING (pattern)->size);
6358 /* Allow some space for wildcard expansion. */
6359 new_pattn = alloca (XSTRING (pattern)->size + 100);
6360
6361 fields = sscanf (full_pattn, "-%49[^-]-%49[^-]-%19[^-]-%c-%s",
6362 foundary, family, style, &slant, pattn_part2);
6363 if (fields == EOF || fields < 5)
6364 return Qnil;
6365
6366 /* If the style and slant are wildcards already there is no point
6367 checking again (and we don't want to keep recursing). */
6368 if (*style == '*' && slant == '*')
6369 return Qnil;
6370
6371 sprintf (new_pattn, "-%s-%s-*-*-%s", foundary, family, pattn_part2);
6372
6373 matches = w32_list_fonts (f, build_string (new_pattn), size, max_names);
6374
6375 for ( ; CONSP (matches); matches = XCDR (matches))
6376 {
6377 tem = XCAR (matches);
6378 if (!STRINGP (tem))
6379 continue;
6380
6381 full_pattn = XSTRING (tem)->data;
6382 fields = sscanf (full_pattn, "-%49[^-]-%49[^-]-%*[^-]-%*c-%s",
6383 foundary, family, pattn_part2);
6384 if (fields == EOF || fields < 3)
6385 continue;
6386
6387 sprintf (new_pattn, "-%s-%s-%s-%c-%s", foundary, family, style,
6388 slant, pattn_part2);
6389
6390 synthed_matches = Fcons (build_string (new_pattn),
6391 synthed_matches);
6392 }
6393
6394 return synthed_matches;
6395 }
6396
6397
6398 /* Return a pointer to struct font_info of font FONT_IDX of frame F. */
6399 struct font_info *
6400 w32_get_font_info (f, font_idx)
6401 FRAME_PTR f;
6402 int font_idx;
6403 {
6404 return (FRAME_W32_FONT_TABLE (f) + font_idx);
6405 }
6406
6407
6408 struct font_info*
6409 w32_query_font (struct frame *f, char *fontname)
6410 {
6411 int i;
6412 struct font_info *pfi;
6413
6414 pfi = FRAME_W32_FONT_TABLE (f);
6415
6416 for (i = 0; i < one_w32_display_info.n_fonts ;i++, pfi++)
6417 {
6418 if (strcmp(pfi->name, fontname) == 0) return pfi;
6419 }
6420
6421 return NULL;
6422 }
6423
6424 /* Find a CCL program for a font specified by FONTP, and set the member
6425 `encoder' of the structure. */
6426
6427 void
6428 w32_find_ccl_program (fontp)
6429 struct font_info *fontp;
6430 {
6431 Lisp_Object list, elt;
6432
6433 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
6434 {
6435 elt = XCAR (list);
6436 if (CONSP (elt)
6437 && STRINGP (XCAR (elt))
6438 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
6439 >= 0))
6440 break;
6441 }
6442 if (! NILP (list))
6443 {
6444 struct ccl_program *ccl
6445 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
6446
6447 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
6448 xfree (ccl);
6449 else
6450 fontp->font_encoder = ccl;
6451 }
6452 }
6453
6454 \f
6455 DEFUN ("w32-find-bdf-fonts", Fw32_find_bdf_fonts, Sw32_find_bdf_fonts,
6456 1, 1, 0,
6457 "Return a list of BDF fonts in DIR, suitable for appending to\n\
6458 w32-bdf-filename-alist. Fonts which do not contain an xfld description\n\
6459 will not be included in the list. DIR may be a list of directories.")
6460 (directory)
6461 Lisp_Object directory;
6462 {
6463 Lisp_Object list = Qnil;
6464 struct gcpro gcpro1, gcpro2;
6465
6466 if (!CONSP (directory))
6467 return w32_find_bdf_fonts_in_dir (directory);
6468
6469 for ( ; CONSP (directory); directory = XCDR (directory))
6470 {
6471 Lisp_Object pair[2];
6472 pair[0] = list;
6473 pair[1] = Qnil;
6474 GCPRO2 (directory, list);
6475 pair[1] = w32_find_bdf_fonts_in_dir( XCAR (directory) );
6476 list = Fnconc( 2, pair );
6477 UNGCPRO;
6478 }
6479 return list;
6480 }
6481
6482 /* Find BDF files in a specified directory. (use GCPRO when calling,
6483 as this calls lisp to get a directory listing). */
6484 Lisp_Object w32_find_bdf_fonts_in_dir( Lisp_Object directory )
6485 {
6486 Lisp_Object filelist, list = Qnil;
6487 char fontname[100];
6488
6489 if (!STRINGP(directory))
6490 return Qnil;
6491
6492 filelist = Fdirectory_files (directory, Qt,
6493 build_string (".*\\.[bB][dD][fF]"), Qt);
6494
6495 for ( ; CONSP(filelist); filelist = XCDR (filelist))
6496 {
6497 Lisp_Object filename = XCAR (filelist);
6498 if (w32_BDF_to_x_font (XSTRING (filename)->data, fontname, 100))
6499 store_in_alist (&list, build_string (fontname), filename);
6500 }
6501 return list;
6502 }
6503
6504 \f
6505 DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
6506 "Return non-nil if color COLOR is supported on frame FRAME.\n\
6507 If FRAME is omitted or nil, use the selected frame.")
6508 (color, frame)
6509 Lisp_Object color, frame;
6510 {
6511 XColor foo;
6512 FRAME_PTR f = check_x_frame (frame);
6513
6514 CHECK_STRING (color, 1);
6515
6516 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
6517 return Qt;
6518 else
6519 return Qnil;
6520 }
6521
6522 DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
6523 "Return a description of the color named COLOR on frame FRAME.\n\
6524 The value is a list of integer RGB values--(RED GREEN BLUE).\n\
6525 These values appear to range from 0 to 65280 or 65535, depending\n\
6526 on the system; white is (65280 65280 65280) or (65535 65535 65535).\n\
6527 If FRAME is omitted or nil, use the selected frame.")
6528 (color, frame)
6529 Lisp_Object color, frame;
6530 {
6531 XColor foo;
6532 FRAME_PTR f = check_x_frame (frame);
6533
6534 CHECK_STRING (color, 1);
6535
6536 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
6537 {
6538 Lisp_Object rgb[3];
6539
6540 rgb[0] = make_number ((GetRValue (foo.pixel) << 8)
6541 | GetRValue (foo.pixel));
6542 rgb[1] = make_number ((GetGValue (foo.pixel) << 8)
6543 | GetGValue (foo.pixel));
6544 rgb[2] = make_number ((GetBValue (foo.pixel) << 8)
6545 | GetBValue (foo.pixel));
6546 return Flist (3, rgb);
6547 }
6548 else
6549 return Qnil;
6550 }
6551
6552 DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
6553 "Return t if the X display supports color.\n\
6554 The optional argument DISPLAY specifies which display to ask about.\n\
6555 DISPLAY should be either a frame or a display name (a string).\n\
6556 If omitted or nil, that stands for the selected frame's display.")
6557 (display)
6558 Lisp_Object display;
6559 {
6560 struct w32_display_info *dpyinfo = check_x_display_info (display);
6561
6562 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 2)
6563 return Qnil;
6564
6565 return Qt;
6566 }
6567
6568 DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p, Sx_display_grayscale_p,
6569 0, 1, 0,
6570 "Return t if the X display supports shades of gray.\n\
6571 Note that color displays do support shades of gray.\n\
6572 The optional argument DISPLAY specifies which display to ask about.\n\
6573 DISPLAY should be either a frame or a display name (a string).\n\
6574 If omitted or nil, that stands for the selected frame's display.")
6575 (display)
6576 Lisp_Object display;
6577 {
6578 struct w32_display_info *dpyinfo = check_x_display_info (display);
6579
6580 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 1)
6581 return Qnil;
6582
6583 return Qt;
6584 }
6585
6586 DEFUN ("x-display-pixel-width", Fx_display_pixel_width, Sx_display_pixel_width,
6587 0, 1, 0,
6588 "Returns the width in pixels of the X display DISPLAY.\n\
6589 The optional argument DISPLAY specifies which display to ask about.\n\
6590 DISPLAY should be either a frame or a display name (a string).\n\
6591 If omitted or nil, that stands for the selected frame's display.")
6592 (display)
6593 Lisp_Object display;
6594 {
6595 struct w32_display_info *dpyinfo = check_x_display_info (display);
6596
6597 return make_number (dpyinfo->width);
6598 }
6599
6600 DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
6601 Sx_display_pixel_height, 0, 1, 0,
6602 "Returns the height in pixels of the X display DISPLAY.\n\
6603 The optional argument DISPLAY specifies which display to ask about.\n\
6604 DISPLAY should be either a frame or a display name (a string).\n\
6605 If omitted or nil, that stands for the selected frame's display.")
6606 (display)
6607 Lisp_Object display;
6608 {
6609 struct w32_display_info *dpyinfo = check_x_display_info (display);
6610
6611 return make_number (dpyinfo->height);
6612 }
6613
6614 DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
6615 0, 1, 0,
6616 "Returns the number of bitplanes of the display DISPLAY.\n\
6617 The optional argument DISPLAY specifies which display to ask about.\n\
6618 DISPLAY should be either a frame or a display name (a string).\n\
6619 If omitted or nil, that stands for the selected frame's display.")
6620 (display)
6621 Lisp_Object display;
6622 {
6623 struct w32_display_info *dpyinfo = check_x_display_info (display);
6624
6625 return make_number (dpyinfo->n_planes * dpyinfo->n_cbits);
6626 }
6627
6628 DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
6629 0, 1, 0,
6630 "Returns the number of color cells of the display DISPLAY.\n\
6631 The optional argument DISPLAY specifies which display to ask about.\n\
6632 DISPLAY should be either a frame or a display name (a string).\n\
6633 If omitted or nil, that stands for the selected frame's display.")
6634 (display)
6635 Lisp_Object display;
6636 {
6637 struct w32_display_info *dpyinfo = check_x_display_info (display);
6638 HDC hdc;
6639 int cap;
6640
6641 hdc = GetDC (dpyinfo->root_window);
6642 if (dpyinfo->has_palette)
6643 cap = GetDeviceCaps (hdc,SIZEPALETTE);
6644 else
6645 cap = GetDeviceCaps (hdc,NUMCOLORS);
6646
6647 ReleaseDC (dpyinfo->root_window, hdc);
6648
6649 return make_number (cap);
6650 }
6651
6652 DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
6653 Sx_server_max_request_size,
6654 0, 1, 0,
6655 "Returns the maximum request size of the server of display DISPLAY.\n\
6656 The optional argument DISPLAY specifies which display to ask about.\n\
6657 DISPLAY should be either a frame or a display name (a string).\n\
6658 If omitted or nil, that stands for the selected frame's display.")
6659 (display)
6660 Lisp_Object display;
6661 {
6662 struct w32_display_info *dpyinfo = check_x_display_info (display);
6663
6664 return make_number (1);
6665 }
6666
6667 DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
6668 "Returns the vendor ID string of the W32 system (Microsoft).\n\
6669 The optional argument DISPLAY specifies which display to ask about.\n\
6670 DISPLAY should be either a frame or a display name (a string).\n\
6671 If omitted or nil, that stands for the selected frame's display.")
6672 (display)
6673 Lisp_Object display;
6674 {
6675 struct w32_display_info *dpyinfo = check_x_display_info (display);
6676 char *vendor = "Microsoft Corp.";
6677
6678 if (! vendor) vendor = "";
6679 return build_string (vendor);
6680 }
6681
6682 DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
6683 "Returns the version numbers of the server of display DISPLAY.\n\
6684 The value is a list of three integers: the major and minor\n\
6685 version numbers, and the vendor-specific release\n\
6686 number. See also the function `x-server-vendor'.\n\n\
6687 The optional argument DISPLAY specifies which display to ask about.\n\
6688 DISPLAY should be either a frame or a display name (a string).\n\
6689 If omitted or nil, that stands for the selected frame's display.")
6690 (display)
6691 Lisp_Object display;
6692 {
6693 struct w32_display_info *dpyinfo = check_x_display_info (display);
6694
6695 return Fcons (make_number (w32_major_version),
6696 Fcons (make_number (w32_minor_version), Qnil));
6697 }
6698
6699 DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
6700 "Returns the number of screens on the server of display DISPLAY.\n\
6701 The optional argument DISPLAY specifies which display to ask about.\n\
6702 DISPLAY should be either a frame or a display name (a string).\n\
6703 If omitted or nil, that stands for the selected frame's display.")
6704 (display)
6705 Lisp_Object display;
6706 {
6707 struct w32_display_info *dpyinfo = check_x_display_info (display);
6708
6709 return make_number (1);
6710 }
6711
6712 DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height, 0, 1, 0,
6713 "Returns the height in millimeters of the X display DISPLAY.\n\
6714 The optional argument DISPLAY specifies which display to ask about.\n\
6715 DISPLAY should be either a frame or a display name (a string).\n\
6716 If omitted or nil, that stands for the selected frame's display.")
6717 (display)
6718 Lisp_Object display;
6719 {
6720 struct w32_display_info *dpyinfo = check_x_display_info (display);
6721 HDC hdc;
6722 int cap;
6723
6724 hdc = GetDC (dpyinfo->root_window);
6725
6726 cap = GetDeviceCaps (hdc, VERTSIZE);
6727
6728 ReleaseDC (dpyinfo->root_window, hdc);
6729
6730 return make_number (cap);
6731 }
6732
6733 DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
6734 "Returns the width in millimeters of the X display DISPLAY.\n\
6735 The optional argument DISPLAY specifies which display to ask about.\n\
6736 DISPLAY should be either a frame or a display name (a string).\n\
6737 If omitted or nil, that stands for the selected frame's display.")
6738 (display)
6739 Lisp_Object display;
6740 {
6741 struct w32_display_info *dpyinfo = check_x_display_info (display);
6742
6743 HDC hdc;
6744 int cap;
6745
6746 hdc = GetDC (dpyinfo->root_window);
6747
6748 cap = GetDeviceCaps (hdc, HORZSIZE);
6749
6750 ReleaseDC (dpyinfo->root_window, hdc);
6751
6752 return make_number (cap);
6753 }
6754
6755 DEFUN ("x-display-backing-store", Fx_display_backing_store,
6756 Sx_display_backing_store, 0, 1, 0,
6757 "Returns an indication of whether display DISPLAY does backing store.\n\
6758 The value may be `always', `when-mapped', or `not-useful'.\n\
6759 The optional argument DISPLAY specifies which display to ask about.\n\
6760 DISPLAY should be either a frame or a display name (a string).\n\
6761 If omitted or nil, that stands for the selected frame's display.")
6762 (display)
6763 Lisp_Object display;
6764 {
6765 return intern ("not-useful");
6766 }
6767
6768 DEFUN ("x-display-visual-class", Fx_display_visual_class,
6769 Sx_display_visual_class, 0, 1, 0,
6770 "Returns the visual class of the display DISPLAY.\n\
6771 The value is one of the symbols `static-gray', `gray-scale',\n\
6772 `static-color', `pseudo-color', `true-color', or `direct-color'.\n\n\
6773 The optional argument DISPLAY specifies which display to ask about.\n\
6774 DISPLAY should be either a frame or a display name (a string).\n\
6775 If omitted or nil, that stands for the selected frame's display.")
6776 (display)
6777 Lisp_Object display;
6778 {
6779 struct w32_display_info *dpyinfo = check_x_display_info (display);
6780
6781 #if 0
6782 switch (dpyinfo->visual->class)
6783 {
6784 case StaticGray: return (intern ("static-gray"));
6785 case GrayScale: return (intern ("gray-scale"));
6786 case StaticColor: return (intern ("static-color"));
6787 case PseudoColor: return (intern ("pseudo-color"));
6788 case TrueColor: return (intern ("true-color"));
6789 case DirectColor: return (intern ("direct-color"));
6790 default:
6791 error ("Display has an unknown visual class");
6792 }
6793 #endif
6794
6795 error ("Display has an unknown visual class");
6796 }
6797
6798 DEFUN ("x-display-save-under", Fx_display_save_under,
6799 Sx_display_save_under, 0, 1, 0,
6800 "Returns t if the display DISPLAY supports the save-under feature.\n\
6801 The optional argument DISPLAY specifies which display to ask about.\n\
6802 DISPLAY should be either a frame or a display name (a string).\n\
6803 If omitted or nil, that stands for the selected frame's display.")
6804 (display)
6805 Lisp_Object display;
6806 {
6807 struct w32_display_info *dpyinfo = check_x_display_info (display);
6808
6809 return Qnil;
6810 }
6811 \f
6812 int
6813 x_pixel_width (f)
6814 register struct frame *f;
6815 {
6816 return PIXEL_WIDTH (f);
6817 }
6818
6819 int
6820 x_pixel_height (f)
6821 register struct frame *f;
6822 {
6823 return PIXEL_HEIGHT (f);
6824 }
6825
6826 int
6827 x_char_width (f)
6828 register struct frame *f;
6829 {
6830 return FONT_WIDTH (f->output_data.w32->font);
6831 }
6832
6833 int
6834 x_char_height (f)
6835 register struct frame *f;
6836 {
6837 return f->output_data.w32->line_height;
6838 }
6839
6840 int
6841 x_screen_planes (f)
6842 register struct frame *f;
6843 {
6844 return FRAME_W32_DISPLAY_INFO (f)->n_planes;
6845 }
6846 \f
6847 /* Return the display structure for the display named NAME.
6848 Open a new connection if necessary. */
6849
6850 struct w32_display_info *
6851 x_display_info_for_name (name)
6852 Lisp_Object name;
6853 {
6854 Lisp_Object names;
6855 struct w32_display_info *dpyinfo;
6856
6857 CHECK_STRING (name, 0);
6858
6859 for (dpyinfo = &one_w32_display_info, names = w32_display_name_list;
6860 dpyinfo;
6861 dpyinfo = dpyinfo->next, names = XCDR (names))
6862 {
6863 Lisp_Object tem;
6864 tem = Fstring_equal (XCAR (XCAR (names)), name);
6865 if (!NILP (tem))
6866 return dpyinfo;
6867 }
6868
6869 /* Use this general default value to start with. */
6870 Vx_resource_name = Vinvocation_name;
6871
6872 validate_x_resource_name ();
6873
6874 dpyinfo = w32_term_init (name, (unsigned char *)0,
6875 (char *) XSTRING (Vx_resource_name)->data);
6876
6877 if (dpyinfo == 0)
6878 error ("Cannot connect to server %s", XSTRING (name)->data);
6879
6880 w32_in_use = 1;
6881 XSETFASTINT (Vwindow_system_version, 3);
6882
6883 return dpyinfo;
6884 }
6885
6886 DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
6887 1, 3, 0, "Open a connection to a server.\n\
6888 DISPLAY is the name of the display to connect to.\n\
6889 Optional second arg XRM-STRING is a string of resources in xrdb format.\n\
6890 If the optional third arg MUST-SUCCEED is non-nil,\n\
6891 terminate Emacs if we can't open the connection.")
6892 (display, xrm_string, must_succeed)
6893 Lisp_Object display, xrm_string, must_succeed;
6894 {
6895 unsigned char *xrm_option;
6896 struct w32_display_info *dpyinfo;
6897
6898 CHECK_STRING (display, 0);
6899 if (! NILP (xrm_string))
6900 CHECK_STRING (xrm_string, 1);
6901
6902 if (! EQ (Vwindow_system, intern ("w32")))
6903 error ("Not using Microsoft Windows");
6904
6905 /* Allow color mapping to be defined externally; first look in user's
6906 HOME directory, then in Emacs etc dir for a file called rgb.txt. */
6907 {
6908 Lisp_Object color_file;
6909 struct gcpro gcpro1;
6910
6911 color_file = build_string("~/rgb.txt");
6912
6913 GCPRO1 (color_file);
6914
6915 if (NILP (Ffile_readable_p (color_file)))
6916 color_file =
6917 Fexpand_file_name (build_string ("rgb.txt"),
6918 Fsymbol_value (intern ("data-directory")));
6919
6920 Vw32_color_map = Fw32_load_color_file (color_file);
6921
6922 UNGCPRO;
6923 }
6924 if (NILP (Vw32_color_map))
6925 Vw32_color_map = Fw32_default_color_map ();
6926
6927 if (! NILP (xrm_string))
6928 xrm_option = (unsigned char *) XSTRING (xrm_string)->data;
6929 else
6930 xrm_option = (unsigned char *) 0;
6931
6932 /* Use this general default value to start with. */
6933 /* First remove .exe suffix from invocation-name - it looks ugly. */
6934 {
6935 char basename[ MAX_PATH ], *str;
6936
6937 strcpy (basename, XSTRING (Vinvocation_name)->data);
6938 str = strrchr (basename, '.');
6939 if (str) *str = 0;
6940 Vinvocation_name = build_string (basename);
6941 }
6942 Vx_resource_name = Vinvocation_name;
6943
6944 validate_x_resource_name ();
6945
6946 /* This is what opens the connection and sets x_current_display.
6947 This also initializes many symbols, such as those used for input. */
6948 dpyinfo = w32_term_init (display, xrm_option,
6949 (char *) XSTRING (Vx_resource_name)->data);
6950
6951 if (dpyinfo == 0)
6952 {
6953 if (!NILP (must_succeed))
6954 fatal ("Cannot connect to server %s.\n",
6955 XSTRING (display)->data);
6956 else
6957 error ("Cannot connect to server %s", XSTRING (display)->data);
6958 }
6959
6960 w32_in_use = 1;
6961
6962 XSETFASTINT (Vwindow_system_version, 3);
6963 return Qnil;
6964 }
6965
6966 DEFUN ("x-close-connection", Fx_close_connection,
6967 Sx_close_connection, 1, 1, 0,
6968 "Close the connection to DISPLAY's server.\n\
6969 For DISPLAY, specify either a frame or a display name (a string).\n\
6970 If DISPLAY is nil, that stands for the selected frame's display.")
6971 (display)
6972 Lisp_Object display;
6973 {
6974 struct w32_display_info *dpyinfo = check_x_display_info (display);
6975 int i;
6976
6977 if (dpyinfo->reference_count > 0)
6978 error ("Display still has frames on it");
6979
6980 BLOCK_INPUT;
6981 /* Free the fonts in the font table. */
6982 for (i = 0; i < dpyinfo->n_fonts; i++)
6983 if (dpyinfo->font_table[i].name)
6984 {
6985 xfree (dpyinfo->font_table[i].name);
6986 /* Don't free the full_name string;
6987 it is always shared with something else. */
6988 w32_unload_font (dpyinfo, dpyinfo->font_table[i].font);
6989 }
6990 x_destroy_all_bitmaps (dpyinfo);
6991
6992 x_delete_display (dpyinfo);
6993 UNBLOCK_INPUT;
6994
6995 return Qnil;
6996 }
6997
6998 DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
6999 "Return the list of display names that Emacs has connections to.")
7000 ()
7001 {
7002 Lisp_Object tail, result;
7003
7004 result = Qnil;
7005 for (tail = w32_display_name_list; ! NILP (tail); tail = XCDR (tail))
7006 result = Fcons (XCAR (XCAR (tail)), result);
7007
7008 return result;
7009 }
7010
7011 DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0,
7012 "If ON is non-nil, report errors as soon as the erring request is made.\n\
7013 If ON is nil, allow buffering of requests.\n\
7014 This is a noop on W32 systems.\n\
7015 The optional second argument DISPLAY specifies which display to act on.\n\
7016 DISPLAY should be either a frame or a display name (a string).\n\
7017 If DISPLAY is omitted or nil, that stands for the selected frame's display.")
7018 (on, display)
7019 Lisp_Object display, on;
7020 {
7021 struct w32_display_info *dpyinfo = check_x_display_info (display);
7022
7023 return Qnil;
7024 }
7025
7026 \f
7027 \f
7028 /***********************************************************************
7029 Image types
7030 ***********************************************************************/
7031
7032 /* Value is the number of elements of vector VECTOR. */
7033
7034 #define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))
7035
7036 /* List of supported image types. Use define_image_type to add new
7037 types. Use lookup_image_type to find a type for a given symbol. */
7038
7039 static struct image_type *image_types;
7040
7041 /* A list of symbols, one for each supported image type. */
7042
7043 Lisp_Object Vimage_types;
7044
7045 /* The symbol `image' which is the car of the lists used to represent
7046 images in Lisp. */
7047
7048 extern Lisp_Object Qimage;
7049
7050 /* The symbol `xbm' which is used as the type symbol for XBM images. */
7051
7052 Lisp_Object Qxbm;
7053
7054 /* Keywords. */
7055
7056 Lisp_Object QCtype, QCdata, QCascent, QCmargin, QCrelief;
7057 extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
7058 Lisp_Object QCalgorithm, QCcolor_symbols, QCheuristic_mask;
7059 extern Lisp_Object QCindex;
7060
7061 /* Other symbols. */
7062
7063 Lisp_Object Qlaplace;
7064
7065 /* Time in seconds after which images should be removed from the cache
7066 if not displayed. */
7067
7068 Lisp_Object Vimage_cache_eviction_delay;
7069
7070 /* Function prototypes. */
7071
7072 static void define_image_type P_ ((struct image_type *type));
7073 static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
7074 static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
7075 static void x_laplace P_ ((struct frame *, struct image *));
7076 static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
7077 Lisp_Object));
7078
7079 /* Define a new image type from TYPE. This adds a copy of TYPE to
7080 image_types and adds the symbol *TYPE->type to Vimage_types. */
7081
7082 static void
7083 define_image_type (type)
7084 struct image_type *type;
7085 {
7086 /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
7087 The initialized data segment is read-only. */
7088 struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
7089 bcopy (type, p, sizeof *p);
7090 p->next = image_types;
7091 image_types = p;
7092 Vimage_types = Fcons (*p->type, Vimage_types);
7093 }
7094
7095
7096 /* Look up image type SYMBOL, and return a pointer to its image_type
7097 structure. Value is null if SYMBOL is not a known image type. */
7098
7099 static INLINE struct image_type *
7100 lookup_image_type (symbol)
7101 Lisp_Object symbol;
7102 {
7103 struct image_type *type;
7104
7105 for (type = image_types; type; type = type->next)
7106 if (EQ (symbol, *type->type))
7107 break;
7108
7109 return type;
7110 }
7111
7112
7113 /* Value is non-zero if OBJECT is a valid Lisp image specification. A
7114 valid image specification is a list whose car is the symbol
7115 `image', and whose rest is a property list. The property list must
7116 contain a value for key `:type'. That value must be the name of a
7117 supported image type. The rest of the property list depends on the
7118 image type. */
7119
7120 int
7121 valid_image_p (object)
7122 Lisp_Object object;
7123 {
7124 int valid_p = 0;
7125
7126 if (CONSP (object) && EQ (XCAR (object), Qimage))
7127 {
7128 Lisp_Object symbol = Fplist_get (XCDR (object), QCtype);
7129 struct image_type *type = lookup_image_type (symbol);
7130
7131 if (type)
7132 valid_p = type->valid_p (object);
7133 }
7134
7135 return valid_p;
7136 }
7137
7138
7139 /* Log error message with format string FORMAT and argument ARG.
7140 Signaling an error, e.g. when an image cannot be loaded, is not a
7141 good idea because this would interrupt redisplay, and the error
7142 message display would lead to another redisplay. This function
7143 therefore simply displays a message. */
7144
7145 static void
7146 image_error (format, arg1, arg2)
7147 char *format;
7148 Lisp_Object arg1, arg2;
7149 {
7150 add_to_log (format, arg1, arg2);
7151 }
7152
7153
7154 \f
7155 /***********************************************************************
7156 Image specifications
7157 ***********************************************************************/
7158
7159 enum image_value_type
7160 {
7161 IMAGE_DONT_CHECK_VALUE_TYPE,
7162 IMAGE_STRING_VALUE,
7163 IMAGE_SYMBOL_VALUE,
7164 IMAGE_POSITIVE_INTEGER_VALUE,
7165 IMAGE_NON_NEGATIVE_INTEGER_VALUE,
7166 IMAGE_INTEGER_VALUE,
7167 IMAGE_FUNCTION_VALUE,
7168 IMAGE_NUMBER_VALUE,
7169 IMAGE_BOOL_VALUE
7170 };
7171
7172 /* Structure used when parsing image specifications. */
7173
7174 struct image_keyword
7175 {
7176 /* Name of keyword. */
7177 char *name;
7178
7179 /* The type of value allowed. */
7180 enum image_value_type type;
7181
7182 /* Non-zero means key must be present. */
7183 int mandatory_p;
7184
7185 /* Used to recognize duplicate keywords in a property list. */
7186 int count;
7187
7188 /* The value that was found. */
7189 Lisp_Object value;
7190 };
7191
7192
7193 static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
7194 int, Lisp_Object));
7195 static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
7196
7197
7198 /* Parse image spec SPEC according to KEYWORDS. A valid image spec
7199 has the format (image KEYWORD VALUE ...). One of the keyword/
7200 value pairs must be `:type TYPE'. KEYWORDS is a vector of
7201 image_keywords structures of size NKEYWORDS describing other
7202 allowed keyword/value pairs. Value is non-zero if SPEC is valid. */
7203
7204 static int
7205 parse_image_spec (spec, keywords, nkeywords, type)
7206 Lisp_Object spec;
7207 struct image_keyword *keywords;
7208 int nkeywords;
7209 Lisp_Object type;
7210 {
7211 int i;
7212 Lisp_Object plist;
7213
7214 if (!CONSP (spec) || !EQ (XCAR (spec), Qimage))
7215 return 0;
7216
7217 plist = XCDR (spec);
7218 while (CONSP (plist))
7219 {
7220 Lisp_Object key, value;
7221
7222 /* First element of a pair must be a symbol. */
7223 key = XCAR (plist);
7224 plist = XCDR (plist);
7225 if (!SYMBOLP (key))
7226 return 0;
7227
7228 /* There must follow a value. */
7229 if (!CONSP (plist))
7230 return 0;
7231 value = XCAR (plist);
7232 plist = XCDR (plist);
7233
7234 /* Find key in KEYWORDS. Error if not found. */
7235 for (i = 0; i < nkeywords; ++i)
7236 if (strcmp (keywords[i].name, XSYMBOL (key)->name->data) == 0)
7237 break;
7238
7239 if (i == nkeywords)
7240 continue;
7241
7242 /* Record that we recognized the keyword. If a keywords
7243 was found more than once, it's an error. */
7244 keywords[i].value = value;
7245 ++keywords[i].count;
7246
7247 if (keywords[i].count > 1)
7248 return 0;
7249
7250 /* Check type of value against allowed type. */
7251 switch (keywords[i].type)
7252 {
7253 case IMAGE_STRING_VALUE:
7254 if (!STRINGP (value))
7255 return 0;
7256 break;
7257
7258 case IMAGE_SYMBOL_VALUE:
7259 if (!SYMBOLP (value))
7260 return 0;
7261 break;
7262
7263 case IMAGE_POSITIVE_INTEGER_VALUE:
7264 if (!INTEGERP (value) || XINT (value) <= 0)
7265 return 0;
7266 break;
7267
7268 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
7269 if (!INTEGERP (value) || XINT (value) < 0)
7270 return 0;
7271 break;
7272
7273 case IMAGE_DONT_CHECK_VALUE_TYPE:
7274 break;
7275
7276 case IMAGE_FUNCTION_VALUE:
7277 value = indirect_function (value);
7278 if (SUBRP (value)
7279 || COMPILEDP (value)
7280 || (CONSP (value) && EQ (XCAR (value), Qlambda)))
7281 break;
7282 return 0;
7283
7284 case IMAGE_NUMBER_VALUE:
7285 if (!INTEGERP (value) && !FLOATP (value))
7286 return 0;
7287 break;
7288
7289 case IMAGE_INTEGER_VALUE:
7290 if (!INTEGERP (value))
7291 return 0;
7292 break;
7293
7294 case IMAGE_BOOL_VALUE:
7295 if (!NILP (value) && !EQ (value, Qt))
7296 return 0;
7297 break;
7298
7299 default:
7300 abort ();
7301 break;
7302 }
7303
7304 if (EQ (key, QCtype) && !EQ (type, value))
7305 return 0;
7306 }
7307
7308 /* Check that all mandatory fields are present. */
7309 for (i = 0; i < nkeywords; ++i)
7310 if (keywords[i].mandatory_p && keywords[i].count == 0)
7311 return 0;
7312
7313 return NILP (plist);
7314 }
7315
7316
7317 /* Return the value of KEY in image specification SPEC. Value is nil
7318 if KEY is not present in SPEC. if FOUND is not null, set *FOUND
7319 to 1 if KEY was found in SPEC, set it to 0 otherwise. */
7320
7321 static Lisp_Object
7322 image_spec_value (spec, key, found)
7323 Lisp_Object spec, key;
7324 int *found;
7325 {
7326 Lisp_Object tail;
7327
7328 xassert (valid_image_p (spec));
7329
7330 for (tail = XCDR (spec);
7331 CONSP (tail) && CONSP (XCDR (tail));
7332 tail = XCDR (XCDR (tail)))
7333 {
7334 if (EQ (XCAR (tail), key))
7335 {
7336 if (found)
7337 *found = 1;
7338 return XCAR (XCDR (tail));
7339 }
7340 }
7341
7342 if (found)
7343 *found = 0;
7344 return Qnil;
7345 }
7346
7347
7348
7349 \f
7350 /***********************************************************************
7351 Image type independent image structures
7352 ***********************************************************************/
7353
7354 static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
7355 static void free_image P_ ((struct frame *f, struct image *img));
7356
7357
7358 /* Allocate and return a new image structure for image specification
7359 SPEC. SPEC has a hash value of HASH. */
7360
7361 static struct image *
7362 make_image (spec, hash)
7363 Lisp_Object spec;
7364 unsigned hash;
7365 {
7366 struct image *img = (struct image *) xmalloc (sizeof *img);
7367
7368 xassert (valid_image_p (spec));
7369 bzero (img, sizeof *img);
7370 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
7371 xassert (img->type != NULL);
7372 img->spec = spec;
7373 img->data.lisp_val = Qnil;
7374 img->ascent = DEFAULT_IMAGE_ASCENT;
7375 img->hash = hash;
7376 return img;
7377 }
7378
7379
7380 /* Free image IMG which was used on frame F, including its resources. */
7381
7382 static void
7383 free_image (f, img)
7384 struct frame *f;
7385 struct image *img;
7386 {
7387 if (img)
7388 {
7389 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
7390
7391 /* Remove IMG from the hash table of its cache. */
7392 if (img->prev)
7393 img->prev->next = img->next;
7394 else
7395 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
7396
7397 if (img->next)
7398 img->next->prev = img->prev;
7399
7400 c->images[img->id] = NULL;
7401
7402 /* Free resources, then free IMG. */
7403 img->type->free (f, img);
7404 xfree (img);
7405 }
7406 }
7407
7408
7409 /* Prepare image IMG for display on frame F. Must be called before
7410 drawing an image. */
7411
7412 void
7413 prepare_image_for_display (f, img)
7414 struct frame *f;
7415 struct image *img;
7416 {
7417 EMACS_TIME t;
7418
7419 /* We're about to display IMG, so set its timestamp to `now'. */
7420 EMACS_GET_TIME (t);
7421 img->timestamp = EMACS_SECS (t);
7422
7423 /* If IMG doesn't have a pixmap yet, load it now, using the image
7424 type dependent loader function. */
7425 if (img->pixmap == 0 && !img->load_failed_p)
7426 img->load_failed_p = img->type->load (f, img) == 0;
7427 }
7428
7429
7430 \f
7431 /***********************************************************************
7432 Helper functions for X image types
7433 ***********************************************************************/
7434
7435 static void x_clear_image P_ ((struct frame *f, struct image *img));
7436 static unsigned long x_alloc_image_color P_ ((struct frame *f,
7437 struct image *img,
7438 Lisp_Object color_name,
7439 unsigned long dflt));
7440
7441 /* Free X resources of image IMG which is used on frame F. */
7442
7443 static void
7444 x_clear_image (f, img)
7445 struct frame *f;
7446 struct image *img;
7447 {
7448 #if 0 /* NTEMACS_TODO: W32 image support */
7449
7450 if (img->pixmap)
7451 {
7452 BLOCK_INPUT;
7453 XFreePixmap (NULL, img->pixmap);
7454 img->pixmap = 0;
7455 UNBLOCK_INPUT;
7456 }
7457
7458 if (img->ncolors)
7459 {
7460 int class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
7461
7462 /* If display has an immutable color map, freeing colors is not
7463 necessary and some servers don't allow it. So don't do it. */
7464 if (class != StaticColor
7465 && class != StaticGray
7466 && class != TrueColor)
7467 {
7468 Colormap cmap;
7469 BLOCK_INPUT;
7470 cmap = DefaultColormapOfScreen (FRAME_W32_DISPLAY_INFO (f)->screen);
7471 XFreeColors (FRAME_W32_DISPLAY (f), cmap, img->colors,
7472 img->ncolors, 0);
7473 UNBLOCK_INPUT;
7474 }
7475
7476 xfree (img->colors);
7477 img->colors = NULL;
7478 img->ncolors = 0;
7479 }
7480 #endif
7481 }
7482
7483
7484 /* Allocate color COLOR_NAME for image IMG on frame F. If color
7485 cannot be allocated, use DFLT. Add a newly allocated color to
7486 IMG->colors, so that it can be freed again. Value is the pixel
7487 color. */
7488
7489 static unsigned long
7490 x_alloc_image_color (f, img, color_name, dflt)
7491 struct frame *f;
7492 struct image *img;
7493 Lisp_Object color_name;
7494 unsigned long dflt;
7495 {
7496 #if 0 /* NTEMACS_TODO: allocing colors. */
7497 XColor color;
7498 unsigned long result;
7499
7500 xassert (STRINGP (color_name));
7501
7502 if (w32_defined_color (f, XSTRING (color_name)->data, &color, 1))
7503 {
7504 /* This isn't called frequently so we get away with simply
7505 reallocating the color vector to the needed size, here. */
7506 ++img->ncolors;
7507 img->colors =
7508 (unsigned long *) xrealloc (img->colors,
7509 img->ncolors * sizeof *img->colors);
7510 img->colors[img->ncolors - 1] = color.pixel;
7511 result = color.pixel;
7512 }
7513 else
7514 result = dflt;
7515 return result;
7516 #endif
7517 return 0;
7518 }
7519
7520
7521 \f
7522 /***********************************************************************
7523 Image Cache
7524 ***********************************************************************/
7525
7526 static void cache_image P_ ((struct frame *f, struct image *img));
7527
7528
7529 /* Return a new, initialized image cache that is allocated from the
7530 heap. Call free_image_cache to free an image cache. */
7531
7532 struct image_cache *
7533 make_image_cache ()
7534 {
7535 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
7536 int size;
7537
7538 bzero (c, sizeof *c);
7539 c->size = 50;
7540 c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
7541 size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
7542 c->buckets = (struct image **) xmalloc (size);
7543 bzero (c->buckets, size);
7544 return c;
7545 }
7546
7547
7548 /* Free image cache of frame F. Be aware that X frames share images
7549 caches. */
7550
7551 void
7552 free_image_cache (f)
7553 struct frame *f;
7554 {
7555 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
7556 if (c)
7557 {
7558 int i;
7559
7560 /* Cache should not be referenced by any frame when freed. */
7561 xassert (c->refcount == 0);
7562
7563 for (i = 0; i < c->used; ++i)
7564 free_image (f, c->images[i]);
7565 xfree (c->images);
7566 xfree (c);
7567 xfree (c->buckets);
7568 FRAME_X_IMAGE_CACHE (f) = NULL;
7569 }
7570 }
7571
7572
7573 /* Clear image cache of frame F. FORCE_P non-zero means free all
7574 images. FORCE_P zero means clear only images that haven't been
7575 displayed for some time. Should be called from time to time to
7576 reduce the number of loaded images. If image-cache-eveiction-delay
7577 is non-nil, this frees images in the cache which weren't displayed for
7578 at least that many seconds. */
7579
7580 void
7581 clear_image_cache (f, force_p)
7582 struct frame *f;
7583 int force_p;
7584 {
7585 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
7586
7587 if (c && INTEGERP (Vimage_cache_eviction_delay))
7588 {
7589 EMACS_TIME t;
7590 unsigned long old;
7591 int i, any_freed_p = 0;
7592
7593 EMACS_GET_TIME (t);
7594 old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
7595
7596 for (i = 0; i < c->used; ++i)
7597 {
7598 struct image *img = c->images[i];
7599 if (img != NULL
7600 && (force_p
7601 || (img->timestamp > old)))
7602 {
7603 free_image (f, img);
7604 any_freed_p = 1;
7605 }
7606 }
7607
7608 /* We may be clearing the image cache because, for example,
7609 Emacs was iconified for a longer period of time. In that
7610 case, current matrices may still contain references to
7611 images freed above. So, clear these matrices. */
7612 if (any_freed_p)
7613 {
7614 clear_current_matrices (f);
7615 ++windows_or_buffers_changed;
7616 }
7617 }
7618 }
7619
7620
7621 DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
7622 0, 1, 0,
7623 "Clear the image cache of FRAME.\n\
7624 FRAME nil or omitted means use the selected frame.\n\
7625 FRAME t means clear the image caches of all frames.")
7626 (frame)
7627 Lisp_Object frame;
7628 {
7629 if (EQ (frame, Qt))
7630 {
7631 Lisp_Object tail;
7632
7633 FOR_EACH_FRAME (tail, frame)
7634 if (FRAME_W32_P (XFRAME (frame)))
7635 clear_image_cache (XFRAME (frame), 1);
7636 }
7637 else
7638 clear_image_cache (check_x_frame (frame), 1);
7639
7640 return Qnil;
7641 }
7642
7643
7644 /* Return the id of image with Lisp specification SPEC on frame F.
7645 SPEC must be a valid Lisp image specification (see valid_image_p). */
7646
7647 int
7648 lookup_image (f, spec)
7649 struct frame *f;
7650 Lisp_Object spec;
7651 {
7652 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
7653 struct image *img;
7654 int i;
7655 unsigned hash;
7656 struct gcpro gcpro1;
7657 EMACS_TIME now;
7658
7659 /* F must be a window-system frame, and SPEC must be a valid image
7660 specification. */
7661 xassert (FRAME_WINDOW_P (f));
7662 xassert (valid_image_p (spec));
7663
7664 GCPRO1 (spec);
7665
7666 /* Look up SPEC in the hash table of the image cache. */
7667 hash = sxhash (spec, 0);
7668 i = hash % IMAGE_CACHE_BUCKETS_SIZE;
7669
7670 for (img = c->buckets[i]; img; img = img->next)
7671 if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
7672 break;
7673
7674 /* If not found, create a new image and cache it. */
7675 if (img == NULL)
7676 {
7677 img = make_image (spec, hash);
7678 cache_image (f, img);
7679 img->load_failed_p = img->type->load (f, img) == 0;
7680 xassert (!interrupt_input_blocked);
7681
7682 /* If we can't load the image, and we don't have a width and
7683 height, use some arbitrary width and height so that we can
7684 draw a rectangle for it. */
7685 if (img->load_failed_p)
7686 {
7687 Lisp_Object value;
7688
7689 value = image_spec_value (spec, QCwidth, NULL);
7690 img->width = (INTEGERP (value)
7691 ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH);
7692 value = image_spec_value (spec, QCheight, NULL);
7693 img->height = (INTEGERP (value)
7694 ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT);
7695 }
7696 else
7697 {
7698 /* Handle image type independent image attributes
7699 `:ascent PERCENT', `:margin MARGIN', `:relief RELIEF'. */
7700 Lisp_Object ascent, margin, relief, algorithm, heuristic_mask;
7701 Lisp_Object file;
7702
7703 ascent = image_spec_value (spec, QCascent, NULL);
7704 if (INTEGERP (ascent))
7705 img->ascent = XFASTINT (ascent);
7706
7707 margin = image_spec_value (spec, QCmargin, NULL);
7708 if (INTEGERP (margin) && XINT (margin) >= 0)
7709 img->margin = XFASTINT (margin);
7710
7711 relief = image_spec_value (spec, QCrelief, NULL);
7712 if (INTEGERP (relief))
7713 {
7714 img->relief = XINT (relief);
7715 img->margin += abs (img->relief);
7716 }
7717
7718 /* Should we apply a Laplace edge-detection algorithm? */
7719 algorithm = image_spec_value (spec, QCalgorithm, NULL);
7720 if (img->pixmap && EQ (algorithm, Qlaplace))
7721 x_laplace (f, img);
7722
7723 /* Should we built a mask heuristically? */
7724 heuristic_mask = image_spec_value (spec, QCheuristic_mask, NULL);
7725 if (img->pixmap && !img->mask && !NILP (heuristic_mask))
7726 x_build_heuristic_mask (f, img, heuristic_mask);
7727 }
7728 }
7729
7730 /* We're using IMG, so set its timestamp to `now'. */
7731 EMACS_GET_TIME (now);
7732 img->timestamp = EMACS_SECS (now);
7733
7734 UNGCPRO;
7735
7736 /* Value is the image id. */
7737 return img->id;
7738 }
7739
7740
7741 /* Cache image IMG in the image cache of frame F. */
7742
7743 static void
7744 cache_image (f, img)
7745 struct frame *f;
7746 struct image *img;
7747 {
7748 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
7749 int i;
7750
7751 /* Find a free slot in c->images. */
7752 for (i = 0; i < c->used; ++i)
7753 if (c->images[i] == NULL)
7754 break;
7755
7756 /* If no free slot found, maybe enlarge c->images. */
7757 if (i == c->used && c->used == c->size)
7758 {
7759 c->size *= 2;
7760 c->images = (struct image **) xrealloc (c->images,
7761 c->size * sizeof *c->images);
7762 }
7763
7764 /* Add IMG to c->images, and assign IMG an id. */
7765 c->images[i] = img;
7766 img->id = i;
7767 if (i == c->used)
7768 ++c->used;
7769
7770 /* Add IMG to the cache's hash table. */
7771 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
7772 img->next = c->buckets[i];
7773 if (img->next)
7774 img->next->prev = img;
7775 img->prev = NULL;
7776 c->buckets[i] = img;
7777 }
7778
7779
7780 /* Call FN on every image in the image cache of frame F. Used to mark
7781 Lisp Objects in the image cache. */
7782
7783 void
7784 forall_images_in_image_cache (f, fn)
7785 struct frame *f;
7786 void (*fn) P_ ((struct image *img));
7787 {
7788 if (FRAME_LIVE_P (f) && FRAME_W32_P (f))
7789 {
7790 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
7791 if (c)
7792 {
7793 int i;
7794 for (i = 0; i < c->used; ++i)
7795 if (c->images[i])
7796 fn (c->images[i]);
7797 }
7798 }
7799 }
7800
7801
7802 \f
7803 /***********************************************************************
7804 W32 support code
7805 ***********************************************************************/
7806
7807 #if 0 /* NTEMACS_TODO: W32 specific image code. */
7808
7809 static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
7810 XImage **, Pixmap *));
7811 static void x_destroy_x_image P_ ((XImage *));
7812 static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
7813
7814
7815 /* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
7816 frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created.
7817 Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
7818 via xmalloc. Print error messages via image_error if an error
7819 occurs. Value is non-zero if successful. */
7820
7821 static int
7822 x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
7823 struct frame *f;
7824 int width, height, depth;
7825 XImage **ximg;
7826 Pixmap *pixmap;
7827 {
7828 #if 0 /* NTEMACS_TODO: Image support for W32 */
7829 Display *display = FRAME_W32_DISPLAY (f);
7830 Screen *screen = FRAME_X_SCREEN (f);
7831 Window window = FRAME_W32_WINDOW (f);
7832
7833 xassert (interrupt_input_blocked);
7834
7835 if (depth <= 0)
7836 depth = DefaultDepthOfScreen (screen);
7837 *ximg = XCreateImage (display, DefaultVisualOfScreen (screen),
7838 depth, ZPixmap, 0, NULL, width, height,
7839 depth > 16 ? 32 : depth > 8 ? 16 : 8, 0);
7840 if (*ximg == NULL)
7841 {
7842 image_error ("Unable to allocate X image", Qnil, Qnil);
7843 return 0;
7844 }
7845
7846 /* Allocate image raster. */
7847 (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height);
7848
7849 /* Allocate a pixmap of the same size. */
7850 *pixmap = XCreatePixmap (display, window, width, height, depth);
7851 if (*pixmap == 0)
7852 {
7853 x_destroy_x_image (*ximg);
7854 *ximg = NULL;
7855 image_error ("Unable to create X pixmap", Qnil, Qnil);
7856 return 0;
7857 }
7858 #endif
7859 return 1;
7860 }
7861
7862
7863 /* Destroy XImage XIMG. Free XIMG->data. */
7864
7865 static void
7866 x_destroy_x_image (ximg)
7867 XImage *ximg;
7868 {
7869 xassert (interrupt_input_blocked);
7870 if (ximg)
7871 {
7872 xfree (ximg->data);
7873 ximg->data = NULL;
7874 XDestroyImage (ximg);
7875 }
7876 }
7877
7878
7879 /* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT
7880 are width and height of both the image and pixmap. */
7881
7882 static void
7883 x_put_x_image (f, ximg, pixmap, width, height)
7884 struct frame *f;
7885 XImage *ximg;
7886 Pixmap pixmap;
7887 {
7888 GC gc;
7889
7890 xassert (interrupt_input_blocked);
7891 gc = XCreateGC (NULL, pixmap, 0, NULL);
7892 XPutImage (NULL, pixmap, gc, ximg, 0, 0, 0, 0, width, height);
7893 XFreeGC (NULL, gc);
7894 }
7895
7896 #endif
7897
7898 \f
7899 /***********************************************************************
7900 Searching files
7901 ***********************************************************************/
7902
7903 static Lisp_Object x_find_image_file P_ ((Lisp_Object));
7904
7905 /* Find image file FILE. Look in data-directory, then
7906 x-bitmap-file-path. Value is the full name of the file found, or
7907 nil if not found. */
7908
7909 static Lisp_Object
7910 x_find_image_file (file)
7911 Lisp_Object file;
7912 {
7913 Lisp_Object file_found, search_path;
7914 struct gcpro gcpro1, gcpro2;
7915 int fd;
7916
7917 file_found = Qnil;
7918 search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
7919 GCPRO2 (file_found, search_path);
7920
7921 /* Try to find FILE in data-directory, then x-bitmap-file-path. */
7922 fd = openp (search_path, file, "", &file_found, 0);
7923
7924 if (fd < 0)
7925 file_found = Qnil;
7926 else
7927 close (fd);
7928
7929 UNGCPRO;
7930 return file_found;
7931 }
7932
7933
7934 \f
7935 /***********************************************************************
7936 XBM images
7937 ***********************************************************************/
7938
7939 static int xbm_load P_ ((struct frame *f, struct image *img));
7940 static int xbm_load_image_from_file P_ ((struct frame *f, struct image *img,
7941 Lisp_Object file));
7942 static int xbm_image_p P_ ((Lisp_Object object));
7943 static int xbm_read_bitmap_file_data P_ ((char *, int *, int *,
7944 unsigned char **));
7945
7946
7947 /* Indices of image specification fields in xbm_format, below. */
7948
7949 enum xbm_keyword_index
7950 {
7951 XBM_TYPE,
7952 XBM_FILE,
7953 XBM_WIDTH,
7954 XBM_HEIGHT,
7955 XBM_DATA,
7956 XBM_FOREGROUND,
7957 XBM_BACKGROUND,
7958 XBM_ASCENT,
7959 XBM_MARGIN,
7960 XBM_RELIEF,
7961 XBM_ALGORITHM,
7962 XBM_HEURISTIC_MASK,
7963 XBM_LAST
7964 };
7965
7966 /* Vector of image_keyword structures describing the format
7967 of valid XBM image specifications. */
7968
7969 static struct image_keyword xbm_format[XBM_LAST] =
7970 {
7971 {":type", IMAGE_SYMBOL_VALUE, 1},
7972 {":file", IMAGE_STRING_VALUE, 0},
7973 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
7974 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
7975 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7976 {":foreground", IMAGE_STRING_VALUE, 0},
7977 {":background", IMAGE_STRING_VALUE, 0},
7978 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
7979 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
7980 {":relief", IMAGE_INTEGER_VALUE, 0},
7981 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7982 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
7983 };
7984
7985 /* Structure describing the image type XBM. */
7986
7987 static struct image_type xbm_type =
7988 {
7989 &Qxbm,
7990 xbm_image_p,
7991 xbm_load,
7992 x_clear_image,
7993 NULL
7994 };
7995
7996 /* Tokens returned from xbm_scan. */
7997
7998 enum xbm_token
7999 {
8000 XBM_TK_IDENT = 256,
8001 XBM_TK_NUMBER
8002 };
8003
8004
8005 /* Return non-zero if OBJECT is a valid XBM-type image specification.
8006 A valid specification is a list starting with the symbol `image'
8007 The rest of the list is a property list which must contain an
8008 entry `:type xbm..
8009
8010 If the specification specifies a file to load, it must contain
8011 an entry `:file FILENAME' where FILENAME is a string.
8012
8013 If the specification is for a bitmap loaded from memory it must
8014 contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
8015 WIDTH and HEIGHT are integers > 0. DATA may be:
8016
8017 1. a string large enough to hold the bitmap data, i.e. it must
8018 have a size >= (WIDTH + 7) / 8 * HEIGHT
8019
8020 2. a bool-vector of size >= WIDTH * HEIGHT
8021
8022 3. a vector of strings or bool-vectors, one for each line of the
8023 bitmap.
8024
8025 Both the file and data forms may contain the additional entries
8026 `:background COLOR' and `:foreground COLOR'. If not present,
8027 foreground and background of the frame on which the image is
8028 displayed, is used. */
8029
8030 static int
8031 xbm_image_p (object)
8032 Lisp_Object object;
8033 {
8034 struct image_keyword kw[XBM_LAST];
8035
8036 bcopy (xbm_format, kw, sizeof kw);
8037 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
8038 return 0;
8039
8040 xassert (EQ (kw[XBM_TYPE].value, Qxbm));
8041
8042 if (kw[XBM_FILE].count)
8043 {
8044 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
8045 return 0;
8046 }
8047 else
8048 {
8049 Lisp_Object data;
8050 int width, height;
8051
8052 /* Entries for `:width', `:height' and `:data' must be present. */
8053 if (!kw[XBM_WIDTH].count
8054 || !kw[XBM_HEIGHT].count
8055 || !kw[XBM_DATA].count)
8056 return 0;
8057
8058 data = kw[XBM_DATA].value;
8059 width = XFASTINT (kw[XBM_WIDTH].value);
8060 height = XFASTINT (kw[XBM_HEIGHT].value);
8061
8062 /* Check type of data, and width and height against contents of
8063 data. */
8064 if (VECTORP (data))
8065 {
8066 int i;
8067
8068 /* Number of elements of the vector must be >= height. */
8069 if (XVECTOR (data)->size < height)
8070 return 0;
8071
8072 /* Each string or bool-vector in data must be large enough
8073 for one line of the image. */
8074 for (i = 0; i < height; ++i)
8075 {
8076 Lisp_Object elt = XVECTOR (data)->contents[i];
8077
8078 if (STRINGP (elt))
8079 {
8080 if (XSTRING (elt)->size
8081 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
8082 return 0;
8083 }
8084 else if (BOOL_VECTOR_P (elt))
8085 {
8086 if (XBOOL_VECTOR (elt)->size < width)
8087 return 0;
8088 }
8089 else
8090 return 0;
8091 }
8092 }
8093 else if (STRINGP (data))
8094 {
8095 if (XSTRING (data)->size
8096 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
8097 return 0;
8098 }
8099 else if (BOOL_VECTOR_P (data))
8100 {
8101 if (XBOOL_VECTOR (data)->size < width * height)
8102 return 0;
8103 }
8104 else
8105 return 0;
8106 }
8107
8108 /* Baseline must be a value between 0 and 100 (a percentage). */
8109 if (kw[XBM_ASCENT].count
8110 && XFASTINT (kw[XBM_ASCENT].value) > 100)
8111 return 0;
8112
8113 return 1;
8114 }
8115
8116
8117 /* Scan a bitmap file. FP is the stream to read from. Value is
8118 either an enumerator from enum xbm_token, or a character for a
8119 single-character token, or 0 at end of file. If scanning an
8120 identifier, store the lexeme of the identifier in SVAL. If
8121 scanning a number, store its value in *IVAL. */
8122
8123 static int
8124 xbm_scan (fp, sval, ival)
8125 FILE *fp;
8126 char *sval;
8127 int *ival;
8128 {
8129 int c;
8130
8131 /* Skip white space. */
8132 while ((c = fgetc (fp)) != EOF && isspace (c))
8133 ;
8134
8135 if (c == EOF)
8136 c = 0;
8137 else if (isdigit (c))
8138 {
8139 int value = 0, digit;
8140
8141 if (c == '0')
8142 {
8143 c = fgetc (fp);
8144 if (c == 'x' || c == 'X')
8145 {
8146 while ((c = fgetc (fp)) != EOF)
8147 {
8148 if (isdigit (c))
8149 digit = c - '0';
8150 else if (c >= 'a' && c <= 'f')
8151 digit = c - 'a' + 10;
8152 else if (c >= 'A' && c <= 'F')
8153 digit = c - 'A' + 10;
8154 else
8155 break;
8156 value = 16 * value + digit;
8157 }
8158 }
8159 else if (isdigit (c))
8160 {
8161 value = c - '0';
8162 while ((c = fgetc (fp)) != EOF
8163 && isdigit (c))
8164 value = 8 * value + c - '0';
8165 }
8166 }
8167 else
8168 {
8169 value = c - '0';
8170 while ((c = fgetc (fp)) != EOF
8171 && isdigit (c))
8172 value = 10 * value + c - '0';
8173 }
8174
8175 if (c != EOF)
8176 ungetc (c, fp);
8177 *ival = value;
8178 c = XBM_TK_NUMBER;
8179 }
8180 else if (isalpha (c) || c == '_')
8181 {
8182 *sval++ = c;
8183 while ((c = fgetc (fp)) != EOF
8184 && (isalnum (c) || c == '_'))
8185 *sval++ = c;
8186 *sval = 0;
8187 if (c != EOF)
8188 ungetc (c, fp);
8189 c = XBM_TK_IDENT;
8190 }
8191
8192 return c;
8193 }
8194
8195
8196 /* Replacement for XReadBitmapFileData which isn't available under old
8197 X versions. FILE is the name of the bitmap file to read. Set
8198 *WIDTH and *HEIGHT to the width and height of the image. Return in
8199 *DATA the bitmap data allocated with xmalloc. Value is non-zero if
8200 successful. */
8201
8202 static int
8203 xbm_read_bitmap_file_data (file, width, height, data)
8204 char *file;
8205 int *width, *height;
8206 unsigned char **data;
8207 {
8208 FILE *fp;
8209 char buffer[BUFSIZ];
8210 int padding_p = 0;
8211 int v10 = 0;
8212 int bytes_per_line, i, nbytes;
8213 unsigned char *p;
8214 int value;
8215 int LA1;
8216
8217 #define match() \
8218 LA1 = xbm_scan (fp, buffer, &value)
8219
8220 #define expect(TOKEN) \
8221 if (LA1 != (TOKEN)) \
8222 goto failure; \
8223 else \
8224 match ()
8225
8226 #define expect_ident(IDENT) \
8227 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
8228 match (); \
8229 else \
8230 goto failure
8231
8232 fp = fopen (file, "r");
8233 if (fp == NULL)
8234 return 0;
8235
8236 *width = *height = -1;
8237 *data = NULL;
8238 LA1 = xbm_scan (fp, buffer, &value);
8239
8240 /* Parse defines for width, height and hot-spots. */
8241 while (LA1 == '#')
8242 {
8243 match ();
8244 expect_ident ("define");
8245 expect (XBM_TK_IDENT);
8246
8247 if (LA1 == XBM_TK_NUMBER);
8248 {
8249 char *p = strrchr (buffer, '_');
8250 p = p ? p + 1 : buffer;
8251 if (strcmp (p, "width") == 0)
8252 *width = value;
8253 else if (strcmp (p, "height") == 0)
8254 *height = value;
8255 }
8256 expect (XBM_TK_NUMBER);
8257 }
8258
8259 if (*width < 0 || *height < 0)
8260 goto failure;
8261
8262 /* Parse bits. Must start with `static'. */
8263 expect_ident ("static");
8264 if (LA1 == XBM_TK_IDENT)
8265 {
8266 if (strcmp (buffer, "unsigned") == 0)
8267 {
8268 match ();
8269 expect_ident ("char");
8270 }
8271 else if (strcmp (buffer, "short") == 0)
8272 {
8273 match ();
8274 v10 = 1;
8275 if (*width % 16 && *width % 16 < 9)
8276 padding_p = 1;
8277 }
8278 else if (strcmp (buffer, "char") == 0)
8279 match ();
8280 else
8281 goto failure;
8282 }
8283 else
8284 goto failure;
8285
8286 expect (XBM_TK_IDENT);
8287 expect ('[');
8288 expect (']');
8289 expect ('=');
8290 expect ('{');
8291
8292 bytes_per_line = (*width + 7) / 8 + padding_p;
8293 nbytes = bytes_per_line * *height;
8294 p = *data = (char *) xmalloc (nbytes);
8295
8296 if (v10)
8297 {
8298
8299 for (i = 0; i < nbytes; i += 2)
8300 {
8301 int val = value;
8302 expect (XBM_TK_NUMBER);
8303
8304 *p++ = val;
8305 if (!padding_p || ((i + 2) % bytes_per_line))
8306 *p++ = value >> 8;
8307
8308 if (LA1 == ',' || LA1 == '}')
8309 match ();
8310 else
8311 goto failure;
8312 }
8313 }
8314 else
8315 {
8316 for (i = 0; i < nbytes; ++i)
8317 {
8318 int val = value;
8319 expect (XBM_TK_NUMBER);
8320
8321 *p++ = val;
8322
8323 if (LA1 == ',' || LA1 == '}')
8324 match ();
8325 else
8326 goto failure;
8327 }
8328 }
8329
8330 fclose (fp);
8331 return 1;
8332
8333 failure:
8334
8335 fclose (fp);
8336 if (*data)
8337 {
8338 xfree (*data);
8339 *data = NULL;
8340 }
8341 return 0;
8342
8343 #undef match
8344 #undef expect
8345 #undef expect_ident
8346 }
8347
8348
8349 /* Load XBM image IMG which will be displayed on frame F from file
8350 SPECIFIED_FILE. Value is non-zero if successful. */
8351
8352 static int
8353 xbm_load_image_from_file (f, img, specified_file)
8354 struct frame *f;
8355 struct image *img;
8356 Lisp_Object specified_file;
8357 {
8358 int rc;
8359 unsigned char *data;
8360 int success_p = 0;
8361 Lisp_Object file;
8362 struct gcpro gcpro1;
8363
8364 xassert (STRINGP (specified_file));
8365 file = Qnil;
8366 GCPRO1 (file);
8367
8368 file = x_find_image_file (specified_file);
8369 if (!STRINGP (file))
8370 {
8371 image_error ("Cannot find image file `%s'", specified_file, Qnil);
8372 UNGCPRO;
8373 return 0;
8374 }
8375
8376 rc = xbm_read_bitmap_file_data (XSTRING (file)->data, &img->width,
8377 &img->height, &data);
8378 if (rc)
8379 {
8380 int depth = one_w32_display_info.n_cbits;
8381 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
8382 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
8383 Lisp_Object value;
8384
8385 xassert (img->width > 0 && img->height > 0);
8386
8387 /* Get foreground and background colors, maybe allocate colors. */
8388 value = image_spec_value (img->spec, QCforeground, NULL);
8389 if (!NILP (value))
8390 foreground = x_alloc_image_color (f, img, value, foreground);
8391
8392 value = image_spec_value (img->spec, QCbackground, NULL);
8393 if (!NILP (value))
8394 background = x_alloc_image_color (f, img, value, background);
8395
8396 #if 0 /* NTEMACS_TODO : Port image display to W32 */
8397 BLOCK_INPUT;
8398 img->pixmap
8399 = XCreatePixmapFromBitmapData (FRAME_W32_DISPLAY (f),
8400 FRAME_W32_WINDOW (f),
8401 data,
8402 img->width, img->height,
8403 foreground, background,
8404 depth);
8405 xfree (data);
8406
8407 if (img->pixmap == 0)
8408 {
8409 x_clear_image (f, img);
8410 image_error ("Unable to create X pixmap for `%s'", file, Qnil);
8411 }
8412 else
8413 success_p = 1;
8414
8415 UNBLOCK_INPUT;
8416 #endif
8417 }
8418 else
8419 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
8420
8421 UNGCPRO;
8422 return success_p;
8423 }
8424
8425
8426 /* Fill image IMG which is used on frame F with pixmap data. Value is
8427 non-zero if successful. */
8428
8429 static int
8430 xbm_load (f, img)
8431 struct frame *f;
8432 struct image *img;
8433 {
8434 int success_p = 0;
8435 Lisp_Object file_name;
8436
8437 xassert (xbm_image_p (img->spec));
8438
8439 /* If IMG->spec specifies a file name, create a non-file spec from it. */
8440 file_name = image_spec_value (img->spec, QCfile, NULL);
8441 if (STRINGP (file_name))
8442 success_p = xbm_load_image_from_file (f, img, file_name);
8443 else
8444 {
8445 struct image_keyword fmt[XBM_LAST];
8446 Lisp_Object data;
8447 int depth;
8448 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
8449 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
8450 char *bits;
8451 int parsed_p;
8452
8453 /* Parse the list specification. */
8454 bcopy (xbm_format, fmt, sizeof fmt);
8455 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
8456 xassert (parsed_p);
8457
8458 /* Get specified width, and height. */
8459 img->width = XFASTINT (fmt[XBM_WIDTH].value);
8460 img->height = XFASTINT (fmt[XBM_HEIGHT].value);
8461 xassert (img->width > 0 && img->height > 0);
8462
8463 BLOCK_INPUT;
8464
8465 if (fmt[XBM_ASCENT].count)
8466 img->ascent = XFASTINT (fmt[XBM_ASCENT].value);
8467
8468 /* Get foreground and background colors, maybe allocate colors. */
8469 if (fmt[XBM_FOREGROUND].count)
8470 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
8471 foreground);
8472 if (fmt[XBM_BACKGROUND].count)
8473 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
8474 background);
8475
8476 /* Set bits to the bitmap image data. */
8477 data = fmt[XBM_DATA].value;
8478 if (VECTORP (data))
8479 {
8480 int i;
8481 char *p;
8482 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
8483
8484 p = bits = (char *) alloca (nbytes * img->height);
8485 for (i = 0; i < img->height; ++i, p += nbytes)
8486 {
8487 Lisp_Object line = XVECTOR (data)->contents[i];
8488 if (STRINGP (line))
8489 bcopy (XSTRING (line)->data, p, nbytes);
8490 else
8491 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
8492 }
8493 }
8494 else if (STRINGP (data))
8495 bits = XSTRING (data)->data;
8496 else
8497 bits = XBOOL_VECTOR (data)->data;
8498
8499 #if 0 /* NTEMACS_TODO : W32 XPM code */
8500 /* Create the pixmap. */
8501 depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
8502 img->pixmap
8503 = XCreatePixmapFromBitmapData (FRAME_W32_DISPLAY (f),
8504 FRAME_W32_WINDOW (f),
8505 bits,
8506 img->width, img->height,
8507 foreground, background,
8508 depth);
8509 #endif /* NTEMACS_TODO */
8510
8511 if (img->pixmap)
8512 success_p = 1;
8513 else
8514 {
8515 image_error ("Unable to create pixmap for XBM image `%s'",
8516 img->spec, Qnil);
8517 x_clear_image (f, img);
8518 }
8519
8520 UNBLOCK_INPUT;
8521 }
8522
8523 return success_p;
8524 }
8525
8526
8527 \f
8528 /***********************************************************************
8529 XPM images
8530 ***********************************************************************/
8531
8532 #if HAVE_XPM
8533
8534 static int xpm_image_p P_ ((Lisp_Object object));
8535 static int xpm_load P_ ((struct frame *f, struct image *img));
8536 static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
8537
8538 #include "X11/xpm.h"
8539
8540 /* The symbol `xpm' identifying XPM-format images. */
8541
8542 Lisp_Object Qxpm;
8543
8544 /* Indices of image specification fields in xpm_format, below. */
8545
8546 enum xpm_keyword_index
8547 {
8548 XPM_TYPE,
8549 XPM_FILE,
8550 XPM_DATA,
8551 XPM_ASCENT,
8552 XPM_MARGIN,
8553 XPM_RELIEF,
8554 XPM_ALGORITHM,
8555 XPM_HEURISTIC_MASK,
8556 XPM_COLOR_SYMBOLS,
8557 XPM_LAST
8558 };
8559
8560 /* Vector of image_keyword structures describing the format
8561 of valid XPM image specifications. */
8562
8563 static struct image_keyword xpm_format[XPM_LAST] =
8564 {
8565 {":type", IMAGE_SYMBOL_VALUE, 1},
8566 {":file", IMAGE_STRING_VALUE, 0},
8567 {":data", IMAGE_STRING_VALUE, 0},
8568 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8569 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
8570 {":relief", IMAGE_INTEGER_VALUE, 0},
8571 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8572 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8573 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
8574 };
8575
8576 /* Structure describing the image type XBM. */
8577
8578 static struct image_type xpm_type =
8579 {
8580 &Qxpm,
8581 xpm_image_p,
8582 xpm_load,
8583 x_clear_image,
8584 NULL
8585 };
8586
8587
8588 /* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
8589 for XPM images. Such a list must consist of conses whose car and
8590 cdr are strings. */
8591
8592 static int
8593 xpm_valid_color_symbols_p (color_symbols)
8594 Lisp_Object color_symbols;
8595 {
8596 while (CONSP (color_symbols))
8597 {
8598 Lisp_Object sym = XCAR (color_symbols);
8599 if (!CONSP (sym)
8600 || !STRINGP (XCAR (sym))
8601 || !STRINGP (XCDR (sym)))
8602 break;
8603 color_symbols = XCDR (color_symbols);
8604 }
8605
8606 return NILP (color_symbols);
8607 }
8608
8609
8610 /* Value is non-zero if OBJECT is a valid XPM image specification. */
8611
8612 static int
8613 xpm_image_p (object)
8614 Lisp_Object object;
8615 {
8616 struct image_keyword fmt[XPM_LAST];
8617 bcopy (xpm_format, fmt, sizeof fmt);
8618 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
8619 /* Either `:file' or `:data' must be present. */
8620 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
8621 /* Either no `:color-symbols' or it's a list of conses
8622 whose car and cdr are strings. */
8623 && (fmt[XPM_COLOR_SYMBOLS].count == 0
8624 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value))
8625 && (fmt[XPM_ASCENT].count == 0
8626 || XFASTINT (fmt[XPM_ASCENT].value) < 100));
8627 }
8628
8629
8630 /* Load image IMG which will be displayed on frame F. Value is
8631 non-zero if successful. */
8632
8633 static int
8634 xpm_load (f, img)
8635 struct frame *f;
8636 struct image *img;
8637 {
8638 int rc, i;
8639 XpmAttributes attrs;
8640 Lisp_Object specified_file, color_symbols;
8641
8642 /* Configure the XPM lib. Use the visual of frame F. Allocate
8643 close colors. Return colors allocated. */
8644 bzero (&attrs, sizeof attrs);
8645 attrs.visual = FRAME_W32_DISPLAY_INFO (f)->visual;
8646 attrs.valuemask |= XpmVisual;
8647 attrs.valuemask |= XpmReturnAllocPixels;
8648 attrs.alloc_close_colors = 1;
8649 attrs.valuemask |= XpmAllocCloseColors;
8650
8651 /* If image specification contains symbolic color definitions, add
8652 these to `attrs'. */
8653 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
8654 if (CONSP (color_symbols))
8655 {
8656 Lisp_Object tail;
8657 XpmColorSymbol *xpm_syms;
8658 int i, size;
8659
8660 attrs.valuemask |= XpmColorSymbols;
8661
8662 /* Count number of symbols. */
8663 attrs.numsymbols = 0;
8664 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
8665 ++attrs.numsymbols;
8666
8667 /* Allocate an XpmColorSymbol array. */
8668 size = attrs.numsymbols * sizeof *xpm_syms;
8669 xpm_syms = (XpmColorSymbol *) alloca (size);
8670 bzero (xpm_syms, size);
8671 attrs.colorsymbols = xpm_syms;
8672
8673 /* Fill the color symbol array. */
8674 for (tail = color_symbols, i = 0;
8675 CONSP (tail);
8676 ++i, tail = XCDR (tail))
8677 {
8678 Lisp_Object name = XCAR (XCAR (tail));
8679 Lisp_Object color = XCDR (XCAR (tail));
8680 xpm_syms[i].name = (char *) alloca (XSTRING (name)->size + 1);
8681 strcpy (xpm_syms[i].name, XSTRING (name)->data);
8682 xpm_syms[i].value = (char *) alloca (XSTRING (color)->size + 1);
8683 strcpy (xpm_syms[i].value, XSTRING (color)->data);
8684 }
8685 }
8686
8687 /* Create a pixmap for the image, either from a file, or from a
8688 string buffer containing data in the same format as an XPM file. */
8689 BLOCK_INPUT;
8690 specified_file = image_spec_value (img->spec, QCfile, NULL);
8691 if (STRINGP (specified_file))
8692 {
8693 Lisp_Object file = x_find_image_file (specified_file);
8694 if (!STRINGP (file))
8695 {
8696 image_error ("Cannot find image file `%s'", specified_file, Qnil);
8697 UNBLOCK_INPUT;
8698 return 0;
8699 }
8700
8701 rc = XpmReadFileToPixmap (NULL, FRAME_W32_WINDOW (f),
8702 XSTRING (file)->data, &img->pixmap, &img->mask,
8703 &attrs);
8704 }
8705 else
8706 {
8707 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
8708 rc = XpmCreatePixmapFromBuffer (NULL, FRAME_W32_WINDOW (f),
8709 XSTRING (buffer)->data,
8710 &img->pixmap, &img->mask,
8711 &attrs);
8712 }
8713 UNBLOCK_INPUT;
8714
8715 if (rc == XpmSuccess)
8716 {
8717 /* Remember allocated colors. */
8718 img->ncolors = attrs.nalloc_pixels;
8719 img->colors = (unsigned long *) xmalloc (img->ncolors
8720 * sizeof *img->colors);
8721 for (i = 0; i < attrs.nalloc_pixels; ++i)
8722 img->colors[i] = attrs.alloc_pixels[i];
8723
8724 img->width = attrs.width;
8725 img->height = attrs.height;
8726 xassert (img->width > 0 && img->height > 0);
8727
8728 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
8729 BLOCK_INPUT;
8730 XpmFreeAttributes (&attrs);
8731 UNBLOCK_INPUT;
8732 }
8733 else
8734 {
8735 switch (rc)
8736 {
8737 case XpmOpenFailed:
8738 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
8739 break;
8740
8741 case XpmFileInvalid:
8742 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
8743 break;
8744
8745 case XpmNoMemory:
8746 image_error ("Out of memory (%s)", img->spec, Qnil);
8747 break;
8748
8749 case XpmColorFailed:
8750 image_error ("Color allocation error (%s)", img->spec, Qnil);
8751 break;
8752
8753 default:
8754 image_error ("Unknown error (%s)", img->spec, Qnil);
8755 break;
8756 }
8757 }
8758
8759 return rc == XpmSuccess;
8760 }
8761
8762 #endif /* HAVE_XPM != 0 */
8763
8764 \f
8765 #if 0 /* NTEMACS_TODO : Color tables on W32. */
8766 /***********************************************************************
8767 Color table
8768 ***********************************************************************/
8769
8770 /* An entry in the color table mapping an RGB color to a pixel color. */
8771
8772 struct ct_color
8773 {
8774 int r, g, b;
8775 unsigned long pixel;
8776
8777 /* Next in color table collision list. */
8778 struct ct_color *next;
8779 };
8780
8781 /* The bucket vector size to use. Must be prime. */
8782
8783 #define CT_SIZE 101
8784
8785 /* Value is a hash of the RGB color given by R, G, and B. */
8786
8787 #define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
8788
8789 /* The color hash table. */
8790
8791 struct ct_color **ct_table;
8792
8793 /* Number of entries in the color table. */
8794
8795 int ct_colors_allocated;
8796
8797 /* Function prototypes. */
8798
8799 static void init_color_table P_ ((void));
8800 static void free_color_table P_ ((void));
8801 static unsigned long *colors_in_color_table P_ ((int *n));
8802 static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
8803 static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
8804
8805
8806 /* Initialize the color table. */
8807
8808 static void
8809 init_color_table ()
8810 {
8811 int size = CT_SIZE * sizeof (*ct_table);
8812 ct_table = (struct ct_color **) xmalloc (size);
8813 bzero (ct_table, size);
8814 ct_colors_allocated = 0;
8815 }
8816
8817
8818 /* Free memory associated with the color table. */
8819
8820 static void
8821 free_color_table ()
8822 {
8823 int i;
8824 struct ct_color *p, *next;
8825
8826 for (i = 0; i < CT_SIZE; ++i)
8827 for (p = ct_table[i]; p; p = next)
8828 {
8829 next = p->next;
8830 xfree (p);
8831 }
8832
8833 xfree (ct_table);
8834 ct_table = NULL;
8835 }
8836
8837
8838 /* Value is a pixel color for RGB color R, G, B on frame F. If an
8839 entry for that color already is in the color table, return the
8840 pixel color of that entry. Otherwise, allocate a new color for R,
8841 G, B, and make an entry in the color table. */
8842
8843 static unsigned long
8844 lookup_rgb_color (f, r, g, b)
8845 struct frame *f;
8846 int r, g, b;
8847 {
8848 unsigned hash = CT_HASH_RGB (r, g, b);
8849 int i = hash % CT_SIZE;
8850 struct ct_color *p;
8851
8852 for (p = ct_table[i]; p; p = p->next)
8853 if (p->r == r && p->g == g && p->b == b)
8854 break;
8855
8856 if (p == NULL)
8857 {
8858 COLORREF color;
8859 Colormap cmap;
8860 int rc;
8861
8862 color = PALETTERGB (r, g, b);
8863
8864 ++ct_colors_allocated;
8865
8866 p = (struct ct_color *) xmalloc (sizeof *p);
8867 p->r = r;
8868 p->g = g;
8869 p->b = b;
8870 p->pixel = color;
8871 p->next = ct_table[i];
8872 ct_table[i] = p;
8873 }
8874
8875 return p->pixel;
8876 }
8877
8878
8879 /* Look up pixel color PIXEL which is used on frame F in the color
8880 table. If not already present, allocate it. Value is PIXEL. */
8881
8882 static unsigned long
8883 lookup_pixel_color (f, pixel)
8884 struct frame *f;
8885 unsigned long pixel;
8886 {
8887 int i = pixel % CT_SIZE;
8888 struct ct_color *p;
8889
8890 for (p = ct_table[i]; p; p = p->next)
8891 if (p->pixel == pixel)
8892 break;
8893
8894 if (p == NULL)
8895 {
8896 XColor color;
8897 Colormap cmap;
8898 int rc;
8899
8900 BLOCK_INPUT;
8901
8902 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
8903 color.pixel = pixel;
8904 XQueryColor (NULL, cmap, &color);
8905 rc = x_alloc_nearest_color (f, cmap, &color);
8906 UNBLOCK_INPUT;
8907
8908 if (rc)
8909 {
8910 ++ct_colors_allocated;
8911
8912 p = (struct ct_color *) xmalloc (sizeof *p);
8913 p->r = color.red;
8914 p->g = color.green;
8915 p->b = color.blue;
8916 p->pixel = pixel;
8917 p->next = ct_table[i];
8918 ct_table[i] = p;
8919 }
8920 else
8921 return FRAME_FOREGROUND_PIXEL (f);
8922 }
8923 return p->pixel;
8924 }
8925
8926
8927 /* Value is a vector of all pixel colors contained in the color table,
8928 allocated via xmalloc. Set *N to the number of colors. */
8929
8930 static unsigned long *
8931 colors_in_color_table (n)
8932 int *n;
8933 {
8934 int i, j;
8935 struct ct_color *p;
8936 unsigned long *colors;
8937
8938 if (ct_colors_allocated == 0)
8939 {
8940 *n = 0;
8941 colors = NULL;
8942 }
8943 else
8944 {
8945 colors = (unsigned long *) xmalloc (ct_colors_allocated
8946 * sizeof *colors);
8947 *n = ct_colors_allocated;
8948
8949 for (i = j = 0; i < CT_SIZE; ++i)
8950 for (p = ct_table[i]; p; p = p->next)
8951 colors[j++] = p->pixel;
8952 }
8953
8954 return colors;
8955 }
8956
8957 #endif /* NTEMACS_TODO */
8958
8959 \f
8960 /***********************************************************************
8961 Algorithms
8962 ***********************************************************************/
8963
8964 #if 0 /* NTEMACS_TODO : W32 versions of low level algorithms */
8965 static void x_laplace_write_row P_ ((struct frame *, long *,
8966 int, XImage *, int));
8967 static void x_laplace_read_row P_ ((struct frame *, Colormap,
8968 XColor *, int, XImage *, int));
8969
8970
8971 /* Fill COLORS with RGB colors from row Y of image XIMG. F is the
8972 frame we operate on, CMAP is the color-map in effect, and WIDTH is
8973 the width of one row in the image. */
8974
8975 static void
8976 x_laplace_read_row (f, cmap, colors, width, ximg, y)
8977 struct frame *f;
8978 Colormap cmap;
8979 XColor *colors;
8980 int width;
8981 XImage *ximg;
8982 int y;
8983 {
8984 int x;
8985
8986 for (x = 0; x < width; ++x)
8987 colors[x].pixel = XGetPixel (ximg, x, y);
8988
8989 XQueryColors (NULL, cmap, colors, width);
8990 }
8991
8992
8993 /* Write row Y of image XIMG. PIXELS is an array of WIDTH longs
8994 containing the pixel colors to write. F is the frame we are
8995 working on. */
8996
8997 static void
8998 x_laplace_write_row (f, pixels, width, ximg, y)
8999 struct frame *f;
9000 long *pixels;
9001 int width;
9002 XImage *ximg;
9003 int y;
9004 {
9005 int x;
9006
9007 for (x = 0; x < width; ++x)
9008 XPutPixel (ximg, x, y, pixels[x]);
9009 }
9010 #endif
9011
9012 /* Transform image IMG which is used on frame F with a Laplace
9013 edge-detection algorithm. The result is an image that can be used
9014 to draw disabled buttons, for example. */
9015
9016 static void
9017 x_laplace (f, img)
9018 struct frame *f;
9019 struct image *img;
9020 {
9021 #if 0 /* NTEMACS_TODO : W32 version */
9022 Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
9023 XImage *ximg, *oimg;
9024 XColor *in[3];
9025 long *out;
9026 Pixmap pixmap;
9027 int x, y, i;
9028 long pixel;
9029 int in_y, out_y, rc;
9030 int mv2 = 45000;
9031
9032 BLOCK_INPUT;
9033
9034 /* Get the X image IMG->pixmap. */
9035 ximg = XGetImage (NULL, img->pixmap,
9036 0, 0, img->width, img->height, ~0, ZPixmap);
9037
9038 /* Allocate 3 input rows, and one output row of colors. */
9039 for (i = 0; i < 3; ++i)
9040 in[i] = (XColor *) alloca (img->width * sizeof (XColor));
9041 out = (long *) alloca (img->width * sizeof (long));
9042
9043 /* Create an X image for output. */
9044 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 0,
9045 &oimg, &pixmap);
9046
9047 /* Fill first two rows. */
9048 x_laplace_read_row (f, cmap, in[0], img->width, ximg, 0);
9049 x_laplace_read_row (f, cmap, in[1], img->width, ximg, 1);
9050 in_y = 2;
9051
9052 /* Write first row, all zeros. */
9053 init_color_table ();
9054 pixel = lookup_rgb_color (f, 0, 0, 0);
9055 for (x = 0; x < img->width; ++x)
9056 out[x] = pixel;
9057 x_laplace_write_row (f, out, img->width, oimg, 0);
9058 out_y = 1;
9059
9060 for (y = 2; y < img->height; ++y)
9061 {
9062 int rowa = y % 3;
9063 int rowb = (y + 2) % 3;
9064
9065 x_laplace_read_row (f, cmap, in[rowa], img->width, ximg, in_y++);
9066
9067 for (x = 0; x < img->width - 2; ++x)
9068 {
9069 int r = in[rowa][x].red + mv2 - in[rowb][x + 2].red;
9070 int g = in[rowa][x].green + mv2 - in[rowb][x + 2].green;
9071 int b = in[rowa][x].blue + mv2 - in[rowb][x + 2].blue;
9072
9073 out[x + 1] = lookup_rgb_color (f, r & 0xffff, g & 0xffff,
9074 b & 0xffff);
9075 }
9076
9077 x_laplace_write_row (f, out, img->width, oimg, out_y++);
9078 }
9079
9080 /* Write last line, all zeros. */
9081 for (x = 0; x < img->width; ++x)
9082 out[x] = pixel;
9083 x_laplace_write_row (f, out, img->width, oimg, out_y);
9084
9085 /* Free the input image, and free resources of IMG. */
9086 XDestroyImage (ximg);
9087 x_clear_image (f, img);
9088
9089 /* Put the output image into pixmap, and destroy it. */
9090 x_put_x_image (f, oimg, pixmap, img->width, img->height);
9091 x_destroy_x_image (oimg);
9092
9093 /* Remember new pixmap and colors in IMG. */
9094 img->pixmap = pixmap;
9095 img->colors = colors_in_color_table (&img->ncolors);
9096 free_color_table ();
9097
9098 UNBLOCK_INPUT;
9099 #endif /* NTEMACS_TODO */
9100 }
9101
9102
9103 /* Build a mask for image IMG which is used on frame F. FILE is the
9104 name of an image file, for error messages. HOW determines how to
9105 determine the background color of IMG. If it is a list '(R G B)',
9106 with R, G, and B being integers >= 0, take that as the color of the
9107 background. Otherwise, determine the background color of IMG
9108 heuristically. Value is non-zero if successful. */
9109
9110 static int
9111 x_build_heuristic_mask (f, img, how)
9112 struct frame *f;
9113 struct image *img;
9114 Lisp_Object how;
9115 {
9116 #if 0 /* NTEMACS_TODO : W32 version */
9117 Display *dpy = FRAME_W32_DISPLAY (f);
9118 XImage *ximg, *mask_img;
9119 int x, y, rc, look_at_corners_p;
9120 unsigned long bg;
9121
9122 BLOCK_INPUT;
9123
9124 /* Create an image and pixmap serving as mask. */
9125 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
9126 &mask_img, &img->mask);
9127 if (!rc)
9128 {
9129 UNBLOCK_INPUT;
9130 return 0;
9131 }
9132
9133 /* Get the X image of IMG->pixmap. */
9134 ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height,
9135 ~0, ZPixmap);
9136
9137 /* Determine the background color of ximg. If HOW is `(R G B)'
9138 take that as color. Otherwise, try to determine the color
9139 heuristically. */
9140 look_at_corners_p = 1;
9141
9142 if (CONSP (how))
9143 {
9144 int rgb[3], i = 0;
9145
9146 while (i < 3
9147 && CONSP (how)
9148 && NATNUMP (XCAR (how)))
9149 {
9150 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
9151 how = XCDR (how);
9152 }
9153
9154 if (i == 3 && NILP (how))
9155 {
9156 char color_name[30];
9157 XColor exact, color;
9158 Colormap cmap;
9159
9160 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
9161
9162 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
9163 if (XLookupColor (dpy, cmap, color_name, &exact, &color))
9164 {
9165 bg = color.pixel;
9166 look_at_corners_p = 0;
9167 }
9168 }
9169 }
9170
9171 if (look_at_corners_p)
9172 {
9173 unsigned long corners[4];
9174 int i, best_count;
9175
9176 /* Get the colors at the corners of ximg. */
9177 corners[0] = XGetPixel (ximg, 0, 0);
9178 corners[1] = XGetPixel (ximg, img->width - 1, 0);
9179 corners[2] = XGetPixel (ximg, img->width - 1, img->height - 1);
9180 corners[3] = XGetPixel (ximg, 0, img->height - 1);
9181
9182 /* Choose the most frequently found color as background. */
9183 for (i = best_count = 0; i < 4; ++i)
9184 {
9185 int j, n;
9186
9187 for (j = n = 0; j < 4; ++j)
9188 if (corners[i] == corners[j])
9189 ++n;
9190
9191 if (n > best_count)
9192 bg = corners[i], best_count = n;
9193 }
9194 }
9195
9196 /* Set all bits in mask_img to 1 whose color in ximg is different
9197 from the background color bg. */
9198 for (y = 0; y < img->height; ++y)
9199 for (x = 0; x < img->width; ++x)
9200 XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg);
9201
9202 /* Put mask_img into img->mask. */
9203 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
9204 x_destroy_x_image (mask_img);
9205 XDestroyImage (ximg);
9206
9207 UNBLOCK_INPUT;
9208 #endif /* NTEMACS_TODO */
9209
9210 return 1;
9211 }
9212
9213
9214 \f
9215 /***********************************************************************
9216 PBM (mono, gray, color)
9217 ***********************************************************************/
9218 #ifdef HAVE_PBM
9219
9220 static int pbm_image_p P_ ((Lisp_Object object));
9221 static int pbm_load P_ ((struct frame *f, struct image *img));
9222 static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
9223
9224 /* The symbol `pbm' identifying images of this type. */
9225
9226 Lisp_Object Qpbm;
9227
9228 /* Indices of image specification fields in gs_format, below. */
9229
9230 enum pbm_keyword_index
9231 {
9232 PBM_TYPE,
9233 PBM_FILE,
9234 PBM_DATA,
9235 PBM_ASCENT,
9236 PBM_MARGIN,
9237 PBM_RELIEF,
9238 PBM_ALGORITHM,
9239 PBM_HEURISTIC_MASK,
9240 PBM_LAST
9241 };
9242
9243 /* Vector of image_keyword structures describing the format
9244 of valid user-defined image specifications. */
9245
9246 static struct image_keyword pbm_format[PBM_LAST] =
9247 {
9248 {":type", IMAGE_SYMBOL_VALUE, 1},
9249 {":file", IMAGE_STRING_VALUE, 0},
9250 {":data", IMAGE_STRING_VALUE, 0},
9251 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
9252 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9253 {":relief", IMAGE_INTEGER_VALUE, 0},
9254 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9255 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
9256 };
9257
9258 /* Structure describing the image type `pbm'. */
9259
9260 static struct image_type pbm_type =
9261 {
9262 &Qpbm,
9263 pbm_image_p,
9264 pbm_load,
9265 x_clear_image,
9266 NULL
9267 };
9268
9269
9270 /* Return non-zero if OBJECT is a valid PBM image specification. */
9271
9272 static int
9273 pbm_image_p (object)
9274 Lisp_Object object;
9275 {
9276 struct image_keyword fmt[PBM_LAST];
9277
9278 bcopy (pbm_format, fmt, sizeof fmt);
9279
9280 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm)
9281 || (fmt[PBM_ASCENT].count
9282 && XFASTINT (fmt[PBM_ASCENT].value) > 100))
9283 return 0;
9284
9285 /* Must specify either :data or :file. */
9286 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
9287 }
9288
9289
9290 /* Scan a decimal number from *S and return it. Advance *S while
9291 reading the number. END is the end of the string. Value is -1 at
9292 end of input. */
9293
9294 static int
9295 pbm_scan_number (s, end)
9296 unsigned char **s, *end;
9297 {
9298 int c, val = -1;
9299
9300 while (*s < end)
9301 {
9302 /* Skip white-space. */
9303 while (*s < end && (c = *(*s)++, isspace (c)))
9304 ;
9305
9306 if (c == '#')
9307 {
9308 /* Skip comment to end of line. */
9309 while (*s < end && (c = *(*s)++, c != '\n'))
9310 ;
9311 }
9312 else if (isdigit (c))
9313 {
9314 /* Read decimal number. */
9315 val = c - '0';
9316 while (*s < end && (c = *(*s)++, isdigit (c)))
9317 val = 10 * val + c - '0';
9318 break;
9319 }
9320 else
9321 break;
9322 }
9323
9324 return val;
9325 }
9326
9327
9328 /* Read FILE into memory. Value is a pointer to a buffer allocated
9329 with xmalloc holding FILE's contents. Value is null if an error
9330 occured. *SIZE is set to the size of the file. */
9331
9332 static char *
9333 pbm_read_file (file, size)
9334 Lisp_Object file;
9335 int *size;
9336 {
9337 FILE *fp = NULL;
9338 char *buf = NULL;
9339 struct stat st;
9340
9341 if (stat (XSTRING (file)->data, &st) == 0
9342 && (fp = fopen (XSTRING (file)->data, "r")) != NULL
9343 && (buf = (char *) xmalloc (st.st_size),
9344 fread (buf, 1, st.st_size, fp) == st.st_size))
9345 {
9346 *size = st.st_size;
9347 fclose (fp);
9348 }
9349 else
9350 {
9351 if (fp)
9352 fclose (fp);
9353 if (buf)
9354 {
9355 xfree (buf);
9356 buf = NULL;
9357 }
9358 }
9359
9360 return buf;
9361 }
9362
9363
9364 /* Load PBM image IMG for use on frame F. */
9365
9366 static int
9367 pbm_load (f, img)
9368 struct frame *f;
9369 struct image *img;
9370 {
9371 int raw_p, x, y;
9372 int width, height, max_color_idx = 0;
9373 XImage *ximg;
9374 Lisp_Object file, specified_file;
9375 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
9376 struct gcpro gcpro1;
9377 unsigned char *contents = NULL;
9378 unsigned char *end, *p;
9379 int size;
9380
9381 specified_file = image_spec_value (img->spec, QCfile, NULL);
9382 file = Qnil;
9383 GCPRO1 (file);
9384
9385 if (STRINGP (specified_file))
9386 {
9387 file = x_find_image_file (specified_file);
9388 if (!STRINGP (file))
9389 {
9390 image_error ("Cannot find image file `%s'", specified_file, Qnil);
9391 UNGCPRO;
9392 return 0;
9393 }
9394
9395 contents = pbm_read_file (file, &size);
9396 if (contents == NULL)
9397 {
9398 image_error ("Error reading `%s'", file, Qnil);
9399 UNGCPRO;
9400 return 0;
9401 }
9402
9403 p = contents;
9404 end = contents + size;
9405 }
9406 else
9407 {
9408 Lisp_Object data;
9409 data = image_spec_value (img->spec, QCdata, NULL);
9410 p = XSTRING (data)->data;
9411 end = p + STRING_BYTES (XSTRING (data));
9412 }
9413
9414 /* Check magic number. */
9415 if (end - p < 2 || *p++ != 'P')
9416 {
9417 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
9418 error:
9419 xfree (contents);
9420 UNGCPRO;
9421 return 0;
9422 }
9423
9424 if (*magic != 'P')
9425 {
9426 fclose (fp);
9427 image_error ("Not a PBM image file: %s", file, Qnil);
9428 UNGCPRO;
9429 return 0;
9430 }
9431
9432 switch (*p++)
9433 {
9434 case '1':
9435 raw_p = 0, type = PBM_MONO;
9436 break;
9437
9438 case '2':
9439 raw_p = 0, type = PBM_GRAY;
9440 break;
9441
9442 case '3':
9443 raw_p = 0, type = PBM_COLOR;
9444 break;
9445
9446 case '4':
9447 raw_p = 1, type = PBM_MONO;
9448 break;
9449
9450 case '5':
9451 raw_p = 1, type = PBM_GRAY;
9452 break;
9453
9454 case '6':
9455 raw_p = 1, type = PBM_COLOR;
9456 break;
9457
9458 default:
9459 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
9460 goto error;
9461 }
9462
9463 /* Read width, height, maximum color-component. Characters
9464 starting with `#' up to the end of a line are ignored. */
9465 width = pbm_scan_number (&p, end);
9466 height = pbm_scan_number (&p, end);
9467
9468 if (type != PBM_MONO)
9469 {
9470 max_color_idx = pbm_scan_number (&p, end);
9471 if (raw_p && max_color_idx > 255)
9472 max_color_idx = 255;
9473 }
9474
9475 if (width < 0
9476 || height < 0
9477 || (type != PBM_MONO && max_color_idx < 0))
9478 goto error;
9479
9480 BLOCK_INPUT;
9481 if (!x_create_x_image_and_pixmap (f, width, height, 0,
9482 &ximg, &img->pixmap))
9483 {
9484 UNBLOCK_INPUT;
9485 goto error;
9486 }
9487
9488 /* Initialize the color hash table. */
9489 init_color_table ();
9490
9491 if (type == PBM_MONO)
9492 {
9493 int c = 0, g;
9494
9495 for (y = 0; y < height; ++y)
9496 for (x = 0; x < width; ++x)
9497 {
9498 if (raw_p)
9499 {
9500 if ((x & 7) == 0)
9501 c = *p++;
9502 g = c & 0x80;
9503 c <<= 1;
9504 }
9505 else
9506 g = pbm_scan_number (&p, end);
9507
9508 XPutPixel (ximg, x, y, (g
9509 ? FRAME_FOREGROUND_PIXEL (f)
9510 : FRAME_BACKGROUND_PIXEL (f)));
9511 }
9512 }
9513 else
9514 {
9515 for (y = 0; y < height; ++y)
9516 for (x = 0; x < width; ++x)
9517 {
9518 int r, g, b;
9519
9520 if (type == PBM_GRAY)
9521 r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
9522 else if (raw_p)
9523 {
9524 r = *p++;
9525 g = *p++;
9526 b = *p++;
9527 }
9528 else
9529 {
9530 r = pbm_scan_number (&p, end);
9531 g = pbm_scan_number (&p, end);
9532 b = pbm_scan_number (&p, end);
9533 }
9534
9535 if (r < 0 || g < 0 || b < 0)
9536 {
9537 b xfree (ximg->data);
9538 ximg->data = NULL;
9539 XDestroyImage (ximg);
9540 UNBLOCK_INPUT;
9541 image_error ("Invalid pixel value in image `%s'",
9542 img->spec, Qnil);
9543 goto error;
9544 }
9545
9546 /* RGB values are now in the range 0..max_color_idx.
9547 Scale this to the range 0..0xffff supported by X. */
9548 r = (double) r * 65535 / max_color_idx;
9549 g = (double) g * 65535 / max_color_idx;
9550 b = (double) b * 65535 / max_color_idx;
9551 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
9552 }
9553 }
9554
9555 /* Store in IMG->colors the colors allocated for the image, and
9556 free the color table. */
9557 img->colors = colors_in_color_table (&img->ncolors);
9558 free_color_table ();
9559
9560 /* Put the image into a pixmap. */
9561 x_put_x_image (f, ximg, img->pixmap, width, height);
9562 x_destroy_x_image (ximg);
9563 UNBLOCK_INPUT;
9564
9565 img->width = width;
9566 img->height = height;
9567
9568 UNGCPRO;
9569 xfree (contents);
9570 return 1;
9571 }
9572 #endif /* HAVE_PBM */
9573
9574 \f
9575 /***********************************************************************
9576 PNG
9577 ***********************************************************************/
9578
9579 #if HAVE_PNG
9580
9581 #include <png.h>
9582
9583 /* Function prototypes. */
9584
9585 static int png_image_p P_ ((Lisp_Object object));
9586 static int png_load P_ ((struct frame *f, struct image *img));
9587
9588 /* The symbol `png' identifying images of this type. */
9589
9590 Lisp_Object Qpng;
9591
9592 /* Indices of image specification fields in png_format, below. */
9593
9594 enum png_keyword_index
9595 {
9596 PNG_TYPE,
9597 PNG_DATA,
9598 PNG_FILE,
9599 PNG_ASCENT,
9600 PNG_MARGIN,
9601 PNG_RELIEF,
9602 PNG_ALGORITHM,
9603 PNG_HEURISTIC_MASK,
9604 PNG_LAST
9605 };
9606
9607 /* Vector of image_keyword structures describing the format
9608 of valid user-defined image specifications. */
9609
9610 static struct image_keyword png_format[PNG_LAST] =
9611 {
9612 {":type", IMAGE_SYMBOL_VALUE, 1},
9613 {":data", IMAGE_STRING_VALUE, 0},
9614 {":file", IMAGE_STRING_VALUE, 0},
9615 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
9616 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9617 {":relief", IMAGE_INTEGER_VALUE, 0},
9618 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9619 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
9620 };
9621
9622 /* Structure describing the image type `png'. */
9623
9624 static struct image_type png_type =
9625 {
9626 &Qpng,
9627 png_image_p,
9628 png_load,
9629 x_clear_image,
9630 NULL
9631 };
9632
9633
9634 /* Return non-zero if OBJECT is a valid PNG image specification. */
9635
9636 static int
9637 png_image_p (object)
9638 Lisp_Object object;
9639 {
9640 struct image_keyword fmt[PNG_LAST];
9641 bcopy (png_format, fmt, sizeof fmt);
9642
9643 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng)
9644 || (fmt[PNG_ASCENT].count
9645 && XFASTINT (fmt[PNG_ASCENT].value) > 100))
9646 return 0;
9647
9648 /* Must specify either the :data or :file keyword. */
9649 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
9650 }
9651
9652
9653 /* Error and warning handlers installed when the PNG library
9654 is initialized. */
9655
9656 static void
9657 my_png_error (png_ptr, msg)
9658 png_struct *png_ptr;
9659 char *msg;
9660 {
9661 xassert (png_ptr != NULL);
9662 image_error ("PNG error: %s", build_string (msg), Qnil);
9663 longjmp (png_ptr->jmpbuf, 1);
9664 }
9665
9666
9667 static void
9668 my_png_warning (png_ptr, msg)
9669 png_struct *png_ptr;
9670 char *msg;
9671 {
9672 xassert (png_ptr != NULL);
9673 image_error ("PNG warning: %s", build_string (msg), Qnil);
9674 }
9675
9676
9677 /* Memory source for PNG decoding. */
9678
9679 struct png_memory_storage
9680 {
9681 unsigned char *bytes; /* The data */
9682 size_t len; /* How big is it? */
9683 int index; /* Where are we? */
9684 };
9685
9686
9687 /* Function set as reader function when reading PNG image from memory.
9688 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
9689 bytes from the input to DATA. */
9690
9691 static void
9692 png_read_from_memory (png_ptr, data, length)
9693 png_structp png_ptr;
9694 png_bytep data;
9695 png_size_t length;
9696 {
9697 struct png_memory_storage *tbr
9698 = (struct png_memory_storage *) png_get_io_ptr (png_ptr);
9699
9700 if (length > tbr->len - tbr->index)
9701 png_error (png_ptr, "Read error");
9702
9703 bcopy (tbr->bytes + tbr->index, data, length);
9704 tbr->index = tbr->index + length;
9705 }
9706
9707
9708 /* Load PNG image IMG for use on frame F. Value is non-zero if
9709 successful. */
9710
9711 static int
9712 png_load (f, img)
9713 struct frame *f;
9714 struct image *img;
9715 {
9716 Lisp_Object file, specified_file;
9717 Lisp_Object specified_data;
9718 int x, y, i;
9719 XImage *ximg, *mask_img = NULL;
9720 struct gcpro gcpro1;
9721 png_struct *png_ptr = NULL;
9722 png_info *info_ptr = NULL, *end_info = NULL;
9723 FILE *fp = NULL;
9724 png_byte sig[8];
9725 png_byte *pixels = NULL;
9726 png_byte **rows = NULL;
9727 png_uint_32 width, height;
9728 int bit_depth, color_type, interlace_type;
9729 png_byte channels;
9730 png_uint_32 row_bytes;
9731 int transparent_p;
9732 char *gamma_str;
9733 double screen_gamma, image_gamma;
9734 int intent;
9735 struct png_memory_storage tbr; /* Data to be read */
9736
9737 /* Find out what file to load. */
9738 specified_file = image_spec_value (img->spec, QCfile, NULL);
9739 specified_data = image_spec_value (img->spec, QCdata, NULL);
9740 file = Qnil;
9741 GCPRO1 (file);
9742
9743 if (NILP (specified_data))
9744 {
9745 file = x_find_image_file (specified_file);
9746 if (!STRINGP (file))
9747 {
9748 image_error ("Cannot find image file `%s'", specified_file, Qnil);
9749 UNGCPRO;
9750 return 0;
9751 }
9752
9753 /* Open the image file. */
9754 fp = fopen (XSTRING (file)->data, "rb");
9755 if (!fp)
9756 {
9757 image_error ("Cannot open image file `%s'", file, Qnil);
9758 UNGCPRO;
9759 fclose (fp);
9760 return 0;
9761 }
9762
9763 /* Check PNG signature. */
9764 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
9765 || !png_check_sig (sig, sizeof sig))
9766 {
9767 image_error ("Not a PNG file:` %s'", file, Qnil);
9768 UNGCPRO;
9769 fclose (fp);
9770 return 0;
9771 }
9772 }
9773 else
9774 {
9775 /* Read from memory. */
9776 tbr.bytes = XSTRING (specified_data)->data;
9777 tbr.len = STRING_BYTES (XSTRING (specified_data));
9778 tbr.index = 0;
9779
9780 /* Check PNG signature. */
9781 if (tbr.len < sizeof sig
9782 || !png_check_sig (tbr.bytes, sizeof sig))
9783 {
9784 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
9785 UNGCPRO;
9786 return 0;
9787 }
9788
9789 /* Need to skip past the signature. */
9790 tbr.bytes += sizeof (sig);
9791 }
9792
9793
9794 /* Initialize read and info structs for PNG lib. */
9795 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
9796 my_png_error, my_png_warning);
9797 if (!png_ptr)
9798 {
9799 if (fp) fclose (fp);
9800 UNGCPRO;
9801 return 0;
9802 }
9803
9804 info_ptr = png_create_info_struct (png_ptr);
9805 if (!info_ptr)
9806 {
9807 png_destroy_read_struct (&png_ptr, NULL, NULL);
9808 if (fp) fclose (fp);
9809 UNGCPRO;
9810 return 0;
9811 }
9812
9813 end_info = png_create_info_struct (png_ptr);
9814 if (!end_info)
9815 {
9816 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
9817 if (fp) fclose (fp);
9818 UNGCPRO;
9819 return 0;
9820 }
9821
9822 /* Set error jump-back. We come back here when the PNG library
9823 detects an error. */
9824 if (setjmp (png_ptr->jmpbuf))
9825 {
9826 error:
9827 if (png_ptr)
9828 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
9829 xfree (pixels);
9830 xfree (rows);
9831 if (fp) fclose (fp);
9832 UNGCPRO;
9833 return 0;
9834 }
9835
9836 /* Read image info. */
9837 if (!NILP (specified_data))
9838 png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
9839 else
9840 png_init_io (png_ptr, fp);
9841
9842 png_set_sig_bytes (png_ptr, sizeof sig);
9843 png_read_info (png_ptr, info_ptr);
9844 png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
9845 &interlace_type, NULL, NULL);
9846
9847 /* If image contains simply transparency data, we prefer to
9848 construct a clipping mask. */
9849 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
9850 transparent_p = 1;
9851 else
9852 transparent_p = 0;
9853
9854 /* This function is easier to write if we only have to handle
9855 one data format: RGB or RGBA with 8 bits per channel. Let's
9856 transform other formats into that format. */
9857
9858 /* Strip more than 8 bits per channel. */
9859 if (bit_depth == 16)
9860 png_set_strip_16 (png_ptr);
9861
9862 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
9863 if available. */
9864 png_set_expand (png_ptr);
9865
9866 /* Convert grayscale images to RGB. */
9867 if (color_type == PNG_COLOR_TYPE_GRAY
9868 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
9869 png_set_gray_to_rgb (png_ptr);
9870
9871 /* The value 2.2 is a guess for PC monitors from PNG example.c. */
9872 gamma_str = getenv ("SCREEN_GAMMA");
9873 screen_gamma = gamma_str ? atof (gamma_str) : 2.2;
9874
9875 /* Tell the PNG lib to handle gamma correction for us. */
9876
9877 #if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
9878 if (png_get_sRGB (png_ptr, info_ptr, &intent))
9879 /* There is a special chunk in the image specifying the gamma. */
9880 png_set_sRGB (png_ptr, info_ptr, intent);
9881 else
9882 #endif
9883 if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
9884 /* Image contains gamma information. */
9885 png_set_gamma (png_ptr, screen_gamma, image_gamma);
9886 else
9887 /* Use a default of 0.5 for the image gamma. */
9888 png_set_gamma (png_ptr, screen_gamma, 0.5);
9889
9890 /* Handle alpha channel by combining the image with a background
9891 color. Do this only if a real alpha channel is supplied. For
9892 simple transparency, we prefer a clipping mask. */
9893 if (!transparent_p)
9894 {
9895 png_color_16 *image_background;
9896
9897 if (png_get_bKGD (png_ptr, info_ptr, &image_background))
9898 /* Image contains a background color with which to
9899 combine the image. */
9900 png_set_background (png_ptr, image_background,
9901 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
9902 else
9903 {
9904 /* Image does not contain a background color with which
9905 to combine the image data via an alpha channel. Use
9906 the frame's background instead. */
9907 XColor color;
9908 Colormap cmap;
9909 png_color_16 frame_background;
9910
9911 BLOCK_INPUT;
9912 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
9913 color.pixel = FRAME_BACKGROUND_PIXEL (f);
9914 XQueryColor (FRAME_W32_DISPLAY (f), cmap, &color);
9915 UNBLOCK_INPUT;
9916
9917 bzero (&frame_background, sizeof frame_background);
9918 frame_background.red = color.red;
9919 frame_background.green = color.green;
9920 frame_background.blue = color.blue;
9921
9922 png_set_background (png_ptr, &frame_background,
9923 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
9924 }
9925 }
9926
9927 /* Update info structure. */
9928 png_read_update_info (png_ptr, info_ptr);
9929
9930 /* Get number of channels. Valid values are 1 for grayscale images
9931 and images with a palette, 2 for grayscale images with transparency
9932 information (alpha channel), 3 for RGB images, and 4 for RGB
9933 images with alpha channel, i.e. RGBA. If conversions above were
9934 sufficient we should only have 3 or 4 channels here. */
9935 channels = png_get_channels (png_ptr, info_ptr);
9936 xassert (channels == 3 || channels == 4);
9937
9938 /* Number of bytes needed for one row of the image. */
9939 row_bytes = png_get_rowbytes (png_ptr, info_ptr);
9940
9941 /* Allocate memory for the image. */
9942 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
9943 rows = (png_byte **) xmalloc (height * sizeof *rows);
9944 for (i = 0; i < height; ++i)
9945 rows[i] = pixels + i * row_bytes;
9946
9947 /* Read the entire image. */
9948 png_read_image (png_ptr, rows);
9949 png_read_end (png_ptr, info_ptr);
9950 if (fp)
9951 {
9952 fclose (fp);
9953 fp = NULL;
9954 }
9955
9956 BLOCK_INPUT;
9957
9958 /* Create the X image and pixmap. */
9959 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
9960 &img->pixmap))
9961 {
9962 UNBLOCK_INPUT;
9963 goto error;
9964 }
9965
9966 /* Create an image and pixmap serving as mask if the PNG image
9967 contains an alpha channel. */
9968 if (channels == 4
9969 && !transparent_p
9970 && !x_create_x_image_and_pixmap (f, width, height, 1,
9971 &mask_img, &img->mask))
9972 {
9973 x_destroy_x_image (ximg);
9974 XFreePixmap (FRAME_W32_DISPLAY (f), img->pixmap);
9975 img->pixmap = 0;
9976 UNBLOCK_INPUT;
9977 goto error;
9978 }
9979
9980 /* Fill the X image and mask from PNG data. */
9981 init_color_table ();
9982
9983 for (y = 0; y < height; ++y)
9984 {
9985 png_byte *p = rows[y];
9986
9987 for (x = 0; x < width; ++x)
9988 {
9989 unsigned r, g, b;
9990
9991 r = *p++ << 8;
9992 g = *p++ << 8;
9993 b = *p++ << 8;
9994 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
9995
9996 /* An alpha channel, aka mask channel, associates variable
9997 transparency with an image. Where other image formats
9998 support binary transparency---fully transparent or fully
9999 opaque---PNG allows up to 254 levels of partial transparency.
10000 The PNG library implements partial transparency by combining
10001 the image with a specified background color.
10002
10003 I'm not sure how to handle this here nicely: because the
10004 background on which the image is displayed may change, for
10005 real alpha channel support, it would be necessary to create
10006 a new image for each possible background.
10007
10008 What I'm doing now is that a mask is created if we have
10009 boolean transparency information. Otherwise I'm using
10010 the frame's background color to combine the image with. */
10011
10012 if (channels == 4)
10013 {
10014 if (mask_img)
10015 XPutPixel (mask_img, x, y, *p > 0);
10016 ++p;
10017 }
10018 }
10019 }
10020
10021 /* Remember colors allocated for this image. */
10022 img->colors = colors_in_color_table (&img->ncolors);
10023 free_color_table ();
10024
10025 /* Clean up. */
10026 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
10027 xfree (rows);
10028 xfree (pixels);
10029
10030 img->width = width;
10031 img->height = height;
10032
10033 /* Put the image into the pixmap, then free the X image and its buffer. */
10034 x_put_x_image (f, ximg, img->pixmap, width, height);
10035 x_destroy_x_image (ximg);
10036
10037 /* Same for the mask. */
10038 if (mask_img)
10039 {
10040 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
10041 x_destroy_x_image (mask_img);
10042 }
10043
10044 UNBLOCK_INPUT;
10045 UNGCPRO;
10046 return 1;
10047 }
10048
10049 #endif /* HAVE_PNG != 0 */
10050
10051
10052 \f
10053 /***********************************************************************
10054 JPEG
10055 ***********************************************************************/
10056
10057 #if HAVE_JPEG
10058
10059 /* Work around a warning about HAVE_STDLIB_H being redefined in
10060 jconfig.h. */
10061 #ifdef HAVE_STDLIB_H
10062 #define HAVE_STDLIB_H_1
10063 #undef HAVE_STDLIB_H
10064 #endif /* HAVE_STLIB_H */
10065
10066 #include <jpeglib.h>
10067 #include <jerror.h>
10068 #include <setjmp.h>
10069
10070 #ifdef HAVE_STLIB_H_1
10071 #define HAVE_STDLIB_H 1
10072 #endif
10073
10074 static int jpeg_image_p P_ ((Lisp_Object object));
10075 static int jpeg_load P_ ((struct frame *f, struct image *img));
10076
10077 /* The symbol `jpeg' identifying images of this type. */
10078
10079 Lisp_Object Qjpeg;
10080
10081 /* Indices of image specification fields in gs_format, below. */
10082
10083 enum jpeg_keyword_index
10084 {
10085 JPEG_TYPE,
10086 JPEG_DATA,
10087 JPEG_FILE,
10088 JPEG_ASCENT,
10089 JPEG_MARGIN,
10090 JPEG_RELIEF,
10091 JPEG_ALGORITHM,
10092 JPEG_HEURISTIC_MASK,
10093 JPEG_LAST
10094 };
10095
10096 /* Vector of image_keyword structures describing the format
10097 of valid user-defined image specifications. */
10098
10099 static struct image_keyword jpeg_format[JPEG_LAST] =
10100 {
10101 {":type", IMAGE_SYMBOL_VALUE, 1},
10102 {":data", IMAGE_STRING_VALUE, 0},
10103 {":file", IMAGE_STRING_VALUE, 0},
10104 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
10105 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
10106 {":relief", IMAGE_INTEGER_VALUE, 0},
10107 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10108 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
10109 };
10110
10111 /* Structure describing the image type `jpeg'. */
10112
10113 static struct image_type jpeg_type =
10114 {
10115 &Qjpeg,
10116 jpeg_image_p,
10117 jpeg_load,
10118 x_clear_image,
10119 NULL
10120 };
10121
10122
10123 /* Return non-zero if OBJECT is a valid JPEG image specification. */
10124
10125 static int
10126 jpeg_image_p (object)
10127 Lisp_Object object;
10128 {
10129 struct image_keyword fmt[JPEG_LAST];
10130
10131 bcopy (jpeg_format, fmt, sizeof fmt);
10132
10133 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg)
10134 || (fmt[JPEG_ASCENT].count
10135 && XFASTINT (fmt[JPEG_ASCENT].value) > 100))
10136 return 0;
10137
10138 /* Must specify either the :data or :file keyword. */
10139 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
10140 }
10141
10142
10143 struct my_jpeg_error_mgr
10144 {
10145 struct jpeg_error_mgr pub;
10146 jmp_buf setjmp_buffer;
10147 };
10148
10149 static void
10150 my_error_exit (cinfo)
10151 j_common_ptr cinfo;
10152 {
10153 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
10154 longjmp (mgr->setjmp_buffer, 1);
10155 }
10156
10157
10158 /* Init source method for JPEG data source manager. Called by
10159 jpeg_read_header() before any data is actually read. See
10160 libjpeg.doc from the JPEG lib distribution. */
10161
10162 static void
10163 our_init_source (cinfo)
10164 j_decompress_ptr cinfo;
10165 {
10166 }
10167
10168
10169 /* Fill input buffer method for JPEG data source manager. Called
10170 whenever more data is needed. We read the whole image in one step,
10171 so this only adds a fake end of input marker at the end. */
10172
10173 static boolean
10174 our_fill_input_buffer (cinfo)
10175 j_decompress_ptr cinfo;
10176 {
10177 /* Insert a fake EOI marker. */
10178 struct jpeg_source_mgr *src = cinfo->src;
10179 static JOCTET buffer[2];
10180
10181 buffer[0] = (JOCTET) 0xFF;
10182 buffer[1] = (JOCTET) JPEG_EOI;
10183
10184 src->next_input_byte = buffer;
10185 src->bytes_in_buffer = 2;
10186 return TRUE;
10187 }
10188
10189
10190 /* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
10191 is the JPEG data source manager. */
10192
10193 static void
10194 our_skip_input_data (cinfo, num_bytes)
10195 j_decompress_ptr cinfo;
10196 long num_bytes;
10197 {
10198 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
10199
10200 if (src)
10201 {
10202 if (num_bytes > src->bytes_in_buffer)
10203 ERREXIT (cinfo, JERR_INPUT_EOF);
10204
10205 src->bytes_in_buffer -= num_bytes;
10206 src->next_input_byte += num_bytes;
10207 }
10208 }
10209
10210
10211 /* Method to terminate data source. Called by
10212 jpeg_finish_decompress() after all data has been processed. */
10213
10214 static void
10215 our_term_source (cinfo)
10216 j_decompress_ptr cinfo;
10217 {
10218 }
10219
10220
10221 /* Set up the JPEG lib for reading an image from DATA which contains
10222 LEN bytes. CINFO is the decompression info structure created for
10223 reading the image. */
10224
10225 static void
10226 jpeg_memory_src (cinfo, data, len)
10227 j_decompress_ptr cinfo;
10228 JOCTET *data;
10229 unsigned int len;
10230 {
10231 struct jpeg_source_mgr *src;
10232
10233 if (cinfo->src == NULL)
10234 {
10235 /* First time for this JPEG object? */
10236 cinfo->src = (struct jpeg_source_mgr *)
10237 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
10238 sizeof (struct jpeg_source_mgr));
10239 src = (struct jpeg_source_mgr *) cinfo->src;
10240 src->next_input_byte = data;
10241 }
10242
10243 src = (struct jpeg_source_mgr *) cinfo->src;
10244 src->init_source = our_init_source;
10245 src->fill_input_buffer = our_fill_input_buffer;
10246 src->skip_input_data = our_skip_input_data;
10247 src->resync_to_restart = jpeg_resync_to_restart; /* Use default method. */
10248 src->term_source = our_term_source;
10249 src->bytes_in_buffer = len;
10250 src->next_input_byte = data;
10251 }
10252
10253
10254 /* Load image IMG for use on frame F. Patterned after example.c
10255 from the JPEG lib. */
10256
10257 static int
10258 jpeg_load (f, img)
10259 struct frame *f;
10260 struct image *img;
10261 {
10262 struct jpeg_decompress_struct cinfo;
10263 struct my_jpeg_error_mgr mgr;
10264 Lisp_Object file, specified_file;
10265 Lisp_Object specified_data;
10266 FILE *fp = NULL;
10267 JSAMPARRAY buffer;
10268 int row_stride, x, y;
10269 XImage *ximg = NULL;
10270 int rc;
10271 unsigned long *colors;
10272 int width, height;
10273 struct gcpro gcpro1;
10274
10275 /* Open the JPEG file. */
10276 specified_file = image_spec_value (img->spec, QCfile, NULL);
10277 specified_data = image_spec_value (img->spec, QCdata, NULL);
10278 file = Qnil;
10279 GCPRO1 (file);
10280
10281
10282 if (NILP (specified_data))
10283 {
10284 file = x_find_image_file (specified_file);
10285 if (!STRINGP (file))
10286 {
10287 image_error ("Cannot find image file `%s'", specified_file, Qnil);
10288 UNGCPRO;
10289 return 0;
10290 }
10291
10292 fp = fopen (XSTRING (file)->data, "r");
10293 if (fp == NULL)
10294 {
10295 image_error ("Cannot open `%s'", file, Qnil);
10296 UNGCPRO;
10297 return 0;
10298 }
10299 }
10300
10301 /* Customize libjpeg's error handling to call my_error_exit when an
10302 error is detected. This function will perform a longjmp. */
10303 mgr.pub.error_exit = my_error_exit;
10304 cinfo.err = jpeg_std_error (&mgr.pub);
10305
10306 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
10307 {
10308 if (rc == 1)
10309 {
10310 /* Called from my_error_exit. Display a JPEG error. */
10311 char buffer[JMSG_LENGTH_MAX];
10312 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
10313 image_error ("Error reading JPEG image `%s': %s", img->spec,
10314 build_string (buffer));
10315 }
10316
10317 /* Close the input file and destroy the JPEG object. */
10318 if (fp)
10319 fclose (fp);
10320 jpeg_destroy_decompress (&cinfo);
10321
10322 BLOCK_INPUT;
10323
10324 /* If we already have an XImage, free that. */
10325 x_destroy_x_image (ximg);
10326
10327 /* Free pixmap and colors. */
10328 x_clear_image (f, img);
10329
10330 UNBLOCK_INPUT;
10331 UNGCPRO;
10332 return 0;
10333 }
10334
10335 /* Create the JPEG decompression object. Let it read from fp.
10336 Read the JPEG image header. */
10337 jpeg_create_decompress (&cinfo);
10338
10339 if (NILP (specified_data))
10340 jpeg_stdio_src (&cinfo, fp);
10341 else
10342 jpeg_memory_src (&cinfo, XSTRING (specified_data)->data,
10343 STRING_BYTES (XSTRING (specified_data)));
10344
10345 jpeg_read_header (&cinfo, TRUE);
10346
10347 /* Customize decompression so that color quantization will be used.
10348 Start decompression. */
10349 cinfo.quantize_colors = TRUE;
10350 jpeg_start_decompress (&cinfo);
10351 width = img->width = cinfo.output_width;
10352 height = img->height = cinfo.output_height;
10353
10354 BLOCK_INPUT;
10355
10356 /* Create X image and pixmap. */
10357 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
10358 &img->pixmap))
10359 {
10360 UNBLOCK_INPUT;
10361 longjmp (mgr.setjmp_buffer, 2);
10362 }
10363
10364 /* Allocate colors. When color quantization is used,
10365 cinfo.actual_number_of_colors has been set with the number of
10366 colors generated, and cinfo.colormap is a two-dimensional array
10367 of color indices in the range 0..cinfo.actual_number_of_colors.
10368 No more than 255 colors will be generated. */
10369 {
10370 int i, ir, ig, ib;
10371
10372 if (cinfo.out_color_components > 2)
10373 ir = 0, ig = 1, ib = 2;
10374 else if (cinfo.out_color_components > 1)
10375 ir = 0, ig = 1, ib = 0;
10376 else
10377 ir = 0, ig = 0, ib = 0;
10378
10379 /* Use the color table mechanism because it handles colors that
10380 cannot be allocated nicely. Such colors will be replaced with
10381 a default color, and we don't have to care about which colors
10382 can be freed safely, and which can't. */
10383 init_color_table ();
10384 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
10385 * sizeof *colors);
10386
10387 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
10388 {
10389 /* Multiply RGB values with 255 because X expects RGB values
10390 in the range 0..0xffff. */
10391 int r = cinfo.colormap[ir][i] << 8;
10392 int g = cinfo.colormap[ig][i] << 8;
10393 int b = cinfo.colormap[ib][i] << 8;
10394 colors[i] = lookup_rgb_color (f, r, g, b);
10395 }
10396
10397 /* Remember those colors actually allocated. */
10398 img->colors = colors_in_color_table (&img->ncolors);
10399 free_color_table ();
10400 }
10401
10402 /* Read pixels. */
10403 row_stride = width * cinfo.output_components;
10404 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
10405 row_stride, 1);
10406 for (y = 0; y < height; ++y)
10407 {
10408 jpeg_read_scanlines (&cinfo, buffer, 1);
10409 for (x = 0; x < cinfo.output_width; ++x)
10410 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
10411 }
10412
10413 /* Clean up. */
10414 jpeg_finish_decompress (&cinfo);
10415 jpeg_destroy_decompress (&cinfo);
10416 if (fp)
10417 fclose (fp);
10418
10419 /* Put the image into the pixmap. */
10420 x_put_x_image (f, ximg, img->pixmap, width, height);
10421 x_destroy_x_image (ximg);
10422 UNBLOCK_INPUT;
10423 UNGCPRO;
10424 return 1;
10425 }
10426
10427 #endif /* HAVE_JPEG */
10428
10429
10430 \f
10431 /***********************************************************************
10432 TIFF
10433 ***********************************************************************/
10434
10435 #if HAVE_TIFF
10436
10437 #include <tiffio.h>
10438
10439 static int tiff_image_p P_ ((Lisp_Object object));
10440 static int tiff_load P_ ((struct frame *f, struct image *img));
10441
10442 /* The symbol `tiff' identifying images of this type. */
10443
10444 Lisp_Object Qtiff;
10445
10446 /* Indices of image specification fields in tiff_format, below. */
10447
10448 enum tiff_keyword_index
10449 {
10450 TIFF_TYPE,
10451 TIFF_DATA,
10452 TIFF_FILE,
10453 TIFF_ASCENT,
10454 TIFF_MARGIN,
10455 TIFF_RELIEF,
10456 TIFF_ALGORITHM,
10457 TIFF_HEURISTIC_MASK,
10458 TIFF_LAST
10459 };
10460
10461 /* Vector of image_keyword structures describing the format
10462 of valid user-defined image specifications. */
10463
10464 static struct image_keyword tiff_format[TIFF_LAST] =
10465 {
10466 {":type", IMAGE_SYMBOL_VALUE, 1},
10467 {":data", IMAGE_STRING_VALUE, 0},
10468 {":file", IMAGE_STRING_VALUE, 0},
10469 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
10470 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
10471 {":relief", IMAGE_INTEGER_VALUE, 0},
10472 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10473 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
10474 };
10475
10476 /* Structure describing the image type `tiff'. */
10477
10478 static struct image_type tiff_type =
10479 {
10480 &Qtiff,
10481 tiff_image_p,
10482 tiff_load,
10483 x_clear_image,
10484 NULL
10485 };
10486
10487
10488 /* Return non-zero if OBJECT is a valid TIFF image specification. */
10489
10490 static int
10491 tiff_image_p (object)
10492 Lisp_Object object;
10493 {
10494 struct image_keyword fmt[TIFF_LAST];
10495 bcopy (tiff_format, fmt, sizeof fmt);
10496
10497 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff)
10498 || (fmt[TIFF_ASCENT].count
10499 && XFASTINT (fmt[TIFF_ASCENT].value) > 100))
10500 return 0;
10501
10502 /* Must specify either the :data or :file keyword. */
10503 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
10504 }
10505
10506
10507 /* Reading from a memory buffer for TIFF images Based on the PNG
10508 memory source, but we have to provide a lot of extra functions.
10509 Blah.
10510
10511 We really only need to implement read and seek, but I am not
10512 convinced that the TIFF library is smart enough not to destroy
10513 itself if we only hand it the function pointers we need to
10514 override. */
10515
10516 typedef struct
10517 {
10518 unsigned char *bytes;
10519 size_t len;
10520 int index;
10521 }
10522 tiff_memory_source;
10523
10524 static size_t
10525 tiff_read_from_memory (data, buf, size)
10526 thandle_t data;
10527 tdata_t buf;
10528 tsize_t size;
10529 {
10530 tiff_memory_source *src = (tiff_memory_source *) data;
10531
10532 if (size > src->len - src->index)
10533 return (size_t) -1;
10534 bcopy (src->bytes + src->index, buf, size);
10535 src->index += size;
10536 return size;
10537 }
10538
10539 static size_t
10540 tiff_write_from_memory (data, buf, size)
10541 thandle_t data;
10542 tdata_t buf;
10543 tsize_t size;
10544 {
10545 return (size_t) -1;
10546 }
10547
10548 static toff_t
10549 tiff_seek_in_memory (data, off, whence)
10550 thandle_t data;
10551 toff_t off;
10552 int whence;
10553 {
10554 tiff_memory_source *src = (tiff_memory_source *) data;
10555 int idx;
10556
10557 switch (whence)
10558 {
10559 case SEEK_SET: /* Go from beginning of source. */
10560 idx = off;
10561 break;
10562
10563 case SEEK_END: /* Go from end of source. */
10564 idx = src->len + off;
10565 break;
10566
10567 case SEEK_CUR: /* Go from current position. */
10568 idx = src->index + off;
10569 break;
10570
10571 default: /* Invalid `whence'. */
10572 return -1;
10573 }
10574
10575 if (idx > src->len || idx < 0)
10576 return -1;
10577
10578 src->index = idx;
10579 return src->index;
10580 }
10581
10582 static int
10583 tiff_close_memory (data)
10584 thandle_t data;
10585 {
10586 /* NOOP */
10587 return 0;
10588 }
10589
10590 static int
10591 tiff_mmap_memory (data, pbase, psize)
10592 thandle_t data;
10593 tdata_t *pbase;
10594 toff_t *psize;
10595 {
10596 /* It is already _IN_ memory. */
10597 return 0;
10598 }
10599
10600 static void
10601 tiff_unmap_memory (data, base, size)
10602 thandle_t data;
10603 tdata_t base;
10604 toff_t size;
10605 {
10606 /* We don't need to do this. */
10607 }
10608
10609 static toff_t
10610 tiff_size_of_memory (data)
10611 thandle_t data;
10612 {
10613 return ((tiff_memory_source *) data)->len;
10614 }
10615
10616
10617 /* Load TIFF image IMG for use on frame F. Value is non-zero if
10618 successful. */
10619
10620 static int
10621 tiff_load (f, img)
10622 struct frame *f;
10623 struct image *img;
10624 {
10625 Lisp_Object file, specified_file;
10626 Lisp_Object specified_data;
10627 TIFF *tiff;
10628 int width, height, x, y;
10629 uint32 *buf;
10630 int rc;
10631 XImage *ximg;
10632 struct gcpro gcpro1;
10633 tiff_memory_source memsrc;
10634
10635 specified_file = image_spec_value (img->spec, QCfile, NULL);
10636 specified_data = image_spec_value (img->spec, QCdata, NULL);
10637 file = Qnil;
10638 GCPRO1 (file);
10639
10640 if (NILP (specified_data))
10641 {
10642 /* Read from a file */
10643 file = x_find_image_file (specified_file);
10644 if (!STRINGP (file))
10645 {
10646 image_error ("Cannot find image file `%s'", file, Qnil);
10647 UNGCPRO;
10648 return 0;
10649 }
10650
10651 /* Try to open the image file. */
10652 tiff = TIFFOpen (XSTRING (file)->data, "r");
10653 if (tiff == NULL)
10654 {
10655 image_error ("Cannot open `%s'", file, Qnil);
10656 UNGCPRO;
10657 return 0;
10658 }
10659 }
10660 else
10661 {
10662 /* Memory source! */
10663 memsrc.bytes = XSTRING (specified_data)->data;
10664 memsrc.len = STRING_BYTES (XSTRING (specified_data));
10665 memsrc.index = 0;
10666
10667 tiff = TIFFClientOpen ("memory_source", "r", &memsrc,
10668 (TIFFReadWriteProc) tiff_read_from_memory,
10669 (TIFFReadWriteProc) tiff_write_from_memory,
10670 tiff_seek_in_memory,
10671 tiff_close_memory,
10672 tiff_size_of_memory,
10673 tiff_mmap_memory,
10674 tiff_unmap_memory);
10675
10676 if (!tiff)
10677 {
10678 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
10679 UNGCPRO;
10680 return 0;
10681 }
10682 }
10683
10684 /* Get width and height of the image, and allocate a raster buffer
10685 of width x height 32-bit values. */
10686 TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
10687 TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
10688 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
10689
10690 rc = TIFFReadRGBAImage (tiff, width, height, buf, 0);
10691 TIFFClose (tiff);
10692 if (!rc)
10693 {
10694 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
10695 xfree (buf);
10696 UNGCPRO;
10697 return 0;
10698 }
10699
10700 BLOCK_INPUT;
10701
10702 /* Create the X image and pixmap. */
10703 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
10704 {
10705 UNBLOCK_INPUT;
10706 xfree (buf);
10707 UNGCPRO;
10708 return 0;
10709 }
10710
10711 /* Initialize the color table. */
10712 init_color_table ();
10713
10714 /* Process the pixel raster. Origin is in the lower-left corner. */
10715 for (y = 0; y < height; ++y)
10716 {
10717 uint32 *row = buf + y * width;
10718
10719 for (x = 0; x < width; ++x)
10720 {
10721 uint32 abgr = row[x];
10722 int r = TIFFGetR (abgr) << 8;
10723 int g = TIFFGetG (abgr) << 8;
10724 int b = TIFFGetB (abgr) << 8;
10725 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
10726 }
10727 }
10728
10729 /* Remember the colors allocated for the image. Free the color table. */
10730 img->colors = colors_in_color_table (&img->ncolors);
10731 free_color_table ();
10732
10733 /* Put the image into the pixmap, then free the X image and its buffer. */
10734 x_put_x_image (f, ximg, img->pixmap, width, height);
10735 x_destroy_x_image (ximg);
10736 xfree (buf);
10737 UNBLOCK_INPUT;
10738
10739 img->width = width;
10740 img->height = height;
10741
10742 UNGCPRO;
10743 return 1;
10744 }
10745
10746 #endif /* HAVE_TIFF != 0 */
10747
10748
10749 \f
10750 /***********************************************************************
10751 GIF
10752 ***********************************************************************/
10753
10754 #if HAVE_GIF
10755
10756 #include <gif_lib.h>
10757
10758 static int gif_image_p P_ ((Lisp_Object object));
10759 static int gif_load P_ ((struct frame *f, struct image *img));
10760
10761 /* The symbol `gif' identifying images of this type. */
10762
10763 Lisp_Object Qgif;
10764
10765 /* Indices of image specification fields in gif_format, below. */
10766
10767 enum gif_keyword_index
10768 {
10769 GIF_TYPE,
10770 GIF_DATA,
10771 GIF_FILE,
10772 GIF_ASCENT,
10773 GIF_MARGIN,
10774 GIF_RELIEF,
10775 GIF_ALGORITHM,
10776 GIF_HEURISTIC_MASK,
10777 GIF_IMAGE,
10778 GIF_LAST
10779 };
10780
10781 /* Vector of image_keyword structures describing the format
10782 of valid user-defined image specifications. */
10783
10784 static struct image_keyword gif_format[GIF_LAST] =
10785 {
10786 {":type", IMAGE_SYMBOL_VALUE, 1},
10787 {":data", IMAGE_STRING_VALUE, 0},
10788 {":file", IMAGE_STRING_VALUE, 0},
10789 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
10790 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
10791 {":relief", IMAGE_INTEGER_VALUE, 0},
10792 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10793 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10794 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}
10795 };
10796
10797 /* Structure describing the image type `gif'. */
10798
10799 static struct image_type gif_type =
10800 {
10801 &Qgif,
10802 gif_image_p,
10803 gif_load,
10804 x_clear_image,
10805 NULL
10806 };
10807
10808 /* Return non-zero if OBJECT is a valid GIF image specification. */
10809
10810 static int
10811 gif_image_p (object)
10812 Lisp_Object object;
10813 {
10814 struct image_keyword fmt[GIF_LAST];
10815 bcopy (gif_format, fmt, sizeof fmt);
10816
10817 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif)
10818 || (fmt[GIF_ASCENT].count
10819 && XFASTINT (fmt[GIF_ASCENT].value) > 100))
10820 return 0;
10821
10822 /* Must specify either the :data or :file keyword. */
10823 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
10824 }
10825
10826 /* Reading a GIF image from memory
10827 Based on the PNG memory stuff to a certain extent. */
10828
10829 typedef struct
10830 {
10831 unsigned char *bytes;
10832 size_t len;
10833 int index;
10834 }
10835 gif_memory_source;
10836
10837 /* Make the current memory source available to gif_read_from_memory.
10838 It's done this way because not all versions of libungif support
10839 a UserData field in the GifFileType structure. */
10840 static gif_memory_source *current_gif_memory_src;
10841
10842 static int
10843 gif_read_from_memory (file, buf, len)
10844 GifFileType *file;
10845 GifByteType *buf;
10846 int len;
10847 {
10848 gif_memory_source *src = current_gif_memory_src;
10849
10850 if (len > src->len - src->index)
10851 return -1;
10852
10853 bcopy (src->bytes + src->index, buf, len);
10854 src->index += len;
10855 return len;
10856 }
10857
10858
10859 /* Load GIF image IMG for use on frame F. Value is non-zero if
10860 successful. */
10861
10862 static int
10863 gif_load (f, img)
10864 struct frame *f;
10865 struct image *img;
10866 {
10867 Lisp_Object file, specified_file;
10868 Lisp_Object specified_data;
10869 int rc, width, height, x, y, i;
10870 XImage *ximg;
10871 ColorMapObject *gif_color_map;
10872 unsigned long pixel_colors[256];
10873 GifFileType *gif;
10874 struct gcpro gcpro1;
10875 Lisp_Object image;
10876 int ino, image_left, image_top, image_width, image_height;
10877 gif_memory_source memsrc;
10878 unsigned char *raster;
10879
10880 specified_file = image_spec_value (img->spec, QCfile, NULL);
10881 specified_data = image_spec_value (img->spec, QCdata, NULL);
10882 file = Qnil;
10883
10884 if (NILP (specified_data))
10885 {
10886 file = x_find_image_file (specified_file);
10887 GCPRO1 (file);
10888 if (!STRINGP (file))
10889 {
10890 image_error ("Cannot find image file `%s'", specified_file, Qnil);
10891 UNGCPRO;
10892 return 0;
10893 }
10894
10895 /* Open the GIF file. */
10896 gif = DGifOpenFileName (XSTRING (file)->data);
10897 if (gif == NULL)
10898 {
10899 image_error ("Cannot open `%s'", file, Qnil);
10900 UNGCPRO;
10901 return 0;
10902 }
10903 }
10904 else
10905 {
10906 /* Read from memory! */
10907 current_gif_memory_src = &memsrc;
10908 memsrc.bytes = XSTRING (specified_data)->data;
10909 memsrc.len = STRING_BYTES (XSTRING (specified_data));
10910 memsrc.index = 0;
10911
10912 gif = DGifOpen(&memsrc, gif_read_from_memory);
10913 if (!gif)
10914 {
10915 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
10916 UNGCPRO;
10917 return 0;
10918 }
10919 }
10920
10921 /* Read entire contents. */
10922 rc = DGifSlurp (gif);
10923 if (rc == GIF_ERROR)
10924 {
10925 image_error ("Error reading `%s'", img->spec, Qnil);
10926 DGifCloseFile (gif);
10927 UNGCPRO;
10928 return 0;
10929 }
10930
10931 image = image_spec_value (img->spec, QCindex, NULL);
10932 ino = INTEGERP (image) ? XFASTINT (image) : 0;
10933 if (ino >= gif->ImageCount)
10934 {
10935 image_error ("Invalid image number `%s' in image `%s'",
10936 image, img->spec);
10937 DGifCloseFile (gif);
10938 UNGCPRO;
10939 return 0;
10940 }
10941
10942 width = img->width = gif->SWidth;
10943 height = img->height = gif->SHeight;
10944
10945 BLOCK_INPUT;
10946
10947 /* Create the X image and pixmap. */
10948 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
10949 {
10950 UNBLOCK_INPUT;
10951 DGifCloseFile (gif);
10952 UNGCPRO;
10953 return 0;
10954 }
10955
10956 /* Allocate colors. */
10957 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
10958 if (!gif_color_map)
10959 gif_color_map = gif->SColorMap;
10960 init_color_table ();
10961 bzero (pixel_colors, sizeof pixel_colors);
10962
10963 for (i = 0; i < gif_color_map->ColorCount; ++i)
10964 {
10965 int r = gif_color_map->Colors[i].Red << 8;
10966 int g = gif_color_map->Colors[i].Green << 8;
10967 int b = gif_color_map->Colors[i].Blue << 8;
10968 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
10969 }
10970
10971 img->colors = colors_in_color_table (&img->ncolors);
10972 free_color_table ();
10973
10974 /* Clear the part of the screen image that are not covered by
10975 the image from the GIF file. Full animated GIF support
10976 requires more than can be done here (see the gif89 spec,
10977 disposal methods). Let's simply assume that the part
10978 not covered by a sub-image is in the frame's background color. */
10979 image_top = gif->SavedImages[ino].ImageDesc.Top;
10980 image_left = gif->SavedImages[ino].ImageDesc.Left;
10981 image_width = gif->SavedImages[ino].ImageDesc.Width;
10982 image_height = gif->SavedImages[ino].ImageDesc.Height;
10983
10984 for (y = 0; y < image_top; ++y)
10985 for (x = 0; x < width; ++x)
10986 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
10987
10988 for (y = image_top + image_height; y < height; ++y)
10989 for (x = 0; x < width; ++x)
10990 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
10991
10992 for (y = image_top; y < image_top + image_height; ++y)
10993 {
10994 for (x = 0; x < image_left; ++x)
10995 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
10996 for (x = image_left + image_width; x < width; ++x)
10997 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
10998 }
10999
11000 /* Read the GIF image into the X image. We use a local variable
11001 `raster' here because RasterBits below is a char *, and invites
11002 problems with bytes >= 0x80. */
11003 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
11004
11005 if (gif->SavedImages[ino].ImageDesc.Interlace)
11006 {
11007 static int interlace_start[] = {0, 4, 2, 1};
11008 static int interlace_increment[] = {8, 8, 4, 2};
11009 int pass, inc;
11010 int row = interlace_start[0];
11011
11012 pass = 0;
11013
11014 for (y = 0; y < image_height; y++)
11015 {
11016 if (row >= image_height)
11017 {
11018 row = interlace_start[++pass];
11019 while (row >= image_height)
11020 row = interlace_start[++pass];
11021 }
11022
11023 for (x = 0; x < image_width; x++)
11024 {
11025 int i = raster[(y * image_width) + x];
11026 XPutPixel (ximg, x + image_left, row + image_top,
11027 pixel_colors[i]);
11028 }
11029
11030 row += interlace_increment[pass];
11031 }
11032 }
11033 else
11034 {
11035 for (y = 0; y < image_height; ++y)
11036 for (x = 0; x < image_width; ++x)
11037 {
11038 int i = raster[y* image_width + x];
11039 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
11040 }
11041 }
11042
11043 DGifCloseFile (gif);
11044
11045 /* Put the image into the pixmap, then free the X image and its buffer. */
11046 x_put_x_image (f, ximg, img->pixmap, width, height);
11047 x_destroy_x_image (ximg);
11048 UNBLOCK_INPUT;
11049
11050 UNGCPRO;
11051 return 1;
11052 }
11053
11054 #endif /* HAVE_GIF != 0 */
11055
11056
11057 \f
11058 /***********************************************************************
11059 Ghostscript
11060 ***********************************************************************/
11061
11062 #ifdef HAVE_GHOSTSCRIPT
11063 static int gs_image_p P_ ((Lisp_Object object));
11064 static int gs_load P_ ((struct frame *f, struct image *img));
11065 static void gs_clear_image P_ ((struct frame *f, struct image *img));
11066
11067 /* The symbol `postscript' identifying images of this type. */
11068
11069 Lisp_Object Qpostscript;
11070
11071 /* Keyword symbols. */
11072
11073 Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
11074
11075 /* Indices of image specification fields in gs_format, below. */
11076
11077 enum gs_keyword_index
11078 {
11079 GS_TYPE,
11080 GS_PT_WIDTH,
11081 GS_PT_HEIGHT,
11082 GS_FILE,
11083 GS_LOADER,
11084 GS_BOUNDING_BOX,
11085 GS_ASCENT,
11086 GS_MARGIN,
11087 GS_RELIEF,
11088 GS_ALGORITHM,
11089 GS_HEURISTIC_MASK,
11090 GS_LAST
11091 };
11092
11093 /* Vector of image_keyword structures describing the format
11094 of valid user-defined image specifications. */
11095
11096 static struct image_keyword gs_format[GS_LAST] =
11097 {
11098 {":type", IMAGE_SYMBOL_VALUE, 1},
11099 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
11100 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
11101 {":file", IMAGE_STRING_VALUE, 1},
11102 {":loader", IMAGE_FUNCTION_VALUE, 0},
11103 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
11104 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
11105 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
11106 {":relief", IMAGE_INTEGER_VALUE, 0},
11107 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11108 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
11109 };
11110
11111 /* Structure describing the image type `ghostscript'. */
11112
11113 static struct image_type gs_type =
11114 {
11115 &Qpostscript,
11116 gs_image_p,
11117 gs_load,
11118 gs_clear_image,
11119 NULL
11120 };
11121
11122
11123 /* Free X resources of Ghostscript image IMG which is used on frame F. */
11124
11125 static void
11126 gs_clear_image (f, img)
11127 struct frame *f;
11128 struct image *img;
11129 {
11130 /* IMG->data.ptr_val may contain a recorded colormap. */
11131 xfree (img->data.ptr_val);
11132 x_clear_image (f, img);
11133 }
11134
11135
11136 /* Return non-zero if OBJECT is a valid Ghostscript image
11137 specification. */
11138
11139 static int
11140 gs_image_p (object)
11141 Lisp_Object object;
11142 {
11143 struct image_keyword fmt[GS_LAST];
11144 Lisp_Object tem;
11145 int i;
11146
11147 bcopy (gs_format, fmt, sizeof fmt);
11148
11149 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript)
11150 || (fmt[GS_ASCENT].count
11151 && XFASTINT (fmt[GS_ASCENT].value) > 100))
11152 return 0;
11153
11154 /* Bounding box must be a list or vector containing 4 integers. */
11155 tem = fmt[GS_BOUNDING_BOX].value;
11156 if (CONSP (tem))
11157 {
11158 for (i = 0; i < 4; ++i, tem = XCDR (tem))
11159 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
11160 return 0;
11161 if (!NILP (tem))
11162 return 0;
11163 }
11164 else if (VECTORP (tem))
11165 {
11166 if (XVECTOR (tem)->size != 4)
11167 return 0;
11168 for (i = 0; i < 4; ++i)
11169 if (!INTEGERP (XVECTOR (tem)->contents[i]))
11170 return 0;
11171 }
11172 else
11173 return 0;
11174
11175 return 1;
11176 }
11177
11178
11179 /* Load Ghostscript image IMG for use on frame F. Value is non-zero
11180 if successful. */
11181
11182 static int
11183 gs_load (f, img)
11184 struct frame *f;
11185 struct image *img;
11186 {
11187 char buffer[100];
11188 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
11189 struct gcpro gcpro1, gcpro2;
11190 Lisp_Object frame;
11191 double in_width, in_height;
11192 Lisp_Object pixel_colors = Qnil;
11193
11194 /* Compute pixel size of pixmap needed from the given size in the
11195 image specification. Sizes in the specification are in pt. 1 pt
11196 = 1/72 in, xdpi and ydpi are stored in the frame's X display
11197 info. */
11198 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
11199 in_width = XFASTINT (pt_width) / 72.0;
11200 img->width = in_width * FRAME_W32_DISPLAY_INFO (f)->resx;
11201 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
11202 in_height = XFASTINT (pt_height) / 72.0;
11203 img->height = in_height * FRAME_W32_DISPLAY_INFO (f)->resy;
11204
11205 /* Create the pixmap. */
11206 BLOCK_INPUT;
11207 xassert (img->pixmap == 0);
11208 img->pixmap = XCreatePixmap (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
11209 img->width, img->height,
11210 DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
11211 UNBLOCK_INPUT;
11212
11213 if (!img->pixmap)
11214 {
11215 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
11216 return 0;
11217 }
11218
11219 /* Call the loader to fill the pixmap. It returns a process object
11220 if successful. We do not record_unwind_protect here because
11221 other places in redisplay like calling window scroll functions
11222 don't either. Let the Lisp loader use `unwind-protect' instead. */
11223 GCPRO2 (window_and_pixmap_id, pixel_colors);
11224
11225 sprintf (buffer, "%lu %lu",
11226 (unsigned long) FRAME_W32_WINDOW (f),
11227 (unsigned long) img->pixmap);
11228 window_and_pixmap_id = build_string (buffer);
11229
11230 sprintf (buffer, "%lu %lu",
11231 FRAME_FOREGROUND_PIXEL (f),
11232 FRAME_BACKGROUND_PIXEL (f));
11233 pixel_colors = build_string (buffer);
11234
11235 XSETFRAME (frame, f);
11236 loader = image_spec_value (img->spec, QCloader, NULL);
11237 if (NILP (loader))
11238 loader = intern ("gs-load-image");
11239
11240 img->data.lisp_val = call6 (loader, frame, img->spec,
11241 make_number (img->width),
11242 make_number (img->height),
11243 window_and_pixmap_id,
11244 pixel_colors);
11245 UNGCPRO;
11246 return PROCESSP (img->data.lisp_val);
11247 }
11248
11249
11250 /* Kill the Ghostscript process that was started to fill PIXMAP on
11251 frame F. Called from XTread_socket when receiving an event
11252 telling Emacs that Ghostscript has finished drawing. */
11253
11254 void
11255 x_kill_gs_process (pixmap, f)
11256 Pixmap pixmap;
11257 struct frame *f;
11258 {
11259 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
11260 int class, i;
11261 struct image *img;
11262
11263 /* Find the image containing PIXMAP. */
11264 for (i = 0; i < c->used; ++i)
11265 if (c->images[i]->pixmap == pixmap)
11266 break;
11267
11268 /* Kill the GS process. We should have found PIXMAP in the image
11269 cache and its image should contain a process object. */
11270 xassert (i < c->used);
11271 img = c->images[i];
11272 xassert (PROCESSP (img->data.lisp_val));
11273 Fkill_process (img->data.lisp_val, Qnil);
11274 img->data.lisp_val = Qnil;
11275
11276 /* On displays with a mutable colormap, figure out the colors
11277 allocated for the image by looking at the pixels of an XImage for
11278 img->pixmap. */
11279 class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
11280 if (class != StaticColor && class != StaticGray && class != TrueColor)
11281 {
11282 XImage *ximg;
11283
11284 BLOCK_INPUT;
11285
11286 /* Try to get an XImage for img->pixmep. */
11287 ximg = XGetImage (FRAME_W32_DISPLAY (f), img->pixmap,
11288 0, 0, img->width, img->height, ~0, ZPixmap);
11289 if (ximg)
11290 {
11291 int x, y;
11292
11293 /* Initialize the color table. */
11294 init_color_table ();
11295
11296 /* For each pixel of the image, look its color up in the
11297 color table. After having done so, the color table will
11298 contain an entry for each color used by the image. */
11299 for (y = 0; y < img->height; ++y)
11300 for (x = 0; x < img->width; ++x)
11301 {
11302 unsigned long pixel = XGetPixel (ximg, x, y);
11303 lookup_pixel_color (f, pixel);
11304 }
11305
11306 /* Record colors in the image. Free color table and XImage. */
11307 img->colors = colors_in_color_table (&img->ncolors);
11308 free_color_table ();
11309 XDestroyImage (ximg);
11310
11311 #if 0 /* This doesn't seem to be the case. If we free the colors
11312 here, we get a BadAccess later in x_clear_image when
11313 freeing the colors. */
11314 /* We have allocated colors once, but Ghostscript has also
11315 allocated colors on behalf of us. So, to get the
11316 reference counts right, free them once. */
11317 if (img->ncolors)
11318 {
11319 Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
11320 XFreeColors (FRAME_W32_DISPLAY (f), cmap,
11321 img->colors, img->ncolors, 0);
11322 }
11323 #endif
11324 }
11325 else
11326 image_error ("Cannot get X image of `%s'; colors will not be freed",
11327 img->spec, Qnil);
11328
11329 UNBLOCK_INPUT;
11330 }
11331 }
11332
11333 #endif /* HAVE_GHOSTSCRIPT */
11334
11335 \f
11336 /***********************************************************************
11337 Window properties
11338 ***********************************************************************/
11339
11340 DEFUN ("x-change-window-property", Fx_change_window_property,
11341 Sx_change_window_property, 2, 3, 0,
11342 "Change window property PROP to VALUE on the X window of FRAME.\n\
11343 PROP and VALUE must be strings. FRAME nil or omitted means use the\n\
11344 selected frame. Value is VALUE.")
11345 (prop, value, frame)
11346 Lisp_Object frame, prop, value;
11347 {
11348 #if 0 /* NTEMACS_TODO : port window properties to W32 */
11349 struct frame *f = check_x_frame (frame);
11350 Atom prop_atom;
11351
11352 CHECK_STRING (prop, 1);
11353 CHECK_STRING (value, 2);
11354
11355 BLOCK_INPUT;
11356 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
11357 XChangeProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
11358 prop_atom, XA_STRING, 8, PropModeReplace,
11359 XSTRING (value)->data, XSTRING (value)->size);
11360
11361 /* Make sure the property is set when we return. */
11362 XFlush (FRAME_W32_DISPLAY (f));
11363 UNBLOCK_INPUT;
11364
11365 #endif /* NTEMACS_TODO */
11366
11367 return value;
11368 }
11369
11370
11371 DEFUN ("x-delete-window-property", Fx_delete_window_property,
11372 Sx_delete_window_property, 1, 2, 0,
11373 "Remove window property PROP from X window of FRAME.\n\
11374 FRAME nil or omitted means use the selected frame. Value is PROP.")
11375 (prop, frame)
11376 Lisp_Object prop, frame;
11377 {
11378 #if 0 /* NTEMACS_TODO : port window properties to W32 */
11379
11380 struct frame *f = check_x_frame (frame);
11381 Atom prop_atom;
11382
11383 CHECK_STRING (prop, 1);
11384 BLOCK_INPUT;
11385 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
11386 XDeleteProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), prop_atom);
11387
11388 /* Make sure the property is removed when we return. */
11389 XFlush (FRAME_W32_DISPLAY (f));
11390 UNBLOCK_INPUT;
11391 #endif /* NTEMACS_TODO */
11392
11393 return prop;
11394 }
11395
11396
11397 DEFUN ("x-window-property", Fx_window_property, Sx_window_property,
11398 1, 2, 0,
11399 "Value is the value of window property PROP on FRAME.\n\
11400 If FRAME is nil or omitted, use the selected frame. Value is nil\n\
11401 if FRAME hasn't a property with name PROP or if PROP has no string\n\
11402 value.")
11403 (prop, frame)
11404 Lisp_Object prop, frame;
11405 {
11406 #if 0 /* NTEMACS_TODO : port window properties to W32 */
11407
11408 struct frame *f = check_x_frame (frame);
11409 Atom prop_atom;
11410 int rc;
11411 Lisp_Object prop_value = Qnil;
11412 char *tmp_data = NULL;
11413 Atom actual_type;
11414 int actual_format;
11415 unsigned long actual_size, bytes_remaining;
11416
11417 CHECK_STRING (prop, 1);
11418 BLOCK_INPUT;
11419 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
11420 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
11421 prop_atom, 0, 0, False, XA_STRING,
11422 &actual_type, &actual_format, &actual_size,
11423 &bytes_remaining, (unsigned char **) &tmp_data);
11424 if (rc == Success)
11425 {
11426 int size = bytes_remaining;
11427
11428 XFree (tmp_data);
11429 tmp_data = NULL;
11430
11431 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
11432 prop_atom, 0, bytes_remaining,
11433 False, XA_STRING,
11434 &actual_type, &actual_format,
11435 &actual_size, &bytes_remaining,
11436 (unsigned char **) &tmp_data);
11437 if (rc == Success)
11438 prop_value = make_string (tmp_data, size);
11439
11440 XFree (tmp_data);
11441 }
11442
11443 UNBLOCK_INPUT;
11444
11445 return prop_value;
11446
11447 #endif /* NTEMACS_TODO */
11448 return Qnil;
11449 }
11450
11451
11452 \f
11453 /***********************************************************************
11454 Busy cursor
11455 ***********************************************************************/
11456
11457 /* The implementation partly follows a patch from
11458 F.Pierresteguy@frcl.bull.fr dated 1994. */
11459
11460 /* Setting inhibit_busy_cursor to 2 inhibits busy-cursor display until
11461 the next X event is read and we enter XTread_socket again. Setting
11462 it to 1 inhibits busy-cursor display for direct commands. */
11463
11464 int inhibit_busy_cursor;
11465
11466 /* Incremented with each call to x-display-busy-cursor.
11467 Decremented in x-undisplay-busy-cursor. */
11468
11469 static int busy_count;
11470
11471
11472 DEFUN ("x-show-busy-cursor", Fx_show_busy_cursor,
11473 Sx_show_busy_cursor, 0, 0, 0,
11474 "Show a busy cursor, if not already shown.\n\
11475 Each call to this function must be matched by a call to\n\
11476 x-undisplay-busy-cursor to make the busy pointer disappear again.")
11477 ()
11478 {
11479 ++busy_count;
11480 if (busy_count == 1)
11481 {
11482 Lisp_Object rest, frame;
11483
11484 FOR_EACH_FRAME (rest, frame)
11485 if (FRAME_X_P (XFRAME (frame)))
11486 {
11487 struct frame *f = XFRAME (frame);
11488 #if 0 /* NTEMACS_TODO : busy cursor */
11489
11490 BLOCK_INPUT;
11491 f->output_data.w32->busy_p = 1;
11492
11493 if (!f->output_data.w32->busy_window)
11494 {
11495 unsigned long mask = CWCursor;
11496 XSetWindowAttributes attrs;
11497
11498 attrs.cursor = f->output_data.w32->busy_cursor;
11499 f->output_data.w32->busy_window
11500 = XCreateWindow (FRAME_W32_DISPLAY (f),
11501 FRAME_OUTER_WINDOW (f),
11502 0, 0, 32000, 32000, 0, 0,
11503 InputOnly, CopyFromParent,
11504 mask, &attrs);
11505 }
11506
11507 XMapRaised (FRAME_W32_DISPLAY (f), f->output_data.w32->busy_window);
11508 UNBLOCK_INPUT;
11509 #endif
11510 }
11511 }
11512
11513 return Qnil;
11514 }
11515
11516
11517 DEFUN ("x-hide-busy-cursor", Fx_hide_busy_cursor,
11518 Sx_hide_busy_cursor, 0, 1, 0,
11519 "Hide a busy-cursor.\n\
11520 A busy-cursor will actually be undisplayed when a matching\n\
11521 `x-undisplay-busy-cursor' is called for each `x-display-busy-cursor'\n\
11522 issued. FORCE non-nil means undisplay the busy-cursor forcibly,\n\
11523 not counting calls.")
11524 (force)
11525 Lisp_Object force;
11526 {
11527 Lisp_Object rest, frame;
11528
11529 if (busy_count == 0)
11530 return Qnil;
11531
11532 if (!NILP (force) && busy_count != 0)
11533 busy_count = 1;
11534
11535 --busy_count;
11536 if (busy_count != 0)
11537 return Qnil;
11538
11539 FOR_EACH_FRAME (rest, frame)
11540 {
11541 struct frame *f = XFRAME (frame);
11542
11543 if (FRAME_X_P (f)
11544 /* Watch out for newly created frames. */
11545 && f->output_data.w32->busy_window)
11546 {
11547 #if 0 /* NTEMACS_TODO : busy cursor */
11548 BLOCK_INPUT;
11549 XUnmapWindow (FRAME_W32_DISPLAY (f), f->output_data.w32->busy_window);
11550 /* Sync here because XTread_socket looks at the busy_p flag
11551 that is reset to zero below. */
11552 XSync (FRAME_W32_DISPLAY (f), False);
11553 UNBLOCK_INPUT;
11554 f->output_data.w32->busy_p = 0;
11555 #endif
11556 }
11557 }
11558
11559 return Qnil;
11560 }
11561
11562
11563 \f
11564 /***********************************************************************
11565 Tool tips
11566 ***********************************************************************/
11567
11568 static Lisp_Object x_create_tip_frame P_ ((struct w32_display_info *,
11569 Lisp_Object));
11570
11571 /* The frame of a currently visible tooltip, or null. */
11572
11573 struct frame *tip_frame;
11574
11575 /* If non-nil, a timer started that hides the last tooltip when it
11576 fires. */
11577
11578 Lisp_Object tip_timer;
11579 Window tip_window;
11580
11581 /* Create a frame for a tooltip on the display described by DPYINFO.
11582 PARMS is a list of frame parameters. Value is the frame. */
11583
11584 static Lisp_Object
11585 x_create_tip_frame (dpyinfo, parms)
11586 struct w32_display_info *dpyinfo;
11587 Lisp_Object parms;
11588 {
11589 #if 0 /* NTEMACS_TODO : w32 version */
11590 struct frame *f;
11591 Lisp_Object frame, tem;
11592 Lisp_Object name;
11593 long window_prompting = 0;
11594 int width, height;
11595 int count = specpdl_ptr - specpdl;
11596 struct gcpro gcpro1, gcpro2, gcpro3;
11597 struct kboard *kb;
11598
11599 check_x ();
11600
11601 /* Use this general default value to start with until we know if
11602 this frame has a specified name. */
11603 Vx_resource_name = Vinvocation_name;
11604
11605 #ifdef MULTI_KBOARD
11606 kb = dpyinfo->kboard;
11607 #else
11608 kb = &the_only_kboard;
11609 #endif
11610
11611 /* Get the name of the frame to use for resource lookup. */
11612 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
11613 if (!STRINGP (name)
11614 && !EQ (name, Qunbound)
11615 && !NILP (name))
11616 error ("Invalid frame name--not a string or nil");
11617 Vx_resource_name = name;
11618
11619 frame = Qnil;
11620 GCPRO3 (parms, name, frame);
11621 tip_frame = f = make_frame (1);
11622 XSETFRAME (frame, f);
11623 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
11624
11625 f->output_method = output_x_window;
11626 f->output_data.w32 =
11627 (struct w32_output *) xmalloc (sizeof (struct w32_output));
11628 bzero (f->output_data.w32, sizeof (struct w32_output));
11629 #if 0
11630 f->output_data.w32->icon_bitmap = -1;
11631 #endif
11632 f->output_data.w32->fontset = -1;
11633 f->icon_name = Qnil;
11634
11635 #ifdef MULTI_KBOARD
11636 FRAME_KBOARD (f) = kb;
11637 #endif
11638 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
11639 f->output_data.w32->explicit_parent = 0;
11640
11641 /* Set the name; the functions to which we pass f expect the name to
11642 be set. */
11643 if (EQ (name, Qunbound) || NILP (name))
11644 {
11645 f->name = build_string (dpyinfo->x_id_name);
11646 f->explicit_name = 0;
11647 }
11648 else
11649 {
11650 f->name = name;
11651 f->explicit_name = 1;
11652 /* use the frame's title when getting resources for this frame. */
11653 specbind (Qx_resource_name, name);
11654 }
11655
11656 /* Create fontsets from `global_fontset_alist' before handling fonts. */
11657 for (tem = Vglobal_fontset_alist; CONSP (tem); tem = XCDR (tem))
11658 fs_register_fontset (f, XCAR (tem));
11659
11660 /* Extract the window parameters from the supplied values
11661 that are needed to determine window geometry. */
11662 {
11663 Lisp_Object font;
11664
11665 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
11666
11667 BLOCK_INPUT;
11668 /* First, try whatever font the caller has specified. */
11669 if (STRINGP (font))
11670 {
11671 tem = Fquery_fontset (font, Qnil);
11672 if (STRINGP (tem))
11673 font = x_new_fontset (f, XSTRING (tem)->data);
11674 else
11675 font = x_new_font (f, XSTRING (font)->data);
11676 }
11677
11678 /* Try out a font which we hope has bold and italic variations. */
11679 if (!STRINGP (font))
11680 font = x_new_font (f, "-adobe-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-1");
11681 if (!STRINGP (font))
11682 font = x_new_font (f, "-misc-fixed-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
11683 if (! STRINGP (font))
11684 font = x_new_font (f, "-*-*-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
11685 if (! STRINGP (font))
11686 /* This was formerly the first thing tried, but it finds too many fonts
11687 and takes too long. */
11688 font = x_new_font (f, "-*-*-medium-r-*-*-*-*-*-*-c-*-iso8859-1");
11689 /* If those didn't work, look for something which will at least work. */
11690 if (! STRINGP (font))
11691 font = x_new_font (f, "-*-fixed-*-*-*-*-*-140-*-*-c-*-iso8859-1");
11692 UNBLOCK_INPUT;
11693 if (! STRINGP (font))
11694 font = build_string ("fixed");
11695
11696 x_default_parameter (f, parms, Qfont, font,
11697 "font", "Font", RES_TYPE_STRING);
11698 }
11699
11700 x_default_parameter (f, parms, Qborder_width, make_number (2),
11701 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
11702
11703 /* This defaults to 2 in order to match xterm. We recognize either
11704 internalBorderWidth or internalBorder (which is what xterm calls
11705 it). */
11706 if (NILP (Fassq (Qinternal_border_width, parms)))
11707 {
11708 Lisp_Object value;
11709
11710 value = w32_get_arg (parms, Qinternal_border_width,
11711 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
11712 if (! EQ (value, Qunbound))
11713 parms = Fcons (Fcons (Qinternal_border_width, value),
11714 parms);
11715 }
11716
11717 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
11718 "internalBorderWidth", "internalBorderWidth",
11719 RES_TYPE_NUMBER);
11720
11721 /* Also do the stuff which must be set before the window exists. */
11722 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
11723 "foreground", "Foreground", RES_TYPE_STRING);
11724 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
11725 "background", "Background", RES_TYPE_STRING);
11726 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
11727 "pointerColor", "Foreground", RES_TYPE_STRING);
11728 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
11729 "cursorColor", "Foreground", RES_TYPE_STRING);
11730 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
11731 "borderColor", "BorderColor", RES_TYPE_STRING);
11732
11733 /* Init faces before x_default_parameter is called for scroll-bar
11734 parameters because that function calls x_set_scroll_bar_width,
11735 which calls change_frame_size, which calls Fset_window_buffer,
11736 which runs hooks, which call Fvertical_motion. At the end, we
11737 end up in init_iterator with a null face cache, which should not
11738 happen. */
11739 init_frame_faces (f);
11740
11741 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
11742 window_prompting = x_figure_window_size (f, parms);
11743
11744 if (window_prompting & XNegative)
11745 {
11746 if (window_prompting & YNegative)
11747 f->output_data.w32->win_gravity = SouthEastGravity;
11748 else
11749 f->output_data.w32->win_gravity = NorthEastGravity;
11750 }
11751 else
11752 {
11753 if (window_prompting & YNegative)
11754 f->output_data.w32->win_gravity = SouthWestGravity;
11755 else
11756 f->output_data.w32->win_gravity = NorthWestGravity;
11757 }
11758
11759 f->output_data.w32->size_hint_flags = window_prompting;
11760 {
11761 XSetWindowAttributes attrs;
11762 unsigned long mask;
11763
11764 BLOCK_INPUT;
11765 mask = CWBackPixel | CWOverrideRedirect | CWSaveUnder | CWEventMask;
11766 /* Window managers looks at the override-redirect flag to
11767 determine whether or net to give windows a decoration (Xlib
11768 3.2.8). */
11769 attrs.override_redirect = True;
11770 attrs.save_under = True;
11771 attrs.background_pixel = FRAME_BACKGROUND_PIXEL (f);
11772 /* Arrange for getting MapNotify and UnmapNotify events. */
11773 attrs.event_mask = StructureNotifyMask;
11774 tip_window
11775 = FRAME_W32_WINDOW (f)
11776 = XCreateWindow (FRAME_W32_DISPLAY (f),
11777 FRAME_W32_DISPLAY_INFO (f)->root_window,
11778 /* x, y, width, height */
11779 0, 0, 1, 1,
11780 /* Border. */
11781 1,
11782 CopyFromParent, InputOutput, CopyFromParent,
11783 mask, &attrs);
11784 UNBLOCK_INPUT;
11785 }
11786
11787 x_make_gc (f);
11788
11789 x_default_parameter (f, parms, Qauto_raise, Qnil,
11790 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
11791 x_default_parameter (f, parms, Qauto_lower, Qnil,
11792 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
11793 x_default_parameter (f, parms, Qcursor_type, Qbox,
11794 "cursorType", "CursorType", RES_TYPE_SYMBOL);
11795
11796 /* Dimensions, especially f->height, must be done via change_frame_size.
11797 Change will not be effected unless different from the current
11798 f->height. */
11799 width = f->width;
11800 height = f->height;
11801 f->height = 0;
11802 SET_FRAME_WIDTH (f, 0);
11803 change_frame_size (f, height, width, 1, 0, 0);
11804
11805 f->no_split = 1;
11806
11807 UNGCPRO;
11808
11809 /* It is now ok to make the frame official even if we get an error
11810 below. And the frame needs to be on Vframe_list or making it
11811 visible won't work. */
11812 Vframe_list = Fcons (frame, Vframe_list);
11813
11814 /* Now that the frame is official, it counts as a reference to
11815 its display. */
11816 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
11817
11818 return unbind_to (count, frame);
11819 #endif /* NTEMACS_TODO */
11820 return Qnil;
11821 }
11822
11823
11824 DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 4, 0,
11825 "Show STRING in a \"tooltip\" window on frame FRAME.\n\
11826 A tooltip window is a small X window displaying STRING at\n\
11827 the current mouse position.\n\
11828 FRAME nil or omitted means use the selected frame.\n\
11829 PARMS is an optional list of frame parameters which can be\n\
11830 used to change the tooltip's appearance.\n\
11831 Automatically hide the tooltip after TIMEOUT seconds.\n\
11832 TIMEOUT nil means use the default timeout of 5 seconds.")
11833 (string, frame, parms, timeout)
11834 Lisp_Object string, frame, parms, timeout;
11835 {
11836 struct frame *f;
11837 struct window *w;
11838 Window root, child;
11839 Lisp_Object buffer;
11840 struct buffer *old_buffer;
11841 struct text_pos pos;
11842 int i, width, height;
11843 int root_x, root_y, win_x, win_y;
11844 unsigned pmask;
11845 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
11846 int old_windows_or_buffers_changed = windows_or_buffers_changed;
11847 int count = specpdl_ptr - specpdl;
11848
11849 specbind (Qinhibit_redisplay, Qt);
11850
11851 GCPRO3 (string, parms, frame, timeout);
11852
11853 CHECK_STRING (string, 0);
11854 f = check_x_frame (frame);
11855 if (NILP (timeout))
11856 timeout = make_number (5);
11857 else
11858 CHECK_NATNUM (timeout, 2);
11859
11860 /* Hide a previous tip, if any. */
11861 Fx_hide_tip ();
11862
11863 /* Add default values to frame parameters. */
11864 if (NILP (Fassq (Qname, parms)))
11865 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
11866 if (NILP (Fassq (Qinternal_border_width, parms)))
11867 parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
11868 if (NILP (Fassq (Qborder_width, parms)))
11869 parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
11870 if (NILP (Fassq (Qborder_color, parms)))
11871 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
11872 if (NILP (Fassq (Qbackground_color, parms)))
11873 parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
11874 parms);
11875
11876 /* Create a frame for the tooltip, and record it in the global
11877 variable tip_frame. */
11878 frame = x_create_tip_frame (FRAME_W32_DISPLAY_INFO (f), parms);
11879 tip_frame = f = XFRAME (frame);
11880
11881 /* Set up the frame's root window. Currently we use a size of 80
11882 columns x 40 lines. If someone wants to show a larger tip, he
11883 will loose. I don't think this is a realistic case. */
11884 w = XWINDOW (FRAME_ROOT_WINDOW (f));
11885 w->left = w->top = make_number (0);
11886 w->width = 80;
11887 w->height = 40;
11888 adjust_glyphs (f);
11889 w->pseudo_window_p = 1;
11890
11891 /* Display the tooltip text in a temporary buffer. */
11892 buffer = Fget_buffer_create (build_string (" *tip*"));
11893 Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer);
11894 old_buffer = current_buffer;
11895 set_buffer_internal_1 (XBUFFER (buffer));
11896 Ferase_buffer ();
11897 Finsert (make_number (1), &string);
11898 clear_glyph_matrix (w->desired_matrix);
11899 clear_glyph_matrix (w->current_matrix);
11900 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
11901 try_window (FRAME_ROOT_WINDOW (f), pos);
11902
11903 /* Compute width and height of the tooltip. */
11904 width = height = 0;
11905 for (i = 0; i < w->desired_matrix->nrows; ++i)
11906 {
11907 struct glyph_row *row = &w->desired_matrix->rows[i];
11908 struct glyph *last;
11909 int row_width;
11910
11911 /* Stop at the first empty row at the end. */
11912 if (!row->enabled_p || !row->displays_text_p)
11913 break;
11914
11915 /* Let the row go over the full width of the frame. */
11916 row->full_width_p = 1;
11917
11918 /* There's a glyph at the end of rows that is use to place
11919 the cursor there. Don't include the width of this glyph. */
11920 if (row->used[TEXT_AREA])
11921 {
11922 last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
11923 row_width = row->pixel_width - last->pixel_width;
11924 }
11925 else
11926 row_width = row->pixel_width;
11927
11928 height += row->height;
11929 width = max (width, row_width);
11930 }
11931
11932 /* Add the frame's internal border to the width and height the X
11933 window should have. */
11934 height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
11935 width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
11936
11937 /* Move the tooltip window where the mouse pointer is. Resize and
11938 show it. */
11939 #if 0 /* NTEMACS_TODO : W32 specifics */
11940 BLOCK_INPUT;
11941 XQueryPointer (FRAME_W32_DISPLAY (f), FRAME_W32_DISPLAY_INFO (f)->root_window,
11942 &root, &child, &root_x, &root_y, &win_x, &win_y, &pmask);
11943 XMoveResizeWindow (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
11944 root_x + 5, root_y - height - 5, width, height);
11945 XMapRaised (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f));
11946 UNBLOCK_INPUT;
11947 #endif /* NTEMACS_TODO */
11948
11949 /* Draw into the window. */
11950 w->must_be_updated_p = 1;
11951 update_single_window (w, 1);
11952
11953 /* Restore original current buffer. */
11954 set_buffer_internal_1 (old_buffer);
11955 windows_or_buffers_changed = old_windows_or_buffers_changed;
11956
11957 /* Let the tip disappear after timeout seconds. */
11958 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
11959 intern ("x-hide-tip"));
11960 UNGCPRO;
11961
11962 return unbind_to (count, Qnil);
11963 }
11964
11965
11966 DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
11967 "Hide the current tooltip window, if there is any.\n\
11968 Value is t is tooltip was open, nil otherwise.")
11969 ()
11970 {
11971 int count = specpdl_ptr - specpdl;
11972 int deleted_p = 0;
11973
11974 specbind (Qinhibit_redisplay, Qt);
11975
11976 if (!NILP (tip_timer))
11977 {
11978 call1 (intern ("cancel-timer"), tip_timer);
11979 tip_timer = Qnil;
11980 }
11981
11982 if (tip_frame)
11983 {
11984 Lisp_Object frame;
11985
11986 XSETFRAME (frame, tip_frame);
11987 Fdelete_frame (frame, Qt);
11988 tip_frame = NULL;
11989 deleted_p = 1;
11990 }
11991
11992 return unbind_to (count, deleted_p ? Qt : Qnil);
11993 }
11994
11995
11996 \f
11997 /***********************************************************************
11998 File selection dialog
11999 ***********************************************************************/
12000
12001 extern Lisp_Object Qfile_name_history;
12002
12003 DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0,
12004 "Read file name, prompting with PROMPT in directory DIR.\n\
12005 Use a file selection dialog.\n\
12006 Select DEFAULT-FILENAME in the dialog's file selection box, if\n\
12007 specified. Don't let the user enter a file name in the file\n\
12008 selection dialog's entry field, if MUSTMATCH is non-nil.")
12009 (prompt, dir, default_filename, mustmatch)
12010 Lisp_Object prompt, dir, default_filename, mustmatch;
12011 {
12012 struct frame *f = SELECTED_FRAME ();
12013 Lisp_Object file = Qnil;
12014 int count = specpdl_ptr - specpdl;
12015 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
12016 char filename[MAX_PATH + 1];
12017 char init_dir[MAX_PATH + 1];
12018 int use_dialog_p = 1;
12019
12020 GCPRO5 (prompt, dir, default_filename, mustmatch, file);
12021 CHECK_STRING (prompt, 0);
12022 CHECK_STRING (dir, 1);
12023
12024 /* Create the dialog with PROMPT as title, using DIR as initial
12025 directory and using "*" as pattern. */
12026 dir = Fexpand_file_name (dir, Qnil);
12027 strncpy (init_dir, XSTRING (dir)->data, MAX_PATH);
12028 init_dir[MAX_PATH] = '\0';
12029 unixtodos_filename (init_dir);
12030
12031 if (STRINGP (default_filename))
12032 {
12033 char *file_name_only;
12034 char *full_path_name = XSTRING (default_filename)->data;
12035
12036 unixtodos_filename (full_path_name);
12037
12038 file_name_only = strrchr (full_path_name, '\\');
12039 if (!file_name_only)
12040 file_name_only = full_path_name;
12041 else
12042 {
12043 file_name_only++;
12044
12045 /* If default_file_name is a directory, don't use the open
12046 file dialog, as it does not support selecting
12047 directories. */
12048 if (!(*file_name_only))
12049 use_dialog_p = 0;
12050 }
12051
12052 strncpy (filename, file_name_only, MAX_PATH);
12053 filename[MAX_PATH] = '\0';
12054 }
12055 else
12056 filename[0] = '\0';
12057
12058 if (use_dialog_p)
12059 {
12060 OPENFILENAME file_details;
12061 char *filename_file;
12062
12063 /* Prevent redisplay. */
12064 specbind (Qinhibit_redisplay, Qt);
12065 BLOCK_INPUT;
12066
12067 bzero (&file_details, sizeof (file_details));
12068 file_details.lStructSize = sizeof (file_details);
12069 file_details.hwndOwner = FRAME_W32_WINDOW (f);
12070 file_details.lpstrFile = filename;
12071 file_details.nMaxFile = sizeof (filename);
12072 file_details.lpstrInitialDir = init_dir;
12073 file_details.lpstrTitle = XSTRING (prompt)->data;
12074 file_details.Flags = OFN_HIDEREADONLY | OFN_NOCHANGEDIR;
12075
12076 if (!NILP (mustmatch))
12077 file_details.Flags |= OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
12078
12079 if (GetOpenFileName (&file_details))
12080 {
12081 dostounix_filename (filename);
12082 file = build_string (filename);
12083 }
12084 else
12085 file = Qnil;
12086
12087 UNBLOCK_INPUT;
12088 file = unbind_to (count, file);
12089 }
12090 /* Open File dialog will not allow folders to be selected, so resort
12091 to minibuffer completing reads for directories. */
12092 else
12093 file = Fcompleting_read (prompt, intern ("read-file-name-internal"),
12094 dir, mustmatch, dir, Qfile_name_history,
12095 default_filename, Qnil);
12096
12097 UNGCPRO;
12098
12099 /* Make "Cancel" equivalent to C-g. */
12100 if (NILP (file))
12101 Fsignal (Qquit, Qnil);
12102
12103 return file;
12104 }
12105
12106
12107 \f
12108 /***********************************************************************
12109 Tests
12110 ***********************************************************************/
12111
12112 #if GLYPH_DEBUG
12113
12114 DEFUN ("imagep", Fimagep, Simagep, 1, 1, 0,
12115 "Value is non-nil if SPEC is a valid image specification.")
12116 (spec)
12117 Lisp_Object spec;
12118 {
12119 return valid_image_p (spec) ? Qt : Qnil;
12120 }
12121
12122
12123 DEFUN ("lookup-image", Flookup_image, Slookup_image, 1, 1, 0, "")
12124 (spec)
12125 Lisp_Object spec;
12126 {
12127 int id = -1;
12128
12129 if (valid_image_p (spec))
12130 id = lookup_image (SELECTED_FRAME (), spec);
12131
12132 debug_print (spec);
12133 return make_number (id);
12134 }
12135
12136 #endif /* GLYPH_DEBUG != 0 */
12137
12138
12139 \f
12140 /***********************************************************************
12141 w32 specialized functions
12142 ***********************************************************************/
12143
12144 DEFUN ("w32-select-font", Fw32_select_font, Sw32_select_font, 0, 1, 0,
12145 "This will display the W32 font dialog and return an X font string corresponding to the selection.")
12146 (frame)
12147 Lisp_Object frame;
12148 {
12149 FRAME_PTR f = check_x_frame (frame);
12150 CHOOSEFONT cf;
12151 LOGFONT lf;
12152 TEXTMETRIC tm;
12153 HDC hdc;
12154 HANDLE oldobj;
12155 char buf[100];
12156
12157 bzero (&cf, sizeof (cf));
12158 bzero (&lf, sizeof (lf));
12159
12160 cf.lStructSize = sizeof (cf);
12161 cf.hwndOwner = FRAME_W32_WINDOW (f);
12162 cf.Flags = CF_FORCEFONTEXIST | CF_SCREENFONTS;
12163 cf.lpLogFont = &lf;
12164
12165 /* Initialize as much of the font details as we can from the current
12166 default font. */
12167 hdc = GetDC (FRAME_W32_WINDOW (f));
12168 oldobj = SelectObject (hdc, FRAME_FONT (f)->hfont);
12169 GetTextFace (hdc, LF_FACESIZE, lf.lfFaceName);
12170 if (GetTextMetrics (hdc, &tm))
12171 {
12172 lf.lfHeight = tm.tmInternalLeading - tm.tmHeight;
12173 lf.lfWeight = tm.tmWeight;
12174 lf.lfItalic = tm.tmItalic;
12175 lf.lfUnderline = tm.tmUnderlined;
12176 lf.lfStrikeOut = tm.tmStruckOut;
12177 lf.lfCharSet = tm.tmCharSet;
12178 cf.Flags |= CF_INITTOLOGFONTSTRUCT;
12179 }
12180 SelectObject (hdc, oldobj);
12181 ReleaseDC (FRAME_W32_WINDOW (f), hdc);
12182
12183 if (!ChooseFont (&cf) || !w32_to_x_font (&lf, buf, 100))
12184 return Qnil;
12185
12186 return build_string (buf);
12187 }
12188
12189 DEFUN ("w32-send-sys-command", Fw32_send_sys_command, Sw32_send_sys_command, 1, 2, 0,
12190 "Send frame a Windows WM_SYSCOMMAND message of type COMMAND.\n\
12191 Some useful values for command are 0xf030 to maximise frame (0xf020\n\
12192 to minimize), 0xf120 to restore frame to original size, and 0xf100\n\
12193 to activate the menubar for keyboard access. 0xf140 activates the\n\
12194 screen saver if defined.\n\
12195 \n\
12196 If optional parameter FRAME is not specified, use selected frame.")
12197 (command, frame)
12198 Lisp_Object command, frame;
12199 {
12200 WPARAM code;
12201 FRAME_PTR f = check_x_frame (frame);
12202
12203 CHECK_NUMBER (command, 0);
12204
12205 PostMessage (FRAME_W32_WINDOW (f), WM_SYSCOMMAND, XINT (command), 0);
12206
12207 return Qnil;
12208 }
12209
12210 DEFUN ("w32-shell-execute", Fw32_shell_execute, Sw32_shell_execute, 2, 4, 0,
12211 "Get Windows to perform OPERATION on DOCUMENT.\n\
12212 This is a wrapper around the ShellExecute system function, which\n\
12213 invokes the application registered to handle OPERATION for DOCUMENT.\n\
12214 OPERATION is typically \"open\", \"print\" or \"explore\" (but can be\n\
12215 nil for the default action), and DOCUMENT is typically the name of a\n\
12216 document file or URL, but can also be a program executable to run or\n\
12217 a directory to open in the Windows Explorer.\n\
12218 \n\
12219 If DOCUMENT is a program executable, PARAMETERS can be a string\n\
12220 containing command line parameters, but otherwise should be nil.\n\
12221 \n\
12222 SHOW-FLAG can be used to control whether the invoked application is hidden\n\
12223 or minimized. If SHOW-FLAG is nil, the application is displayed normally,\n\
12224 otherwise it is an integer representing a ShowWindow flag:\n\
12225 \n\
12226 0 - start hidden\n\
12227 1 - start normally\n\
12228 3 - start maximized\n\
12229 6 - start minimized")
12230 (operation, document, parameters, show_flag)
12231 Lisp_Object operation, document, parameters, show_flag;
12232 {
12233 Lisp_Object current_dir;
12234
12235 CHECK_STRING (document, 0);
12236
12237 /* Encode filename and current directory. */
12238 current_dir = ENCODE_FILE (current_buffer->directory);
12239 document = ENCODE_FILE (document);
12240 if ((int) ShellExecute (NULL,
12241 (STRINGP (operation) ?
12242 XSTRING (operation)->data : NULL),
12243 XSTRING (document)->data,
12244 (STRINGP (parameters) ?
12245 XSTRING (parameters)->data : NULL),
12246 XSTRING (current_dir)->data,
12247 (INTEGERP (show_flag) ?
12248 XINT (show_flag) : SW_SHOWDEFAULT))
12249 > 32)
12250 return Qt;
12251 error ("ShellExecute failed");
12252 }
12253
12254 /* Lookup virtual keycode from string representing the name of a
12255 non-ascii keystroke into the corresponding virtual key, using
12256 lispy_function_keys. */
12257 static int
12258 lookup_vk_code (char *key)
12259 {
12260 int i;
12261
12262 for (i = 0; i < 256; i++)
12263 if (lispy_function_keys[i] != 0
12264 && strcmp (lispy_function_keys[i], key) == 0)
12265 return i;
12266
12267 return -1;
12268 }
12269
12270 /* Convert a one-element vector style key sequence to a hot key
12271 definition. */
12272 static int
12273 w32_parse_hot_key (key)
12274 Lisp_Object key;
12275 {
12276 /* Copied from Fdefine_key and store_in_keymap. */
12277 register Lisp_Object c;
12278 int vk_code;
12279 int lisp_modifiers;
12280 int w32_modifiers;
12281 struct gcpro gcpro1;
12282
12283 CHECK_VECTOR (key, 0);
12284
12285 if (XFASTINT (Flength (key)) != 1)
12286 return Qnil;
12287
12288 GCPRO1 (key);
12289
12290 c = Faref (key, make_number (0));
12291
12292 if (CONSP (c) && lucid_event_type_list_p (c))
12293 c = Fevent_convert_list (c);
12294
12295 UNGCPRO;
12296
12297 if (! INTEGERP (c) && ! SYMBOLP (c))
12298 error ("Key definition is invalid");
12299
12300 /* Work out the base key and the modifiers. */
12301 if (SYMBOLP (c))
12302 {
12303 c = parse_modifiers (c);
12304 lisp_modifiers = Fcar (Fcdr (c));
12305 c = Fcar (c);
12306 if (!SYMBOLP (c))
12307 abort ();
12308 vk_code = lookup_vk_code (XSYMBOL (c)->name->data);
12309 }
12310 else if (INTEGERP (c))
12311 {
12312 lisp_modifiers = XINT (c) & ~CHARACTERBITS;
12313 /* Many ascii characters are their own virtual key code. */
12314 vk_code = XINT (c) & CHARACTERBITS;
12315 }
12316
12317 if (vk_code < 0 || vk_code > 255)
12318 return Qnil;
12319
12320 if ((lisp_modifiers & meta_modifier) != 0
12321 && !NILP (Vw32_alt_is_meta))
12322 lisp_modifiers |= alt_modifier;
12323
12324 /* Convert lisp modifiers to Windows hot-key form. */
12325 w32_modifiers = (lisp_modifiers & hyper_modifier) ? MOD_WIN : 0;
12326 w32_modifiers |= (lisp_modifiers & alt_modifier) ? MOD_ALT : 0;
12327 w32_modifiers |= (lisp_modifiers & ctrl_modifier) ? MOD_CONTROL : 0;
12328 w32_modifiers |= (lisp_modifiers & shift_modifier) ? MOD_SHIFT : 0;
12329
12330 return HOTKEY (vk_code, w32_modifiers);
12331 }
12332
12333 DEFUN ("w32-register-hot-key", Fw32_register_hot_key, Sw32_register_hot_key, 1, 1, 0,
12334 "Register KEY as a hot-key combination.\n\
12335 Certain key combinations like Alt-Tab are reserved for system use on\n\
12336 Windows, and therefore are normally intercepted by the system. However,\n\
12337 most of these key combinations can be received by registering them as\n\
12338 hot-keys, overriding their special meaning.\n\
12339 \n\
12340 KEY must be a one element key definition in vector form that would be\n\
12341 acceptable to `define-key' (e.g. [A-tab] for Alt-Tab). The meta\n\
12342 modifier is interpreted as Alt if `w32-alt-is-meta' is t, and hyper\n\
12343 is always interpreted as the Windows modifier keys.\n\
12344 \n\
12345 The return value is the hotkey-id if registered, otherwise nil.")
12346 (key)
12347 Lisp_Object key;
12348 {
12349 key = w32_parse_hot_key (key);
12350
12351 if (NILP (Fmemq (key, w32_grabbed_keys)))
12352 {
12353 /* Reuse an empty slot if possible. */
12354 Lisp_Object item = Fmemq (Qnil, w32_grabbed_keys);
12355
12356 /* Safe to add new key to list, even if we have focus. */
12357 if (NILP (item))
12358 w32_grabbed_keys = Fcons (key, w32_grabbed_keys);
12359 else
12360 XCAR (item) = key;
12361
12362 /* Notify input thread about new hot-key definition, so that it
12363 takes effect without needing to switch focus. */
12364 PostThreadMessage (dwWindowsThreadId, WM_EMACS_REGISTER_HOT_KEY,
12365 (WPARAM) key, 0);
12366 }
12367
12368 return key;
12369 }
12370
12371 DEFUN ("w32-unregister-hot-key", Fw32_unregister_hot_key, Sw32_unregister_hot_key, 1, 1, 0,
12372 "Unregister HOTKEY as a hot-key combination.")
12373 (key)
12374 Lisp_Object key;
12375 {
12376 Lisp_Object item;
12377
12378 if (!INTEGERP (key))
12379 key = w32_parse_hot_key (key);
12380
12381 item = Fmemq (key, w32_grabbed_keys);
12382
12383 if (!NILP (item))
12384 {
12385 /* Notify input thread about hot-key definition being removed, so
12386 that it takes effect without needing focus switch. */
12387 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_UNREGISTER_HOT_KEY,
12388 (WPARAM) XINT (XCAR (item)), (LPARAM) item))
12389 {
12390 MSG msg;
12391 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
12392 }
12393 return Qt;
12394 }
12395 return Qnil;
12396 }
12397
12398 DEFUN ("w32-registered-hot-keys", Fw32_registered_hot_keys, Sw32_registered_hot_keys, 0, 0, 0,
12399 "Return list of registered hot-key IDs.")
12400 ()
12401 {
12402 return Fcopy_sequence (w32_grabbed_keys);
12403 }
12404
12405 DEFUN ("w32-reconstruct-hot-key", Fw32_reconstruct_hot_key, Sw32_reconstruct_hot_key, 1, 1, 0,
12406 "Convert hot-key ID to a lisp key combination.")
12407 (hotkeyid)
12408 Lisp_Object hotkeyid;
12409 {
12410 int vk_code, w32_modifiers;
12411 Lisp_Object key;
12412
12413 CHECK_NUMBER (hotkeyid, 0);
12414
12415 vk_code = HOTKEY_VK_CODE (hotkeyid);
12416 w32_modifiers = HOTKEY_MODIFIERS (hotkeyid);
12417
12418 if (lispy_function_keys[vk_code])
12419 key = intern (lispy_function_keys[vk_code]);
12420 else
12421 key = make_number (vk_code);
12422
12423 key = Fcons (key, Qnil);
12424 if (w32_modifiers & MOD_SHIFT)
12425 key = Fcons (Qshift, key);
12426 if (w32_modifiers & MOD_CONTROL)
12427 key = Fcons (Qctrl, key);
12428 if (w32_modifiers & MOD_ALT)
12429 key = Fcons (NILP (Vw32_alt_is_meta) ? Qalt : Qmeta, key);
12430 if (w32_modifiers & MOD_WIN)
12431 key = Fcons (Qhyper, key);
12432
12433 return key;
12434 }
12435
12436 DEFUN ("w32-toggle-lock-key", Fw32_toggle_lock_key, Sw32_toggle_lock_key, 1, 2, 0,
12437 "Toggle the state of the lock key KEY.\n\
12438 KEY can be `capslock', `kp-numlock', or `scroll'.\n\
12439 If the optional parameter NEW-STATE is a number, then the state of KEY\n\
12440 is set to off if the low bit of NEW-STATE is zero, otherwise on.")
12441 (key, new_state)
12442 Lisp_Object key, new_state;
12443 {
12444 int vk_code;
12445 int cur_state;
12446
12447 if (EQ (key, intern ("capslock")))
12448 vk_code = VK_CAPITAL;
12449 else if (EQ (key, intern ("kp-numlock")))
12450 vk_code = VK_NUMLOCK;
12451 else if (EQ (key, intern ("scroll")))
12452 vk_code = VK_SCROLL;
12453 else
12454 return Qnil;
12455
12456 if (!dwWindowsThreadId)
12457 return make_number (w32_console_toggle_lock_key (vk_code, new_state));
12458
12459 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_TOGGLE_LOCK_KEY,
12460 (WPARAM) vk_code, (LPARAM) new_state))
12461 {
12462 MSG msg;
12463 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
12464 return make_number (msg.wParam);
12465 }
12466 return Qnil;
12467 }
12468 \f
12469 syms_of_w32fns ()
12470 {
12471 /* This is zero if not using MS-Windows. */
12472 w32_in_use = 0;
12473
12474 /* The section below is built by the lisp expression at the top of the file,
12475 just above where these variables are declared. */
12476 /*&&& init symbols here &&&*/
12477 Qauto_raise = intern ("auto-raise");
12478 staticpro (&Qauto_raise);
12479 Qauto_lower = intern ("auto-lower");
12480 staticpro (&Qauto_lower);
12481 Qbar = intern ("bar");
12482 staticpro (&Qbar);
12483 Qborder_color = intern ("border-color");
12484 staticpro (&Qborder_color);
12485 Qborder_width = intern ("border-width");
12486 staticpro (&Qborder_width);
12487 Qbox = intern ("box");
12488 staticpro (&Qbox);
12489 Qcursor_color = intern ("cursor-color");
12490 staticpro (&Qcursor_color);
12491 Qcursor_type = intern ("cursor-type");
12492 staticpro (&Qcursor_type);
12493 Qgeometry = intern ("geometry");
12494 staticpro (&Qgeometry);
12495 Qicon_left = intern ("icon-left");
12496 staticpro (&Qicon_left);
12497 Qicon_top = intern ("icon-top");
12498 staticpro (&Qicon_top);
12499 Qicon_type = intern ("icon-type");
12500 staticpro (&Qicon_type);
12501 Qicon_name = intern ("icon-name");
12502 staticpro (&Qicon_name);
12503 Qinternal_border_width = intern ("internal-border-width");
12504 staticpro (&Qinternal_border_width);
12505 Qleft = intern ("left");
12506 staticpro (&Qleft);
12507 Qright = intern ("right");
12508 staticpro (&Qright);
12509 Qmouse_color = intern ("mouse-color");
12510 staticpro (&Qmouse_color);
12511 Qnone = intern ("none");
12512 staticpro (&Qnone);
12513 Qparent_id = intern ("parent-id");
12514 staticpro (&Qparent_id);
12515 Qscroll_bar_width = intern ("scroll-bar-width");
12516 staticpro (&Qscroll_bar_width);
12517 Qsuppress_icon = intern ("suppress-icon");
12518 staticpro (&Qsuppress_icon);
12519 Qundefined_color = intern ("undefined-color");
12520 staticpro (&Qundefined_color);
12521 Qvertical_scroll_bars = intern ("vertical-scroll-bars");
12522 staticpro (&Qvertical_scroll_bars);
12523 Qvisibility = intern ("visibility");
12524 staticpro (&Qvisibility);
12525 Qwindow_id = intern ("window-id");
12526 staticpro (&Qwindow_id);
12527 Qx_frame_parameter = intern ("x-frame-parameter");
12528 staticpro (&Qx_frame_parameter);
12529 Qx_resource_name = intern ("x-resource-name");
12530 staticpro (&Qx_resource_name);
12531 Quser_position = intern ("user-position");
12532 staticpro (&Quser_position);
12533 Quser_size = intern ("user-size");
12534 staticpro (&Quser_size);
12535 #if 0 /* Duplicate initialization in xdisp.c */
12536 Qdisplay = intern ("display");
12537 staticpro (&Qdisplay);
12538 #endif
12539 Qscreen_gamma = intern ("screen-gamma");
12540 staticpro (&Qscreen_gamma);
12541 /* This is the end of symbol initialization. */
12542
12543 Qhyper = intern ("hyper");
12544 staticpro (&Qhyper);
12545 Qsuper = intern ("super");
12546 staticpro (&Qsuper);
12547 Qmeta = intern ("meta");
12548 staticpro (&Qmeta);
12549 Qalt = intern ("alt");
12550 staticpro (&Qalt);
12551 Qctrl = intern ("ctrl");
12552 staticpro (&Qctrl);
12553 Qcontrol = intern ("control");
12554 staticpro (&Qcontrol);
12555 Qshift = intern ("shift");
12556 staticpro (&Qshift);
12557
12558 /* Text property `display' should be nonsticky by default. */
12559 Vtext_property_default_nonsticky
12560 = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky);
12561
12562
12563 Qlaplace = intern ("laplace");
12564 staticpro (&Qlaplace);
12565
12566 Qface_set_after_frame_default = intern ("face-set-after-frame-default");
12567 staticpro (&Qface_set_after_frame_default);
12568
12569 Fput (Qundefined_color, Qerror_conditions,
12570 Fcons (Qundefined_color, Fcons (Qerror, Qnil)));
12571 Fput (Qundefined_color, Qerror_message,
12572 build_string ("Undefined color"));
12573
12574 staticpro (&w32_grabbed_keys);
12575 w32_grabbed_keys = Qnil;
12576
12577 DEFVAR_LISP ("w32-color-map", &Vw32_color_map,
12578 "An array of color name mappings for windows.");
12579 Vw32_color_map = Qnil;
12580
12581 DEFVAR_LISP ("w32-pass-alt-to-system", &Vw32_pass_alt_to_system,
12582 "Non-nil if alt key presses are passed on to Windows.\n\
12583 When non-nil, for example, alt pressed and released and then space will\n\
12584 open the System menu. When nil, Emacs silently swallows alt key events.");
12585 Vw32_pass_alt_to_system = Qnil;
12586
12587 DEFVAR_LISP ("w32-alt-is-meta", &Vw32_alt_is_meta,
12588 "Non-nil if the alt key is to be considered the same as the meta key.\n\
12589 When nil, Emacs will translate the alt key to the Alt modifier, and not Meta.");
12590 Vw32_alt_is_meta = Qt;
12591
12592 DEFVAR_INT ("w32-quit-key", &Vw32_quit_key,
12593 "If non-zero, the virtual key code for an alternative quit key.");
12594 XSETINT (Vw32_quit_key, 0);
12595
12596 DEFVAR_LISP ("w32-pass-lwindow-to-system",
12597 &Vw32_pass_lwindow_to_system,
12598 "Non-nil if the left \"Windows\" key is passed on to Windows.\n\
12599 When non-nil, the Start menu is opened by tapping the key.");
12600 Vw32_pass_lwindow_to_system = Qt;
12601
12602 DEFVAR_LISP ("w32-pass-rwindow-to-system",
12603 &Vw32_pass_rwindow_to_system,
12604 "Non-nil if the right \"Windows\" key is passed on to Windows.\n\
12605 When non-nil, the Start menu is opened by tapping the key.");
12606 Vw32_pass_rwindow_to_system = Qt;
12607
12608 DEFVAR_INT ("w32-phantom-key-code",
12609 &Vw32_phantom_key_code,
12610 "Virtual key code used to generate \"phantom\" key presses.\n\
12611 Value is a number between 0 and 255.\n\
12612 \n\
12613 Phantom key presses are generated in order to stop the system from\n\
12614 acting on \"Windows\" key events when `w32-pass-lwindow-to-system' or\n\
12615 `w32-pass-rwindow-to-system' is nil.");
12616 /* Although 255 is technically not a valid key code, it works and
12617 means that this hack won't interfere with any real key code. */
12618 Vw32_phantom_key_code = 255;
12619
12620 DEFVAR_LISP ("w32-enable-num-lock",
12621 &Vw32_enable_num_lock,
12622 "Non-nil if Num Lock should act normally.\n\
12623 Set to nil to see Num Lock as the key `kp-numlock'.");
12624 Vw32_enable_num_lock = Qt;
12625
12626 DEFVAR_LISP ("w32-enable-caps-lock",
12627 &Vw32_enable_caps_lock,
12628 "Non-nil if Caps Lock should act normally.\n\
12629 Set to nil to see Caps Lock as the key `capslock'.");
12630 Vw32_enable_caps_lock = Qt;
12631
12632 DEFVAR_LISP ("w32-scroll-lock-modifier",
12633 &Vw32_scroll_lock_modifier,
12634 "Modifier to use for the Scroll Lock on state.\n\
12635 The value can be hyper, super, meta, alt, control or shift for the\n\
12636 respective modifier, or nil to see Scroll Lock as the key `scroll'.\n\
12637 Any other value will cause the key to be ignored.");
12638 Vw32_scroll_lock_modifier = Qt;
12639
12640 DEFVAR_LISP ("w32-lwindow-modifier",
12641 &Vw32_lwindow_modifier,
12642 "Modifier to use for the left \"Windows\" key.\n\
12643 The value can be hyper, super, meta, alt, control or shift for the\n\
12644 respective modifier, or nil to appear as the key `lwindow'.\n\
12645 Any other value will cause the key to be ignored.");
12646 Vw32_lwindow_modifier = Qnil;
12647
12648 DEFVAR_LISP ("w32-rwindow-modifier",
12649 &Vw32_rwindow_modifier,
12650 "Modifier to use for the right \"Windows\" key.\n\
12651 The value can be hyper, super, meta, alt, control or shift for the\n\
12652 respective modifier, or nil to appear as the key `rwindow'.\n\
12653 Any other value will cause the key to be ignored.");
12654 Vw32_rwindow_modifier = Qnil;
12655
12656 DEFVAR_LISP ("w32-apps-modifier",
12657 &Vw32_apps_modifier,
12658 "Modifier to use for the \"Apps\" key.\n\
12659 The value can be hyper, super, meta, alt, control or shift for the\n\
12660 respective modifier, or nil to appear as the key `apps'.\n\
12661 Any other value will cause the key to be ignored.");
12662 Vw32_apps_modifier = Qnil;
12663
12664 DEFVAR_LISP ("w32-enable-synthesized_fonts", &Vw32_enable_synthesized_fonts,
12665 "Non-nil enables selection of artificially italicized and bold fonts.");
12666 Vw32_enable_synthesized_fonts = Qnil;
12667
12668 DEFVAR_LISP ("w32-enable-palette", &Vw32_enable_palette,
12669 "Non-nil enables Windows palette management to map colors exactly.");
12670 Vw32_enable_palette = Qt;
12671
12672 DEFVAR_INT ("w32-mouse-button-tolerance",
12673 &Vw32_mouse_button_tolerance,
12674 "Analogue of double click interval for faking middle mouse events.\n\
12675 The value is the minimum time in milliseconds that must elapse between\n\
12676 left/right button down events before they are considered distinct events.\n\
12677 If both mouse buttons are depressed within this interval, a middle mouse\n\
12678 button down event is generated instead.");
12679 XSETINT (Vw32_mouse_button_tolerance, GetDoubleClickTime () / 2);
12680
12681 DEFVAR_INT ("w32-mouse-move-interval",
12682 &Vw32_mouse_move_interval,
12683 "Minimum interval between mouse move events.\n\
12684 The value is the minimum time in milliseconds that must elapse between\n\
12685 successive mouse move (or scroll bar drag) events before they are\n\
12686 reported as lisp events.");
12687 XSETINT (Vw32_mouse_move_interval, 0);
12688
12689 init_x_parm_symbols ();
12690
12691 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
12692 "List of directories to search for bitmap files for w32.");
12693 Vx_bitmap_file_path = decode_env_path ((char *) 0, "PATH");
12694
12695 DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
12696 "The shape of the pointer when over text.\n\
12697 Changing the value does not affect existing frames\n\
12698 unless you set the mouse color.");
12699 Vx_pointer_shape = Qnil;
12700
12701 DEFVAR_LISP ("x-resource-name", &Vx_resource_name,
12702 "The name Emacs uses to look up resources; for internal use only.\n\
12703 `x-get-resource' uses this as the first component of the instance name\n\
12704 when requesting resource values.\n\
12705 Emacs initially sets `x-resource-name' to the name under which Emacs\n\
12706 was invoked, or to the value specified with the `-name' or `-rn'\n\
12707 switches, if present.");
12708 Vx_resource_name = Qnil;
12709
12710 Vx_nontext_pointer_shape = Qnil;
12711
12712 Vx_mode_pointer_shape = Qnil;
12713
12714 DEFVAR_LISP ("x-busy-pointer-shape", &Vx_busy_pointer_shape,
12715 "The shape of the pointer when Emacs is busy.\n\
12716 This variable takes effect when you create a new frame\n\
12717 or when you set the mouse color.");
12718 Vx_busy_pointer_shape = Qnil;
12719
12720 DEFVAR_BOOL ("display-busy-cursor", &display_busy_cursor_p,
12721 "Non-zero means Emacs displays a busy cursor on window systems.");
12722 display_busy_cursor_p = 1;
12723
12724 DEFVAR_LISP ("x-sensitive-text-pointer-shape",
12725 &Vx_sensitive_text_pointer_shape,
12726 "The shape of the pointer when over mouse-sensitive text.\n\
12727 This variable takes effect when you create a new frame\n\
12728 or when you set the mouse color.");
12729 Vx_sensitive_text_pointer_shape = Qnil;
12730
12731 DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
12732 "A string indicating the foreground color of the cursor box.");
12733 Vx_cursor_fore_pixel = Qnil;
12734
12735 DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
12736 "Non-nil if no window manager is in use.\n\
12737 Emacs doesn't try to figure this out; this is always nil\n\
12738 unless you set it to something else.");
12739 /* We don't have any way to find this out, so set it to nil
12740 and maybe the user would like to set it to t. */
12741 Vx_no_window_manager = Qnil;
12742
12743 DEFVAR_LISP ("x-pixel-size-width-font-regexp",
12744 &Vx_pixel_size_width_font_regexp,
12745 "Regexp matching a font name whose width is the same as `PIXEL_SIZE'.\n\
12746 \n\
12747 Since Emacs gets width of a font matching with this regexp from\n\
12748 PIXEL_SIZE field of the name, font finding mechanism gets faster for\n\
12749 such a font. This is especially effective for such large fonts as\n\
12750 Chinese, Japanese, and Korean.");
12751 Vx_pixel_size_width_font_regexp = Qnil;
12752
12753 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
12754 "Time after which cached images are removed from the cache.\n\
12755 When an image has not been displayed this many seconds, remove it\n\
12756 from the image cache. Value must be an integer or nil with nil\n\
12757 meaning don't clear the cache.");
12758 Vimage_cache_eviction_delay = make_number (30 * 60);
12759
12760 DEFVAR_LISP ("image-types", &Vimage_types,
12761 "List of supported image types.\n\
12762 Each element of the list is a symbol for a supported image type.");
12763 Vimage_types = Qnil;
12764
12765 DEFVAR_LISP ("w32-bdf-filename-alist",
12766 &Vw32_bdf_filename_alist,
12767 "List of bdf fonts and their corresponding filenames.");
12768 Vw32_bdf_filename_alist = Qnil;
12769
12770 DEFVAR_BOOL ("w32-strict-fontnames",
12771 &w32_strict_fontnames,
12772 "Non-nil means only use fonts that are exact matches for those requested.\n\
12773 Default is nil, which allows old fontnames that are not XLFD compliant,\n\
12774 and allows third-party CJK display to work by specifying false charset\n\
12775 fields to trick Emacs into translating to Big5, SJIS etc.\n\
12776 Setting this to t will prevent wrong fonts being selected when\n\
12777 fontsets are automatically created.");
12778 w32_strict_fontnames = 0;
12779
12780 DEFVAR_BOOL ("w32-strict-painting",
12781 &w32_strict_painting,
12782 "Non-nil means use strict rules for repainting frames.\n\
12783 Set this to nil to get the old behaviour for repainting; this should\n\
12784 only be necessary if the default setting causes problems.");
12785 w32_strict_painting = 1;
12786
12787 DEFVAR_LISP ("w32-system-coding-system",
12788 &Vw32_system_coding_system,
12789 "Coding system used by Windows system functions, such as for font names.");
12790 Vw32_system_coding_system = Qnil;
12791
12792 defsubr (&Sx_get_resource);
12793 #if 0 /* NTEMACS_TODO: Port to W32 */
12794 defsubr (&Sx_change_window_property);
12795 defsubr (&Sx_delete_window_property);
12796 defsubr (&Sx_window_property);
12797 #endif
12798 defsubr (&Sxw_display_color_p);
12799 defsubr (&Sx_display_grayscale_p);
12800 defsubr (&Sxw_color_defined_p);
12801 defsubr (&Sxw_color_values);
12802 defsubr (&Sx_server_max_request_size);
12803 defsubr (&Sx_server_vendor);
12804 defsubr (&Sx_server_version);
12805 defsubr (&Sx_display_pixel_width);
12806 defsubr (&Sx_display_pixel_height);
12807 defsubr (&Sx_display_mm_width);
12808 defsubr (&Sx_display_mm_height);
12809 defsubr (&Sx_display_screens);
12810 defsubr (&Sx_display_planes);
12811 defsubr (&Sx_display_color_cells);
12812 defsubr (&Sx_display_visual_class);
12813 defsubr (&Sx_display_backing_store);
12814 defsubr (&Sx_display_save_under);
12815 defsubr (&Sx_parse_geometry);
12816 defsubr (&Sx_create_frame);
12817 defsubr (&Sx_open_connection);
12818 defsubr (&Sx_close_connection);
12819 defsubr (&Sx_display_list);
12820 defsubr (&Sx_synchronize);
12821
12822 /* W32 specific functions */
12823
12824 defsubr (&Sw32_focus_frame);
12825 defsubr (&Sw32_select_font);
12826 defsubr (&Sw32_define_rgb_color);
12827 defsubr (&Sw32_default_color_map);
12828 defsubr (&Sw32_load_color_file);
12829 defsubr (&Sw32_send_sys_command);
12830 defsubr (&Sw32_shell_execute);
12831 defsubr (&Sw32_register_hot_key);
12832 defsubr (&Sw32_unregister_hot_key);
12833 defsubr (&Sw32_registered_hot_keys);
12834 defsubr (&Sw32_reconstruct_hot_key);
12835 defsubr (&Sw32_toggle_lock_key);
12836 defsubr (&Sw32_find_bdf_fonts);
12837
12838 /* Setting callback functions for fontset handler. */
12839 get_font_info_func = w32_get_font_info;
12840
12841 #if 0 /* This function pointer doesn't seem to be used anywhere.
12842 And the pointer assigned has the wrong type, anyway. */
12843 list_fonts_func = w32_list_fonts;
12844 #endif
12845
12846 load_font_func = w32_load_font;
12847 find_ccl_program_func = w32_find_ccl_program;
12848 query_font_func = w32_query_font;
12849 set_frame_fontset_func = x_set_font;
12850 check_window_system_func = check_w32;
12851
12852 #if 0 /* NTEMACS_TODO Image support for W32 */
12853 /* Images. */
12854 Qxbm = intern ("xbm");
12855 staticpro (&Qxbm);
12856 QCtype = intern (":type");
12857 staticpro (&QCtype);
12858 QCalgorithm = intern (":algorithm");
12859 staticpro (&QCalgorithm);
12860 QCheuristic_mask = intern (":heuristic-mask");
12861 staticpro (&QCheuristic_mask);
12862 QCcolor_symbols = intern (":color-symbols");
12863 staticpro (&QCcolor_symbols);
12864 QCdata = intern (":data");
12865 staticpro (&QCdata);
12866 QCascent = intern (":ascent");
12867 staticpro (&QCascent);
12868 QCmargin = intern (":margin");
12869 staticpro (&QCmargin);
12870 QCrelief = intern (":relief");
12871 staticpro (&QCrelief);
12872 Qpostscript = intern ("postscript");
12873 staticpro (&Qpostscript);
12874 QCloader = intern (":loader");
12875 staticpro (&QCloader);
12876 QCbounding_box = intern (":bounding-box");
12877 staticpro (&QCbounding_box);
12878 QCpt_width = intern (":pt-width");
12879 staticpro (&QCpt_width);
12880 QCpt_height = intern (":pt-height");
12881 staticpro (&QCpt_height);
12882 QCindex = intern (":index");
12883 staticpro (&QCindex);
12884 Qpbm = intern ("pbm");
12885 staticpro (&Qpbm);
12886
12887 #if HAVE_XPM
12888 Qxpm = intern ("xpm");
12889 staticpro (&Qxpm);
12890 #endif
12891
12892 #if HAVE_JPEG
12893 Qjpeg = intern ("jpeg");
12894 staticpro (&Qjpeg);
12895 #endif
12896
12897 #if HAVE_TIFF
12898 Qtiff = intern ("tiff");
12899 staticpro (&Qtiff);
12900 #endif
12901
12902 #if HAVE_GIF
12903 Qgif = intern ("gif");
12904 staticpro (&Qgif);
12905 #endif
12906
12907 #if HAVE_PNG
12908 Qpng = intern ("png");
12909 staticpro (&Qpng);
12910 #endif
12911
12912 defsubr (&Sclear_image_cache);
12913
12914 #if GLYPH_DEBUG
12915 defsubr (&Simagep);
12916 defsubr (&Slookup_image);
12917 #endif
12918 #endif /* NTEMACS_TODO */
12919
12920 /* Busy-cursor. */
12921 defsubr (&Sx_show_busy_cursor);
12922 defsubr (&Sx_hide_busy_cursor);
12923 busy_count = 0;
12924 inhibit_busy_cursor = 0;
12925
12926 defsubr (&Sx_show_tip);
12927 defsubr (&Sx_hide_tip);
12928 staticpro (&tip_timer);
12929 tip_timer = Qnil;
12930
12931 defsubr (&Sx_file_dialog);
12932 }
12933
12934
12935 void
12936 init_xfns ()
12937 {
12938 image_types = NULL;
12939 Vimage_types = Qnil;
12940
12941 #if 0 /* NTEMACS_TODO : Image support for W32 */
12942 define_image_type (&xbm_type);
12943 define_image_type (&gs_type);
12944 define_image_type (&pbm_type);
12945
12946 #if HAVE_XPM
12947 define_image_type (&xpm_type);
12948 #endif
12949
12950 #if HAVE_JPEG
12951 define_image_type (&jpeg_type);
12952 #endif
12953
12954 #if HAVE_TIFF
12955 define_image_type (&tiff_type);
12956 #endif
12957
12958 #if HAVE_GIF
12959 define_image_type (&gif_type);
12960 #endif
12961
12962 #if HAVE_PNG
12963 define_image_type (&png_type);
12964 #endif
12965 #endif /* NTEMACS_TODO */
12966 }
12967
12968 #undef abort
12969
12970 void
12971 w32_abort()
12972 {
12973 int button;
12974 button = MessageBox (NULL,
12975 "A fatal error has occurred!\n\n"
12976 "Select Abort to exit, Retry to debug, Ignore to continue",
12977 "Emacs Abort Dialog",
12978 MB_ICONEXCLAMATION | MB_TASKMODAL
12979 | MB_SETFOREGROUND | MB_ABORTRETRYIGNORE);
12980 switch (button)
12981 {
12982 case IDRETRY:
12983 DebugBreak ();
12984 break;
12985 case IDIGNORE:
12986 break;
12987 case IDABORT:
12988 default:
12989 abort ();
12990 break;
12991 }
12992 }
12993
12994 /* For convenience when debugging. */
12995 int
12996 w32_last_error()
12997 {
12998 return GetLastError ();
12999 }