(trackmouse_window, track_mouse_event_fn): New vars.
[bpt/emacs.git] / src / w32fns.c
1 /* Graphical user interface functions for the Microsoft W32 API.
2 Copyright (C) 1989, 92, 93, 94, 95, 1996, 1997, 1998, 1999, 2000, 2001
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 "dispextern.h"
34 #include "w32term.h"
35 #include "keyboard.h"
36 #include "frame.h"
37 #include "window.h"
38 #include "buffer.h"
39 #include "fontset.h"
40 #include "intervals.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 void x_compute_fringe_widths P_ ((struct frame *, int));
57 extern double atof ();
58 extern int w32_console_toggle_lock_key P_ ((int, Lisp_Object));
59 extern void w32_menu_display_help P_ ((HWND, HMENU, UINT, UINT));
60 extern void w32_free_menu_strings P_ ((HWND));
61
62 extern int quit_char;
63
64 /* A definition of XColor for non-X frames. */
65 #ifndef HAVE_X_WINDOWS
66 typedef struct {
67 unsigned long pixel;
68 unsigned short red, green, blue;
69 char flags;
70 char pad;
71 } XColor;
72 #endif
73
74 extern char *lispy_function_keys[];
75
76 /* The gray bitmap `bitmaps/gray'. This is done because w32term.c uses
77 it, and including `bitmaps/gray' more than once is a problem when
78 config.h defines `static' as an empty replacement string. */
79
80 int gray_bitmap_width = gray_width;
81 int gray_bitmap_height = gray_height;
82 unsigned char *gray_bitmap_bits = gray_bits;
83
84 /* The colormap for converting color names to RGB values */
85 Lisp_Object Vw32_color_map;
86
87 /* Non nil if alt key presses are passed on to Windows. */
88 Lisp_Object Vw32_pass_alt_to_system;
89
90 /* Non nil if alt key is translated to meta_modifier, nil if it is translated
91 to alt_modifier. */
92 Lisp_Object Vw32_alt_is_meta;
93
94 /* If non-zero, the windows virtual key code for an alternative quit key. */
95 Lisp_Object Vw32_quit_key;
96
97 /* Non nil if left window key events are passed on to Windows (this only
98 affects whether "tapping" the key opens the Start menu). */
99 Lisp_Object Vw32_pass_lwindow_to_system;
100
101 /* Non nil if right window key events are passed on to Windows (this
102 only affects whether "tapping" the key opens the Start menu). */
103 Lisp_Object Vw32_pass_rwindow_to_system;
104
105 /* Virtual key code used to generate "phantom" key presses in order
106 to stop system from acting on Windows key events. */
107 Lisp_Object Vw32_phantom_key_code;
108
109 /* Modifier associated with the left "Windows" key, or nil to act as a
110 normal key. */
111 Lisp_Object Vw32_lwindow_modifier;
112
113 /* Modifier associated with the right "Windows" key, or nil to act as a
114 normal key. */
115 Lisp_Object Vw32_rwindow_modifier;
116
117 /* Modifier associated with the "Apps" key, or nil to act as a normal
118 key. */
119 Lisp_Object Vw32_apps_modifier;
120
121 /* Value is nil if Num Lock acts as a function key. */
122 Lisp_Object Vw32_enable_num_lock;
123
124 /* Value is nil if Caps Lock acts as a function key. */
125 Lisp_Object Vw32_enable_caps_lock;
126
127 /* Modifier associated with Scroll Lock, or nil to act as a normal key. */
128 Lisp_Object Vw32_scroll_lock_modifier;
129
130 /* Switch to control whether we inhibit requests for synthesized bold
131 and italic versions of fonts. */
132 Lisp_Object Vw32_enable_synthesized_fonts;
133
134 /* Enable palette management. */
135 Lisp_Object Vw32_enable_palette;
136
137 /* Control how close left/right button down events must be to
138 be converted to a middle button down event. */
139 Lisp_Object Vw32_mouse_button_tolerance;
140
141 /* Minimum interval between mouse movement (and scroll bar drag)
142 events that are passed on to the event loop. */
143 Lisp_Object Vw32_mouse_move_interval;
144
145 /* The name we're using in resource queries. */
146 Lisp_Object Vx_resource_name;
147
148 /* Non nil if no window manager is in use. */
149 Lisp_Object Vx_no_window_manager;
150
151 /* Non-zero means we're allowed to display a hourglass pointer. */
152
153 int display_hourglass_p;
154
155 /* The background and shape of the mouse pointer, and shape when not
156 over text or in the modeline. */
157
158 Lisp_Object Vx_pointer_shape, Vx_nontext_pointer_shape, Vx_mode_pointer_shape;
159 Lisp_Object Vx_hourglass_pointer_shape, Vx_window_horizontal_drag_shape;
160
161 /* The shape when over mouse-sensitive text. */
162
163 Lisp_Object Vx_sensitive_text_pointer_shape;
164
165 /* Color of chars displayed in cursor box. */
166
167 Lisp_Object Vx_cursor_fore_pixel;
168
169 /* Nonzero if using Windows. */
170
171 static int w32_in_use;
172
173 /* Search path for bitmap files. */
174
175 Lisp_Object Vx_bitmap_file_path;
176
177 /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'. */
178
179 Lisp_Object Vx_pixel_size_width_font_regexp;
180
181 /* Alist of bdf fonts and the files that define them. */
182 Lisp_Object Vw32_bdf_filename_alist;
183
184 /* A flag to control whether fonts are matched strictly or not. */
185 int w32_strict_fontnames;
186
187 /* A flag to control whether we should only repaint if GetUpdateRect
188 indicates there is an update region. */
189 int w32_strict_painting;
190
191 /* Associative list linking character set strings to Windows codepages. */
192 Lisp_Object Vw32_charset_info_alist;
193
194 /* VIETNAMESE_CHARSET is not defined in some versions of MSVC. */
195 #ifndef VIETNAMESE_CHARSET
196 #define VIETNAMESE_CHARSET 163
197 #endif
198
199 Lisp_Object Qauto_raise;
200 Lisp_Object Qauto_lower;
201 Lisp_Object Qbar;
202 Lisp_Object Qborder_color;
203 Lisp_Object Qborder_width;
204 Lisp_Object Qbox;
205 Lisp_Object Qcursor_color;
206 Lisp_Object Qcursor_type;
207 Lisp_Object Qgeometry;
208 Lisp_Object Qicon_left;
209 Lisp_Object Qicon_top;
210 Lisp_Object Qicon_type;
211 Lisp_Object Qicon_name;
212 Lisp_Object Qinternal_border_width;
213 Lisp_Object Qleft;
214 Lisp_Object Qright;
215 Lisp_Object Qmouse_color;
216 Lisp_Object Qnone;
217 Lisp_Object Qparent_id;
218 Lisp_Object Qscroll_bar_width;
219 Lisp_Object Qsuppress_icon;
220 Lisp_Object Qundefined_color;
221 Lisp_Object Qvertical_scroll_bars;
222 Lisp_Object Qvisibility;
223 Lisp_Object Qwindow_id;
224 Lisp_Object Qx_frame_parameter;
225 Lisp_Object Qx_resource_name;
226 Lisp_Object Quser_position;
227 Lisp_Object Quser_size;
228 Lisp_Object Qscreen_gamma;
229 Lisp_Object Qline_spacing;
230 Lisp_Object Qcenter;
231 Lisp_Object Qcancel_timer;
232 Lisp_Object Qhyper;
233 Lisp_Object Qsuper;
234 Lisp_Object Qmeta;
235 Lisp_Object Qalt;
236 Lisp_Object Qctrl;
237 Lisp_Object Qcontrol;
238 Lisp_Object Qshift;
239
240 Lisp_Object Qw32_charset_ansi;
241 Lisp_Object Qw32_charset_default;
242 Lisp_Object Qw32_charset_symbol;
243 Lisp_Object Qw32_charset_shiftjis;
244 Lisp_Object Qw32_charset_hangeul;
245 Lisp_Object Qw32_charset_gb2312;
246 Lisp_Object Qw32_charset_chinesebig5;
247 Lisp_Object Qw32_charset_oem;
248
249 #ifndef JOHAB_CHARSET
250 #define JOHAB_CHARSET 130
251 #endif
252 #ifdef JOHAB_CHARSET
253 Lisp_Object Qw32_charset_easteurope;
254 Lisp_Object Qw32_charset_turkish;
255 Lisp_Object Qw32_charset_baltic;
256 Lisp_Object Qw32_charset_russian;
257 Lisp_Object Qw32_charset_arabic;
258 Lisp_Object Qw32_charset_greek;
259 Lisp_Object Qw32_charset_hebrew;
260 Lisp_Object Qw32_charset_vietnamese;
261 Lisp_Object Qw32_charset_thai;
262 Lisp_Object Qw32_charset_johab;
263 Lisp_Object Qw32_charset_mac;
264 #endif
265
266 #ifdef UNICODE_CHARSET
267 Lisp_Object Qw32_charset_unicode;
268 #endif
269
270 extern Lisp_Object Qtop;
271 extern Lisp_Object Qdisplay;
272 extern Lisp_Object Qtool_bar_lines;
273
274 /* State variables for emulating a three button mouse. */
275 #define LMOUSE 1
276 #define MMOUSE 2
277 #define RMOUSE 4
278
279 static int button_state = 0;
280 static W32Msg saved_mouse_button_msg;
281 static unsigned mouse_button_timer; /* non-zero when timer is active */
282 static W32Msg saved_mouse_move_msg;
283 static unsigned mouse_move_timer;
284
285 /* Window that is tracking the mouse. */
286 static HWND track_mouse_window;
287 FARPROC track_mouse_event_fn;
288
289 /* W95 mousewheel handler */
290 unsigned int msh_mousewheel = 0;
291
292 #define MOUSE_BUTTON_ID 1
293 #define MOUSE_MOVE_ID 2
294
295 /* The below are defined in frame.c. */
296
297 extern Lisp_Object Qheight, Qminibuffer, Qname, Qonly, Qwidth;
298 extern Lisp_Object Qunsplittable, Qmenu_bar_lines, Qbuffer_predicate, Qtitle;
299 extern Lisp_Object Qtool_bar_lines;
300
301 extern Lisp_Object Vwindow_system_version;
302
303 Lisp_Object Qface_set_after_frame_default;
304
305 #ifdef GLYPH_DEBUG
306 int image_cache_refcount, dpyinfo_refcount;
307 #endif
308
309
310 /* From w32term.c. */
311 extern Lisp_Object Vw32_num_mouse_buttons;
312 extern Lisp_Object Vw32_recognize_altgr;
313
314 extern HWND w32_system_caret_hwnd;
315 extern int w32_system_caret_width;
316 extern int w32_system_caret_height;
317 extern int w32_system_caret_x;
318 extern int w32_system_caret_y;
319
320 \f
321 /* Error if we are not connected to MS-Windows. */
322 void
323 check_w32 ()
324 {
325 if (! w32_in_use)
326 error ("MS-Windows not in use or not initialized");
327 }
328
329 /* Nonzero if we can use mouse menus.
330 You should not call this unless HAVE_MENUS is defined. */
331
332 int
333 have_menus_p ()
334 {
335 return w32_in_use;
336 }
337
338 /* Extract a frame as a FRAME_PTR, defaulting to the selected frame
339 and checking validity for W32. */
340
341 FRAME_PTR
342 check_x_frame (frame)
343 Lisp_Object frame;
344 {
345 FRAME_PTR f;
346
347 if (NILP (frame))
348 frame = selected_frame;
349 CHECK_LIVE_FRAME (frame);
350 f = XFRAME (frame);
351 if (! FRAME_W32_P (f))
352 error ("non-w32 frame used");
353 return f;
354 }
355
356 /* Let the user specify an display with a frame.
357 nil stands for the selected frame--or, if that is not a w32 frame,
358 the first display on the list. */
359
360 static struct w32_display_info *
361 check_x_display_info (frame)
362 Lisp_Object frame;
363 {
364 if (NILP (frame))
365 {
366 struct frame *sf = XFRAME (selected_frame);
367
368 if (FRAME_W32_P (sf) && FRAME_LIVE_P (sf))
369 return FRAME_W32_DISPLAY_INFO (sf);
370 else
371 return &one_w32_display_info;
372 }
373 else if (STRINGP (frame))
374 return x_display_info_for_name (frame);
375 else
376 {
377 FRAME_PTR f;
378
379 CHECK_LIVE_FRAME (frame);
380 f = XFRAME (frame);
381 if (! FRAME_W32_P (f))
382 error ("non-w32 frame used");
383 return FRAME_W32_DISPLAY_INFO (f);
384 }
385 }
386 \f
387 /* Return the Emacs frame-object corresponding to an w32 window.
388 It could be the frame's main window or an icon window. */
389
390 /* This function can be called during GC, so use GC_xxx type test macros. */
391
392 struct frame *
393 x_window_to_frame (dpyinfo, wdesc)
394 struct w32_display_info *dpyinfo;
395 HWND wdesc;
396 {
397 Lisp_Object tail, frame;
398 struct frame *f;
399
400 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
401 {
402 frame = XCAR (tail);
403 if (!GC_FRAMEP (frame))
404 continue;
405 f = XFRAME (frame);
406 if (!FRAME_W32_P (f) || FRAME_W32_DISPLAY_INFO (f) != dpyinfo)
407 continue;
408 if (f->output_data.w32->hourglass_window == wdesc)
409 return f;
410
411 if (FRAME_W32_WINDOW (f) == wdesc)
412 return f;
413 }
414 return 0;
415 }
416
417 \f
418
419 /* Code to deal with bitmaps. Bitmaps are referenced by their bitmap
420 id, which is just an int that this section returns. Bitmaps are
421 reference counted so they can be shared among frames.
422
423 Bitmap indices are guaranteed to be > 0, so a negative number can
424 be used to indicate no bitmap.
425
426 If you use x_create_bitmap_from_data, then you must keep track of
427 the bitmaps yourself. That is, creating a bitmap from the same
428 data more than once will not be caught. */
429
430
431 /* Functions to access the contents of a bitmap, given an id. */
432
433 int
434 x_bitmap_height (f, id)
435 FRAME_PTR f;
436 int id;
437 {
438 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].height;
439 }
440
441 int
442 x_bitmap_width (f, id)
443 FRAME_PTR f;
444 int id;
445 {
446 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].width;
447 }
448
449 int
450 x_bitmap_pixmap (f, id)
451 FRAME_PTR f;
452 int id;
453 {
454 return (int) FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
455 }
456
457
458 /* Allocate a new bitmap record. Returns index of new record. */
459
460 static int
461 x_allocate_bitmap_record (f)
462 FRAME_PTR f;
463 {
464 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
465 int i;
466
467 if (dpyinfo->bitmaps == NULL)
468 {
469 dpyinfo->bitmaps_size = 10;
470 dpyinfo->bitmaps
471 = (struct w32_bitmap_record *) xmalloc (dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
472 dpyinfo->bitmaps_last = 1;
473 return 1;
474 }
475
476 if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size)
477 return ++dpyinfo->bitmaps_last;
478
479 for (i = 0; i < dpyinfo->bitmaps_size; ++i)
480 if (dpyinfo->bitmaps[i].refcount == 0)
481 return i + 1;
482
483 dpyinfo->bitmaps_size *= 2;
484 dpyinfo->bitmaps
485 = (struct w32_bitmap_record *) xrealloc (dpyinfo->bitmaps,
486 dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
487 return ++dpyinfo->bitmaps_last;
488 }
489
490 /* Add one reference to the reference count of the bitmap with id ID. */
491
492 void
493 x_reference_bitmap (f, id)
494 FRAME_PTR f;
495 int id;
496 {
497 ++FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
498 }
499
500 /* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at BITS. */
501
502 int
503 x_create_bitmap_from_data (f, bits, width, height)
504 struct frame *f;
505 char *bits;
506 unsigned int width, height;
507 {
508 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
509 Pixmap bitmap;
510 int id;
511
512 bitmap = CreateBitmap (width, height,
513 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_planes,
514 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_cbits,
515 bits);
516
517 if (! bitmap)
518 return -1;
519
520 id = x_allocate_bitmap_record (f);
521 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
522 dpyinfo->bitmaps[id - 1].file = NULL;
523 dpyinfo->bitmaps[id - 1].hinst = NULL;
524 dpyinfo->bitmaps[id - 1].refcount = 1;
525 dpyinfo->bitmaps[id - 1].depth = 1;
526 dpyinfo->bitmaps[id - 1].height = height;
527 dpyinfo->bitmaps[id - 1].width = width;
528
529 return id;
530 }
531
532 /* Create bitmap from file FILE for frame F. */
533
534 int
535 x_create_bitmap_from_file (f, file)
536 struct frame *f;
537 Lisp_Object file;
538 {
539 return -1;
540 #if 0 /* TODO : bitmap support */
541 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
542 unsigned int width, height;
543 HBITMAP bitmap;
544 int xhot, yhot, result, id;
545 Lisp_Object found;
546 int fd;
547 char *filename;
548 HINSTANCE hinst;
549
550 /* Look for an existing bitmap with the same name. */
551 for (id = 0; id < dpyinfo->bitmaps_last; ++id)
552 {
553 if (dpyinfo->bitmaps[id].refcount
554 && dpyinfo->bitmaps[id].file
555 && !strcmp (dpyinfo->bitmaps[id].file, (char *) XSTRING (file)->data))
556 {
557 ++dpyinfo->bitmaps[id].refcount;
558 return id + 1;
559 }
560 }
561
562 /* Search bitmap-file-path for the file, if appropriate. */
563 fd = openp (Vx_bitmap_file_path, file, Qnil, &found, 0);
564 if (fd < 0)
565 return -1;
566 emacs_close (fd);
567
568 filename = (char *) XSTRING (found)->data;
569
570 hinst = LoadLibraryEx (filename, NULL, LOAD_LIBRARY_AS_DATAFILE);
571
572 if (hinst == NULL)
573 return -1;
574
575
576 result = XReadBitmapFile (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
577 filename, &width, &height, &bitmap, &xhot, &yhot);
578 if (result != BitmapSuccess)
579 return -1;
580
581 id = x_allocate_bitmap_record (f);
582 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
583 dpyinfo->bitmaps[id - 1].refcount = 1;
584 dpyinfo->bitmaps[id - 1].file = (char *) xmalloc (XSTRING (file)->size + 1);
585 dpyinfo->bitmaps[id - 1].depth = 1;
586 dpyinfo->bitmaps[id - 1].height = height;
587 dpyinfo->bitmaps[id - 1].width = width;
588 strcpy (dpyinfo->bitmaps[id - 1].file, XSTRING (file)->data);
589
590 return id;
591 #endif /* TODO */
592 }
593
594 /* Remove reference to bitmap with id number ID. */
595
596 void
597 x_destroy_bitmap (f, id)
598 FRAME_PTR f;
599 int id;
600 {
601 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
602
603 if (id > 0)
604 {
605 --dpyinfo->bitmaps[id - 1].refcount;
606 if (dpyinfo->bitmaps[id - 1].refcount == 0)
607 {
608 BLOCK_INPUT;
609 DeleteObject (dpyinfo->bitmaps[id - 1].pixmap);
610 if (dpyinfo->bitmaps[id - 1].file)
611 {
612 xfree (dpyinfo->bitmaps[id - 1].file);
613 dpyinfo->bitmaps[id - 1].file = NULL;
614 }
615 UNBLOCK_INPUT;
616 }
617 }
618 }
619
620 /* Free all the bitmaps for the display specified by DPYINFO. */
621
622 static void
623 x_destroy_all_bitmaps (dpyinfo)
624 struct w32_display_info *dpyinfo;
625 {
626 int i;
627 for (i = 0; i < dpyinfo->bitmaps_last; i++)
628 if (dpyinfo->bitmaps[i].refcount > 0)
629 {
630 DeleteObject (dpyinfo->bitmaps[i].pixmap);
631 if (dpyinfo->bitmaps[i].file)
632 xfree (dpyinfo->bitmaps[i].file);
633 }
634 dpyinfo->bitmaps_last = 0;
635 }
636 \f
637 /* Connect the frame-parameter names for W32 frames
638 to the ways of passing the parameter values to the window system.
639
640 The name of a parameter, as a Lisp symbol,
641 has an `x-frame-parameter' property which is an integer in Lisp
642 but can be interpreted as an `enum x_frame_parm' in C. */
643
644 enum x_frame_parm
645 {
646 X_PARM_FOREGROUND_COLOR,
647 X_PARM_BACKGROUND_COLOR,
648 X_PARM_MOUSE_COLOR,
649 X_PARM_CURSOR_COLOR,
650 X_PARM_BORDER_COLOR,
651 X_PARM_ICON_TYPE,
652 X_PARM_FONT,
653 X_PARM_BORDER_WIDTH,
654 X_PARM_INTERNAL_BORDER_WIDTH,
655 X_PARM_NAME,
656 X_PARM_AUTORAISE,
657 X_PARM_AUTOLOWER,
658 X_PARM_VERT_SCROLL_BAR,
659 X_PARM_VISIBILITY,
660 X_PARM_MENU_BAR_LINES
661 };
662
663
664 struct x_frame_parm_table
665 {
666 char *name;
667 void (*setter) P_ ((struct frame *, Lisp_Object, Lisp_Object));
668 };
669
670 BOOL my_show_window P_ ((struct frame *, HWND, int));
671 void my_set_window_pos P_ ((HWND, HWND, int, int, int, int, UINT));
672 static Lisp_Object unwind_create_frame P_ ((Lisp_Object));
673 static Lisp_Object unwind_create_tip_frame P_ ((Lisp_Object));
674 static void x_change_window_heights P_ ((Lisp_Object, int));
675 /* TODO: Native Input Method support; see x_create_im. */
676 void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
677 static void x_set_line_spacing P_ ((struct frame *, Lisp_Object, Lisp_Object));
678 void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
679 void x_set_mouse_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
680 void x_set_cursor_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
681 void x_set_border_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
682 void x_set_cursor_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
683 void x_set_icon_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
684 void x_set_icon_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
685 void x_set_font P_ ((struct frame *, Lisp_Object, Lisp_Object));
686 static void x_set_fringe_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
687 void x_set_border_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
688 void x_set_internal_border_width P_ ((struct frame *, Lisp_Object,
689 Lisp_Object));
690 void x_explicitly_set_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
691 void x_set_autoraise P_ ((struct frame *, Lisp_Object, Lisp_Object));
692 void x_set_autolower P_ ((struct frame *, Lisp_Object, Lisp_Object));
693 void x_set_vertical_scroll_bars P_ ((struct frame *, Lisp_Object,
694 Lisp_Object));
695 void x_set_visibility P_ ((struct frame *, Lisp_Object, Lisp_Object));
696 void x_set_menu_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
697 void x_set_scroll_bar_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
698 void x_set_title P_ ((struct frame *, Lisp_Object, Lisp_Object));
699 void x_set_unsplittable P_ ((struct frame *, Lisp_Object, Lisp_Object));
700 void x_set_tool_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
701 static void x_set_screen_gamma P_ ((struct frame *, Lisp_Object, Lisp_Object));
702 static void x_edge_detection P_ ((struct frame *, struct image *, Lisp_Object,
703 Lisp_Object));
704
705 static struct x_frame_parm_table x_frame_parms[] =
706 {
707 "auto-raise", x_set_autoraise,
708 "auto-lower", x_set_autolower,
709 "background-color", x_set_background_color,
710 "border-color", x_set_border_color,
711 "border-width", x_set_border_width,
712 "cursor-color", x_set_cursor_color,
713 "cursor-type", x_set_cursor_type,
714 "font", x_set_font,
715 "foreground-color", x_set_foreground_color,
716 "icon-name", x_set_icon_name,
717 "icon-type", x_set_icon_type,
718 "internal-border-width", x_set_internal_border_width,
719 "menu-bar-lines", x_set_menu_bar_lines,
720 "mouse-color", x_set_mouse_color,
721 "name", x_explicitly_set_name,
722 "scroll-bar-width", x_set_scroll_bar_width,
723 "title", x_set_title,
724 "unsplittable", x_set_unsplittable,
725 "vertical-scroll-bars", x_set_vertical_scroll_bars,
726 "visibility", x_set_visibility,
727 "tool-bar-lines", x_set_tool_bar_lines,
728 "screen-gamma", x_set_screen_gamma,
729 "line-spacing", x_set_line_spacing,
730 "left-fringe", x_set_fringe_width,
731 "right-fringe", x_set_fringe_width
732
733 };
734
735 /* Attach the `x-frame-parameter' properties to
736 the Lisp symbol names of parameters relevant to W32. */
737
738 void
739 init_x_parm_symbols ()
740 {
741 int i;
742
743 for (i = 0; i < sizeof (x_frame_parms) / sizeof (x_frame_parms[0]); i++)
744 Fput (intern (x_frame_parms[i].name), Qx_frame_parameter,
745 make_number (i));
746 }
747 \f
748 /* Change the parameters of frame F as specified by ALIST.
749 If a parameter is not specially recognized, do nothing;
750 otherwise call the `x_set_...' function for that parameter. */
751
752 void
753 x_set_frame_parameters (f, alist)
754 FRAME_PTR f;
755 Lisp_Object alist;
756 {
757 Lisp_Object tail;
758
759 /* If both of these parameters are present, it's more efficient to
760 set them both at once. So we wait until we've looked at the
761 entire list before we set them. */
762 int width, height;
763
764 /* Same here. */
765 Lisp_Object left, top;
766
767 /* Same with these. */
768 Lisp_Object icon_left, icon_top;
769
770 /* Record in these vectors all the parms specified. */
771 Lisp_Object *parms;
772 Lisp_Object *values;
773 int i, p;
774 int left_no_change = 0, top_no_change = 0;
775 int icon_left_no_change = 0, icon_top_no_change = 0;
776
777 struct gcpro gcpro1, gcpro2;
778
779 i = 0;
780 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
781 i++;
782
783 parms = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
784 values = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
785
786 /* Extract parm names and values into those vectors. */
787
788 i = 0;
789 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
790 {
791 Lisp_Object elt;
792
793 elt = Fcar (tail);
794 parms[i] = Fcar (elt);
795 values[i] = Fcdr (elt);
796 i++;
797 }
798 /* TAIL and ALIST are not used again below here. */
799 alist = tail = Qnil;
800
801 GCPRO2 (*parms, *values);
802 gcpro1.nvars = i;
803 gcpro2.nvars = i;
804
805 /* There is no need to gcpro LEFT, TOP, ICON_LEFT, or ICON_TOP,
806 because their values appear in VALUES and strings are not valid. */
807 top = left = Qunbound;
808 icon_left = icon_top = Qunbound;
809
810 /* Provide default values for HEIGHT and WIDTH. */
811 if (FRAME_NEW_WIDTH (f))
812 width = FRAME_NEW_WIDTH (f);
813 else
814 width = FRAME_WIDTH (f);
815
816 if (FRAME_NEW_HEIGHT (f))
817 height = FRAME_NEW_HEIGHT (f);
818 else
819 height = FRAME_HEIGHT (f);
820
821 /* Process foreground_color and background_color before anything else.
822 They are independent of other properties, but other properties (e.g.,
823 cursor_color) are dependent upon them. */
824 /* Process default font as well, since fringe widths depends on it. */
825 for (p = 0; p < i; p++)
826 {
827 Lisp_Object prop, val;
828
829 prop = parms[p];
830 val = values[p];
831 if (EQ (prop, Qforeground_color)
832 || EQ (prop, Qbackground_color)
833 || EQ (prop, Qfont))
834 {
835 register Lisp_Object param_index, old_value;
836
837 old_value = get_frame_param (f, prop);
838
839 if (NILP (Fequal (val, old_value)))
840 {
841 store_frame_param (f, prop, val);
842
843 param_index = Fget (prop, Qx_frame_parameter);
844 if (NATNUMP (param_index)
845 && (XFASTINT (param_index)
846 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
847 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
848 }
849 }
850 }
851
852 /* Now process them in reverse of specified order. */
853 for (i--; i >= 0; i--)
854 {
855 Lisp_Object prop, val;
856
857 prop = parms[i];
858 val = values[i];
859
860 if (EQ (prop, Qwidth) && NUMBERP (val))
861 width = XFASTINT (val);
862 else if (EQ (prop, Qheight) && NUMBERP (val))
863 height = XFASTINT (val);
864 else if (EQ (prop, Qtop))
865 top = val;
866 else if (EQ (prop, Qleft))
867 left = val;
868 else if (EQ (prop, Qicon_top))
869 icon_top = val;
870 else if (EQ (prop, Qicon_left))
871 icon_left = val;
872 else if (EQ (prop, Qforeground_color)
873 || EQ (prop, Qbackground_color)
874 || EQ (prop, Qfont))
875 /* Processed above. */
876 continue;
877 else
878 {
879 register Lisp_Object param_index, old_value;
880
881 old_value = get_frame_param (f, prop);
882
883 store_frame_param (f, prop, val);
884
885 param_index = Fget (prop, Qx_frame_parameter);
886 if (NATNUMP (param_index)
887 && (XFASTINT (param_index)
888 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
889 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
890 }
891 }
892
893 /* Don't die if just one of these was set. */
894 if (EQ (left, Qunbound))
895 {
896 left_no_change = 1;
897 if (f->output_data.w32->left_pos < 0)
898 left = Fcons (Qplus, Fcons (make_number (f->output_data.w32->left_pos), Qnil));
899 else
900 XSETINT (left, f->output_data.w32->left_pos);
901 }
902 if (EQ (top, Qunbound))
903 {
904 top_no_change = 1;
905 if (f->output_data.w32->top_pos < 0)
906 top = Fcons (Qplus, Fcons (make_number (f->output_data.w32->top_pos), Qnil));
907 else
908 XSETINT (top, f->output_data.w32->top_pos);
909 }
910
911 /* If one of the icon positions was not set, preserve or default it. */
912 if (EQ (icon_left, Qunbound) || ! INTEGERP (icon_left))
913 {
914 icon_left_no_change = 1;
915 icon_left = Fcdr (Fassq (Qicon_left, f->param_alist));
916 if (NILP (icon_left))
917 XSETINT (icon_left, 0);
918 }
919 if (EQ (icon_top, Qunbound) || ! INTEGERP (icon_top))
920 {
921 icon_top_no_change = 1;
922 icon_top = Fcdr (Fassq (Qicon_top, f->param_alist));
923 if (NILP (icon_top))
924 XSETINT (icon_top, 0);
925 }
926
927 /* Don't set these parameters unless they've been explicitly
928 specified. The window might be mapped or resized while we're in
929 this function, and we don't want to override that unless the lisp
930 code has asked for it.
931
932 Don't set these parameters unless they actually differ from the
933 window's current parameters; the window may not actually exist
934 yet. */
935 {
936 Lisp_Object frame;
937
938 check_frame_size (f, &height, &width);
939
940 XSETFRAME (frame, f);
941
942 if (width != FRAME_WIDTH (f)
943 || height != FRAME_HEIGHT (f)
944 || FRAME_NEW_HEIGHT (f) || FRAME_NEW_WIDTH (f))
945 Fset_frame_size (frame, make_number (width), make_number (height));
946
947 if ((!NILP (left) || !NILP (top))
948 && ! (left_no_change && top_no_change)
949 && ! (NUMBERP (left) && XINT (left) == f->output_data.w32->left_pos
950 && NUMBERP (top) && XINT (top) == f->output_data.w32->top_pos))
951 {
952 int leftpos = 0;
953 int toppos = 0;
954
955 /* Record the signs. */
956 f->output_data.w32->size_hint_flags &= ~ (XNegative | YNegative);
957 if (EQ (left, Qminus))
958 f->output_data.w32->size_hint_flags |= XNegative;
959 else if (INTEGERP (left))
960 {
961 leftpos = XINT (left);
962 if (leftpos < 0)
963 f->output_data.w32->size_hint_flags |= XNegative;
964 }
965 else if (CONSP (left) && EQ (XCAR (left), Qminus)
966 && CONSP (XCDR (left))
967 && INTEGERP (XCAR (XCDR (left))))
968 {
969 leftpos = - XINT (XCAR (XCDR (left)));
970 f->output_data.w32->size_hint_flags |= XNegative;
971 }
972 else if (CONSP (left) && EQ (XCAR (left), Qplus)
973 && CONSP (XCDR (left))
974 && INTEGERP (XCAR (XCDR (left))))
975 {
976 leftpos = XINT (XCAR (XCDR (left)));
977 }
978
979 if (EQ (top, Qminus))
980 f->output_data.w32->size_hint_flags |= YNegative;
981 else if (INTEGERP (top))
982 {
983 toppos = XINT (top);
984 if (toppos < 0)
985 f->output_data.w32->size_hint_flags |= YNegative;
986 }
987 else if (CONSP (top) && EQ (XCAR (top), Qminus)
988 && CONSP (XCDR (top))
989 && INTEGERP (XCAR (XCDR (top))))
990 {
991 toppos = - XINT (XCAR (XCDR (top)));
992 f->output_data.w32->size_hint_flags |= YNegative;
993 }
994 else if (CONSP (top) && EQ (XCAR (top), Qplus)
995 && CONSP (XCDR (top))
996 && INTEGERP (XCAR (XCDR (top))))
997 {
998 toppos = XINT (XCAR (XCDR (top)));
999 }
1000
1001
1002 /* Store the numeric value of the position. */
1003 f->output_data.w32->top_pos = toppos;
1004 f->output_data.w32->left_pos = leftpos;
1005
1006 f->output_data.w32->win_gravity = NorthWestGravity;
1007
1008 /* Actually set that position, and convert to absolute. */
1009 x_set_offset (f, leftpos, toppos, -1);
1010 }
1011
1012 if ((!NILP (icon_left) || !NILP (icon_top))
1013 && ! (icon_left_no_change && icon_top_no_change))
1014 x_wm_set_icon_position (f, XINT (icon_left), XINT (icon_top));
1015 }
1016
1017 UNGCPRO;
1018 }
1019
1020 /* Store the screen positions of frame F into XPTR and YPTR.
1021 These are the positions of the containing window manager window,
1022 not Emacs's own window. */
1023
1024 void
1025 x_real_positions (f, xptr, yptr)
1026 FRAME_PTR f;
1027 int *xptr, *yptr;
1028 {
1029 POINT pt;
1030
1031 {
1032 RECT rect;
1033
1034 GetClientRect(FRAME_W32_WINDOW(f), &rect);
1035 AdjustWindowRect(&rect, f->output_data.w32->dwStyle, FRAME_EXTERNAL_MENU_BAR(f));
1036
1037 pt.x = rect.left;
1038 pt.y = rect.top;
1039 }
1040
1041 ClientToScreen (FRAME_W32_WINDOW(f), &pt);
1042
1043 *xptr = pt.x;
1044 *yptr = pt.y;
1045 }
1046
1047 /* Insert a description of internally-recorded parameters of frame X
1048 into the parameter alist *ALISTPTR that is to be given to the user.
1049 Only parameters that are specific to W32
1050 and whose values are not correctly recorded in the frame's
1051 param_alist need to be considered here. */
1052
1053 void
1054 x_report_frame_params (f, alistptr)
1055 struct frame *f;
1056 Lisp_Object *alistptr;
1057 {
1058 char buf[16];
1059 Lisp_Object tem;
1060
1061 /* Represent negative positions (off the top or left screen edge)
1062 in a way that Fmodify_frame_parameters will understand correctly. */
1063 XSETINT (tem, f->output_data.w32->left_pos);
1064 if (f->output_data.w32->left_pos >= 0)
1065 store_in_alist (alistptr, Qleft, tem);
1066 else
1067 store_in_alist (alistptr, Qleft, Fcons (Qplus, Fcons (tem, Qnil)));
1068
1069 XSETINT (tem, f->output_data.w32->top_pos);
1070 if (f->output_data.w32->top_pos >= 0)
1071 store_in_alist (alistptr, Qtop, tem);
1072 else
1073 store_in_alist (alistptr, Qtop, Fcons (Qplus, Fcons (tem, Qnil)));
1074
1075 store_in_alist (alistptr, Qborder_width,
1076 make_number (f->output_data.w32->border_width));
1077 store_in_alist (alistptr, Qinternal_border_width,
1078 make_number (f->output_data.w32->internal_border_width));
1079 sprintf (buf, "%ld", (long) FRAME_W32_WINDOW (f));
1080 store_in_alist (alistptr, Qwindow_id,
1081 build_string (buf));
1082 store_in_alist (alistptr, Qicon_name, f->icon_name);
1083 FRAME_SAMPLE_VISIBILITY (f);
1084 store_in_alist (alistptr, Qvisibility,
1085 (FRAME_VISIBLE_P (f) ? Qt
1086 : FRAME_ICONIFIED_P (f) ? Qicon : Qnil));
1087 store_in_alist (alistptr, Qdisplay,
1088 XCAR (FRAME_W32_DISPLAY_INFO (f)->name_list_element));
1089 }
1090 \f
1091
1092 DEFUN ("w32-define-rgb-color", Fw32_define_rgb_color,
1093 Sw32_define_rgb_color, 4, 4, 0,
1094 doc: /* Convert RGB numbers to a windows color reference and associate with NAME.
1095 This adds or updates a named color to w32-color-map, making it
1096 available for use. The original entry's RGB ref is returned, or nil
1097 if the entry is new. */)
1098 (red, green, blue, name)
1099 Lisp_Object red, green, blue, name;
1100 {
1101 Lisp_Object rgb;
1102 Lisp_Object oldrgb = Qnil;
1103 Lisp_Object entry;
1104
1105 CHECK_NUMBER (red);
1106 CHECK_NUMBER (green);
1107 CHECK_NUMBER (blue);
1108 CHECK_STRING (name);
1109
1110 XSET (rgb, Lisp_Int, RGB(XUINT (red), XUINT (green), XUINT (blue)));
1111
1112 BLOCK_INPUT;
1113
1114 /* replace existing entry in w32-color-map or add new entry. */
1115 entry = Fassoc (name, Vw32_color_map);
1116 if (NILP (entry))
1117 {
1118 entry = Fcons (name, rgb);
1119 Vw32_color_map = Fcons (entry, Vw32_color_map);
1120 }
1121 else
1122 {
1123 oldrgb = Fcdr (entry);
1124 Fsetcdr (entry, rgb);
1125 }
1126
1127 UNBLOCK_INPUT;
1128
1129 return (oldrgb);
1130 }
1131
1132 DEFUN ("w32-load-color-file", Fw32_load_color_file,
1133 Sw32_load_color_file, 1, 1, 0,
1134 doc: /* Create an alist of color entries from an external file.
1135 Assign this value to w32-color-map to replace the existing color map.
1136
1137 The file should define one named RGB color per line like so:
1138 R G B name
1139 where R,G,B are numbers between 0 and 255 and name is an arbitrary string. */)
1140 (filename)
1141 Lisp_Object filename;
1142 {
1143 FILE *fp;
1144 Lisp_Object cmap = Qnil;
1145 Lisp_Object abspath;
1146
1147 CHECK_STRING (filename);
1148 abspath = Fexpand_file_name (filename, Qnil);
1149
1150 fp = fopen (XSTRING (filename)->data, "rt");
1151 if (fp)
1152 {
1153 char buf[512];
1154 int red, green, blue;
1155 int num;
1156
1157 BLOCK_INPUT;
1158
1159 while (fgets (buf, sizeof (buf), fp) != NULL) {
1160 if (sscanf (buf, "%u %u %u %n", &red, &green, &blue, &num) == 3)
1161 {
1162 char *name = buf + num;
1163 num = strlen (name) - 1;
1164 if (name[num] == '\n')
1165 name[num] = 0;
1166 cmap = Fcons (Fcons (build_string (name),
1167 make_number (RGB (red, green, blue))),
1168 cmap);
1169 }
1170 }
1171 fclose (fp);
1172
1173 UNBLOCK_INPUT;
1174 }
1175
1176 return cmap;
1177 }
1178
1179 /* The default colors for the w32 color map */
1180 typedef struct colormap_t
1181 {
1182 char *name;
1183 COLORREF colorref;
1184 } colormap_t;
1185
1186 colormap_t w32_color_map[] =
1187 {
1188 {"snow" , PALETTERGB (255,250,250)},
1189 {"ghost white" , PALETTERGB (248,248,255)},
1190 {"GhostWhite" , PALETTERGB (248,248,255)},
1191 {"white smoke" , PALETTERGB (245,245,245)},
1192 {"WhiteSmoke" , PALETTERGB (245,245,245)},
1193 {"gainsboro" , PALETTERGB (220,220,220)},
1194 {"floral white" , PALETTERGB (255,250,240)},
1195 {"FloralWhite" , PALETTERGB (255,250,240)},
1196 {"old lace" , PALETTERGB (253,245,230)},
1197 {"OldLace" , PALETTERGB (253,245,230)},
1198 {"linen" , PALETTERGB (250,240,230)},
1199 {"antique white" , PALETTERGB (250,235,215)},
1200 {"AntiqueWhite" , PALETTERGB (250,235,215)},
1201 {"papaya whip" , PALETTERGB (255,239,213)},
1202 {"PapayaWhip" , PALETTERGB (255,239,213)},
1203 {"blanched almond" , PALETTERGB (255,235,205)},
1204 {"BlanchedAlmond" , PALETTERGB (255,235,205)},
1205 {"bisque" , PALETTERGB (255,228,196)},
1206 {"peach puff" , PALETTERGB (255,218,185)},
1207 {"PeachPuff" , PALETTERGB (255,218,185)},
1208 {"navajo white" , PALETTERGB (255,222,173)},
1209 {"NavajoWhite" , PALETTERGB (255,222,173)},
1210 {"moccasin" , PALETTERGB (255,228,181)},
1211 {"cornsilk" , PALETTERGB (255,248,220)},
1212 {"ivory" , PALETTERGB (255,255,240)},
1213 {"lemon chiffon" , PALETTERGB (255,250,205)},
1214 {"LemonChiffon" , PALETTERGB (255,250,205)},
1215 {"seashell" , PALETTERGB (255,245,238)},
1216 {"honeydew" , PALETTERGB (240,255,240)},
1217 {"mint cream" , PALETTERGB (245,255,250)},
1218 {"MintCream" , PALETTERGB (245,255,250)},
1219 {"azure" , PALETTERGB (240,255,255)},
1220 {"alice blue" , PALETTERGB (240,248,255)},
1221 {"AliceBlue" , PALETTERGB (240,248,255)},
1222 {"lavender" , PALETTERGB (230,230,250)},
1223 {"lavender blush" , PALETTERGB (255,240,245)},
1224 {"LavenderBlush" , PALETTERGB (255,240,245)},
1225 {"misty rose" , PALETTERGB (255,228,225)},
1226 {"MistyRose" , PALETTERGB (255,228,225)},
1227 {"white" , PALETTERGB (255,255,255)},
1228 {"black" , PALETTERGB ( 0, 0, 0)},
1229 {"dark slate gray" , PALETTERGB ( 47, 79, 79)},
1230 {"DarkSlateGray" , PALETTERGB ( 47, 79, 79)},
1231 {"dark slate grey" , PALETTERGB ( 47, 79, 79)},
1232 {"DarkSlateGrey" , PALETTERGB ( 47, 79, 79)},
1233 {"dim gray" , PALETTERGB (105,105,105)},
1234 {"DimGray" , PALETTERGB (105,105,105)},
1235 {"dim grey" , PALETTERGB (105,105,105)},
1236 {"DimGrey" , PALETTERGB (105,105,105)},
1237 {"slate gray" , PALETTERGB (112,128,144)},
1238 {"SlateGray" , PALETTERGB (112,128,144)},
1239 {"slate grey" , PALETTERGB (112,128,144)},
1240 {"SlateGrey" , PALETTERGB (112,128,144)},
1241 {"light slate gray" , PALETTERGB (119,136,153)},
1242 {"LightSlateGray" , PALETTERGB (119,136,153)},
1243 {"light slate grey" , PALETTERGB (119,136,153)},
1244 {"LightSlateGrey" , PALETTERGB (119,136,153)},
1245 {"gray" , PALETTERGB (190,190,190)},
1246 {"grey" , PALETTERGB (190,190,190)},
1247 {"light grey" , PALETTERGB (211,211,211)},
1248 {"LightGrey" , PALETTERGB (211,211,211)},
1249 {"light gray" , PALETTERGB (211,211,211)},
1250 {"LightGray" , PALETTERGB (211,211,211)},
1251 {"midnight blue" , PALETTERGB ( 25, 25,112)},
1252 {"MidnightBlue" , PALETTERGB ( 25, 25,112)},
1253 {"navy" , PALETTERGB ( 0, 0,128)},
1254 {"navy blue" , PALETTERGB ( 0, 0,128)},
1255 {"NavyBlue" , PALETTERGB ( 0, 0,128)},
1256 {"cornflower blue" , PALETTERGB (100,149,237)},
1257 {"CornflowerBlue" , PALETTERGB (100,149,237)},
1258 {"dark slate blue" , PALETTERGB ( 72, 61,139)},
1259 {"DarkSlateBlue" , PALETTERGB ( 72, 61,139)},
1260 {"slate blue" , PALETTERGB (106, 90,205)},
1261 {"SlateBlue" , PALETTERGB (106, 90,205)},
1262 {"medium slate blue" , PALETTERGB (123,104,238)},
1263 {"MediumSlateBlue" , PALETTERGB (123,104,238)},
1264 {"light slate blue" , PALETTERGB (132,112,255)},
1265 {"LightSlateBlue" , PALETTERGB (132,112,255)},
1266 {"medium blue" , PALETTERGB ( 0, 0,205)},
1267 {"MediumBlue" , PALETTERGB ( 0, 0,205)},
1268 {"royal blue" , PALETTERGB ( 65,105,225)},
1269 {"RoyalBlue" , PALETTERGB ( 65,105,225)},
1270 {"blue" , PALETTERGB ( 0, 0,255)},
1271 {"dodger blue" , PALETTERGB ( 30,144,255)},
1272 {"DodgerBlue" , PALETTERGB ( 30,144,255)},
1273 {"deep sky blue" , PALETTERGB ( 0,191,255)},
1274 {"DeepSkyBlue" , PALETTERGB ( 0,191,255)},
1275 {"sky blue" , PALETTERGB (135,206,235)},
1276 {"SkyBlue" , PALETTERGB (135,206,235)},
1277 {"light sky blue" , PALETTERGB (135,206,250)},
1278 {"LightSkyBlue" , PALETTERGB (135,206,250)},
1279 {"steel blue" , PALETTERGB ( 70,130,180)},
1280 {"SteelBlue" , PALETTERGB ( 70,130,180)},
1281 {"light steel blue" , PALETTERGB (176,196,222)},
1282 {"LightSteelBlue" , PALETTERGB (176,196,222)},
1283 {"light blue" , PALETTERGB (173,216,230)},
1284 {"LightBlue" , PALETTERGB (173,216,230)},
1285 {"powder blue" , PALETTERGB (176,224,230)},
1286 {"PowderBlue" , PALETTERGB (176,224,230)},
1287 {"pale turquoise" , PALETTERGB (175,238,238)},
1288 {"PaleTurquoise" , PALETTERGB (175,238,238)},
1289 {"dark turquoise" , PALETTERGB ( 0,206,209)},
1290 {"DarkTurquoise" , PALETTERGB ( 0,206,209)},
1291 {"medium turquoise" , PALETTERGB ( 72,209,204)},
1292 {"MediumTurquoise" , PALETTERGB ( 72,209,204)},
1293 {"turquoise" , PALETTERGB ( 64,224,208)},
1294 {"cyan" , PALETTERGB ( 0,255,255)},
1295 {"light cyan" , PALETTERGB (224,255,255)},
1296 {"LightCyan" , PALETTERGB (224,255,255)},
1297 {"cadet blue" , PALETTERGB ( 95,158,160)},
1298 {"CadetBlue" , PALETTERGB ( 95,158,160)},
1299 {"medium aquamarine" , PALETTERGB (102,205,170)},
1300 {"MediumAquamarine" , PALETTERGB (102,205,170)},
1301 {"aquamarine" , PALETTERGB (127,255,212)},
1302 {"dark green" , PALETTERGB ( 0,100, 0)},
1303 {"DarkGreen" , PALETTERGB ( 0,100, 0)},
1304 {"dark olive green" , PALETTERGB ( 85,107, 47)},
1305 {"DarkOliveGreen" , PALETTERGB ( 85,107, 47)},
1306 {"dark sea green" , PALETTERGB (143,188,143)},
1307 {"DarkSeaGreen" , PALETTERGB (143,188,143)},
1308 {"sea green" , PALETTERGB ( 46,139, 87)},
1309 {"SeaGreen" , PALETTERGB ( 46,139, 87)},
1310 {"medium sea green" , PALETTERGB ( 60,179,113)},
1311 {"MediumSeaGreen" , PALETTERGB ( 60,179,113)},
1312 {"light sea green" , PALETTERGB ( 32,178,170)},
1313 {"LightSeaGreen" , PALETTERGB ( 32,178,170)},
1314 {"pale green" , PALETTERGB (152,251,152)},
1315 {"PaleGreen" , PALETTERGB (152,251,152)},
1316 {"spring green" , PALETTERGB ( 0,255,127)},
1317 {"SpringGreen" , PALETTERGB ( 0,255,127)},
1318 {"lawn green" , PALETTERGB (124,252, 0)},
1319 {"LawnGreen" , PALETTERGB (124,252, 0)},
1320 {"green" , PALETTERGB ( 0,255, 0)},
1321 {"chartreuse" , PALETTERGB (127,255, 0)},
1322 {"medium spring green" , PALETTERGB ( 0,250,154)},
1323 {"MediumSpringGreen" , PALETTERGB ( 0,250,154)},
1324 {"green yellow" , PALETTERGB (173,255, 47)},
1325 {"GreenYellow" , PALETTERGB (173,255, 47)},
1326 {"lime green" , PALETTERGB ( 50,205, 50)},
1327 {"LimeGreen" , PALETTERGB ( 50,205, 50)},
1328 {"yellow green" , PALETTERGB (154,205, 50)},
1329 {"YellowGreen" , PALETTERGB (154,205, 50)},
1330 {"forest green" , PALETTERGB ( 34,139, 34)},
1331 {"ForestGreen" , PALETTERGB ( 34,139, 34)},
1332 {"olive drab" , PALETTERGB (107,142, 35)},
1333 {"OliveDrab" , PALETTERGB (107,142, 35)},
1334 {"dark khaki" , PALETTERGB (189,183,107)},
1335 {"DarkKhaki" , PALETTERGB (189,183,107)},
1336 {"khaki" , PALETTERGB (240,230,140)},
1337 {"pale goldenrod" , PALETTERGB (238,232,170)},
1338 {"PaleGoldenrod" , PALETTERGB (238,232,170)},
1339 {"light goldenrod yellow" , PALETTERGB (250,250,210)},
1340 {"LightGoldenrodYellow" , PALETTERGB (250,250,210)},
1341 {"light yellow" , PALETTERGB (255,255,224)},
1342 {"LightYellow" , PALETTERGB (255,255,224)},
1343 {"yellow" , PALETTERGB (255,255, 0)},
1344 {"gold" , PALETTERGB (255,215, 0)},
1345 {"light goldenrod" , PALETTERGB (238,221,130)},
1346 {"LightGoldenrod" , PALETTERGB (238,221,130)},
1347 {"goldenrod" , PALETTERGB (218,165, 32)},
1348 {"dark goldenrod" , PALETTERGB (184,134, 11)},
1349 {"DarkGoldenrod" , PALETTERGB (184,134, 11)},
1350 {"rosy brown" , PALETTERGB (188,143,143)},
1351 {"RosyBrown" , PALETTERGB (188,143,143)},
1352 {"indian red" , PALETTERGB (205, 92, 92)},
1353 {"IndianRed" , PALETTERGB (205, 92, 92)},
1354 {"saddle brown" , PALETTERGB (139, 69, 19)},
1355 {"SaddleBrown" , PALETTERGB (139, 69, 19)},
1356 {"sienna" , PALETTERGB (160, 82, 45)},
1357 {"peru" , PALETTERGB (205,133, 63)},
1358 {"burlywood" , PALETTERGB (222,184,135)},
1359 {"beige" , PALETTERGB (245,245,220)},
1360 {"wheat" , PALETTERGB (245,222,179)},
1361 {"sandy brown" , PALETTERGB (244,164, 96)},
1362 {"SandyBrown" , PALETTERGB (244,164, 96)},
1363 {"tan" , PALETTERGB (210,180,140)},
1364 {"chocolate" , PALETTERGB (210,105, 30)},
1365 {"firebrick" , PALETTERGB (178,34, 34)},
1366 {"brown" , PALETTERGB (165,42, 42)},
1367 {"dark salmon" , PALETTERGB (233,150,122)},
1368 {"DarkSalmon" , PALETTERGB (233,150,122)},
1369 {"salmon" , PALETTERGB (250,128,114)},
1370 {"light salmon" , PALETTERGB (255,160,122)},
1371 {"LightSalmon" , PALETTERGB (255,160,122)},
1372 {"orange" , PALETTERGB (255,165, 0)},
1373 {"dark orange" , PALETTERGB (255,140, 0)},
1374 {"DarkOrange" , PALETTERGB (255,140, 0)},
1375 {"coral" , PALETTERGB (255,127, 80)},
1376 {"light coral" , PALETTERGB (240,128,128)},
1377 {"LightCoral" , PALETTERGB (240,128,128)},
1378 {"tomato" , PALETTERGB (255, 99, 71)},
1379 {"orange red" , PALETTERGB (255, 69, 0)},
1380 {"OrangeRed" , PALETTERGB (255, 69, 0)},
1381 {"red" , PALETTERGB (255, 0, 0)},
1382 {"hot pink" , PALETTERGB (255,105,180)},
1383 {"HotPink" , PALETTERGB (255,105,180)},
1384 {"deep pink" , PALETTERGB (255, 20,147)},
1385 {"DeepPink" , PALETTERGB (255, 20,147)},
1386 {"pink" , PALETTERGB (255,192,203)},
1387 {"light pink" , PALETTERGB (255,182,193)},
1388 {"LightPink" , PALETTERGB (255,182,193)},
1389 {"pale violet red" , PALETTERGB (219,112,147)},
1390 {"PaleVioletRed" , PALETTERGB (219,112,147)},
1391 {"maroon" , PALETTERGB (176, 48, 96)},
1392 {"medium violet red" , PALETTERGB (199, 21,133)},
1393 {"MediumVioletRed" , PALETTERGB (199, 21,133)},
1394 {"violet red" , PALETTERGB (208, 32,144)},
1395 {"VioletRed" , PALETTERGB (208, 32,144)},
1396 {"magenta" , PALETTERGB (255, 0,255)},
1397 {"violet" , PALETTERGB (238,130,238)},
1398 {"plum" , PALETTERGB (221,160,221)},
1399 {"orchid" , PALETTERGB (218,112,214)},
1400 {"medium orchid" , PALETTERGB (186, 85,211)},
1401 {"MediumOrchid" , PALETTERGB (186, 85,211)},
1402 {"dark orchid" , PALETTERGB (153, 50,204)},
1403 {"DarkOrchid" , PALETTERGB (153, 50,204)},
1404 {"dark violet" , PALETTERGB (148, 0,211)},
1405 {"DarkViolet" , PALETTERGB (148, 0,211)},
1406 {"blue violet" , PALETTERGB (138, 43,226)},
1407 {"BlueViolet" , PALETTERGB (138, 43,226)},
1408 {"purple" , PALETTERGB (160, 32,240)},
1409 {"medium purple" , PALETTERGB (147,112,219)},
1410 {"MediumPurple" , PALETTERGB (147,112,219)},
1411 {"thistle" , PALETTERGB (216,191,216)},
1412 {"gray0" , PALETTERGB ( 0, 0, 0)},
1413 {"grey0" , PALETTERGB ( 0, 0, 0)},
1414 {"dark grey" , PALETTERGB (169,169,169)},
1415 {"DarkGrey" , PALETTERGB (169,169,169)},
1416 {"dark gray" , PALETTERGB (169,169,169)},
1417 {"DarkGray" , PALETTERGB (169,169,169)},
1418 {"dark blue" , PALETTERGB ( 0, 0,139)},
1419 {"DarkBlue" , PALETTERGB ( 0, 0,139)},
1420 {"dark cyan" , PALETTERGB ( 0,139,139)},
1421 {"DarkCyan" , PALETTERGB ( 0,139,139)},
1422 {"dark magenta" , PALETTERGB (139, 0,139)},
1423 {"DarkMagenta" , PALETTERGB (139, 0,139)},
1424 {"dark red" , PALETTERGB (139, 0, 0)},
1425 {"DarkRed" , PALETTERGB (139, 0, 0)},
1426 {"light green" , PALETTERGB (144,238,144)},
1427 {"LightGreen" , PALETTERGB (144,238,144)},
1428 };
1429
1430 DEFUN ("w32-default-color-map", Fw32_default_color_map, Sw32_default_color_map,
1431 0, 0, 0, doc: /* Return the default color map. */)
1432 ()
1433 {
1434 int i;
1435 colormap_t *pc = w32_color_map;
1436 Lisp_Object cmap;
1437
1438 BLOCK_INPUT;
1439
1440 cmap = Qnil;
1441
1442 for (i = 0; i < sizeof (w32_color_map) / sizeof (w32_color_map[0]);
1443 pc++, i++)
1444 cmap = Fcons (Fcons (build_string (pc->name),
1445 make_number (pc->colorref)),
1446 cmap);
1447
1448 UNBLOCK_INPUT;
1449
1450 return (cmap);
1451 }
1452
1453 Lisp_Object
1454 w32_to_x_color (rgb)
1455 Lisp_Object rgb;
1456 {
1457 Lisp_Object color;
1458
1459 CHECK_NUMBER (rgb);
1460
1461 BLOCK_INPUT;
1462
1463 color = Frassq (rgb, Vw32_color_map);
1464
1465 UNBLOCK_INPUT;
1466
1467 if (!NILP (color))
1468 return (Fcar (color));
1469 else
1470 return Qnil;
1471 }
1472
1473 COLORREF
1474 w32_color_map_lookup (colorname)
1475 char *colorname;
1476 {
1477 Lisp_Object tail, ret = Qnil;
1478
1479 BLOCK_INPUT;
1480
1481 for (tail = Vw32_color_map; !NILP (tail); tail = Fcdr (tail))
1482 {
1483 register Lisp_Object elt, tem;
1484
1485 elt = Fcar (tail);
1486 if (!CONSP (elt)) continue;
1487
1488 tem = Fcar (elt);
1489
1490 if (lstrcmpi (XSTRING (tem)->data, colorname) == 0)
1491 {
1492 ret = XUINT (Fcdr (elt));
1493 break;
1494 }
1495
1496 QUIT;
1497 }
1498
1499
1500 UNBLOCK_INPUT;
1501
1502 return ret;
1503 }
1504
1505 COLORREF
1506 x_to_w32_color (colorname)
1507 char * colorname;
1508 {
1509 register Lisp_Object ret = Qnil;
1510
1511 BLOCK_INPUT;
1512
1513 if (colorname[0] == '#')
1514 {
1515 /* Could be an old-style RGB Device specification. */
1516 char *color;
1517 int size;
1518 color = colorname + 1;
1519
1520 size = strlen(color);
1521 if (size == 3 || size == 6 || size == 9 || size == 12)
1522 {
1523 UINT colorval;
1524 int i, pos;
1525 pos = 0;
1526 size /= 3;
1527 colorval = 0;
1528
1529 for (i = 0; i < 3; i++)
1530 {
1531 char *end;
1532 char t;
1533 unsigned long value;
1534
1535 /* The check for 'x' in the following conditional takes into
1536 account the fact that strtol allows a "0x" in front of
1537 our numbers, and we don't. */
1538 if (!isxdigit(color[0]) || color[1] == 'x')
1539 break;
1540 t = color[size];
1541 color[size] = '\0';
1542 value = strtoul(color, &end, 16);
1543 color[size] = t;
1544 if (errno == ERANGE || end - color != size)
1545 break;
1546 switch (size)
1547 {
1548 case 1:
1549 value = value * 0x10;
1550 break;
1551 case 2:
1552 break;
1553 case 3:
1554 value /= 0x10;
1555 break;
1556 case 4:
1557 value /= 0x100;
1558 break;
1559 }
1560 colorval |= (value << pos);
1561 pos += 0x8;
1562 if (i == 2)
1563 {
1564 UNBLOCK_INPUT;
1565 return (colorval);
1566 }
1567 color = end;
1568 }
1569 }
1570 }
1571 else if (strnicmp(colorname, "rgb:", 4) == 0)
1572 {
1573 char *color;
1574 UINT colorval;
1575 int i, pos;
1576 pos = 0;
1577
1578 colorval = 0;
1579 color = colorname + 4;
1580 for (i = 0; i < 3; i++)
1581 {
1582 char *end;
1583 unsigned long value;
1584
1585 /* The check for 'x' in the following conditional takes into
1586 account the fact that strtol allows a "0x" in front of
1587 our numbers, and we don't. */
1588 if (!isxdigit(color[0]) || color[1] == 'x')
1589 break;
1590 value = strtoul(color, &end, 16);
1591 if (errno == ERANGE)
1592 break;
1593 switch (end - color)
1594 {
1595 case 1:
1596 value = value * 0x10 + value;
1597 break;
1598 case 2:
1599 break;
1600 case 3:
1601 value /= 0x10;
1602 break;
1603 case 4:
1604 value /= 0x100;
1605 break;
1606 default:
1607 value = ULONG_MAX;
1608 }
1609 if (value == ULONG_MAX)
1610 break;
1611 colorval |= (value << pos);
1612 pos += 0x8;
1613 if (i == 2)
1614 {
1615 if (*end != '\0')
1616 break;
1617 UNBLOCK_INPUT;
1618 return (colorval);
1619 }
1620 if (*end != '/')
1621 break;
1622 color = end + 1;
1623 }
1624 }
1625 else if (strnicmp(colorname, "rgbi:", 5) == 0)
1626 {
1627 /* This is an RGB Intensity specification. */
1628 char *color;
1629 UINT colorval;
1630 int i, pos;
1631 pos = 0;
1632
1633 colorval = 0;
1634 color = colorname + 5;
1635 for (i = 0; i < 3; i++)
1636 {
1637 char *end;
1638 double value;
1639 UINT val;
1640
1641 value = strtod(color, &end);
1642 if (errno == ERANGE)
1643 break;
1644 if (value < 0.0 || value > 1.0)
1645 break;
1646 val = (UINT)(0x100 * value);
1647 /* We used 0x100 instead of 0xFF to give an continuous
1648 range between 0.0 and 1.0 inclusive. The next statement
1649 fixes the 1.0 case. */
1650 if (val == 0x100)
1651 val = 0xFF;
1652 colorval |= (val << pos);
1653 pos += 0x8;
1654 if (i == 2)
1655 {
1656 if (*end != '\0')
1657 break;
1658 UNBLOCK_INPUT;
1659 return (colorval);
1660 }
1661 if (*end != '/')
1662 break;
1663 color = end + 1;
1664 }
1665 }
1666 /* I am not going to attempt to handle any of the CIE color schemes
1667 or TekHVC, since I don't know the algorithms for conversion to
1668 RGB. */
1669
1670 /* If we fail to lookup the color name in w32_color_map, then check the
1671 colorname to see if it can be crudely approximated: If the X color
1672 ends in a number (e.g., "darkseagreen2"), strip the number and
1673 return the result of looking up the base color name. */
1674 ret = w32_color_map_lookup (colorname);
1675 if (NILP (ret))
1676 {
1677 int len = strlen (colorname);
1678
1679 if (isdigit (colorname[len - 1]))
1680 {
1681 char *ptr, *approx = alloca (len + 1);
1682
1683 strcpy (approx, colorname);
1684 ptr = &approx[len - 1];
1685 while (ptr > approx && isdigit (*ptr))
1686 *ptr-- = '\0';
1687
1688 ret = w32_color_map_lookup (approx);
1689 }
1690 }
1691
1692 UNBLOCK_INPUT;
1693 return ret;
1694 }
1695
1696
1697 void
1698 w32_regenerate_palette (FRAME_PTR f)
1699 {
1700 struct w32_palette_entry * list;
1701 LOGPALETTE * log_palette;
1702 HPALETTE new_palette;
1703 int i;
1704
1705 /* don't bother trying to create palette if not supported */
1706 if (! FRAME_W32_DISPLAY_INFO (f)->has_palette)
1707 return;
1708
1709 log_palette = (LOGPALETTE *)
1710 alloca (sizeof (LOGPALETTE) +
1711 FRAME_W32_DISPLAY_INFO (f)->num_colors * sizeof (PALETTEENTRY));
1712 log_palette->palVersion = 0x300;
1713 log_palette->palNumEntries = FRAME_W32_DISPLAY_INFO (f)->num_colors;
1714
1715 list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1716 for (i = 0;
1717 i < FRAME_W32_DISPLAY_INFO (f)->num_colors;
1718 i++, list = list->next)
1719 log_palette->palPalEntry[i] = list->entry;
1720
1721 new_palette = CreatePalette (log_palette);
1722
1723 enter_crit ();
1724
1725 if (FRAME_W32_DISPLAY_INFO (f)->palette)
1726 DeleteObject (FRAME_W32_DISPLAY_INFO (f)->palette);
1727 FRAME_W32_DISPLAY_INFO (f)->palette = new_palette;
1728
1729 /* Realize display palette and garbage all frames. */
1730 release_frame_dc (f, get_frame_dc (f));
1731
1732 leave_crit ();
1733 }
1734
1735 #define W32_COLOR(pe) RGB (pe.peRed, pe.peGreen, pe.peBlue)
1736 #define SET_W32_COLOR(pe, color) \
1737 do \
1738 { \
1739 pe.peRed = GetRValue (color); \
1740 pe.peGreen = GetGValue (color); \
1741 pe.peBlue = GetBValue (color); \
1742 pe.peFlags = 0; \
1743 } while (0)
1744
1745 #if 0
1746 /* Keep these around in case we ever want to track color usage. */
1747 void
1748 w32_map_color (FRAME_PTR f, COLORREF color)
1749 {
1750 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1751
1752 if (NILP (Vw32_enable_palette))
1753 return;
1754
1755 /* check if color is already mapped */
1756 while (list)
1757 {
1758 if (W32_COLOR (list->entry) == color)
1759 {
1760 ++list->refcount;
1761 return;
1762 }
1763 list = list->next;
1764 }
1765
1766 /* not already mapped, so add to list and recreate Windows palette */
1767 list = (struct w32_palette_entry *)
1768 xmalloc (sizeof (struct w32_palette_entry));
1769 SET_W32_COLOR (list->entry, color);
1770 list->refcount = 1;
1771 list->next = FRAME_W32_DISPLAY_INFO (f)->color_list;
1772 FRAME_W32_DISPLAY_INFO (f)->color_list = list;
1773 FRAME_W32_DISPLAY_INFO (f)->num_colors++;
1774
1775 /* set flag that palette must be regenerated */
1776 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
1777 }
1778
1779 void
1780 w32_unmap_color (FRAME_PTR f, COLORREF color)
1781 {
1782 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1783 struct w32_palette_entry **prev = &FRAME_W32_DISPLAY_INFO (f)->color_list;
1784
1785 if (NILP (Vw32_enable_palette))
1786 return;
1787
1788 /* check if color is already mapped */
1789 while (list)
1790 {
1791 if (W32_COLOR (list->entry) == color)
1792 {
1793 if (--list->refcount == 0)
1794 {
1795 *prev = list->next;
1796 xfree (list);
1797 FRAME_W32_DISPLAY_INFO (f)->num_colors--;
1798 break;
1799 }
1800 else
1801 return;
1802 }
1803 prev = &list->next;
1804 list = list->next;
1805 }
1806
1807 /* set flag that palette must be regenerated */
1808 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
1809 }
1810 #endif
1811
1812
1813 /* Gamma-correct COLOR on frame F. */
1814
1815 void
1816 gamma_correct (f, color)
1817 struct frame *f;
1818 COLORREF *color;
1819 {
1820 if (f->gamma)
1821 {
1822 *color = PALETTERGB (
1823 pow (GetRValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1824 pow (GetGValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1825 pow (GetBValue (*color) / 255.0, f->gamma) * 255.0 + 0.5);
1826 }
1827 }
1828
1829
1830 /* Decide if color named COLOR is valid for the display associated with
1831 the selected frame; if so, return the rgb values in COLOR_DEF.
1832 If ALLOC is nonzero, allocate a new colormap cell. */
1833
1834 int
1835 w32_defined_color (f, color, color_def, alloc)
1836 FRAME_PTR f;
1837 char *color;
1838 XColor *color_def;
1839 int alloc;
1840 {
1841 register Lisp_Object tem;
1842 COLORREF w32_color_ref;
1843
1844 tem = x_to_w32_color (color);
1845
1846 if (!NILP (tem))
1847 {
1848 if (f)
1849 {
1850 /* Apply gamma correction. */
1851 w32_color_ref = XUINT (tem);
1852 gamma_correct (f, &w32_color_ref);
1853 XSETINT (tem, w32_color_ref);
1854 }
1855
1856 /* Map this color to the palette if it is enabled. */
1857 if (!NILP (Vw32_enable_palette))
1858 {
1859 struct w32_palette_entry * entry =
1860 one_w32_display_info.color_list;
1861 struct w32_palette_entry ** prev =
1862 &one_w32_display_info.color_list;
1863
1864 /* check if color is already mapped */
1865 while (entry)
1866 {
1867 if (W32_COLOR (entry->entry) == XUINT (tem))
1868 break;
1869 prev = &entry->next;
1870 entry = entry->next;
1871 }
1872
1873 if (entry == NULL && alloc)
1874 {
1875 /* not already mapped, so add to list */
1876 entry = (struct w32_palette_entry *)
1877 xmalloc (sizeof (struct w32_palette_entry));
1878 SET_W32_COLOR (entry->entry, XUINT (tem));
1879 entry->next = NULL;
1880 *prev = entry;
1881 one_w32_display_info.num_colors++;
1882
1883 /* set flag that palette must be regenerated */
1884 one_w32_display_info.regen_palette = TRUE;
1885 }
1886 }
1887 /* Ensure COLORREF value is snapped to nearest color in (default)
1888 palette by simulating the PALETTERGB macro. This works whether
1889 or not the display device has a palette. */
1890 w32_color_ref = XUINT (tem) | 0x2000000;
1891
1892 color_def->pixel = w32_color_ref;
1893 color_def->red = GetRValue (w32_color_ref);
1894 color_def->green = GetGValue (w32_color_ref);
1895 color_def->blue = GetBValue (w32_color_ref);
1896
1897 return 1;
1898 }
1899 else
1900 {
1901 return 0;
1902 }
1903 }
1904
1905 /* Given a string ARG naming a color, compute a pixel value from it
1906 suitable for screen F.
1907 If F is not a color screen, return DEF (default) regardless of what
1908 ARG says. */
1909
1910 int
1911 x_decode_color (f, arg, def)
1912 FRAME_PTR f;
1913 Lisp_Object arg;
1914 int def;
1915 {
1916 XColor cdef;
1917
1918 CHECK_STRING (arg);
1919
1920 if (strcmp (XSTRING (arg)->data, "black") == 0)
1921 return BLACK_PIX_DEFAULT (f);
1922 else if (strcmp (XSTRING (arg)->data, "white") == 0)
1923 return WHITE_PIX_DEFAULT (f);
1924
1925 if ((FRAME_W32_DISPLAY_INFO (f)->n_planes * FRAME_W32_DISPLAY_INFO (f)->n_cbits) == 1)
1926 return def;
1927
1928 /* w32_defined_color is responsible for coping with failures
1929 by looking for a near-miss. */
1930 if (w32_defined_color (f, XSTRING (arg)->data, &cdef, 1))
1931 return cdef.pixel;
1932
1933 /* defined_color failed; return an ultimate default. */
1934 return def;
1935 }
1936 \f
1937 /* Change the `line-spacing' frame parameter of frame F. OLD_VALUE is
1938 the previous value of that parameter, NEW_VALUE is the new value. */
1939
1940 static void
1941 x_set_line_spacing (f, new_value, old_value)
1942 struct frame *f;
1943 Lisp_Object new_value, old_value;
1944 {
1945 if (NILP (new_value))
1946 f->extra_line_spacing = 0;
1947 else if (NATNUMP (new_value))
1948 f->extra_line_spacing = XFASTINT (new_value);
1949 else
1950 Fsignal (Qerror, Fcons (build_string ("Invalid line-spacing"),
1951 Fcons (new_value, Qnil)));
1952 if (FRAME_VISIBLE_P (f))
1953 redraw_frame (f);
1954 }
1955
1956
1957 /* Change the `screen-gamma' frame parameter of frame F. OLD_VALUE is
1958 the previous value of that parameter, NEW_VALUE is the new value. */
1959
1960 static void
1961 x_set_screen_gamma (f, new_value, old_value)
1962 struct frame *f;
1963 Lisp_Object new_value, old_value;
1964 {
1965 if (NILP (new_value))
1966 f->gamma = 0;
1967 else if (NUMBERP (new_value) && XFLOATINT (new_value) > 0)
1968 /* The value 0.4545 is the normal viewing gamma. */
1969 f->gamma = 1.0 / (0.4545 * XFLOATINT (new_value));
1970 else
1971 Fsignal (Qerror, Fcons (build_string ("Invalid screen-gamma"),
1972 Fcons (new_value, Qnil)));
1973
1974 clear_face_cache (0);
1975 }
1976
1977
1978 /* Functions called only from `x_set_frame_param'
1979 to set individual parameters.
1980
1981 If FRAME_W32_WINDOW (f) is 0,
1982 the frame is being created and its window does not exist yet.
1983 In that case, just record the parameter's new value
1984 in the standard place; do not attempt to change the window. */
1985
1986 void
1987 x_set_foreground_color (f, arg, oldval)
1988 struct frame *f;
1989 Lisp_Object arg, oldval;
1990 {
1991 struct w32_output *x = f->output_data.w32;
1992 PIX_TYPE fg, old_fg;
1993
1994 fg = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
1995 old_fg = FRAME_FOREGROUND_PIXEL (f);
1996 FRAME_FOREGROUND_PIXEL (f) = fg;
1997
1998 if (FRAME_W32_WINDOW (f) != 0)
1999 {
2000 if (x->cursor_pixel == old_fg)
2001 x->cursor_pixel = fg;
2002
2003 update_face_from_frame_parameter (f, Qforeground_color, arg);
2004 if (FRAME_VISIBLE_P (f))
2005 redraw_frame (f);
2006 }
2007 }
2008
2009 void
2010 x_set_background_color (f, arg, oldval)
2011 struct frame *f;
2012 Lisp_Object arg, oldval;
2013 {
2014 FRAME_BACKGROUND_PIXEL (f)
2015 = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
2016
2017 if (FRAME_W32_WINDOW (f) != 0)
2018 {
2019 SetWindowLong (FRAME_W32_WINDOW (f), WND_BACKGROUND_INDEX,
2020 FRAME_BACKGROUND_PIXEL (f));
2021
2022 update_face_from_frame_parameter (f, Qbackground_color, arg);
2023
2024 if (FRAME_VISIBLE_P (f))
2025 redraw_frame (f);
2026 }
2027 }
2028
2029 void
2030 x_set_mouse_color (f, arg, oldval)
2031 struct frame *f;
2032 Lisp_Object arg, oldval;
2033 {
2034 Cursor cursor, nontext_cursor, mode_cursor, cross_cursor;
2035 int count;
2036 int mask_color;
2037
2038 if (!EQ (Qnil, arg))
2039 f->output_data.w32->mouse_pixel
2040 = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2041 mask_color = FRAME_BACKGROUND_PIXEL (f);
2042
2043 /* Don't let pointers be invisible. */
2044 if (mask_color == f->output_data.w32->mouse_pixel
2045 && mask_color == FRAME_BACKGROUND_PIXEL (f))
2046 f->output_data.w32->mouse_pixel = FRAME_FOREGROUND_PIXEL (f);
2047
2048 #if 0 /* TODO : cursor changes */
2049 BLOCK_INPUT;
2050
2051 /* It's not okay to crash if the user selects a screwy cursor. */
2052 count = x_catch_errors (FRAME_W32_DISPLAY (f));
2053
2054 if (!EQ (Qnil, Vx_pointer_shape))
2055 {
2056 CHECK_NUMBER (Vx_pointer_shape);
2057 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XINT (Vx_pointer_shape));
2058 }
2059 else
2060 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2061 x_check_errors (FRAME_W32_DISPLAY (f), "bad text pointer cursor: %s");
2062
2063 if (!EQ (Qnil, Vx_nontext_pointer_shape))
2064 {
2065 CHECK_NUMBER (Vx_nontext_pointer_shape);
2066 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2067 XINT (Vx_nontext_pointer_shape));
2068 }
2069 else
2070 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_left_ptr);
2071 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
2072
2073 if (!EQ (Qnil, Vx_hourglass_pointer_shape))
2074 {
2075 CHECK_NUMBER (Vx_hourglass_pointer_shape);
2076 hourglass_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2077 XINT (Vx_hourglass_pointer_shape));
2078 }
2079 else
2080 hourglass_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_watch);
2081 x_check_errors (FRAME_W32_DISPLAY (f), "bad busy pointer cursor: %s");
2082
2083 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
2084 if (!EQ (Qnil, Vx_mode_pointer_shape))
2085 {
2086 CHECK_NUMBER (Vx_mode_pointer_shape);
2087 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2088 XINT (Vx_mode_pointer_shape));
2089 }
2090 else
2091 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2092 x_check_errors (FRAME_W32_DISPLAY (f), "bad modeline pointer cursor: %s");
2093
2094 if (!EQ (Qnil, Vx_sensitive_text_pointer_shape))
2095 {
2096 CHECK_NUMBER (Vx_sensitive_text_pointer_shape);
2097 cross_cursor
2098 = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2099 XINT (Vx_sensitive_text_pointer_shape));
2100 }
2101 else
2102 cross_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_crosshair);
2103
2104 if (!NILP (Vx_window_horizontal_drag_shape))
2105 {
2106 CHECK_NUMBER (Vx_window_horizontal_drag_shape);
2107 horizontal_drag_cursor
2108 = XCreateFontCursor (FRAME_X_DISPLAY (f),
2109 XINT (Vx_window_horizontal_drag_shape));
2110 }
2111 else
2112 horizontal_drag_cursor
2113 = XCreateFontCursor (FRAME_X_DISPLAY (f), XC_sb_h_double_arrow);
2114
2115 /* Check and report errors with the above calls. */
2116 x_check_errors (FRAME_W32_DISPLAY (f), "can't set cursor shape: %s");
2117 x_uncatch_errors (FRAME_W32_DISPLAY (f), count);
2118
2119 {
2120 XColor fore_color, back_color;
2121
2122 fore_color.pixel = f->output_data.w32->mouse_pixel;
2123 back_color.pixel = mask_color;
2124 XQueryColor (FRAME_W32_DISPLAY (f),
2125 DefaultColormap (FRAME_W32_DISPLAY (f),
2126 DefaultScreen (FRAME_W32_DISPLAY (f))),
2127 &fore_color);
2128 XQueryColor (FRAME_W32_DISPLAY (f),
2129 DefaultColormap (FRAME_W32_DISPLAY (f),
2130 DefaultScreen (FRAME_W32_DISPLAY (f))),
2131 &back_color);
2132 XRecolorCursor (FRAME_W32_DISPLAY (f), cursor,
2133 &fore_color, &back_color);
2134 XRecolorCursor (FRAME_W32_DISPLAY (f), nontext_cursor,
2135 &fore_color, &back_color);
2136 XRecolorCursor (FRAME_W32_DISPLAY (f), mode_cursor,
2137 &fore_color, &back_color);
2138 XRecolorCursor (FRAME_W32_DISPLAY (f), cross_cursor,
2139 &fore_color, &back_color);
2140 XRecolorCursor (FRAME_W32_DISPLAY (f), hourglass_cursor,
2141 &fore_color, &back_color);
2142 }
2143
2144 if (FRAME_W32_WINDOW (f) != 0)
2145 XDefineCursor (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), cursor);
2146
2147 if (cursor != f->output_data.w32->text_cursor && f->output_data.w32->text_cursor != 0)
2148 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->text_cursor);
2149 f->output_data.w32->text_cursor = cursor;
2150
2151 if (nontext_cursor != f->output_data.w32->nontext_cursor
2152 && f->output_data.w32->nontext_cursor != 0)
2153 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->nontext_cursor);
2154 f->output_data.w32->nontext_cursor = nontext_cursor;
2155
2156 if (hourglass_cursor != f->output_data.w32->hourglass_cursor
2157 && f->output_data.w32->hourglass_cursor != 0)
2158 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->hourglass_cursor);
2159 f->output_data.w32->hourglass_cursor = hourglass_cursor;
2160
2161 if (mode_cursor != f->output_data.w32->modeline_cursor
2162 && f->output_data.w32->modeline_cursor != 0)
2163 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->modeline_cursor);
2164 f->output_data.w32->modeline_cursor = mode_cursor;
2165
2166 if (cross_cursor != f->output_data.w32->cross_cursor
2167 && f->output_data.w32->cross_cursor != 0)
2168 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->cross_cursor);
2169 f->output_data.w32->cross_cursor = cross_cursor;
2170
2171 XFlush (FRAME_W32_DISPLAY (f));
2172 UNBLOCK_INPUT;
2173
2174 update_face_from_frame_parameter (f, Qmouse_color, arg);
2175 #endif /* TODO */
2176 }
2177
2178 /* Defined in w32term.c. */
2179 void x_update_cursor (struct frame *f, int on_p);
2180
2181 void
2182 x_set_cursor_color (f, arg, oldval)
2183 struct frame *f;
2184 Lisp_Object arg, oldval;
2185 {
2186 unsigned long fore_pixel, pixel;
2187
2188 if (!NILP (Vx_cursor_fore_pixel))
2189 fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel,
2190 WHITE_PIX_DEFAULT (f));
2191 else
2192 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
2193
2194 pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2195
2196 /* Make sure that the cursor color differs from the background color. */
2197 if (pixel == FRAME_BACKGROUND_PIXEL (f))
2198 {
2199 pixel = f->output_data.w32->mouse_pixel;
2200 if (pixel == fore_pixel)
2201 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
2202 }
2203
2204 FRAME_FOREGROUND_PIXEL (f) = fore_pixel;
2205 f->output_data.w32->cursor_pixel = pixel;
2206
2207 if (FRAME_W32_WINDOW (f) != 0)
2208 {
2209 if (FRAME_VISIBLE_P (f))
2210 {
2211 x_update_cursor (f, 0);
2212 x_update_cursor (f, 1);
2213 }
2214 }
2215
2216 update_face_from_frame_parameter (f, Qcursor_color, arg);
2217 }
2218
2219 /* Set the border-color of frame F to pixel value PIX.
2220 Note that this does not fully take effect if done before
2221 F has an window. */
2222 void
2223 x_set_border_pixel (f, pix)
2224 struct frame *f;
2225 int pix;
2226 {
2227 f->output_data.w32->border_pixel = pix;
2228
2229 if (FRAME_W32_WINDOW (f) != 0 && f->output_data.w32->border_width > 0)
2230 {
2231 if (FRAME_VISIBLE_P (f))
2232 redraw_frame (f);
2233 }
2234 }
2235
2236 /* Set the border-color of frame F to value described by ARG.
2237 ARG can be a string naming a color.
2238 The border-color is used for the border that is drawn by the server.
2239 Note that this does not fully take effect if done before
2240 F has a window; it must be redone when the window is created. */
2241
2242 void
2243 x_set_border_color (f, arg, oldval)
2244 struct frame *f;
2245 Lisp_Object arg, oldval;
2246 {
2247 int pix;
2248
2249 CHECK_STRING (arg);
2250 pix = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2251 x_set_border_pixel (f, pix);
2252 update_face_from_frame_parameter (f, Qborder_color, arg);
2253 }
2254
2255 /* Value is the internal representation of the specified cursor type
2256 ARG. If type is BAR_CURSOR, return in *WIDTH the specified width
2257 of the bar cursor. */
2258
2259 enum text_cursor_kinds
2260 x_specified_cursor_type (arg, width)
2261 Lisp_Object arg;
2262 int *width;
2263 {
2264 enum text_cursor_kinds type;
2265
2266 if (EQ (arg, Qbar))
2267 {
2268 type = BAR_CURSOR;
2269 *width = 2;
2270 }
2271 else if (CONSP (arg)
2272 && EQ (XCAR (arg), Qbar)
2273 && INTEGERP (XCDR (arg))
2274 && XINT (XCDR (arg)) >= 0)
2275 {
2276 type = BAR_CURSOR;
2277 *width = XINT (XCDR (arg));
2278 }
2279 else if (NILP (arg))
2280 type = NO_CURSOR;
2281 else
2282 /* Treat anything unknown as "box cursor".
2283 It was bad to signal an error; people have trouble fixing
2284 .Xdefaults with Emacs, when it has something bad in it. */
2285 type = FILLED_BOX_CURSOR;
2286
2287 return type;
2288 }
2289
2290 void
2291 x_set_cursor_type (f, arg, oldval)
2292 FRAME_PTR f;
2293 Lisp_Object arg, oldval;
2294 {
2295 int width;
2296
2297 FRAME_DESIRED_CURSOR (f) = x_specified_cursor_type (arg, &width);
2298 f->output_data.w32->cursor_width = width;
2299
2300 /* Make sure the cursor gets redrawn. This is overkill, but how
2301 often do people change cursor types? */
2302 update_mode_lines++;
2303 }
2304 \f
2305 void
2306 x_set_icon_type (f, arg, oldval)
2307 struct frame *f;
2308 Lisp_Object arg, oldval;
2309 {
2310 int result;
2311
2312 if (NILP (arg) && NILP (oldval))
2313 return;
2314
2315 if (STRINGP (arg) && STRINGP (oldval)
2316 && EQ (Fstring_equal (oldval, arg), Qt))
2317 return;
2318
2319 if (SYMBOLP (arg) && SYMBOLP (oldval) && EQ (arg, oldval))
2320 return;
2321
2322 BLOCK_INPUT;
2323
2324 result = x_bitmap_icon (f, arg);
2325 if (result)
2326 {
2327 UNBLOCK_INPUT;
2328 error ("No icon window available");
2329 }
2330
2331 UNBLOCK_INPUT;
2332 }
2333
2334 /* Return non-nil if frame F wants a bitmap icon. */
2335
2336 Lisp_Object
2337 x_icon_type (f)
2338 FRAME_PTR f;
2339 {
2340 Lisp_Object tem;
2341
2342 tem = assq_no_quit (Qicon_type, f->param_alist);
2343 if (CONSP (tem))
2344 return XCDR (tem);
2345 else
2346 return Qnil;
2347 }
2348
2349 void
2350 x_set_icon_name (f, arg, oldval)
2351 struct frame *f;
2352 Lisp_Object arg, oldval;
2353 {
2354 if (STRINGP (arg))
2355 {
2356 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
2357 return;
2358 }
2359 else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
2360 return;
2361
2362 f->icon_name = arg;
2363
2364 #if 0
2365 if (f->output_data.w32->icon_bitmap != 0)
2366 return;
2367
2368 BLOCK_INPUT;
2369
2370 result = x_text_icon (f,
2371 (char *) XSTRING ((!NILP (f->icon_name)
2372 ? f->icon_name
2373 : !NILP (f->title)
2374 ? f->title
2375 : f->name))->data);
2376
2377 if (result)
2378 {
2379 UNBLOCK_INPUT;
2380 error ("No icon window available");
2381 }
2382
2383 /* If the window was unmapped (and its icon was mapped),
2384 the new icon is not mapped, so map the window in its stead. */
2385 if (FRAME_VISIBLE_P (f))
2386 {
2387 #ifdef USE_X_TOOLKIT
2388 XtPopup (f->output_data.w32->widget, XtGrabNone);
2389 #endif
2390 XMapWindow (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f));
2391 }
2392
2393 XFlush (FRAME_W32_DISPLAY (f));
2394 UNBLOCK_INPUT;
2395 #endif
2396 }
2397
2398 extern Lisp_Object x_new_font ();
2399 extern Lisp_Object x_new_fontset();
2400
2401 void
2402 x_set_font (f, arg, oldval)
2403 struct frame *f;
2404 Lisp_Object arg, oldval;
2405 {
2406 Lisp_Object result;
2407 Lisp_Object fontset_name;
2408 Lisp_Object frame;
2409 int old_fontset = FRAME_FONTSET(f);
2410
2411 CHECK_STRING (arg);
2412
2413 fontset_name = Fquery_fontset (arg, Qnil);
2414
2415 BLOCK_INPUT;
2416 result = (STRINGP (fontset_name)
2417 ? x_new_fontset (f, XSTRING (fontset_name)->data)
2418 : x_new_font (f, XSTRING (arg)->data));
2419 UNBLOCK_INPUT;
2420
2421 if (EQ (result, Qnil))
2422 error ("Font `%s' is not defined", XSTRING (arg)->data);
2423 else if (EQ (result, Qt))
2424 error ("The characters of the given font have varying widths");
2425 else if (STRINGP (result))
2426 {
2427 if (STRINGP (fontset_name))
2428 {
2429 /* Fontset names are built from ASCII font names, so the
2430 names may be equal despite there was a change. */
2431 if (old_fontset == FRAME_FONTSET (f))
2432 return;
2433 }
2434 else if (!NILP (Fequal (result, oldval)))
2435 return;
2436
2437 store_frame_param (f, Qfont, result);
2438 recompute_basic_faces (f);
2439 }
2440 else
2441 abort ();
2442
2443 do_pending_window_change (0);
2444
2445 /* Don't call `face-set-after-frame-default' when faces haven't been
2446 initialized yet. This is the case when called from
2447 Fx_create_frame. In that case, the X widget or window doesn't
2448 exist either, and we can end up in x_report_frame_params with a
2449 null widget which gives a segfault. */
2450 if (FRAME_FACE_CACHE (f))
2451 {
2452 XSETFRAME (frame, f);
2453 call1 (Qface_set_after_frame_default, frame);
2454 }
2455 }
2456
2457 static void
2458 x_set_fringe_width (f, new_value, old_value)
2459 struct frame *f;
2460 Lisp_Object new_value, old_value;
2461 {
2462 x_compute_fringe_widths (f, 1);
2463 }
2464
2465 void
2466 x_set_border_width (f, arg, oldval)
2467 struct frame *f;
2468 Lisp_Object arg, oldval;
2469 {
2470 CHECK_NUMBER (arg);
2471
2472 if (XINT (arg) == f->output_data.w32->border_width)
2473 return;
2474
2475 if (FRAME_W32_WINDOW (f) != 0)
2476 error ("Cannot change the border width of a window");
2477
2478 f->output_data.w32->border_width = XINT (arg);
2479 }
2480
2481 void
2482 x_set_internal_border_width (f, arg, oldval)
2483 struct frame *f;
2484 Lisp_Object arg, oldval;
2485 {
2486 int old = f->output_data.w32->internal_border_width;
2487
2488 CHECK_NUMBER (arg);
2489 f->output_data.w32->internal_border_width = XINT (arg);
2490 if (f->output_data.w32->internal_border_width < 0)
2491 f->output_data.w32->internal_border_width = 0;
2492
2493 if (f->output_data.w32->internal_border_width == old)
2494 return;
2495
2496 if (FRAME_W32_WINDOW (f) != 0)
2497 {
2498 x_set_window_size (f, 0, f->width, f->height);
2499 SET_FRAME_GARBAGED (f);
2500 do_pending_window_change (0);
2501 }
2502 else
2503 SET_FRAME_GARBAGED (f);
2504 }
2505
2506 void
2507 x_set_visibility (f, value, oldval)
2508 struct frame *f;
2509 Lisp_Object value, oldval;
2510 {
2511 Lisp_Object frame;
2512 XSETFRAME (frame, f);
2513
2514 if (NILP (value))
2515 Fmake_frame_invisible (frame, Qt);
2516 else if (EQ (value, Qicon))
2517 Ficonify_frame (frame);
2518 else
2519 Fmake_frame_visible (frame);
2520 }
2521
2522 \f
2523 /* Change window heights in windows rooted in WINDOW by N lines. */
2524
2525 static void
2526 x_change_window_heights (window, n)
2527 Lisp_Object window;
2528 int n;
2529 {
2530 struct window *w = XWINDOW (window);
2531
2532 XSETFASTINT (w->top, XFASTINT (w->top) + n);
2533 XSETFASTINT (w->height, XFASTINT (w->height) - n);
2534
2535 if (INTEGERP (w->orig_top))
2536 XSETFASTINT (w->orig_top, XFASTINT (w->orig_top) + n);
2537 if (INTEGERP (w->orig_height))
2538 XSETFASTINT (w->orig_height, XFASTINT (w->orig_height) - n);
2539
2540 /* Handle just the top child in a vertical split. */
2541 if (!NILP (w->vchild))
2542 x_change_window_heights (w->vchild, n);
2543
2544 /* Adjust all children in a horizontal split. */
2545 for (window = w->hchild; !NILP (window); window = w->next)
2546 {
2547 w = XWINDOW (window);
2548 x_change_window_heights (window, n);
2549 }
2550 }
2551
2552 void
2553 x_set_menu_bar_lines (f, value, oldval)
2554 struct frame *f;
2555 Lisp_Object value, oldval;
2556 {
2557 int nlines;
2558 int olines = FRAME_MENU_BAR_LINES (f);
2559
2560 /* Right now, menu bars don't work properly in minibuf-only frames;
2561 most of the commands try to apply themselves to the minibuffer
2562 frame itself, and get an error because you can't switch buffers
2563 in or split the minibuffer window. */
2564 if (FRAME_MINIBUF_ONLY_P (f))
2565 return;
2566
2567 if (INTEGERP (value))
2568 nlines = XINT (value);
2569 else
2570 nlines = 0;
2571
2572 FRAME_MENU_BAR_LINES (f) = 0;
2573 if (nlines)
2574 FRAME_EXTERNAL_MENU_BAR (f) = 1;
2575 else
2576 {
2577 if (FRAME_EXTERNAL_MENU_BAR (f) == 1)
2578 free_frame_menubar (f);
2579 FRAME_EXTERNAL_MENU_BAR (f) = 0;
2580
2581 /* Adjust the frame size so that the client (text) dimensions
2582 remain the same. This depends on FRAME_EXTERNAL_MENU_BAR being
2583 set correctly. */
2584 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2585 do_pending_window_change (0);
2586 }
2587 adjust_glyphs (f);
2588 }
2589
2590
2591 /* Set the number of lines used for the tool bar of frame F to VALUE.
2592 VALUE not an integer, or < 0 means set the lines to zero. OLDVAL
2593 is the old number of tool bar lines. This function changes the
2594 height of all windows on frame F to match the new tool bar height.
2595 The frame's height doesn't change. */
2596
2597 void
2598 x_set_tool_bar_lines (f, value, oldval)
2599 struct frame *f;
2600 Lisp_Object value, oldval;
2601 {
2602 int delta, nlines, root_height;
2603 Lisp_Object root_window;
2604
2605 /* Treat tool bars like menu bars. */
2606 if (FRAME_MINIBUF_ONLY_P (f))
2607 return;
2608
2609 /* Use VALUE only if an integer >= 0. */
2610 if (INTEGERP (value) && XINT (value) >= 0)
2611 nlines = XFASTINT (value);
2612 else
2613 nlines = 0;
2614
2615 /* Make sure we redisplay all windows in this frame. */
2616 ++windows_or_buffers_changed;
2617
2618 delta = nlines - FRAME_TOOL_BAR_LINES (f);
2619
2620 /* Don't resize the tool-bar to more than we have room for. */
2621 root_window = FRAME_ROOT_WINDOW (f);
2622 root_height = XINT (XWINDOW (root_window)->height);
2623 if (root_height - delta < 1)
2624 {
2625 delta = root_height - 1;
2626 nlines = FRAME_TOOL_BAR_LINES (f) + delta;
2627 }
2628
2629 FRAME_TOOL_BAR_LINES (f) = nlines;
2630 x_change_window_heights (root_window, delta);
2631 adjust_glyphs (f);
2632
2633 /* We also have to make sure that the internal border at the top of
2634 the frame, below the menu bar or tool bar, is redrawn when the
2635 tool bar disappears. This is so because the internal border is
2636 below the tool bar if one is displayed, but is below the menu bar
2637 if there isn't a tool bar. The tool bar draws into the area
2638 below the menu bar. */
2639 if (FRAME_W32_WINDOW (f) && FRAME_TOOL_BAR_LINES (f) == 0)
2640 {
2641 updating_frame = f;
2642 clear_frame ();
2643 clear_current_matrices (f);
2644 updating_frame = NULL;
2645 }
2646
2647 /* If the tool bar gets smaller, the internal border below it
2648 has to be cleared. It was formerly part of the display
2649 of the larger tool bar, and updating windows won't clear it. */
2650 if (delta < 0)
2651 {
2652 int height = FRAME_INTERNAL_BORDER_WIDTH (f);
2653 int width = PIXEL_WIDTH (f);
2654 int y = nlines * CANON_Y_UNIT (f);
2655
2656 BLOCK_INPUT;
2657 {
2658 HDC hdc = get_frame_dc (f);
2659 w32_clear_area (f, hdc, 0, y, width, height);
2660 release_frame_dc (f, hdc);
2661 }
2662 UNBLOCK_INPUT;
2663
2664 if (WINDOWP (f->tool_bar_window))
2665 clear_glyph_matrix (XWINDOW (f->tool_bar_window)->current_matrix);
2666 }
2667 }
2668
2669
2670 /* Change the name of frame F to NAME. If NAME is nil, set F's name to
2671 w32_id_name.
2672
2673 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2674 name; if NAME is a string, set F's name to NAME and set
2675 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2676
2677 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2678 suggesting a new name, which lisp code should override; if
2679 F->explicit_name is set, ignore the new name; otherwise, set it. */
2680
2681 void
2682 x_set_name (f, name, explicit)
2683 struct frame *f;
2684 Lisp_Object name;
2685 int explicit;
2686 {
2687 /* Make sure that requests from lisp code override requests from
2688 Emacs redisplay code. */
2689 if (explicit)
2690 {
2691 /* If we're switching from explicit to implicit, we had better
2692 update the mode lines and thereby update the title. */
2693 if (f->explicit_name && NILP (name))
2694 update_mode_lines = 1;
2695
2696 f->explicit_name = ! NILP (name);
2697 }
2698 else if (f->explicit_name)
2699 return;
2700
2701 /* If NAME is nil, set the name to the w32_id_name. */
2702 if (NILP (name))
2703 {
2704 /* Check for no change needed in this very common case
2705 before we do any consing. */
2706 if (!strcmp (FRAME_W32_DISPLAY_INFO (f)->w32_id_name,
2707 XSTRING (f->name)->data))
2708 return;
2709 name = build_string (FRAME_W32_DISPLAY_INFO (f)->w32_id_name);
2710 }
2711 else
2712 CHECK_STRING (name);
2713
2714 /* Don't change the name if it's already NAME. */
2715 if (! NILP (Fstring_equal (name, f->name)))
2716 return;
2717
2718 f->name = name;
2719
2720 /* For setting the frame title, the title parameter should override
2721 the name parameter. */
2722 if (! NILP (f->title))
2723 name = f->title;
2724
2725 if (FRAME_W32_WINDOW (f))
2726 {
2727 if (STRING_MULTIBYTE (name))
2728 name = ENCODE_SYSTEM (name);
2729
2730 BLOCK_INPUT;
2731 SetWindowText(FRAME_W32_WINDOW (f), XSTRING (name)->data);
2732 UNBLOCK_INPUT;
2733 }
2734 }
2735
2736 /* This function should be called when the user's lisp code has
2737 specified a name for the frame; the name will override any set by the
2738 redisplay code. */
2739 void
2740 x_explicitly_set_name (f, arg, oldval)
2741 FRAME_PTR f;
2742 Lisp_Object arg, oldval;
2743 {
2744 x_set_name (f, arg, 1);
2745 }
2746
2747 /* This function should be called by Emacs redisplay code to set the
2748 name; names set this way will never override names set by the user's
2749 lisp code. */
2750 void
2751 x_implicitly_set_name (f, arg, oldval)
2752 FRAME_PTR f;
2753 Lisp_Object arg, oldval;
2754 {
2755 x_set_name (f, arg, 0);
2756 }
2757 \f
2758 /* Change the title of frame F to NAME.
2759 If NAME is nil, use the frame name as the title.
2760
2761 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2762 name; if NAME is a string, set F's name to NAME and set
2763 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2764
2765 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2766 suggesting a new name, which lisp code should override; if
2767 F->explicit_name is set, ignore the new name; otherwise, set it. */
2768
2769 void
2770 x_set_title (f, name, old_name)
2771 struct frame *f;
2772 Lisp_Object name, old_name;
2773 {
2774 /* Don't change the title if it's already NAME. */
2775 if (EQ (name, f->title))
2776 return;
2777
2778 update_mode_lines = 1;
2779
2780 f->title = name;
2781
2782 if (NILP (name))
2783 name = f->name;
2784
2785 if (FRAME_W32_WINDOW (f))
2786 {
2787 if (STRING_MULTIBYTE (name))
2788 name = ENCODE_SYSTEM (name);
2789
2790 BLOCK_INPUT;
2791 SetWindowText(FRAME_W32_WINDOW (f), XSTRING (name)->data);
2792 UNBLOCK_INPUT;
2793 }
2794 }
2795 \f
2796 void
2797 x_set_autoraise (f, arg, oldval)
2798 struct frame *f;
2799 Lisp_Object arg, oldval;
2800 {
2801 f->auto_raise = !EQ (Qnil, arg);
2802 }
2803
2804 void
2805 x_set_autolower (f, arg, oldval)
2806 struct frame *f;
2807 Lisp_Object arg, oldval;
2808 {
2809 f->auto_lower = !EQ (Qnil, arg);
2810 }
2811
2812 void
2813 x_set_unsplittable (f, arg, oldval)
2814 struct frame *f;
2815 Lisp_Object arg, oldval;
2816 {
2817 f->no_split = !NILP (arg);
2818 }
2819
2820 void
2821 x_set_vertical_scroll_bars (f, arg, oldval)
2822 struct frame *f;
2823 Lisp_Object arg, oldval;
2824 {
2825 if ((EQ (arg, Qleft) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
2826 || (EQ (arg, Qright) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
2827 || (NILP (arg) && FRAME_HAS_VERTICAL_SCROLL_BARS (f))
2828 || (!NILP (arg) && ! FRAME_HAS_VERTICAL_SCROLL_BARS (f)))
2829 {
2830 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = NILP (arg) ?
2831 vertical_scroll_bar_none :
2832 /* Put scroll bars on the right by default, as is conventional
2833 on MS-Windows. */
2834 EQ (Qleft, arg)
2835 ? vertical_scroll_bar_left
2836 : vertical_scroll_bar_right;
2837
2838 /* We set this parameter before creating the window for the
2839 frame, so we can get the geometry right from the start.
2840 However, if the window hasn't been created yet, we shouldn't
2841 call x_set_window_size. */
2842 if (FRAME_W32_WINDOW (f))
2843 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2844 do_pending_window_change (0);
2845 }
2846 }
2847
2848 void
2849 x_set_scroll_bar_width (f, arg, oldval)
2850 struct frame *f;
2851 Lisp_Object arg, oldval;
2852 {
2853 int wid = FONT_WIDTH (f->output_data.w32->font);
2854
2855 if (NILP (arg))
2856 {
2857 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = GetSystemMetrics (SM_CXVSCROLL);
2858 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) +
2859 wid - 1) / wid;
2860 if (FRAME_W32_WINDOW (f))
2861 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2862 do_pending_window_change (0);
2863 }
2864 else if (INTEGERP (arg) && XINT (arg) > 0
2865 && XFASTINT (arg) != FRAME_SCROLL_BAR_PIXEL_WIDTH (f))
2866 {
2867 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = XFASTINT (arg);
2868 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
2869 + wid-1) / wid;
2870 if (FRAME_W32_WINDOW (f))
2871 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2872 do_pending_window_change (0);
2873 }
2874 change_frame_size (f, 0, FRAME_WIDTH (f), 0, 0, 0);
2875 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.hpos = 0;
2876 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.x = 0;
2877 }
2878 \f
2879 /* Subroutines of creating an frame. */
2880
2881 /* Make sure that Vx_resource_name is set to a reasonable value.
2882 Fix it up, or set it to `emacs' if it is too hopeless. */
2883
2884 static void
2885 validate_x_resource_name ()
2886 {
2887 int len = 0;
2888 /* Number of valid characters in the resource name. */
2889 int good_count = 0;
2890 /* Number of invalid characters in the resource name. */
2891 int bad_count = 0;
2892 Lisp_Object new;
2893 int i;
2894
2895 if (STRINGP (Vx_resource_name))
2896 {
2897 unsigned char *p = XSTRING (Vx_resource_name)->data;
2898 int i;
2899
2900 len = STRING_BYTES (XSTRING (Vx_resource_name));
2901
2902 /* Only letters, digits, - and _ are valid in resource names.
2903 Count the valid characters and count the invalid ones. */
2904 for (i = 0; i < len; i++)
2905 {
2906 int c = p[i];
2907 if (! ((c >= 'a' && c <= 'z')
2908 || (c >= 'A' && c <= 'Z')
2909 || (c >= '0' && c <= '9')
2910 || c == '-' || c == '_'))
2911 bad_count++;
2912 else
2913 good_count++;
2914 }
2915 }
2916 else
2917 /* Not a string => completely invalid. */
2918 bad_count = 5, good_count = 0;
2919
2920 /* If name is valid already, return. */
2921 if (bad_count == 0)
2922 return;
2923
2924 /* If name is entirely invalid, or nearly so, use `emacs'. */
2925 if (good_count == 0
2926 || (good_count == 1 && bad_count > 0))
2927 {
2928 Vx_resource_name = build_string ("emacs");
2929 return;
2930 }
2931
2932 /* Name is partly valid. Copy it and replace the invalid characters
2933 with underscores. */
2934
2935 Vx_resource_name = new = Fcopy_sequence (Vx_resource_name);
2936
2937 for (i = 0; i < len; i++)
2938 {
2939 int c = XSTRING (new)->data[i];
2940 if (! ((c >= 'a' && c <= 'z')
2941 || (c >= 'A' && c <= 'Z')
2942 || (c >= '0' && c <= '9')
2943 || c == '-' || c == '_'))
2944 XSTRING (new)->data[i] = '_';
2945 }
2946 }
2947
2948
2949 extern char *x_get_string_resource ();
2950
2951 DEFUN ("x-get-resource", Fx_get_resource, Sx_get_resource, 2, 4, 0,
2952 doc: /* Return the value of ATTRIBUTE, of class CLASS, from the X defaults database.
2953 This uses `INSTANCE.ATTRIBUTE' as the key and `Emacs.CLASS' as the
2954 class, where INSTANCE is the name under which Emacs was invoked, or
2955 the name specified by the `-name' or `-rn' command-line arguments.
2956
2957 The optional arguments COMPONENT and SUBCLASS add to the key and the
2958 class, respectively. You must specify both of them or neither.
2959 If you specify them, the key is `INSTANCE.COMPONENT.ATTRIBUTE'
2960 and the class is `Emacs.CLASS.SUBCLASS'. */)
2961 (attribute, class, component, subclass)
2962 Lisp_Object attribute, class, component, subclass;
2963 {
2964 register char *value;
2965 char *name_key;
2966 char *class_key;
2967
2968 CHECK_STRING (attribute);
2969 CHECK_STRING (class);
2970
2971 if (!NILP (component))
2972 CHECK_STRING (component);
2973 if (!NILP (subclass))
2974 CHECK_STRING (subclass);
2975 if (NILP (component) != NILP (subclass))
2976 error ("x-get-resource: must specify both COMPONENT and SUBCLASS or neither");
2977
2978 validate_x_resource_name ();
2979
2980 /* Allocate space for the components, the dots which separate them,
2981 and the final '\0'. Make them big enough for the worst case. */
2982 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vx_resource_name))
2983 + (STRINGP (component)
2984 ? STRING_BYTES (XSTRING (component)) : 0)
2985 + STRING_BYTES (XSTRING (attribute))
2986 + 3);
2987
2988 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
2989 + STRING_BYTES (XSTRING (class))
2990 + (STRINGP (subclass)
2991 ? STRING_BYTES (XSTRING (subclass)) : 0)
2992 + 3);
2993
2994 /* Start with emacs.FRAMENAME for the name (the specific one)
2995 and with `Emacs' for the class key (the general one). */
2996 strcpy (name_key, XSTRING (Vx_resource_name)->data);
2997 strcpy (class_key, EMACS_CLASS);
2998
2999 strcat (class_key, ".");
3000 strcat (class_key, XSTRING (class)->data);
3001
3002 if (!NILP (component))
3003 {
3004 strcat (class_key, ".");
3005 strcat (class_key, XSTRING (subclass)->data);
3006
3007 strcat (name_key, ".");
3008 strcat (name_key, XSTRING (component)->data);
3009 }
3010
3011 strcat (name_key, ".");
3012 strcat (name_key, XSTRING (attribute)->data);
3013
3014 value = x_get_string_resource (Qnil,
3015 name_key, class_key);
3016
3017 if (value != (char *) 0)
3018 return build_string (value);
3019 else
3020 return Qnil;
3021 }
3022
3023 /* Used when C code wants a resource value. */
3024
3025 char *
3026 x_get_resource_string (attribute, class)
3027 char *attribute, *class;
3028 {
3029 char *name_key;
3030 char *class_key;
3031 struct frame *sf = SELECTED_FRAME ();
3032
3033 /* Allocate space for the components, the dots which separate them,
3034 and the final '\0'. */
3035 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vinvocation_name))
3036 + strlen (attribute) + 2);
3037 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
3038 + strlen (class) + 2);
3039
3040 sprintf (name_key, "%s.%s",
3041 XSTRING (Vinvocation_name)->data,
3042 attribute);
3043 sprintf (class_key, "%s.%s", EMACS_CLASS, class);
3044
3045 return x_get_string_resource (sf, name_key, class_key);
3046 }
3047
3048 /* Types we might convert a resource string into. */
3049 enum resource_types
3050 {
3051 RES_TYPE_NUMBER,
3052 RES_TYPE_FLOAT,
3053 RES_TYPE_BOOLEAN,
3054 RES_TYPE_STRING,
3055 RES_TYPE_SYMBOL
3056 };
3057
3058 /* Return the value of parameter PARAM.
3059
3060 First search ALIST, then Vdefault_frame_alist, then the X defaults
3061 database, using ATTRIBUTE as the attribute name and CLASS as its class.
3062
3063 Convert the resource to the type specified by desired_type.
3064
3065 If no default is specified, return Qunbound. If you call
3066 w32_get_arg, make sure you deal with Qunbound in a reasonable way,
3067 and don't let it get stored in any Lisp-visible variables! */
3068
3069 static Lisp_Object
3070 w32_get_arg (alist, param, attribute, class, type)
3071 Lisp_Object alist, param;
3072 char *attribute;
3073 char *class;
3074 enum resource_types type;
3075 {
3076 register Lisp_Object tem;
3077
3078 tem = Fassq (param, alist);
3079 if (EQ (tem, Qnil))
3080 tem = Fassq (param, Vdefault_frame_alist);
3081 if (EQ (tem, Qnil))
3082 {
3083
3084 if (attribute)
3085 {
3086 tem = Fx_get_resource (build_string (attribute),
3087 build_string (class),
3088 Qnil, Qnil);
3089
3090 if (NILP (tem))
3091 return Qunbound;
3092
3093 switch (type)
3094 {
3095 case RES_TYPE_NUMBER:
3096 return make_number (atoi (XSTRING (tem)->data));
3097
3098 case RES_TYPE_FLOAT:
3099 return make_float (atof (XSTRING (tem)->data));
3100
3101 case RES_TYPE_BOOLEAN:
3102 tem = Fdowncase (tem);
3103 if (!strcmp (XSTRING (tem)->data, "on")
3104 || !strcmp (XSTRING (tem)->data, "true"))
3105 return Qt;
3106 else
3107 return Qnil;
3108
3109 case RES_TYPE_STRING:
3110 return tem;
3111
3112 case RES_TYPE_SYMBOL:
3113 /* As a special case, we map the values `true' and `on'
3114 to Qt, and `false' and `off' to Qnil. */
3115 {
3116 Lisp_Object lower;
3117 lower = Fdowncase (tem);
3118 if (!strcmp (XSTRING (lower)->data, "on")
3119 || !strcmp (XSTRING (lower)->data, "true"))
3120 return Qt;
3121 else if (!strcmp (XSTRING (lower)->data, "off")
3122 || !strcmp (XSTRING (lower)->data, "false"))
3123 return Qnil;
3124 else
3125 return Fintern (tem, Qnil);
3126 }
3127
3128 default:
3129 abort ();
3130 }
3131 }
3132 else
3133 return Qunbound;
3134 }
3135 return Fcdr (tem);
3136 }
3137
3138 /* Record in frame F the specified or default value according to ALIST
3139 of the parameter named PROP (a Lisp symbol).
3140 If no value is specified for PROP, look for an X default for XPROP
3141 on the frame named NAME.
3142 If that is not found either, use the value DEFLT. */
3143
3144 static Lisp_Object
3145 x_default_parameter (f, alist, prop, deflt, xprop, xclass, type)
3146 struct frame *f;
3147 Lisp_Object alist;
3148 Lisp_Object prop;
3149 Lisp_Object deflt;
3150 char *xprop;
3151 char *xclass;
3152 enum resource_types type;
3153 {
3154 Lisp_Object tem;
3155
3156 tem = w32_get_arg (alist, prop, xprop, xclass, type);
3157 if (EQ (tem, Qunbound))
3158 tem = deflt;
3159 x_set_frame_parameters (f, Fcons (Fcons (prop, tem), Qnil));
3160 return tem;
3161 }
3162 \f
3163 DEFUN ("x-parse-geometry", Fx_parse_geometry, Sx_parse_geometry, 1, 1, 0,
3164 doc: /* Parse an X-style geometry string STRING.
3165 Returns an alist of the form ((top . TOP), (left . LEFT) ... ).
3166 The properties returned may include `top', `left', `height', and `width'.
3167 The value of `left' or `top' may be an integer,
3168 or a list (+ N) meaning N pixels relative to top/left corner,
3169 or a list (- N) meaning -N pixels relative to bottom/right corner. */)
3170 (string)
3171 Lisp_Object string;
3172 {
3173 int geometry, x, y;
3174 unsigned int width, height;
3175 Lisp_Object result;
3176
3177 CHECK_STRING (string);
3178
3179 geometry = XParseGeometry ((char *) XSTRING (string)->data,
3180 &x, &y, &width, &height);
3181
3182 result = Qnil;
3183 if (geometry & XValue)
3184 {
3185 Lisp_Object element;
3186
3187 if (x >= 0 && (geometry & XNegative))
3188 element = Fcons (Qleft, Fcons (Qminus, Fcons (make_number (-x), Qnil)));
3189 else if (x < 0 && ! (geometry & XNegative))
3190 element = Fcons (Qleft, Fcons (Qplus, Fcons (make_number (x), Qnil)));
3191 else
3192 element = Fcons (Qleft, make_number (x));
3193 result = Fcons (element, result);
3194 }
3195
3196 if (geometry & YValue)
3197 {
3198 Lisp_Object element;
3199
3200 if (y >= 0 && (geometry & YNegative))
3201 element = Fcons (Qtop, Fcons (Qminus, Fcons (make_number (-y), Qnil)));
3202 else if (y < 0 && ! (geometry & YNegative))
3203 element = Fcons (Qtop, Fcons (Qplus, Fcons (make_number (y), Qnil)));
3204 else
3205 element = Fcons (Qtop, make_number (y));
3206 result = Fcons (element, result);
3207 }
3208
3209 if (geometry & WidthValue)
3210 result = Fcons (Fcons (Qwidth, make_number (width)), result);
3211 if (geometry & HeightValue)
3212 result = Fcons (Fcons (Qheight, make_number (height)), result);
3213
3214 return result;
3215 }
3216
3217 /* Calculate the desired size and position of this window,
3218 and return the flags saying which aspects were specified.
3219
3220 This function does not make the coordinates positive. */
3221
3222 #define DEFAULT_ROWS 40
3223 #define DEFAULT_COLS 80
3224
3225 static int
3226 x_figure_window_size (f, parms)
3227 struct frame *f;
3228 Lisp_Object parms;
3229 {
3230 register Lisp_Object tem0, tem1, tem2;
3231 long window_prompting = 0;
3232
3233 /* Default values if we fall through.
3234 Actually, if that happens we should get
3235 window manager prompting. */
3236 SET_FRAME_WIDTH (f, DEFAULT_COLS);
3237 f->height = DEFAULT_ROWS;
3238 /* Window managers expect that if program-specified
3239 positions are not (0,0), they're intentional, not defaults. */
3240 f->output_data.w32->top_pos = 0;
3241 f->output_data.w32->left_pos = 0;
3242
3243 /* Ensure that old new_width and new_height will not override the
3244 values set here. */
3245 FRAME_NEW_WIDTH (f) = 0;
3246 FRAME_NEW_HEIGHT (f) = 0;
3247
3248 tem0 = w32_get_arg (parms, Qheight, 0, 0, RES_TYPE_NUMBER);
3249 tem1 = w32_get_arg (parms, Qwidth, 0, 0, RES_TYPE_NUMBER);
3250 tem2 = w32_get_arg (parms, Quser_size, 0, 0, RES_TYPE_NUMBER);
3251 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3252 {
3253 if (!EQ (tem0, Qunbound))
3254 {
3255 CHECK_NUMBER (tem0);
3256 f->height = XINT (tem0);
3257 }
3258 if (!EQ (tem1, Qunbound))
3259 {
3260 CHECK_NUMBER (tem1);
3261 SET_FRAME_WIDTH (f, XINT (tem1));
3262 }
3263 if (!NILP (tem2) && !EQ (tem2, Qunbound))
3264 window_prompting |= USSize;
3265 else
3266 window_prompting |= PSize;
3267 }
3268
3269 f->output_data.w32->vertical_scroll_bar_extra
3270 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
3271 ? 0
3272 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
3273 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
3274 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.w32->font)));
3275 x_compute_fringe_widths (f, 0);
3276 f->output_data.w32->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
3277 f->output_data.w32->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
3278
3279 tem0 = w32_get_arg (parms, Qtop, 0, 0, RES_TYPE_NUMBER);
3280 tem1 = w32_get_arg (parms, Qleft, 0, 0, RES_TYPE_NUMBER);
3281 tem2 = w32_get_arg (parms, Quser_position, 0, 0, RES_TYPE_NUMBER);
3282 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3283 {
3284 if (EQ (tem0, Qminus))
3285 {
3286 f->output_data.w32->top_pos = 0;
3287 window_prompting |= YNegative;
3288 }
3289 else if (CONSP (tem0) && EQ (XCAR (tem0), Qminus)
3290 && CONSP (XCDR (tem0))
3291 && INTEGERP (XCAR (XCDR (tem0))))
3292 {
3293 f->output_data.w32->top_pos = - XINT (XCAR (XCDR (tem0)));
3294 window_prompting |= YNegative;
3295 }
3296 else if (CONSP (tem0) && EQ (XCAR (tem0), Qplus)
3297 && CONSP (XCDR (tem0))
3298 && INTEGERP (XCAR (XCDR (tem0))))
3299 {
3300 f->output_data.w32->top_pos = XINT (XCAR (XCDR (tem0)));
3301 }
3302 else if (EQ (tem0, Qunbound))
3303 f->output_data.w32->top_pos = 0;
3304 else
3305 {
3306 CHECK_NUMBER (tem0);
3307 f->output_data.w32->top_pos = XINT (tem0);
3308 if (f->output_data.w32->top_pos < 0)
3309 window_prompting |= YNegative;
3310 }
3311
3312 if (EQ (tem1, Qminus))
3313 {
3314 f->output_data.w32->left_pos = 0;
3315 window_prompting |= XNegative;
3316 }
3317 else if (CONSP (tem1) && EQ (XCAR (tem1), Qminus)
3318 && CONSP (XCDR (tem1))
3319 && INTEGERP (XCAR (XCDR (tem1))))
3320 {
3321 f->output_data.w32->left_pos = - XINT (XCAR (XCDR (tem1)));
3322 window_prompting |= XNegative;
3323 }
3324 else if (CONSP (tem1) && EQ (XCAR (tem1), Qplus)
3325 && CONSP (XCDR (tem1))
3326 && INTEGERP (XCAR (XCDR (tem1))))
3327 {
3328 f->output_data.w32->left_pos = XINT (XCAR (XCDR (tem1)));
3329 }
3330 else if (EQ (tem1, Qunbound))
3331 f->output_data.w32->left_pos = 0;
3332 else
3333 {
3334 CHECK_NUMBER (tem1);
3335 f->output_data.w32->left_pos = XINT (tem1);
3336 if (f->output_data.w32->left_pos < 0)
3337 window_prompting |= XNegative;
3338 }
3339
3340 if (!NILP (tem2) && ! EQ (tem2, Qunbound))
3341 window_prompting |= USPosition;
3342 else
3343 window_prompting |= PPosition;
3344 }
3345
3346 return window_prompting;
3347 }
3348
3349 \f
3350
3351 extern LRESULT CALLBACK w32_wnd_proc ();
3352
3353 BOOL
3354 w32_init_class (hinst)
3355 HINSTANCE hinst;
3356 {
3357 WNDCLASS wc;
3358
3359 wc.style = CS_HREDRAW | CS_VREDRAW;
3360 wc.lpfnWndProc = (WNDPROC) w32_wnd_proc;
3361 wc.cbClsExtra = 0;
3362 wc.cbWndExtra = WND_EXTRA_BYTES;
3363 wc.hInstance = hinst;
3364 wc.hIcon = LoadIcon (hinst, EMACS_CLASS);
3365 wc.hCursor = LoadCursor (NULL, IDC_ARROW);
3366 wc.hbrBackground = NULL; /* GetStockObject (WHITE_BRUSH); */
3367 wc.lpszMenuName = NULL;
3368 wc.lpszClassName = EMACS_CLASS;
3369
3370 return (RegisterClass (&wc));
3371 }
3372
3373 HWND
3374 w32_createscrollbar (f, bar)
3375 struct frame *f;
3376 struct scroll_bar * bar;
3377 {
3378 return (CreateWindow ("SCROLLBAR", "", SBS_VERT | WS_CHILD | WS_VISIBLE,
3379 /* Position and size of scroll bar. */
3380 XINT(bar->left) + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
3381 XINT(bar->top),
3382 XINT(bar->width) - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
3383 XINT(bar->height),
3384 FRAME_W32_WINDOW (f),
3385 NULL,
3386 hinst,
3387 NULL));
3388 }
3389
3390 void
3391 w32_createwindow (f)
3392 struct frame *f;
3393 {
3394 HWND hwnd;
3395 RECT rect;
3396
3397 rect.left = rect.top = 0;
3398 rect.right = PIXEL_WIDTH (f);
3399 rect.bottom = PIXEL_HEIGHT (f);
3400
3401 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
3402 FRAME_EXTERNAL_MENU_BAR (f));
3403
3404 /* Do first time app init */
3405
3406 if (!hprevinst)
3407 {
3408 w32_init_class (hinst);
3409 }
3410
3411 FRAME_W32_WINDOW (f) = hwnd
3412 = CreateWindow (EMACS_CLASS,
3413 f->namebuf,
3414 f->output_data.w32->dwStyle | WS_CLIPCHILDREN,
3415 f->output_data.w32->left_pos,
3416 f->output_data.w32->top_pos,
3417 rect.right - rect.left,
3418 rect.bottom - rect.top,
3419 NULL,
3420 NULL,
3421 hinst,
3422 NULL);
3423
3424 if (hwnd)
3425 {
3426 SetWindowLong (hwnd, WND_FONTWIDTH_INDEX, FONT_WIDTH (f->output_data.w32->font));
3427 SetWindowLong (hwnd, WND_LINEHEIGHT_INDEX, f->output_data.w32->line_height);
3428 SetWindowLong (hwnd, WND_BORDER_INDEX, f->output_data.w32->internal_border_width);
3429 SetWindowLong (hwnd, WND_SCROLLBAR_INDEX, f->output_data.w32->vertical_scroll_bar_extra);
3430 SetWindowLong (hwnd, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f));
3431
3432 /* Enable drag-n-drop. */
3433 DragAcceptFiles (hwnd, TRUE);
3434
3435 /* Do this to discard the default setting specified by our parent. */
3436 ShowWindow (hwnd, SW_HIDE);
3437 }
3438 }
3439
3440 void
3441 my_post_msg (wmsg, hwnd, msg, wParam, lParam)
3442 W32Msg * wmsg;
3443 HWND hwnd;
3444 UINT msg;
3445 WPARAM wParam;
3446 LPARAM lParam;
3447 {
3448 wmsg->msg.hwnd = hwnd;
3449 wmsg->msg.message = msg;
3450 wmsg->msg.wParam = wParam;
3451 wmsg->msg.lParam = lParam;
3452 wmsg->msg.time = GetMessageTime ();
3453
3454 post_msg (wmsg);
3455 }
3456
3457 /* GetKeyState and MapVirtualKey on Windows 95 do not actually distinguish
3458 between left and right keys as advertised. We test for this
3459 support dynamically, and set a flag when the support is absent. If
3460 absent, we keep track of the left and right control and alt keys
3461 ourselves. This is particularly necessary on keyboards that rely
3462 upon the AltGr key, which is represented as having the left control
3463 and right alt keys pressed. For these keyboards, we need to know
3464 when the left alt key has been pressed in addition to the AltGr key
3465 so that we can properly support M-AltGr-key sequences (such as M-@
3466 on Swedish keyboards). */
3467
3468 #define EMACS_LCONTROL 0
3469 #define EMACS_RCONTROL 1
3470 #define EMACS_LMENU 2
3471 #define EMACS_RMENU 3
3472
3473 static int modifiers[4];
3474 static int modifiers_recorded;
3475 static int modifier_key_support_tested;
3476
3477 static void
3478 test_modifier_support (unsigned int wparam)
3479 {
3480 unsigned int l, r;
3481
3482 if (wparam != VK_CONTROL && wparam != VK_MENU)
3483 return;
3484 if (wparam == VK_CONTROL)
3485 {
3486 l = VK_LCONTROL;
3487 r = VK_RCONTROL;
3488 }
3489 else
3490 {
3491 l = VK_LMENU;
3492 r = VK_RMENU;
3493 }
3494 if (!(GetKeyState (l) & 0x8000) && !(GetKeyState (r) & 0x8000))
3495 modifiers_recorded = 1;
3496 else
3497 modifiers_recorded = 0;
3498 modifier_key_support_tested = 1;
3499 }
3500
3501 static void
3502 record_keydown (unsigned int wparam, unsigned int lparam)
3503 {
3504 int i;
3505
3506 if (!modifier_key_support_tested)
3507 test_modifier_support (wparam);
3508
3509 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3510 return;
3511
3512 if (wparam == VK_CONTROL)
3513 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3514 else
3515 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3516
3517 modifiers[i] = 1;
3518 }
3519
3520 static void
3521 record_keyup (unsigned int wparam, unsigned int lparam)
3522 {
3523 int i;
3524
3525 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3526 return;
3527
3528 if (wparam == VK_CONTROL)
3529 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3530 else
3531 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3532
3533 modifiers[i] = 0;
3534 }
3535
3536 /* Emacs can lose focus while a modifier key has been pressed. When
3537 it regains focus, be conservative and clear all modifiers since
3538 we cannot reconstruct the left and right modifier state. */
3539 static void
3540 reset_modifiers ()
3541 {
3542 SHORT ctrl, alt;
3543
3544 if (GetFocus () == NULL)
3545 /* Emacs doesn't have keyboard focus. Do nothing. */
3546 return;
3547
3548 ctrl = GetAsyncKeyState (VK_CONTROL);
3549 alt = GetAsyncKeyState (VK_MENU);
3550
3551 if (!(ctrl & 0x08000))
3552 /* Clear any recorded control modifier state. */
3553 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3554
3555 if (!(alt & 0x08000))
3556 /* Clear any recorded alt modifier state. */
3557 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3558
3559 /* Update the state of all modifier keys, because modifiers used in
3560 hot-key combinations can get stuck on if Emacs loses focus as a
3561 result of a hot-key being pressed. */
3562 {
3563 BYTE keystate[256];
3564
3565 #define CURRENT_STATE(key) ((GetAsyncKeyState (key) & 0x8000) >> 8)
3566
3567 GetKeyboardState (keystate);
3568 keystate[VK_SHIFT] = CURRENT_STATE (VK_SHIFT);
3569 keystate[VK_CONTROL] = CURRENT_STATE (VK_CONTROL);
3570 keystate[VK_LCONTROL] = CURRENT_STATE (VK_LCONTROL);
3571 keystate[VK_RCONTROL] = CURRENT_STATE (VK_RCONTROL);
3572 keystate[VK_MENU] = CURRENT_STATE (VK_MENU);
3573 keystate[VK_LMENU] = CURRENT_STATE (VK_LMENU);
3574 keystate[VK_RMENU] = CURRENT_STATE (VK_RMENU);
3575 keystate[VK_LWIN] = CURRENT_STATE (VK_LWIN);
3576 keystate[VK_RWIN] = CURRENT_STATE (VK_RWIN);
3577 keystate[VK_APPS] = CURRENT_STATE (VK_APPS);
3578 SetKeyboardState (keystate);
3579 }
3580 }
3581
3582 /* Synchronize modifier state with what is reported with the current
3583 keystroke. Even if we cannot distinguish between left and right
3584 modifier keys, we know that, if no modifiers are set, then neither
3585 the left or right modifier should be set. */
3586 static void
3587 sync_modifiers ()
3588 {
3589 if (!modifiers_recorded)
3590 return;
3591
3592 if (!(GetKeyState (VK_CONTROL) & 0x8000))
3593 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3594
3595 if (!(GetKeyState (VK_MENU) & 0x8000))
3596 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3597 }
3598
3599 static int
3600 modifier_set (int vkey)
3601 {
3602 if (vkey == VK_CAPITAL || vkey == VK_SCROLL)
3603 return (GetKeyState (vkey) & 0x1);
3604 if (!modifiers_recorded)
3605 return (GetKeyState (vkey) & 0x8000);
3606
3607 switch (vkey)
3608 {
3609 case VK_LCONTROL:
3610 return modifiers[EMACS_LCONTROL];
3611 case VK_RCONTROL:
3612 return modifiers[EMACS_RCONTROL];
3613 case VK_LMENU:
3614 return modifiers[EMACS_LMENU];
3615 case VK_RMENU:
3616 return modifiers[EMACS_RMENU];
3617 }
3618 return (GetKeyState (vkey) & 0x8000);
3619 }
3620
3621 /* Convert between the modifier bits W32 uses and the modifier bits
3622 Emacs uses. */
3623
3624 unsigned int
3625 w32_key_to_modifier (int key)
3626 {
3627 Lisp_Object key_mapping;
3628
3629 switch (key)
3630 {
3631 case VK_LWIN:
3632 key_mapping = Vw32_lwindow_modifier;
3633 break;
3634 case VK_RWIN:
3635 key_mapping = Vw32_rwindow_modifier;
3636 break;
3637 case VK_APPS:
3638 key_mapping = Vw32_apps_modifier;
3639 break;
3640 case VK_SCROLL:
3641 key_mapping = Vw32_scroll_lock_modifier;
3642 break;
3643 default:
3644 key_mapping = Qnil;
3645 }
3646
3647 /* NB. This code runs in the input thread, asychronously to the lisp
3648 thread, so we must be careful to ensure access to lisp data is
3649 thread-safe. The following code is safe because the modifier
3650 variable values are updated atomically from lisp and symbols are
3651 not relocated by GC. Also, we don't have to worry about seeing GC
3652 markbits here. */
3653 if (EQ (key_mapping, Qhyper))
3654 return hyper_modifier;
3655 if (EQ (key_mapping, Qsuper))
3656 return super_modifier;
3657 if (EQ (key_mapping, Qmeta))
3658 return meta_modifier;
3659 if (EQ (key_mapping, Qalt))
3660 return alt_modifier;
3661 if (EQ (key_mapping, Qctrl))
3662 return ctrl_modifier;
3663 if (EQ (key_mapping, Qcontrol)) /* synonym for ctrl */
3664 return ctrl_modifier;
3665 if (EQ (key_mapping, Qshift))
3666 return shift_modifier;
3667
3668 /* Don't generate any modifier if not explicitly requested. */
3669 return 0;
3670 }
3671
3672 unsigned int
3673 w32_get_modifiers ()
3674 {
3675 return ((modifier_set (VK_SHIFT) ? shift_modifier : 0) |
3676 (modifier_set (VK_CONTROL) ? ctrl_modifier : 0) |
3677 (modifier_set (VK_LWIN) ? w32_key_to_modifier (VK_LWIN) : 0) |
3678 (modifier_set (VK_RWIN) ? w32_key_to_modifier (VK_RWIN) : 0) |
3679 (modifier_set (VK_APPS) ? w32_key_to_modifier (VK_APPS) : 0) |
3680 (modifier_set (VK_SCROLL) ? w32_key_to_modifier (VK_SCROLL) : 0) |
3681 (modifier_set (VK_MENU) ?
3682 ((NILP (Vw32_alt_is_meta)) ? alt_modifier : meta_modifier) : 0));
3683 }
3684
3685 /* We map the VK_* modifiers into console modifier constants
3686 so that we can use the same routines to handle both console
3687 and window input. */
3688
3689 static int
3690 construct_console_modifiers ()
3691 {
3692 int mods;
3693
3694 mods = 0;
3695 mods |= (modifier_set (VK_SHIFT)) ? SHIFT_PRESSED : 0;
3696 mods |= (modifier_set (VK_CAPITAL)) ? CAPSLOCK_ON : 0;
3697 mods |= (modifier_set (VK_SCROLL)) ? SCROLLLOCK_ON : 0;
3698 mods |= (modifier_set (VK_NUMLOCK)) ? NUMLOCK_ON : 0;
3699 mods |= (modifier_set (VK_LCONTROL)) ? LEFT_CTRL_PRESSED : 0;
3700 mods |= (modifier_set (VK_RCONTROL)) ? RIGHT_CTRL_PRESSED : 0;
3701 mods |= (modifier_set (VK_LMENU)) ? LEFT_ALT_PRESSED : 0;
3702 mods |= (modifier_set (VK_RMENU)) ? RIGHT_ALT_PRESSED : 0;
3703 mods |= (modifier_set (VK_LWIN)) ? LEFT_WIN_PRESSED : 0;
3704 mods |= (modifier_set (VK_RWIN)) ? RIGHT_WIN_PRESSED : 0;
3705 mods |= (modifier_set (VK_APPS)) ? APPS_PRESSED : 0;
3706
3707 return mods;
3708 }
3709
3710 static int
3711 w32_get_key_modifiers (unsigned int wparam, unsigned int lparam)
3712 {
3713 int mods;
3714
3715 /* Convert to emacs modifiers. */
3716 mods = w32_kbd_mods_to_emacs (construct_console_modifiers (), wparam);
3717
3718 return mods;
3719 }
3720
3721 unsigned int
3722 map_keypad_keys (unsigned int virt_key, unsigned int extended)
3723 {
3724 if (virt_key < VK_CLEAR || virt_key > VK_DELETE)
3725 return virt_key;
3726
3727 if (virt_key == VK_RETURN)
3728 return (extended ? VK_NUMPAD_ENTER : VK_RETURN);
3729
3730 if (virt_key >= VK_PRIOR && virt_key <= VK_DOWN)
3731 return (!extended ? (VK_NUMPAD_PRIOR + (virt_key - VK_PRIOR)) : virt_key);
3732
3733 if (virt_key == VK_INSERT || virt_key == VK_DELETE)
3734 return (!extended ? (VK_NUMPAD_INSERT + (virt_key - VK_INSERT)) : virt_key);
3735
3736 if (virt_key == VK_CLEAR)
3737 return (!extended ? VK_NUMPAD_CLEAR : virt_key);
3738
3739 return virt_key;
3740 }
3741
3742 /* List of special key combinations which w32 would normally capture,
3743 but emacs should grab instead. Not directly visible to lisp, to
3744 simplify synchronization. Each item is an integer encoding a virtual
3745 key code and modifier combination to capture. */
3746 Lisp_Object w32_grabbed_keys;
3747
3748 #define HOTKEY(vk,mods) make_number (((vk) & 255) | ((mods) << 8))
3749 #define HOTKEY_ID(k) (XFASTINT (k) & 0xbfff)
3750 #define HOTKEY_VK_CODE(k) (XFASTINT (k) & 255)
3751 #define HOTKEY_MODIFIERS(k) (XFASTINT (k) >> 8)
3752
3753 /* Register hot-keys for reserved key combinations when Emacs has
3754 keyboard focus, since this is the only way Emacs can receive key
3755 combinations like Alt-Tab which are used by the system. */
3756
3757 static void
3758 register_hot_keys (hwnd)
3759 HWND hwnd;
3760 {
3761 Lisp_Object keylist;
3762
3763 /* Use GC_CONSP, since we are called asynchronously. */
3764 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3765 {
3766 Lisp_Object key = XCAR (keylist);
3767
3768 /* Deleted entries get set to nil. */
3769 if (!INTEGERP (key))
3770 continue;
3771
3772 RegisterHotKey (hwnd, HOTKEY_ID (key),
3773 HOTKEY_MODIFIERS (key), HOTKEY_VK_CODE (key));
3774 }
3775 }
3776
3777 static void
3778 unregister_hot_keys (hwnd)
3779 HWND hwnd;
3780 {
3781 Lisp_Object keylist;
3782
3783 /* Use GC_CONSP, since we are called asynchronously. */
3784 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3785 {
3786 Lisp_Object key = XCAR (keylist);
3787
3788 if (!INTEGERP (key))
3789 continue;
3790
3791 UnregisterHotKey (hwnd, HOTKEY_ID (key));
3792 }
3793 }
3794
3795 /* Main message dispatch loop. */
3796
3797 static void
3798 w32_msg_pump (deferred_msg * msg_buf)
3799 {
3800 MSG msg;
3801 int result;
3802 HWND focus_window;
3803
3804 msh_mousewheel = RegisterWindowMessage (MSH_MOUSEWHEEL);
3805
3806 while (GetMessage (&msg, NULL, 0, 0))
3807 {
3808 if (msg.hwnd == NULL)
3809 {
3810 switch (msg.message)
3811 {
3812 case WM_NULL:
3813 /* Produced by complete_deferred_msg; just ignore. */
3814 break;
3815 case WM_EMACS_CREATEWINDOW:
3816 w32_createwindow ((struct frame *) msg.wParam);
3817 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3818 abort ();
3819 break;
3820 case WM_EMACS_SETLOCALE:
3821 SetThreadLocale (msg.wParam);
3822 /* Reply is not expected. */
3823 break;
3824 case WM_EMACS_SETKEYBOARDLAYOUT:
3825 result = (int) ActivateKeyboardLayout ((HKL) msg.wParam, 0);
3826 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
3827 result, 0))
3828 abort ();
3829 break;
3830 case WM_EMACS_REGISTER_HOT_KEY:
3831 focus_window = GetFocus ();
3832 if (focus_window != NULL)
3833 RegisterHotKey (focus_window,
3834 HOTKEY_ID (msg.wParam),
3835 HOTKEY_MODIFIERS (msg.wParam),
3836 HOTKEY_VK_CODE (msg.wParam));
3837 /* Reply is not expected. */
3838 break;
3839 case WM_EMACS_UNREGISTER_HOT_KEY:
3840 focus_window = GetFocus ();
3841 if (focus_window != NULL)
3842 UnregisterHotKey (focus_window, HOTKEY_ID (msg.wParam));
3843 /* Mark item as erased. NB: this code must be
3844 thread-safe. The next line is okay because the cons
3845 cell is never made into garbage and is not relocated by
3846 GC. */
3847 XSETCAR ((Lisp_Object) msg.lParam, Qnil);
3848 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3849 abort ();
3850 break;
3851 case WM_EMACS_TOGGLE_LOCK_KEY:
3852 {
3853 int vk_code = (int) msg.wParam;
3854 int cur_state = (GetKeyState (vk_code) & 1);
3855 Lisp_Object new_state = (Lisp_Object) msg.lParam;
3856
3857 /* NB: This code must be thread-safe. It is safe to
3858 call NILP because symbols are not relocated by GC,
3859 and pointer here is not touched by GC (so the markbit
3860 can't be set). Numbers are safe because they are
3861 immediate values. */
3862 if (NILP (new_state)
3863 || (NUMBERP (new_state)
3864 && ((XUINT (new_state)) & 1) != cur_state))
3865 {
3866 one_w32_display_info.faked_key = vk_code;
3867
3868 keybd_event ((BYTE) vk_code,
3869 (BYTE) MapVirtualKey (vk_code, 0),
3870 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3871 keybd_event ((BYTE) vk_code,
3872 (BYTE) MapVirtualKey (vk_code, 0),
3873 KEYEVENTF_EXTENDEDKEY | 0, 0);
3874 keybd_event ((BYTE) vk_code,
3875 (BYTE) MapVirtualKey (vk_code, 0),
3876 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3877 cur_state = !cur_state;
3878 }
3879 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
3880 cur_state, 0))
3881 abort ();
3882 }
3883 break;
3884 default:
3885 DebPrint (("msg %x not expected by w32_msg_pump\n", msg.message));
3886 }
3887 }
3888 else
3889 {
3890 DispatchMessage (&msg);
3891 }
3892
3893 /* Exit nested loop when our deferred message has completed. */
3894 if (msg_buf->completed)
3895 break;
3896 }
3897 }
3898
3899 deferred_msg * deferred_msg_head;
3900
3901 static deferred_msg *
3902 find_deferred_msg (HWND hwnd, UINT msg)
3903 {
3904 deferred_msg * item;
3905
3906 /* Don't actually need synchronization for read access, since
3907 modification of single pointer is always atomic. */
3908 /* enter_crit (); */
3909
3910 for (item = deferred_msg_head; item != NULL; item = item->next)
3911 if (item->w32msg.msg.hwnd == hwnd
3912 && item->w32msg.msg.message == msg)
3913 break;
3914
3915 /* leave_crit (); */
3916
3917 return item;
3918 }
3919
3920 static LRESULT
3921 send_deferred_msg (deferred_msg * msg_buf,
3922 HWND hwnd,
3923 UINT msg,
3924 WPARAM wParam,
3925 LPARAM lParam)
3926 {
3927 /* Only input thread can send deferred messages. */
3928 if (GetCurrentThreadId () != dwWindowsThreadId)
3929 abort ();
3930
3931 /* It is an error to send a message that is already deferred. */
3932 if (find_deferred_msg (hwnd, msg) != NULL)
3933 abort ();
3934
3935 /* Enforced synchronization is not needed because this is the only
3936 function that alters deferred_msg_head, and the following critical
3937 section is guaranteed to only be serially reentered (since only the
3938 input thread can call us). */
3939
3940 /* enter_crit (); */
3941
3942 msg_buf->completed = 0;
3943 msg_buf->next = deferred_msg_head;
3944 deferred_msg_head = msg_buf;
3945 my_post_msg (&msg_buf->w32msg, hwnd, msg, wParam, lParam);
3946
3947 /* leave_crit (); */
3948
3949 /* Start a new nested message loop to process other messages until
3950 this one is completed. */
3951 w32_msg_pump (msg_buf);
3952
3953 deferred_msg_head = msg_buf->next;
3954
3955 return msg_buf->result;
3956 }
3957
3958 void
3959 complete_deferred_msg (HWND hwnd, UINT msg, LRESULT result)
3960 {
3961 deferred_msg * msg_buf = find_deferred_msg (hwnd, msg);
3962
3963 if (msg_buf == NULL)
3964 /* Message may have been cancelled, so don't abort(). */
3965 return;
3966
3967 msg_buf->result = result;
3968 msg_buf->completed = 1;
3969
3970 /* Ensure input thread is woken so it notices the completion. */
3971 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
3972 }
3973
3974 void
3975 cancel_all_deferred_msgs ()
3976 {
3977 deferred_msg * item;
3978
3979 /* Don't actually need synchronization for read access, since
3980 modification of single pointer is always atomic. */
3981 /* enter_crit (); */
3982
3983 for (item = deferred_msg_head; item != NULL; item = item->next)
3984 {
3985 item->result = 0;
3986 item->completed = 1;
3987 }
3988
3989 /* leave_crit (); */
3990
3991 /* Ensure input thread is woken so it notices the completion. */
3992 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
3993 }
3994
3995 DWORD
3996 w32_msg_worker (dw)
3997 DWORD dw;
3998 {
3999 MSG msg;
4000 deferred_msg dummy_buf;
4001
4002 /* Ensure our message queue is created */
4003
4004 PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
4005
4006 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
4007 abort ();
4008
4009 memset (&dummy_buf, 0, sizeof (dummy_buf));
4010 dummy_buf.w32msg.msg.hwnd = NULL;
4011 dummy_buf.w32msg.msg.message = WM_NULL;
4012
4013 /* This is the inital message loop which should only exit when the
4014 application quits. */
4015 w32_msg_pump (&dummy_buf);
4016
4017 return 0;
4018 }
4019
4020 static void
4021 post_character_message (hwnd, msg, wParam, lParam, modifiers)
4022 HWND hwnd;
4023 UINT msg;
4024 WPARAM wParam;
4025 LPARAM lParam;
4026 DWORD modifiers;
4027
4028 {
4029 W32Msg wmsg;
4030
4031 wmsg.dwModifiers = modifiers;
4032
4033 /* Detect quit_char and set quit-flag directly. Note that we
4034 still need to post a message to ensure the main thread will be
4035 woken up if blocked in sys_select(), but we do NOT want to post
4036 the quit_char message itself (because it will usually be as if
4037 the user had typed quit_char twice). Instead, we post a dummy
4038 message that has no particular effect. */
4039 {
4040 int c = wParam;
4041 if (isalpha (c) && wmsg.dwModifiers == ctrl_modifier)
4042 c = make_ctrl_char (c) & 0377;
4043 if (c == quit_char
4044 || (wmsg.dwModifiers == 0 &&
4045 XFASTINT (Vw32_quit_key) && wParam == XFASTINT (Vw32_quit_key)))
4046 {
4047 Vquit_flag = Qt;
4048
4049 /* The choice of message is somewhat arbitrary, as long as
4050 the main thread handler just ignores it. */
4051 msg = WM_NULL;
4052
4053 /* Interrupt any blocking system calls. */
4054 signal_quit ();
4055
4056 /* As a safety precaution, forcibly complete any deferred
4057 messages. This is a kludge, but I don't see any particularly
4058 clean way to handle the situation where a deferred message is
4059 "dropped" in the lisp thread, and will thus never be
4060 completed, eg. by the user trying to activate the menubar
4061 when the lisp thread is busy, and then typing C-g when the
4062 menubar doesn't open promptly (with the result that the
4063 menubar never responds at all because the deferred
4064 WM_INITMENU message is never completed). Another problem
4065 situation is when the lisp thread calls SendMessage (to send
4066 a window manager command) when a message has been deferred;
4067 the lisp thread gets blocked indefinitely waiting for the
4068 deferred message to be completed, which itself is waiting for
4069 the lisp thread to respond.
4070
4071 Note that we don't want to block the input thread waiting for
4072 a reponse from the lisp thread (although that would at least
4073 solve the deadlock problem above), because we want to be able
4074 to receive C-g to interrupt the lisp thread. */
4075 cancel_all_deferred_msgs ();
4076 }
4077 }
4078
4079 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4080 }
4081
4082 /* Main window procedure */
4083
4084 LRESULT CALLBACK
4085 w32_wnd_proc (hwnd, msg, wParam, lParam)
4086 HWND hwnd;
4087 UINT msg;
4088 WPARAM wParam;
4089 LPARAM lParam;
4090 {
4091 struct frame *f;
4092 struct w32_display_info *dpyinfo = &one_w32_display_info;
4093 W32Msg wmsg;
4094 int windows_translate;
4095 int key;
4096
4097 /* Note that it is okay to call x_window_to_frame, even though we are
4098 not running in the main lisp thread, because frame deletion
4099 requires the lisp thread to synchronize with this thread. Thus, if
4100 a frame struct is returned, it can be used without concern that the
4101 lisp thread might make it disappear while we are using it.
4102
4103 NB. Walking the frame list in this thread is safe (as long as
4104 writes of Lisp_Object slots are atomic, which they are on Windows).
4105 Although delete-frame can destructively modify the frame list while
4106 we are walking it, a garbage collection cannot occur until after
4107 delete-frame has synchronized with this thread.
4108
4109 It is also safe to use functions that make GDI calls, such as
4110 w32_clear_rect, because these functions must obtain a DC handle
4111 from the frame struct using get_frame_dc which is thread-aware. */
4112
4113 switch (msg)
4114 {
4115 case WM_ERASEBKGND:
4116 f = x_window_to_frame (dpyinfo, hwnd);
4117 if (f)
4118 {
4119 HDC hdc = get_frame_dc (f);
4120 GetUpdateRect (hwnd, &wmsg.rect, FALSE);
4121 w32_clear_rect (f, hdc, &wmsg.rect);
4122 release_frame_dc (f, hdc);
4123
4124 #if defined (W32_DEBUG_DISPLAY)
4125 DebPrint (("WM_ERASEBKGND (frame %p): erasing %d,%d-%d,%d\n",
4126 f,
4127 wmsg.rect.left, wmsg.rect.top,
4128 wmsg.rect.right, wmsg.rect.bottom));
4129 #endif /* W32_DEBUG_DISPLAY */
4130 }
4131 return 1;
4132 case WM_PALETTECHANGED:
4133 /* ignore our own changes */
4134 if ((HWND)wParam != hwnd)
4135 {
4136 f = x_window_to_frame (dpyinfo, hwnd);
4137 if (f)
4138 /* get_frame_dc will realize our palette and force all
4139 frames to be redrawn if needed. */
4140 release_frame_dc (f, get_frame_dc (f));
4141 }
4142 return 0;
4143 case WM_PAINT:
4144 {
4145 PAINTSTRUCT paintStruct;
4146 RECT update_rect;
4147
4148 f = x_window_to_frame (dpyinfo, hwnd);
4149 if (f == 0)
4150 {
4151 DebPrint (("WM_PAINT received for unknown window %p\n", hwnd));
4152 return 0;
4153 }
4154
4155 /* MSDN Docs say not to call BeginPaint if GetUpdateRect
4156 fails. Apparently this can happen under some
4157 circumstances. */
4158 if (!w32_strict_painting || GetUpdateRect (hwnd, &update_rect, FALSE))
4159 {
4160 enter_crit ();
4161 BeginPaint (hwnd, &paintStruct);
4162
4163 if (w32_strict_painting)
4164 /* The rectangles returned by GetUpdateRect and BeginPaint
4165 do not always match. GetUpdateRect seems to be the
4166 more reliable of the two. */
4167 wmsg.rect = update_rect;
4168 else
4169 wmsg.rect = paintStruct.rcPaint;
4170
4171 #if defined (W32_DEBUG_DISPLAY)
4172 DebPrint (("WM_PAINT (frame %p): painting %d,%d-%d,%d\n",
4173 f,
4174 wmsg.rect.left, wmsg.rect.top,
4175 wmsg.rect.right, wmsg.rect.bottom));
4176 DebPrint ((" [update region is %d,%d-%d,%d]\n",
4177 update_rect.left, update_rect.top,
4178 update_rect.right, update_rect.bottom));
4179 #endif
4180 EndPaint (hwnd, &paintStruct);
4181 leave_crit ();
4182
4183 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4184
4185 return 0;
4186 }
4187
4188 /* If GetUpdateRect returns 0 (meaning there is no update
4189 region), assume the whole window needs to be repainted. */
4190 GetClientRect(hwnd, &wmsg.rect);
4191 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4192 return 0;
4193 }
4194
4195 case WM_INPUTLANGCHANGE:
4196 /* Inform lisp thread of keyboard layout changes. */
4197 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4198
4199 /* Clear dead keys in the keyboard state; for simplicity only
4200 preserve modifier key states. */
4201 {
4202 int i;
4203 BYTE keystate[256];
4204
4205 GetKeyboardState (keystate);
4206 for (i = 0; i < 256; i++)
4207 if (1
4208 && i != VK_SHIFT
4209 && i != VK_LSHIFT
4210 && i != VK_RSHIFT
4211 && i != VK_CAPITAL
4212 && i != VK_NUMLOCK
4213 && i != VK_SCROLL
4214 && i != VK_CONTROL
4215 && i != VK_LCONTROL
4216 && i != VK_RCONTROL
4217 && i != VK_MENU
4218 && i != VK_LMENU
4219 && i != VK_RMENU
4220 && i != VK_LWIN
4221 && i != VK_RWIN)
4222 keystate[i] = 0;
4223 SetKeyboardState (keystate);
4224 }
4225 goto dflt;
4226
4227 case WM_HOTKEY:
4228 /* Synchronize hot keys with normal input. */
4229 PostMessage (hwnd, WM_KEYDOWN, HIWORD (lParam), 0);
4230 return (0);
4231
4232 case WM_KEYUP:
4233 case WM_SYSKEYUP:
4234 record_keyup (wParam, lParam);
4235 goto dflt;
4236
4237 case WM_KEYDOWN:
4238 case WM_SYSKEYDOWN:
4239 /* Ignore keystrokes we fake ourself; see below. */
4240 if (dpyinfo->faked_key == wParam)
4241 {
4242 dpyinfo->faked_key = 0;
4243 /* Make sure TranslateMessage sees them though (as long as
4244 they don't produce WM_CHAR messages). This ensures that
4245 indicator lights are toggled promptly on Windows 9x, for
4246 example. */
4247 if (lispy_function_keys[wParam] != 0)
4248 {
4249 windows_translate = 1;
4250 goto translate;
4251 }
4252 return 0;
4253 }
4254
4255 /* Synchronize modifiers with current keystroke. */
4256 sync_modifiers ();
4257 record_keydown (wParam, lParam);
4258 wParam = map_keypad_keys (wParam, (lParam & 0x1000000L) != 0);
4259
4260 windows_translate = 0;
4261
4262 switch (wParam)
4263 {
4264 case VK_LWIN:
4265 if (NILP (Vw32_pass_lwindow_to_system))
4266 {
4267 /* Prevent system from acting on keyup (which opens the
4268 Start menu if no other key was pressed) by simulating a
4269 press of Space which we will ignore. */
4270 if (GetAsyncKeyState (wParam) & 1)
4271 {
4272 if (NUMBERP (Vw32_phantom_key_code))
4273 key = XUINT (Vw32_phantom_key_code) & 255;
4274 else
4275 key = VK_SPACE;
4276 dpyinfo->faked_key = key;
4277 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
4278 }
4279 }
4280 if (!NILP (Vw32_lwindow_modifier))
4281 return 0;
4282 break;
4283 case VK_RWIN:
4284 if (NILP (Vw32_pass_rwindow_to_system))
4285 {
4286 if (GetAsyncKeyState (wParam) & 1)
4287 {
4288 if (NUMBERP (Vw32_phantom_key_code))
4289 key = XUINT (Vw32_phantom_key_code) & 255;
4290 else
4291 key = VK_SPACE;
4292 dpyinfo->faked_key = key;
4293 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
4294 }
4295 }
4296 if (!NILP (Vw32_rwindow_modifier))
4297 return 0;
4298 break;
4299 case VK_APPS:
4300 if (!NILP (Vw32_apps_modifier))
4301 return 0;
4302 break;
4303 case VK_MENU:
4304 if (NILP (Vw32_pass_alt_to_system))
4305 /* Prevent DefWindowProc from activating the menu bar if an
4306 Alt key is pressed and released by itself. */
4307 return 0;
4308 windows_translate = 1;
4309 break;
4310 case VK_CAPITAL:
4311 /* Decide whether to treat as modifier or function key. */
4312 if (NILP (Vw32_enable_caps_lock))
4313 goto disable_lock_key;
4314 windows_translate = 1;
4315 break;
4316 case VK_NUMLOCK:
4317 /* Decide whether to treat as modifier or function key. */
4318 if (NILP (Vw32_enable_num_lock))
4319 goto disable_lock_key;
4320 windows_translate = 1;
4321 break;
4322 case VK_SCROLL:
4323 /* Decide whether to treat as modifier or function key. */
4324 if (NILP (Vw32_scroll_lock_modifier))
4325 goto disable_lock_key;
4326 windows_translate = 1;
4327 break;
4328 disable_lock_key:
4329 /* Ensure the appropriate lock key state (and indicator light)
4330 remains in the same state. We do this by faking another
4331 press of the relevant key. Apparently, this really is the
4332 only way to toggle the state of the indicator lights. */
4333 dpyinfo->faked_key = wParam;
4334 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4335 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4336 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4337 KEYEVENTF_EXTENDEDKEY | 0, 0);
4338 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4339 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4340 /* Ensure indicator lights are updated promptly on Windows 9x
4341 (TranslateMessage apparently does this), after forwarding
4342 input event. */
4343 post_character_message (hwnd, msg, wParam, lParam,
4344 w32_get_key_modifiers (wParam, lParam));
4345 windows_translate = 1;
4346 break;
4347 case VK_CONTROL:
4348 case VK_SHIFT:
4349 case VK_PROCESSKEY: /* Generated by IME. */
4350 windows_translate = 1;
4351 break;
4352 case VK_CANCEL:
4353 /* Windows maps Ctrl-Pause (aka Ctrl-Break) into VK_CANCEL,
4354 which is confusing for purposes of key binding; convert
4355 VK_CANCEL events into VK_PAUSE events. */
4356 wParam = VK_PAUSE;
4357 break;
4358 case VK_PAUSE:
4359 /* Windows maps Ctrl-NumLock into VK_PAUSE, which is confusing
4360 for purposes of key binding; convert these back into
4361 VK_NUMLOCK events, at least when we want to see NumLock key
4362 presses. (Note that there is never any possibility that
4363 VK_PAUSE with Ctrl really is C-Pause as per above.) */
4364 if (NILP (Vw32_enable_num_lock) && modifier_set (VK_CONTROL))
4365 wParam = VK_NUMLOCK;
4366 break;
4367 default:
4368 /* If not defined as a function key, change it to a WM_CHAR message. */
4369 if (lispy_function_keys[wParam] == 0)
4370 {
4371 DWORD modifiers = construct_console_modifiers ();
4372
4373 if (!NILP (Vw32_recognize_altgr)
4374 && modifier_set (VK_LCONTROL) && modifier_set (VK_RMENU))
4375 {
4376 /* Always let TranslateMessage handle AltGr key chords;
4377 for some reason, ToAscii doesn't always process AltGr
4378 chords correctly. */
4379 windows_translate = 1;
4380 }
4381 else if ((modifiers & (~SHIFT_PRESSED & ~CAPSLOCK_ON)) != 0)
4382 {
4383 /* Handle key chords including any modifiers other
4384 than shift directly, in order to preserve as much
4385 modifier information as possible. */
4386 if ('A' <= wParam && wParam <= 'Z')
4387 {
4388 /* Don't translate modified alphabetic keystrokes,
4389 so the user doesn't need to constantly switch
4390 layout to type control or meta keystrokes when
4391 the normal layout translates alphabetic
4392 characters to non-ascii characters. */
4393 if (!modifier_set (VK_SHIFT))
4394 wParam += ('a' - 'A');
4395 msg = WM_CHAR;
4396 }
4397 else
4398 {
4399 /* Try to handle other keystrokes by determining the
4400 base character (ie. translating the base key plus
4401 shift modifier). */
4402 int add;
4403 int isdead = 0;
4404 KEY_EVENT_RECORD key;
4405
4406 key.bKeyDown = TRUE;
4407 key.wRepeatCount = 1;
4408 key.wVirtualKeyCode = wParam;
4409 key.wVirtualScanCode = (lParam & 0xFF0000) >> 16;
4410 key.uChar.AsciiChar = 0;
4411 key.dwControlKeyState = modifiers;
4412
4413 add = w32_kbd_patch_key (&key);
4414 /* 0 means an unrecognised keycode, negative means
4415 dead key. Ignore both. */
4416 while (--add >= 0)
4417 {
4418 /* Forward asciified character sequence. */
4419 post_character_message
4420 (hwnd, WM_CHAR, key.uChar.AsciiChar, lParam,
4421 w32_get_key_modifiers (wParam, lParam));
4422 w32_kbd_patch_key (&key);
4423 }
4424 return 0;
4425 }
4426 }
4427 else
4428 {
4429 /* Let TranslateMessage handle everything else. */
4430 windows_translate = 1;
4431 }
4432 }
4433 }
4434
4435 translate:
4436 if (windows_translate)
4437 {
4438 MSG windows_msg = { hwnd, msg, wParam, lParam, 0, {0,0} };
4439
4440 windows_msg.time = GetMessageTime ();
4441 TranslateMessage (&windows_msg);
4442 goto dflt;
4443 }
4444
4445 /* Fall through */
4446
4447 case WM_SYSCHAR:
4448 case WM_CHAR:
4449 post_character_message (hwnd, msg, wParam, lParam,
4450 w32_get_key_modifiers (wParam, lParam));
4451 break;
4452
4453 /* Simulate middle mouse button events when left and right buttons
4454 are used together, but only if user has two button mouse. */
4455 case WM_LBUTTONDOWN:
4456 case WM_RBUTTONDOWN:
4457 if (XINT (Vw32_num_mouse_buttons) > 2)
4458 goto handle_plain_button;
4459
4460 {
4461 int this = (msg == WM_LBUTTONDOWN) ? LMOUSE : RMOUSE;
4462 int other = (msg == WM_LBUTTONDOWN) ? RMOUSE : LMOUSE;
4463
4464 if (button_state & this)
4465 return 0;
4466
4467 if (button_state == 0)
4468 SetCapture (hwnd);
4469
4470 button_state |= this;
4471
4472 if (button_state & other)
4473 {
4474 if (mouse_button_timer)
4475 {
4476 KillTimer (hwnd, mouse_button_timer);
4477 mouse_button_timer = 0;
4478
4479 /* Generate middle mouse event instead. */
4480 msg = WM_MBUTTONDOWN;
4481 button_state |= MMOUSE;
4482 }
4483 else if (button_state & MMOUSE)
4484 {
4485 /* Ignore button event if we've already generated a
4486 middle mouse down event. This happens if the
4487 user releases and press one of the two buttons
4488 after we've faked a middle mouse event. */
4489 return 0;
4490 }
4491 else
4492 {
4493 /* Flush out saved message. */
4494 post_msg (&saved_mouse_button_msg);
4495 }
4496 wmsg.dwModifiers = w32_get_modifiers ();
4497 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4498
4499 /* Clear message buffer. */
4500 saved_mouse_button_msg.msg.hwnd = 0;
4501 }
4502 else
4503 {
4504 /* Hold onto message for now. */
4505 mouse_button_timer =
4506 SetTimer (hwnd, MOUSE_BUTTON_ID,
4507 XINT (Vw32_mouse_button_tolerance), NULL);
4508 saved_mouse_button_msg.msg.hwnd = hwnd;
4509 saved_mouse_button_msg.msg.message = msg;
4510 saved_mouse_button_msg.msg.wParam = wParam;
4511 saved_mouse_button_msg.msg.lParam = lParam;
4512 saved_mouse_button_msg.msg.time = GetMessageTime ();
4513 saved_mouse_button_msg.dwModifiers = w32_get_modifiers ();
4514 }
4515 }
4516 return 0;
4517
4518 case WM_LBUTTONUP:
4519 case WM_RBUTTONUP:
4520 if (XINT (Vw32_num_mouse_buttons) > 2)
4521 goto handle_plain_button;
4522
4523 {
4524 int this = (msg == WM_LBUTTONUP) ? LMOUSE : RMOUSE;
4525 int other = (msg == WM_LBUTTONUP) ? RMOUSE : LMOUSE;
4526
4527 if ((button_state & this) == 0)
4528 return 0;
4529
4530 button_state &= ~this;
4531
4532 if (button_state & MMOUSE)
4533 {
4534 /* Only generate event when second button is released. */
4535 if ((button_state & other) == 0)
4536 {
4537 msg = WM_MBUTTONUP;
4538 button_state &= ~MMOUSE;
4539
4540 if (button_state) abort ();
4541 }
4542 else
4543 return 0;
4544 }
4545 else
4546 {
4547 /* Flush out saved message if necessary. */
4548 if (saved_mouse_button_msg.msg.hwnd)
4549 {
4550 post_msg (&saved_mouse_button_msg);
4551 }
4552 }
4553 wmsg.dwModifiers = w32_get_modifiers ();
4554 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4555
4556 /* Always clear message buffer and cancel timer. */
4557 saved_mouse_button_msg.msg.hwnd = 0;
4558 KillTimer (hwnd, mouse_button_timer);
4559 mouse_button_timer = 0;
4560
4561 if (button_state == 0)
4562 ReleaseCapture ();
4563 }
4564 return 0;
4565
4566 case WM_MBUTTONDOWN:
4567 case WM_MBUTTONUP:
4568 handle_plain_button:
4569 {
4570 BOOL up;
4571 int button;
4572
4573 if (parse_button (msg, &button, &up))
4574 {
4575 if (up) ReleaseCapture ();
4576 else SetCapture (hwnd);
4577 button = (button == 0) ? LMOUSE :
4578 ((button == 1) ? MMOUSE : RMOUSE);
4579 if (up)
4580 button_state &= ~button;
4581 else
4582 button_state |= button;
4583 }
4584 }
4585
4586 wmsg.dwModifiers = w32_get_modifiers ();
4587 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4588 return 0;
4589
4590 case WM_MOUSEMOVE:
4591 /* If the mouse has just moved into the frame, start tracking
4592 it, so we will be notified when it leaves the frame. Mouse
4593 tracking only works under W98 and NT4 and later. On earlier
4594 versions, there is no way of telling when the mouse leaves the
4595 frame, so we just have to put up with help-echo and mouse
4596 highlighting remaining while the frame is not active. */
4597 if (track_mouse_event_fn && !track_mouse_window)
4598 {
4599 TRACKMOUSEEVENT tme;
4600 tme.cbSize = sizeof (tme);
4601 tme.dwFlags = TME_LEAVE;
4602 tme.hwndTrack = hwnd;
4603
4604 track_mouse_event_fn (&tme);
4605 track_mouse_window = hwnd;
4606 }
4607 case WM_VSCROLL:
4608 if (XINT (Vw32_mouse_move_interval) <= 0
4609 || (msg == WM_MOUSEMOVE && button_state == 0))
4610 {
4611 wmsg.dwModifiers = w32_get_modifiers ();
4612 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4613 return 0;
4614 }
4615
4616 /* Hang onto mouse move and scroll messages for a bit, to avoid
4617 sending such events to Emacs faster than it can process them.
4618 If we get more events before the timer from the first message
4619 expires, we just replace the first message. */
4620
4621 if (saved_mouse_move_msg.msg.hwnd == 0)
4622 mouse_move_timer =
4623 SetTimer (hwnd, MOUSE_MOVE_ID,
4624 XINT (Vw32_mouse_move_interval), NULL);
4625
4626 /* Hold onto message for now. */
4627 saved_mouse_move_msg.msg.hwnd = hwnd;
4628 saved_mouse_move_msg.msg.message = msg;
4629 saved_mouse_move_msg.msg.wParam = wParam;
4630 saved_mouse_move_msg.msg.lParam = lParam;
4631 saved_mouse_move_msg.msg.time = GetMessageTime ();
4632 saved_mouse_move_msg.dwModifiers = w32_get_modifiers ();
4633
4634 return 0;
4635
4636 case WM_MOUSEWHEEL:
4637 wmsg.dwModifiers = w32_get_modifiers ();
4638 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4639 return 0;
4640
4641 case WM_DROPFILES:
4642 wmsg.dwModifiers = w32_get_modifiers ();
4643 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4644 return 0;
4645
4646 case WM_TIMER:
4647 /* Flush out saved messages if necessary. */
4648 if (wParam == mouse_button_timer)
4649 {
4650 if (saved_mouse_button_msg.msg.hwnd)
4651 {
4652 post_msg (&saved_mouse_button_msg);
4653 saved_mouse_button_msg.msg.hwnd = 0;
4654 }
4655 KillTimer (hwnd, mouse_button_timer);
4656 mouse_button_timer = 0;
4657 }
4658 else if (wParam == mouse_move_timer)
4659 {
4660 if (saved_mouse_move_msg.msg.hwnd)
4661 {
4662 post_msg (&saved_mouse_move_msg);
4663 saved_mouse_move_msg.msg.hwnd = 0;
4664 }
4665 KillTimer (hwnd, mouse_move_timer);
4666 mouse_move_timer = 0;
4667 }
4668 return 0;
4669
4670 case WM_NCACTIVATE:
4671 /* Windows doesn't send us focus messages when putting up and
4672 taking down a system popup dialog as for Ctrl-Alt-Del on Windows 95.
4673 The only indication we get that something happened is receiving
4674 this message afterwards. So this is a good time to reset our
4675 keyboard modifiers' state. */
4676 reset_modifiers ();
4677 goto dflt;
4678
4679 case WM_INITMENU:
4680 button_state = 0;
4681 ReleaseCapture ();
4682 /* We must ensure menu bar is fully constructed and up to date
4683 before allowing user interaction with it. To achieve this
4684 we send this message to the lisp thread and wait for a
4685 reply (whose value is not actually needed) to indicate that
4686 the menu bar is now ready for use, so we can now return.
4687
4688 To remain responsive in the meantime, we enter a nested message
4689 loop that can process all other messages.
4690
4691 However, we skip all this if the message results from calling
4692 TrackPopupMenu - in fact, we must NOT attempt to send the lisp
4693 thread a message because it is blocked on us at this point. We
4694 set menubar_active before calling TrackPopupMenu to indicate
4695 this (there is no possibility of confusion with real menubar
4696 being active). */
4697
4698 f = x_window_to_frame (dpyinfo, hwnd);
4699 if (f
4700 && (f->output_data.w32->menubar_active
4701 /* We can receive this message even in the absence of a
4702 menubar (ie. when the system menu is activated) - in this
4703 case we do NOT want to forward the message, otherwise it
4704 will cause the menubar to suddenly appear when the user
4705 had requested it to be turned off! */
4706 || f->output_data.w32->menubar_widget == NULL))
4707 return 0;
4708
4709 {
4710 deferred_msg msg_buf;
4711
4712 /* Detect if message has already been deferred; in this case
4713 we cannot return any sensible value to ignore this. */
4714 if (find_deferred_msg (hwnd, msg) != NULL)
4715 abort ();
4716
4717 return send_deferred_msg (&msg_buf, hwnd, msg, wParam, lParam);
4718 }
4719
4720 case WM_EXITMENULOOP:
4721 f = x_window_to_frame (dpyinfo, hwnd);
4722
4723 /* Free memory used by owner-drawn and help-echo strings. */
4724 w32_free_menu_strings (hwnd);
4725
4726 /* Indicate that menubar can be modified again. */
4727 if (f)
4728 f->output_data.w32->menubar_active = 0;
4729 goto dflt;
4730
4731 case WM_MENUSELECT:
4732 /* Direct handling of help_echo in menus. Should be safe now
4733 that we generate the help_echo by placing a help event in the
4734 keyboard buffer. */
4735 {
4736 HMENU menu = (HMENU) lParam;
4737 UINT menu_item = (UINT) LOWORD (wParam);
4738 UINT flags = (UINT) HIWORD (wParam);
4739
4740 w32_menu_display_help (hwnd, menu, menu_item, flags);
4741 }
4742 return 0;
4743
4744 case WM_MEASUREITEM:
4745 f = x_window_to_frame (dpyinfo, hwnd);
4746 if (f)
4747 {
4748 MEASUREITEMSTRUCT * pMis = (MEASUREITEMSTRUCT *) lParam;
4749
4750 if (pMis->CtlType == ODT_MENU)
4751 {
4752 /* Work out dimensions for popup menu titles. */
4753 char * title = (char *) pMis->itemData;
4754 HDC hdc = GetDC (hwnd);
4755 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4756 LOGFONT menu_logfont;
4757 HFONT old_font;
4758 SIZE size;
4759
4760 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4761 menu_logfont.lfWeight = FW_BOLD;
4762 menu_font = CreateFontIndirect (&menu_logfont);
4763 old_font = SelectObject (hdc, menu_font);
4764
4765 pMis->itemHeight = GetSystemMetrics (SM_CYMENUSIZE);
4766 if (title)
4767 {
4768 GetTextExtentPoint32 (hdc, title, strlen (title), &size);
4769 pMis->itemWidth = size.cx;
4770 if (pMis->itemHeight < size.cy)
4771 pMis->itemHeight = size.cy;
4772 }
4773 else
4774 pMis->itemWidth = 0;
4775
4776 SelectObject (hdc, old_font);
4777 DeleteObject (menu_font);
4778 ReleaseDC (hwnd, hdc);
4779 return TRUE;
4780 }
4781 }
4782 return 0;
4783
4784 case WM_DRAWITEM:
4785 f = x_window_to_frame (dpyinfo, hwnd);
4786 if (f)
4787 {
4788 DRAWITEMSTRUCT * pDis = (DRAWITEMSTRUCT *) lParam;
4789
4790 if (pDis->CtlType == ODT_MENU)
4791 {
4792 /* Draw popup menu title. */
4793 char * title = (char *) pDis->itemData;
4794 if (title)
4795 {
4796 HDC hdc = pDis->hDC;
4797 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4798 LOGFONT menu_logfont;
4799 HFONT old_font;
4800
4801 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4802 menu_logfont.lfWeight = FW_BOLD;
4803 menu_font = CreateFontIndirect (&menu_logfont);
4804 old_font = SelectObject (hdc, menu_font);
4805
4806 /* Always draw title as if not selected. */
4807 ExtTextOut (hdc,
4808 pDis->rcItem.left
4809 + GetSystemMetrics (SM_CXMENUCHECK),
4810 pDis->rcItem.top,
4811 ETO_OPAQUE, &pDis->rcItem,
4812 title, strlen (title), NULL);
4813
4814 SelectObject (hdc, old_font);
4815 DeleteObject (menu_font);
4816 }
4817 return TRUE;
4818 }
4819 }
4820 return 0;
4821
4822 #if 0
4823 /* Still not right - can't distinguish between clicks in the
4824 client area of the frame from clicks forwarded from the scroll
4825 bars - may have to hook WM_NCHITTEST to remember the mouse
4826 position and then check if it is in the client area ourselves. */
4827 case WM_MOUSEACTIVATE:
4828 /* Discard the mouse click that activates a frame, allowing the
4829 user to click anywhere without changing point (or worse!).
4830 Don't eat mouse clicks on scrollbars though!! */
4831 if (LOWORD (lParam) == HTCLIENT )
4832 return MA_ACTIVATEANDEAT;
4833 goto dflt;
4834 #endif
4835
4836 case WM_MOUSELEAVE:
4837 /* No longer tracking mouse. */
4838 track_mouse_window = NULL;
4839
4840 case WM_ACTIVATEAPP:
4841 case WM_ACTIVATE:
4842 case WM_WINDOWPOSCHANGED:
4843 case WM_SHOWWINDOW:
4844 /* Inform lisp thread that a frame might have just been obscured
4845 or exposed, so should recheck visibility of all frames. */
4846 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4847 goto dflt;
4848
4849 case WM_SETFOCUS:
4850 dpyinfo->faked_key = 0;
4851 reset_modifiers ();
4852 register_hot_keys (hwnd);
4853 goto command;
4854 case WM_KILLFOCUS:
4855 unregister_hot_keys (hwnd);
4856 button_state = 0;
4857 ReleaseCapture ();
4858 /* Relinquish the system caret. */
4859 if (w32_system_caret_hwnd)
4860 {
4861 DestroyCaret ();
4862 w32_system_caret_hwnd = NULL;
4863 }
4864 case WM_MOVE:
4865 case WM_SIZE:
4866 case WM_COMMAND:
4867 command:
4868 wmsg.dwModifiers = w32_get_modifiers ();
4869 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4870 goto dflt;
4871
4872 case WM_CLOSE:
4873 wmsg.dwModifiers = w32_get_modifiers ();
4874 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4875 return 0;
4876
4877 case WM_WINDOWPOSCHANGING:
4878 /* Don't restrict the sizing of tip frames. */
4879 if (hwnd == tip_window)
4880 return 0;
4881 {
4882 WINDOWPLACEMENT wp;
4883 LPWINDOWPOS lppos = (WINDOWPOS *) lParam;
4884
4885 wp.length = sizeof (WINDOWPLACEMENT);
4886 GetWindowPlacement (hwnd, &wp);
4887
4888 if (wp.showCmd != SW_SHOWMINIMIZED && (lppos->flags & SWP_NOSIZE) == 0)
4889 {
4890 RECT rect;
4891 int wdiff;
4892 int hdiff;
4893 DWORD font_width;
4894 DWORD line_height;
4895 DWORD internal_border;
4896 DWORD scrollbar_extra;
4897 RECT wr;
4898
4899 wp.length = sizeof(wp);
4900 GetWindowRect (hwnd, &wr);
4901
4902 enter_crit ();
4903
4904 font_width = GetWindowLong (hwnd, WND_FONTWIDTH_INDEX);
4905 line_height = GetWindowLong (hwnd, WND_LINEHEIGHT_INDEX);
4906 internal_border = GetWindowLong (hwnd, WND_BORDER_INDEX);
4907 scrollbar_extra = GetWindowLong (hwnd, WND_SCROLLBAR_INDEX);
4908
4909 leave_crit ();
4910
4911 memset (&rect, 0, sizeof (rect));
4912 AdjustWindowRect (&rect, GetWindowLong (hwnd, GWL_STYLE),
4913 GetMenu (hwnd) != NULL);
4914
4915 /* Force width and height of client area to be exact
4916 multiples of the character cell dimensions. */
4917 wdiff = (lppos->cx - (rect.right - rect.left)
4918 - 2 * internal_border - scrollbar_extra)
4919 % font_width;
4920 hdiff = (lppos->cy - (rect.bottom - rect.top)
4921 - 2 * internal_border)
4922 % line_height;
4923
4924 if (wdiff || hdiff)
4925 {
4926 /* For right/bottom sizing we can just fix the sizes.
4927 However for top/left sizing we will need to fix the X
4928 and Y positions as well. */
4929
4930 lppos->cx -= wdiff;
4931 lppos->cy -= hdiff;
4932
4933 if (wp.showCmd != SW_SHOWMAXIMIZED
4934 && (lppos->flags & SWP_NOMOVE) == 0)
4935 {
4936 if (lppos->x != wr.left || lppos->y != wr.top)
4937 {
4938 lppos->x += wdiff;
4939 lppos->y += hdiff;
4940 }
4941 else
4942 {
4943 lppos->flags |= SWP_NOMOVE;
4944 }
4945 }
4946
4947 return 0;
4948 }
4949 }
4950 }
4951
4952 goto dflt;
4953
4954 case WM_GETMINMAXINFO:
4955 /* Hack to correct bug that allows Emacs frames to be resized
4956 below the Minimum Tracking Size. */
4957 ((LPMINMAXINFO) lParam)->ptMinTrackSize.y++;
4958 /* Hack to allow resizing the Emacs frame above the screen size.
4959 Note that Windows 9x limits coordinates to 16-bits. */
4960 ((LPMINMAXINFO) lParam)->ptMaxTrackSize.x = 32767;
4961 ((LPMINMAXINFO) lParam)->ptMaxTrackSize.y = 32767;
4962 return 0;
4963
4964 case WM_EMACS_CREATESCROLLBAR:
4965 return (LRESULT) w32_createscrollbar ((struct frame *) wParam,
4966 (struct scroll_bar *) lParam);
4967
4968 case WM_EMACS_SHOWWINDOW:
4969 return ShowWindow ((HWND) wParam, (WPARAM) lParam);
4970
4971 case WM_EMACS_SETFOREGROUND:
4972 {
4973 HWND foreground_window;
4974 DWORD foreground_thread, retval;
4975
4976 /* On NT 5.0, and apparently Windows 98, it is necessary to
4977 attach to the thread that currently has focus in order to
4978 pull the focus away from it. */
4979 foreground_window = GetForegroundWindow ();
4980 foreground_thread = GetWindowThreadProcessId (foreground_window, NULL);
4981 if (!foreground_window
4982 || foreground_thread == GetCurrentThreadId ()
4983 || !AttachThreadInput (GetCurrentThreadId (),
4984 foreground_thread, TRUE))
4985 foreground_thread = 0;
4986
4987 retval = SetForegroundWindow ((HWND) wParam);
4988
4989 /* Detach from the previous foreground thread. */
4990 if (foreground_thread)
4991 AttachThreadInput (GetCurrentThreadId (),
4992 foreground_thread, FALSE);
4993
4994 return retval;
4995 }
4996
4997 case WM_EMACS_SETWINDOWPOS:
4998 {
4999 WINDOWPOS * pos = (WINDOWPOS *) wParam;
5000 return SetWindowPos (hwnd, pos->hwndInsertAfter,
5001 pos->x, pos->y, pos->cx, pos->cy, pos->flags);
5002 }
5003
5004 case WM_EMACS_DESTROYWINDOW:
5005 DragAcceptFiles ((HWND) wParam, FALSE);
5006 return DestroyWindow ((HWND) wParam);
5007
5008 case WM_EMACS_DESTROY_CARET:
5009 w32_system_caret_hwnd = NULL;
5010 return DestroyCaret ();
5011
5012 case WM_EMACS_TRACK_CARET:
5013 /* If there is currently no system caret, create one. */
5014 if (w32_system_caret_hwnd == NULL)
5015 {
5016 w32_system_caret_hwnd = hwnd;
5017 CreateCaret (hwnd, NULL, w32_system_caret_width,
5018 w32_system_caret_height);
5019 }
5020 return SetCaretPos (w32_system_caret_x, w32_system_caret_y);
5021
5022 case WM_EMACS_TRACKPOPUPMENU:
5023 {
5024 UINT flags;
5025 POINT *pos;
5026 int retval;
5027 pos = (POINT *)lParam;
5028 flags = TPM_CENTERALIGN;
5029 if (button_state & LMOUSE)
5030 flags |= TPM_LEFTBUTTON;
5031 else if (button_state & RMOUSE)
5032 flags |= TPM_RIGHTBUTTON;
5033
5034 /* Remember we did a SetCapture on the initial mouse down event,
5035 so for safety, we make sure the capture is cancelled now. */
5036 ReleaseCapture ();
5037 button_state = 0;
5038
5039 /* Use menubar_active to indicate that WM_INITMENU is from
5040 TrackPopupMenu below, and should be ignored. */
5041 f = x_window_to_frame (dpyinfo, hwnd);
5042 if (f)
5043 f->output_data.w32->menubar_active = 1;
5044
5045 if (TrackPopupMenu ((HMENU)wParam, flags, pos->x, pos->y,
5046 0, hwnd, NULL))
5047 {
5048 MSG amsg;
5049 /* Eat any mouse messages during popupmenu */
5050 while (PeekMessage (&amsg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST,
5051 PM_REMOVE));
5052 /* Get the menu selection, if any */
5053 if (PeekMessage (&amsg, hwnd, WM_COMMAND, WM_COMMAND, PM_REMOVE))
5054 {
5055 retval = LOWORD (amsg.wParam);
5056 }
5057 else
5058 {
5059 retval = 0;
5060 }
5061 }
5062 else
5063 {
5064 retval = -1;
5065 }
5066
5067 return retval;
5068 }
5069
5070 default:
5071 /* Check for messages registered at runtime. */
5072 if (msg == msh_mousewheel)
5073 {
5074 wmsg.dwModifiers = w32_get_modifiers ();
5075 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
5076 return 0;
5077 }
5078
5079 dflt:
5080 return DefWindowProc (hwnd, msg, wParam, lParam);
5081 }
5082
5083
5084 /* The most common default return code for handled messages is 0. */
5085 return 0;
5086 }
5087
5088 void
5089 my_create_window (f)
5090 struct frame * f;
5091 {
5092 MSG msg;
5093
5094 if (!PostThreadMessage (dwWindowsThreadId, WM_EMACS_CREATEWINDOW, (WPARAM)f, 0))
5095 abort ();
5096 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
5097 }
5098
5099
5100 /* Create a tooltip window. Unlike my_create_window, we do not do this
5101 indirectly via the Window thread, as we do not need to process Window
5102 messages for the tooltip. Creating tooltips indirectly also creates
5103 deadlocks when tooltips are created for menu items. */
5104 void
5105 my_create_tip_window (f)
5106 struct frame *f;
5107 {
5108 RECT rect;
5109
5110 rect.left = rect.top = 0;
5111 rect.right = PIXEL_WIDTH (f);
5112 rect.bottom = PIXEL_HEIGHT (f);
5113
5114 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
5115 FRAME_EXTERNAL_MENU_BAR (f));
5116
5117 tip_window = FRAME_W32_WINDOW (f)
5118 = CreateWindow (EMACS_CLASS,
5119 f->namebuf,
5120 f->output_data.w32->dwStyle,
5121 f->output_data.w32->left_pos,
5122 f->output_data.w32->top_pos,
5123 rect.right - rect.left,
5124 rect.bottom - rect.top,
5125 FRAME_W32_WINDOW (SELECTED_FRAME ()), /* owner */
5126 NULL,
5127 hinst,
5128 NULL);
5129
5130 if (tip_window)
5131 {
5132 SetWindowLong (tip_window, WND_FONTWIDTH_INDEX, FONT_WIDTH (f->output_data.w32->font));
5133 SetWindowLong (tip_window, WND_LINEHEIGHT_INDEX, f->output_data.w32->line_height);
5134 SetWindowLong (tip_window, WND_BORDER_INDEX, f->output_data.w32->internal_border_width);
5135 SetWindowLong (tip_window, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f));
5136
5137 /* Tip frames have no scrollbars. */
5138 SetWindowLong (tip_window, WND_SCROLLBAR_INDEX, 0);
5139
5140 /* Do this to discard the default setting specified by our parent. */
5141 ShowWindow (tip_window, SW_HIDE);
5142 }
5143 }
5144
5145
5146 /* Create and set up the w32 window for frame F. */
5147
5148 static void
5149 w32_window (f, window_prompting, minibuffer_only)
5150 struct frame *f;
5151 long window_prompting;
5152 int minibuffer_only;
5153 {
5154 BLOCK_INPUT;
5155
5156 /* Use the resource name as the top-level window name
5157 for looking up resources. Make a non-Lisp copy
5158 for the window manager, so GC relocation won't bother it.
5159
5160 Elsewhere we specify the window name for the window manager. */
5161
5162 {
5163 char *str = (char *) XSTRING (Vx_resource_name)->data;
5164 f->namebuf = (char *) xmalloc (strlen (str) + 1);
5165 strcpy (f->namebuf, str);
5166 }
5167
5168 my_create_window (f);
5169
5170 validate_x_resource_name ();
5171
5172 /* x_set_name normally ignores requests to set the name if the
5173 requested name is the same as the current name. This is the one
5174 place where that assumption isn't correct; f->name is set, but
5175 the server hasn't been told. */
5176 {
5177 Lisp_Object name;
5178 int explicit = f->explicit_name;
5179
5180 f->explicit_name = 0;
5181 name = f->name;
5182 f->name = Qnil;
5183 x_set_name (f, name, explicit);
5184 }
5185
5186 UNBLOCK_INPUT;
5187
5188 if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f))
5189 initialize_frame_menubar (f);
5190
5191 if (FRAME_W32_WINDOW (f) == 0)
5192 error ("Unable to create window");
5193 }
5194
5195 /* Handle the icon stuff for this window. Perhaps later we might
5196 want an x_set_icon_position which can be called interactively as
5197 well. */
5198
5199 static void
5200 x_icon (f, parms)
5201 struct frame *f;
5202 Lisp_Object parms;
5203 {
5204 Lisp_Object icon_x, icon_y;
5205
5206 /* Set the position of the icon. Note that Windows 95 groups all
5207 icons in the tray. */
5208 icon_x = w32_get_arg (parms, Qicon_left, 0, 0, RES_TYPE_NUMBER);
5209 icon_y = w32_get_arg (parms, Qicon_top, 0, 0, RES_TYPE_NUMBER);
5210 if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
5211 {
5212 CHECK_NUMBER (icon_x);
5213 CHECK_NUMBER (icon_y);
5214 }
5215 else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
5216 error ("Both left and top icon corners of icon must be specified");
5217
5218 BLOCK_INPUT;
5219
5220 if (! EQ (icon_x, Qunbound))
5221 x_wm_set_icon_position (f, XINT (icon_x), XINT (icon_y));
5222
5223 #if 0 /* TODO */
5224 /* Start up iconic or window? */
5225 x_wm_set_window_state
5226 (f, (EQ (w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL), Qicon)
5227 ? IconicState
5228 : NormalState));
5229
5230 x_text_icon (f, (char *) XSTRING ((!NILP (f->icon_name)
5231 ? f->icon_name
5232 : f->name))->data);
5233 #endif
5234
5235 UNBLOCK_INPUT;
5236 }
5237
5238
5239 static void
5240 x_make_gc (f)
5241 struct frame *f;
5242 {
5243 XGCValues gc_values;
5244
5245 BLOCK_INPUT;
5246
5247 /* Create the GC's of this frame.
5248 Note that many default values are used. */
5249
5250 /* Normal video */
5251 gc_values.font = f->output_data.w32->font;
5252
5253 /* Cursor has cursor-color background, background-color foreground. */
5254 gc_values.foreground = FRAME_BACKGROUND_PIXEL (f);
5255 gc_values.background = f->output_data.w32->cursor_pixel;
5256 f->output_data.w32->cursor_gc
5257 = XCreateGC (NULL, FRAME_W32_WINDOW (f),
5258 (GCFont | GCForeground | GCBackground),
5259 &gc_values);
5260
5261 /* Reliefs. */
5262 f->output_data.w32->white_relief.gc = 0;
5263 f->output_data.w32->black_relief.gc = 0;
5264
5265 UNBLOCK_INPUT;
5266 }
5267
5268
5269 /* Handler for signals raised during x_create_frame and
5270 x_create_top_frame. FRAME is the frame which is partially
5271 constructed. */
5272
5273 static Lisp_Object
5274 unwind_create_frame (frame)
5275 Lisp_Object frame;
5276 {
5277 struct frame *f = XFRAME (frame);
5278
5279 /* If frame is ``official'', nothing to do. */
5280 if (!CONSP (Vframe_list) || !EQ (XCAR (Vframe_list), frame))
5281 {
5282 #ifdef GLYPH_DEBUG
5283 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
5284 #endif
5285
5286 x_free_frame_resources (f);
5287
5288 /* Check that reference counts are indeed correct. */
5289 xassert (dpyinfo->reference_count == dpyinfo_refcount);
5290 xassert (dpyinfo->image_cache->refcount == image_cache_refcount);
5291
5292 return Qt;
5293 }
5294
5295 return Qnil;
5296 }
5297
5298
5299 DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
5300 1, 1, 0,
5301 doc: /* Make a new window, which is called a \"frame\" in Emacs terms.
5302 Returns an Emacs frame object.
5303 ALIST is an alist of frame parameters.
5304 If the parameters specify that the frame should not have a minibuffer,
5305 and do not specify a specific minibuffer window to use,
5306 then `default-minibuffer-frame' must be a frame whose minibuffer can
5307 be shared by the new frame.
5308
5309 This function is an internal primitive--use `make-frame' instead. */)
5310 (parms)
5311 Lisp_Object parms;
5312 {
5313 struct frame *f;
5314 Lisp_Object frame, tem;
5315 Lisp_Object name;
5316 int minibuffer_only = 0;
5317 long window_prompting = 0;
5318 int width, height;
5319 int count = BINDING_STACK_SIZE ();
5320 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
5321 Lisp_Object display;
5322 struct w32_display_info *dpyinfo = NULL;
5323 Lisp_Object parent;
5324 struct kboard *kb;
5325
5326 check_w32 ();
5327
5328 /* Use this general default value to start with
5329 until we know if this frame has a specified name. */
5330 Vx_resource_name = Vinvocation_name;
5331
5332 display = w32_get_arg (parms, Qdisplay, 0, 0, RES_TYPE_STRING);
5333 if (EQ (display, Qunbound))
5334 display = Qnil;
5335 dpyinfo = check_x_display_info (display);
5336 #ifdef MULTI_KBOARD
5337 kb = dpyinfo->kboard;
5338 #else
5339 kb = &the_only_kboard;
5340 #endif
5341
5342 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
5343 if (!STRINGP (name)
5344 && ! EQ (name, Qunbound)
5345 && ! NILP (name))
5346 error ("Invalid frame name--not a string or nil");
5347
5348 if (STRINGP (name))
5349 Vx_resource_name = name;
5350
5351 /* See if parent window is specified. */
5352 parent = w32_get_arg (parms, Qparent_id, NULL, NULL, RES_TYPE_NUMBER);
5353 if (EQ (parent, Qunbound))
5354 parent = Qnil;
5355 if (! NILP (parent))
5356 CHECK_NUMBER (parent);
5357
5358 /* make_frame_without_minibuffer can run Lisp code and garbage collect. */
5359 /* No need to protect DISPLAY because that's not used after passing
5360 it to make_frame_without_minibuffer. */
5361 frame = Qnil;
5362 GCPRO4 (parms, parent, name, frame);
5363 tem = w32_get_arg (parms, Qminibuffer, "minibuffer", "Minibuffer",
5364 RES_TYPE_SYMBOL);
5365 if (EQ (tem, Qnone) || NILP (tem))
5366 f = make_frame_without_minibuffer (Qnil, kb, display);
5367 else if (EQ (tem, Qonly))
5368 {
5369 f = make_minibuffer_frame ();
5370 minibuffer_only = 1;
5371 }
5372 else if (WINDOWP (tem))
5373 f = make_frame_without_minibuffer (tem, kb, display);
5374 else
5375 f = make_frame (1);
5376
5377 XSETFRAME (frame, f);
5378
5379 /* Note that Windows does support scroll bars. */
5380 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
5381 /* By default, make scrollbars the system standard width. */
5382 f->scroll_bar_pixel_width = GetSystemMetrics (SM_CXVSCROLL);
5383
5384 f->output_method = output_w32;
5385 f->output_data.w32 =
5386 (struct w32_output *) xmalloc (sizeof (struct w32_output));
5387 bzero (f->output_data.w32, sizeof (struct w32_output));
5388 FRAME_FONTSET (f) = -1;
5389 record_unwind_protect (unwind_create_frame, frame);
5390
5391 f->icon_name
5392 = w32_get_arg (parms, Qicon_name, "iconName", "Title", RES_TYPE_STRING);
5393 if (! STRINGP (f->icon_name))
5394 f->icon_name = Qnil;
5395
5396 /* FRAME_W32_DISPLAY_INFO (f) = dpyinfo; */
5397 #ifdef MULTI_KBOARD
5398 FRAME_KBOARD (f) = kb;
5399 #endif
5400
5401 /* Specify the parent under which to make this window. */
5402
5403 if (!NILP (parent))
5404 {
5405 f->output_data.w32->parent_desc = (Window) XFASTINT (parent);
5406 f->output_data.w32->explicit_parent = 1;
5407 }
5408 else
5409 {
5410 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
5411 f->output_data.w32->explicit_parent = 0;
5412 }
5413
5414 /* Set the name; the functions to which we pass f expect the name to
5415 be set. */
5416 if (EQ (name, Qunbound) || NILP (name))
5417 {
5418 f->name = build_string (dpyinfo->w32_id_name);
5419 f->explicit_name = 0;
5420 }
5421 else
5422 {
5423 f->name = name;
5424 f->explicit_name = 1;
5425 /* use the frame's title when getting resources for this frame. */
5426 specbind (Qx_resource_name, name);
5427 }
5428
5429 /* Extract the window parameters from the supplied values
5430 that are needed to determine window geometry. */
5431 {
5432 Lisp_Object font;
5433
5434 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
5435
5436 BLOCK_INPUT;
5437 /* First, try whatever font the caller has specified. */
5438 if (STRINGP (font))
5439 {
5440 tem = Fquery_fontset (font, Qnil);
5441 if (STRINGP (tem))
5442 font = x_new_fontset (f, XSTRING (tem)->data);
5443 else
5444 font = x_new_font (f, XSTRING (font)->data);
5445 }
5446 /* Try out a font which we hope has bold and italic variations. */
5447 if (!STRINGP (font))
5448 font = x_new_font (f, "-*-Courier New-normal-r-*-*-*-100-*-*-c-*-iso8859-1");
5449 if (! STRINGP (font))
5450 font = x_new_font (f, "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
5451 /* If those didn't work, look for something which will at least work. */
5452 if (! STRINGP (font))
5453 font = x_new_font (f, "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1");
5454 UNBLOCK_INPUT;
5455 if (! STRINGP (font))
5456 font = build_string ("Fixedsys");
5457
5458 x_default_parameter (f, parms, Qfont, font,
5459 "font", "Font", RES_TYPE_STRING);
5460 }
5461
5462 x_default_parameter (f, parms, Qborder_width, make_number (2),
5463 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
5464 /* This defaults to 2 in order to match xterm. We recognize either
5465 internalBorderWidth or internalBorder (which is what xterm calls
5466 it). */
5467 if (NILP (Fassq (Qinternal_border_width, parms)))
5468 {
5469 Lisp_Object value;
5470
5471 value = w32_get_arg (parms, Qinternal_border_width,
5472 "internalBorder", "InternalBorder", RES_TYPE_NUMBER);
5473 if (! EQ (value, Qunbound))
5474 parms = Fcons (Fcons (Qinternal_border_width, value),
5475 parms);
5476 }
5477 /* Default internalBorderWidth to 0 on Windows to match other programs. */
5478 x_default_parameter (f, parms, Qinternal_border_width, make_number (0),
5479 "internalBorderWidth", "InternalBorder", RES_TYPE_NUMBER);
5480 x_default_parameter (f, parms, Qvertical_scroll_bars, Qright,
5481 "verticalScrollBars", "ScrollBars", RES_TYPE_SYMBOL);
5482
5483 /* Also do the stuff which must be set before the window exists. */
5484 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
5485 "foreground", "Foreground", RES_TYPE_STRING);
5486 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
5487 "background", "Background", RES_TYPE_STRING);
5488 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
5489 "pointerColor", "Foreground", RES_TYPE_STRING);
5490 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
5491 "cursorColor", "Foreground", RES_TYPE_STRING);
5492 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
5493 "borderColor", "BorderColor", RES_TYPE_STRING);
5494 x_default_parameter (f, parms, Qscreen_gamma, Qnil,
5495 "screenGamma", "ScreenGamma", RES_TYPE_FLOAT);
5496 x_default_parameter (f, parms, Qline_spacing, Qnil,
5497 "lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
5498 x_default_parameter (f, parms, Qleft_fringe, Qnil,
5499 "leftFringe", "LeftFringe", RES_TYPE_NUMBER);
5500 x_default_parameter (f, parms, Qright_fringe, Qnil,
5501 "rightFringe", "RightFringe", RES_TYPE_NUMBER);
5502
5503
5504 /* Init faces before x_default_parameter is called for scroll-bar
5505 parameters because that function calls x_set_scroll_bar_width,
5506 which calls change_frame_size, which calls Fset_window_buffer,
5507 which runs hooks, which call Fvertical_motion. At the end, we
5508 end up in init_iterator with a null face cache, which should not
5509 happen. */
5510 init_frame_faces (f);
5511
5512 x_default_parameter (f, parms, Qmenu_bar_lines, make_number (1),
5513 "menuBar", "MenuBar", RES_TYPE_NUMBER);
5514 x_default_parameter (f, parms, Qtool_bar_lines, make_number (0),
5515 "toolBar", "ToolBar", RES_TYPE_NUMBER);
5516 x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
5517 "bufferPredicate", "BufferPredicate", RES_TYPE_SYMBOL);
5518 x_default_parameter (f, parms, Qtitle, Qnil,
5519 "title", "Title", RES_TYPE_STRING);
5520
5521 f->output_data.w32->dwStyle = WS_OVERLAPPEDWINDOW;
5522 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
5523
5524 /* Add the tool-bar height to the initial frame height so that the
5525 user gets a text display area of the size he specified with -g or
5526 via .Xdefaults. Later changes of the tool-bar height don't
5527 change the frame size. This is done so that users can create
5528 tall Emacs frames without having to guess how tall the tool-bar
5529 will get. */
5530 if (FRAME_TOOL_BAR_LINES (f))
5531 {
5532 int margin, relief, bar_height;
5533
5534 relief = (tool_bar_button_relief >= 0
5535 ? tool_bar_button_relief
5536 : DEFAULT_TOOL_BAR_BUTTON_RELIEF);
5537
5538 if (INTEGERP (Vtool_bar_button_margin)
5539 && XINT (Vtool_bar_button_margin) > 0)
5540 margin = XFASTINT (Vtool_bar_button_margin);
5541 else if (CONSP (Vtool_bar_button_margin)
5542 && INTEGERP (XCDR (Vtool_bar_button_margin))
5543 && XINT (XCDR (Vtool_bar_button_margin)) > 0)
5544 margin = XFASTINT (XCDR (Vtool_bar_button_margin));
5545 else
5546 margin = 0;
5547
5548 bar_height = DEFAULT_TOOL_BAR_IMAGE_HEIGHT + 2 * margin + 2 * relief;
5549 f->height += (bar_height + CANON_Y_UNIT (f) - 1) / CANON_Y_UNIT (f);
5550 }
5551
5552 window_prompting = x_figure_window_size (f, parms);
5553
5554 if (window_prompting & XNegative)
5555 {
5556 if (window_prompting & YNegative)
5557 f->output_data.w32->win_gravity = SouthEastGravity;
5558 else
5559 f->output_data.w32->win_gravity = NorthEastGravity;
5560 }
5561 else
5562 {
5563 if (window_prompting & YNegative)
5564 f->output_data.w32->win_gravity = SouthWestGravity;
5565 else
5566 f->output_data.w32->win_gravity = NorthWestGravity;
5567 }
5568
5569 f->output_data.w32->size_hint_flags = window_prompting;
5570
5571 tem = w32_get_arg (parms, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN);
5572 f->no_split = minibuffer_only || EQ (tem, Qt);
5573
5574 w32_window (f, window_prompting, minibuffer_only);
5575 x_icon (f, parms);
5576
5577 x_make_gc (f);
5578
5579 /* Now consider the frame official. */
5580 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
5581 Vframe_list = Fcons (frame, Vframe_list);
5582
5583 /* We need to do this after creating the window, so that the
5584 icon-creation functions can say whose icon they're describing. */
5585 x_default_parameter (f, parms, Qicon_type, Qnil,
5586 "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL);
5587
5588 x_default_parameter (f, parms, Qauto_raise, Qnil,
5589 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
5590 x_default_parameter (f, parms, Qauto_lower, Qnil,
5591 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
5592 x_default_parameter (f, parms, Qcursor_type, Qbox,
5593 "cursorType", "CursorType", RES_TYPE_SYMBOL);
5594 x_default_parameter (f, parms, Qscroll_bar_width, Qnil,
5595 "scrollBarWidth", "ScrollBarWidth", RES_TYPE_NUMBER);
5596
5597 /* Dimensions, especially f->height, must be done via change_frame_size.
5598 Change will not be effected unless different from the current
5599 f->height. */
5600 width = f->width;
5601 height = f->height;
5602
5603 f->height = 0;
5604 SET_FRAME_WIDTH (f, 0);
5605 change_frame_size (f, height, width, 1, 0, 0);
5606
5607 /* Tell the server what size and position, etc, we want, and how
5608 badly we want them. This should be done after we have the menu
5609 bar so that its size can be taken into account. */
5610 BLOCK_INPUT;
5611 x_wm_set_size_hint (f, window_prompting, 0);
5612 UNBLOCK_INPUT;
5613
5614 /* Set up faces after all frame parameters are known. This call
5615 also merges in face attributes specified for new frames. If we
5616 don't do this, the `menu' face for instance won't have the right
5617 colors, and the menu bar won't appear in the specified colors for
5618 new frames. */
5619 call1 (Qface_set_after_frame_default, frame);
5620
5621 /* Make the window appear on the frame and enable display, unless
5622 the caller says not to. However, with explicit parent, Emacs
5623 cannot control visibility, so don't try. */
5624 if (! f->output_data.w32->explicit_parent)
5625 {
5626 Lisp_Object visibility;
5627
5628 visibility = w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL);
5629 if (EQ (visibility, Qunbound))
5630 visibility = Qt;
5631
5632 if (EQ (visibility, Qicon))
5633 x_iconify_frame (f);
5634 else if (! NILP (visibility))
5635 x_make_frame_visible (f);
5636 else
5637 /* Must have been Qnil. */
5638 ;
5639 }
5640 UNGCPRO;
5641
5642 /* Make sure windows on this frame appear in calls to next-window
5643 and similar functions. */
5644 Vwindow_list = Qnil;
5645
5646 return unbind_to (count, frame);
5647 }
5648
5649 /* FRAME is used only to get a handle on the X display. We don't pass the
5650 display info directly because we're called from frame.c, which doesn't
5651 know about that structure. */
5652 Lisp_Object
5653 x_get_focus_frame (frame)
5654 struct frame *frame;
5655 {
5656 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (frame);
5657 Lisp_Object xfocus;
5658 if (! dpyinfo->w32_focus_frame)
5659 return Qnil;
5660
5661 XSETFRAME (xfocus, dpyinfo->w32_focus_frame);
5662 return xfocus;
5663 }
5664
5665 DEFUN ("w32-focus-frame", Fw32_focus_frame, Sw32_focus_frame, 1, 1, 0,
5666 doc: /* Give FRAME input focus, raising to foreground if necessary. */)
5667 (frame)
5668 Lisp_Object frame;
5669 {
5670 x_focus_on_frame (check_x_frame (frame));
5671 return Qnil;
5672 }
5673
5674 \f
5675 /* Return the charset portion of a font name. */
5676 char * xlfd_charset_of_font (char * fontname)
5677 {
5678 char *charset, *encoding;
5679
5680 encoding = strrchr(fontname, '-');
5681 if (!encoding || encoding == fontname)
5682 return NULL;
5683
5684 for (charset = encoding - 1; charset >= fontname; charset--)
5685 if (*charset == '-')
5686 break;
5687
5688 if (charset == fontname || strcmp(charset, "-*-*") == 0)
5689 return NULL;
5690
5691 return charset + 1;
5692 }
5693
5694 struct font_info *w32_load_bdf_font (struct frame *f, char *fontname,
5695 int size, char* filename);
5696 static Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names);
5697 static BOOL w32_to_x_font (LOGFONT * lplf, char * lpxstr, int len,
5698 char * charset);
5699 static BOOL x_to_w32_font (char *lpxstr, LOGFONT *lplogfont);
5700
5701 static struct font_info *
5702 w32_load_system_font (f,fontname,size)
5703 struct frame *f;
5704 char * fontname;
5705 int size;
5706 {
5707 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
5708 Lisp_Object font_names;
5709
5710 /* Get a list of all the fonts that match this name. Once we
5711 have a list of matching fonts, we compare them against the fonts
5712 we already have loaded by comparing names. */
5713 font_names = w32_list_fonts (f, build_string (fontname), size, 100);
5714
5715 if (!NILP (font_names))
5716 {
5717 Lisp_Object tail;
5718 int i;
5719
5720 /* First check if any are already loaded, as that is cheaper
5721 than loading another one. */
5722 for (i = 0; i < dpyinfo->n_fonts; i++)
5723 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
5724 if (dpyinfo->font_table[i].name
5725 && (!strcmp (dpyinfo->font_table[i].name,
5726 XSTRING (XCAR (tail))->data)
5727 || !strcmp (dpyinfo->font_table[i].full_name,
5728 XSTRING (XCAR (tail))->data)))
5729 return (dpyinfo->font_table + i);
5730
5731 fontname = (char *) XSTRING (XCAR (font_names))->data;
5732 }
5733 else if (w32_strict_fontnames)
5734 {
5735 /* If EnumFontFamiliesEx was available, we got a full list of
5736 fonts back so stop now to avoid the possibility of loading a
5737 random font. If we had to fall back to EnumFontFamilies, the
5738 list is incomplete, so continue whether the font we want was
5739 listed or not. */
5740 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
5741 FARPROC enum_font_families_ex
5742 = GetProcAddress (gdi32, "EnumFontFamiliesExA");
5743 if (enum_font_families_ex)
5744 return NULL;
5745 }
5746
5747 /* Load the font and add it to the table. */
5748 {
5749 char *full_name, *encoding, *charset;
5750 XFontStruct *font;
5751 struct font_info *fontp;
5752 LOGFONT lf;
5753 BOOL ok;
5754 int codepage;
5755 int i;
5756
5757 if (!fontname || !x_to_w32_font (fontname, &lf))
5758 return (NULL);
5759
5760 if (!*lf.lfFaceName)
5761 /* If no name was specified for the font, we get a random font
5762 from CreateFontIndirect - this is not particularly
5763 desirable, especially since CreateFontIndirect does not
5764 fill out the missing name in lf, so we never know what we
5765 ended up with. */
5766 return NULL;
5767
5768 font = (XFontStruct *) xmalloc (sizeof (XFontStruct));
5769 bzero (font, sizeof (*font));
5770
5771 /* Set bdf to NULL to indicate that this is a Windows font. */
5772 font->bdf = NULL;
5773
5774 BLOCK_INPUT;
5775
5776 font->hfont = CreateFontIndirect (&lf);
5777
5778 if (font->hfont == NULL)
5779 {
5780 ok = FALSE;
5781 }
5782 else
5783 {
5784 HDC hdc;
5785 HANDLE oldobj;
5786
5787 codepage = w32_codepage_for_font (fontname);
5788
5789 hdc = GetDC (dpyinfo->root_window);
5790 oldobj = SelectObject (hdc, font->hfont);
5791
5792 ok = GetTextMetrics (hdc, &font->tm);
5793 if (codepage == CP_UNICODE)
5794 font->double_byte_p = 1;
5795 else
5796 {
5797 /* Unfortunately, some fonts (eg. MingLiU, a big5 ttf font)
5798 don't report themselves as double byte fonts, when
5799 patently they are. So instead of trusting
5800 GetFontLanguageInfo, we check the properties of the
5801 codepage directly, since that is ultimately what we are
5802 working from anyway. */
5803 /* font->double_byte_p = GetFontLanguageInfo(hdc) & GCP_DBCS; */
5804 CPINFO cpi = {0};
5805 GetCPInfo (codepage, &cpi);
5806 font->double_byte_p = cpi.MaxCharSize > 1;
5807 }
5808
5809 SelectObject (hdc, oldobj);
5810 ReleaseDC (dpyinfo->root_window, hdc);
5811 /* Fill out details in lf according to the font that was
5812 actually loaded. */
5813 lf.lfHeight = font->tm.tmInternalLeading - font->tm.tmHeight;
5814 lf.lfWidth = font->tm.tmAveCharWidth;
5815 lf.lfWeight = font->tm.tmWeight;
5816 lf.lfItalic = font->tm.tmItalic;
5817 lf.lfCharSet = font->tm.tmCharSet;
5818 lf.lfPitchAndFamily = ((font->tm.tmPitchAndFamily & TMPF_FIXED_PITCH)
5819 ? VARIABLE_PITCH : FIXED_PITCH);
5820 lf.lfOutPrecision = ((font->tm.tmPitchAndFamily & TMPF_VECTOR)
5821 ? OUT_STROKE_PRECIS : OUT_STRING_PRECIS);
5822
5823 w32_cache_char_metrics (font);
5824 }
5825
5826 UNBLOCK_INPUT;
5827
5828 if (!ok)
5829 {
5830 w32_unload_font (dpyinfo, font);
5831 return (NULL);
5832 }
5833
5834 /* Find a free slot in the font table. */
5835 for (i = 0; i < dpyinfo->n_fonts; ++i)
5836 if (dpyinfo->font_table[i].name == NULL)
5837 break;
5838
5839 /* If no free slot found, maybe enlarge the font table. */
5840 if (i == dpyinfo->n_fonts
5841 && dpyinfo->n_fonts == dpyinfo->font_table_size)
5842 {
5843 int sz;
5844 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
5845 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
5846 dpyinfo->font_table
5847 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
5848 }
5849
5850 fontp = dpyinfo->font_table + i;
5851 if (i == dpyinfo->n_fonts)
5852 ++dpyinfo->n_fonts;
5853
5854 /* Now fill in the slots of *FONTP. */
5855 BLOCK_INPUT;
5856 fontp->font = font;
5857 fontp->font_idx = i;
5858 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
5859 bcopy (fontname, fontp->name, strlen (fontname) + 1);
5860
5861 charset = xlfd_charset_of_font (fontname);
5862
5863 /* Cache the W32 codepage for a font. This makes w32_encode_char
5864 (called for every glyph during redisplay) much faster. */
5865 fontp->codepage = codepage;
5866
5867 /* Work out the font's full name. */
5868 full_name = (char *)xmalloc (100);
5869 if (full_name && w32_to_x_font (&lf, full_name, 100, charset))
5870 fontp->full_name = full_name;
5871 else
5872 {
5873 /* If all else fails - just use the name we used to load it. */
5874 xfree (full_name);
5875 fontp->full_name = fontp->name;
5876 }
5877
5878 fontp->size = FONT_WIDTH (font);
5879 fontp->height = FONT_HEIGHT (font);
5880
5881 /* The slot `encoding' specifies how to map a character
5882 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
5883 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
5884 (0:0x20..0x7F, 1:0xA0..0xFF,
5885 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
5886 2:0xA020..0xFF7F). For the moment, we don't know which charset
5887 uses this font. So, we set information in fontp->encoding[1]
5888 which is never used by any charset. If mapping can't be
5889 decided, set FONT_ENCODING_NOT_DECIDED. */
5890
5891 /* SJIS fonts need to be set to type 4, all others seem to work as
5892 type FONT_ENCODING_NOT_DECIDED. */
5893 encoding = strrchr (fontp->name, '-');
5894 if (encoding && stricmp (encoding+1, "sjis") == 0)
5895 fontp->encoding[1] = 4;
5896 else
5897 fontp->encoding[1] = FONT_ENCODING_NOT_DECIDED;
5898
5899 /* The following three values are set to 0 under W32, which is
5900 what they get set to if XGetFontProperty fails under X. */
5901 fontp->baseline_offset = 0;
5902 fontp->relative_compose = 0;
5903 fontp->default_ascent = 0;
5904
5905 /* Set global flag fonts_changed_p to non-zero if the font loaded
5906 has a character with a smaller width than any other character
5907 before, or if the font loaded has a smalle>r height than any
5908 other font loaded before. If this happens, it will make a
5909 glyph matrix reallocation necessary. */
5910 fonts_changed_p = x_compute_min_glyph_bounds (f);
5911 UNBLOCK_INPUT;
5912 return fontp;
5913 }
5914 }
5915
5916 /* Load font named FONTNAME of size SIZE for frame F, and return a
5917 pointer to the structure font_info while allocating it dynamically.
5918 If loading fails, return NULL. */
5919 struct font_info *
5920 w32_load_font (f,fontname,size)
5921 struct frame *f;
5922 char * fontname;
5923 int size;
5924 {
5925 Lisp_Object bdf_fonts;
5926 struct font_info *retval = NULL;
5927
5928 bdf_fonts = w32_list_bdf_fonts (build_string (fontname), 1);
5929
5930 while (!retval && CONSP (bdf_fonts))
5931 {
5932 char *bdf_name, *bdf_file;
5933 Lisp_Object bdf_pair;
5934
5935 bdf_name = XSTRING (XCAR (bdf_fonts))->data;
5936 bdf_pair = Fassoc (XCAR (bdf_fonts), Vw32_bdf_filename_alist);
5937 bdf_file = XSTRING (XCDR (bdf_pair))->data;
5938
5939 retval = w32_load_bdf_font (f, bdf_name, size, bdf_file);
5940
5941 bdf_fonts = XCDR (bdf_fonts);
5942 }
5943
5944 if (retval)
5945 return retval;
5946
5947 return w32_load_system_font(f, fontname, size);
5948 }
5949
5950
5951 void
5952 w32_unload_font (dpyinfo, font)
5953 struct w32_display_info *dpyinfo;
5954 XFontStruct * font;
5955 {
5956 if (font)
5957 {
5958 if (font->per_char) xfree (font->per_char);
5959 if (font->bdf) w32_free_bdf_font (font->bdf);
5960
5961 if (font->hfont) DeleteObject(font->hfont);
5962 xfree (font);
5963 }
5964 }
5965
5966 /* The font conversion stuff between x and w32 */
5967
5968 /* X font string is as follows (from faces.el)
5969 * (let ((- "[-?]")
5970 * (foundry "[^-]+")
5971 * (family "[^-]+")
5972 * (weight "\\(bold\\|demibold\\|medium\\)") ; 1
5973 * (weight\? "\\([^-]*\\)") ; 1
5974 * (slant "\\([ior]\\)") ; 2
5975 * (slant\? "\\([^-]?\\)") ; 2
5976 * (swidth "\\([^-]*\\)") ; 3
5977 * (adstyle "[^-]*") ; 4
5978 * (pixelsize "[0-9]+")
5979 * (pointsize "[0-9][0-9]+")
5980 * (resx "[0-9][0-9]+")
5981 * (resy "[0-9][0-9]+")
5982 * (spacing "[cmp?*]")
5983 * (avgwidth "[0-9]+")
5984 * (registry "[^-]+")
5985 * (encoding "[^-]+")
5986 * )
5987 */
5988
5989 static LONG
5990 x_to_w32_weight (lpw)
5991 char * lpw;
5992 {
5993 if (!lpw) return (FW_DONTCARE);
5994
5995 if (stricmp (lpw,"heavy") == 0) return FW_HEAVY;
5996 else if (stricmp (lpw,"extrabold") == 0) return FW_EXTRABOLD;
5997 else if (stricmp (lpw,"bold") == 0) return FW_BOLD;
5998 else if (stricmp (lpw,"demibold") == 0) return FW_SEMIBOLD;
5999 else if (stricmp (lpw,"semibold") == 0) return FW_SEMIBOLD;
6000 else if (stricmp (lpw,"medium") == 0) return FW_MEDIUM;
6001 else if (stricmp (lpw,"normal") == 0) return FW_NORMAL;
6002 else if (stricmp (lpw,"light") == 0) return FW_LIGHT;
6003 else if (stricmp (lpw,"extralight") == 0) return FW_EXTRALIGHT;
6004 else if (stricmp (lpw,"thin") == 0) return FW_THIN;
6005 else
6006 return FW_DONTCARE;
6007 }
6008
6009
6010 static char *
6011 w32_to_x_weight (fnweight)
6012 int fnweight;
6013 {
6014 if (fnweight >= FW_HEAVY) return "heavy";
6015 if (fnweight >= FW_EXTRABOLD) return "extrabold";
6016 if (fnweight >= FW_BOLD) return "bold";
6017 if (fnweight >= FW_SEMIBOLD) return "demibold";
6018 if (fnweight >= FW_MEDIUM) return "medium";
6019 if (fnweight >= FW_NORMAL) return "normal";
6020 if (fnweight >= FW_LIGHT) return "light";
6021 if (fnweight >= FW_EXTRALIGHT) return "extralight";
6022 if (fnweight >= FW_THIN) return "thin";
6023 else
6024 return "*";
6025 }
6026
6027 static LONG
6028 x_to_w32_charset (lpcs)
6029 char * lpcs;
6030 {
6031 Lisp_Object this_entry, w32_charset;
6032 char *charset;
6033 int len = strlen (lpcs);
6034
6035 /* Support "*-#nnn" format for unknown charsets. */
6036 if (strncmp (lpcs, "*-#", 3) == 0)
6037 return atoi (lpcs + 3);
6038
6039 /* Handle wildcards by ignoring them; eg. treat "big5*-*" as "big5". */
6040 charset = alloca (len + 1);
6041 strcpy (charset, lpcs);
6042 lpcs = strchr (charset, '*');
6043 if (lpcs)
6044 *lpcs = 0;
6045
6046 /* Look through w32-charset-info-alist for the character set.
6047 Format of each entry is
6048 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
6049 */
6050 this_entry = Fassoc (build_string(charset), Vw32_charset_info_alist);
6051
6052 if (NILP(this_entry))
6053 {
6054 /* At startup, we want iso8859-1 fonts to come up properly. */
6055 if (stricmp(charset, "iso8859-1") == 0)
6056 return ANSI_CHARSET;
6057 else
6058 return DEFAULT_CHARSET;
6059 }
6060
6061 w32_charset = Fcar (Fcdr (this_entry));
6062
6063 // Translate Lisp symbol to number.
6064 if (w32_charset == Qw32_charset_ansi)
6065 return ANSI_CHARSET;
6066 if (w32_charset == Qw32_charset_symbol)
6067 return SYMBOL_CHARSET;
6068 if (w32_charset == Qw32_charset_shiftjis)
6069 return SHIFTJIS_CHARSET;
6070 if (w32_charset == Qw32_charset_hangeul)
6071 return HANGEUL_CHARSET;
6072 if (w32_charset == Qw32_charset_chinesebig5)
6073 return CHINESEBIG5_CHARSET;
6074 if (w32_charset == Qw32_charset_gb2312)
6075 return GB2312_CHARSET;
6076 if (w32_charset == Qw32_charset_oem)
6077 return OEM_CHARSET;
6078 #ifdef JOHAB_CHARSET
6079 if (w32_charset == Qw32_charset_johab)
6080 return JOHAB_CHARSET;
6081 if (w32_charset == Qw32_charset_easteurope)
6082 return EASTEUROPE_CHARSET;
6083 if (w32_charset == Qw32_charset_turkish)
6084 return TURKISH_CHARSET;
6085 if (w32_charset == Qw32_charset_baltic)
6086 return BALTIC_CHARSET;
6087 if (w32_charset == Qw32_charset_russian)
6088 return RUSSIAN_CHARSET;
6089 if (w32_charset == Qw32_charset_arabic)
6090 return ARABIC_CHARSET;
6091 if (w32_charset == Qw32_charset_greek)
6092 return GREEK_CHARSET;
6093 if (w32_charset == Qw32_charset_hebrew)
6094 return HEBREW_CHARSET;
6095 if (w32_charset == Qw32_charset_vietnamese)
6096 return VIETNAMESE_CHARSET;
6097 if (w32_charset == Qw32_charset_thai)
6098 return THAI_CHARSET;
6099 if (w32_charset == Qw32_charset_mac)
6100 return MAC_CHARSET;
6101 #endif /* JOHAB_CHARSET */
6102 #ifdef UNICODE_CHARSET
6103 if (w32_charset == Qw32_charset_unicode)
6104 return UNICODE_CHARSET;
6105 #endif
6106
6107 return DEFAULT_CHARSET;
6108 }
6109
6110
6111 static char *
6112 w32_to_x_charset (fncharset)
6113 int fncharset;
6114 {
6115 static char buf[32];
6116 Lisp_Object charset_type;
6117
6118 switch (fncharset)
6119 {
6120 case ANSI_CHARSET:
6121 /* Handle startup case of w32-charset-info-alist not
6122 being set up yet. */
6123 if (NILP(Vw32_charset_info_alist))
6124 return "iso8859-1";
6125 charset_type = Qw32_charset_ansi;
6126 break;
6127 case DEFAULT_CHARSET:
6128 charset_type = Qw32_charset_default;
6129 break;
6130 case SYMBOL_CHARSET:
6131 charset_type = Qw32_charset_symbol;
6132 break;
6133 case SHIFTJIS_CHARSET:
6134 charset_type = Qw32_charset_shiftjis;
6135 break;
6136 case HANGEUL_CHARSET:
6137 charset_type = Qw32_charset_hangeul;
6138 break;
6139 case GB2312_CHARSET:
6140 charset_type = Qw32_charset_gb2312;
6141 break;
6142 case CHINESEBIG5_CHARSET:
6143 charset_type = Qw32_charset_chinesebig5;
6144 break;
6145 case OEM_CHARSET:
6146 charset_type = Qw32_charset_oem;
6147 break;
6148
6149 /* More recent versions of Windows (95 and NT4.0) define more
6150 character sets. */
6151 #ifdef EASTEUROPE_CHARSET
6152 case EASTEUROPE_CHARSET:
6153 charset_type = Qw32_charset_easteurope;
6154 break;
6155 case TURKISH_CHARSET:
6156 charset_type = Qw32_charset_turkish;
6157 break;
6158 case BALTIC_CHARSET:
6159 charset_type = Qw32_charset_baltic;
6160 break;
6161 case RUSSIAN_CHARSET:
6162 charset_type = Qw32_charset_russian;
6163 break;
6164 case ARABIC_CHARSET:
6165 charset_type = Qw32_charset_arabic;
6166 break;
6167 case GREEK_CHARSET:
6168 charset_type = Qw32_charset_greek;
6169 break;
6170 case HEBREW_CHARSET:
6171 charset_type = Qw32_charset_hebrew;
6172 break;
6173 case VIETNAMESE_CHARSET:
6174 charset_type = Qw32_charset_vietnamese;
6175 break;
6176 case THAI_CHARSET:
6177 charset_type = Qw32_charset_thai;
6178 break;
6179 case MAC_CHARSET:
6180 charset_type = Qw32_charset_mac;
6181 break;
6182 case JOHAB_CHARSET:
6183 charset_type = Qw32_charset_johab;
6184 break;
6185 #endif
6186
6187 #ifdef UNICODE_CHARSET
6188 case UNICODE_CHARSET:
6189 charset_type = Qw32_charset_unicode;
6190 break;
6191 #endif
6192 default:
6193 /* Encode numerical value of unknown charset. */
6194 sprintf (buf, "*-#%u", fncharset);
6195 return buf;
6196 }
6197
6198 {
6199 Lisp_Object rest;
6200 char * best_match = NULL;
6201
6202 /* Look through w32-charset-info-alist for the character set.
6203 Prefer ISO codepages, and prefer lower numbers in the ISO
6204 range. Only return charsets for codepages which are installed.
6205
6206 Format of each entry is
6207 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
6208 */
6209 for (rest = Vw32_charset_info_alist; CONSP (rest); rest = XCDR (rest))
6210 {
6211 char * x_charset;
6212 Lisp_Object w32_charset;
6213 Lisp_Object codepage;
6214
6215 Lisp_Object this_entry = XCAR (rest);
6216
6217 /* Skip invalid entries in alist. */
6218 if (!CONSP (this_entry) || !STRINGP (XCAR (this_entry))
6219 || !CONSP (XCDR (this_entry))
6220 || !SYMBOLP (XCAR (XCDR (this_entry))))
6221 continue;
6222
6223 x_charset = XSTRING (XCAR (this_entry))->data;
6224 w32_charset = XCAR (XCDR (this_entry));
6225 codepage = XCDR (XCDR (this_entry));
6226
6227 /* Look for Same charset and a valid codepage (or non-int
6228 which means ignore). */
6229 if (w32_charset == charset_type
6230 && (!INTEGERP (codepage) || codepage == CP_DEFAULT
6231 || IsValidCodePage (XINT (codepage))))
6232 {
6233 /* If we don't have a match already, then this is the
6234 best. */
6235 if (!best_match)
6236 best_match = x_charset;
6237 /* If this is an ISO codepage, and the best so far isn't,
6238 then this is better. */
6239 else if (stricmp (best_match, "iso") != 0
6240 && stricmp (x_charset, "iso") == 0)
6241 best_match = x_charset;
6242 /* If both are ISO8859 codepages, choose the one with the
6243 lowest number in the encoding field. */
6244 else if (stricmp (best_match, "iso8859-") == 0
6245 && stricmp (x_charset, "iso8859-") == 0)
6246 {
6247 int best_enc = atoi (best_match + 8);
6248 int this_enc = atoi (x_charset + 8);
6249 if (this_enc > 0 && this_enc < best_enc)
6250 best_match = x_charset;
6251 }
6252 }
6253 }
6254
6255 /* If no match, encode the numeric value. */
6256 if (!best_match)
6257 {
6258 sprintf (buf, "*-#%u", fncharset);
6259 return buf;
6260 }
6261
6262 strncpy(buf, best_match, 31);
6263 buf[31] = '\0';
6264 return buf;
6265 }
6266 }
6267
6268
6269 /* Get the Windows codepage corresponding to the specified font. The
6270 charset info in the font name is used to look up
6271 w32-charset-to-codepage-alist. */
6272 int
6273 w32_codepage_for_font (char *fontname)
6274 {
6275 Lisp_Object codepage, entry;
6276 char *charset_str, *charset, *end;
6277
6278 if (NILP (Vw32_charset_info_alist))
6279 return CP_DEFAULT;
6280
6281 /* Extract charset part of font string. */
6282 charset = xlfd_charset_of_font (fontname);
6283
6284 if (!charset)
6285 return CP_UNKNOWN;
6286
6287 charset_str = (char *) alloca (strlen (charset) + 1);
6288 strcpy (charset_str, charset);
6289
6290 #if 0
6291 /* Remove leading "*-". */
6292 if (strncmp ("*-", charset_str, 2) == 0)
6293 charset = charset_str + 2;
6294 else
6295 #endif
6296 charset = charset_str;
6297
6298 /* Stop match at wildcard (including preceding '-'). */
6299 if (end = strchr (charset, '*'))
6300 {
6301 if (end > charset && *(end-1) == '-')
6302 end--;
6303 *end = '\0';
6304 }
6305
6306 entry = Fassoc (build_string(charset), Vw32_charset_info_alist);
6307 if (NILP (entry))
6308 return CP_UNKNOWN;
6309
6310 codepage = Fcdr (Fcdr (entry));
6311
6312 if (NILP (codepage))
6313 return CP_8BIT;
6314 else if (XFASTINT (codepage) == XFASTINT (Qt))
6315 return CP_UNICODE;
6316 else if (INTEGERP (codepage))
6317 return XINT (codepage);
6318 else
6319 return CP_UNKNOWN;
6320 }
6321
6322
6323 static BOOL
6324 w32_to_x_font (lplogfont, lpxstr, len, specific_charset)
6325 LOGFONT * lplogfont;
6326 char * lpxstr;
6327 int len;
6328 char * specific_charset;
6329 {
6330 char* fonttype;
6331 char *fontname;
6332 char height_pixels[8];
6333 char height_dpi[8];
6334 char width_pixels[8];
6335 char *fontname_dash;
6336 int display_resy = one_w32_display_info.resy;
6337 int display_resx = one_w32_display_info.resx;
6338 int bufsz;
6339 struct coding_system coding;
6340
6341 if (!lpxstr) abort ();
6342
6343 if (!lplogfont)
6344 return FALSE;
6345
6346 if (lplogfont->lfOutPrecision == OUT_STRING_PRECIS)
6347 fonttype = "raster";
6348 else if (lplogfont->lfOutPrecision == OUT_STROKE_PRECIS)
6349 fonttype = "outline";
6350 else
6351 fonttype = "unknown";
6352
6353 setup_coding_system (Fcheck_coding_system (Vlocale_coding_system),
6354 &coding);
6355 coding.src_multibyte = 0;
6356 coding.dst_multibyte = 1;
6357 coding.mode |= CODING_MODE_LAST_BLOCK;
6358 bufsz = decoding_buffer_size (&coding, LF_FACESIZE);
6359
6360 fontname = alloca(sizeof(*fontname) * bufsz);
6361 decode_coding (&coding, lplogfont->lfFaceName, fontname,
6362 strlen(lplogfont->lfFaceName), bufsz - 1);
6363 *(fontname + coding.produced) = '\0';
6364
6365 /* Replace dashes with underscores so the dashes are not
6366 misinterpreted. */
6367 fontname_dash = fontname;
6368 while (fontname_dash = strchr (fontname_dash, '-'))
6369 *fontname_dash = '_';
6370
6371 if (lplogfont->lfHeight)
6372 {
6373 sprintf (height_pixels, "%u", abs (lplogfont->lfHeight));
6374 sprintf (height_dpi, "%u",
6375 abs (lplogfont->lfHeight) * 720 / display_resy);
6376 }
6377 else
6378 {
6379 strcpy (height_pixels, "*");
6380 strcpy (height_dpi, "*");
6381 }
6382 if (lplogfont->lfWidth)
6383 sprintf (width_pixels, "%u", lplogfont->lfWidth * 10);
6384 else
6385 strcpy (width_pixels, "*");
6386
6387 _snprintf (lpxstr, len - 1,
6388 "-%s-%s-%s-%c-normal-normal-%s-%s-%d-%d-%c-%s-%s",
6389 fonttype, /* foundry */
6390 fontname, /* family */
6391 w32_to_x_weight (lplogfont->lfWeight), /* weight */
6392 lplogfont->lfItalic?'i':'r', /* slant */
6393 /* setwidth name */
6394 /* add style name */
6395 height_pixels, /* pixel size */
6396 height_dpi, /* point size */
6397 display_resx, /* resx */
6398 display_resy, /* resy */
6399 ((lplogfont->lfPitchAndFamily & 0x3) == VARIABLE_PITCH)
6400 ? 'p' : 'c', /* spacing */
6401 width_pixels, /* avg width */
6402 specific_charset ? specific_charset
6403 : w32_to_x_charset (lplogfont->lfCharSet)
6404 /* charset registry and encoding */
6405 );
6406
6407 lpxstr[len - 1] = 0; /* just to be sure */
6408 return (TRUE);
6409 }
6410
6411 static BOOL
6412 x_to_w32_font (lpxstr, lplogfont)
6413 char * lpxstr;
6414 LOGFONT * lplogfont;
6415 {
6416 struct coding_system coding;
6417
6418 if (!lplogfont) return (FALSE);
6419
6420 memset (lplogfont, 0, sizeof (*lplogfont));
6421
6422 /* Set default value for each field. */
6423 #if 1
6424 lplogfont->lfOutPrecision = OUT_DEFAULT_PRECIS;
6425 lplogfont->lfClipPrecision = CLIP_DEFAULT_PRECIS;
6426 lplogfont->lfQuality = DEFAULT_QUALITY;
6427 #else
6428 /* go for maximum quality */
6429 lplogfont->lfOutPrecision = OUT_STROKE_PRECIS;
6430 lplogfont->lfClipPrecision = CLIP_STROKE_PRECIS;
6431 lplogfont->lfQuality = PROOF_QUALITY;
6432 #endif
6433
6434 lplogfont->lfCharSet = DEFAULT_CHARSET;
6435 lplogfont->lfWeight = FW_DONTCARE;
6436 lplogfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
6437
6438 if (!lpxstr)
6439 return FALSE;
6440
6441 /* Provide a simple escape mechanism for specifying Windows font names
6442 * directly -- if font spec does not beginning with '-', assume this
6443 * format:
6444 * "<font name>[:height in pixels[:width in pixels[:weight]]]"
6445 */
6446
6447 if (*lpxstr == '-')
6448 {
6449 int fields, tem;
6450 char name[50], weight[20], slant, pitch, pixels[10], height[10],
6451 width[10], resy[10], remainder[50];
6452 char * encoding;
6453 int dpi = one_w32_display_info.resy;
6454
6455 fields = sscanf (lpxstr,
6456 "-%*[^-]-%49[^-]-%19[^-]-%c-%*[^-]-%*[^-]-%9[^-]-%9[^-]-%*[^-]-%9[^-]-%c-%9[^-]-%49s",
6457 name, weight, &slant, pixels, height, resy, &pitch, width, remainder);
6458 if (fields == EOF)
6459 return (FALSE);
6460
6461 /* In the general case when wildcards cover more than one field,
6462 we don't know which field is which, so don't fill any in.
6463 However, we need to cope with this particular form, which is
6464 generated by font_list_1 (invoked by try_font_list):
6465 "-raster-6x10-*-gb2312*-*"
6466 and make sure to correctly parse the charset field. */
6467 if (fields == 3)
6468 {
6469 fields = sscanf (lpxstr,
6470 "-%*[^-]-%49[^-]-*-%49s",
6471 name, remainder);
6472 }
6473 else if (fields < 9)
6474 {
6475 fields = 0;
6476 remainder[0] = 0;
6477 }
6478
6479 if (fields > 0 && name[0] != '*')
6480 {
6481 int bufsize;
6482 unsigned char *buf;
6483
6484 setup_coding_system
6485 (Fcheck_coding_system (Vlocale_coding_system), &coding);
6486 coding.src_multibyte = 1;
6487 coding.dst_multibyte = 1;
6488 bufsize = encoding_buffer_size (&coding, strlen (name));
6489 buf = (unsigned char *) alloca (bufsize);
6490 coding.mode |= CODING_MODE_LAST_BLOCK;
6491 encode_coding (&coding, name, buf, strlen (name), bufsize);
6492 if (coding.produced >= LF_FACESIZE)
6493 coding.produced = LF_FACESIZE - 1;
6494 buf[coding.produced] = 0;
6495 strcpy (lplogfont->lfFaceName, buf);
6496 }
6497 else
6498 {
6499 lplogfont->lfFaceName[0] = '\0';
6500 }
6501
6502 fields--;
6503
6504 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
6505
6506 fields--;
6507
6508 lplogfont->lfItalic = (fields > 0 && slant == 'i');
6509
6510 fields--;
6511
6512 if (fields > 0 && pixels[0] != '*')
6513 lplogfont->lfHeight = atoi (pixels);
6514
6515 fields--;
6516 fields--;
6517 if (fields > 0 && resy[0] != '*')
6518 {
6519 tem = atoi (resy);
6520 if (tem > 0) dpi = tem;
6521 }
6522
6523 if (fields > -1 && lplogfont->lfHeight == 0 && height[0] != '*')
6524 lplogfont->lfHeight = atoi (height) * dpi / 720;
6525
6526 if (fields > 0)
6527 lplogfont->lfPitchAndFamily =
6528 (fields > 0 && pitch == 'p') ? VARIABLE_PITCH : FIXED_PITCH;
6529
6530 fields--;
6531
6532 if (fields > 0 && width[0] != '*')
6533 lplogfont->lfWidth = atoi (width) / 10;
6534
6535 fields--;
6536
6537 /* Strip the trailing '-' if present. (it shouldn't be, as it
6538 fails the test against xlfd-tight-regexp in fontset.el). */
6539 {
6540 int len = strlen (remainder);
6541 if (len > 0 && remainder[len-1] == '-')
6542 remainder[len-1] = 0;
6543 }
6544 encoding = remainder;
6545 #if 0
6546 if (strncmp (encoding, "*-", 2) == 0)
6547 encoding += 2;
6548 #endif
6549 lplogfont->lfCharSet = x_to_w32_charset (encoding);
6550 }
6551 else
6552 {
6553 int fields;
6554 char name[100], height[10], width[10], weight[20];
6555
6556 fields = sscanf (lpxstr,
6557 "%99[^:]:%9[^:]:%9[^:]:%19s",
6558 name, height, width, weight);
6559
6560 if (fields == EOF) return (FALSE);
6561
6562 if (fields > 0)
6563 {
6564 strncpy (lplogfont->lfFaceName,name, LF_FACESIZE);
6565 lplogfont->lfFaceName[LF_FACESIZE-1] = 0;
6566 }
6567 else
6568 {
6569 lplogfont->lfFaceName[0] = 0;
6570 }
6571
6572 fields--;
6573
6574 if (fields > 0)
6575 lplogfont->lfHeight = atoi (height);
6576
6577 fields--;
6578
6579 if (fields > 0)
6580 lplogfont->lfWidth = atoi (width);
6581
6582 fields--;
6583
6584 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
6585 }
6586
6587 /* This makes TrueType fonts work better. */
6588 lplogfont->lfHeight = - abs (lplogfont->lfHeight);
6589
6590 return (TRUE);
6591 }
6592
6593 /* Strip the pixel height and point height from the given xlfd, and
6594 return the pixel height. If no pixel height is specified, calculate
6595 one from the point height, or if that isn't defined either, return
6596 0 (which usually signifies a scalable font).
6597 */
6598 static int
6599 xlfd_strip_height (char *fontname)
6600 {
6601 int pixel_height, field_number;
6602 char *read_from, *write_to;
6603
6604 xassert (fontname);
6605
6606 pixel_height = field_number = 0;
6607 write_to = NULL;
6608
6609 /* Look for height fields. */
6610 for (read_from = fontname; *read_from; read_from++)
6611 {
6612 if (*read_from == '-')
6613 {
6614 field_number++;
6615 if (field_number == 7) /* Pixel height. */
6616 {
6617 read_from++;
6618 write_to = read_from;
6619
6620 /* Find end of field. */
6621 for (;*read_from && *read_from != '-'; read_from++)
6622 ;
6623
6624 /* Split the fontname at end of field. */
6625 if (*read_from)
6626 {
6627 *read_from = '\0';
6628 read_from++;
6629 }
6630 pixel_height = atoi (write_to);
6631 /* Blank out field. */
6632 if (read_from > write_to)
6633 {
6634 *write_to = '-';
6635 write_to++;
6636 }
6637 /* If the pixel height field is at the end (partial xlfd),
6638 return now. */
6639 else
6640 return pixel_height;
6641
6642 /* If we got a pixel height, the point height can be
6643 ignored. Just blank it out and break now. */
6644 if (pixel_height)
6645 {
6646 /* Find end of point size field. */
6647 for (; *read_from && *read_from != '-'; read_from++)
6648 ;
6649
6650 if (*read_from)
6651 read_from++;
6652
6653 /* Blank out the point size field. */
6654 if (read_from > write_to)
6655 {
6656 *write_to = '-';
6657 write_to++;
6658 }
6659 else
6660 return pixel_height;
6661
6662 break;
6663 }
6664 /* If the point height is already blank, break now. */
6665 if (*read_from == '-')
6666 {
6667 read_from++;
6668 break;
6669 }
6670 }
6671 else if (field_number == 8)
6672 {
6673 /* If we didn't get a pixel height, try to get the point
6674 height and convert that. */
6675 int point_size;
6676 char *point_size_start = read_from++;
6677
6678 /* Find end of field. */
6679 for (; *read_from && *read_from != '-'; read_from++)
6680 ;
6681
6682 if (*read_from)
6683 {
6684 *read_from = '\0';
6685 read_from++;
6686 }
6687
6688 point_size = atoi (point_size_start);
6689
6690 /* Convert to pixel height. */
6691 pixel_height = point_size
6692 * one_w32_display_info.height_in / 720;
6693
6694 /* Blank out this field and break. */
6695 *write_to = '-';
6696 write_to++;
6697 break;
6698 }
6699 }
6700 }
6701
6702 /* Shift the rest of the font spec into place. */
6703 if (write_to && read_from > write_to)
6704 {
6705 for (; *read_from; read_from++, write_to++)
6706 *write_to = *read_from;
6707 *write_to = '\0';
6708 }
6709
6710 return pixel_height;
6711 }
6712
6713 /* Assume parameter 1 is fully qualified, no wildcards. */
6714 static BOOL
6715 w32_font_match (fontname, pattern)
6716 char * fontname;
6717 char * pattern;
6718 {
6719 char *regex = alloca (strlen (pattern) * 2 + 3);
6720 char *font_name_copy = alloca (strlen (fontname) + 1);
6721 char *ptr;
6722
6723 /* Copy fontname so we can modify it during comparison. */
6724 strcpy (font_name_copy, fontname);
6725
6726 ptr = regex;
6727 *ptr++ = '^';
6728
6729 /* Turn pattern into a regexp and do a regexp match. */
6730 for (; *pattern; pattern++)
6731 {
6732 if (*pattern == '?')
6733 *ptr++ = '.';
6734 else if (*pattern == '*')
6735 {
6736 *ptr++ = '.';
6737 *ptr++ = '*';
6738 }
6739 else
6740 *ptr++ = *pattern;
6741 }
6742 *ptr = '$';
6743 *(ptr + 1) = '\0';
6744
6745 /* Strip out font heights and compare them seperately, since
6746 rounding error can cause mismatches. This also allows a
6747 comparison between a font that declares only a pixel height and a
6748 pattern that declares the point height.
6749 */
6750 {
6751 int font_height, pattern_height;
6752
6753 font_height = xlfd_strip_height (font_name_copy);
6754 pattern_height = xlfd_strip_height (regex);
6755
6756 /* Compare now, and don't bother doing expensive regexp matching
6757 if the heights differ. */
6758 if (font_height && pattern_height && (font_height != pattern_height))
6759 return FALSE;
6760 }
6761
6762 return (fast_c_string_match_ignore_case (build_string (regex),
6763 font_name_copy) >= 0);
6764 }
6765
6766 /* Callback functions, and a structure holding info they need, for
6767 listing system fonts on W32. We need one set of functions to do the
6768 job properly, but these don't work on NT 3.51 and earlier, so we
6769 have a second set which don't handle character sets properly to
6770 fall back on.
6771
6772 In both cases, there are two passes made. The first pass gets one
6773 font from each family, the second pass lists all the fonts from
6774 each family. */
6775
6776 typedef struct enumfont_t
6777 {
6778 HDC hdc;
6779 int numFonts;
6780 LOGFONT logfont;
6781 XFontStruct *size_ref;
6782 Lisp_Object *pattern;
6783 Lisp_Object *tail;
6784 } enumfont_t;
6785
6786 static int CALLBACK
6787 enum_font_cb2 (lplf, lptm, FontType, lpef)
6788 ENUMLOGFONT * lplf;
6789 NEWTEXTMETRIC * lptm;
6790 int FontType;
6791 enumfont_t * lpef;
6792 {
6793 /* Ignore struck out and underlined versions of fonts. */
6794 if (lplf->elfLogFont.lfStrikeOut || lplf->elfLogFont.lfUnderline)
6795 return 1;
6796
6797 /* Only return fonts with names starting with @ if they were
6798 explicitly specified, since Microsoft uses an initial @ to
6799 denote fonts for vertical writing, without providing a more
6800 convenient way of identifying them. */
6801 if (lplf->elfLogFont.lfFaceName[0] == '@'
6802 && lpef->logfont.lfFaceName[0] != '@')
6803 return 1;
6804
6805 /* Check that the character set matches if it was specified */
6806 if (lpef->logfont.lfCharSet != DEFAULT_CHARSET &&
6807 lplf->elfLogFont.lfCharSet != lpef->logfont.lfCharSet)
6808 return 1;
6809
6810 {
6811 char buf[100];
6812 Lisp_Object width = Qnil;
6813 char *charset = NULL;
6814
6815 /* Truetype fonts do not report their true metrics until loaded */
6816 if (FontType != RASTER_FONTTYPE)
6817 {
6818 if (!NILP (*(lpef->pattern)))
6819 {
6820 /* Scalable fonts are as big as you want them to be. */
6821 lplf->elfLogFont.lfHeight = lpef->logfont.lfHeight;
6822 lplf->elfLogFont.lfWidth = lpef->logfont.lfWidth;
6823 width = make_number (lpef->logfont.lfWidth);
6824 }
6825 else
6826 {
6827 lplf->elfLogFont.lfHeight = 0;
6828 lplf->elfLogFont.lfWidth = 0;
6829 }
6830 }
6831
6832 /* Make sure the height used here is the same as everywhere
6833 else (ie character height, not cell height). */
6834 if (lplf->elfLogFont.lfHeight > 0)
6835 {
6836 /* lptm can be trusted for RASTER fonts, but not scalable ones. */
6837 if (FontType == RASTER_FONTTYPE)
6838 lplf->elfLogFont.lfHeight = lptm->tmInternalLeading - lptm->tmHeight;
6839 else
6840 lplf->elfLogFont.lfHeight = -lplf->elfLogFont.lfHeight;
6841 }
6842
6843 if (!NILP (*(lpef->pattern)))
6844 {
6845 charset = xlfd_charset_of_font (XSTRING(*(lpef->pattern))->data);
6846
6847 /* Ensure that charset is valid for this font. */
6848 if (charset
6849 && (x_to_w32_charset (charset) != lplf->elfLogFont.lfCharSet))
6850 charset = NULL;
6851 }
6852
6853 /* TODO: List all relevant charsets if charset not specified. */
6854 if (!w32_to_x_font (&(lplf->elfLogFont), buf, 100, charset))
6855 return 1;
6856
6857 if (NILP (*(lpef->pattern))
6858 || w32_font_match (buf, XSTRING (*(lpef->pattern))->data))
6859 {
6860 *lpef->tail = Fcons (Fcons (build_string (buf), width), Qnil);
6861 lpef->tail = &(XCDR (*lpef->tail));
6862 lpef->numFonts++;
6863 }
6864 }
6865
6866 return 1;
6867 }
6868
6869 static int CALLBACK
6870 enum_font_cb1 (lplf, lptm, FontType, lpef)
6871 ENUMLOGFONT * lplf;
6872 NEWTEXTMETRIC * lptm;
6873 int FontType;
6874 enumfont_t * lpef;
6875 {
6876 return EnumFontFamilies (lpef->hdc,
6877 lplf->elfLogFont.lfFaceName,
6878 (FONTENUMPROC) enum_font_cb2,
6879 (LPARAM) lpef);
6880 }
6881
6882
6883 static int CALLBACK
6884 enum_fontex_cb2 (lplf, lptm, font_type, lpef)
6885 ENUMLOGFONTEX * lplf;
6886 NEWTEXTMETRICEX * lptm;
6887 int font_type;
6888 enumfont_t * lpef;
6889 {
6890 /* We are not interested in the extra info we get back from the 'Ex
6891 version - only the fact that we get character set variations
6892 enumerated seperately. */
6893 return enum_font_cb2 ((ENUMLOGFONT *) lplf, (NEWTEXTMETRIC *) lptm,
6894 font_type, lpef);
6895 }
6896
6897 static int CALLBACK
6898 enum_fontex_cb1 (lplf, lptm, font_type, lpef)
6899 ENUMLOGFONTEX * lplf;
6900 NEWTEXTMETRICEX * lptm;
6901 int font_type;
6902 enumfont_t * lpef;
6903 {
6904 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
6905 FARPROC enum_font_families_ex
6906 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
6907 /* We don't really expect EnumFontFamiliesEx to disappear once we
6908 get here, so don't bother handling it gracefully. */
6909 if (enum_font_families_ex == NULL)
6910 error ("gdi32.dll has disappeared!");
6911 return enum_font_families_ex (lpef->hdc,
6912 &lplf->elfLogFont,
6913 (FONTENUMPROC) enum_fontex_cb2,
6914 (LPARAM) lpef, 0);
6915 }
6916
6917 /* Interface to fontset handler. (adapted from mw32font.c in Meadow
6918 and xterm.c in Emacs 20.3) */
6919
6920 static Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names)
6921 {
6922 char *fontname, *ptnstr;
6923 Lisp_Object list, tem, newlist = Qnil;
6924 int n_fonts = 0;
6925
6926 list = Vw32_bdf_filename_alist;
6927 ptnstr = XSTRING (pattern)->data;
6928
6929 for ( ; CONSP (list); list = XCDR (list))
6930 {
6931 tem = XCAR (list);
6932 if (CONSP (tem))
6933 fontname = XSTRING (XCAR (tem))->data;
6934 else if (STRINGP (tem))
6935 fontname = XSTRING (tem)->data;
6936 else
6937 continue;
6938
6939 if (w32_font_match (fontname, ptnstr))
6940 {
6941 newlist = Fcons (XCAR (tem), newlist);
6942 n_fonts++;
6943 if (n_fonts >= max_names)
6944 break;
6945 }
6946 }
6947
6948 return newlist;
6949 }
6950
6951 static Lisp_Object w32_list_synthesized_fonts (FRAME_PTR f,
6952 Lisp_Object pattern,
6953 int size, int max_names);
6954
6955 /* Return a list of names of available fonts matching PATTERN on frame
6956 F. If SIZE is not 0, it is the size (maximum bound width) of fonts
6957 to be listed. Frame F NULL means we have not yet created any
6958 frame, which means we can't get proper size info, as we don't have
6959 a device context to use for GetTextMetrics.
6960 MAXNAMES sets a limit on how many fonts to match. */
6961
6962 Lisp_Object
6963 w32_list_fonts (f, pattern, size, maxnames)
6964 struct frame *f;
6965 Lisp_Object pattern;
6966 int size;
6967 int maxnames;
6968 {
6969 Lisp_Object patterns, key = Qnil, tem, tpat;
6970 Lisp_Object list = Qnil, newlist = Qnil, second_best = Qnil;
6971 struct w32_display_info *dpyinfo = &one_w32_display_info;
6972 int n_fonts = 0;
6973
6974 patterns = Fassoc (pattern, Valternate_fontname_alist);
6975 if (NILP (patterns))
6976 patterns = Fcons (pattern, Qnil);
6977
6978 for (; CONSP (patterns); patterns = XCDR (patterns))
6979 {
6980 enumfont_t ef;
6981 int codepage;
6982
6983 tpat = XCAR (patterns);
6984
6985 if (!STRINGP (tpat))
6986 continue;
6987
6988 /* Avoid expensive EnumFontFamilies functions if we are not
6989 going to be able to output one of these anyway. */
6990 codepage = w32_codepage_for_font (XSTRING (tpat)->data);
6991 if (codepage != CP_8BIT && codepage != CP_UNICODE
6992 && codepage != CP_DEFAULT && codepage != CP_UNKNOWN
6993 && !IsValidCodePage(codepage))
6994 continue;
6995
6996 /* See if we cached the result for this particular query.
6997 The cache is an alist of the form:
6998 ((PATTERN (FONTNAME . WIDTH) ...) ...)
6999 */
7000 if (tem = XCDR (dpyinfo->name_list_element),
7001 !NILP (list = Fassoc (tpat, tem)))
7002 {
7003 list = Fcdr_safe (list);
7004 /* We have a cached list. Don't have to get the list again. */
7005 goto label_cached;
7006 }
7007
7008 BLOCK_INPUT;
7009 /* At first, put PATTERN in the cache. */
7010 list = Qnil;
7011 ef.pattern = &tpat;
7012 ef.tail = &list;
7013 ef.numFonts = 0;
7014
7015 /* Use EnumFontFamiliesEx where it is available, as it knows
7016 about character sets. Fall back to EnumFontFamilies for
7017 older versions of NT that don't support the 'Ex function. */
7018 x_to_w32_font (XSTRING (tpat)->data, &ef.logfont);
7019 {
7020 LOGFONT font_match_pattern;
7021 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
7022 FARPROC enum_font_families_ex
7023 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
7024
7025 /* We do our own pattern matching so we can handle wildcards. */
7026 font_match_pattern.lfFaceName[0] = 0;
7027 font_match_pattern.lfPitchAndFamily = 0;
7028 /* We can use the charset, because if it is a wildcard it will
7029 be DEFAULT_CHARSET anyway. */
7030 font_match_pattern.lfCharSet = ef.logfont.lfCharSet;
7031
7032 ef.hdc = GetDC (dpyinfo->root_window);
7033
7034 if (enum_font_families_ex)
7035 enum_font_families_ex (ef.hdc,
7036 &font_match_pattern,
7037 (FONTENUMPROC) enum_fontex_cb1,
7038 (LPARAM) &ef, 0);
7039 else
7040 EnumFontFamilies (ef.hdc, NULL, (FONTENUMPROC) enum_font_cb1,
7041 (LPARAM)&ef);
7042
7043 ReleaseDC (dpyinfo->root_window, ef.hdc);
7044 }
7045
7046 UNBLOCK_INPUT;
7047
7048 /* Make a list of the fonts we got back.
7049 Store that in the font cache for the display. */
7050 XSETCDR (dpyinfo->name_list_element,
7051 Fcons (Fcons (tpat, list),
7052 XCDR (dpyinfo->name_list_element)));
7053
7054 label_cached:
7055 if (NILP (list)) continue; /* Try the remaining alternatives. */
7056
7057 newlist = second_best = Qnil;
7058
7059 /* Make a list of the fonts that have the right width. */
7060 for (; CONSP (list); list = XCDR (list))
7061 {
7062 int found_size;
7063 tem = XCAR (list);
7064
7065 if (!CONSP (tem))
7066 continue;
7067 if (NILP (XCAR (tem)))
7068 continue;
7069 if (!size)
7070 {
7071 newlist = Fcons (XCAR (tem), newlist);
7072 n_fonts++;
7073 if (n_fonts >= maxnames)
7074 break;
7075 else
7076 continue;
7077 }
7078 if (!INTEGERP (XCDR (tem)))
7079 {
7080 /* Since we don't yet know the size of the font, we must
7081 load it and try GetTextMetrics. */
7082 W32FontStruct thisinfo;
7083 LOGFONT lf;
7084 HDC hdc;
7085 HANDLE oldobj;
7086
7087 if (!x_to_w32_font (XSTRING (XCAR (tem))->data, &lf))
7088 continue;
7089
7090 BLOCK_INPUT;
7091 thisinfo.bdf = NULL;
7092 thisinfo.hfont = CreateFontIndirect (&lf);
7093 if (thisinfo.hfont == NULL)
7094 continue;
7095
7096 hdc = GetDC (dpyinfo->root_window);
7097 oldobj = SelectObject (hdc, thisinfo.hfont);
7098 if (GetTextMetrics (hdc, &thisinfo.tm))
7099 XSETCDR (tem, make_number (FONT_WIDTH (&thisinfo)));
7100 else
7101 XSETCDR (tem, make_number (0));
7102 SelectObject (hdc, oldobj);
7103 ReleaseDC (dpyinfo->root_window, hdc);
7104 DeleteObject(thisinfo.hfont);
7105 UNBLOCK_INPUT;
7106 }
7107 found_size = XINT (XCDR (tem));
7108 if (found_size == size)
7109 {
7110 newlist = Fcons (XCAR (tem), newlist);
7111 n_fonts++;
7112 if (n_fonts >= maxnames)
7113 break;
7114 }
7115 /* keep track of the closest matching size in case
7116 no exact match is found. */
7117 else if (found_size > 0)
7118 {
7119 if (NILP (second_best))
7120 second_best = tem;
7121
7122 else if (found_size < size)
7123 {
7124 if (XINT (XCDR (second_best)) > size
7125 || XINT (XCDR (second_best)) < found_size)
7126 second_best = tem;
7127 }
7128 else
7129 {
7130 if (XINT (XCDR (second_best)) > size
7131 && XINT (XCDR (second_best)) >
7132 found_size)
7133 second_best = tem;
7134 }
7135 }
7136 }
7137
7138 if (!NILP (newlist))
7139 break;
7140 else if (!NILP (second_best))
7141 {
7142 newlist = Fcons (XCAR (second_best), Qnil);
7143 break;
7144 }
7145 }
7146
7147 /* Include any bdf fonts. */
7148 if (n_fonts < maxnames)
7149 {
7150 Lisp_Object combined[2];
7151 combined[0] = w32_list_bdf_fonts (pattern, maxnames - n_fonts);
7152 combined[1] = newlist;
7153 newlist = Fnconc(2, combined);
7154 }
7155
7156 /* If we can't find a font that matches, check if Windows would be
7157 able to synthesize it from a different style. */
7158 if (NILP (newlist) && !NILP (Vw32_enable_synthesized_fonts))
7159 newlist = w32_list_synthesized_fonts (f, pattern, size, maxnames);
7160
7161 return newlist;
7162 }
7163
7164 static Lisp_Object
7165 w32_list_synthesized_fonts (f, pattern, size, max_names)
7166 FRAME_PTR f;
7167 Lisp_Object pattern;
7168 int size;
7169 int max_names;
7170 {
7171 int fields;
7172 char *full_pattn, *new_pattn, foundary[50], family[50], *pattn_part2;
7173 char style[20], slant;
7174 Lisp_Object matches, tem, synthed_matches = Qnil;
7175
7176 full_pattn = XSTRING (pattern)->data;
7177
7178 pattn_part2 = alloca (XSTRING (pattern)->size + 1);
7179 /* Allow some space for wildcard expansion. */
7180 new_pattn = alloca (XSTRING (pattern)->size + 100);
7181
7182 fields = sscanf (full_pattn, "-%49[^-]-%49[^-]-%19[^-]-%c-%s",
7183 foundary, family, style, &slant, pattn_part2);
7184 if (fields == EOF || fields < 5)
7185 return Qnil;
7186
7187 /* If the style and slant are wildcards already there is no point
7188 checking again (and we don't want to keep recursing). */
7189 if (*style == '*' && slant == '*')
7190 return Qnil;
7191
7192 sprintf (new_pattn, "-%s-%s-*-*-%s", foundary, family, pattn_part2);
7193
7194 matches = w32_list_fonts (f, build_string (new_pattn), size, max_names);
7195
7196 for ( ; CONSP (matches); matches = XCDR (matches))
7197 {
7198 tem = XCAR (matches);
7199 if (!STRINGP (tem))
7200 continue;
7201
7202 full_pattn = XSTRING (tem)->data;
7203 fields = sscanf (full_pattn, "-%49[^-]-%49[^-]-%*[^-]-%*c-%s",
7204 foundary, family, pattn_part2);
7205 if (fields == EOF || fields < 3)
7206 continue;
7207
7208 sprintf (new_pattn, "-%s-%s-%s-%c-%s", foundary, family, style,
7209 slant, pattn_part2);
7210
7211 synthed_matches = Fcons (build_string (new_pattn),
7212 synthed_matches);
7213 }
7214
7215 return synthed_matches;
7216 }
7217
7218
7219 /* Return a pointer to struct font_info of font FONT_IDX of frame F. */
7220 struct font_info *
7221 w32_get_font_info (f, font_idx)
7222 FRAME_PTR f;
7223 int font_idx;
7224 {
7225 return (FRAME_W32_FONT_TABLE (f) + font_idx);
7226 }
7227
7228
7229 struct font_info*
7230 w32_query_font (struct frame *f, char *fontname)
7231 {
7232 int i;
7233 struct font_info *pfi;
7234
7235 pfi = FRAME_W32_FONT_TABLE (f);
7236
7237 for (i = 0; i < one_w32_display_info.n_fonts ;i++, pfi++)
7238 {
7239 if (strcmp(pfi->name, fontname) == 0) return pfi;
7240 }
7241
7242 return NULL;
7243 }
7244
7245 /* Find a CCL program for a font specified by FONTP, and set the member
7246 `encoder' of the structure. */
7247
7248 void
7249 w32_find_ccl_program (fontp)
7250 struct font_info *fontp;
7251 {
7252 Lisp_Object list, elt;
7253
7254 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
7255 {
7256 elt = XCAR (list);
7257 if (CONSP (elt)
7258 && STRINGP (XCAR (elt))
7259 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
7260 >= 0))
7261 break;
7262 }
7263 if (! NILP (list))
7264 {
7265 struct ccl_program *ccl
7266 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
7267
7268 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
7269 xfree (ccl);
7270 else
7271 fontp->font_encoder = ccl;
7272 }
7273 }
7274
7275 \f
7276 /* Find BDF files in a specified directory. (use GCPRO when calling,
7277 as this calls lisp to get a directory listing). */
7278 static Lisp_Object
7279 w32_find_bdf_fonts_in_dir (Lisp_Object directory)
7280 {
7281 Lisp_Object filelist, list = Qnil;
7282 char fontname[100];
7283
7284 if (!STRINGP(directory))
7285 return Qnil;
7286
7287 filelist = Fdirectory_files (directory, Qt,
7288 build_string (".*\\.[bB][dD][fF]"), Qt);
7289
7290 for ( ; CONSP(filelist); filelist = XCDR (filelist))
7291 {
7292 Lisp_Object filename = XCAR (filelist);
7293 if (w32_BDF_to_x_font (XSTRING (filename)->data, fontname, 100))
7294 store_in_alist (&list, build_string (fontname), filename);
7295 }
7296 return list;
7297 }
7298
7299 DEFUN ("w32-find-bdf-fonts", Fw32_find_bdf_fonts, Sw32_find_bdf_fonts,
7300 1, 1, 0,
7301 doc: /* Return a list of BDF fonts in DIR.
7302 The list is suitable for appending to w32-bdf-filename-alist. Fonts
7303 which do not contain an xlfd description will not be included in the
7304 list. DIR may be a list of directories. */)
7305 (directory)
7306 Lisp_Object directory;
7307 {
7308 Lisp_Object list = Qnil;
7309 struct gcpro gcpro1, gcpro2;
7310
7311 if (!CONSP (directory))
7312 return w32_find_bdf_fonts_in_dir (directory);
7313
7314 for ( ; CONSP (directory); directory = XCDR (directory))
7315 {
7316 Lisp_Object pair[2];
7317 pair[0] = list;
7318 pair[1] = Qnil;
7319 GCPRO2 (directory, list);
7320 pair[1] = w32_find_bdf_fonts_in_dir( XCAR (directory) );
7321 list = Fnconc( 2, pair );
7322 UNGCPRO;
7323 }
7324 return list;
7325 }
7326
7327 \f
7328 DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
7329 doc: /* Internal function called by `color-defined-p', which see. */)
7330 (color, frame)
7331 Lisp_Object color, frame;
7332 {
7333 XColor foo;
7334 FRAME_PTR f = check_x_frame (frame);
7335
7336 CHECK_STRING (color);
7337
7338 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
7339 return Qt;
7340 else
7341 return Qnil;
7342 }
7343
7344 DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
7345 doc: /* Internal function called by `color-values', which see. */)
7346 (color, frame)
7347 Lisp_Object color, frame;
7348 {
7349 XColor foo;
7350 FRAME_PTR f = check_x_frame (frame);
7351
7352 CHECK_STRING (color);
7353
7354 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
7355 {
7356 Lisp_Object rgb[3];
7357
7358 rgb[0] = make_number ((GetRValue (foo.pixel) << 8)
7359 | GetRValue (foo.pixel));
7360 rgb[1] = make_number ((GetGValue (foo.pixel) << 8)
7361 | GetGValue (foo.pixel));
7362 rgb[2] = make_number ((GetBValue (foo.pixel) << 8)
7363 | GetBValue (foo.pixel));
7364 return Flist (3, rgb);
7365 }
7366 else
7367 return Qnil;
7368 }
7369
7370 DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
7371 doc: /* Internal function called by `display-color-p', which see. */)
7372 (display)
7373 Lisp_Object display;
7374 {
7375 struct w32_display_info *dpyinfo = check_x_display_info (display);
7376
7377 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 2)
7378 return Qnil;
7379
7380 return Qt;
7381 }
7382
7383 DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p,
7384 Sx_display_grayscale_p, 0, 1, 0,
7385 doc: /* Return t if the X display supports shades of gray.
7386 Note that color displays do support shades of gray.
7387 The optional argument DISPLAY specifies which display to ask about.
7388 DISPLAY should be either a frame or a display name (a string).
7389 If omitted or nil, that stands for the selected frame's display. */)
7390 (display)
7391 Lisp_Object display;
7392 {
7393 struct w32_display_info *dpyinfo = check_x_display_info (display);
7394
7395 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 1)
7396 return Qnil;
7397
7398 return Qt;
7399 }
7400
7401 DEFUN ("x-display-pixel-width", Fx_display_pixel_width,
7402 Sx_display_pixel_width, 0, 1, 0,
7403 doc: /* Returns the width in pixels of DISPLAY.
7404 The optional argument DISPLAY specifies which display to ask about.
7405 DISPLAY should be either a frame or a display name (a string).
7406 If omitted or nil, that stands for the selected frame's display. */)
7407 (display)
7408 Lisp_Object display;
7409 {
7410 struct w32_display_info *dpyinfo = check_x_display_info (display);
7411
7412 return make_number (dpyinfo->width);
7413 }
7414
7415 DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
7416 Sx_display_pixel_height, 0, 1, 0,
7417 doc: /* Returns the height in pixels of DISPLAY.
7418 The optional argument DISPLAY specifies which display to ask about.
7419 DISPLAY should be either a frame or a display name (a string).
7420 If omitted or nil, that stands for the selected frame's display. */)
7421 (display)
7422 Lisp_Object display;
7423 {
7424 struct w32_display_info *dpyinfo = check_x_display_info (display);
7425
7426 return make_number (dpyinfo->height);
7427 }
7428
7429 DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
7430 0, 1, 0,
7431 doc: /* Returns the number of bitplanes of DISPLAY.
7432 The optional argument DISPLAY specifies which display to ask about.
7433 DISPLAY should be either a frame or a display name (a string).
7434 If omitted or nil, that stands for the selected frame's display. */)
7435 (display)
7436 Lisp_Object display;
7437 {
7438 struct w32_display_info *dpyinfo = check_x_display_info (display);
7439
7440 return make_number (dpyinfo->n_planes * dpyinfo->n_cbits);
7441 }
7442
7443 DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
7444 0, 1, 0,
7445 doc: /* Returns the number of color cells of DISPLAY.
7446 The optional argument DISPLAY specifies which display to ask about.
7447 DISPLAY should be either a frame or a display name (a string).
7448 If omitted or nil, that stands for the selected frame's display. */)
7449 (display)
7450 Lisp_Object display;
7451 {
7452 struct w32_display_info *dpyinfo = check_x_display_info (display);
7453 HDC hdc;
7454 int cap;
7455
7456 hdc = GetDC (dpyinfo->root_window);
7457 if (dpyinfo->has_palette)
7458 cap = GetDeviceCaps (hdc,SIZEPALETTE);
7459 else
7460 cap = GetDeviceCaps (hdc,NUMCOLORS);
7461
7462 if (cap < 0)
7463 cap = 1 << (dpyinfo->n_planes * dpyinfo->n_cbits);
7464
7465 ReleaseDC (dpyinfo->root_window, hdc);
7466
7467 return make_number (cap);
7468 }
7469
7470 DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
7471 Sx_server_max_request_size,
7472 0, 1, 0,
7473 doc: /* Returns the maximum request size of the server of DISPLAY.
7474 The optional argument DISPLAY specifies which display to ask about.
7475 DISPLAY should be either a frame or a display name (a string).
7476 If omitted or nil, that stands for the selected frame's display. */)
7477 (display)
7478 Lisp_Object display;
7479 {
7480 struct w32_display_info *dpyinfo = check_x_display_info (display);
7481
7482 return make_number (1);
7483 }
7484
7485 DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
7486 doc: /* Returns the vendor ID string of the W32 system (Microsoft).
7487 The optional argument DISPLAY specifies which display to ask about.
7488 DISPLAY should be either a frame or a display name (a string).
7489 If omitted or nil, that stands for the selected frame's display. */)
7490 (display)
7491 Lisp_Object display;
7492 {
7493 return build_string ("Microsoft Corp.");
7494 }
7495
7496 DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
7497 doc: /* Returns the version numbers of the server of DISPLAY.
7498 The value is a list of three integers: the major and minor
7499 version numbers, and the vendor-specific release
7500 number. See also the function `x-server-vendor'.
7501
7502 The optional argument DISPLAY specifies which display to ask about.
7503 DISPLAY should be either a frame or a display name (a string).
7504 If omitted or nil, that stands for the selected frame's display. */)
7505 (display)
7506 Lisp_Object display;
7507 {
7508 return Fcons (make_number (w32_major_version),
7509 Fcons (make_number (w32_minor_version),
7510 Fcons (make_number (w32_build_number), Qnil)));
7511 }
7512
7513 DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
7514 doc: /* Returns the number of screens on the server of DISPLAY.
7515 The optional argument DISPLAY specifies which display to ask about.
7516 DISPLAY should be either a frame or a display name (a string).
7517 If omitted or nil, that stands for the selected frame's display. */)
7518 (display)
7519 Lisp_Object display;
7520 {
7521 return make_number (1);
7522 }
7523
7524 DEFUN ("x-display-mm-height", Fx_display_mm_height,
7525 Sx_display_mm_height, 0, 1, 0,
7526 doc: /* Returns the height in millimeters of DISPLAY.
7527 The optional argument DISPLAY specifies which display to ask about.
7528 DISPLAY should be either a frame or a display name (a string).
7529 If omitted or nil, that stands for the selected frame's display. */)
7530 (display)
7531 Lisp_Object display;
7532 {
7533 struct w32_display_info *dpyinfo = check_x_display_info (display);
7534 HDC hdc;
7535 int cap;
7536
7537 hdc = GetDC (dpyinfo->root_window);
7538
7539 cap = GetDeviceCaps (hdc, VERTSIZE);
7540
7541 ReleaseDC (dpyinfo->root_window, hdc);
7542
7543 return make_number (cap);
7544 }
7545
7546 DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
7547 doc: /* Returns the width in millimeters of DISPLAY.
7548 The optional argument DISPLAY specifies which display to ask about.
7549 DISPLAY should be either a frame or a display name (a string).
7550 If omitted or nil, that stands for the selected frame's display. */)
7551 (display)
7552 Lisp_Object display;
7553 {
7554 struct w32_display_info *dpyinfo = check_x_display_info (display);
7555
7556 HDC hdc;
7557 int cap;
7558
7559 hdc = GetDC (dpyinfo->root_window);
7560
7561 cap = GetDeviceCaps (hdc, HORZSIZE);
7562
7563 ReleaseDC (dpyinfo->root_window, hdc);
7564
7565 return make_number (cap);
7566 }
7567
7568 DEFUN ("x-display-backing-store", Fx_display_backing_store,
7569 Sx_display_backing_store, 0, 1, 0,
7570 doc: /* Returns an indication of whether DISPLAY does backing store.
7571 The value may be `always', `when-mapped', or `not-useful'.
7572 The optional argument DISPLAY specifies which display to ask about.
7573 DISPLAY should be either a frame or a display name (a string).
7574 If omitted or nil, that stands for the selected frame's display. */)
7575 (display)
7576 Lisp_Object display;
7577 {
7578 return intern ("not-useful");
7579 }
7580
7581 DEFUN ("x-display-visual-class", Fx_display_visual_class,
7582 Sx_display_visual_class, 0, 1, 0,
7583 doc: /* Returns the visual class of DISPLAY.
7584 The value is one of the symbols `static-gray', `gray-scale',
7585 `static-color', `pseudo-color', `true-color', or `direct-color'.
7586
7587 The optional argument DISPLAY specifies which display to ask about.
7588 DISPLAY should be either a frame or a display name (a string).
7589 If omitted or nil, that stands for the selected frame's display. */)
7590 (display)
7591 Lisp_Object display;
7592 {
7593 struct w32_display_info *dpyinfo = check_x_display_info (display);
7594 Lisp_Object result = Qnil;
7595
7596 if (dpyinfo->has_palette)
7597 result = intern ("pseudo-color");
7598 else if (dpyinfo->n_planes * dpyinfo->n_cbits == 1)
7599 result = intern ("static-grey");
7600 else if (dpyinfo->n_planes * dpyinfo->n_cbits == 4)
7601 result = intern ("static-color");
7602 else if (dpyinfo->n_planes * dpyinfo->n_cbits > 8)
7603 result = intern ("true-color");
7604
7605 return result;
7606 }
7607
7608 DEFUN ("x-display-save-under", Fx_display_save_under,
7609 Sx_display_save_under, 0, 1, 0,
7610 doc: /* Returns t if DISPLAY supports the save-under feature.
7611 The optional argument DISPLAY specifies which display to ask about.
7612 DISPLAY should be either a frame or a display name (a string).
7613 If omitted or nil, that stands for the selected frame's display. */)
7614 (display)
7615 Lisp_Object display;
7616 {
7617 return Qnil;
7618 }
7619 \f
7620 int
7621 x_pixel_width (f)
7622 register struct frame *f;
7623 {
7624 return PIXEL_WIDTH (f);
7625 }
7626
7627 int
7628 x_pixel_height (f)
7629 register struct frame *f;
7630 {
7631 return PIXEL_HEIGHT (f);
7632 }
7633
7634 int
7635 x_char_width (f)
7636 register struct frame *f;
7637 {
7638 return FONT_WIDTH (f->output_data.w32->font);
7639 }
7640
7641 int
7642 x_char_height (f)
7643 register struct frame *f;
7644 {
7645 return f->output_data.w32->line_height;
7646 }
7647
7648 int
7649 x_screen_planes (f)
7650 register struct frame *f;
7651 {
7652 return FRAME_W32_DISPLAY_INFO (f)->n_planes;
7653 }
7654 \f
7655 /* Return the display structure for the display named NAME.
7656 Open a new connection if necessary. */
7657
7658 struct w32_display_info *
7659 x_display_info_for_name (name)
7660 Lisp_Object name;
7661 {
7662 Lisp_Object names;
7663 struct w32_display_info *dpyinfo;
7664
7665 CHECK_STRING (name);
7666
7667 for (dpyinfo = &one_w32_display_info, names = w32_display_name_list;
7668 dpyinfo;
7669 dpyinfo = dpyinfo->next, names = XCDR (names))
7670 {
7671 Lisp_Object tem;
7672 tem = Fstring_equal (XCAR (XCAR (names)), name);
7673 if (!NILP (tem))
7674 return dpyinfo;
7675 }
7676
7677 /* Use this general default value to start with. */
7678 Vx_resource_name = Vinvocation_name;
7679
7680 validate_x_resource_name ();
7681
7682 dpyinfo = w32_term_init (name, (unsigned char *)0,
7683 (char *) XSTRING (Vx_resource_name)->data);
7684
7685 if (dpyinfo == 0)
7686 error ("Cannot connect to server %s", XSTRING (name)->data);
7687
7688 w32_in_use = 1;
7689 XSETFASTINT (Vwindow_system_version, 3);
7690
7691 return dpyinfo;
7692 }
7693
7694 DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
7695 1, 3, 0, doc: /* Open a connection to a server.
7696 DISPLAY is the name of the display to connect to.
7697 Optional second arg XRM-STRING is a string of resources in xrdb format.
7698 If the optional third arg MUST-SUCCEED is non-nil,
7699 terminate Emacs if we can't open the connection. */)
7700 (display, xrm_string, must_succeed)
7701 Lisp_Object display, xrm_string, must_succeed;
7702 {
7703 unsigned char *xrm_option;
7704 struct w32_display_info *dpyinfo;
7705
7706 /* If initialization has already been done, return now to avoid
7707 overwriting critical parts of one_w32_display_info. */
7708 if (w32_in_use)
7709 return Qnil;
7710
7711 CHECK_STRING (display);
7712 if (! NILP (xrm_string))
7713 CHECK_STRING (xrm_string);
7714
7715 if (! EQ (Vwindow_system, intern ("w32")))
7716 error ("Not using Microsoft Windows");
7717
7718 /* Allow color mapping to be defined externally; first look in user's
7719 HOME directory, then in Emacs etc dir for a file called rgb.txt. */
7720 {
7721 Lisp_Object color_file;
7722 struct gcpro gcpro1;
7723
7724 color_file = build_string("~/rgb.txt");
7725
7726 GCPRO1 (color_file);
7727
7728 if (NILP (Ffile_readable_p (color_file)))
7729 color_file =
7730 Fexpand_file_name (build_string ("rgb.txt"),
7731 Fsymbol_value (intern ("data-directory")));
7732
7733 Vw32_color_map = Fw32_load_color_file (color_file);
7734
7735 UNGCPRO;
7736 }
7737 if (NILP (Vw32_color_map))
7738 Vw32_color_map = Fw32_default_color_map ();
7739
7740 if (! NILP (xrm_string))
7741 xrm_option = (unsigned char *) XSTRING (xrm_string)->data;
7742 else
7743 xrm_option = (unsigned char *) 0;
7744
7745 /* Use this general default value to start with. */
7746 /* First remove .exe suffix from invocation-name - it looks ugly. */
7747 {
7748 char basename[ MAX_PATH ], *str;
7749
7750 strcpy (basename, XSTRING (Vinvocation_name)->data);
7751 str = strrchr (basename, '.');
7752 if (str) *str = 0;
7753 Vinvocation_name = build_string (basename);
7754 }
7755 Vx_resource_name = Vinvocation_name;
7756
7757 validate_x_resource_name ();
7758
7759 /* This is what opens the connection and sets x_current_display.
7760 This also initializes many symbols, such as those used for input. */
7761 dpyinfo = w32_term_init (display, xrm_option,
7762 (char *) XSTRING (Vx_resource_name)->data);
7763
7764 if (dpyinfo == 0)
7765 {
7766 if (!NILP (must_succeed))
7767 fatal ("Cannot connect to server %s.\n",
7768 XSTRING (display)->data);
7769 else
7770 error ("Cannot connect to server %s", XSTRING (display)->data);
7771 }
7772
7773 w32_in_use = 1;
7774
7775 XSETFASTINT (Vwindow_system_version, 3);
7776 return Qnil;
7777 }
7778
7779 DEFUN ("x-close-connection", Fx_close_connection,
7780 Sx_close_connection, 1, 1, 0,
7781 doc: /* Close the connection to DISPLAY's server.
7782 For DISPLAY, specify either a frame or a display name (a string).
7783 If DISPLAY is nil, that stands for the selected frame's display. */)
7784 (display)
7785 Lisp_Object display;
7786 {
7787 struct w32_display_info *dpyinfo = check_x_display_info (display);
7788 int i;
7789
7790 if (dpyinfo->reference_count > 0)
7791 error ("Display still has frames on it");
7792
7793 BLOCK_INPUT;
7794 /* Free the fonts in the font table. */
7795 for (i = 0; i < dpyinfo->n_fonts; i++)
7796 if (dpyinfo->font_table[i].name)
7797 {
7798 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
7799 xfree (dpyinfo->font_table[i].full_name);
7800 xfree (dpyinfo->font_table[i].name);
7801 w32_unload_font (dpyinfo, dpyinfo->font_table[i].font);
7802 }
7803 x_destroy_all_bitmaps (dpyinfo);
7804
7805 x_delete_display (dpyinfo);
7806 UNBLOCK_INPUT;
7807
7808 return Qnil;
7809 }
7810
7811 DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
7812 doc: /* Return the list of display names that Emacs has connections to. */)
7813 ()
7814 {
7815 Lisp_Object tail, result;
7816
7817 result = Qnil;
7818 for (tail = w32_display_name_list; ! NILP (tail); tail = XCDR (tail))
7819 result = Fcons (XCAR (XCAR (tail)), result);
7820
7821 return result;
7822 }
7823
7824 DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0,
7825 doc: /* This is a noop on W32 systems. */)
7826 (on, display)
7827 Lisp_Object display, on;
7828 {
7829 return Qnil;
7830 }
7831
7832 \f
7833 \f
7834 /***********************************************************************
7835 Image types
7836 ***********************************************************************/
7837
7838 /* Value is the number of elements of vector VECTOR. */
7839
7840 #define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))
7841
7842 /* List of supported image types. Use define_image_type to add new
7843 types. Use lookup_image_type to find a type for a given symbol. */
7844
7845 static struct image_type *image_types;
7846
7847 /* The symbol `image' which is the car of the lists used to represent
7848 images in Lisp. */
7849
7850 extern Lisp_Object Qimage;
7851
7852 /* The symbol `xbm' which is used as the type symbol for XBM images. */
7853
7854 Lisp_Object Qxbm;
7855
7856 /* Keywords. */
7857
7858 extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
7859 extern Lisp_Object QCdata;
7860 Lisp_Object QCtype, QCascent, QCmargin, QCrelief;
7861 Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask;
7862 Lisp_Object QCindex, QCmatrix, QCcolor_adjustment, QCmask;
7863
7864 /* Other symbols. */
7865
7866 Lisp_Object Qlaplace, Qemboss, Qedge_detection, Qheuristic;
7867
7868 /* Time in seconds after which images should be removed from the cache
7869 if not displayed. */
7870
7871 Lisp_Object Vimage_cache_eviction_delay;
7872
7873 /* Function prototypes. */
7874
7875 static void define_image_type P_ ((struct image_type *type));
7876 static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
7877 static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
7878 static void x_laplace P_ ((struct frame *, struct image *));
7879 static void x_emboss P_ ((struct frame *, struct image *));
7880 static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
7881 Lisp_Object));
7882
7883
7884 /* Define a new image type from TYPE. This adds a copy of TYPE to
7885 image_types and adds the symbol *TYPE->type to Vimage_types. */
7886
7887 static void
7888 define_image_type (type)
7889 struct image_type *type;
7890 {
7891 /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
7892 The initialized data segment is read-only. */
7893 struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
7894 bcopy (type, p, sizeof *p);
7895 p->next = image_types;
7896 image_types = p;
7897 Vimage_types = Fcons (*p->type, Vimage_types);
7898 }
7899
7900
7901 /* Look up image type SYMBOL, and return a pointer to its image_type
7902 structure. Value is null if SYMBOL is not a known image type. */
7903
7904 static INLINE struct image_type *
7905 lookup_image_type (symbol)
7906 Lisp_Object symbol;
7907 {
7908 struct image_type *type;
7909
7910 for (type = image_types; type; type = type->next)
7911 if (EQ (symbol, *type->type))
7912 break;
7913
7914 return type;
7915 }
7916
7917
7918 /* Value is non-zero if OBJECT is a valid Lisp image specification. A
7919 valid image specification is a list whose car is the symbol
7920 `image', and whose rest is a property list. The property list must
7921 contain a value for key `:type'. That value must be the name of a
7922 supported image type. The rest of the property list depends on the
7923 image type. */
7924
7925 int
7926 valid_image_p (object)
7927 Lisp_Object object;
7928 {
7929 int valid_p = 0;
7930
7931 if (CONSP (object) && EQ (XCAR (object), Qimage))
7932 {
7933 Lisp_Object tem;
7934
7935 for (tem = XCDR (object); CONSP (tem); tem = XCDR (tem))
7936 if (EQ (XCAR (tem), QCtype))
7937 {
7938 tem = XCDR (tem);
7939 if (CONSP (tem) && SYMBOLP (XCAR (tem)))
7940 {
7941 struct image_type *type;
7942 type = lookup_image_type (XCAR (tem));
7943 if (type)
7944 valid_p = type->valid_p (object);
7945 }
7946
7947 break;
7948 }
7949 }
7950
7951 return valid_p;
7952 }
7953
7954
7955 /* Log error message with format string FORMAT and argument ARG.
7956 Signaling an error, e.g. when an image cannot be loaded, is not a
7957 good idea because this would interrupt redisplay, and the error
7958 message display would lead to another redisplay. This function
7959 therefore simply displays a message. */
7960
7961 static void
7962 image_error (format, arg1, arg2)
7963 char *format;
7964 Lisp_Object arg1, arg2;
7965 {
7966 add_to_log (format, arg1, arg2);
7967 }
7968
7969
7970 \f
7971 /***********************************************************************
7972 Image specifications
7973 ***********************************************************************/
7974
7975 enum image_value_type
7976 {
7977 IMAGE_DONT_CHECK_VALUE_TYPE,
7978 IMAGE_STRING_VALUE,
7979 IMAGE_STRING_OR_NIL_VALUE,
7980 IMAGE_SYMBOL_VALUE,
7981 IMAGE_POSITIVE_INTEGER_VALUE,
7982 IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,
7983 IMAGE_NON_NEGATIVE_INTEGER_VALUE,
7984 IMAGE_ASCENT_VALUE,
7985 IMAGE_INTEGER_VALUE,
7986 IMAGE_FUNCTION_VALUE,
7987 IMAGE_NUMBER_VALUE,
7988 IMAGE_BOOL_VALUE
7989 };
7990
7991 /* Structure used when parsing image specifications. */
7992
7993 struct image_keyword
7994 {
7995 /* Name of keyword. */
7996 char *name;
7997
7998 /* The type of value allowed. */
7999 enum image_value_type type;
8000
8001 /* Non-zero means key must be present. */
8002 int mandatory_p;
8003
8004 /* Used to recognize duplicate keywords in a property list. */
8005 int count;
8006
8007 /* The value that was found. */
8008 Lisp_Object value;
8009 };
8010
8011
8012 static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
8013 int, Lisp_Object));
8014 static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
8015
8016
8017 /* Parse image spec SPEC according to KEYWORDS. A valid image spec
8018 has the format (image KEYWORD VALUE ...). One of the keyword/
8019 value pairs must be `:type TYPE'. KEYWORDS is a vector of
8020 image_keywords structures of size NKEYWORDS describing other
8021 allowed keyword/value pairs. Value is non-zero if SPEC is valid. */
8022
8023 static int
8024 parse_image_spec (spec, keywords, nkeywords, type)
8025 Lisp_Object spec;
8026 struct image_keyword *keywords;
8027 int nkeywords;
8028 Lisp_Object type;
8029 {
8030 int i;
8031 Lisp_Object plist;
8032
8033 if (!CONSP (spec) || !EQ (XCAR (spec), Qimage))
8034 return 0;
8035
8036 plist = XCDR (spec);
8037 while (CONSP (plist))
8038 {
8039 Lisp_Object key, value;
8040
8041 /* First element of a pair must be a symbol. */
8042 key = XCAR (plist);
8043 plist = XCDR (plist);
8044 if (!SYMBOLP (key))
8045 return 0;
8046
8047 /* There must follow a value. */
8048 if (!CONSP (plist))
8049 return 0;
8050 value = XCAR (plist);
8051 plist = XCDR (plist);
8052
8053 /* Find key in KEYWORDS. Error if not found. */
8054 for (i = 0; i < nkeywords; ++i)
8055 if (strcmp (keywords[i].name, XSYMBOL (key)->name->data) == 0)
8056 break;
8057
8058 if (i == nkeywords)
8059 continue;
8060
8061 /* Record that we recognized the keyword. If a keywords
8062 was found more than once, it's an error. */
8063 keywords[i].value = value;
8064 ++keywords[i].count;
8065
8066 if (keywords[i].count > 1)
8067 return 0;
8068
8069 /* Check type of value against allowed type. */
8070 switch (keywords[i].type)
8071 {
8072 case IMAGE_STRING_VALUE:
8073 if (!STRINGP (value))
8074 return 0;
8075 break;
8076
8077 case IMAGE_STRING_OR_NIL_VALUE:
8078 if (!STRINGP (value) && !NILP (value))
8079 return 0;
8080 break;
8081
8082 case IMAGE_SYMBOL_VALUE:
8083 if (!SYMBOLP (value))
8084 return 0;
8085 break;
8086
8087 case IMAGE_POSITIVE_INTEGER_VALUE:
8088 if (!INTEGERP (value) || XINT (value) <= 0)
8089 return 0;
8090 break;
8091
8092 case IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR:
8093 if (INTEGERP (value) && XINT (value) >= 0)
8094 break;
8095 if (CONSP (value)
8096 && INTEGERP (XCAR (value)) && INTEGERP (XCDR (value))
8097 && XINT (XCAR (value)) >= 0 && XINT (XCDR (value)) >= 0)
8098 break;
8099 return 0;
8100
8101 case IMAGE_ASCENT_VALUE:
8102 if (SYMBOLP (value) && EQ (value, Qcenter))
8103 break;
8104 else if (INTEGERP (value)
8105 && XINT (value) >= 0
8106 && XINT (value) <= 100)
8107 break;
8108 return 0;
8109
8110 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
8111 if (!INTEGERP (value) || XINT (value) < 0)
8112 return 0;
8113 break;
8114
8115 case IMAGE_DONT_CHECK_VALUE_TYPE:
8116 break;
8117
8118 case IMAGE_FUNCTION_VALUE:
8119 value = indirect_function (value);
8120 if (SUBRP (value)
8121 || COMPILEDP (value)
8122 || (CONSP (value) && EQ (XCAR (value), Qlambda)))
8123 break;
8124 return 0;
8125
8126 case IMAGE_NUMBER_VALUE:
8127 if (!INTEGERP (value) && !FLOATP (value))
8128 return 0;
8129 break;
8130
8131 case IMAGE_INTEGER_VALUE:
8132 if (!INTEGERP (value))
8133 return 0;
8134 break;
8135
8136 case IMAGE_BOOL_VALUE:
8137 if (!NILP (value) && !EQ (value, Qt))
8138 return 0;
8139 break;
8140
8141 default:
8142 abort ();
8143 break;
8144 }
8145
8146 if (EQ (key, QCtype) && !EQ (type, value))
8147 return 0;
8148 }
8149
8150 /* Check that all mandatory fields are present. */
8151 for (i = 0; i < nkeywords; ++i)
8152 if (keywords[i].mandatory_p && keywords[i].count == 0)
8153 return 0;
8154
8155 return NILP (plist);
8156 }
8157
8158
8159 /* Return the value of KEY in image specification SPEC. Value is nil
8160 if KEY is not present in SPEC. if FOUND is not null, set *FOUND
8161 to 1 if KEY was found in SPEC, set it to 0 otherwise. */
8162
8163 static Lisp_Object
8164 image_spec_value (spec, key, found)
8165 Lisp_Object spec, key;
8166 int *found;
8167 {
8168 Lisp_Object tail;
8169
8170 xassert (valid_image_p (spec));
8171
8172 for (tail = XCDR (spec);
8173 CONSP (tail) && CONSP (XCDR (tail));
8174 tail = XCDR (XCDR (tail)))
8175 {
8176 if (EQ (XCAR (tail), key))
8177 {
8178 if (found)
8179 *found = 1;
8180 return XCAR (XCDR (tail));
8181 }
8182 }
8183
8184 if (found)
8185 *found = 0;
8186 return Qnil;
8187 }
8188
8189
8190
8191 \f
8192 /***********************************************************************
8193 Image type independent image structures
8194 ***********************************************************************/
8195
8196 static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
8197 static void free_image P_ ((struct frame *f, struct image *img));
8198
8199
8200 /* Allocate and return a new image structure for image specification
8201 SPEC. SPEC has a hash value of HASH. */
8202
8203 static struct image *
8204 make_image (spec, hash)
8205 Lisp_Object spec;
8206 unsigned hash;
8207 {
8208 struct image *img = (struct image *) xmalloc (sizeof *img);
8209
8210 xassert (valid_image_p (spec));
8211 bzero (img, sizeof *img);
8212 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
8213 xassert (img->type != NULL);
8214 img->spec = spec;
8215 img->data.lisp_val = Qnil;
8216 img->ascent = DEFAULT_IMAGE_ASCENT;
8217 img->hash = hash;
8218 return img;
8219 }
8220
8221
8222 /* Free image IMG which was used on frame F, including its resources. */
8223
8224 static void
8225 free_image (f, img)
8226 struct frame *f;
8227 struct image *img;
8228 {
8229 if (img)
8230 {
8231 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8232
8233 /* Remove IMG from the hash table of its cache. */
8234 if (img->prev)
8235 img->prev->next = img->next;
8236 else
8237 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
8238
8239 if (img->next)
8240 img->next->prev = img->prev;
8241
8242 c->images[img->id] = NULL;
8243
8244 /* Free resources, then free IMG. */
8245 img->type->free (f, img);
8246 xfree (img);
8247 }
8248 }
8249
8250
8251 /* Prepare image IMG for display on frame F. Must be called before
8252 drawing an image. */
8253
8254 void
8255 prepare_image_for_display (f, img)
8256 struct frame *f;
8257 struct image *img;
8258 {
8259 EMACS_TIME t;
8260
8261 /* We're about to display IMG, so set its timestamp to `now'. */
8262 EMACS_GET_TIME (t);
8263 img->timestamp = EMACS_SECS (t);
8264
8265 /* If IMG doesn't have a pixmap yet, load it now, using the image
8266 type dependent loader function. */
8267 if (img->pixmap == 0 && !img->load_failed_p)
8268 img->load_failed_p = img->type->load (f, img) == 0;
8269 }
8270
8271
8272 /* Value is the number of pixels for the ascent of image IMG when
8273 drawn in face FACE. */
8274
8275 int
8276 image_ascent (img, face)
8277 struct image *img;
8278 struct face *face;
8279 {
8280 int height = img->height + img->vmargin;
8281 int ascent;
8282
8283 if (img->ascent == CENTERED_IMAGE_ASCENT)
8284 {
8285 if (face->font)
8286 ascent = height / 2 - (FONT_DESCENT(face->font)
8287 - FONT_BASE(face->font)) / 2;
8288 else
8289 ascent = height / 2;
8290 }
8291 else
8292 ascent = height * img->ascent / 100.0;
8293
8294 return ascent;
8295 }
8296
8297
8298 \f
8299 /* Image background colors. */
8300
8301 static unsigned long
8302 four_corners_best (ximg, width, height)
8303 XImage *ximg;
8304 unsigned long width, height;
8305 {
8306 #if 0 /* TODO: Image support. */
8307 unsigned long corners[4], best;
8308 int i, best_count;
8309
8310 /* Get the colors at the corners of ximg. */
8311 corners[0] = XGetPixel (ximg, 0, 0);
8312 corners[1] = XGetPixel (ximg, width - 1, 0);
8313 corners[2] = XGetPixel (ximg, width - 1, height - 1);
8314 corners[3] = XGetPixel (ximg, 0, height - 1);
8315
8316 /* Choose the most frequently found color as background. */
8317 for (i = best_count = 0; i < 4; ++i)
8318 {
8319 int j, n;
8320
8321 for (j = n = 0; j < 4; ++j)
8322 if (corners[i] == corners[j])
8323 ++n;
8324
8325 if (n > best_count)
8326 best = corners[i], best_count = n;
8327 }
8328
8329 return best;
8330 #else
8331 return 0;
8332 #endif
8333 }
8334
8335 /* Return the `background' field of IMG. If IMG doesn't have one yet,
8336 it is guessed heuristically. If non-zero, XIMG is an existing XImage
8337 object to use for the heuristic. */
8338
8339 unsigned long
8340 image_background (img, f, ximg)
8341 struct image *img;
8342 struct frame *f;
8343 XImage *ximg;
8344 {
8345 if (! img->background_valid)
8346 /* IMG doesn't have a background yet, try to guess a reasonable value. */
8347 {
8348 #if 0 /* TODO: Image support. */
8349 int free_ximg = !ximg;
8350
8351 if (! ximg)
8352 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
8353 0, 0, img->width, img->height, ~0, ZPixmap);
8354
8355 img->background = four_corners_best (ximg, img->width, img->height);
8356
8357 if (free_ximg)
8358 XDestroyImage (ximg);
8359
8360 img->background_valid = 1;
8361 #endif
8362 }
8363
8364 return img->background;
8365 }
8366
8367 /* Return the `background_transparent' field of IMG. If IMG doesn't
8368 have one yet, it is guessed heuristically. If non-zero, MASK is an
8369 existing XImage object to use for the heuristic. */
8370
8371 int
8372 image_background_transparent (img, f, mask)
8373 struct image *img;
8374 struct frame *f;
8375 XImage *mask;
8376 {
8377 if (! img->background_transparent_valid)
8378 /* IMG doesn't have a background yet, try to guess a reasonable value. */
8379 {
8380 #if 0 /* TODO: Image support. */
8381 if (img->mask)
8382 {
8383 int free_mask = !mask;
8384
8385 if (! mask)
8386 mask = XGetImage (FRAME_X_DISPLAY (f), img->mask,
8387 0, 0, img->width, img->height, ~0, ZPixmap);
8388
8389 img->background_transparent
8390 = !four_corners_best (mask, img->width, img->height);
8391
8392 if (free_mask)
8393 XDestroyImage (mask);
8394 }
8395 else
8396 #endif
8397 img->background_transparent = 0;
8398
8399 img->background_transparent_valid = 1;
8400 }
8401
8402 return img->background_transparent;
8403 }
8404
8405 \f
8406 /***********************************************************************
8407 Helper functions for X image types
8408 ***********************************************************************/
8409
8410 static void x_clear_image_1 P_ ((struct frame *, struct image *, int,
8411 int, int));
8412 static void x_clear_image P_ ((struct frame *f, struct image *img));
8413 static unsigned long x_alloc_image_color P_ ((struct frame *f,
8414 struct image *img,
8415 Lisp_Object color_name,
8416 unsigned long dflt));
8417
8418
8419 /* Clear X resources of image IMG on frame F. PIXMAP_P non-zero means
8420 free the pixmap if any. MASK_P non-zero means clear the mask
8421 pixmap if any. COLORS_P non-zero means free colors allocated for
8422 the image, if any. */
8423
8424 static void
8425 x_clear_image_1 (f, img, pixmap_p, mask_p, colors_p)
8426 struct frame *f;
8427 struct image *img;
8428 int pixmap_p, mask_p, colors_p;
8429 {
8430 #if 0 /* TODO: W32 image support */
8431 if (pixmap_p && img->pixmap)
8432 {
8433 XFreePixmap (FRAME_X_DISPLAY (f), img->pixmap);
8434 img->pixmap = None;
8435 img->background_valid = 0;
8436 }
8437
8438 if (mask_p && img->mask)
8439 {
8440 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
8441 img->mask = None;
8442 img->background_transparent_valid = 0;
8443 }
8444
8445 if (colors_p && img->ncolors)
8446 {
8447 x_free_colors (f, img->colors, img->ncolors);
8448 xfree (img->colors);
8449 img->colors = NULL;
8450 img->ncolors = 0;
8451 }
8452 #endif
8453 }
8454
8455 /* Free X resources of image IMG which is used on frame F. */
8456
8457 static void
8458 x_clear_image (f, img)
8459 struct frame *f;
8460 struct image *img;
8461 {
8462 #if 0 /* TODO: W32 image support */
8463
8464 if (img->pixmap)
8465 {
8466 BLOCK_INPUT;
8467 XFreePixmap (NULL, img->pixmap);
8468 img->pixmap = 0;
8469 UNBLOCK_INPUT;
8470 }
8471
8472 if (img->ncolors)
8473 {
8474 int class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
8475
8476 /* If display has an immutable color map, freeing colors is not
8477 necessary and some servers don't allow it. So don't do it. */
8478 if (class != StaticColor
8479 && class != StaticGray
8480 && class != TrueColor)
8481 {
8482 Colormap cmap;
8483 BLOCK_INPUT;
8484 cmap = DefaultColormapOfScreen (FRAME_W32_DISPLAY_INFO (f)->screen);
8485 XFreeColors (FRAME_W32_DISPLAY (f), cmap, img->colors,
8486 img->ncolors, 0);
8487 UNBLOCK_INPUT;
8488 }
8489
8490 xfree (img->colors);
8491 img->colors = NULL;
8492 img->ncolors = 0;
8493 }
8494 #endif
8495 }
8496
8497
8498 /* Allocate color COLOR_NAME for image IMG on frame F. If color
8499 cannot be allocated, use DFLT. Add a newly allocated color to
8500 IMG->colors, so that it can be freed again. Value is the pixel
8501 color. */
8502
8503 static unsigned long
8504 x_alloc_image_color (f, img, color_name, dflt)
8505 struct frame *f;
8506 struct image *img;
8507 Lisp_Object color_name;
8508 unsigned long dflt;
8509 {
8510 #if 0 /* TODO: allocing colors. */
8511 XColor color;
8512 unsigned long result;
8513
8514 xassert (STRINGP (color_name));
8515
8516 if (w32_defined_color (f, XSTRING (color_name)->data, &color, 1))
8517 {
8518 /* This isn't called frequently so we get away with simply
8519 reallocating the color vector to the needed size, here. */
8520 ++img->ncolors;
8521 img->colors =
8522 (unsigned long *) xrealloc (img->colors,
8523 img->ncolors * sizeof *img->colors);
8524 img->colors[img->ncolors - 1] = color.pixel;
8525 result = color.pixel;
8526 }
8527 else
8528 result = dflt;
8529 return result;
8530 #endif
8531 return 0;
8532 }
8533
8534
8535 \f
8536 /***********************************************************************
8537 Image Cache
8538 ***********************************************************************/
8539
8540 static void cache_image P_ ((struct frame *f, struct image *img));
8541 static void postprocess_image P_ ((struct frame *, struct image *));
8542
8543
8544 /* Return a new, initialized image cache that is allocated from the
8545 heap. Call free_image_cache to free an image cache. */
8546
8547 struct image_cache *
8548 make_image_cache ()
8549 {
8550 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
8551 int size;
8552
8553 bzero (c, sizeof *c);
8554 c->size = 50;
8555 c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
8556 size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
8557 c->buckets = (struct image **) xmalloc (size);
8558 bzero (c->buckets, size);
8559 return c;
8560 }
8561
8562
8563 /* Free image cache of frame F. Be aware that X frames share images
8564 caches. */
8565
8566 void
8567 free_image_cache (f)
8568 struct frame *f;
8569 {
8570 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8571 if (c)
8572 {
8573 int i;
8574
8575 /* Cache should not be referenced by any frame when freed. */
8576 xassert (c->refcount == 0);
8577
8578 for (i = 0; i < c->used; ++i)
8579 free_image (f, c->images[i]);
8580 xfree (c->images);
8581 xfree (c);
8582 xfree (c->buckets);
8583 FRAME_X_IMAGE_CACHE (f) = NULL;
8584 }
8585 }
8586
8587
8588 /* Clear image cache of frame F. FORCE_P non-zero means free all
8589 images. FORCE_P zero means clear only images that haven't been
8590 displayed for some time. Should be called from time to time to
8591 reduce the number of loaded images. If image-eviction-seconds is
8592 non-nil, this frees images in the cache which weren't displayed for
8593 at least that many seconds. */
8594
8595 void
8596 clear_image_cache (f, force_p)
8597 struct frame *f;
8598 int force_p;
8599 {
8600 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8601
8602 if (c && INTEGERP (Vimage_cache_eviction_delay))
8603 {
8604 EMACS_TIME t;
8605 unsigned long old;
8606 int i, any_freed_p = 0;
8607
8608 EMACS_GET_TIME (t);
8609 old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
8610
8611 for (i = 0; i < c->used; ++i)
8612 {
8613 struct image *img = c->images[i];
8614 if (img != NULL
8615 && (force_p
8616 || (img->timestamp > old)))
8617 {
8618 free_image (f, img);
8619 any_freed_p = 1;
8620 }
8621 }
8622
8623 /* We may be clearing the image cache because, for example,
8624 Emacs was iconified for a longer period of time. In that
8625 case, current matrices may still contain references to
8626 images freed above. So, clear these matrices. */
8627 if (any_freed_p)
8628 {
8629 clear_current_matrices (f);
8630 ++windows_or_buffers_changed;
8631 }
8632 }
8633 }
8634
8635
8636 DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
8637 0, 1, 0,
8638 doc: /* Clear the image cache of FRAME.
8639 FRAME nil or omitted means use the selected frame.
8640 FRAME t means clear the image caches of all frames. */)
8641 (frame)
8642 Lisp_Object frame;
8643 {
8644 if (EQ (frame, Qt))
8645 {
8646 Lisp_Object tail;
8647
8648 FOR_EACH_FRAME (tail, frame)
8649 if (FRAME_W32_P (XFRAME (frame)))
8650 clear_image_cache (XFRAME (frame), 1);
8651 }
8652 else
8653 clear_image_cache (check_x_frame (frame), 1);
8654
8655 return Qnil;
8656 }
8657
8658
8659 /* Compute masks and transform image IMG on frame F, as specified
8660 by the image's specification, */
8661
8662 static void
8663 postprocess_image (f, img)
8664 struct frame *f;
8665 struct image *img;
8666 {
8667 #if 0 /* TODO: image support. */
8668 /* Manipulation of the image's mask. */
8669 if (img->pixmap)
8670 {
8671 Lisp_Object conversion, spec;
8672 Lisp_Object mask;
8673
8674 spec = img->spec;
8675
8676 /* `:heuristic-mask t'
8677 `:mask heuristic'
8678 means build a mask heuristically.
8679 `:heuristic-mask (R G B)'
8680 `:mask (heuristic (R G B))'
8681 means build a mask from color (R G B) in the
8682 image.
8683 `:mask nil'
8684 means remove a mask, if any. */
8685
8686 mask = image_spec_value (spec, QCheuristic_mask, NULL);
8687 if (!NILP (mask))
8688 x_build_heuristic_mask (f, img, mask);
8689 else
8690 {
8691 int found_p;
8692
8693 mask = image_spec_value (spec, QCmask, &found_p);
8694
8695 if (EQ (mask, Qheuristic))
8696 x_build_heuristic_mask (f, img, Qt);
8697 else if (CONSP (mask)
8698 && EQ (XCAR (mask), Qheuristic))
8699 {
8700 if (CONSP (XCDR (mask)))
8701 x_build_heuristic_mask (f, img, XCAR (XCDR (mask)));
8702 else
8703 x_build_heuristic_mask (f, img, XCDR (mask));
8704 }
8705 else if (NILP (mask) && found_p && img->mask)
8706 {
8707 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
8708 img->mask = NULL;
8709 }
8710 }
8711
8712
8713 /* Should we apply an image transformation algorithm? */
8714 conversion = image_spec_value (spec, QCconversion, NULL);
8715 if (EQ (conversion, Qdisabled))
8716 x_disable_image (f, img);
8717 else if (EQ (conversion, Qlaplace))
8718 x_laplace (f, img);
8719 else if (EQ (conversion, Qemboss))
8720 x_emboss (f, img);
8721 else if (CONSP (conversion)
8722 && EQ (XCAR (conversion), Qedge_detection))
8723 {
8724 Lisp_Object tem;
8725 tem = XCDR (conversion);
8726 if (CONSP (tem))
8727 x_edge_detection (f, img,
8728 Fplist_get (tem, QCmatrix),
8729 Fplist_get (tem, QCcolor_adjustment));
8730 }
8731 }
8732 #endif
8733 }
8734
8735
8736 /* Return the id of image with Lisp specification SPEC on frame F.
8737 SPEC must be a valid Lisp image specification (see valid_image_p). */
8738
8739 int
8740 lookup_image (f, spec)
8741 struct frame *f;
8742 Lisp_Object spec;
8743 {
8744 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8745 struct image *img;
8746 int i;
8747 unsigned hash;
8748 struct gcpro gcpro1;
8749 EMACS_TIME now;
8750
8751 /* F must be a window-system frame, and SPEC must be a valid image
8752 specification. */
8753 xassert (FRAME_WINDOW_P (f));
8754 xassert (valid_image_p (spec));
8755
8756 GCPRO1 (spec);
8757
8758 /* Look up SPEC in the hash table of the image cache. */
8759 hash = sxhash (spec, 0);
8760 i = hash % IMAGE_CACHE_BUCKETS_SIZE;
8761
8762 for (img = c->buckets[i]; img; img = img->next)
8763 if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
8764 break;
8765
8766 /* If not found, create a new image and cache it. */
8767 if (img == NULL)
8768 {
8769 extern Lisp_Object Qpostscript;
8770
8771 BLOCK_INPUT;
8772 img = make_image (spec, hash);
8773 cache_image (f, img);
8774 img->load_failed_p = img->type->load (f, img) == 0;
8775
8776 /* If we can't load the image, and we don't have a width and
8777 height, use some arbitrary width and height so that we can
8778 draw a rectangle for it. */
8779 if (img->load_failed_p)
8780 {
8781 Lisp_Object value;
8782
8783 value = image_spec_value (spec, QCwidth, NULL);
8784 img->width = (INTEGERP (value)
8785 ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH);
8786 value = image_spec_value (spec, QCheight, NULL);
8787 img->height = (INTEGERP (value)
8788 ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT);
8789 }
8790 else
8791 {
8792 /* Handle image type independent image attributes
8793 `:ascent PERCENT', `:margin MARGIN', `:relief RELIEF',
8794 `:background COLOR'. */
8795 Lisp_Object ascent, margin, relief, bg;
8796
8797 ascent = image_spec_value (spec, QCascent, NULL);
8798 if (INTEGERP (ascent))
8799 img->ascent = XFASTINT (ascent);
8800 else if (EQ (ascent, Qcenter))
8801 img->ascent = CENTERED_IMAGE_ASCENT;
8802
8803 margin = image_spec_value (spec, QCmargin, NULL);
8804 if (INTEGERP (margin) && XINT (margin) >= 0)
8805 img->vmargin = img->hmargin = XFASTINT (margin);
8806 else if (CONSP (margin) && INTEGERP (XCAR (margin))
8807 && INTEGERP (XCDR (margin)))
8808 {
8809 if (XINT (XCAR (margin)) > 0)
8810 img->hmargin = XFASTINT (XCAR (margin));
8811 if (XINT (XCDR (margin)) > 0)
8812 img->vmargin = XFASTINT (XCDR (margin));
8813 }
8814
8815 relief = image_spec_value (spec, QCrelief, NULL);
8816 if (INTEGERP (relief))
8817 {
8818 img->relief = XINT (relief);
8819 img->hmargin += abs (img->relief);
8820 img->vmargin += abs (img->relief);
8821 }
8822
8823 if (! img->background_valid)
8824 {
8825 bg = image_spec_value (img->spec, QCbackground, NULL);
8826 if (!NILP (bg))
8827 {
8828 img->background
8829 = x_alloc_image_color (f, img, bg,
8830 FRAME_BACKGROUND_PIXEL (f));
8831 img->background_valid = 1;
8832 }
8833 }
8834
8835 /* Do image transformations and compute masks, unless we
8836 don't have the image yet. */
8837 if (!EQ (*img->type->type, Qpostscript))
8838 postprocess_image (f, img);
8839 }
8840
8841 UNBLOCK_INPUT;
8842 xassert (!interrupt_input_blocked);
8843 }
8844
8845 /* We're using IMG, so set its timestamp to `now'. */
8846 EMACS_GET_TIME (now);
8847 img->timestamp = EMACS_SECS (now);
8848
8849 UNGCPRO;
8850
8851 /* Value is the image id. */
8852 return img->id;
8853 }
8854
8855
8856 /* Cache image IMG in the image cache of frame F. */
8857
8858 static void
8859 cache_image (f, img)
8860 struct frame *f;
8861 struct image *img;
8862 {
8863 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8864 int i;
8865
8866 /* Find a free slot in c->images. */
8867 for (i = 0; i < c->used; ++i)
8868 if (c->images[i] == NULL)
8869 break;
8870
8871 /* If no free slot found, maybe enlarge c->images. */
8872 if (i == c->used && c->used == c->size)
8873 {
8874 c->size *= 2;
8875 c->images = (struct image **) xrealloc (c->images,
8876 c->size * sizeof *c->images);
8877 }
8878
8879 /* Add IMG to c->images, and assign IMG an id. */
8880 c->images[i] = img;
8881 img->id = i;
8882 if (i == c->used)
8883 ++c->used;
8884
8885 /* Add IMG to the cache's hash table. */
8886 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
8887 img->next = c->buckets[i];
8888 if (img->next)
8889 img->next->prev = img;
8890 img->prev = NULL;
8891 c->buckets[i] = img;
8892 }
8893
8894
8895 /* Call FN on every image in the image cache of frame F. Used to mark
8896 Lisp Objects in the image cache. */
8897
8898 void
8899 forall_images_in_image_cache (f, fn)
8900 struct frame *f;
8901 void (*fn) P_ ((struct image *img));
8902 {
8903 if (FRAME_LIVE_P (f) && FRAME_W32_P (f))
8904 {
8905 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8906 if (c)
8907 {
8908 int i;
8909 for (i = 0; i < c->used; ++i)
8910 if (c->images[i])
8911 fn (c->images[i]);
8912 }
8913 }
8914 }
8915
8916
8917 \f
8918 /***********************************************************************
8919 W32 support code
8920 ***********************************************************************/
8921
8922 #if 0 /* TODO: W32 specific image code. */
8923
8924 static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
8925 XImage **, Pixmap *));
8926 static void x_destroy_x_image P_ ((XImage *));
8927 static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
8928
8929
8930 /* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
8931 frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created.
8932 Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
8933 via xmalloc. Print error messages via image_error if an error
8934 occurs. Value is non-zero if successful. */
8935
8936 static int
8937 x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
8938 struct frame *f;
8939 int width, height, depth;
8940 XImage **ximg;
8941 Pixmap *pixmap;
8942 {
8943 #if 0 /* TODO: Image support for W32 */
8944 Display *display = FRAME_W32_DISPLAY (f);
8945 Screen *screen = FRAME_X_SCREEN (f);
8946 Window window = FRAME_W32_WINDOW (f);
8947
8948 xassert (interrupt_input_blocked);
8949
8950 if (depth <= 0)
8951 depth = one_w32_display_info.n_cbits;
8952 *ximg = XCreateImage (display, DefaultVisualOfScreen (screen),
8953 depth, ZPixmap, 0, NULL, width, height,
8954 depth > 16 ? 32 : depth > 8 ? 16 : 8, 0);
8955 if (*ximg == NULL)
8956 {
8957 image_error ("Unable to allocate X image", Qnil, Qnil);
8958 return 0;
8959 }
8960
8961 /* Allocate image raster. */
8962 (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height);
8963
8964 /* Allocate a pixmap of the same size. */
8965 *pixmap = XCreatePixmap (display, window, width, height, depth);
8966 if (*pixmap == 0)
8967 {
8968 x_destroy_x_image (*ximg);
8969 *ximg = NULL;
8970 image_error ("Unable to create X pixmap", Qnil, Qnil);
8971 return 0;
8972 }
8973 #endif
8974 return 1;
8975 }
8976
8977
8978 /* Destroy XImage XIMG. Free XIMG->data. */
8979
8980 static void
8981 x_destroy_x_image (ximg)
8982 XImage *ximg;
8983 {
8984 xassert (interrupt_input_blocked);
8985 if (ximg)
8986 {
8987 xfree (ximg->data);
8988 ximg->data = NULL;
8989 XDestroyImage (ximg);
8990 }
8991 }
8992
8993
8994 /* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT
8995 are width and height of both the image and pixmap. */
8996
8997 static void
8998 x_put_x_image (f, ximg, pixmap, width, height)
8999 struct frame *f;
9000 XImage *ximg;
9001 Pixmap pixmap;
9002 {
9003 GC gc;
9004
9005 xassert (interrupt_input_blocked);
9006 gc = XCreateGC (NULL, pixmap, 0, NULL);
9007 XPutImage (NULL, pixmap, gc, ximg, 0, 0, 0, 0, width, height);
9008 XFreeGC (NULL, gc);
9009 }
9010
9011 #endif
9012
9013 \f
9014 /***********************************************************************
9015 File Handling
9016 ***********************************************************************/
9017
9018 static Lisp_Object x_find_image_file P_ ((Lisp_Object));
9019 static char *slurp_file P_ ((char *, int *));
9020
9021
9022 /* Find image file FILE. Look in data-directory, then
9023 x-bitmap-file-path. Value is the full name of the file found, or
9024 nil if not found. */
9025
9026 static Lisp_Object
9027 x_find_image_file (file)
9028 Lisp_Object file;
9029 {
9030 Lisp_Object file_found, search_path;
9031 struct gcpro gcpro1, gcpro2;
9032 int fd;
9033
9034 file_found = Qnil;
9035 search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
9036 GCPRO2 (file_found, search_path);
9037
9038 /* Try to find FILE in data-directory, then x-bitmap-file-path. */
9039 fd = openp (search_path, file, Qnil, &file_found, 0);
9040
9041 if (fd == -1)
9042 file_found = Qnil;
9043 else
9044 close (fd);
9045
9046 UNGCPRO;
9047 return file_found;
9048 }
9049
9050
9051 /* Read FILE into memory. Value is a pointer to a buffer allocated
9052 with xmalloc holding FILE's contents. Value is null if an error
9053 occurred. *SIZE is set to the size of the file. */
9054
9055 static char *
9056 slurp_file (file, size)
9057 char *file;
9058 int *size;
9059 {
9060 FILE *fp = NULL;
9061 char *buf = NULL;
9062 struct stat st;
9063
9064 if (stat (file, &st) == 0
9065 && (fp = fopen (file, "r")) != NULL
9066 && (buf = (char *) xmalloc (st.st_size),
9067 fread (buf, 1, st.st_size, fp) == st.st_size))
9068 {
9069 *size = st.st_size;
9070 fclose (fp);
9071 }
9072 else
9073 {
9074 if (fp)
9075 fclose (fp);
9076 if (buf)
9077 {
9078 xfree (buf);
9079 buf = NULL;
9080 }
9081 }
9082
9083 return buf;
9084 }
9085
9086
9087 \f
9088 /***********************************************************************
9089 XBM images
9090 ***********************************************************************/
9091
9092 static int xbm_load P_ ((struct frame *f, struct image *img));
9093 static int xbm_load_image_from_file P_ ((struct frame *f, struct image *img,
9094 Lisp_Object file));
9095 static int xbm_image_p P_ ((Lisp_Object object));
9096 static int xbm_read_bitmap_file_data P_ ((char *, int *, int *,
9097 unsigned char **));
9098
9099
9100 /* Indices of image specification fields in xbm_format, below. */
9101
9102 enum xbm_keyword_index
9103 {
9104 XBM_TYPE,
9105 XBM_FILE,
9106 XBM_WIDTH,
9107 XBM_HEIGHT,
9108 XBM_DATA,
9109 XBM_FOREGROUND,
9110 XBM_BACKGROUND,
9111 XBM_ASCENT,
9112 XBM_MARGIN,
9113 XBM_RELIEF,
9114 XBM_ALGORITHM,
9115 XBM_HEURISTIC_MASK,
9116 XBM_MASK,
9117 XBM_LAST
9118 };
9119
9120 /* Vector of image_keyword structures describing the format
9121 of valid XBM image specifications. */
9122
9123 static struct image_keyword xbm_format[XBM_LAST] =
9124 {
9125 {":type", IMAGE_SYMBOL_VALUE, 1},
9126 {":file", IMAGE_STRING_VALUE, 0},
9127 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9128 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9129 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9130 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
9131 {":background", IMAGE_STRING_OR_NIL_VALUE, 0},
9132 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
9133 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
9134 {":relief", IMAGE_INTEGER_VALUE, 0},
9135 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9136 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
9137 };
9138
9139 /* Structure describing the image type XBM. */
9140
9141 static struct image_type xbm_type =
9142 {
9143 &Qxbm,
9144 xbm_image_p,
9145 xbm_load,
9146 x_clear_image,
9147 NULL
9148 };
9149
9150 /* Tokens returned from xbm_scan. */
9151
9152 enum xbm_token
9153 {
9154 XBM_TK_IDENT = 256,
9155 XBM_TK_NUMBER
9156 };
9157
9158
9159 /* Return non-zero if OBJECT is a valid XBM-type image specification.
9160 A valid specification is a list starting with the symbol `image'
9161 The rest of the list is a property list which must contain an
9162 entry `:type xbm..
9163
9164 If the specification specifies a file to load, it must contain
9165 an entry `:file FILENAME' where FILENAME is a string.
9166
9167 If the specification is for a bitmap loaded from memory it must
9168 contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
9169 WIDTH and HEIGHT are integers > 0. DATA may be:
9170
9171 1. a string large enough to hold the bitmap data, i.e. it must
9172 have a size >= (WIDTH + 7) / 8 * HEIGHT
9173
9174 2. a bool-vector of size >= WIDTH * HEIGHT
9175
9176 3. a vector of strings or bool-vectors, one for each line of the
9177 bitmap.
9178
9179 Both the file and data forms may contain the additional entries
9180 `:background COLOR' and `:foreground COLOR'. If not present,
9181 foreground and background of the frame on which the image is
9182 displayed, is used. */
9183
9184 static int
9185 xbm_image_p (object)
9186 Lisp_Object object;
9187 {
9188 struct image_keyword kw[XBM_LAST];
9189
9190 bcopy (xbm_format, kw, sizeof kw);
9191 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
9192 return 0;
9193
9194 xassert (EQ (kw[XBM_TYPE].value, Qxbm));
9195
9196 if (kw[XBM_FILE].count)
9197 {
9198 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
9199 return 0;
9200 }
9201 else
9202 {
9203 Lisp_Object data;
9204 int width, height;
9205
9206 /* Entries for `:width', `:height' and `:data' must be present. */
9207 if (!kw[XBM_WIDTH].count
9208 || !kw[XBM_HEIGHT].count
9209 || !kw[XBM_DATA].count)
9210 return 0;
9211
9212 data = kw[XBM_DATA].value;
9213 width = XFASTINT (kw[XBM_WIDTH].value);
9214 height = XFASTINT (kw[XBM_HEIGHT].value);
9215
9216 /* Check type of data, and width and height against contents of
9217 data. */
9218 if (VECTORP (data))
9219 {
9220 int i;
9221
9222 /* Number of elements of the vector must be >= height. */
9223 if (XVECTOR (data)->size < height)
9224 return 0;
9225
9226 /* Each string or bool-vector in data must be large enough
9227 for one line of the image. */
9228 for (i = 0; i < height; ++i)
9229 {
9230 Lisp_Object elt = XVECTOR (data)->contents[i];
9231
9232 if (STRINGP (elt))
9233 {
9234 if (XSTRING (elt)->size
9235 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
9236 return 0;
9237 }
9238 else if (BOOL_VECTOR_P (elt))
9239 {
9240 if (XBOOL_VECTOR (elt)->size < width)
9241 return 0;
9242 }
9243 else
9244 return 0;
9245 }
9246 }
9247 else if (STRINGP (data))
9248 {
9249 if (XSTRING (data)->size
9250 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
9251 return 0;
9252 }
9253 else if (BOOL_VECTOR_P (data))
9254 {
9255 if (XBOOL_VECTOR (data)->size < width * height)
9256 return 0;
9257 }
9258 else
9259 return 0;
9260 }
9261
9262 /* Baseline must be a value between 0 and 100 (a percentage). */
9263 if (kw[XBM_ASCENT].count
9264 && XFASTINT (kw[XBM_ASCENT].value) > 100)
9265 return 0;
9266
9267 return 1;
9268 }
9269
9270
9271 /* Scan a bitmap file. FP is the stream to read from. Value is
9272 either an enumerator from enum xbm_token, or a character for a
9273 single-character token, or 0 at end of file. If scanning an
9274 identifier, store the lexeme of the identifier in SVAL. If
9275 scanning a number, store its value in *IVAL. */
9276
9277 static int
9278 xbm_scan (s, end, sval, ival)
9279 char **s, *end;
9280 char *sval;
9281 int *ival;
9282 {
9283 int c;
9284
9285 loop:
9286
9287 /* Skip white space. */
9288 while (*s < end &&(c = *(*s)++, isspace (c)))
9289 ;
9290
9291 if (*s >= end)
9292 c = 0;
9293 else if (isdigit (c))
9294 {
9295 int value = 0, digit;
9296
9297 if (c == '0' && *s < end)
9298 {
9299 c = *(*s)++;
9300 if (c == 'x' || c == 'X')
9301 {
9302 while (*s < end)
9303 {
9304 c = *(*s)++;
9305 if (isdigit (c))
9306 digit = c - '0';
9307 else if (c >= 'a' && c <= 'f')
9308 digit = c - 'a' + 10;
9309 else if (c >= 'A' && c <= 'F')
9310 digit = c - 'A' + 10;
9311 else
9312 break;
9313 value = 16 * value + digit;
9314 }
9315 }
9316 else if (isdigit (c))
9317 {
9318 value = c - '0';
9319 while (*s < end
9320 && (c = *(*s)++, isdigit (c)))
9321 value = 8 * value + c - '0';
9322 }
9323 }
9324 else
9325 {
9326 value = c - '0';
9327 while (*s < end
9328 && (c = *(*s)++, isdigit (c)))
9329 value = 10 * value + c - '0';
9330 }
9331
9332 if (*s < end)
9333 *s = *s - 1;
9334 *ival = value;
9335 c = XBM_TK_NUMBER;
9336 }
9337 else if (isalpha (c) || c == '_')
9338 {
9339 *sval++ = c;
9340 while (*s < end
9341 && (c = *(*s)++, (isalnum (c) || c == '_')))
9342 *sval++ = c;
9343 *sval = 0;
9344 if (*s < end)
9345 *s = *s - 1;
9346 c = XBM_TK_IDENT;
9347 }
9348 else if (c == '/' && **s == '*')
9349 {
9350 /* C-style comment. */
9351 ++*s;
9352 while (**s && (**s != '*' || *(*s + 1) != '/'))
9353 ++*s;
9354 if (**s)
9355 {
9356 *s += 2;
9357 goto loop;
9358 }
9359 }
9360
9361 return c;
9362 }
9363
9364
9365 /* Replacement for XReadBitmapFileData which isn't available under old
9366 X versions. CONTENTS is a pointer to a buffer to parse; END is the
9367 buffer's end. Set *WIDTH and *HEIGHT to the width and height of
9368 the image. Return in *DATA the bitmap data allocated with xmalloc.
9369 Value is non-zero if successful. DATA null means just test if
9370 CONTENTS looks like an in-memory XBM file. */
9371
9372 static int
9373 xbm_read_bitmap_data (contents, end, width, height, data)
9374 char *contents, *end;
9375 int *width, *height;
9376 unsigned char **data;
9377 {
9378 char *s = contents;
9379 char buffer[BUFSIZ];
9380 int padding_p = 0;
9381 int v10 = 0;
9382 int bytes_per_line, i, nbytes;
9383 unsigned char *p;
9384 int value;
9385 int LA1;
9386
9387 #define match() \
9388 LA1 = xbm_scan (contents, end, buffer, &value)
9389
9390 #define expect(TOKEN) \
9391 if (LA1 != (TOKEN)) \
9392 goto failure; \
9393 else \
9394 match ()
9395
9396 #define expect_ident(IDENT) \
9397 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
9398 match (); \
9399 else \
9400 goto failure
9401
9402 *width = *height = -1;
9403 if (data)
9404 *data = NULL;
9405 LA1 = xbm_scan (&s, end, buffer, &value);
9406
9407 /* Parse defines for width, height and hot-spots. */
9408 while (LA1 == '#')
9409 {
9410 match ();
9411 expect_ident ("define");
9412 expect (XBM_TK_IDENT);
9413
9414 if (LA1 == XBM_TK_NUMBER);
9415 {
9416 char *p = strrchr (buffer, '_');
9417 p = p ? p + 1 : buffer;
9418 if (strcmp (p, "width") == 0)
9419 *width = value;
9420 else if (strcmp (p, "height") == 0)
9421 *height = value;
9422 }
9423 expect (XBM_TK_NUMBER);
9424 }
9425
9426 if (*width < 0 || *height < 0)
9427 goto failure;
9428 else if (data == NULL)
9429 goto success;
9430
9431 /* Parse bits. Must start with `static'. */
9432 expect_ident ("static");
9433 if (LA1 == XBM_TK_IDENT)
9434 {
9435 if (strcmp (buffer, "unsigned") == 0)
9436 {
9437 match ();
9438 expect_ident ("char");
9439 }
9440 else if (strcmp (buffer, "short") == 0)
9441 {
9442 match ();
9443 v10 = 1;
9444 if (*width % 16 && *width % 16 < 9)
9445 padding_p = 1;
9446 }
9447 else if (strcmp (buffer, "char") == 0)
9448 match ();
9449 else
9450 goto failure;
9451 }
9452 else
9453 goto failure;
9454
9455 expect (XBM_TK_IDENT);
9456 expect ('[');
9457 expect (']');
9458 expect ('=');
9459 expect ('{');
9460
9461 bytes_per_line = (*width + 7) / 8 + padding_p;
9462 nbytes = bytes_per_line * *height;
9463 p = *data = (char *) xmalloc (nbytes);
9464
9465 if (v10)
9466 {
9467
9468 for (i = 0; i < nbytes; i += 2)
9469 {
9470 int val = value;
9471 expect (XBM_TK_NUMBER);
9472
9473 *p++ = val;
9474 if (!padding_p || ((i + 2) % bytes_per_line))
9475 *p++ = value >> 8;
9476
9477 if (LA1 == ',' || LA1 == '}')
9478 match ();
9479 else
9480 goto failure;
9481 }
9482 }
9483 else
9484 {
9485 for (i = 0; i < nbytes; ++i)
9486 {
9487 int val = value;
9488 expect (XBM_TK_NUMBER);
9489
9490 *p++ = val;
9491
9492 if (LA1 == ',' || LA1 == '}')
9493 match ();
9494 else
9495 goto failure;
9496 }
9497 }
9498
9499 success:
9500 return 1;
9501
9502 failure:
9503
9504 if (data && *data)
9505 {
9506 xfree (*data);
9507 *data = NULL;
9508 }
9509 return 0;
9510
9511 #undef match
9512 #undef expect
9513 #undef expect_ident
9514 }
9515
9516
9517 /* Load XBM image IMG which will be displayed on frame F from buffer
9518 CONTENTS. END is the end of the buffer. Value is non-zero if
9519 successful. */
9520
9521 static int
9522 xbm_load_image (f, img, contents, end)
9523 struct frame *f;
9524 struct image *img;
9525 char *contents, *end;
9526 {
9527 int rc;
9528 unsigned char *data;
9529 int success_p = 0;
9530
9531 rc = xbm_read_bitmap_data (contents, end, &img->width, &img->height, &data);
9532 if (rc)
9533 {
9534 int depth = one_w32_display_info.n_cbits;
9535 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
9536 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
9537 Lisp_Object value;
9538
9539 xassert (img->width > 0 && img->height > 0);
9540
9541 /* Get foreground and background colors, maybe allocate colors. */
9542 value = image_spec_value (img->spec, QCforeground, NULL);
9543 if (!NILP (value))
9544 foreground = x_alloc_image_color (f, img, value, foreground);
9545 value = image_spec_value (img->spec, QCbackground, NULL);
9546 if (!NILP (value))
9547 {
9548 background = x_alloc_image_color (f, img, value, background);
9549 img->background = background;
9550 img->background_valid = 1;
9551 }
9552
9553 #if 0 /* TODO : Port image display to W32 */
9554 img->pixmap
9555 = XCreatePixmapFromBitmapData (FRAME_W32_DISPLAY (f),
9556 FRAME_W32_WINDOW (f),
9557 data,
9558 img->width, img->height,
9559 foreground, background,
9560 depth);
9561 #endif
9562 xfree (data);
9563
9564 if (img->pixmap == 0)
9565 {
9566 x_clear_image (f, img);
9567 image_error ("Unable to create X pixmap for `%s'", img->spec, Qnil);
9568 }
9569 else
9570 success_p = 1;
9571 }
9572 else
9573 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
9574
9575 return success_p;
9576 }
9577
9578
9579 /* Value is non-zero if DATA looks like an in-memory XBM file. */
9580
9581 static int
9582 xbm_file_p (data)
9583 Lisp_Object data;
9584 {
9585 int w, h;
9586 return (STRINGP (data)
9587 && xbm_read_bitmap_data (XSTRING (data)->data,
9588 (XSTRING (data)->data
9589 + STRING_BYTES (XSTRING (data))),
9590 &w, &h, NULL));
9591 }
9592
9593
9594 /* Fill image IMG which is used on frame F with pixmap data. Value is
9595 non-zero if successful. */
9596
9597 static int
9598 xbm_load (f, img)
9599 struct frame *f;
9600 struct image *img;
9601 {
9602 int success_p = 0;
9603 Lisp_Object file_name;
9604
9605 xassert (xbm_image_p (img->spec));
9606
9607 /* If IMG->spec specifies a file name, create a non-file spec from it. */
9608 file_name = image_spec_value (img->spec, QCfile, NULL);
9609 if (STRINGP (file_name))
9610 {
9611 Lisp_Object file;
9612 char *contents;
9613 int size;
9614 struct gcpro gcpro1;
9615
9616 file = x_find_image_file (file_name);
9617 GCPRO1 (file);
9618 if (!STRINGP (file))
9619 {
9620 image_error ("Cannot find image file `%s'", file_name, Qnil);
9621 UNGCPRO;
9622 return 0;
9623 }
9624
9625 contents = slurp_file (XSTRING (file)->data, &size);
9626 if (contents == NULL)
9627 {
9628 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
9629 UNGCPRO;
9630 return 0;
9631 }
9632
9633 success_p = xbm_load_image (f, img, contents, contents + size);
9634 UNGCPRO;
9635 }
9636 else
9637 {
9638 struct image_keyword fmt[XBM_LAST];
9639 Lisp_Object data;
9640 int depth;
9641 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
9642 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
9643 char *bits;
9644 int parsed_p;
9645 int in_memory_file_p = 0;
9646
9647 /* See if data looks like an in-memory XBM file. */
9648 data = image_spec_value (img->spec, QCdata, NULL);
9649 in_memory_file_p = xbm_file_p (data);
9650
9651 /* Parse the list specification. */
9652 bcopy (xbm_format, fmt, sizeof fmt);
9653 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
9654 xassert (parsed_p);
9655
9656 /* Get specified width, and height. */
9657 if (!in_memory_file_p)
9658 {
9659 img->width = XFASTINT (fmt[XBM_WIDTH].value);
9660 img->height = XFASTINT (fmt[XBM_HEIGHT].value);
9661 xassert (img->width > 0 && img->height > 0);
9662 }
9663 /* Get foreground and background colors, maybe allocate colors. */
9664 if (fmt[XBM_FOREGROUND].count
9665 && STRINGP (fmt[XBM_FOREGROUND].value))
9666 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
9667 foreground);
9668 if (fmt[XBM_BACKGROUND].count
9669 && STRINGP (fmt[XBM_BACKGROUND].value))
9670 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
9671 background);
9672
9673 if (in_memory_file_p)
9674 success_p = xbm_load_image (f, img, XSTRING (data)->data,
9675 (XSTRING (data)->data
9676 + STRING_BYTES (XSTRING (data))));
9677 else
9678 {
9679 if (VECTORP (data))
9680 {
9681 int i;
9682 char *p;
9683 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
9684
9685 p = bits = (char *) alloca (nbytes * img->height);
9686 for (i = 0; i < img->height; ++i, p += nbytes)
9687 {
9688 Lisp_Object line = XVECTOR (data)->contents[i];
9689 if (STRINGP (line))
9690 bcopy (XSTRING (line)->data, p, nbytes);
9691 else
9692 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
9693 }
9694 }
9695 else if (STRINGP (data))
9696 bits = XSTRING (data)->data;
9697 else
9698 bits = XBOOL_VECTOR (data)->data;
9699 #ifdef TODO /* image support. */
9700 /* Create the pixmap. */
9701 depth = one_w32_display_info.n_cbits;
9702 img->pixmap
9703 = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
9704 FRAME_X_WINDOW (f),
9705 bits,
9706 img->width, img->height,
9707 foreground, background,
9708 depth);
9709 #endif
9710 if (img->pixmap)
9711 success_p = 1;
9712 else
9713 {
9714 image_error ("Unable to create pixmap for XBM image `%s'",
9715 img->spec, Qnil);
9716 x_clear_image (f, img);
9717 }
9718 }
9719 }
9720
9721 return success_p;
9722 }
9723
9724
9725 \f
9726 /***********************************************************************
9727 XPM images
9728 ***********************************************************************/
9729
9730 #if HAVE_XPM
9731
9732 static int xpm_image_p P_ ((Lisp_Object object));
9733 static int xpm_load P_ ((struct frame *f, struct image *img));
9734 static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
9735
9736 #include "X11/xpm.h"
9737
9738 /* The symbol `xpm' identifying XPM-format images. */
9739
9740 Lisp_Object Qxpm;
9741
9742 /* Indices of image specification fields in xpm_format, below. */
9743
9744 enum xpm_keyword_index
9745 {
9746 XPM_TYPE,
9747 XPM_FILE,
9748 XPM_DATA,
9749 XPM_ASCENT,
9750 XPM_MARGIN,
9751 XPM_RELIEF,
9752 XPM_ALGORITHM,
9753 XPM_HEURISTIC_MASK,
9754 XPM_MASK,
9755 XPM_COLOR_SYMBOLS,
9756 XPM_BACKGROUND,
9757 XPM_LAST
9758 };
9759
9760 /* Vector of image_keyword structures describing the format
9761 of valid XPM image specifications. */
9762
9763 static struct image_keyword xpm_format[XPM_LAST] =
9764 {
9765 {":type", IMAGE_SYMBOL_VALUE, 1},
9766 {":file", IMAGE_STRING_VALUE, 0},
9767 {":data", IMAGE_STRING_VALUE, 0},
9768 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
9769 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
9770 {":relief", IMAGE_INTEGER_VALUE, 0},
9771 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9772 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9773 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9774 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9775 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
9776 };
9777
9778 /* Structure describing the image type XBM. */
9779
9780 static struct image_type xpm_type =
9781 {
9782 &Qxpm,
9783 xpm_image_p,
9784 xpm_load,
9785 x_clear_image,
9786 NULL
9787 };
9788
9789
9790 /* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
9791 for XPM images. Such a list must consist of conses whose car and
9792 cdr are strings. */
9793
9794 static int
9795 xpm_valid_color_symbols_p (color_symbols)
9796 Lisp_Object color_symbols;
9797 {
9798 while (CONSP (color_symbols))
9799 {
9800 Lisp_Object sym = XCAR (color_symbols);
9801 if (!CONSP (sym)
9802 || !STRINGP (XCAR (sym))
9803 || !STRINGP (XCDR (sym)))
9804 break;
9805 color_symbols = XCDR (color_symbols);
9806 }
9807
9808 return NILP (color_symbols);
9809 }
9810
9811
9812 /* Value is non-zero if OBJECT is a valid XPM image specification. */
9813
9814 static int
9815 xpm_image_p (object)
9816 Lisp_Object object;
9817 {
9818 struct image_keyword fmt[XPM_LAST];
9819 bcopy (xpm_format, fmt, sizeof fmt);
9820 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
9821 /* Either `:file' or `:data' must be present. */
9822 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
9823 /* Either no `:color-symbols' or it's a list of conses
9824 whose car and cdr are strings. */
9825 && (fmt[XPM_COLOR_SYMBOLS].count == 0
9826 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value))
9827 && (fmt[XPM_ASCENT].count == 0
9828 || XFASTINT (fmt[XPM_ASCENT].value) < 100));
9829 }
9830
9831
9832 /* Load image IMG which will be displayed on frame F. Value is
9833 non-zero if successful. */
9834
9835 static int
9836 xpm_load (f, img)
9837 struct frame *f;
9838 struct image *img;
9839 {
9840 int rc, i;
9841 XpmAttributes attrs;
9842 Lisp_Object specified_file, color_symbols;
9843
9844 /* Configure the XPM lib. Use the visual of frame F. Allocate
9845 close colors. Return colors allocated. */
9846 bzero (&attrs, sizeof attrs);
9847 attrs.visual = FRAME_X_VISUAL (f);
9848 attrs.colormap = FRAME_X_COLORMAP (f);
9849 attrs.valuemask |= XpmVisual;
9850 attrs.valuemask |= XpmColormap;
9851 attrs.valuemask |= XpmReturnAllocPixels;
9852 #ifdef XpmAllocCloseColors
9853 attrs.alloc_close_colors = 1;
9854 attrs.valuemask |= XpmAllocCloseColors;
9855 #else
9856 attrs.closeness = 600;
9857 attrs.valuemask |= XpmCloseness;
9858 #endif
9859
9860 /* If image specification contains symbolic color definitions, add
9861 these to `attrs'. */
9862 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
9863 if (CONSP (color_symbols))
9864 {
9865 Lisp_Object tail;
9866 XpmColorSymbol *xpm_syms;
9867 int i, size;
9868
9869 attrs.valuemask |= XpmColorSymbols;
9870
9871 /* Count number of symbols. */
9872 attrs.numsymbols = 0;
9873 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
9874 ++attrs.numsymbols;
9875
9876 /* Allocate an XpmColorSymbol array. */
9877 size = attrs.numsymbols * sizeof *xpm_syms;
9878 xpm_syms = (XpmColorSymbol *) alloca (size);
9879 bzero (xpm_syms, size);
9880 attrs.colorsymbols = xpm_syms;
9881
9882 /* Fill the color symbol array. */
9883 for (tail = color_symbols, i = 0;
9884 CONSP (tail);
9885 ++i, tail = XCDR (tail))
9886 {
9887 Lisp_Object name = XCAR (XCAR (tail));
9888 Lisp_Object color = XCDR (XCAR (tail));
9889 xpm_syms[i].name = (char *) alloca (XSTRING (name)->size + 1);
9890 strcpy (xpm_syms[i].name, XSTRING (name)->data);
9891 xpm_syms[i].value = (char *) alloca (XSTRING (color)->size + 1);
9892 strcpy (xpm_syms[i].value, XSTRING (color)->data);
9893 }
9894 }
9895
9896 /* Create a pixmap for the image, either from a file, or from a
9897 string buffer containing data in the same format as an XPM file. */
9898 BLOCK_INPUT;
9899 specified_file = image_spec_value (img->spec, QCfile, NULL);
9900 if (STRINGP (specified_file))
9901 {
9902 Lisp_Object file = x_find_image_file (specified_file);
9903 if (!STRINGP (file))
9904 {
9905 image_error ("Cannot find image file `%s'", specified_file, Qnil);
9906 UNBLOCK_INPUT;
9907 return 0;
9908 }
9909
9910 rc = XpmReadFileToPixmap (NULL, FRAME_W32_WINDOW (f),
9911 XSTRING (file)->data, &img->pixmap, &img->mask,
9912 &attrs);
9913 }
9914 else
9915 {
9916 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
9917 rc = XpmCreatePixmapFromBuffer (NULL, FRAME_W32_WINDOW (f),
9918 XSTRING (buffer)->data,
9919 &img->pixmap, &img->mask,
9920 &attrs);
9921 }
9922 UNBLOCK_INPUT;
9923
9924 if (rc == XpmSuccess)
9925 {
9926 /* Remember allocated colors. */
9927 img->ncolors = attrs.nalloc_pixels;
9928 img->colors = (unsigned long *) xmalloc (img->ncolors
9929 * sizeof *img->colors);
9930 for (i = 0; i < attrs.nalloc_pixels; ++i)
9931 img->colors[i] = attrs.alloc_pixels[i];
9932
9933 img->width = attrs.width;
9934 img->height = attrs.height;
9935 xassert (img->width > 0 && img->height > 0);
9936
9937 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
9938 BLOCK_INPUT;
9939 XpmFreeAttributes (&attrs);
9940 UNBLOCK_INPUT;
9941 }
9942 else
9943 {
9944 switch (rc)
9945 {
9946 case XpmOpenFailed:
9947 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
9948 break;
9949
9950 case XpmFileInvalid:
9951 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
9952 break;
9953
9954 case XpmNoMemory:
9955 image_error ("Out of memory (%s)", img->spec, Qnil);
9956 break;
9957
9958 case XpmColorFailed:
9959 image_error ("Color allocation error (%s)", img->spec, Qnil);
9960 break;
9961
9962 default:
9963 image_error ("Unknown error (%s)", img->spec, Qnil);
9964 break;
9965 }
9966 }
9967
9968 return rc == XpmSuccess;
9969 }
9970
9971 #endif /* HAVE_XPM != 0 */
9972
9973 \f
9974 #if 0 /* TODO : Color tables on W32. */
9975 /***********************************************************************
9976 Color table
9977 ***********************************************************************/
9978
9979 /* An entry in the color table mapping an RGB color to a pixel color. */
9980
9981 struct ct_color
9982 {
9983 int r, g, b;
9984 unsigned long pixel;
9985
9986 /* Next in color table collision list. */
9987 struct ct_color *next;
9988 };
9989
9990 /* The bucket vector size to use. Must be prime. */
9991
9992 #define CT_SIZE 101
9993
9994 /* Value is a hash of the RGB color given by R, G, and B. */
9995
9996 #define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
9997
9998 /* The color hash table. */
9999
10000 struct ct_color **ct_table;
10001
10002 /* Number of entries in the color table. */
10003
10004 int ct_colors_allocated;
10005
10006 /* Function prototypes. */
10007
10008 static void init_color_table P_ ((void));
10009 static void free_color_table P_ ((void));
10010 static unsigned long *colors_in_color_table P_ ((int *n));
10011 static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
10012 static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
10013
10014
10015 /* Initialize the color table. */
10016
10017 static void
10018 init_color_table ()
10019 {
10020 int size = CT_SIZE * sizeof (*ct_table);
10021 ct_table = (struct ct_color **) xmalloc (size);
10022 bzero (ct_table, size);
10023 ct_colors_allocated = 0;
10024 }
10025
10026
10027 /* Free memory associated with the color table. */
10028
10029 static void
10030 free_color_table ()
10031 {
10032 int i;
10033 struct ct_color *p, *next;
10034
10035 for (i = 0; i < CT_SIZE; ++i)
10036 for (p = ct_table[i]; p; p = next)
10037 {
10038 next = p->next;
10039 xfree (p);
10040 }
10041
10042 xfree (ct_table);
10043 ct_table = NULL;
10044 }
10045
10046
10047 /* Value is a pixel color for RGB color R, G, B on frame F. If an
10048 entry for that color already is in the color table, return the
10049 pixel color of that entry. Otherwise, allocate a new color for R,
10050 G, B, and make an entry in the color table. */
10051
10052 static unsigned long
10053 lookup_rgb_color (f, r, g, b)
10054 struct frame *f;
10055 int r, g, b;
10056 {
10057 unsigned hash = CT_HASH_RGB (r, g, b);
10058 int i = hash % CT_SIZE;
10059 struct ct_color *p;
10060
10061 for (p = ct_table[i]; p; p = p->next)
10062 if (p->r == r && p->g == g && p->b == b)
10063 break;
10064
10065 if (p == NULL)
10066 {
10067 COLORREF color;
10068 Colormap cmap;
10069 int rc;
10070
10071 color = PALETTERGB (r, g, b);
10072
10073 ++ct_colors_allocated;
10074
10075 p = (struct ct_color *) xmalloc (sizeof *p);
10076 p->r = r;
10077 p->g = g;
10078 p->b = b;
10079 p->pixel = color;
10080 p->next = ct_table[i];
10081 ct_table[i] = p;
10082 }
10083
10084 return p->pixel;
10085 }
10086
10087
10088 /* Look up pixel color PIXEL which is used on frame F in the color
10089 table. If not already present, allocate it. Value is PIXEL. */
10090
10091 static unsigned long
10092 lookup_pixel_color (f, pixel)
10093 struct frame *f;
10094 unsigned long pixel;
10095 {
10096 int i = pixel % CT_SIZE;
10097 struct ct_color *p;
10098
10099 for (p = ct_table[i]; p; p = p->next)
10100 if (p->pixel == pixel)
10101 break;
10102
10103 if (p == NULL)
10104 {
10105 XColor color;
10106 Colormap cmap;
10107 int rc;
10108
10109 BLOCK_INPUT;
10110
10111 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
10112 color.pixel = pixel;
10113 XQueryColor (NULL, cmap, &color);
10114 rc = x_alloc_nearest_color (f, cmap, &color);
10115 UNBLOCK_INPUT;
10116
10117 if (rc)
10118 {
10119 ++ct_colors_allocated;
10120
10121 p = (struct ct_color *) xmalloc (sizeof *p);
10122 p->r = color.red;
10123 p->g = color.green;
10124 p->b = color.blue;
10125 p->pixel = pixel;
10126 p->next = ct_table[i];
10127 ct_table[i] = p;
10128 }
10129 else
10130 return FRAME_FOREGROUND_PIXEL (f);
10131 }
10132 return p->pixel;
10133 }
10134
10135
10136 /* Value is a vector of all pixel colors contained in the color table,
10137 allocated via xmalloc. Set *N to the number of colors. */
10138
10139 static unsigned long *
10140 colors_in_color_table (n)
10141 int *n;
10142 {
10143 int i, j;
10144 struct ct_color *p;
10145 unsigned long *colors;
10146
10147 if (ct_colors_allocated == 0)
10148 {
10149 *n = 0;
10150 colors = NULL;
10151 }
10152 else
10153 {
10154 colors = (unsigned long *) xmalloc (ct_colors_allocated
10155 * sizeof *colors);
10156 *n = ct_colors_allocated;
10157
10158 for (i = j = 0; i < CT_SIZE; ++i)
10159 for (p = ct_table[i]; p; p = p->next)
10160 colors[j++] = p->pixel;
10161 }
10162
10163 return colors;
10164 }
10165
10166 #endif /* TODO */
10167
10168 \f
10169 /***********************************************************************
10170 Algorithms
10171 ***********************************************************************/
10172 #if 0 /* TODO: image support. */
10173 static XColor *x_to_xcolors P_ ((struct frame *, struct image *, int));
10174 static void x_from_xcolors P_ ((struct frame *, struct image *, XColor *));
10175 static void x_detect_edges P_ ((struct frame *, struct image *, int[9], int));
10176
10177 /* Non-zero means draw a cross on images having `:conversion
10178 disabled'. */
10179
10180 int cross_disabled_images;
10181
10182 /* Edge detection matrices for different edge-detection
10183 strategies. */
10184
10185 static int emboss_matrix[9] = {
10186 /* x - 1 x x + 1 */
10187 2, -1, 0, /* y - 1 */
10188 -1, 0, 1, /* y */
10189 0, 1, -2 /* y + 1 */
10190 };
10191
10192 static int laplace_matrix[9] = {
10193 /* x - 1 x x + 1 */
10194 1, 0, 0, /* y - 1 */
10195 0, 0, 0, /* y */
10196 0, 0, -1 /* y + 1 */
10197 };
10198
10199 /* Value is the intensity of the color whose red/green/blue values
10200 are R, G, and B. */
10201
10202 #define COLOR_INTENSITY(R, G, B) ((2 * (R) + 3 * (G) + (B)) / 6)
10203
10204
10205 /* On frame F, return an array of XColor structures describing image
10206 IMG->pixmap. Each XColor structure has its pixel color set. RGB_P
10207 non-zero means also fill the red/green/blue members of the XColor
10208 structures. Value is a pointer to the array of XColors structures,
10209 allocated with xmalloc; it must be freed by the caller. */
10210
10211 static XColor *
10212 x_to_xcolors (f, img, rgb_p)
10213 struct frame *f;
10214 struct image *img;
10215 int rgb_p;
10216 {
10217 int x, y;
10218 XColor *colors, *p;
10219 XImage *ximg;
10220
10221 colors = (XColor *) xmalloc (img->width * img->height * sizeof *colors);
10222
10223 /* Get the X image IMG->pixmap. */
10224 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
10225 0, 0, img->width, img->height, ~0, ZPixmap);
10226
10227 /* Fill the `pixel' members of the XColor array. I wished there
10228 were an easy and portable way to circumvent XGetPixel. */
10229 p = colors;
10230 for (y = 0; y < img->height; ++y)
10231 {
10232 XColor *row = p;
10233
10234 for (x = 0; x < img->width; ++x, ++p)
10235 p->pixel = XGetPixel (ximg, x, y);
10236
10237 if (rgb_p)
10238 x_query_colors (f, row, img->width);
10239 }
10240
10241 XDestroyImage (ximg);
10242 return colors;
10243 }
10244
10245
10246 /* Create IMG->pixmap from an array COLORS of XColor structures, whose
10247 RGB members are set. F is the frame on which this all happens.
10248 COLORS will be freed; an existing IMG->pixmap will be freed, too. */
10249
10250 static void
10251 x_from_xcolors (f, img, colors)
10252 struct frame *f;
10253 struct image *img;
10254 XColor *colors;
10255 {
10256 int x, y;
10257 XImage *oimg;
10258 Pixmap pixmap;
10259 XColor *p;
10260
10261 init_color_table ();
10262
10263 x_create_x_image_and_pixmap (f, img->width, img->height, 0,
10264 &oimg, &pixmap);
10265 p = colors;
10266 for (y = 0; y < img->height; ++y)
10267 for (x = 0; x < img->width; ++x, ++p)
10268 {
10269 unsigned long pixel;
10270 pixel = lookup_rgb_color (f, p->red, p->green, p->blue);
10271 XPutPixel (oimg, x, y, pixel);
10272 }
10273
10274 xfree (colors);
10275 x_clear_image_1 (f, img, 1, 0, 1);
10276
10277 x_put_x_image (f, oimg, pixmap, img->width, img->height);
10278 x_destroy_x_image (oimg);
10279 img->pixmap = pixmap;
10280 img->colors = colors_in_color_table (&img->ncolors);
10281 free_color_table ();
10282 }
10283
10284
10285 /* On frame F, perform edge-detection on image IMG.
10286
10287 MATRIX is a nine-element array specifying the transformation
10288 matrix. See emboss_matrix for an example.
10289
10290 COLOR_ADJUST is a color adjustment added to each pixel of the
10291 outgoing image. */
10292
10293 static void
10294 x_detect_edges (f, img, matrix, color_adjust)
10295 struct frame *f;
10296 struct image *img;
10297 int matrix[9], color_adjust;
10298 {
10299 XColor *colors = x_to_xcolors (f, img, 1);
10300 XColor *new, *p;
10301 int x, y, i, sum;
10302
10303 for (i = sum = 0; i < 9; ++i)
10304 sum += abs (matrix[i]);
10305
10306 #define COLOR(A, X, Y) ((A) + (Y) * img->width + (X))
10307
10308 new = (XColor *) xmalloc (img->width * img->height * sizeof *new);
10309
10310 for (y = 0; y < img->height; ++y)
10311 {
10312 p = COLOR (new, 0, y);
10313 p->red = p->green = p->blue = 0xffff/2;
10314 p = COLOR (new, img->width - 1, y);
10315 p->red = p->green = p->blue = 0xffff/2;
10316 }
10317
10318 for (x = 1; x < img->width - 1; ++x)
10319 {
10320 p = COLOR (new, x, 0);
10321 p->red = p->green = p->blue = 0xffff/2;
10322 p = COLOR (new, x, img->height - 1);
10323 p->red = p->green = p->blue = 0xffff/2;
10324 }
10325
10326 for (y = 1; y < img->height - 1; ++y)
10327 {
10328 p = COLOR (new, 1, y);
10329
10330 for (x = 1; x < img->width - 1; ++x, ++p)
10331 {
10332 int r, g, b, y1, x1;
10333
10334 r = g = b = i = 0;
10335 for (y1 = y - 1; y1 < y + 2; ++y1)
10336 for (x1 = x - 1; x1 < x + 2; ++x1, ++i)
10337 if (matrix[i])
10338 {
10339 XColor *t = COLOR (colors, x1, y1);
10340 r += matrix[i] * t->red;
10341 g += matrix[i] * t->green;
10342 b += matrix[i] * t->blue;
10343 }
10344
10345 r = (r / sum + color_adjust) & 0xffff;
10346 g = (g / sum + color_adjust) & 0xffff;
10347 b = (b / sum + color_adjust) & 0xffff;
10348 p->red = p->green = p->blue = COLOR_INTENSITY (r, g, b);
10349 }
10350 }
10351
10352 xfree (colors);
10353 x_from_xcolors (f, img, new);
10354
10355 #undef COLOR
10356 }
10357
10358
10359 /* Perform the pre-defined `emboss' edge-detection on image IMG
10360 on frame F. */
10361
10362 static void
10363 x_emboss (f, img)
10364 struct frame *f;
10365 struct image *img;
10366 {
10367 x_detect_edges (f, img, emboss_matrix, 0xffff / 2);
10368 }
10369
10370
10371 /* Transform image IMG which is used on frame F with a Laplace
10372 edge-detection algorithm. The result is an image that can be used
10373 to draw disabled buttons, for example. */
10374
10375 static void
10376 x_laplace (f, img)
10377 struct frame *f;
10378 struct image *img;
10379 {
10380 x_detect_edges (f, img, laplace_matrix, 45000);
10381 }
10382
10383
10384 /* Perform edge-detection on image IMG on frame F, with specified
10385 transformation matrix MATRIX and color-adjustment COLOR_ADJUST.
10386
10387 MATRIX must be either
10388
10389 - a list of at least 9 numbers in row-major form
10390 - a vector of at least 9 numbers
10391
10392 COLOR_ADJUST nil means use a default; otherwise it must be a
10393 number. */
10394
10395 static void
10396 x_edge_detection (f, img, matrix, color_adjust)
10397 struct frame *f;
10398 struct image *img;
10399 Lisp_Object matrix, color_adjust;
10400 {
10401 int i = 0;
10402 int trans[9];
10403
10404 if (CONSP (matrix))
10405 {
10406 for (i = 0;
10407 i < 9 && CONSP (matrix) && NUMBERP (XCAR (matrix));
10408 ++i, matrix = XCDR (matrix))
10409 trans[i] = XFLOATINT (XCAR (matrix));
10410 }
10411 else if (VECTORP (matrix) && ASIZE (matrix) >= 9)
10412 {
10413 for (i = 0; i < 9 && NUMBERP (AREF (matrix, i)); ++i)
10414 trans[i] = XFLOATINT (AREF (matrix, i));
10415 }
10416
10417 if (NILP (color_adjust))
10418 color_adjust = make_number (0xffff / 2);
10419
10420 if (i == 9 && NUMBERP (color_adjust))
10421 x_detect_edges (f, img, trans, (int) XFLOATINT (color_adjust));
10422 }
10423
10424
10425 /* Transform image IMG on frame F so that it looks disabled. */
10426
10427 static void
10428 x_disable_image (f, img)
10429 struct frame *f;
10430 struct image *img;
10431 {
10432 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
10433
10434 if (dpyinfo->n_planes >= 2)
10435 {
10436 /* Color (or grayscale). Convert to gray, and equalize. Just
10437 drawing such images with a stipple can look very odd, so
10438 we're using this method instead. */
10439 XColor *colors = x_to_xcolors (f, img, 1);
10440 XColor *p, *end;
10441 const int h = 15000;
10442 const int l = 30000;
10443
10444 for (p = colors, end = colors + img->width * img->height;
10445 p < end;
10446 ++p)
10447 {
10448 int i = COLOR_INTENSITY (p->red, p->green, p->blue);
10449 int i2 = (0xffff - h - l) * i / 0xffff + l;
10450 p->red = p->green = p->blue = i2;
10451 }
10452
10453 x_from_xcolors (f, img, colors);
10454 }
10455
10456 /* Draw a cross over the disabled image, if we must or if we
10457 should. */
10458 if (dpyinfo->n_planes < 2 || cross_disabled_images)
10459 {
10460 Display *dpy = FRAME_X_DISPLAY (f);
10461 GC gc;
10462
10463 gc = XCreateGC (dpy, img->pixmap, 0, NULL);
10464 XSetForeground (dpy, gc, BLACK_PIX_DEFAULT (f));
10465 XDrawLine (dpy, img->pixmap, gc, 0, 0,
10466 img->width - 1, img->height - 1);
10467 XDrawLine (dpy, img->pixmap, gc, 0, img->height - 1,
10468 img->width - 1, 0);
10469 XFreeGC (dpy, gc);
10470
10471 if (img->mask)
10472 {
10473 gc = XCreateGC (dpy, img->mask, 0, NULL);
10474 XSetForeground (dpy, gc, WHITE_PIX_DEFAULT (f));
10475 XDrawLine (dpy, img->mask, gc, 0, 0,
10476 img->width - 1, img->height - 1);
10477 XDrawLine (dpy, img->mask, gc, 0, img->height - 1,
10478 img->width - 1, 0);
10479 XFreeGC (dpy, gc);
10480 }
10481 }
10482 }
10483
10484
10485 /* Build a mask for image IMG which is used on frame F. FILE is the
10486 name of an image file, for error messages. HOW determines how to
10487 determine the background color of IMG. If it is a list '(R G B)',
10488 with R, G, and B being integers >= 0, take that as the color of the
10489 background. Otherwise, determine the background color of IMG
10490 heuristically. Value is non-zero if successful. */
10491
10492 static int
10493 x_build_heuristic_mask (f, img, how)
10494 struct frame *f;
10495 struct image *img;
10496 Lisp_Object how;
10497 {
10498 Display *dpy = FRAME_W32_DISPLAY (f);
10499 XImage *ximg, *mask_img;
10500 int x, y, rc, use_img_background;
10501 unsigned long bg = 0;
10502
10503 if (img->mask)
10504 {
10505 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
10506 img->mask = None;
10507 img->background_transparent_valid = 0;
10508 }
10509
10510 /* Create an image and pixmap serving as mask. */
10511 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
10512 &mask_img, &img->mask);
10513 if (!rc)
10514 return 0;
10515
10516 /* Get the X image of IMG->pixmap. */
10517 ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height,
10518 ~0, ZPixmap);
10519
10520 /* Determine the background color of ximg. If HOW is `(R G B)'
10521 take that as color. Otherwise, use the image's background color. */
10522 use_img_background = 1;
10523
10524 if (CONSP (how))
10525 {
10526 int rgb[3], i;
10527
10528 for (i = 0; i < 3 && CONSP (how) && NATNUMP (XCAR (how)); ++i)
10529 {
10530 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
10531 how = XCDR (how);
10532 }
10533
10534 if (i == 3 && NILP (how))
10535 {
10536 char color_name[30];
10537 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
10538 bg = x_alloc_image_color (f, img, build_string (color_name), 0);
10539 use_img_background = 0;
10540 }
10541 }
10542
10543 if (use_img_background)
10544 bg = four_corners_best (ximg, img->width, img->height);
10545
10546 /* Set all bits in mask_img to 1 whose color in ximg is different
10547 from the background color bg. */
10548 for (y = 0; y < img->height; ++y)
10549 for (x = 0; x < img->width; ++x)
10550 XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg);
10551
10552 /* Fill in the background_transparent field while we have the mask handy. */
10553 image_background_transparent (img, f, mask_img);
10554
10555 /* Put mask_img into img->mask. */
10556 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
10557 x_destroy_x_image (mask_img);
10558 XDestroyImage (ximg);
10559
10560 return 1;
10561 }
10562 #endif /* TODO */
10563
10564 \f
10565 /***********************************************************************
10566 PBM (mono, gray, color)
10567 ***********************************************************************/
10568 #ifdef HAVE_PBM
10569
10570 static int pbm_image_p P_ ((Lisp_Object object));
10571 static int pbm_load P_ ((struct frame *f, struct image *img));
10572 static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
10573
10574 /* The symbol `pbm' identifying images of this type. */
10575
10576 Lisp_Object Qpbm;
10577
10578 /* Indices of image specification fields in gs_format, below. */
10579
10580 enum pbm_keyword_index
10581 {
10582 PBM_TYPE,
10583 PBM_FILE,
10584 PBM_DATA,
10585 PBM_ASCENT,
10586 PBM_MARGIN,
10587 PBM_RELIEF,
10588 PBM_ALGORITHM,
10589 PBM_HEURISTIC_MASK,
10590 PBM_MASK,
10591 PBM_FOREGROUND,
10592 PBM_BACKGROUND,
10593 PBM_LAST
10594 };
10595
10596 /* Vector of image_keyword structures describing the format
10597 of valid user-defined image specifications. */
10598
10599 static struct image_keyword pbm_format[PBM_LAST] =
10600 {
10601 {":type", IMAGE_SYMBOL_VALUE, 1},
10602 {":file", IMAGE_STRING_VALUE, 0},
10603 {":data", IMAGE_STRING_VALUE, 0},
10604 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
10605 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
10606 {":relief", IMAGE_INTEGER_VALUE, 0},
10607 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10608 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10609 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10610 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
10611 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
10612 };
10613
10614 /* Structure describing the image type `pbm'. */
10615
10616 static struct image_type pbm_type =
10617 {
10618 &Qpbm,
10619 pbm_image_p,
10620 pbm_load,
10621 x_clear_image,
10622 NULL
10623 };
10624
10625
10626 /* Return non-zero if OBJECT is a valid PBM image specification. */
10627
10628 static int
10629 pbm_image_p (object)
10630 Lisp_Object object;
10631 {
10632 struct image_keyword fmt[PBM_LAST];
10633
10634 bcopy (pbm_format, fmt, sizeof fmt);
10635
10636 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm)
10637 || (fmt[PBM_ASCENT].count
10638 && XFASTINT (fmt[PBM_ASCENT].value) > 100))
10639 return 0;
10640
10641 /* Must specify either :data or :file. */
10642 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
10643 }
10644
10645
10646 /* Scan a decimal number from *S and return it. Advance *S while
10647 reading the number. END is the end of the string. Value is -1 at
10648 end of input. */
10649
10650 static int
10651 pbm_scan_number (s, end)
10652 unsigned char **s, *end;
10653 {
10654 int c, val = -1;
10655
10656 while (*s < end)
10657 {
10658 /* Skip white-space. */
10659 while (*s < end && (c = *(*s)++, isspace (c)))
10660 ;
10661
10662 if (c == '#')
10663 {
10664 /* Skip comment to end of line. */
10665 while (*s < end && (c = *(*s)++, c != '\n'))
10666 ;
10667 }
10668 else if (isdigit (c))
10669 {
10670 /* Read decimal number. */
10671 val = c - '0';
10672 while (*s < end && (c = *(*s)++, isdigit (c)))
10673 val = 10 * val + c - '0';
10674 break;
10675 }
10676 else
10677 break;
10678 }
10679
10680 return val;
10681 }
10682
10683
10684 /* Read FILE into memory. Value is a pointer to a buffer allocated
10685 with xmalloc holding FILE's contents. Value is null if an error
10686 occured. *SIZE is set to the size of the file. */
10687
10688 static char *
10689 pbm_read_file (file, size)
10690 Lisp_Object file;
10691 int *size;
10692 {
10693 FILE *fp = NULL;
10694 char *buf = NULL;
10695 struct stat st;
10696
10697 if (stat (XSTRING (file)->data, &st) == 0
10698 && (fp = fopen (XSTRING (file)->data, "r")) != NULL
10699 && (buf = (char *) xmalloc (st.st_size),
10700 fread (buf, 1, st.st_size, fp) == st.st_size))
10701 {
10702 *size = st.st_size;
10703 fclose (fp);
10704 }
10705 else
10706 {
10707 if (fp)
10708 fclose (fp);
10709 if (buf)
10710 {
10711 xfree (buf);
10712 buf = NULL;
10713 }
10714 }
10715
10716 return buf;
10717 }
10718
10719
10720 /* Load PBM image IMG for use on frame F. */
10721
10722 static int
10723 pbm_load (f, img)
10724 struct frame *f;
10725 struct image *img;
10726 {
10727 int raw_p, x, y;
10728 int width, height, max_color_idx = 0;
10729 XImage *ximg;
10730 Lisp_Object file, specified_file;
10731 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
10732 struct gcpro gcpro1;
10733 unsigned char *contents = NULL;
10734 unsigned char *end, *p;
10735 int size;
10736
10737 specified_file = image_spec_value (img->spec, QCfile, NULL);
10738 file = Qnil;
10739 GCPRO1 (file);
10740
10741 if (STRINGP (specified_file))
10742 {
10743 file = x_find_image_file (specified_file);
10744 if (!STRINGP (file))
10745 {
10746 image_error ("Cannot find image file `%s'", specified_file, Qnil);
10747 UNGCPRO;
10748 return 0;
10749 }
10750
10751 contents = slurp_file (XSTRING (file)->data, &size);
10752 if (contents == NULL)
10753 {
10754 image_error ("Error reading `%s'", file, Qnil);
10755 UNGCPRO;
10756 return 0;
10757 }
10758
10759 p = contents;
10760 end = contents + size;
10761 }
10762 else
10763 {
10764 Lisp_Object data;
10765 data = image_spec_value (img->spec, QCdata, NULL);
10766 p = XSTRING (data)->data;
10767 end = p + STRING_BYTES (XSTRING (data));
10768 }
10769
10770 /* Check magic number. */
10771 if (end - p < 2 || *p++ != 'P')
10772 {
10773 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
10774 error:
10775 xfree (contents);
10776 UNGCPRO;
10777 return 0;
10778 }
10779
10780 switch (*p++)
10781 {
10782 case '1':
10783 raw_p = 0, type = PBM_MONO;
10784 break;
10785
10786 case '2':
10787 raw_p = 0, type = PBM_GRAY;
10788 break;
10789
10790 case '3':
10791 raw_p = 0, type = PBM_COLOR;
10792 break;
10793
10794 case '4':
10795 raw_p = 1, type = PBM_MONO;
10796 break;
10797
10798 case '5':
10799 raw_p = 1, type = PBM_GRAY;
10800 break;
10801
10802 case '6':
10803 raw_p = 1, type = PBM_COLOR;
10804 break;
10805
10806 default:
10807 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
10808 goto error;
10809 }
10810
10811 /* Read width, height, maximum color-component. Characters
10812 starting with `#' up to the end of a line are ignored. */
10813 width = pbm_scan_number (&p, end);
10814 height = pbm_scan_number (&p, end);
10815
10816 if (type != PBM_MONO)
10817 {
10818 max_color_idx = pbm_scan_number (&p, end);
10819 if (raw_p && max_color_idx > 255)
10820 max_color_idx = 255;
10821 }
10822
10823 if (width < 0
10824 || height < 0
10825 || (type != PBM_MONO && max_color_idx < 0))
10826 goto error;
10827
10828 if (!x_create_x_image_and_pixmap (f, width, height, 0,
10829 &ximg, &img->pixmap))
10830 goto error;
10831
10832 /* Initialize the color hash table. */
10833 init_color_table ();
10834
10835 if (type == PBM_MONO)
10836 {
10837 int c = 0, g;
10838 struct image_keyword fmt[PBM_LAST];
10839 unsigned long fg = FRAME_FOREGROUND_PIXEL (f);
10840 unsigned long bg = FRAME_BACKGROUND_PIXEL (f);
10841
10842 /* Parse the image specification. */
10843 bcopy (pbm_format, fmt, sizeof fmt);
10844 parse_image_spec (img->spec, fmt, PBM_LAST, Qpbm);
10845
10846 /* Get foreground and background colors, maybe allocate colors. */
10847 if (fmt[PBM_FOREGROUND].count
10848 && STRINGP (fmt[PBM_FOREGROUND].value))
10849 fg = x_alloc_image_color (f, img, fmt[PBM_FOREGROUND].value, fg);
10850 if (fmt[PBM_BACKGROUND].count
10851 && STRINGP (fmt[PBM_BACKGROUND].value))
10852 {
10853 bg = x_alloc_image_color (f, img, fmt[PBM_BACKGROUND].value, bg);
10854 img->background = bg;
10855 img->background_valid = 1;
10856 }
10857
10858 for (y = 0; y < height; ++y)
10859 for (x = 0; x < width; ++x)
10860 {
10861 if (raw_p)
10862 {
10863 if ((x & 7) == 0)
10864 c = *p++;
10865 g = c & 0x80;
10866 c <<= 1;
10867 }
10868 else
10869 g = pbm_scan_number (&p, end);
10870
10871 XPutPixel (ximg, x, y, g ? fg : bg);
10872 }
10873 }
10874 else
10875 {
10876 for (y = 0; y < height; ++y)
10877 for (x = 0; x < width; ++x)
10878 {
10879 int r, g, b;
10880
10881 if (type == PBM_GRAY)
10882 r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
10883 else if (raw_p)
10884 {
10885 r = *p++;
10886 g = *p++;
10887 b = *p++;
10888 }
10889 else
10890 {
10891 r = pbm_scan_number (&p, end);
10892 g = pbm_scan_number (&p, end);
10893 b = pbm_scan_number (&p, end);
10894 }
10895
10896 if (r < 0 || g < 0 || b < 0)
10897 {
10898 xfree (ximg->data);
10899 ximg->data = NULL;
10900 XDestroyImage (ximg);
10901 image_error ("Invalid pixel value in image `%s'",
10902 img->spec, Qnil);
10903 goto error;
10904 }
10905
10906 /* RGB values are now in the range 0..max_color_idx.
10907 Scale this to the range 0..0xffff supported by X. */
10908 r = (double) r * 65535 / max_color_idx;
10909 g = (double) g * 65535 / max_color_idx;
10910 b = (double) b * 65535 / max_color_idx;
10911 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
10912 }
10913 }
10914
10915 /* Store in IMG->colors the colors allocated for the image, and
10916 free the color table. */
10917 img->colors = colors_in_color_table (&img->ncolors);
10918 free_color_table ();
10919
10920 /* Maybe fill in the background field while we have ximg handy. */
10921 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
10922 IMAGE_BACKGROUND (img, f, ximg);
10923
10924 /* Put the image into a pixmap. */
10925 x_put_x_image (f, ximg, img->pixmap, width, height);
10926 x_destroy_x_image (ximg);
10927
10928 img->width = width;
10929 img->height = height;
10930
10931 UNGCPRO;
10932 xfree (contents);
10933 return 1;
10934 }
10935 #endif /* HAVE_PBM */
10936
10937 \f
10938 /***********************************************************************
10939 PNG
10940 ***********************************************************************/
10941
10942 #if HAVE_PNG
10943
10944 #include <png.h>
10945
10946 /* Function prototypes. */
10947
10948 static int png_image_p P_ ((Lisp_Object object));
10949 static int png_load P_ ((struct frame *f, struct image *img));
10950
10951 /* The symbol `png' identifying images of this type. */
10952
10953 Lisp_Object Qpng;
10954
10955 /* Indices of image specification fields in png_format, below. */
10956
10957 enum png_keyword_index
10958 {
10959 PNG_TYPE,
10960 PNG_DATA,
10961 PNG_FILE,
10962 PNG_ASCENT,
10963 PNG_MARGIN,
10964 PNG_RELIEF,
10965 PNG_ALGORITHM,
10966 PNG_HEURISTIC_MASK,
10967 PNG_MASK,
10968 PNG_BACKGROUND,
10969 PNG_LAST
10970 };
10971
10972 /* Vector of image_keyword structures describing the format
10973 of valid user-defined image specifications. */
10974
10975 static struct image_keyword png_format[PNG_LAST] =
10976 {
10977 {":type", IMAGE_SYMBOL_VALUE, 1},
10978 {":data", IMAGE_STRING_VALUE, 0},
10979 {":file", IMAGE_STRING_VALUE, 0},
10980 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
10981 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
10982 {":relief", IMAGE_INTEGER_VALUE, 0},
10983 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10984 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10985 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10986 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
10987 };
10988
10989 /* Structure describing the image type `png'. */
10990
10991 static struct image_type png_type =
10992 {
10993 &Qpng,
10994 png_image_p,
10995 png_load,
10996 x_clear_image,
10997 NULL
10998 };
10999
11000
11001 /* Return non-zero if OBJECT is a valid PNG image specification. */
11002
11003 static int
11004 png_image_p (object)
11005 Lisp_Object object;
11006 {
11007 struct image_keyword fmt[PNG_LAST];
11008 bcopy (png_format, fmt, sizeof fmt);
11009
11010 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng)
11011 || (fmt[PNG_ASCENT].count
11012 && XFASTINT (fmt[PNG_ASCENT].value) > 100))
11013 return 0;
11014
11015 /* Must specify either the :data or :file keyword. */
11016 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
11017 }
11018
11019
11020 /* Error and warning handlers installed when the PNG library
11021 is initialized. */
11022
11023 static void
11024 my_png_error (png_ptr, msg)
11025 png_struct *png_ptr;
11026 char *msg;
11027 {
11028 xassert (png_ptr != NULL);
11029 image_error ("PNG error: %s", build_string (msg), Qnil);
11030 longjmp (png_ptr->jmpbuf, 1);
11031 }
11032
11033
11034 static void
11035 my_png_warning (png_ptr, msg)
11036 png_struct *png_ptr;
11037 char *msg;
11038 {
11039 xassert (png_ptr != NULL);
11040 image_error ("PNG warning: %s", build_string (msg), Qnil);
11041 }
11042
11043 /* Memory source for PNG decoding. */
11044
11045 struct png_memory_storage
11046 {
11047 unsigned char *bytes; /* The data */
11048 size_t len; /* How big is it? */
11049 int index; /* Where are we? */
11050 };
11051
11052
11053 /* Function set as reader function when reading PNG image from memory.
11054 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
11055 bytes from the input to DATA. */
11056
11057 static void
11058 png_read_from_memory (png_ptr, data, length)
11059 png_structp png_ptr;
11060 png_bytep data;
11061 png_size_t length;
11062 {
11063 struct png_memory_storage *tbr
11064 = (struct png_memory_storage *) png_get_io_ptr (png_ptr);
11065
11066 if (length > tbr->len - tbr->index)
11067 png_error (png_ptr, "Read error");
11068
11069 bcopy (tbr->bytes + tbr->index, data, length);
11070 tbr->index = tbr->index + length;
11071 }
11072
11073 /* Load PNG image IMG for use on frame F. Value is non-zero if
11074 successful. */
11075
11076 static int
11077 png_load (f, img)
11078 struct frame *f;
11079 struct image *img;
11080 {
11081 Lisp_Object file, specified_file;
11082 Lisp_Object specified_data;
11083 int x, y, i;
11084 XImage *ximg, *mask_img = NULL;
11085 struct gcpro gcpro1;
11086 png_struct *png_ptr = NULL;
11087 png_info *info_ptr = NULL, *end_info = NULL;
11088 FILE *volatile fp = NULL;
11089 png_byte sig[8];
11090 png_byte *volatile pixels = NULL;
11091 png_byte **volatile rows = NULL;
11092 png_uint_32 width, height;
11093 int bit_depth, color_type, interlace_type;
11094 png_byte channels;
11095 png_uint_32 row_bytes;
11096 int transparent_p;
11097 char *gamma_str;
11098 double screen_gamma, image_gamma;
11099 int intent;
11100 struct png_memory_storage tbr; /* Data to be read */
11101
11102 /* Find out what file to load. */
11103 specified_file = image_spec_value (img->spec, QCfile, NULL);
11104 specified_data = image_spec_value (img->spec, QCdata, NULL);
11105 file = Qnil;
11106 GCPRO1 (file);
11107
11108 if (NILP (specified_data))
11109 {
11110 file = x_find_image_file (specified_file);
11111 if (!STRINGP (file))
11112 {
11113 image_error ("Cannot find image file `%s'", specified_file, Qnil);
11114 UNGCPRO;
11115 return 0;
11116 }
11117
11118 /* Open the image file. */
11119 fp = fopen (XSTRING (file)->data, "rb");
11120 if (!fp)
11121 {
11122 image_error ("Cannot open image file `%s'", file, Qnil);
11123 UNGCPRO;
11124 fclose (fp);
11125 return 0;
11126 }
11127
11128 /* Check PNG signature. */
11129 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
11130 || !png_check_sig (sig, sizeof sig))
11131 {
11132 image_error ("Not a PNG file:` %s'", file, Qnil);
11133 UNGCPRO;
11134 fclose (fp);
11135 return 0;
11136 }
11137 }
11138 else
11139 {
11140 /* Read from memory. */
11141 tbr.bytes = XSTRING (specified_data)->data;
11142 tbr.len = STRING_BYTES (XSTRING (specified_data));
11143 tbr.index = 0;
11144
11145 /* Check PNG signature. */
11146 if (tbr.len < sizeof sig
11147 || !png_check_sig (tbr.bytes, sizeof sig))
11148 {
11149 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
11150 UNGCPRO;
11151 return 0;
11152 }
11153
11154 /* Need to skip past the signature. */
11155 tbr.bytes += sizeof (sig);
11156 }
11157
11158 /* Initialize read and info structs for PNG lib. */
11159 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
11160 my_png_error, my_png_warning);
11161 if (!png_ptr)
11162 {
11163 if (fp) fclose (fp);
11164 UNGCPRO;
11165 return 0;
11166 }
11167
11168 info_ptr = png_create_info_struct (png_ptr);
11169 if (!info_ptr)
11170 {
11171 png_destroy_read_struct (&png_ptr, NULL, NULL);
11172 if (fp) fclose (fp);
11173 UNGCPRO;
11174 return 0;
11175 }
11176
11177 end_info = png_create_info_struct (png_ptr);
11178 if (!end_info)
11179 {
11180 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
11181 if (fp) fclose (fp);
11182 UNGCPRO;
11183 return 0;
11184 }
11185
11186 /* Set error jump-back. We come back here when the PNG library
11187 detects an error. */
11188 if (setjmp (png_ptr->jmpbuf))
11189 {
11190 error:
11191 if (png_ptr)
11192 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
11193 xfree (pixels);
11194 xfree (rows);
11195 if (fp) fclose (fp);
11196 UNGCPRO;
11197 return 0;
11198 }
11199
11200 /* Read image info. */
11201 if (!NILP (specified_data))
11202 png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
11203 else
11204 png_init_io (png_ptr, fp);
11205
11206 png_set_sig_bytes (png_ptr, sizeof sig);
11207 png_read_info (png_ptr, info_ptr);
11208 png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
11209 &interlace_type, NULL, NULL);
11210
11211 /* If image contains simply transparency data, we prefer to
11212 construct a clipping mask. */
11213 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
11214 transparent_p = 1;
11215 else
11216 transparent_p = 0;
11217
11218 /* This function is easier to write if we only have to handle
11219 one data format: RGB or RGBA with 8 bits per channel. Let's
11220 transform other formats into that format. */
11221
11222 /* Strip more than 8 bits per channel. */
11223 if (bit_depth == 16)
11224 png_set_strip_16 (png_ptr);
11225
11226 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
11227 if available. */
11228 png_set_expand (png_ptr);
11229
11230 /* Convert grayscale images to RGB. */
11231 if (color_type == PNG_COLOR_TYPE_GRAY
11232 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
11233 png_set_gray_to_rgb (png_ptr);
11234
11235 /* The value 2.2 is a guess for PC monitors from PNG example.c. */
11236 gamma_str = getenv ("SCREEN_GAMMA");
11237 screen_gamma = gamma_str ? atof (gamma_str) : 2.2;
11238
11239 /* Tell the PNG lib to handle gamma correction for us. */
11240
11241 #if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
11242 if (png_get_sRGB (png_ptr, info_ptr, &intent))
11243 /* There is a special chunk in the image specifying the gamma. */
11244 png_set_sRGB (png_ptr, info_ptr, intent);
11245 else
11246 #endif
11247 if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
11248 /* Image contains gamma information. */
11249 png_set_gamma (png_ptr, screen_gamma, image_gamma);
11250 else
11251 /* Use a default of 0.5 for the image gamma. */
11252 png_set_gamma (png_ptr, screen_gamma, 0.5);
11253
11254 /* Handle alpha channel by combining the image with a background
11255 color. Do this only if a real alpha channel is supplied. For
11256 simple transparency, we prefer a clipping mask. */
11257 if (!transparent_p)
11258 {
11259 png_color_16 *image_background;
11260 Lisp_Object specified_bg
11261 = image_spec_value (img->spec, QCbackground, NULL);
11262
11263
11264 if (STRINGP (specified_bg))
11265 /* The user specified `:background', use that. */
11266 {
11267 COLORREF color;
11268 if (w32_defined_color (f, XSTRING (specified_bg)->data, &color, 0))
11269 {
11270 png_color_16 user_bg;
11271
11272 bzero (&user_bg, sizeof user_bg);
11273 user_bg.red = color.red;
11274 user_bg.green = color.green;
11275 user_bg.blue = color.blue;
11276
11277 png_set_background (png_ptr, &user_bg,
11278 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
11279 }
11280 }
11281 else if (png_get_bKGD (png_ptr, info_ptr, &image_background))
11282 /* Image contains a background color with which to
11283 combine the image. */
11284 png_set_background (png_ptr, image_background,
11285 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
11286 else
11287 {
11288 /* Image does not contain a background color with which
11289 to combine the image data via an alpha channel. Use
11290 the frame's background instead. */
11291 XColor color;
11292 Colormap cmap;
11293 png_color_16 frame_background;
11294
11295 cmap = FRAME_X_COLORMAP (f);
11296 color.pixel = FRAME_BACKGROUND_PIXEL (f);
11297 x_query_color (f, &color);
11298
11299 bzero (&frame_background, sizeof frame_background);
11300 frame_background.red = color.red;
11301 frame_background.green = color.green;
11302 frame_background.blue = color.blue;
11303
11304 png_set_background (png_ptr, &frame_background,
11305 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
11306 }
11307 }
11308
11309 /* Update info structure. */
11310 png_read_update_info (png_ptr, info_ptr);
11311
11312 /* Get number of channels. Valid values are 1 for grayscale images
11313 and images with a palette, 2 for grayscale images with transparency
11314 information (alpha channel), 3 for RGB images, and 4 for RGB
11315 images with alpha channel, i.e. RGBA. If conversions above were
11316 sufficient we should only have 3 or 4 channels here. */
11317 channels = png_get_channels (png_ptr, info_ptr);
11318 xassert (channels == 3 || channels == 4);
11319
11320 /* Number of bytes needed for one row of the image. */
11321 row_bytes = png_get_rowbytes (png_ptr, info_ptr);
11322
11323 /* Allocate memory for the image. */
11324 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
11325 rows = (png_byte **) xmalloc (height * sizeof *rows);
11326 for (i = 0; i < height; ++i)
11327 rows[i] = pixels + i * row_bytes;
11328
11329 /* Read the entire image. */
11330 png_read_image (png_ptr, rows);
11331 png_read_end (png_ptr, info_ptr);
11332 if (fp)
11333 {
11334 fclose (fp);
11335 fp = NULL;
11336 }
11337
11338 /* Create the X image and pixmap. */
11339 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
11340 &img->pixmap))
11341 goto error;
11342
11343 /* Create an image and pixmap serving as mask if the PNG image
11344 contains an alpha channel. */
11345 if (channels == 4
11346 && !transparent_p
11347 && !x_create_x_image_and_pixmap (f, width, height, 1,
11348 &mask_img, &img->mask))
11349 {
11350 x_destroy_x_image (ximg);
11351 XFreePixmap (FRAME_W32_DISPLAY (f), img->pixmap);
11352 img->pixmap = 0;
11353 goto error;
11354 }
11355
11356 /* Fill the X image and mask from PNG data. */
11357 init_color_table ();
11358
11359 for (y = 0; y < height; ++y)
11360 {
11361 png_byte *p = rows[y];
11362
11363 for (x = 0; x < width; ++x)
11364 {
11365 unsigned r, g, b;
11366
11367 r = *p++ << 8;
11368 g = *p++ << 8;
11369 b = *p++ << 8;
11370 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
11371
11372 /* An alpha channel, aka mask channel, associates variable
11373 transparency with an image. Where other image formats
11374 support binary transparency---fully transparent or fully
11375 opaque---PNG allows up to 254 levels of partial transparency.
11376 The PNG library implements partial transparency by combining
11377 the image with a specified background color.
11378
11379 I'm not sure how to handle this here nicely: because the
11380 background on which the image is displayed may change, for
11381 real alpha channel support, it would be necessary to create
11382 a new image for each possible background.
11383
11384 What I'm doing now is that a mask is created if we have
11385 boolean transparency information. Otherwise I'm using
11386 the frame's background color to combine the image with. */
11387
11388 if (channels == 4)
11389 {
11390 if (mask_img)
11391 XPutPixel (mask_img, x, y, *p > 0);
11392 ++p;
11393 }
11394 }
11395 }
11396
11397 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
11398 /* Set IMG's background color from the PNG image, unless the user
11399 overrode it. */
11400 {
11401 png_color_16 *bg;
11402 if (png_get_bKGD (png_ptr, info_ptr, &bg))
11403 {
11404 img->background = lookup_rgb_color (f, bg->red, bg->green, bg->blue);
11405 img->background_valid = 1;
11406 }
11407 }
11408
11409 /* Remember colors allocated for this image. */
11410 img->colors = colors_in_color_table (&img->ncolors);
11411 free_color_table ();
11412
11413 /* Clean up. */
11414 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
11415 xfree (rows);
11416 xfree (pixels);
11417
11418 img->width = width;
11419 img->height = height;
11420
11421 /* Maybe fill in the background field while we have ximg handy. */
11422 IMAGE_BACKGROUND (img, f, ximg);
11423
11424 /* Put the image into the pixmap, then free the X image and its buffer. */
11425 x_put_x_image (f, ximg, img->pixmap, width, height);
11426 x_destroy_x_image (ximg);
11427
11428 /* Same for the mask. */
11429 if (mask_img)
11430 {
11431 /* Fill in the background_transparent field while we have the mask
11432 handy. */
11433 image_background_transparent (img, f, mask_img);
11434
11435 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
11436 x_destroy_x_image (mask_img);
11437 }
11438
11439 UNGCPRO;
11440 return 1;
11441 }
11442
11443 #endif /* HAVE_PNG != 0 */
11444
11445
11446 \f
11447 /***********************************************************************
11448 JPEG
11449 ***********************************************************************/
11450
11451 #if HAVE_JPEG
11452
11453 /* Work around a warning about HAVE_STDLIB_H being redefined in
11454 jconfig.h. */
11455 #ifdef HAVE_STDLIB_H
11456 #define HAVE_STDLIB_H_1
11457 #undef HAVE_STDLIB_H
11458 #endif /* HAVE_STLIB_H */
11459
11460 #include <jpeglib.h>
11461 #include <jerror.h>
11462 #include <setjmp.h>
11463
11464 #ifdef HAVE_STLIB_H_1
11465 #define HAVE_STDLIB_H 1
11466 #endif
11467
11468 static int jpeg_image_p P_ ((Lisp_Object object));
11469 static int jpeg_load P_ ((struct frame *f, struct image *img));
11470
11471 /* The symbol `jpeg' identifying images of this type. */
11472
11473 Lisp_Object Qjpeg;
11474
11475 /* Indices of image specification fields in gs_format, below. */
11476
11477 enum jpeg_keyword_index
11478 {
11479 JPEG_TYPE,
11480 JPEG_DATA,
11481 JPEG_FILE,
11482 JPEG_ASCENT,
11483 JPEG_MARGIN,
11484 JPEG_RELIEF,
11485 JPEG_ALGORITHM,
11486 JPEG_HEURISTIC_MASK,
11487 JPEG_MASK,
11488 JPEG_BACKGROUND,
11489 JPEG_LAST
11490 };
11491
11492 /* Vector of image_keyword structures describing the format
11493 of valid user-defined image specifications. */
11494
11495 static struct image_keyword jpeg_format[JPEG_LAST] =
11496 {
11497 {":type", IMAGE_SYMBOL_VALUE, 1},
11498 {":data", IMAGE_STRING_VALUE, 0},
11499 {":file", IMAGE_STRING_VALUE, 0},
11500 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
11501 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
11502 {":relief", IMAGE_INTEGER_VALUE, 0},
11503 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11504 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11505 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11506 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
11507 };
11508
11509 /* Structure describing the image type `jpeg'. */
11510
11511 static struct image_type jpeg_type =
11512 {
11513 &Qjpeg,
11514 jpeg_image_p,
11515 jpeg_load,
11516 x_clear_image,
11517 NULL
11518 };
11519
11520
11521 /* Return non-zero if OBJECT is a valid JPEG image specification. */
11522
11523 static int
11524 jpeg_image_p (object)
11525 Lisp_Object object;
11526 {
11527 struct image_keyword fmt[JPEG_LAST];
11528
11529 bcopy (jpeg_format, fmt, sizeof fmt);
11530
11531 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg)
11532 || (fmt[JPEG_ASCENT].count
11533 && XFASTINT (fmt[JPEG_ASCENT].value) > 100))
11534 return 0;
11535
11536 /* Must specify either the :data or :file keyword. */
11537 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
11538 }
11539
11540
11541 struct my_jpeg_error_mgr
11542 {
11543 struct jpeg_error_mgr pub;
11544 jmp_buf setjmp_buffer;
11545 };
11546
11547 static void
11548 my_error_exit (cinfo)
11549 j_common_ptr cinfo;
11550 {
11551 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
11552 longjmp (mgr->setjmp_buffer, 1);
11553 }
11554
11555 /* Init source method for JPEG data source manager. Called by
11556 jpeg_read_header() before any data is actually read. See
11557 libjpeg.doc from the JPEG lib distribution. */
11558
11559 static void
11560 our_init_source (cinfo)
11561 j_decompress_ptr cinfo;
11562 {
11563 }
11564
11565
11566 /* Fill input buffer method for JPEG data source manager. Called
11567 whenever more data is needed. We read the whole image in one step,
11568 so this only adds a fake end of input marker at the end. */
11569
11570 static boolean
11571 our_fill_input_buffer (cinfo)
11572 j_decompress_ptr cinfo;
11573 {
11574 /* Insert a fake EOI marker. */
11575 struct jpeg_source_mgr *src = cinfo->src;
11576 static JOCTET buffer[2];
11577
11578 buffer[0] = (JOCTET) 0xFF;
11579 buffer[1] = (JOCTET) JPEG_EOI;
11580
11581 src->next_input_byte = buffer;
11582 src->bytes_in_buffer = 2;
11583 return TRUE;
11584 }
11585
11586
11587 /* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
11588 is the JPEG data source manager. */
11589
11590 static void
11591 our_skip_input_data (cinfo, num_bytes)
11592 j_decompress_ptr cinfo;
11593 long num_bytes;
11594 {
11595 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
11596
11597 if (src)
11598 {
11599 if (num_bytes > src->bytes_in_buffer)
11600 ERREXIT (cinfo, JERR_INPUT_EOF);
11601
11602 src->bytes_in_buffer -= num_bytes;
11603 src->next_input_byte += num_bytes;
11604 }
11605 }
11606
11607
11608 /* Method to terminate data source. Called by
11609 jpeg_finish_decompress() after all data has been processed. */
11610
11611 static void
11612 our_term_source (cinfo)
11613 j_decompress_ptr cinfo;
11614 {
11615 }
11616
11617
11618 /* Set up the JPEG lib for reading an image from DATA which contains
11619 LEN bytes. CINFO is the decompression info structure created for
11620 reading the image. */
11621
11622 static void
11623 jpeg_memory_src (cinfo, data, len)
11624 j_decompress_ptr cinfo;
11625 JOCTET *data;
11626 unsigned int len;
11627 {
11628 struct jpeg_source_mgr *src;
11629
11630 if (cinfo->src == NULL)
11631 {
11632 /* First time for this JPEG object? */
11633 cinfo->src = (struct jpeg_source_mgr *)
11634 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
11635 sizeof (struct jpeg_source_mgr));
11636 src = (struct jpeg_source_mgr *) cinfo->src;
11637 src->next_input_byte = data;
11638 }
11639
11640 src = (struct jpeg_source_mgr *) cinfo->src;
11641 src->init_source = our_init_source;
11642 src->fill_input_buffer = our_fill_input_buffer;
11643 src->skip_input_data = our_skip_input_data;
11644 src->resync_to_restart = jpeg_resync_to_restart; /* Use default method. */
11645 src->term_source = our_term_source;
11646 src->bytes_in_buffer = len;
11647 src->next_input_byte = data;
11648 }
11649
11650
11651 /* Load image IMG for use on frame F. Patterned after example.c
11652 from the JPEG lib. */
11653
11654 static int
11655 jpeg_load (f, img)
11656 struct frame *f;
11657 struct image *img;
11658 {
11659 struct jpeg_decompress_struct cinfo;
11660 struct my_jpeg_error_mgr mgr;
11661 Lisp_Object file, specified_file;
11662 Lisp_Object specified_data;
11663 FILE * volatile fp = NULL;
11664 JSAMPARRAY buffer;
11665 int row_stride, x, y;
11666 XImage *ximg = NULL;
11667 int rc;
11668 unsigned long *colors;
11669 int width, height;
11670 struct gcpro gcpro1;
11671
11672 /* Open the JPEG file. */
11673 specified_file = image_spec_value (img->spec, QCfile, NULL);
11674 specified_data = image_spec_value (img->spec, QCdata, NULL);
11675 file = Qnil;
11676 GCPRO1 (file);
11677
11678 if (NILP (specified_data))
11679 {
11680 file = x_find_image_file (specified_file);
11681 if (!STRINGP (file))
11682 {
11683 image_error ("Cannot find image file `%s'", specified_file, Qnil);
11684 UNGCPRO;
11685 return 0;
11686 }
11687
11688 fp = fopen (XSTRING (file)->data, "r");
11689 if (fp == NULL)
11690 {
11691 image_error ("Cannot open `%s'", file, Qnil);
11692 UNGCPRO;
11693 return 0;
11694 }
11695 }
11696
11697 /* Customize libjpeg's error handling to call my_error_exit when an
11698 error is detected. This function will perform a longjmp. */
11699 cinfo.err = jpeg_std_error (&mgr.pub);
11700 mgr.pub.error_exit = my_error_exit;
11701
11702 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
11703 {
11704 if (rc == 1)
11705 {
11706 /* Called from my_error_exit. Display a JPEG error. */
11707 char buffer[JMSG_LENGTH_MAX];
11708 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
11709 image_error ("Error reading JPEG image `%s': %s", img->spec,
11710 build_string (buffer));
11711 }
11712
11713 /* Close the input file and destroy the JPEG object. */
11714 if (fp)
11715 fclose (fp);
11716 jpeg_destroy_decompress (&cinfo);
11717
11718 /* If we already have an XImage, free that. */
11719 x_destroy_x_image (ximg);
11720
11721 /* Free pixmap and colors. */
11722 x_clear_image (f, img);
11723
11724 UNGCPRO;
11725 return 0;
11726 }
11727
11728 /* Create the JPEG decompression object. Let it read from fp.
11729 Read the JPEG image header. */
11730 jpeg_create_decompress (&cinfo);
11731
11732 if (NILP (specified_data))
11733 jpeg_stdio_src (&cinfo, fp);
11734 else
11735 jpeg_memory_src (&cinfo, XSTRING (specified_data)->data,
11736 STRING_BYTES (XSTRING (specified_data)));
11737
11738 jpeg_read_header (&cinfo, TRUE);
11739
11740 /* Customize decompression so that color quantization will be used.
11741 Start decompression. */
11742 cinfo.quantize_colors = TRUE;
11743 jpeg_start_decompress (&cinfo);
11744 width = img->width = cinfo.output_width;
11745 height = img->height = cinfo.output_height;
11746
11747 /* Create X image and pixmap. */
11748 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
11749 &img->pixmap))
11750 longjmp (mgr.setjmp_buffer, 2);
11751
11752 /* Allocate colors. When color quantization is used,
11753 cinfo.actual_number_of_colors has been set with the number of
11754 colors generated, and cinfo.colormap is a two-dimensional array
11755 of color indices in the range 0..cinfo.actual_number_of_colors.
11756 No more than 255 colors will be generated. */
11757 {
11758 int i, ir, ig, ib;
11759
11760 if (cinfo.out_color_components > 2)
11761 ir = 0, ig = 1, ib = 2;
11762 else if (cinfo.out_color_components > 1)
11763 ir = 0, ig = 1, ib = 0;
11764 else
11765 ir = 0, ig = 0, ib = 0;
11766
11767 /* Use the color table mechanism because it handles colors that
11768 cannot be allocated nicely. Such colors will be replaced with
11769 a default color, and we don't have to care about which colors
11770 can be freed safely, and which can't. */
11771 init_color_table ();
11772 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
11773 * sizeof *colors);
11774
11775 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
11776 {
11777 /* Multiply RGB values with 255 because X expects RGB values
11778 in the range 0..0xffff. */
11779 int r = cinfo.colormap[ir][i] << 8;
11780 int g = cinfo.colormap[ig][i] << 8;
11781 int b = cinfo.colormap[ib][i] << 8;
11782 colors[i] = lookup_rgb_color (f, r, g, b);
11783 }
11784
11785 /* Remember those colors actually allocated. */
11786 img->colors = colors_in_color_table (&img->ncolors);
11787 free_color_table ();
11788 }
11789
11790 /* Read pixels. */
11791 row_stride = width * cinfo.output_components;
11792 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
11793 row_stride, 1);
11794 for (y = 0; y < height; ++y)
11795 {
11796 jpeg_read_scanlines (&cinfo, buffer, 1);
11797 for (x = 0; x < cinfo.output_width; ++x)
11798 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
11799 }
11800
11801 /* Clean up. */
11802 jpeg_finish_decompress (&cinfo);
11803 jpeg_destroy_decompress (&cinfo);
11804 if (fp)
11805 fclose (fp);
11806
11807 /* Maybe fill in the background field while we have ximg handy. */
11808 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
11809 IMAGE_BACKGROUND (img, f, ximg);
11810
11811 /* Put the image into the pixmap. */
11812 x_put_x_image (f, ximg, img->pixmap, width, height);
11813 x_destroy_x_image (ximg);
11814 UNBLOCK_INPUT;
11815 UNGCPRO;
11816 return 1;
11817 }
11818
11819 #endif /* HAVE_JPEG */
11820
11821
11822 \f
11823 /***********************************************************************
11824 TIFF
11825 ***********************************************************************/
11826
11827 #if HAVE_TIFF
11828
11829 #include <tiffio.h>
11830
11831 static int tiff_image_p P_ ((Lisp_Object object));
11832 static int tiff_load P_ ((struct frame *f, struct image *img));
11833
11834 /* The symbol `tiff' identifying images of this type. */
11835
11836 Lisp_Object Qtiff;
11837
11838 /* Indices of image specification fields in tiff_format, below. */
11839
11840 enum tiff_keyword_index
11841 {
11842 TIFF_TYPE,
11843 TIFF_DATA,
11844 TIFF_FILE,
11845 TIFF_ASCENT,
11846 TIFF_MARGIN,
11847 TIFF_RELIEF,
11848 TIFF_ALGORITHM,
11849 TIFF_HEURISTIC_MASK,
11850 TIFF_MASK,
11851 TIFF_BACKGROUND,
11852 TIFF_LAST
11853 };
11854
11855 /* Vector of image_keyword structures describing the format
11856 of valid user-defined image specifications. */
11857
11858 static struct image_keyword tiff_format[TIFF_LAST] =
11859 {
11860 {":type", IMAGE_SYMBOL_VALUE, 1},
11861 {":data", IMAGE_STRING_VALUE, 0},
11862 {":file", IMAGE_STRING_VALUE, 0},
11863 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
11864 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
11865 {":relief", IMAGE_INTEGER_VALUE, 0},
11866 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11867 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11868 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11869 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
11870 };
11871
11872 /* Structure describing the image type `tiff'. */
11873
11874 static struct image_type tiff_type =
11875 {
11876 &Qtiff,
11877 tiff_image_p,
11878 tiff_load,
11879 x_clear_image,
11880 NULL
11881 };
11882
11883
11884 /* Return non-zero if OBJECT is a valid TIFF image specification. */
11885
11886 static int
11887 tiff_image_p (object)
11888 Lisp_Object object;
11889 {
11890 struct image_keyword fmt[TIFF_LAST];
11891 bcopy (tiff_format, fmt, sizeof fmt);
11892
11893 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff)
11894 || (fmt[TIFF_ASCENT].count
11895 && XFASTINT (fmt[TIFF_ASCENT].value) > 100))
11896 return 0;
11897
11898 /* Must specify either the :data or :file keyword. */
11899 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
11900 }
11901
11902
11903 /* Reading from a memory buffer for TIFF images Based on the PNG
11904 memory source, but we have to provide a lot of extra functions.
11905 Blah.
11906
11907 We really only need to implement read and seek, but I am not
11908 convinced that the TIFF library is smart enough not to destroy
11909 itself if we only hand it the function pointers we need to
11910 override. */
11911
11912 typedef struct
11913 {
11914 unsigned char *bytes;
11915 size_t len;
11916 int index;
11917 }
11918 tiff_memory_source;
11919
11920 static size_t
11921 tiff_read_from_memory (data, buf, size)
11922 thandle_t data;
11923 tdata_t buf;
11924 tsize_t size;
11925 {
11926 tiff_memory_source *src = (tiff_memory_source *) data;
11927
11928 if (size > src->len - src->index)
11929 return (size_t) -1;
11930 bcopy (src->bytes + src->index, buf, size);
11931 src->index += size;
11932 return size;
11933 }
11934
11935 static size_t
11936 tiff_write_from_memory (data, buf, size)
11937 thandle_t data;
11938 tdata_t buf;
11939 tsize_t size;
11940 {
11941 return (size_t) -1;
11942 }
11943
11944 static toff_t
11945 tiff_seek_in_memory (data, off, whence)
11946 thandle_t data;
11947 toff_t off;
11948 int whence;
11949 {
11950 tiff_memory_source *src = (tiff_memory_source *) data;
11951 int idx;
11952
11953 switch (whence)
11954 {
11955 case SEEK_SET: /* Go from beginning of source. */
11956 idx = off;
11957 break;
11958
11959 case SEEK_END: /* Go from end of source. */
11960 idx = src->len + off;
11961 break;
11962
11963 case SEEK_CUR: /* Go from current position. */
11964 idx = src->index + off;
11965 break;
11966
11967 default: /* Invalid `whence'. */
11968 return -1;
11969 }
11970
11971 if (idx > src->len || idx < 0)
11972 return -1;
11973
11974 src->index = idx;
11975 return src->index;
11976 }
11977
11978 static int
11979 tiff_close_memory (data)
11980 thandle_t data;
11981 {
11982 /* NOOP */
11983 return 0;
11984 }
11985
11986 static int
11987 tiff_mmap_memory (data, pbase, psize)
11988 thandle_t data;
11989 tdata_t *pbase;
11990 toff_t *psize;
11991 {
11992 /* It is already _IN_ memory. */
11993 return 0;
11994 }
11995
11996 static void
11997 tiff_unmap_memory (data, base, size)
11998 thandle_t data;
11999 tdata_t base;
12000 toff_t size;
12001 {
12002 /* We don't need to do this. */
12003 }
12004
12005 static toff_t
12006 tiff_size_of_memory (data)
12007 thandle_t data;
12008 {
12009 return ((tiff_memory_source *) data)->len;
12010 }
12011
12012
12013 static void
12014 tiff_error_handler (title, format, ap)
12015 const char *title, *format;
12016 va_list ap;
12017 {
12018 char buf[512];
12019 int len;
12020
12021 len = sprintf (buf, "TIFF error: %s ", title);
12022 vsprintf (buf + len, format, ap);
12023 add_to_log (buf, Qnil, Qnil);
12024 }
12025
12026
12027 static void
12028 tiff_warning_handler (title, format, ap)
12029 const char *title, *format;
12030 va_list ap;
12031 {
12032 char buf[512];
12033 int len;
12034
12035 len = sprintf (buf, "TIFF warning: %s ", title);
12036 vsprintf (buf + len, format, ap);
12037 add_to_log (buf, Qnil, Qnil);
12038 }
12039
12040
12041 /* Load TIFF image IMG for use on frame F. Value is non-zero if
12042 successful. */
12043
12044 static int
12045 tiff_load (f, img)
12046 struct frame *f;
12047 struct image *img;
12048 {
12049 Lisp_Object file, specified_file;
12050 Lisp_Object specified_data;
12051 TIFF *tiff;
12052 int width, height, x, y;
12053 uint32 *buf;
12054 int rc;
12055 XImage *ximg;
12056 struct gcpro gcpro1;
12057 tiff_memory_source memsrc;
12058
12059 specified_file = image_spec_value (img->spec, QCfile, NULL);
12060 specified_data = image_spec_value (img->spec, QCdata, NULL);
12061 file = Qnil;
12062 GCPRO1 (file);
12063
12064 TIFFSetErrorHandler (tiff_error_handler);
12065 TIFFSetWarningHandler (tiff_warning_handler);
12066
12067 if (NILP (specified_data))
12068 {
12069 /* Read from a file */
12070 file = x_find_image_file (specified_file);
12071 if (!STRINGP (file))
12072 {
12073 image_error ("Cannot find image file `%s'", file, Qnil);
12074 UNGCPRO;
12075 return 0;
12076 }
12077
12078 /* Try to open the image file. */
12079 tiff = TIFFOpen (XSTRING (file)->data, "r");
12080 if (tiff == NULL)
12081 {
12082 image_error ("Cannot open `%s'", file, Qnil);
12083 UNGCPRO;
12084 return 0;
12085 }
12086 }
12087 else
12088 {
12089 /* Memory source! */
12090 memsrc.bytes = XSTRING (specified_data)->data;
12091 memsrc.len = STRING_BYTES (XSTRING (specified_data));
12092 memsrc.index = 0;
12093
12094 tiff = TIFFClientOpen ("memory_source", "r", &memsrc,
12095 (TIFFReadWriteProc) tiff_read_from_memory,
12096 (TIFFReadWriteProc) tiff_write_from_memory,
12097 tiff_seek_in_memory,
12098 tiff_close_memory,
12099 tiff_size_of_memory,
12100 tiff_mmap_memory,
12101 tiff_unmap_memory);
12102
12103 if (!tiff)
12104 {
12105 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
12106 UNGCPRO;
12107 return 0;
12108 }
12109 }
12110
12111 /* Get width and height of the image, and allocate a raster buffer
12112 of width x height 32-bit values. */
12113 TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
12114 TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
12115 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
12116
12117 rc = TIFFReadRGBAImage (tiff, width, height, buf, 0);
12118 TIFFClose (tiff);
12119 if (!rc)
12120 {
12121 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
12122 xfree (buf);
12123 UNGCPRO;
12124 return 0;
12125 }
12126
12127 /* Create the X image and pixmap. */
12128 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
12129 {
12130 xfree (buf);
12131 UNGCPRO;
12132 return 0;
12133 }
12134
12135 /* Initialize the color table. */
12136 init_color_table ();
12137
12138 /* Process the pixel raster. Origin is in the lower-left corner. */
12139 for (y = 0; y < height; ++y)
12140 {
12141 uint32 *row = buf + y * width;
12142
12143 for (x = 0; x < width; ++x)
12144 {
12145 uint32 abgr = row[x];
12146 int r = TIFFGetR (abgr) << 8;
12147 int g = TIFFGetG (abgr) << 8;
12148 int b = TIFFGetB (abgr) << 8;
12149 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
12150 }
12151 }
12152
12153 /* Remember the colors allocated for the image. Free the color table. */
12154 img->colors = colors_in_color_table (&img->ncolors);
12155 free_color_table ();
12156
12157 img->width = width;
12158 img->height = height;
12159
12160 /* Maybe fill in the background field while we have ximg handy. */
12161 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
12162 IMAGE_BACKGROUND (img, f, ximg);
12163
12164 /* Put the image into the pixmap, then free the X image and its buffer. */
12165 x_put_x_image (f, ximg, img->pixmap, width, height);
12166 x_destroy_x_image (ximg);
12167 xfree (buf);
12168
12169 UNGCPRO;
12170 return 1;
12171 }
12172
12173 #endif /* HAVE_TIFF != 0 */
12174
12175
12176 \f
12177 /***********************************************************************
12178 GIF
12179 ***********************************************************************/
12180
12181 #if HAVE_GIF
12182
12183 #include <gif_lib.h>
12184
12185 static int gif_image_p P_ ((Lisp_Object object));
12186 static int gif_load P_ ((struct frame *f, struct image *img));
12187
12188 /* The symbol `gif' identifying images of this type. */
12189
12190 Lisp_Object Qgif;
12191
12192 /* Indices of image specification fields in gif_format, below. */
12193
12194 enum gif_keyword_index
12195 {
12196 GIF_TYPE,
12197 GIF_DATA,
12198 GIF_FILE,
12199 GIF_ASCENT,
12200 GIF_MARGIN,
12201 GIF_RELIEF,
12202 GIF_ALGORITHM,
12203 GIF_HEURISTIC_MASK,
12204 GIF_MASK,
12205 GIF_IMAGE,
12206 GIF_BACKGROUND,
12207 GIF_LAST
12208 };
12209
12210 /* Vector of image_keyword structures describing the format
12211 of valid user-defined image specifications. */
12212
12213 static struct image_keyword gif_format[GIF_LAST] =
12214 {
12215 {":type", IMAGE_SYMBOL_VALUE, 1},
12216 {":data", IMAGE_STRING_VALUE, 0},
12217 {":file", IMAGE_STRING_VALUE, 0},
12218 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
12219 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
12220 {":relief", IMAGE_INTEGER_VALUE, 0},
12221 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12222 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12223 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12224 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
12225 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
12226 };
12227
12228 /* Structure describing the image type `gif'. */
12229
12230 static struct image_type gif_type =
12231 {
12232 &Qgif,
12233 gif_image_p,
12234 gif_load,
12235 x_clear_image,
12236 NULL
12237 };
12238
12239 /* Return non-zero if OBJECT is a valid GIF image specification. */
12240
12241 static int
12242 gif_image_p (object)
12243 Lisp_Object object;
12244 {
12245 struct image_keyword fmt[GIF_LAST];
12246 bcopy (gif_format, fmt, sizeof fmt);
12247
12248 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif)
12249 || (fmt[GIF_ASCENT].count
12250 && XFASTINT (fmt[GIF_ASCENT].value) > 100))
12251 return 0;
12252
12253 /* Must specify either the :data or :file keyword. */
12254 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
12255 }
12256
12257 /* Reading a GIF image from memory
12258 Based on the PNG memory stuff to a certain extent. */
12259
12260 typedef struct
12261 {
12262 unsigned char *bytes;
12263 size_t len;
12264 int index;
12265 }
12266 gif_memory_source;
12267
12268 /* Make the current memory source available to gif_read_from_memory.
12269 It's done this way because not all versions of libungif support
12270 a UserData field in the GifFileType structure. */
12271 static gif_memory_source *current_gif_memory_src;
12272
12273 static int
12274 gif_read_from_memory (file, buf, len)
12275 GifFileType *file;
12276 GifByteType *buf;
12277 int len;
12278 {
12279 gif_memory_source *src = current_gif_memory_src;
12280
12281 if (len > src->len - src->index)
12282 return -1;
12283
12284 bcopy (src->bytes + src->index, buf, len);
12285 src->index += len;
12286 return len;
12287 }
12288
12289
12290 /* Load GIF image IMG for use on frame F. Value is non-zero if
12291 successful. */
12292
12293 static int
12294 gif_load (f, img)
12295 struct frame *f;
12296 struct image *img;
12297 {
12298 Lisp_Object file, specified_file;
12299 Lisp_Object specified_data;
12300 int rc, width, height, x, y, i;
12301 XImage *ximg;
12302 ColorMapObject *gif_color_map;
12303 unsigned long pixel_colors[256];
12304 GifFileType *gif;
12305 struct gcpro gcpro1;
12306 Lisp_Object image;
12307 int ino, image_left, image_top, image_width, image_height;
12308 gif_memory_source memsrc;
12309 unsigned char *raster;
12310
12311 specified_file = image_spec_value (img->spec, QCfile, NULL);
12312 specified_data = image_spec_value (img->spec, QCdata, NULL);
12313 file = Qnil;
12314 GCPRO1 (file);
12315
12316 if (NILP (specified_data))
12317 {
12318 file = x_find_image_file (specified_file);
12319 if (!STRINGP (file))
12320 {
12321 image_error ("Cannot find image file `%s'", specified_file, Qnil);
12322 UNGCPRO;
12323 return 0;
12324 }
12325
12326 /* Open the GIF file. */
12327 gif = DGifOpenFileName (XSTRING (file)->data);
12328 if (gif == NULL)
12329 {
12330 image_error ("Cannot open `%s'", file, Qnil);
12331 UNGCPRO;
12332 return 0;
12333 }
12334 }
12335 else
12336 {
12337 /* Read from memory! */
12338 current_gif_memory_src = &memsrc;
12339 memsrc.bytes = XSTRING (specified_data)->data;
12340 memsrc.len = STRING_BYTES (XSTRING (specified_data));
12341 memsrc.index = 0;
12342
12343 gif = DGifOpen(&memsrc, gif_read_from_memory);
12344 if (!gif)
12345 {
12346 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
12347 UNGCPRO;
12348 return 0;
12349 }
12350 }
12351
12352 /* Read entire contents. */
12353 rc = DGifSlurp (gif);
12354 if (rc == GIF_ERROR)
12355 {
12356 image_error ("Error reading `%s'", img->spec, Qnil);
12357 DGifCloseFile (gif);
12358 UNGCPRO;
12359 return 0;
12360 }
12361
12362 image = image_spec_value (img->spec, QCindex, NULL);
12363 ino = INTEGERP (image) ? XFASTINT (image) : 0;
12364 if (ino >= gif->ImageCount)
12365 {
12366 image_error ("Invalid image number `%s' in image `%s'",
12367 image, img->spec);
12368 DGifCloseFile (gif);
12369 UNGCPRO;
12370 return 0;
12371 }
12372
12373 width = img->width = gif->SWidth;
12374 height = img->height = gif->SHeight;
12375
12376 /* Create the X image and pixmap. */
12377 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
12378 {
12379 DGifCloseFile (gif);
12380 UNGCPRO;
12381 return 0;
12382 }
12383
12384 /* Allocate colors. */
12385 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
12386 if (!gif_color_map)
12387 gif_color_map = gif->SColorMap;
12388 init_color_table ();
12389 bzero (pixel_colors, sizeof pixel_colors);
12390
12391 for (i = 0; i < gif_color_map->ColorCount; ++i)
12392 {
12393 int r = gif_color_map->Colors[i].Red << 8;
12394 int g = gif_color_map->Colors[i].Green << 8;
12395 int b = gif_color_map->Colors[i].Blue << 8;
12396 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
12397 }
12398
12399 img->colors = colors_in_color_table (&img->ncolors);
12400 free_color_table ();
12401
12402 /* Clear the part of the screen image that are not covered by
12403 the image from the GIF file. Full animated GIF support
12404 requires more than can be done here (see the gif89 spec,
12405 disposal methods). Let's simply assume that the part
12406 not covered by a sub-image is in the frame's background color. */
12407 image_top = gif->SavedImages[ino].ImageDesc.Top;
12408 image_left = gif->SavedImages[ino].ImageDesc.Left;
12409 image_width = gif->SavedImages[ino].ImageDesc.Width;
12410 image_height = gif->SavedImages[ino].ImageDesc.Height;
12411
12412 for (y = 0; y < image_top; ++y)
12413 for (x = 0; x < width; ++x)
12414 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12415
12416 for (y = image_top + image_height; y < height; ++y)
12417 for (x = 0; x < width; ++x)
12418 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12419
12420 for (y = image_top; y < image_top + image_height; ++y)
12421 {
12422 for (x = 0; x < image_left; ++x)
12423 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12424 for (x = image_left + image_width; x < width; ++x)
12425 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12426 }
12427
12428 /* Read the GIF image into the X image. We use a local variable
12429 `raster' here because RasterBits below is a char *, and invites
12430 problems with bytes >= 0x80. */
12431 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
12432
12433 if (gif->SavedImages[ino].ImageDesc.Interlace)
12434 {
12435 static int interlace_start[] = {0, 4, 2, 1};
12436 static int interlace_increment[] = {8, 8, 4, 2};
12437 int pass;
12438 int row = interlace_start[0];
12439
12440 pass = 0;
12441
12442 for (y = 0; y < image_height; y++)
12443 {
12444 if (row >= image_height)
12445 {
12446 row = interlace_start[++pass];
12447 while (row >= image_height)
12448 row = interlace_start[++pass];
12449 }
12450
12451 for (x = 0; x < image_width; x++)
12452 {
12453 int i = raster[(y * image_width) + x];
12454 XPutPixel (ximg, x + image_left, row + image_top,
12455 pixel_colors[i]);
12456 }
12457
12458 row += interlace_increment[pass];
12459 }
12460 }
12461 else
12462 {
12463 for (y = 0; y < image_height; ++y)
12464 for (x = 0; x < image_width; ++x)
12465 {
12466 int i = raster[y* image_width + x];
12467 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
12468 }
12469 }
12470
12471 DGifCloseFile (gif);
12472
12473 /* Maybe fill in the background field while we have ximg handy. */
12474 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
12475 IMAGE_BACKGROUND (img, f, ximg);
12476
12477 /* Put the image into the pixmap, then free the X image and its buffer. */
12478 x_put_x_image (f, ximg, img->pixmap, width, height);
12479 x_destroy_x_image (ximg);
12480
12481 UNGCPRO;
12482 return 1;
12483 }
12484
12485 #endif /* HAVE_GIF != 0 */
12486
12487
12488 \f
12489 /***********************************************************************
12490 Ghostscript
12491 ***********************************************************************/
12492
12493 Lisp_Object Qpostscript;
12494
12495 #ifdef HAVE_GHOSTSCRIPT
12496 static int gs_image_p P_ ((Lisp_Object object));
12497 static int gs_load P_ ((struct frame *f, struct image *img));
12498 static void gs_clear_image P_ ((struct frame *f, struct image *img));
12499
12500 /* The symbol `postscript' identifying images of this type. */
12501
12502 /* Keyword symbols. */
12503
12504 Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
12505
12506 /* Indices of image specification fields in gs_format, below. */
12507
12508 enum gs_keyword_index
12509 {
12510 GS_TYPE,
12511 GS_PT_WIDTH,
12512 GS_PT_HEIGHT,
12513 GS_FILE,
12514 GS_LOADER,
12515 GS_BOUNDING_BOX,
12516 GS_ASCENT,
12517 GS_MARGIN,
12518 GS_RELIEF,
12519 GS_ALGORITHM,
12520 GS_HEURISTIC_MASK,
12521 GS_MASK,
12522 GS_BACKGROUND,
12523 GS_LAST
12524 };
12525
12526 /* Vector of image_keyword structures describing the format
12527 of valid user-defined image specifications. */
12528
12529 static struct image_keyword gs_format[GS_LAST] =
12530 {
12531 {":type", IMAGE_SYMBOL_VALUE, 1},
12532 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
12533 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
12534 {":file", IMAGE_STRING_VALUE, 1},
12535 {":loader", IMAGE_FUNCTION_VALUE, 0},
12536 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
12537 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
12538 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
12539 {":relief", IMAGE_INTEGER_VALUE, 0},
12540 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12541 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12542 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12543 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
12544 };
12545
12546 /* Structure describing the image type `ghostscript'. */
12547
12548 static struct image_type gs_type =
12549 {
12550 &Qpostscript,
12551 gs_image_p,
12552 gs_load,
12553 gs_clear_image,
12554 NULL
12555 };
12556
12557
12558 /* Free X resources of Ghostscript image IMG which is used on frame F. */
12559
12560 static void
12561 gs_clear_image (f, img)
12562 struct frame *f;
12563 struct image *img;
12564 {
12565 /* IMG->data.ptr_val may contain a recorded colormap. */
12566 xfree (img->data.ptr_val);
12567 x_clear_image (f, img);
12568 }
12569
12570
12571 /* Return non-zero if OBJECT is a valid Ghostscript image
12572 specification. */
12573
12574 static int
12575 gs_image_p (object)
12576 Lisp_Object object;
12577 {
12578 struct image_keyword fmt[GS_LAST];
12579 Lisp_Object tem;
12580 int i;
12581
12582 bcopy (gs_format, fmt, sizeof fmt);
12583
12584 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript)
12585 || (fmt[GS_ASCENT].count
12586 && XFASTINT (fmt[GS_ASCENT].value) > 100))
12587 return 0;
12588
12589 /* Bounding box must be a list or vector containing 4 integers. */
12590 tem = fmt[GS_BOUNDING_BOX].value;
12591 if (CONSP (tem))
12592 {
12593 for (i = 0; i < 4; ++i, tem = XCDR (tem))
12594 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
12595 return 0;
12596 if (!NILP (tem))
12597 return 0;
12598 }
12599 else if (VECTORP (tem))
12600 {
12601 if (XVECTOR (tem)->size != 4)
12602 return 0;
12603 for (i = 0; i < 4; ++i)
12604 if (!INTEGERP (XVECTOR (tem)->contents[i]))
12605 return 0;
12606 }
12607 else
12608 return 0;
12609
12610 return 1;
12611 }
12612
12613
12614 /* Load Ghostscript image IMG for use on frame F. Value is non-zero
12615 if successful. */
12616
12617 static int
12618 gs_load (f, img)
12619 struct frame *f;
12620 struct image *img;
12621 {
12622 char buffer[100];
12623 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
12624 struct gcpro gcpro1, gcpro2;
12625 Lisp_Object frame;
12626 double in_width, in_height;
12627 Lisp_Object pixel_colors = Qnil;
12628
12629 /* Compute pixel size of pixmap needed from the given size in the
12630 image specification. Sizes in the specification are in pt. 1 pt
12631 = 1/72 in, xdpi and ydpi are stored in the frame's X display
12632 info. */
12633 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
12634 in_width = XFASTINT (pt_width) / 72.0;
12635 img->width = in_width * FRAME_W32_DISPLAY_INFO (f)->resx;
12636 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
12637 in_height = XFASTINT (pt_height) / 72.0;
12638 img->height = in_height * FRAME_W32_DISPLAY_INFO (f)->resy;
12639
12640 /* Create the pixmap. */
12641 BLOCK_INPUT;
12642 xassert (img->pixmap == 0);
12643 img->pixmap = XCreatePixmap (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
12644 img->width, img->height,
12645 one_w32_display_info.n_cbits);
12646 UNBLOCK_INPUT;
12647
12648 if (!img->pixmap)
12649 {
12650 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
12651 return 0;
12652 }
12653
12654 /* Call the loader to fill the pixmap. It returns a process object
12655 if successful. We do not record_unwind_protect here because
12656 other places in redisplay like calling window scroll functions
12657 don't either. Let the Lisp loader use `unwind-protect' instead. */
12658 GCPRO2 (window_and_pixmap_id, pixel_colors);
12659
12660 sprintf (buffer, "%lu %lu",
12661 (unsigned long) FRAME_W32_WINDOW (f),
12662 (unsigned long) img->pixmap);
12663 window_and_pixmap_id = build_string (buffer);
12664
12665 sprintf (buffer, "%lu %lu",
12666 FRAME_FOREGROUND_PIXEL (f),
12667 FRAME_BACKGROUND_PIXEL (f));
12668 pixel_colors = build_string (buffer);
12669
12670 XSETFRAME (frame, f);
12671 loader = image_spec_value (img->spec, QCloader, NULL);
12672 if (NILP (loader))
12673 loader = intern ("gs-load-image");
12674
12675 img->data.lisp_val = call6 (loader, frame, img->spec,
12676 make_number (img->width),
12677 make_number (img->height),
12678 window_and_pixmap_id,
12679 pixel_colors);
12680 UNGCPRO;
12681 return PROCESSP (img->data.lisp_val);
12682 }
12683
12684
12685 /* Kill the Ghostscript process that was started to fill PIXMAP on
12686 frame F. Called from XTread_socket when receiving an event
12687 telling Emacs that Ghostscript has finished drawing. */
12688
12689 void
12690 x_kill_gs_process (pixmap, f)
12691 Pixmap pixmap;
12692 struct frame *f;
12693 {
12694 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
12695 int class, i;
12696 struct image *img;
12697
12698 /* Find the image containing PIXMAP. */
12699 for (i = 0; i < c->used; ++i)
12700 if (c->images[i]->pixmap == pixmap)
12701 break;
12702
12703 /* Should someone in between have cleared the image cache, for
12704 instance, give up. */
12705 if (i == c->used)
12706 return;
12707
12708 /* Kill the GS process. We should have found PIXMAP in the image
12709 cache and its image should contain a process object. */
12710 img = c->images[i];
12711 xassert (PROCESSP (img->data.lisp_val));
12712 Fkill_process (img->data.lisp_val, Qnil);
12713 img->data.lisp_val = Qnil;
12714
12715 /* On displays with a mutable colormap, figure out the colors
12716 allocated for the image by looking at the pixels of an XImage for
12717 img->pixmap. */
12718 class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
12719 if (class != StaticColor && class != StaticGray && class != TrueColor)
12720 {
12721 XImage *ximg;
12722
12723 BLOCK_INPUT;
12724
12725 /* Try to get an XImage for img->pixmep. */
12726 ximg = XGetImage (FRAME_W32_DISPLAY (f), img->pixmap,
12727 0, 0, img->width, img->height, ~0, ZPixmap);
12728 if (ximg)
12729 {
12730 int x, y;
12731
12732 /* Initialize the color table. */
12733 init_color_table ();
12734
12735 /* For each pixel of the image, look its color up in the
12736 color table. After having done so, the color table will
12737 contain an entry for each color used by the image. */
12738 for (y = 0; y < img->height; ++y)
12739 for (x = 0; x < img->width; ++x)
12740 {
12741 unsigned long pixel = XGetPixel (ximg, x, y);
12742 lookup_pixel_color (f, pixel);
12743 }
12744
12745 /* Record colors in the image. Free color table and XImage. */
12746 img->colors = colors_in_color_table (&img->ncolors);
12747 free_color_table ();
12748 XDestroyImage (ximg);
12749
12750 #if 0 /* This doesn't seem to be the case. If we free the colors
12751 here, we get a BadAccess later in x_clear_image when
12752 freeing the colors. */
12753 /* We have allocated colors once, but Ghostscript has also
12754 allocated colors on behalf of us. So, to get the
12755 reference counts right, free them once. */
12756 if (img->ncolors)
12757 x_free_colors (FRAME_W32_DISPLAY (f), cmap,
12758 img->colors, img->ncolors, 0);
12759 #endif
12760 }
12761 else
12762 image_error ("Cannot get X image of `%s'; colors will not be freed",
12763 img->spec, Qnil);
12764
12765 UNBLOCK_INPUT;
12766 }
12767
12768 /* Now that we have the pixmap, compute mask and transform the
12769 image if requested. */
12770 BLOCK_INPUT;
12771 postprocess_image (f, img);
12772 UNBLOCK_INPUT;
12773 }
12774
12775 #endif /* HAVE_GHOSTSCRIPT */
12776
12777 \f
12778 /***********************************************************************
12779 Window properties
12780 ***********************************************************************/
12781
12782 DEFUN ("x-change-window-property", Fx_change_window_property,
12783 Sx_change_window_property, 2, 3, 0,
12784 doc: /* Change window property PROP to VALUE on the X window of FRAME.
12785 PROP and VALUE must be strings. FRAME nil or omitted means use the
12786 selected frame. Value is VALUE. */)
12787 (prop, value, frame)
12788 Lisp_Object frame, prop, value;
12789 {
12790 #if 0 /* TODO : port window properties to W32 */
12791 struct frame *f = check_x_frame (frame);
12792 Atom prop_atom;
12793
12794 CHECK_STRING (prop);
12795 CHECK_STRING (value);
12796
12797 BLOCK_INPUT;
12798 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
12799 XChangeProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
12800 prop_atom, XA_STRING, 8, PropModeReplace,
12801 XSTRING (value)->data, XSTRING (value)->size);
12802
12803 /* Make sure the property is set when we return. */
12804 XFlush (FRAME_W32_DISPLAY (f));
12805 UNBLOCK_INPUT;
12806
12807 #endif /* TODO */
12808
12809 return value;
12810 }
12811
12812
12813 DEFUN ("x-delete-window-property", Fx_delete_window_property,
12814 Sx_delete_window_property, 1, 2, 0,
12815 doc: /* Remove window property PROP from X window of FRAME.
12816 FRAME nil or omitted means use the selected frame. Value is PROP. */)
12817 (prop, frame)
12818 Lisp_Object prop, frame;
12819 {
12820 #if 0 /* TODO : port window properties to W32 */
12821
12822 struct frame *f = check_x_frame (frame);
12823 Atom prop_atom;
12824
12825 CHECK_STRING (prop);
12826 BLOCK_INPUT;
12827 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
12828 XDeleteProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), prop_atom);
12829
12830 /* Make sure the property is removed when we return. */
12831 XFlush (FRAME_W32_DISPLAY (f));
12832 UNBLOCK_INPUT;
12833 #endif /* TODO */
12834
12835 return prop;
12836 }
12837
12838
12839 DEFUN ("x-window-property", Fx_window_property, Sx_window_property,
12840 1, 2, 0,
12841 doc: /* Value is the value of window property PROP on FRAME.
12842 If FRAME is nil or omitted, use the selected frame. Value is nil
12843 if FRAME hasn't a property with name PROP or if PROP has no string
12844 value. */)
12845 (prop, frame)
12846 Lisp_Object prop, frame;
12847 {
12848 #if 0 /* TODO : port window properties to W32 */
12849
12850 struct frame *f = check_x_frame (frame);
12851 Atom prop_atom;
12852 int rc;
12853 Lisp_Object prop_value = Qnil;
12854 char *tmp_data = NULL;
12855 Atom actual_type;
12856 int actual_format;
12857 unsigned long actual_size, bytes_remaining;
12858
12859 CHECK_STRING (prop);
12860 BLOCK_INPUT;
12861 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
12862 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
12863 prop_atom, 0, 0, False, XA_STRING,
12864 &actual_type, &actual_format, &actual_size,
12865 &bytes_remaining, (unsigned char **) &tmp_data);
12866 if (rc == Success)
12867 {
12868 int size = bytes_remaining;
12869
12870 XFree (tmp_data);
12871 tmp_data = NULL;
12872
12873 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
12874 prop_atom, 0, bytes_remaining,
12875 False, XA_STRING,
12876 &actual_type, &actual_format,
12877 &actual_size, &bytes_remaining,
12878 (unsigned char **) &tmp_data);
12879 if (rc == Success)
12880 prop_value = make_string (tmp_data, size);
12881
12882 XFree (tmp_data);
12883 }
12884
12885 UNBLOCK_INPUT;
12886
12887 return prop_value;
12888
12889 #endif /* TODO */
12890 return Qnil;
12891 }
12892
12893
12894 \f
12895 /***********************************************************************
12896 Busy cursor
12897 ***********************************************************************/
12898
12899 /* If non-null, an asynchronous timer that, when it expires, displays
12900 an hourglass cursor on all frames. */
12901
12902 static struct atimer *hourglass_atimer;
12903
12904 /* Non-zero means an hourglass cursor is currently shown. */
12905
12906 static int hourglass_shown_p;
12907
12908 /* Number of seconds to wait before displaying an hourglass cursor. */
12909
12910 static Lisp_Object Vhourglass_delay;
12911
12912 /* Default number of seconds to wait before displaying an hourglass
12913 cursor. */
12914
12915 #define DEFAULT_HOURGLASS_DELAY 1
12916
12917 /* Function prototypes. */
12918
12919 static void show_hourglass P_ ((struct atimer *));
12920 static void hide_hourglass P_ ((void));
12921
12922
12923 /* Cancel a currently active hourglass timer, and start a new one. */
12924
12925 void
12926 start_hourglass ()
12927 {
12928 #if 0 /* TODO: cursor shape changes. */
12929 EMACS_TIME delay;
12930 int secs, usecs = 0;
12931
12932 cancel_hourglass ();
12933
12934 if (INTEGERP (Vhourglass_delay)
12935 && XINT (Vhourglass_delay) > 0)
12936 secs = XFASTINT (Vhourglass_delay);
12937 else if (FLOATP (Vhourglass_delay)
12938 && XFLOAT_DATA (Vhourglass_delay) > 0)
12939 {
12940 Lisp_Object tem;
12941 tem = Ftruncate (Vhourglass_delay, Qnil);
12942 secs = XFASTINT (tem);
12943 usecs = (XFLOAT_DATA (Vhourglass_delay) - secs) * 1000000;
12944 }
12945 else
12946 secs = DEFAULT_HOURGLASS_DELAY;
12947
12948 EMACS_SET_SECS_USECS (delay, secs, usecs);
12949 hourglass_atimer = start_atimer (ATIMER_RELATIVE, delay,
12950 show_hourglass, NULL);
12951 #endif
12952 }
12953
12954
12955 /* Cancel the hourglass cursor timer if active, hide an hourglass
12956 cursor if shown. */
12957
12958 void
12959 cancel_hourglass ()
12960 {
12961 if (hourglass_atimer)
12962 {
12963 cancel_atimer (hourglass_atimer);
12964 hourglass_atimer = NULL;
12965 }
12966
12967 if (hourglass_shown_p)
12968 hide_hourglass ();
12969 }
12970
12971
12972 /* Timer function of hourglass_atimer. TIMER is equal to
12973 hourglass_atimer.
12974
12975 Display an hourglass cursor on all frames by mapping the frames'
12976 hourglass_window. Set the hourglass_p flag in the frames'
12977 output_data.x structure to indicate that an hourglass cursor is
12978 shown on the frames. */
12979
12980 static void
12981 show_hourglass (timer)
12982 struct atimer *timer;
12983 {
12984 #if 0 /* TODO: cursor shape changes. */
12985 /* The timer implementation will cancel this timer automatically
12986 after this function has run. Set hourglass_atimer to null
12987 so that we know the timer doesn't have to be canceled. */
12988 hourglass_atimer = NULL;
12989
12990 if (!hourglass_shown_p)
12991 {
12992 Lisp_Object rest, frame;
12993
12994 BLOCK_INPUT;
12995
12996 FOR_EACH_FRAME (rest, frame)
12997 if (FRAME_W32_P (XFRAME (frame)))
12998 {
12999 struct frame *f = XFRAME (frame);
13000
13001 f->output_data.w32->hourglass_p = 1;
13002
13003 if (!f->output_data.w32->hourglass_window)
13004 {
13005 unsigned long mask = CWCursor;
13006 XSetWindowAttributes attrs;
13007
13008 attrs.cursor = f->output_data.w32->hourglass_cursor;
13009
13010 f->output_data.w32->hourglass_window
13011 = XCreateWindow (FRAME_X_DISPLAY (f),
13012 FRAME_OUTER_WINDOW (f),
13013 0, 0, 32000, 32000, 0, 0,
13014 InputOnly,
13015 CopyFromParent,
13016 mask, &attrs);
13017 }
13018
13019 XMapRaised (FRAME_X_DISPLAY (f),
13020 f->output_data.w32->hourglass_window);
13021 XFlush (FRAME_X_DISPLAY (f));
13022 }
13023
13024 hourglass_shown_p = 1;
13025 UNBLOCK_INPUT;
13026 }
13027 #endif
13028 }
13029
13030
13031 /* Hide the hourglass cursor on all frames, if it is currently shown. */
13032
13033 static void
13034 hide_hourglass ()
13035 {
13036 #if 0 /* TODO: cursor shape changes. */
13037 if (hourglass_shown_p)
13038 {
13039 Lisp_Object rest, frame;
13040
13041 BLOCK_INPUT;
13042 FOR_EACH_FRAME (rest, frame)
13043 {
13044 struct frame *f = XFRAME (frame);
13045
13046 if (FRAME_W32_P (f)
13047 /* Watch out for newly created frames. */
13048 && f->output_data.x->hourglass_window)
13049 {
13050 XUnmapWindow (FRAME_X_DISPLAY (f),
13051 f->output_data.x->hourglass_window);
13052 /* Sync here because XTread_socket looks at the
13053 hourglass_p flag that is reset to zero below. */
13054 XSync (FRAME_X_DISPLAY (f), False);
13055 f->output_data.x->hourglass_p = 0;
13056 }
13057 }
13058
13059 hourglass_shown_p = 0;
13060 UNBLOCK_INPUT;
13061 }
13062 #endif
13063 }
13064
13065
13066 \f
13067 /***********************************************************************
13068 Tool tips
13069 ***********************************************************************/
13070
13071 static Lisp_Object x_create_tip_frame P_ ((struct w32_display_info *,
13072 Lisp_Object, Lisp_Object));
13073 static void compute_tip_xy P_ ((struct frame *, Lisp_Object, Lisp_Object,
13074 Lisp_Object, int, int, int *, int *));
13075
13076 /* The frame of a currently visible tooltip. */
13077
13078 Lisp_Object tip_frame;
13079
13080 /* If non-nil, a timer started that hides the last tooltip when it
13081 fires. */
13082
13083 Lisp_Object tip_timer;
13084 Window tip_window;
13085
13086 /* If non-nil, a vector of 3 elements containing the last args
13087 with which x-show-tip was called. See there. */
13088
13089 Lisp_Object last_show_tip_args;
13090
13091 /* Maximum size for tooltips; a cons (COLUMNS . ROWS). */
13092
13093 Lisp_Object Vx_max_tooltip_size;
13094
13095
13096 static Lisp_Object
13097 unwind_create_tip_frame (frame)
13098 Lisp_Object frame;
13099 {
13100 Lisp_Object deleted;
13101
13102 deleted = unwind_create_frame (frame);
13103 if (EQ (deleted, Qt))
13104 {
13105 tip_window = NULL;
13106 tip_frame = Qnil;
13107 }
13108
13109 return deleted;
13110 }
13111
13112
13113 /* Create a frame for a tooltip on the display described by DPYINFO.
13114 PARMS is a list of frame parameters. TEXT is the string to
13115 display in the tip frame. Value is the frame.
13116
13117 Note that functions called here, esp. x_default_parameter can
13118 signal errors, for instance when a specified color name is
13119 undefined. We have to make sure that we're in a consistent state
13120 when this happens. */
13121
13122 static Lisp_Object
13123 x_create_tip_frame (dpyinfo, parms, text)
13124 struct w32_display_info *dpyinfo;
13125 Lisp_Object parms, text;
13126 {
13127 struct frame *f;
13128 Lisp_Object frame, tem;
13129 Lisp_Object name;
13130 long window_prompting = 0;
13131 int width, height;
13132 int count = BINDING_STACK_SIZE ();
13133 struct gcpro gcpro1, gcpro2, gcpro3;
13134 struct kboard *kb;
13135 int face_change_count_before = face_change_count;
13136 Lisp_Object buffer;
13137 struct buffer *old_buffer;
13138
13139 check_w32 ();
13140
13141 /* Use this general default value to start with until we know if
13142 this frame has a specified name. */
13143 Vx_resource_name = Vinvocation_name;
13144
13145 #ifdef MULTI_KBOARD
13146 kb = dpyinfo->kboard;
13147 #else
13148 kb = &the_only_kboard;
13149 #endif
13150
13151 /* Get the name of the frame to use for resource lookup. */
13152 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
13153 if (!STRINGP (name)
13154 && !EQ (name, Qunbound)
13155 && !NILP (name))
13156 error ("Invalid frame name--not a string or nil");
13157 Vx_resource_name = name;
13158
13159 frame = Qnil;
13160 GCPRO3 (parms, name, frame);
13161 /* Make a frame without minibuffer nor mode-line. */
13162 f = make_frame (0);
13163 f->wants_modeline = 0;
13164 XSETFRAME (frame, f);
13165
13166 buffer = Fget_buffer_create (build_string (" *tip*"));
13167 Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer);
13168 old_buffer = current_buffer;
13169 set_buffer_internal_1 (XBUFFER (buffer));
13170 current_buffer->truncate_lines = Qnil;
13171 Ferase_buffer ();
13172 Finsert (1, &text);
13173 set_buffer_internal_1 (old_buffer);
13174
13175 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
13176 record_unwind_protect (unwind_create_tip_frame, frame);
13177
13178 /* By setting the output method, we're essentially saying that
13179 the frame is live, as per FRAME_LIVE_P. If we get a signal
13180 from this point on, x_destroy_window might screw up reference
13181 counts etc. */
13182 f->output_method = output_w32;
13183 f->output_data.w32 =
13184 (struct w32_output *) xmalloc (sizeof (struct w32_output));
13185 bzero (f->output_data.w32, sizeof (struct w32_output));
13186
13187 FRAME_FONTSET (f) = -1;
13188 f->icon_name = Qnil;
13189
13190 #if 0 /* GLYPH_DEBUG TODO: image support. */
13191 image_cache_refcount = FRAME_X_IMAGE_CACHE (f)->refcount;
13192 dpyinfo_refcount = dpyinfo->reference_count;
13193 #endif /* GLYPH_DEBUG */
13194 #ifdef MULTI_KBOARD
13195 FRAME_KBOARD (f) = kb;
13196 #endif
13197 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
13198 f->output_data.w32->explicit_parent = 0;
13199
13200 /* Set the name; the functions to which we pass f expect the name to
13201 be set. */
13202 if (EQ (name, Qunbound) || NILP (name))
13203 {
13204 f->name = build_string (dpyinfo->w32_id_name);
13205 f->explicit_name = 0;
13206 }
13207 else
13208 {
13209 f->name = name;
13210 f->explicit_name = 1;
13211 /* use the frame's title when getting resources for this frame. */
13212 specbind (Qx_resource_name, name);
13213 }
13214
13215 /* Extract the window parameters from the supplied values
13216 that are needed to determine window geometry. */
13217 {
13218 Lisp_Object font;
13219
13220 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
13221
13222 BLOCK_INPUT;
13223 /* First, try whatever font the caller has specified. */
13224 if (STRINGP (font))
13225 {
13226 tem = Fquery_fontset (font, Qnil);
13227 if (STRINGP (tem))
13228 font = x_new_fontset (f, XSTRING (tem)->data);
13229 else
13230 font = x_new_font (f, XSTRING (font)->data);
13231 }
13232
13233 /* Try out a font which we hope has bold and italic variations. */
13234 if (!STRINGP (font))
13235 font = x_new_font (f, "-*-Courier New-normal-r-*-*-*-100-*-*-c-*-iso8859-1");
13236 if (! STRINGP (font))
13237 font = x_new_font (f, "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
13238 /* If those didn't work, look for something which will at least work. */
13239 if (! STRINGP (font))
13240 font = x_new_font (f, "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1");
13241 UNBLOCK_INPUT;
13242 if (! STRINGP (font))
13243 font = build_string ("Fixedsys");
13244
13245 x_default_parameter (f, parms, Qfont, font,
13246 "font", "Font", RES_TYPE_STRING);
13247 }
13248
13249 x_default_parameter (f, parms, Qborder_width, make_number (2),
13250 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
13251 /* This defaults to 2 in order to match xterm. We recognize either
13252 internalBorderWidth or internalBorder (which is what xterm calls
13253 it). */
13254 if (NILP (Fassq (Qinternal_border_width, parms)))
13255 {
13256 Lisp_Object value;
13257
13258 value = w32_get_arg (parms, Qinternal_border_width,
13259 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
13260 if (! EQ (value, Qunbound))
13261 parms = Fcons (Fcons (Qinternal_border_width, value),
13262 parms);
13263 }
13264 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
13265 "internalBorderWidth", "internalBorderWidth",
13266 RES_TYPE_NUMBER);
13267
13268 /* Also do the stuff which must be set before the window exists. */
13269 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
13270 "foreground", "Foreground", RES_TYPE_STRING);
13271 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
13272 "background", "Background", RES_TYPE_STRING);
13273 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
13274 "pointerColor", "Foreground", RES_TYPE_STRING);
13275 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
13276 "cursorColor", "Foreground", RES_TYPE_STRING);
13277 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
13278 "borderColor", "BorderColor", RES_TYPE_STRING);
13279
13280 /* Init faces before x_default_parameter is called for scroll-bar
13281 parameters because that function calls x_set_scroll_bar_width,
13282 which calls change_frame_size, which calls Fset_window_buffer,
13283 which runs hooks, which call Fvertical_motion. At the end, we
13284 end up in init_iterator with a null face cache, which should not
13285 happen. */
13286 init_frame_faces (f);
13287
13288 f->output_data.w32->dwStyle = WS_BORDER | WS_POPUP | WS_DISABLED;
13289 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
13290
13291 window_prompting = x_figure_window_size (f, parms);
13292
13293 /* No fringes on tip frame. */
13294 f->output_data.w32->fringes_extra = 0;
13295 f->output_data.w32->fringe_cols = 0;
13296 f->output_data.w32->left_fringe_width = 0;
13297 f->output_data.w32->right_fringe_width = 0;
13298
13299 if (window_prompting & XNegative)
13300 {
13301 if (window_prompting & YNegative)
13302 f->output_data.w32->win_gravity = SouthEastGravity;
13303 else
13304 f->output_data.w32->win_gravity = NorthEastGravity;
13305 }
13306 else
13307 {
13308 if (window_prompting & YNegative)
13309 f->output_data.w32->win_gravity = SouthWestGravity;
13310 else
13311 f->output_data.w32->win_gravity = NorthWestGravity;
13312 }
13313
13314 f->output_data.w32->size_hint_flags = window_prompting;
13315
13316 BLOCK_INPUT;
13317 my_create_tip_window (f);
13318 UNBLOCK_INPUT;
13319
13320 x_make_gc (f);
13321
13322 x_default_parameter (f, parms, Qauto_raise, Qnil,
13323 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
13324 x_default_parameter (f, parms, Qauto_lower, Qnil,
13325 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
13326 x_default_parameter (f, parms, Qcursor_type, Qbox,
13327 "cursorType", "CursorType", RES_TYPE_SYMBOL);
13328
13329 /* Dimensions, especially f->height, must be done via change_frame_size.
13330 Change will not be effected unless different from the current
13331 f->height. */
13332 width = f->width;
13333 height = f->height;
13334 f->height = 0;
13335 SET_FRAME_WIDTH (f, 0);
13336 change_frame_size (f, height, width, 1, 0, 0);
13337
13338 /* Set up faces after all frame parameters are known. This call
13339 also merges in face attributes specified for new frames.
13340
13341 Frame parameters may be changed if .Xdefaults contains
13342 specifications for the default font. For example, if there is an
13343 `Emacs.default.attributeBackground: pink', the `background-color'
13344 attribute of the frame get's set, which let's the internal border
13345 of the tooltip frame appear in pink. Prevent this. */
13346 {
13347 Lisp_Object bg = Fframe_parameter (frame, Qbackground_color);
13348
13349 /* Set tip_frame here, so that */
13350 tip_frame = frame;
13351 call1 (Qface_set_after_frame_default, frame);
13352
13353 if (!EQ (bg, Fframe_parameter (frame, Qbackground_color)))
13354 Fmodify_frame_parameters (frame, Fcons (Fcons (Qbackground_color, bg),
13355 Qnil));
13356 }
13357
13358 f->no_split = 1;
13359
13360 UNGCPRO;
13361
13362 /* It is now ok to make the frame official even if we get an error
13363 below. And the frame needs to be on Vframe_list or making it
13364 visible won't work. */
13365 Vframe_list = Fcons (frame, Vframe_list);
13366
13367 /* Now that the frame is official, it counts as a reference to
13368 its display. */
13369 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
13370
13371 /* Setting attributes of faces of the tooltip frame from resources
13372 and similar will increment face_change_count, which leads to the
13373 clearing of all current matrices. Since this isn't necessary
13374 here, avoid it by resetting face_change_count to the value it
13375 had before we created the tip frame. */
13376 face_change_count = face_change_count_before;
13377
13378 /* Discard the unwind_protect. */
13379 return unbind_to (count, frame);
13380 }
13381
13382
13383 /* Compute where to display tip frame F. PARMS is the list of frame
13384 parameters for F. DX and DY are specified offsets from the current
13385 location of the mouse. WIDTH and HEIGHT are the width and height
13386 of the tooltip. Return coordinates relative to the root window of
13387 the display in *ROOT_X, and *ROOT_Y. */
13388
13389 static void
13390 compute_tip_xy (f, parms, dx, dy, width, height, root_x, root_y)
13391 struct frame *f;
13392 Lisp_Object parms, dx, dy;
13393 int width, height;
13394 int *root_x, *root_y;
13395 {
13396 Lisp_Object left, top;
13397
13398 /* User-specified position? */
13399 left = Fcdr (Fassq (Qleft, parms));
13400 top = Fcdr (Fassq (Qtop, parms));
13401
13402 /* Move the tooltip window where the mouse pointer is. Resize and
13403 show it. */
13404 if (!INTEGERP (left) || !INTEGERP (top))
13405 {
13406 POINT pt;
13407
13408 BLOCK_INPUT;
13409 GetCursorPos (&pt);
13410 *root_x = pt.x;
13411 *root_y = pt.y;
13412 UNBLOCK_INPUT;
13413 }
13414
13415 if (INTEGERP (top))
13416 *root_y = XINT (top);
13417 else if (*root_y + XINT (dy) - height < 0)
13418 *root_y -= XINT (dy);
13419 else
13420 {
13421 *root_y -= height;
13422 *root_y += XINT (dy);
13423 }
13424
13425 if (INTEGERP (left))
13426 *root_x = XINT (left);
13427 else if (*root_x + XINT (dx) + width > FRAME_W32_DISPLAY_INFO (f)->width)
13428 *root_x -= width + XINT (dx);
13429 else
13430 *root_x += XINT (dx);
13431 }
13432
13433
13434 DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
13435 doc: /* Show STRING in a \"tooltip\" window on frame FRAME.
13436 A tooltip window is a small window displaying a string.
13437
13438 FRAME nil or omitted means use the selected frame.
13439
13440 PARMS is an optional list of frame parameters which can be
13441 used to change the tooltip's appearance.
13442
13443 Automatically hide the tooltip after TIMEOUT seconds. TIMEOUT nil
13444 means use the default timeout of 5 seconds.
13445
13446 If the list of frame parameters PARAMS contains a `left' parameter,
13447 the tooltip is displayed at that x-position. Otherwise it is
13448 displayed at the mouse position, with offset DX added (default is 5 if
13449 DX isn't specified). Likewise for the y-position; if a `top' frame
13450 parameter is specified, it determines the y-position of the tooltip
13451 window, otherwise it is displayed at the mouse position, with offset
13452 DY added (default is -10).
13453
13454 A tooltip's maximum size is specified by `x-max-tooltip-size'.
13455 Text larger than the specified size is clipped. */)
13456 (string, frame, parms, timeout, dx, dy)
13457 Lisp_Object string, frame, parms, timeout, dx, dy;
13458 {
13459 struct frame *f;
13460 struct window *w;
13461 int root_x, root_y;
13462 struct buffer *old_buffer;
13463 struct text_pos pos;
13464 int i, width, height;
13465 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
13466 int old_windows_or_buffers_changed = windows_or_buffers_changed;
13467 int count = BINDING_STACK_SIZE ();
13468
13469 specbind (Qinhibit_redisplay, Qt);
13470
13471 GCPRO4 (string, parms, frame, timeout);
13472
13473 CHECK_STRING (string);
13474 f = check_x_frame (frame);
13475 if (NILP (timeout))
13476 timeout = make_number (5);
13477 else
13478 CHECK_NATNUM (timeout);
13479
13480 if (NILP (dx))
13481 dx = make_number (5);
13482 else
13483 CHECK_NUMBER (dx);
13484
13485 if (NILP (dy))
13486 dy = make_number (-10);
13487 else
13488 CHECK_NUMBER (dy);
13489
13490 if (NILP (last_show_tip_args))
13491 last_show_tip_args = Fmake_vector (make_number (3), Qnil);
13492
13493 if (!NILP (tip_frame))
13494 {
13495 Lisp_Object last_string = AREF (last_show_tip_args, 0);
13496 Lisp_Object last_frame = AREF (last_show_tip_args, 1);
13497 Lisp_Object last_parms = AREF (last_show_tip_args, 2);
13498
13499 if (EQ (frame, last_frame)
13500 && !NILP (Fequal (last_string, string))
13501 && !NILP (Fequal (last_parms, parms)))
13502 {
13503 struct frame *f = XFRAME (tip_frame);
13504
13505 /* Only DX and DY have changed. */
13506 if (!NILP (tip_timer))
13507 {
13508 Lisp_Object timer = tip_timer;
13509 tip_timer = Qnil;
13510 call1 (Qcancel_timer, timer);
13511 }
13512
13513 BLOCK_INPUT;
13514 compute_tip_xy (f, parms, dx, dy, PIXEL_WIDTH (f),
13515 PIXEL_HEIGHT (f), &root_x, &root_y);
13516 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST,
13517 root_x, root_y, 0, 0,
13518 SWP_NOSIZE | SWP_NOACTIVATE);
13519 UNBLOCK_INPUT;
13520 goto start_timer;
13521 }
13522 }
13523
13524 /* Hide a previous tip, if any. */
13525 Fx_hide_tip ();
13526
13527 ASET (last_show_tip_args, 0, string);
13528 ASET (last_show_tip_args, 1, frame);
13529 ASET (last_show_tip_args, 2, parms);
13530
13531 /* Add default values to frame parameters. */
13532 if (NILP (Fassq (Qname, parms)))
13533 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
13534 if (NILP (Fassq (Qinternal_border_width, parms)))
13535 parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
13536 if (NILP (Fassq (Qborder_width, parms)))
13537 parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
13538 if (NILP (Fassq (Qborder_color, parms)))
13539 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
13540 if (NILP (Fassq (Qbackground_color, parms)))
13541 parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
13542 parms);
13543
13544 /* Block input until the tip has been fully drawn, to avoid crashes
13545 when drawing tips in menus. */
13546 BLOCK_INPUT;
13547
13548 /* Create a frame for the tooltip, and record it in the global
13549 variable tip_frame. */
13550 frame = x_create_tip_frame (FRAME_W32_DISPLAY_INFO (f), parms, string);
13551 f = XFRAME (frame);
13552
13553 /* Set up the frame's root window. */
13554 w = XWINDOW (FRAME_ROOT_WINDOW (f));
13555 w->left = w->top = make_number (0);
13556
13557 if (CONSP (Vx_max_tooltip_size)
13558 && INTEGERP (XCAR (Vx_max_tooltip_size))
13559 && XINT (XCAR (Vx_max_tooltip_size)) > 0
13560 && INTEGERP (XCDR (Vx_max_tooltip_size))
13561 && XINT (XCDR (Vx_max_tooltip_size)) > 0)
13562 {
13563 w->width = XCAR (Vx_max_tooltip_size);
13564 w->height = XCDR (Vx_max_tooltip_size);
13565 }
13566 else
13567 {
13568 w->width = make_number (80);
13569 w->height = make_number (40);
13570 }
13571
13572 f->window_width = XINT (w->width);
13573 adjust_glyphs (f);
13574 w->pseudo_window_p = 1;
13575
13576 /* Display the tooltip text in a temporary buffer. */
13577 old_buffer = current_buffer;
13578 set_buffer_internal_1 (XBUFFER (XWINDOW (FRAME_ROOT_WINDOW (f))->buffer));
13579 current_buffer->truncate_lines = Qnil;
13580 clear_glyph_matrix (w->desired_matrix);
13581 clear_glyph_matrix (w->current_matrix);
13582 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
13583 try_window (FRAME_ROOT_WINDOW (f), pos);
13584
13585 /* Compute width and height of the tooltip. */
13586 width = height = 0;
13587 for (i = 0; i < w->desired_matrix->nrows; ++i)
13588 {
13589 struct glyph_row *row = &w->desired_matrix->rows[i];
13590 struct glyph *last;
13591 int row_width;
13592
13593 /* Stop at the first empty row at the end. */
13594 if (!row->enabled_p || !row->displays_text_p)
13595 break;
13596
13597 /* Let the row go over the full width of the frame. */
13598 row->full_width_p = 1;
13599
13600 #ifdef TODO /* Investigate why some fonts need more width than is
13601 calculated for some tooltips. */
13602 /* There's a glyph at the end of rows that is use to place
13603 the cursor there. Don't include the width of this glyph. */
13604 if (row->used[TEXT_AREA])
13605 {
13606 last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
13607 row_width = row->pixel_width - last->pixel_width;
13608 }
13609 else
13610 #endif
13611 row_width = row->pixel_width;
13612
13613 /* TODO: find why tips do not draw along baseline as instructed. */
13614 height += row->height;
13615 width = max (width, row_width);
13616 }
13617
13618 /* Add the frame's internal border to the width and height the X
13619 window should have. */
13620 height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
13621 width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
13622
13623 /* Move the tooltip window where the mouse pointer is. Resize and
13624 show it. */
13625 compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y);
13626
13627 {
13628 /* Adjust Window size to take border into account. */
13629 RECT rect;
13630 rect.left = rect.top = 0;
13631 rect.right = width;
13632 rect.bottom = height;
13633 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
13634 FRAME_EXTERNAL_MENU_BAR (f));
13635
13636 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST,
13637 root_x, root_y, rect.right - rect.left,
13638 rect.bottom - rect.top, SWP_NOACTIVATE);
13639
13640 /* Let redisplay know that we have made the frame visible already. */
13641 f->async_visible = 1;
13642
13643 ShowWindow (FRAME_W32_WINDOW (f), SW_SHOWNOACTIVATE);
13644 }
13645
13646 /* Draw into the window. */
13647 w->must_be_updated_p = 1;
13648 update_single_window (w, 1);
13649
13650 UNBLOCK_INPUT;
13651
13652 /* Restore original current buffer. */
13653 set_buffer_internal_1 (old_buffer);
13654 windows_or_buffers_changed = old_windows_or_buffers_changed;
13655
13656 start_timer:
13657 /* Let the tip disappear after timeout seconds. */
13658 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
13659 intern ("x-hide-tip"));
13660
13661 UNGCPRO;
13662 return unbind_to (count, Qnil);
13663 }
13664
13665
13666 DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
13667 doc: /* Hide the current tooltip window, if there is any.
13668 Value is t if tooltip was open, nil otherwise. */)
13669 ()
13670 {
13671 int count;
13672 Lisp_Object deleted, frame, timer;
13673 struct gcpro gcpro1, gcpro2;
13674
13675 /* Return quickly if nothing to do. */
13676 if (NILP (tip_timer) && NILP (tip_frame))
13677 return Qnil;
13678
13679 frame = tip_frame;
13680 timer = tip_timer;
13681 GCPRO2 (frame, timer);
13682 tip_frame = tip_timer = deleted = Qnil;
13683
13684 count = BINDING_STACK_SIZE ();
13685 specbind (Qinhibit_redisplay, Qt);
13686 specbind (Qinhibit_quit, Qt);
13687
13688 if (!NILP (timer))
13689 call1 (Qcancel_timer, timer);
13690
13691 if (FRAMEP (frame))
13692 {
13693 Fdelete_frame (frame, Qnil);
13694 deleted = Qt;
13695 }
13696
13697 UNGCPRO;
13698 return unbind_to (count, deleted);
13699 }
13700
13701
13702 \f
13703 /***********************************************************************
13704 File selection dialog
13705 ***********************************************************************/
13706
13707 extern Lisp_Object Qfile_name_history;
13708
13709 DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0,
13710 doc: /* Read file name, prompting with PROMPT in directory DIR.
13711 Use a file selection dialog.
13712 Select DEFAULT-FILENAME in the dialog's file selection box, if
13713 specified. Ensure that file exists if MUSTMATCH is non-nil. */)
13714 (prompt, dir, default_filename, mustmatch)
13715 Lisp_Object prompt, dir, default_filename, mustmatch;
13716 {
13717 struct frame *f = SELECTED_FRAME ();
13718 Lisp_Object file = Qnil;
13719 int count = specpdl_ptr - specpdl;
13720 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
13721 char filename[MAX_PATH + 1];
13722 char init_dir[MAX_PATH + 1];
13723 int use_dialog_p = 1;
13724
13725 GCPRO5 (prompt, dir, default_filename, mustmatch, file);
13726 CHECK_STRING (prompt);
13727 CHECK_STRING (dir);
13728
13729 /* Create the dialog with PROMPT as title, using DIR as initial
13730 directory and using "*" as pattern. */
13731 dir = Fexpand_file_name (dir, Qnil);
13732 strncpy (init_dir, XSTRING (dir)->data, MAX_PATH);
13733 init_dir[MAX_PATH] = '\0';
13734 unixtodos_filename (init_dir);
13735
13736 if (STRINGP (default_filename))
13737 {
13738 char *file_name_only;
13739 char *full_path_name = XSTRING (default_filename)->data;
13740
13741 unixtodos_filename (full_path_name);
13742
13743 file_name_only = strrchr (full_path_name, '\\');
13744 if (!file_name_only)
13745 file_name_only = full_path_name;
13746 else
13747 {
13748 file_name_only++;
13749
13750 /* If default_file_name is a directory, don't use the open
13751 file dialog, as it does not support selecting
13752 directories. */
13753 if (!(*file_name_only))
13754 use_dialog_p = 0;
13755 }
13756
13757 strncpy (filename, file_name_only, MAX_PATH);
13758 filename[MAX_PATH] = '\0';
13759 }
13760 else
13761 filename[0] = '\0';
13762
13763 if (use_dialog_p)
13764 {
13765 OPENFILENAME file_details;
13766
13767 /* Prevent redisplay. */
13768 specbind (Qinhibit_redisplay, Qt);
13769 BLOCK_INPUT;
13770
13771 bzero (&file_details, sizeof (file_details));
13772 file_details.lStructSize = sizeof (file_details);
13773 file_details.hwndOwner = FRAME_W32_WINDOW (f);
13774 /* Undocumented Bug in Common File Dialog:
13775 If a filter is not specified, shell links are not resolved. */
13776 file_details.lpstrFilter = "ALL Files (*.*)\0*.*\0\0";
13777 file_details.lpstrFile = filename;
13778 file_details.nMaxFile = sizeof (filename);
13779 file_details.lpstrInitialDir = init_dir;
13780 file_details.lpstrTitle = XSTRING (prompt)->data;
13781 file_details.Flags = OFN_HIDEREADONLY | OFN_NOCHANGEDIR;
13782
13783 if (!NILP (mustmatch))
13784 file_details.Flags |= OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
13785
13786 if (GetOpenFileName (&file_details))
13787 {
13788 dostounix_filename (filename);
13789 file = build_string (filename);
13790 }
13791 else
13792 file = Qnil;
13793
13794 UNBLOCK_INPUT;
13795 file = unbind_to (count, file);
13796 }
13797 /* Open File dialog will not allow folders to be selected, so resort
13798 to minibuffer completing reads for directories. */
13799 else
13800 file = Fcompleting_read (prompt, intern ("read-file-name-internal"),
13801 dir, mustmatch, dir, Qfile_name_history,
13802 default_filename, Qnil);
13803
13804 UNGCPRO;
13805
13806 /* Make "Cancel" equivalent to C-g. */
13807 if (NILP (file))
13808 Fsignal (Qquit, Qnil);
13809
13810 return unbind_to (count, file);
13811 }
13812
13813
13814 \f
13815 /***********************************************************************
13816 w32 specialized functions
13817 ***********************************************************************/
13818
13819 DEFUN ("w32-select-font", Fw32_select_font, Sw32_select_font, 0, 1, 0,
13820 doc: /* Select a font using the W32 font dialog.
13821 Returns an X font string corresponding to the selection. */)
13822 (frame)
13823 Lisp_Object frame;
13824 {
13825 FRAME_PTR f = check_x_frame (frame);
13826 CHOOSEFONT cf;
13827 LOGFONT lf;
13828 TEXTMETRIC tm;
13829 HDC hdc;
13830 HANDLE oldobj;
13831 char buf[100];
13832
13833 bzero (&cf, sizeof (cf));
13834 bzero (&lf, sizeof (lf));
13835
13836 cf.lStructSize = sizeof (cf);
13837 cf.hwndOwner = FRAME_W32_WINDOW (f);
13838 cf.Flags = CF_FORCEFONTEXIST | CF_SCREENFONTS;
13839 cf.lpLogFont = &lf;
13840
13841 /* Initialize as much of the font details as we can from the current
13842 default font. */
13843 hdc = GetDC (FRAME_W32_WINDOW (f));
13844 oldobj = SelectObject (hdc, FRAME_FONT (f)->hfont);
13845 GetTextFace (hdc, LF_FACESIZE, lf.lfFaceName);
13846 if (GetTextMetrics (hdc, &tm))
13847 {
13848 lf.lfHeight = tm.tmInternalLeading - tm.tmHeight;
13849 lf.lfWeight = tm.tmWeight;
13850 lf.lfItalic = tm.tmItalic;
13851 lf.lfUnderline = tm.tmUnderlined;
13852 lf.lfStrikeOut = tm.tmStruckOut;
13853 lf.lfCharSet = tm.tmCharSet;
13854 cf.Flags |= CF_INITTOLOGFONTSTRUCT;
13855 }
13856 SelectObject (hdc, oldobj);
13857 ReleaseDC (FRAME_W32_WINDOW (f), hdc);
13858
13859 if (!ChooseFont (&cf) || !w32_to_x_font (&lf, buf, 100, NULL))
13860 return Qnil;
13861
13862 return build_string (buf);
13863 }
13864
13865 DEFUN ("w32-send-sys-command", Fw32_send_sys_command,
13866 Sw32_send_sys_command, 1, 2, 0,
13867 doc: /* Send frame a Windows WM_SYSCOMMAND message of type COMMAND.
13868 Some useful values for command are 0xf030 to maximise frame (0xf020
13869 to minimize), 0xf120 to restore frame to original size, and 0xf100
13870 to activate the menubar for keyboard access. 0xf140 activates the
13871 screen saver if defined.
13872
13873 If optional parameter FRAME is not specified, use selected frame. */)
13874 (command, frame)
13875 Lisp_Object command, frame;
13876 {
13877 FRAME_PTR f = check_x_frame (frame);
13878
13879 CHECK_NUMBER (command);
13880
13881 PostMessage (FRAME_W32_WINDOW (f), WM_SYSCOMMAND, XINT (command), 0);
13882
13883 return Qnil;
13884 }
13885
13886 DEFUN ("w32-shell-execute", Fw32_shell_execute, Sw32_shell_execute, 2, 4, 0,
13887 doc: /* Get Windows to perform OPERATION on DOCUMENT.
13888 This is a wrapper around the ShellExecute system function, which
13889 invokes the application registered to handle OPERATION for DOCUMENT.
13890 OPERATION is typically \"open\", \"print\" or \"explore\" (but can be
13891 nil for the default action), and DOCUMENT is typically the name of a
13892 document file or URL, but can also be a program executable to run or
13893 a directory to open in the Windows Explorer.
13894
13895 If DOCUMENT is a program executable, PARAMETERS can be a string
13896 containing command line parameters, but otherwise should be nil.
13897
13898 SHOW-FLAG can be used to control whether the invoked application is hidden
13899 or minimized. If SHOW-FLAG is nil, the application is displayed normally,
13900 otherwise it is an integer representing a ShowWindow flag:
13901
13902 0 - start hidden
13903 1 - start normally
13904 3 - start maximized
13905 6 - start minimized */)
13906 (operation, document, parameters, show_flag)
13907 Lisp_Object operation, document, parameters, show_flag;
13908 {
13909 Lisp_Object current_dir;
13910
13911 CHECK_STRING (document);
13912
13913 /* Encode filename and current directory. */
13914 current_dir = ENCODE_FILE (current_buffer->directory);
13915 document = ENCODE_FILE (document);
13916 if ((int) ShellExecute (NULL,
13917 (STRINGP (operation) ?
13918 XSTRING (operation)->data : NULL),
13919 XSTRING (document)->data,
13920 (STRINGP (parameters) ?
13921 XSTRING (parameters)->data : NULL),
13922 XSTRING (current_dir)->data,
13923 (INTEGERP (show_flag) ?
13924 XINT (show_flag) : SW_SHOWDEFAULT))
13925 > 32)
13926 return Qt;
13927 error ("ShellExecute failed: %s", w32_strerror (0));
13928 }
13929
13930 /* Lookup virtual keycode from string representing the name of a
13931 non-ascii keystroke into the corresponding virtual key, using
13932 lispy_function_keys. */
13933 static int
13934 lookup_vk_code (char *key)
13935 {
13936 int i;
13937
13938 for (i = 0; i < 256; i++)
13939 if (lispy_function_keys[i] != 0
13940 && strcmp (lispy_function_keys[i], key) == 0)
13941 return i;
13942
13943 return -1;
13944 }
13945
13946 /* Convert a one-element vector style key sequence to a hot key
13947 definition. */
13948 static int
13949 w32_parse_hot_key (key)
13950 Lisp_Object key;
13951 {
13952 /* Copied from Fdefine_key and store_in_keymap. */
13953 register Lisp_Object c;
13954 int vk_code;
13955 int lisp_modifiers;
13956 int w32_modifiers;
13957 struct gcpro gcpro1;
13958
13959 CHECK_VECTOR (key);
13960
13961 if (XFASTINT (Flength (key)) != 1)
13962 return Qnil;
13963
13964 GCPRO1 (key);
13965
13966 c = Faref (key, make_number (0));
13967
13968 if (CONSP (c) && lucid_event_type_list_p (c))
13969 c = Fevent_convert_list (c);
13970
13971 UNGCPRO;
13972
13973 if (! INTEGERP (c) && ! SYMBOLP (c))
13974 error ("Key definition is invalid");
13975
13976 /* Work out the base key and the modifiers. */
13977 if (SYMBOLP (c))
13978 {
13979 c = parse_modifiers (c);
13980 lisp_modifiers = Fcar (Fcdr (c));
13981 c = Fcar (c);
13982 if (!SYMBOLP (c))
13983 abort ();
13984 vk_code = lookup_vk_code (XSYMBOL (c)->name->data);
13985 }
13986 else if (INTEGERP (c))
13987 {
13988 lisp_modifiers = XINT (c) & ~CHARACTERBITS;
13989 /* Many ascii characters are their own virtual key code. */
13990 vk_code = XINT (c) & CHARACTERBITS;
13991 }
13992
13993 if (vk_code < 0 || vk_code > 255)
13994 return Qnil;
13995
13996 if ((lisp_modifiers & meta_modifier) != 0
13997 && !NILP (Vw32_alt_is_meta))
13998 lisp_modifiers |= alt_modifier;
13999
14000 /* Supply defs missing from mingw32. */
14001 #ifndef MOD_ALT
14002 #define MOD_ALT 0x0001
14003 #define MOD_CONTROL 0x0002
14004 #define MOD_SHIFT 0x0004
14005 #define MOD_WIN 0x0008
14006 #endif
14007
14008 /* Convert lisp modifiers to Windows hot-key form. */
14009 w32_modifiers = (lisp_modifiers & hyper_modifier) ? MOD_WIN : 0;
14010 w32_modifiers |= (lisp_modifiers & alt_modifier) ? MOD_ALT : 0;
14011 w32_modifiers |= (lisp_modifiers & ctrl_modifier) ? MOD_CONTROL : 0;
14012 w32_modifiers |= (lisp_modifiers & shift_modifier) ? MOD_SHIFT : 0;
14013
14014 return HOTKEY (vk_code, w32_modifiers);
14015 }
14016
14017 DEFUN ("w32-register-hot-key", Fw32_register_hot_key,
14018 Sw32_register_hot_key, 1, 1, 0,
14019 doc: /* Register KEY as a hot-key combination.
14020 Certain key combinations like Alt-Tab are reserved for system use on
14021 Windows, and therefore are normally intercepted by the system. However,
14022 most of these key combinations can be received by registering them as
14023 hot-keys, overriding their special meaning.
14024
14025 KEY must be a one element key definition in vector form that would be
14026 acceptable to `define-key' (e.g. [A-tab] for Alt-Tab). The meta
14027 modifier is interpreted as Alt if `w32-alt-is-meta' is t, and hyper
14028 is always interpreted as the Windows modifier keys.
14029
14030 The return value is the hotkey-id if registered, otherwise nil. */)
14031 (key)
14032 Lisp_Object key;
14033 {
14034 key = w32_parse_hot_key (key);
14035
14036 if (NILP (Fmemq (key, w32_grabbed_keys)))
14037 {
14038 /* Reuse an empty slot if possible. */
14039 Lisp_Object item = Fmemq (Qnil, w32_grabbed_keys);
14040
14041 /* Safe to add new key to list, even if we have focus. */
14042 if (NILP (item))
14043 w32_grabbed_keys = Fcons (key, w32_grabbed_keys);
14044 else
14045 XSETCAR (item, key);
14046
14047 /* Notify input thread about new hot-key definition, so that it
14048 takes effect without needing to switch focus. */
14049 PostThreadMessage (dwWindowsThreadId, WM_EMACS_REGISTER_HOT_KEY,
14050 (WPARAM) key, 0);
14051 }
14052
14053 return key;
14054 }
14055
14056 DEFUN ("w32-unregister-hot-key", Fw32_unregister_hot_key,
14057 Sw32_unregister_hot_key, 1, 1, 0,
14058 doc: /* Unregister HOTKEY as a hot-key combination. */)
14059 (key)
14060 Lisp_Object key;
14061 {
14062 Lisp_Object item;
14063
14064 if (!INTEGERP (key))
14065 key = w32_parse_hot_key (key);
14066
14067 item = Fmemq (key, w32_grabbed_keys);
14068
14069 if (!NILP (item))
14070 {
14071 /* Notify input thread about hot-key definition being removed, so
14072 that it takes effect without needing focus switch. */
14073 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_UNREGISTER_HOT_KEY,
14074 (WPARAM) XINT (XCAR (item)), (LPARAM) item))
14075 {
14076 MSG msg;
14077 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
14078 }
14079 return Qt;
14080 }
14081 return Qnil;
14082 }
14083
14084 DEFUN ("w32-registered-hot-keys", Fw32_registered_hot_keys,
14085 Sw32_registered_hot_keys, 0, 0, 0,
14086 doc: /* Return list of registered hot-key IDs. */)
14087 ()
14088 {
14089 return Fcopy_sequence (w32_grabbed_keys);
14090 }
14091
14092 DEFUN ("w32-reconstruct-hot-key", Fw32_reconstruct_hot_key,
14093 Sw32_reconstruct_hot_key, 1, 1, 0,
14094 doc: /* Convert hot-key ID to a lisp key combination. */)
14095 (hotkeyid)
14096 Lisp_Object hotkeyid;
14097 {
14098 int vk_code, w32_modifiers;
14099 Lisp_Object key;
14100
14101 CHECK_NUMBER (hotkeyid);
14102
14103 vk_code = HOTKEY_VK_CODE (hotkeyid);
14104 w32_modifiers = HOTKEY_MODIFIERS (hotkeyid);
14105
14106 if (lispy_function_keys[vk_code])
14107 key = intern (lispy_function_keys[vk_code]);
14108 else
14109 key = make_number (vk_code);
14110
14111 key = Fcons (key, Qnil);
14112 if (w32_modifiers & MOD_SHIFT)
14113 key = Fcons (Qshift, key);
14114 if (w32_modifiers & MOD_CONTROL)
14115 key = Fcons (Qctrl, key);
14116 if (w32_modifiers & MOD_ALT)
14117 key = Fcons (NILP (Vw32_alt_is_meta) ? Qalt : Qmeta, key);
14118 if (w32_modifiers & MOD_WIN)
14119 key = Fcons (Qhyper, key);
14120
14121 return key;
14122 }
14123
14124 DEFUN ("w32-toggle-lock-key", Fw32_toggle_lock_key,
14125 Sw32_toggle_lock_key, 1, 2, 0,
14126 doc: /* Toggle the state of the lock key KEY.
14127 KEY can be `capslock', `kp-numlock', or `scroll'.
14128 If the optional parameter NEW-STATE is a number, then the state of KEY
14129 is set to off if the low bit of NEW-STATE is zero, otherwise on. */)
14130 (key, new_state)
14131 Lisp_Object key, new_state;
14132 {
14133 int vk_code;
14134
14135 if (EQ (key, intern ("capslock")))
14136 vk_code = VK_CAPITAL;
14137 else if (EQ (key, intern ("kp-numlock")))
14138 vk_code = VK_NUMLOCK;
14139 else if (EQ (key, intern ("scroll")))
14140 vk_code = VK_SCROLL;
14141 else
14142 return Qnil;
14143
14144 if (!dwWindowsThreadId)
14145 return make_number (w32_console_toggle_lock_key (vk_code, new_state));
14146
14147 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_TOGGLE_LOCK_KEY,
14148 (WPARAM) vk_code, (LPARAM) new_state))
14149 {
14150 MSG msg;
14151 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
14152 return make_number (msg.wParam);
14153 }
14154 return Qnil;
14155 }
14156 \f
14157 DEFUN ("file-system-info", Ffile_system_info, Sfile_system_info, 1, 1, 0,
14158 doc: /* Return storage information about the file system FILENAME is on.
14159 Value is a list of floats (TOTAL FREE AVAIL), where TOTAL is the total
14160 storage of the file system, FREE is the free storage, and AVAIL is the
14161 storage available to a non-superuser. All 3 numbers are in bytes.
14162 If the underlying system call fails, value is nil. */)
14163 (filename)
14164 Lisp_Object filename;
14165 {
14166 Lisp_Object encoded, value;
14167
14168 CHECK_STRING (filename);
14169 filename = Fexpand_file_name (filename, Qnil);
14170 encoded = ENCODE_FILE (filename);
14171
14172 value = Qnil;
14173
14174 /* Determining the required information on Windows turns out, sadly,
14175 to be more involved than one would hope. The original Win32 api
14176 call for this will return bogus information on some systems, but we
14177 must dynamically probe for the replacement api, since that was
14178 added rather late on. */
14179 {
14180 HMODULE hKernel = GetModuleHandle ("kernel32");
14181 BOOL (*pfn_GetDiskFreeSpaceEx)
14182 (char *, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER)
14183 = (void *) GetProcAddress (hKernel, "GetDiskFreeSpaceEx");
14184
14185 /* On Windows, we may need to specify the root directory of the
14186 volume holding FILENAME. */
14187 char rootname[MAX_PATH];
14188 char *name = XSTRING (encoded)->data;
14189
14190 /* find the root name of the volume if given */
14191 if (isalpha (name[0]) && name[1] == ':')
14192 {
14193 rootname[0] = name[0];
14194 rootname[1] = name[1];
14195 rootname[2] = '\\';
14196 rootname[3] = 0;
14197 }
14198 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
14199 {
14200 char *str = rootname;
14201 int slashes = 4;
14202 do
14203 {
14204 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
14205 break;
14206 *str++ = *name++;
14207 }
14208 while ( *name );
14209
14210 *str++ = '\\';
14211 *str = 0;
14212 }
14213
14214 if (pfn_GetDiskFreeSpaceEx)
14215 {
14216 LARGE_INTEGER availbytes;
14217 LARGE_INTEGER freebytes;
14218 LARGE_INTEGER totalbytes;
14219
14220 if (pfn_GetDiskFreeSpaceEx(rootname,
14221 &availbytes,
14222 &totalbytes,
14223 &freebytes))
14224 value = list3 (make_float ((double) totalbytes.QuadPart),
14225 make_float ((double) freebytes.QuadPart),
14226 make_float ((double) availbytes.QuadPart));
14227 }
14228 else
14229 {
14230 DWORD sectors_per_cluster;
14231 DWORD bytes_per_sector;
14232 DWORD free_clusters;
14233 DWORD total_clusters;
14234
14235 if (GetDiskFreeSpace(rootname,
14236 &sectors_per_cluster,
14237 &bytes_per_sector,
14238 &free_clusters,
14239 &total_clusters))
14240 value = list3 (make_float ((double) total_clusters
14241 * sectors_per_cluster * bytes_per_sector),
14242 make_float ((double) free_clusters
14243 * sectors_per_cluster * bytes_per_sector),
14244 make_float ((double) free_clusters
14245 * sectors_per_cluster * bytes_per_sector));
14246 }
14247 }
14248
14249 return value;
14250 }
14251 \f
14252 /***********************************************************************
14253 Initialization
14254 ***********************************************************************/
14255
14256 void
14257 syms_of_w32fns ()
14258 {
14259 HMODULE user32_lib = GetModuleHandle ("user32.dll");
14260
14261 /* This is zero if not using MS-Windows. */
14262 w32_in_use = 0;
14263
14264 /* TrackMouseEvent not available in all versions of Windows, so must load
14265 it dynamically. Do it once, here, instead of every time it is used. */
14266 track_mouse_event_fn = GetProcAddress (user32_lib, "TrackMouseEvent");
14267 track_mouse_window = NULL;
14268
14269 /* The section below is built by the lisp expression at the top of the file,
14270 just above where these variables are declared. */
14271 /*&&& init symbols here &&&*/
14272 Qauto_raise = intern ("auto-raise");
14273 staticpro (&Qauto_raise);
14274 Qauto_lower = intern ("auto-lower");
14275 staticpro (&Qauto_lower);
14276 Qbar = intern ("bar");
14277 staticpro (&Qbar);
14278 Qborder_color = intern ("border-color");
14279 staticpro (&Qborder_color);
14280 Qborder_width = intern ("border-width");
14281 staticpro (&Qborder_width);
14282 Qbox = intern ("box");
14283 staticpro (&Qbox);
14284 Qcursor_color = intern ("cursor-color");
14285 staticpro (&Qcursor_color);
14286 Qcursor_type = intern ("cursor-type");
14287 staticpro (&Qcursor_type);
14288 Qgeometry = intern ("geometry");
14289 staticpro (&Qgeometry);
14290 Qicon_left = intern ("icon-left");
14291 staticpro (&Qicon_left);
14292 Qicon_top = intern ("icon-top");
14293 staticpro (&Qicon_top);
14294 Qicon_type = intern ("icon-type");
14295 staticpro (&Qicon_type);
14296 Qicon_name = intern ("icon-name");
14297 staticpro (&Qicon_name);
14298 Qinternal_border_width = intern ("internal-border-width");
14299 staticpro (&Qinternal_border_width);
14300 Qleft = intern ("left");
14301 staticpro (&Qleft);
14302 Qright = intern ("right");
14303 staticpro (&Qright);
14304 Qmouse_color = intern ("mouse-color");
14305 staticpro (&Qmouse_color);
14306 Qnone = intern ("none");
14307 staticpro (&Qnone);
14308 Qparent_id = intern ("parent-id");
14309 staticpro (&Qparent_id);
14310 Qscroll_bar_width = intern ("scroll-bar-width");
14311 staticpro (&Qscroll_bar_width);
14312 Qsuppress_icon = intern ("suppress-icon");
14313 staticpro (&Qsuppress_icon);
14314 Qundefined_color = intern ("undefined-color");
14315 staticpro (&Qundefined_color);
14316 Qvertical_scroll_bars = intern ("vertical-scroll-bars");
14317 staticpro (&Qvertical_scroll_bars);
14318 Qvisibility = intern ("visibility");
14319 staticpro (&Qvisibility);
14320 Qwindow_id = intern ("window-id");
14321 staticpro (&Qwindow_id);
14322 Qx_frame_parameter = intern ("x-frame-parameter");
14323 staticpro (&Qx_frame_parameter);
14324 Qx_resource_name = intern ("x-resource-name");
14325 staticpro (&Qx_resource_name);
14326 Quser_position = intern ("user-position");
14327 staticpro (&Quser_position);
14328 Quser_size = intern ("user-size");
14329 staticpro (&Quser_size);
14330 Qscreen_gamma = intern ("screen-gamma");
14331 staticpro (&Qscreen_gamma);
14332 Qline_spacing = intern ("line-spacing");
14333 staticpro (&Qline_spacing);
14334 Qcenter = intern ("center");
14335 staticpro (&Qcenter);
14336 Qcancel_timer = intern ("cancel-timer");
14337 staticpro (&Qcancel_timer);
14338 /* This is the end of symbol initialization. */
14339
14340 Qhyper = intern ("hyper");
14341 staticpro (&Qhyper);
14342 Qsuper = intern ("super");
14343 staticpro (&Qsuper);
14344 Qmeta = intern ("meta");
14345 staticpro (&Qmeta);
14346 Qalt = intern ("alt");
14347 staticpro (&Qalt);
14348 Qctrl = intern ("ctrl");
14349 staticpro (&Qctrl);
14350 Qcontrol = intern ("control");
14351 staticpro (&Qcontrol);
14352 Qshift = intern ("shift");
14353 staticpro (&Qshift);
14354
14355 /* Text property `display' should be nonsticky by default. */
14356 Vtext_property_default_nonsticky
14357 = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky);
14358
14359
14360 Qlaplace = intern ("laplace");
14361 staticpro (&Qlaplace);
14362 Qemboss = intern ("emboss");
14363 staticpro (&Qemboss);
14364 Qedge_detection = intern ("edge-detection");
14365 staticpro (&Qedge_detection);
14366 Qheuristic = intern ("heuristic");
14367 staticpro (&Qheuristic);
14368 QCmatrix = intern (":matrix");
14369 staticpro (&QCmatrix);
14370 QCcolor_adjustment = intern (":color-adjustment");
14371 staticpro (&QCcolor_adjustment);
14372 QCmask = intern (":mask");
14373 staticpro (&QCmask);
14374
14375 Qface_set_after_frame_default = intern ("face-set-after-frame-default");
14376 staticpro (&Qface_set_after_frame_default);
14377
14378 Fput (Qundefined_color, Qerror_conditions,
14379 Fcons (Qundefined_color, Fcons (Qerror, Qnil)));
14380 Fput (Qundefined_color, Qerror_message,
14381 build_string ("Undefined color"));
14382
14383 staticpro (&w32_grabbed_keys);
14384 w32_grabbed_keys = Qnil;
14385
14386 DEFVAR_LISP ("w32-color-map", &Vw32_color_map,
14387 doc: /* An array of color name mappings for windows. */);
14388 Vw32_color_map = Qnil;
14389
14390 DEFVAR_LISP ("w32-pass-alt-to-system", &Vw32_pass_alt_to_system,
14391 doc: /* Non-nil if alt key presses are passed on to Windows.
14392 When non-nil, for example, alt pressed and released and then space will
14393 open the System menu. When nil, Emacs silently swallows alt key events. */);
14394 Vw32_pass_alt_to_system = Qnil;
14395
14396 DEFVAR_LISP ("w32-alt-is-meta", &Vw32_alt_is_meta,
14397 doc: /* Non-nil if the alt key is to be considered the same as the meta key.
14398 When nil, Emacs will translate the alt key to the Alt modifier, and not Meta. */);
14399 Vw32_alt_is_meta = Qt;
14400
14401 DEFVAR_INT ("w32-quit-key", &Vw32_quit_key,
14402 doc: /* If non-zero, the virtual key code for an alternative quit key. */);
14403 XSETINT (Vw32_quit_key, 0);
14404
14405 DEFVAR_LISP ("w32-pass-lwindow-to-system",
14406 &Vw32_pass_lwindow_to_system,
14407 doc: /* Non-nil if the left \"Windows\" key is passed on to Windows.
14408 When non-nil, the Start menu is opened by tapping the key. */);
14409 Vw32_pass_lwindow_to_system = Qt;
14410
14411 DEFVAR_LISP ("w32-pass-rwindow-to-system",
14412 &Vw32_pass_rwindow_to_system,
14413 doc: /* Non-nil if the right \"Windows\" key is passed on to Windows.
14414 When non-nil, the Start menu is opened by tapping the key. */);
14415 Vw32_pass_rwindow_to_system = Qt;
14416
14417 DEFVAR_INT ("w32-phantom-key-code",
14418 &Vw32_phantom_key_code,
14419 doc: /* Virtual key code used to generate \"phantom\" key presses.
14420 Value is a number between 0 and 255.
14421
14422 Phantom key presses are generated in order to stop the system from
14423 acting on \"Windows\" key events when `w32-pass-lwindow-to-system' or
14424 `w32-pass-rwindow-to-system' is nil. */);
14425 /* Although 255 is technically not a valid key code, it works and
14426 means that this hack won't interfere with any real key code. */
14427 Vw32_phantom_key_code = 255;
14428
14429 DEFVAR_LISP ("w32-enable-num-lock",
14430 &Vw32_enable_num_lock,
14431 doc: /* Non-nil if Num Lock should act normally.
14432 Set to nil to see Num Lock as the key `kp-numlock'. */);
14433 Vw32_enable_num_lock = Qt;
14434
14435 DEFVAR_LISP ("w32-enable-caps-lock",
14436 &Vw32_enable_caps_lock,
14437 doc: /* Non-nil if Caps Lock should act normally.
14438 Set to nil to see Caps Lock as the key `capslock'. */);
14439 Vw32_enable_caps_lock = Qt;
14440
14441 DEFVAR_LISP ("w32-scroll-lock-modifier",
14442 &Vw32_scroll_lock_modifier,
14443 doc: /* Modifier to use for the Scroll Lock on state.
14444 The value can be hyper, super, meta, alt, control or shift for the
14445 respective modifier, or nil to see Scroll Lock as the key `scroll'.
14446 Any other value will cause the key to be ignored. */);
14447 Vw32_scroll_lock_modifier = Qt;
14448
14449 DEFVAR_LISP ("w32-lwindow-modifier",
14450 &Vw32_lwindow_modifier,
14451 doc: /* Modifier to use for the left \"Windows\" key.
14452 The value can be hyper, super, meta, alt, control or shift for the
14453 respective modifier, or nil to appear as the key `lwindow'.
14454 Any other value will cause the key to be ignored. */);
14455 Vw32_lwindow_modifier = Qnil;
14456
14457 DEFVAR_LISP ("w32-rwindow-modifier",
14458 &Vw32_rwindow_modifier,
14459 doc: /* Modifier to use for the right \"Windows\" key.
14460 The value can be hyper, super, meta, alt, control or shift for the
14461 respective modifier, or nil to appear as the key `rwindow'.
14462 Any other value will cause the key to be ignored. */);
14463 Vw32_rwindow_modifier = Qnil;
14464
14465 DEFVAR_LISP ("w32-apps-modifier",
14466 &Vw32_apps_modifier,
14467 doc: /* Modifier to use for the \"Apps\" key.
14468 The value can be hyper, super, meta, alt, control or shift for the
14469 respective modifier, or nil to appear as the key `apps'.
14470 Any other value will cause the key to be ignored. */);
14471 Vw32_apps_modifier = Qnil;
14472
14473 DEFVAR_LISP ("w32-enable-synthesized-fonts", &Vw32_enable_synthesized_fonts,
14474 doc: /* Non-nil enables selection of artificially italicized and bold fonts. */);
14475 Vw32_enable_synthesized_fonts = Qnil;
14476
14477 DEFVAR_LISP ("w32-enable-palette", &Vw32_enable_palette,
14478 doc: /* Non-nil enables Windows palette management to map colors exactly. */);
14479 Vw32_enable_palette = Qt;
14480
14481 DEFVAR_INT ("w32-mouse-button-tolerance",
14482 &Vw32_mouse_button_tolerance,
14483 doc: /* Analogue of double click interval for faking middle mouse events.
14484 The value is the minimum time in milliseconds that must elapse between
14485 left/right button down events before they are considered distinct events.
14486 If both mouse buttons are depressed within this interval, a middle mouse
14487 button down event is generated instead. */);
14488 XSETINT (Vw32_mouse_button_tolerance, GetDoubleClickTime () / 2);
14489
14490 DEFVAR_INT ("w32-mouse-move-interval",
14491 &Vw32_mouse_move_interval,
14492 doc: /* Minimum interval between mouse move events.
14493 The value is the minimum time in milliseconds that must elapse between
14494 successive mouse move (or scroll bar drag) events before they are
14495 reported as lisp events. */);
14496 XSETINT (Vw32_mouse_move_interval, 0);
14497
14498 init_x_parm_symbols ();
14499
14500 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
14501 doc: /* List of directories to search for bitmap files for w32. */);
14502 Vx_bitmap_file_path = decode_env_path ((char *) 0, "PATH");
14503
14504 DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
14505 doc: /* The shape of the pointer when over text.
14506 Changing the value does not affect existing frames
14507 unless you set the mouse color. */);
14508 Vx_pointer_shape = Qnil;
14509
14510 DEFVAR_LISP ("x-resource-name", &Vx_resource_name,
14511 doc: /* The name Emacs uses to look up resources; for internal use only.
14512 `x-get-resource' uses this as the first component of the instance name
14513 when requesting resource values.
14514 Emacs initially sets `x-resource-name' to the name under which Emacs
14515 was invoked, or to the value specified with the `-name' or `-rn'
14516 switches, if present. */);
14517 Vx_resource_name = Qnil;
14518
14519 Vx_nontext_pointer_shape = Qnil;
14520
14521 Vx_mode_pointer_shape = Qnil;
14522
14523 DEFVAR_LISP ("x-hourglass-pointer-shape", &Vx_hourglass_pointer_shape,
14524 doc: /* The shape of the pointer when Emacs is busy.
14525 This variable takes effect when you create a new frame
14526 or when you set the mouse color. */);
14527 Vx_hourglass_pointer_shape = Qnil;
14528
14529 DEFVAR_BOOL ("display-hourglass", &display_hourglass_p,
14530 doc: /* Non-zero means Emacs displays an hourglass pointer on window systems. */);
14531 display_hourglass_p = 1;
14532
14533 DEFVAR_LISP ("hourglass-delay", &Vhourglass_delay,
14534 doc: /* *Seconds to wait before displaying an hourglass pointer.
14535 Value must be an integer or float. */);
14536 Vhourglass_delay = make_number (DEFAULT_HOURGLASS_DELAY);
14537
14538 DEFVAR_LISP ("x-sensitive-text-pointer-shape",
14539 &Vx_sensitive_text_pointer_shape,
14540 doc: /* The shape of the pointer when over mouse-sensitive text.
14541 This variable takes effect when you create a new frame
14542 or when you set the mouse color. */);
14543 Vx_sensitive_text_pointer_shape = Qnil;
14544
14545 DEFVAR_LISP ("x-window-horizontal-drag-cursor",
14546 &Vx_window_horizontal_drag_shape,
14547 doc: /* Pointer shape to use for indicating a window can be dragged horizontally.
14548 This variable takes effect when you create a new frame
14549 or when you set the mouse color. */);
14550 Vx_window_horizontal_drag_shape = Qnil;
14551
14552 DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
14553 doc: /* A string indicating the foreground color of the cursor box. */);
14554 Vx_cursor_fore_pixel = Qnil;
14555
14556 DEFVAR_LISP ("x-max-tooltip-size", &Vx_max_tooltip_size,
14557 doc: /* Maximum size for tooltips.
14558 Value is a pair (COLUMNS . ROWS). Text larger than this is clipped. */);
14559 Vx_max_tooltip_size = Fcons (make_number (80), make_number (40));
14560
14561 DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
14562 doc: /* Non-nil if no window manager is in use.
14563 Emacs doesn't try to figure this out; this is always nil
14564 unless you set it to something else. */);
14565 /* We don't have any way to find this out, so set it to nil
14566 and maybe the user would like to set it to t. */
14567 Vx_no_window_manager = Qnil;
14568
14569 DEFVAR_LISP ("x-pixel-size-width-font-regexp",
14570 &Vx_pixel_size_width_font_regexp,
14571 doc: /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'.
14572
14573 Since Emacs gets width of a font matching with this regexp from
14574 PIXEL_SIZE field of the name, font finding mechanism gets faster for
14575 such a font. This is especially effective for such large fonts as
14576 Chinese, Japanese, and Korean. */);
14577 Vx_pixel_size_width_font_regexp = Qnil;
14578
14579 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
14580 doc: /* Time after which cached images are removed from the cache.
14581 When an image has not been displayed this many seconds, remove it
14582 from the image cache. Value must be an integer or nil with nil
14583 meaning don't clear the cache. */);
14584 Vimage_cache_eviction_delay = make_number (30 * 60);
14585
14586 DEFVAR_LISP ("w32-bdf-filename-alist",
14587 &Vw32_bdf_filename_alist,
14588 doc: /* List of bdf fonts and their corresponding filenames. */);
14589 Vw32_bdf_filename_alist = Qnil;
14590
14591 DEFVAR_BOOL ("w32-strict-fontnames",
14592 &w32_strict_fontnames,
14593 doc: /* Non-nil means only use fonts that are exact matches for those requested.
14594 Default is nil, which allows old fontnames that are not XLFD compliant,
14595 and allows third-party CJK display to work by specifying false charset
14596 fields to trick Emacs into translating to Big5, SJIS etc.
14597 Setting this to t will prevent wrong fonts being selected when
14598 fontsets are automatically created. */);
14599 w32_strict_fontnames = 0;
14600
14601 DEFVAR_BOOL ("w32-strict-painting",
14602 &w32_strict_painting,
14603 doc: /* Non-nil means use strict rules for repainting frames.
14604 Set this to nil to get the old behaviour for repainting; this should
14605 only be necessary if the default setting causes problems. */);
14606 w32_strict_painting = 1;
14607
14608 DEFVAR_LISP ("w32-charset-info-alist",
14609 &Vw32_charset_info_alist,
14610 doc: /* Alist linking Emacs character sets to Windows fonts and codepages.
14611 Each entry should be of the form:
14612
14613 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE))
14614
14615 where CHARSET_NAME is a string used in font names to identify the charset,
14616 WINDOWS_CHARSET is a symbol that can be one of:
14617 w32-charset-ansi, w32-charset-default, w32-charset-symbol,
14618 w32-charset-shiftjis, w32-charset-hangeul, w32-charset-gb2312,
14619 w32-charset-chinesebig5,
14620 #ifdef JOHAB_CHARSET
14621 w32-charset-johab, w32-charset-hebrew,
14622 w32-charset-arabic, w32-charset-greek, w32-charset-turkish,
14623 w32-charset-vietnamese, w32-charset-thai, w32-charset-easteurope,
14624 w32-charset-russian, w32-charset-mac, w32-charset-baltic,
14625 #endif
14626 #ifdef UNICODE_CHARSET
14627 w32-charset-unicode,
14628 #endif
14629 or w32-charset-oem.
14630 CODEPAGE should be an integer specifying the codepage that should be used
14631 to display the character set, t to do no translation and output as Unicode,
14632 or nil to do no translation and output as 8 bit (or multibyte on far-east
14633 versions of Windows) characters. */);
14634 Vw32_charset_info_alist = Qnil;
14635
14636 staticpro (&Qw32_charset_ansi);
14637 Qw32_charset_ansi = intern ("w32-charset-ansi");
14638 staticpro (&Qw32_charset_symbol);
14639 Qw32_charset_symbol = intern ("w32-charset-symbol");
14640 staticpro (&Qw32_charset_shiftjis);
14641 Qw32_charset_shiftjis = intern ("w32-charset-shiftjis");
14642 staticpro (&Qw32_charset_hangeul);
14643 Qw32_charset_hangeul = intern ("w32-charset-hangeul");
14644 staticpro (&Qw32_charset_chinesebig5);
14645 Qw32_charset_chinesebig5 = intern ("w32-charset-chinesebig5");
14646 staticpro (&Qw32_charset_gb2312);
14647 Qw32_charset_gb2312 = intern ("w32-charset-gb2312");
14648 staticpro (&Qw32_charset_oem);
14649 Qw32_charset_oem = intern ("w32-charset-oem");
14650
14651 #ifdef JOHAB_CHARSET
14652 {
14653 static int w32_extra_charsets_defined = 1;
14654 DEFVAR_BOOL ("w32-extra-charsets-defined", &w32_extra_charsets_defined,
14655 doc: /* Internal variable. */);
14656
14657 staticpro (&Qw32_charset_johab);
14658 Qw32_charset_johab = intern ("w32-charset-johab");
14659 staticpro (&Qw32_charset_easteurope);
14660 Qw32_charset_easteurope = intern ("w32-charset-easteurope");
14661 staticpro (&Qw32_charset_turkish);
14662 Qw32_charset_turkish = intern ("w32-charset-turkish");
14663 staticpro (&Qw32_charset_baltic);
14664 Qw32_charset_baltic = intern ("w32-charset-baltic");
14665 staticpro (&Qw32_charset_russian);
14666 Qw32_charset_russian = intern ("w32-charset-russian");
14667 staticpro (&Qw32_charset_arabic);
14668 Qw32_charset_arabic = intern ("w32-charset-arabic");
14669 staticpro (&Qw32_charset_greek);
14670 Qw32_charset_greek = intern ("w32-charset-greek");
14671 staticpro (&Qw32_charset_hebrew);
14672 Qw32_charset_hebrew = intern ("w32-charset-hebrew");
14673 staticpro (&Qw32_charset_vietnamese);
14674 Qw32_charset_vietnamese = intern ("w32-charset-vietnamese");
14675 staticpro (&Qw32_charset_thai);
14676 Qw32_charset_thai = intern ("w32-charset-thai");
14677 staticpro (&Qw32_charset_mac);
14678 Qw32_charset_mac = intern ("w32-charset-mac");
14679 }
14680 #endif
14681
14682 #ifdef UNICODE_CHARSET
14683 {
14684 static int w32_unicode_charset_defined = 1;
14685 DEFVAR_BOOL ("w32-unicode-charset-defined",
14686 &w32_unicode_charset_defined,
14687 doc: /* Internal variable. */);
14688
14689 staticpro (&Qw32_charset_unicode);
14690 Qw32_charset_unicode = intern ("w32-charset-unicode");
14691 #endif
14692
14693 defsubr (&Sx_get_resource);
14694 #if 0 /* TODO: Port to W32 */
14695 defsubr (&Sx_change_window_property);
14696 defsubr (&Sx_delete_window_property);
14697 defsubr (&Sx_window_property);
14698 #endif
14699 defsubr (&Sxw_display_color_p);
14700 defsubr (&Sx_display_grayscale_p);
14701 defsubr (&Sxw_color_defined_p);
14702 defsubr (&Sxw_color_values);
14703 defsubr (&Sx_server_max_request_size);
14704 defsubr (&Sx_server_vendor);
14705 defsubr (&Sx_server_version);
14706 defsubr (&Sx_display_pixel_width);
14707 defsubr (&Sx_display_pixel_height);
14708 defsubr (&Sx_display_mm_width);
14709 defsubr (&Sx_display_mm_height);
14710 defsubr (&Sx_display_screens);
14711 defsubr (&Sx_display_planes);
14712 defsubr (&Sx_display_color_cells);
14713 defsubr (&Sx_display_visual_class);
14714 defsubr (&Sx_display_backing_store);
14715 defsubr (&Sx_display_save_under);
14716 defsubr (&Sx_parse_geometry);
14717 defsubr (&Sx_create_frame);
14718 defsubr (&Sx_open_connection);
14719 defsubr (&Sx_close_connection);
14720 defsubr (&Sx_display_list);
14721 defsubr (&Sx_synchronize);
14722
14723 /* W32 specific functions */
14724
14725 defsubr (&Sw32_focus_frame);
14726 defsubr (&Sw32_select_font);
14727 defsubr (&Sw32_define_rgb_color);
14728 defsubr (&Sw32_default_color_map);
14729 defsubr (&Sw32_load_color_file);
14730 defsubr (&Sw32_send_sys_command);
14731 defsubr (&Sw32_shell_execute);
14732 defsubr (&Sw32_register_hot_key);
14733 defsubr (&Sw32_unregister_hot_key);
14734 defsubr (&Sw32_registered_hot_keys);
14735 defsubr (&Sw32_reconstruct_hot_key);
14736 defsubr (&Sw32_toggle_lock_key);
14737 defsubr (&Sw32_find_bdf_fonts);
14738
14739 defsubr (&Sfile_system_info);
14740
14741 /* Setting callback functions for fontset handler. */
14742 get_font_info_func = w32_get_font_info;
14743
14744 #if 0 /* This function pointer doesn't seem to be used anywhere.
14745 And the pointer assigned has the wrong type, anyway. */
14746 list_fonts_func = w32_list_fonts;
14747 #endif
14748
14749 load_font_func = w32_load_font;
14750 find_ccl_program_func = w32_find_ccl_program;
14751 query_font_func = w32_query_font;
14752 set_frame_fontset_func = x_set_font;
14753 check_window_system_func = check_w32;
14754
14755 #if 0 /* TODO Image support for W32 */
14756 /* Images. */
14757 Qxbm = intern ("xbm");
14758 staticpro (&Qxbm);
14759 QCtype = intern (":type");
14760 staticpro (&QCtype);
14761 QCconversion = intern (":conversion");
14762 staticpro (&QCconversion);
14763 QCheuristic_mask = intern (":heuristic-mask");
14764 staticpro (&QCheuristic_mask);
14765 QCcolor_symbols = intern (":color-symbols");
14766 staticpro (&QCcolor_symbols);
14767 QCascent = intern (":ascent");
14768 staticpro (&QCascent);
14769 QCmargin = intern (":margin");
14770 staticpro (&QCmargin);
14771 QCrelief = intern (":relief");
14772 staticpro (&QCrelief);
14773 Qpostscript = intern ("postscript");
14774 staticpro (&Qpostscript);
14775 QCloader = intern (":loader");
14776 staticpro (&QCloader);
14777 QCbounding_box = intern (":bounding-box");
14778 staticpro (&QCbounding_box);
14779 QCpt_width = intern (":pt-width");
14780 staticpro (&QCpt_width);
14781 QCpt_height = intern (":pt-height");
14782 staticpro (&QCpt_height);
14783 QCindex = intern (":index");
14784 staticpro (&QCindex);
14785 Qpbm = intern ("pbm");
14786 staticpro (&Qpbm);
14787
14788 #if HAVE_XPM
14789 Qxpm = intern ("xpm");
14790 staticpro (&Qxpm);
14791 #endif
14792
14793 #if HAVE_JPEG
14794 Qjpeg = intern ("jpeg");
14795 staticpro (&Qjpeg);
14796 #endif
14797
14798 #if HAVE_TIFF
14799 Qtiff = intern ("tiff");
14800 staticpro (&Qtiff);
14801 #endif
14802
14803 #if HAVE_GIF
14804 Qgif = intern ("gif");
14805 staticpro (&Qgif);
14806 #endif
14807
14808 #if HAVE_PNG
14809 Qpng = intern ("png");
14810 staticpro (&Qpng);
14811 #endif
14812
14813 defsubr (&Sclear_image_cache);
14814
14815 #if GLYPH_DEBUG
14816 defsubr (&Simagep);
14817 defsubr (&Slookup_image);
14818 #endif
14819 #endif /* TODO */
14820
14821 hourglass_atimer = NULL;
14822 hourglass_shown_p = 0;
14823 defsubr (&Sx_show_tip);
14824 defsubr (&Sx_hide_tip);
14825 tip_timer = Qnil;
14826 staticpro (&tip_timer);
14827 tip_frame = Qnil;
14828 staticpro (&tip_frame);
14829
14830 last_show_tip_args = Qnil;
14831 staticpro (&last_show_tip_args);
14832
14833 defsubr (&Sx_file_dialog);
14834 }
14835
14836
14837 void
14838 init_xfns ()
14839 {
14840 image_types = NULL;
14841 Vimage_types = Qnil;
14842
14843 #if 0 /* TODO : Image support for W32 */
14844 define_image_type (&xbm_type);
14845 define_image_type (&gs_type);
14846 define_image_type (&pbm_type);
14847
14848 #if HAVE_XPM
14849 define_image_type (&xpm_type);
14850 #endif
14851
14852 #if HAVE_JPEG
14853 define_image_type (&jpeg_type);
14854 #endif
14855
14856 #if HAVE_TIFF
14857 define_image_type (&tiff_type);
14858 #endif
14859
14860 #if HAVE_GIF
14861 define_image_type (&gif_type);
14862 #endif
14863
14864 #if HAVE_PNG
14865 define_image_type (&png_type);
14866 #endif
14867 #endif /* TODO */
14868 }
14869
14870 #undef abort
14871
14872 void
14873 w32_abort()
14874 {
14875 int button;
14876 button = MessageBox (NULL,
14877 "A fatal error has occurred!\n\n"
14878 "Select Abort to exit, Retry to debug, Ignore to continue",
14879 "Emacs Abort Dialog",
14880 MB_ICONEXCLAMATION | MB_TASKMODAL
14881 | MB_SETFOREGROUND | MB_ABORTRETRYIGNORE);
14882 switch (button)
14883 {
14884 case IDRETRY:
14885 DebugBreak ();
14886 break;
14887 case IDIGNORE:
14888 break;
14889 case IDABORT:
14890 default:
14891 abort ();
14892 break;
14893 }
14894 }
14895
14896 /* For convenience when debugging. */
14897 int
14898 w32_last_error()
14899 {
14900 return GetLastError ();
14901 }