(x_set_cursor_color): Set cursor_gc as well.
[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 int w32_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 /* Flag to indicate if XBUTTON events should be passed on to Windows. */
146 int w32_pass_extra_mouse_buttons_to_system;
147
148 /* The name we're using in resource queries. */
149 Lisp_Object Vx_resource_name;
150
151 /* Non nil if no window manager is in use. */
152 Lisp_Object Vx_no_window_manager;
153
154 /* Non-zero means we're allowed to display a hourglass pointer. */
155
156 int display_hourglass_p;
157
158 /* The background and shape of the mouse pointer, and shape when not
159 over text or in the modeline. */
160
161 Lisp_Object Vx_pointer_shape, Vx_nontext_pointer_shape, Vx_mode_pointer_shape;
162 Lisp_Object Vx_hourglass_pointer_shape, Vx_window_horizontal_drag_shape;
163
164 /* The shape when over mouse-sensitive text. */
165
166 Lisp_Object Vx_sensitive_text_pointer_shape;
167
168 /* Color of chars displayed in cursor box. */
169
170 Lisp_Object Vx_cursor_fore_pixel;
171
172 /* Nonzero if using Windows. */
173
174 static int w32_in_use;
175
176 /* Search path for bitmap files. */
177
178 Lisp_Object Vx_bitmap_file_path;
179
180 /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'. */
181
182 Lisp_Object Vx_pixel_size_width_font_regexp;
183
184 /* Alist of bdf fonts and the files that define them. */
185 Lisp_Object Vw32_bdf_filename_alist;
186
187 /* A flag to control whether fonts are matched strictly or not. */
188 int w32_strict_fontnames;
189
190 /* A flag to control whether we should only repaint if GetUpdateRect
191 indicates there is an update region. */
192 int w32_strict_painting;
193
194 /* Associative list linking character set strings to Windows codepages. */
195 Lisp_Object Vw32_charset_info_alist;
196
197 /* VIETNAMESE_CHARSET is not defined in some versions of MSVC. */
198 #ifndef VIETNAMESE_CHARSET
199 #define VIETNAMESE_CHARSET 163
200 #endif
201
202 Lisp_Object Qauto_raise;
203 Lisp_Object Qauto_lower;
204 Lisp_Object Qbar;
205 Lisp_Object Qborder_color;
206 Lisp_Object Qborder_width;
207 Lisp_Object Qbox;
208 Lisp_Object Qcursor_color;
209 Lisp_Object Qcursor_type;
210 Lisp_Object Qgeometry;
211 Lisp_Object Qicon_left;
212 Lisp_Object Qicon_top;
213 Lisp_Object Qicon_type;
214 Lisp_Object Qicon_name;
215 Lisp_Object Qinternal_border_width;
216 Lisp_Object Qleft;
217 Lisp_Object Qright;
218 Lisp_Object Qmouse_color;
219 Lisp_Object Qnone;
220 Lisp_Object Qparent_id;
221 Lisp_Object Qscroll_bar_width;
222 Lisp_Object Qsuppress_icon;
223 Lisp_Object Qundefined_color;
224 Lisp_Object Qvertical_scroll_bars;
225 Lisp_Object Qvisibility;
226 Lisp_Object Qwindow_id;
227 Lisp_Object Qx_frame_parameter;
228 Lisp_Object Qx_resource_name;
229 Lisp_Object Quser_position;
230 Lisp_Object Quser_size;
231 Lisp_Object Qscreen_gamma;
232 Lisp_Object Qline_spacing;
233 Lisp_Object Qcenter;
234 Lisp_Object Qcancel_timer;
235 Lisp_Object Qhyper;
236 Lisp_Object Qsuper;
237 Lisp_Object Qmeta;
238 Lisp_Object Qalt;
239 Lisp_Object Qctrl;
240 Lisp_Object Qcontrol;
241 Lisp_Object Qshift;
242
243 Lisp_Object Qw32_charset_ansi;
244 Lisp_Object Qw32_charset_default;
245 Lisp_Object Qw32_charset_symbol;
246 Lisp_Object Qw32_charset_shiftjis;
247 Lisp_Object Qw32_charset_hangeul;
248 Lisp_Object Qw32_charset_gb2312;
249 Lisp_Object Qw32_charset_chinesebig5;
250 Lisp_Object Qw32_charset_oem;
251
252 #ifndef JOHAB_CHARSET
253 #define JOHAB_CHARSET 130
254 #endif
255 #ifdef JOHAB_CHARSET
256 Lisp_Object Qw32_charset_easteurope;
257 Lisp_Object Qw32_charset_turkish;
258 Lisp_Object Qw32_charset_baltic;
259 Lisp_Object Qw32_charset_russian;
260 Lisp_Object Qw32_charset_arabic;
261 Lisp_Object Qw32_charset_greek;
262 Lisp_Object Qw32_charset_hebrew;
263 Lisp_Object Qw32_charset_vietnamese;
264 Lisp_Object Qw32_charset_thai;
265 Lisp_Object Qw32_charset_johab;
266 Lisp_Object Qw32_charset_mac;
267 #endif
268
269 #ifdef UNICODE_CHARSET
270 Lisp_Object Qw32_charset_unicode;
271 #endif
272
273 Lisp_Object Qfullscreen;
274 Lisp_Object Qfullwidth;
275 Lisp_Object Qfullheight;
276 Lisp_Object Qfullboth;
277
278 extern Lisp_Object Qtop;
279 extern Lisp_Object Qdisplay;
280
281 /* State variables for emulating a three button mouse. */
282 #define LMOUSE 1
283 #define MMOUSE 2
284 #define RMOUSE 4
285
286 static int button_state = 0;
287 static W32Msg saved_mouse_button_msg;
288 static unsigned mouse_button_timer = 0; /* non-zero when timer is active */
289 static W32Msg saved_mouse_move_msg;
290 static unsigned mouse_move_timer = 0;
291
292 /* Window that is tracking the mouse. */
293 static HWND track_mouse_window;
294 FARPROC track_mouse_event_fn;
295
296 /* W95 mousewheel handler */
297 unsigned int msh_mousewheel = 0;
298
299 /* Timers */
300 #define MOUSE_BUTTON_ID 1
301 #define MOUSE_MOVE_ID 2
302 #define MENU_FREE_ID 3
303 /* The delay (milliseconds) before a menu is freed after WM_EXITMENULOOP
304 is received. */
305 #define MENU_FREE_DELAY 1000
306 static unsigned menu_free_timer = 0;
307
308 /* The below are defined in frame.c. */
309
310 extern Lisp_Object Qheight, Qminibuffer, Qname, Qonly, Qwidth;
311 extern Lisp_Object Qunsplittable, Qmenu_bar_lines, Qbuffer_predicate, Qtitle;
312 extern Lisp_Object Qtool_bar_lines;
313
314 extern Lisp_Object Vwindow_system_version;
315
316 Lisp_Object Qface_set_after_frame_default;
317
318 #ifdef GLYPH_DEBUG
319 int image_cache_refcount, dpyinfo_refcount;
320 #endif
321
322
323 /* From w32term.c. */
324 extern Lisp_Object Vw32_num_mouse_buttons;
325 extern Lisp_Object Vw32_recognize_altgr;
326
327 extern HWND w32_system_caret_hwnd;
328
329 extern int w32_system_caret_height;
330 extern int w32_system_caret_x;
331 extern int w32_system_caret_y;
332 extern int w32_use_visible_system_caret;
333
334 static HWND w32_visible_system_caret_hwnd;
335
336 \f
337 /* Error if we are not connected to MS-Windows. */
338 void
339 check_w32 ()
340 {
341 if (! w32_in_use)
342 error ("MS-Windows not in use or not initialized");
343 }
344
345 /* Nonzero if we can use mouse menus.
346 You should not call this unless HAVE_MENUS is defined. */
347
348 int
349 have_menus_p ()
350 {
351 return w32_in_use;
352 }
353
354 /* Extract a frame as a FRAME_PTR, defaulting to the selected frame
355 and checking validity for W32. */
356
357 FRAME_PTR
358 check_x_frame (frame)
359 Lisp_Object frame;
360 {
361 FRAME_PTR f;
362
363 if (NILP (frame))
364 frame = selected_frame;
365 CHECK_LIVE_FRAME (frame);
366 f = XFRAME (frame);
367 if (! FRAME_W32_P (f))
368 error ("non-w32 frame used");
369 return f;
370 }
371
372 /* Let the user specify an display with a frame.
373 nil stands for the selected frame--or, if that is not a w32 frame,
374 the first display on the list. */
375
376 static struct w32_display_info *
377 check_x_display_info (frame)
378 Lisp_Object frame;
379 {
380 if (NILP (frame))
381 {
382 struct frame *sf = XFRAME (selected_frame);
383
384 if (FRAME_W32_P (sf) && FRAME_LIVE_P (sf))
385 return FRAME_W32_DISPLAY_INFO (sf);
386 else
387 return &one_w32_display_info;
388 }
389 else if (STRINGP (frame))
390 return x_display_info_for_name (frame);
391 else
392 {
393 FRAME_PTR f;
394
395 CHECK_LIVE_FRAME (frame);
396 f = XFRAME (frame);
397 if (! FRAME_W32_P (f))
398 error ("non-w32 frame used");
399 return FRAME_W32_DISPLAY_INFO (f);
400 }
401 }
402 \f
403 /* Return the Emacs frame-object corresponding to an w32 window.
404 It could be the frame's main window or an icon window. */
405
406 /* This function can be called during GC, so use GC_xxx type test macros. */
407
408 struct frame *
409 x_window_to_frame (dpyinfo, wdesc)
410 struct w32_display_info *dpyinfo;
411 HWND wdesc;
412 {
413 Lisp_Object tail, frame;
414 struct frame *f;
415
416 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
417 {
418 frame = XCAR (tail);
419 if (!GC_FRAMEP (frame))
420 continue;
421 f = XFRAME (frame);
422 if (!FRAME_W32_P (f) || FRAME_W32_DISPLAY_INFO (f) != dpyinfo)
423 continue;
424 if (f->output_data.w32->hourglass_window == wdesc)
425 return f;
426
427 if (FRAME_W32_WINDOW (f) == wdesc)
428 return f;
429 }
430 return 0;
431 }
432
433 \f
434
435 /* Code to deal with bitmaps. Bitmaps are referenced by their bitmap
436 id, which is just an int that this section returns. Bitmaps are
437 reference counted so they can be shared among frames.
438
439 Bitmap indices are guaranteed to be > 0, so a negative number can
440 be used to indicate no bitmap.
441
442 If you use x_create_bitmap_from_data, then you must keep track of
443 the bitmaps yourself. That is, creating a bitmap from the same
444 data more than once will not be caught. */
445
446
447 /* Functions to access the contents of a bitmap, given an id. */
448
449 int
450 x_bitmap_height (f, id)
451 FRAME_PTR f;
452 int id;
453 {
454 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].height;
455 }
456
457 int
458 x_bitmap_width (f, id)
459 FRAME_PTR f;
460 int id;
461 {
462 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].width;
463 }
464
465 int
466 x_bitmap_pixmap (f, id)
467 FRAME_PTR f;
468 int id;
469 {
470 return (int) FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
471 }
472
473
474 /* Allocate a new bitmap record. Returns index of new record. */
475
476 static int
477 x_allocate_bitmap_record (f)
478 FRAME_PTR f;
479 {
480 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
481 int i;
482
483 if (dpyinfo->bitmaps == NULL)
484 {
485 dpyinfo->bitmaps_size = 10;
486 dpyinfo->bitmaps
487 = (struct w32_bitmap_record *) xmalloc (dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
488 dpyinfo->bitmaps_last = 1;
489 return 1;
490 }
491
492 if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size)
493 return ++dpyinfo->bitmaps_last;
494
495 for (i = 0; i < dpyinfo->bitmaps_size; ++i)
496 if (dpyinfo->bitmaps[i].refcount == 0)
497 return i + 1;
498
499 dpyinfo->bitmaps_size *= 2;
500 dpyinfo->bitmaps
501 = (struct w32_bitmap_record *) xrealloc (dpyinfo->bitmaps,
502 dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
503 return ++dpyinfo->bitmaps_last;
504 }
505
506 /* Add one reference to the reference count of the bitmap with id ID. */
507
508 void
509 x_reference_bitmap (f, id)
510 FRAME_PTR f;
511 int id;
512 {
513 ++FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
514 }
515
516 /* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at BITS. */
517
518 int
519 x_create_bitmap_from_data (f, bits, width, height)
520 struct frame *f;
521 char *bits;
522 unsigned int width, height;
523 {
524 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
525 Pixmap bitmap;
526 int id;
527
528 bitmap = CreateBitmap (width, height,
529 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_planes,
530 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_cbits,
531 bits);
532
533 if (! bitmap)
534 return -1;
535
536 id = x_allocate_bitmap_record (f);
537 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
538 dpyinfo->bitmaps[id - 1].file = NULL;
539 dpyinfo->bitmaps[id - 1].hinst = NULL;
540 dpyinfo->bitmaps[id - 1].refcount = 1;
541 dpyinfo->bitmaps[id - 1].depth = 1;
542 dpyinfo->bitmaps[id - 1].height = height;
543 dpyinfo->bitmaps[id - 1].width = width;
544
545 return id;
546 }
547
548 /* Create bitmap from file FILE for frame F. */
549
550 int
551 x_create_bitmap_from_file (f, file)
552 struct frame *f;
553 Lisp_Object file;
554 {
555 return -1;
556 #if 0 /* TODO : bitmap support */
557 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
558 unsigned int width, height;
559 HBITMAP bitmap;
560 int xhot, yhot, result, id;
561 Lisp_Object found;
562 int fd;
563 char *filename;
564 HINSTANCE hinst;
565
566 /* Look for an existing bitmap with the same name. */
567 for (id = 0; id < dpyinfo->bitmaps_last; ++id)
568 {
569 if (dpyinfo->bitmaps[id].refcount
570 && dpyinfo->bitmaps[id].file
571 && !strcmp (dpyinfo->bitmaps[id].file, (char *) XSTRING (file)->data))
572 {
573 ++dpyinfo->bitmaps[id].refcount;
574 return id + 1;
575 }
576 }
577
578 /* Search bitmap-file-path for the file, if appropriate. */
579 fd = openp (Vx_bitmap_file_path, file, Qnil, &found, 0);
580 if (fd < 0)
581 return -1;
582 emacs_close (fd);
583
584 filename = (char *) XSTRING (found)->data;
585
586 hinst = LoadLibraryEx (filename, NULL, LOAD_LIBRARY_AS_DATAFILE);
587
588 if (hinst == NULL)
589 return -1;
590
591
592 result = XReadBitmapFile (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
593 filename, &width, &height, &bitmap, &xhot, &yhot);
594 if (result != BitmapSuccess)
595 return -1;
596
597 id = x_allocate_bitmap_record (f);
598 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
599 dpyinfo->bitmaps[id - 1].refcount = 1;
600 dpyinfo->bitmaps[id - 1].file = (char *) xmalloc (XSTRING (file)->size + 1);
601 dpyinfo->bitmaps[id - 1].depth = 1;
602 dpyinfo->bitmaps[id - 1].height = height;
603 dpyinfo->bitmaps[id - 1].width = width;
604 strcpy (dpyinfo->bitmaps[id - 1].file, XSTRING (file)->data);
605
606 return id;
607 #endif /* TODO */
608 }
609
610 /* Remove reference to bitmap with id number ID. */
611
612 void
613 x_destroy_bitmap (f, id)
614 FRAME_PTR f;
615 int id;
616 {
617 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
618
619 if (id > 0)
620 {
621 --dpyinfo->bitmaps[id - 1].refcount;
622 if (dpyinfo->bitmaps[id - 1].refcount == 0)
623 {
624 BLOCK_INPUT;
625 DeleteObject (dpyinfo->bitmaps[id - 1].pixmap);
626 if (dpyinfo->bitmaps[id - 1].file)
627 {
628 xfree (dpyinfo->bitmaps[id - 1].file);
629 dpyinfo->bitmaps[id - 1].file = NULL;
630 }
631 UNBLOCK_INPUT;
632 }
633 }
634 }
635
636 /* Free all the bitmaps for the display specified by DPYINFO. */
637
638 static void
639 x_destroy_all_bitmaps (dpyinfo)
640 struct w32_display_info *dpyinfo;
641 {
642 int i;
643 for (i = 0; i < dpyinfo->bitmaps_last; i++)
644 if (dpyinfo->bitmaps[i].refcount > 0)
645 {
646 DeleteObject (dpyinfo->bitmaps[i].pixmap);
647 if (dpyinfo->bitmaps[i].file)
648 xfree (dpyinfo->bitmaps[i].file);
649 }
650 dpyinfo->bitmaps_last = 0;
651 }
652 \f
653 /* Connect the frame-parameter names for W32 frames
654 to the ways of passing the parameter values to the window system.
655
656 The name of a parameter, as a Lisp symbol,
657 has an `x-frame-parameter' property which is an integer in Lisp
658 but can be interpreted as an `enum x_frame_parm' in C. */
659
660 enum x_frame_parm
661 {
662 X_PARM_FOREGROUND_COLOR,
663 X_PARM_BACKGROUND_COLOR,
664 X_PARM_MOUSE_COLOR,
665 X_PARM_CURSOR_COLOR,
666 X_PARM_BORDER_COLOR,
667 X_PARM_ICON_TYPE,
668 X_PARM_FONT,
669 X_PARM_BORDER_WIDTH,
670 X_PARM_INTERNAL_BORDER_WIDTH,
671 X_PARM_NAME,
672 X_PARM_AUTORAISE,
673 X_PARM_AUTOLOWER,
674 X_PARM_VERT_SCROLL_BAR,
675 X_PARM_VISIBILITY,
676 X_PARM_MENU_BAR_LINES
677 };
678
679
680 struct x_frame_parm_table
681 {
682 char *name;
683 void (*setter) P_ ((struct frame *, Lisp_Object, Lisp_Object));
684 };
685
686 BOOL my_show_window P_ ((struct frame *, HWND, int));
687 void my_set_window_pos P_ ((HWND, HWND, int, int, int, int, UINT));
688 static Lisp_Object unwind_create_frame P_ ((Lisp_Object));
689 static Lisp_Object unwind_create_tip_frame P_ ((Lisp_Object));
690 static void x_change_window_heights P_ ((Lisp_Object, int));
691 /* TODO: Native Input Method support; see x_create_im. */
692 void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
693 static void x_set_line_spacing P_ ((struct frame *, Lisp_Object, Lisp_Object));
694 static void x_set_fullscreen P_ ((struct frame *, Lisp_Object, Lisp_Object));
695 void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
696 void x_set_mouse_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
697 void x_set_cursor_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
698 void x_set_border_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
699 void x_set_cursor_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
700 void x_set_icon_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
701 void x_set_icon_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
702 void x_set_font P_ ((struct frame *, Lisp_Object, Lisp_Object));
703 static void x_set_fringe_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
704 void x_set_border_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
705 void x_set_internal_border_width P_ ((struct frame *, Lisp_Object,
706 Lisp_Object));
707 void x_explicitly_set_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
708 void x_set_autoraise P_ ((struct frame *, Lisp_Object, Lisp_Object));
709 void x_set_autolower P_ ((struct frame *, Lisp_Object, Lisp_Object));
710 void x_set_vertical_scroll_bars P_ ((struct frame *, Lisp_Object,
711 Lisp_Object));
712 void x_set_visibility P_ ((struct frame *, Lisp_Object, Lisp_Object));
713 void x_set_menu_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
714 void x_set_scroll_bar_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
715 void x_set_title P_ ((struct frame *, Lisp_Object, Lisp_Object));
716 void x_set_unsplittable P_ ((struct frame *, Lisp_Object, Lisp_Object));
717 void x_set_tool_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
718 static void x_set_screen_gamma P_ ((struct frame *, Lisp_Object, Lisp_Object));
719 static void x_edge_detection P_ ((struct frame *, struct image *, Lisp_Object,
720 Lisp_Object));
721
722 static struct x_frame_parm_table x_frame_parms[] =
723 {
724 {"auto-raise", x_set_autoraise},
725 {"auto-lower", x_set_autolower},
726 {"background-color", x_set_background_color},
727 {"border-color", x_set_border_color},
728 {"border-width", x_set_border_width},
729 {"cursor-color", x_set_cursor_color},
730 {"cursor-type", x_set_cursor_type},
731 {"font", x_set_font},
732 {"foreground-color", x_set_foreground_color},
733 {"icon-name", x_set_icon_name},
734 {"icon-type", x_set_icon_type},
735 {"internal-border-width", x_set_internal_border_width},
736 {"menu-bar-lines", x_set_menu_bar_lines},
737 {"mouse-color", x_set_mouse_color},
738 {"name", x_explicitly_set_name},
739 {"scroll-bar-width", x_set_scroll_bar_width},
740 {"title", x_set_title},
741 {"unsplittable", x_set_unsplittable},
742 {"vertical-scroll-bars", x_set_vertical_scroll_bars},
743 {"visibility", x_set_visibility},
744 {"tool-bar-lines", x_set_tool_bar_lines},
745 {"screen-gamma", x_set_screen_gamma},
746 {"line-spacing", x_set_line_spacing},
747 {"left-fringe", x_set_fringe_width},
748 {"right-fringe", x_set_fringe_width},
749 {"fullscreen", x_set_fullscreen},
750 };
751
752 /* Attach the `x-frame-parameter' properties to
753 the Lisp symbol names of parameters relevant to W32. */
754
755 void
756 init_x_parm_symbols ()
757 {
758 int i;
759
760 for (i = 0; i < sizeof (x_frame_parms) / sizeof (x_frame_parms[0]); i++)
761 Fput (intern (x_frame_parms[i].name), Qx_frame_parameter,
762 make_number (i));
763 }
764 \f
765 /* Really try to move where we want to be in case of fullscreen. Some WMs
766 moves the window where we tell them. Some (mwm, twm) moves the outer
767 window manager window there instead.
768 Try to compensate for those WM here. */
769 static void
770 x_fullscreen_move (f, new_top, new_left)
771 struct frame *f;
772 int new_top;
773 int new_left;
774 {
775 if (new_top != f->output_data.w32->top_pos
776 || new_left != f->output_data.w32->left_pos)
777 {
778 int move_x = new_left;
779 int move_y = new_top;
780
781 f->output_data.w32->want_fullscreen |= FULLSCREEN_MOVE_WAIT;
782 x_set_offset (f, move_x, move_y, 1);
783 }
784 }
785
786 /* Change the parameters of frame F as specified by ALIST.
787 If a parameter is not specially recognized, do nothing;
788 otherwise call the `x_set_...' function for that parameter. */
789
790 void
791 x_set_frame_parameters (f, alist)
792 FRAME_PTR f;
793 Lisp_Object alist;
794 {
795 Lisp_Object tail;
796
797 /* If both of these parameters are present, it's more efficient to
798 set them both at once. So we wait until we've looked at the
799 entire list before we set them. */
800 int width, height;
801
802 /* Same here. */
803 Lisp_Object left, top;
804
805 /* Same with these. */
806 Lisp_Object icon_left, icon_top;
807
808 /* Record in these vectors all the parms specified. */
809 Lisp_Object *parms;
810 Lisp_Object *values;
811 int i, p;
812 int left_no_change = 0, top_no_change = 0;
813 int icon_left_no_change = 0, icon_top_no_change = 0;
814 int fullscreen_is_being_set = 0;
815
816 struct gcpro gcpro1, gcpro2;
817
818 i = 0;
819 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
820 i++;
821
822 parms = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
823 values = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
824
825 /* Extract parm names and values into those vectors. */
826
827 i = 0;
828 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
829 {
830 Lisp_Object elt;
831
832 elt = Fcar (tail);
833 parms[i] = Fcar (elt);
834 values[i] = Fcdr (elt);
835 i++;
836 }
837 /* TAIL and ALIST are not used again below here. */
838 alist = tail = Qnil;
839
840 GCPRO2 (*parms, *values);
841 gcpro1.nvars = i;
842 gcpro2.nvars = i;
843
844 /* There is no need to gcpro LEFT, TOP, ICON_LEFT, or ICON_TOP,
845 because their values appear in VALUES and strings are not valid. */
846 top = left = Qunbound;
847 icon_left = icon_top = Qunbound;
848
849 /* Provide default values for HEIGHT and WIDTH. */
850 if (FRAME_NEW_WIDTH (f))
851 width = FRAME_NEW_WIDTH (f);
852 else
853 width = FRAME_WIDTH (f);
854
855 if (FRAME_NEW_HEIGHT (f))
856 height = FRAME_NEW_HEIGHT (f);
857 else
858 height = FRAME_HEIGHT (f);
859
860 /* Process foreground_color and background_color before anything else.
861 They are independent of other properties, but other properties (e.g.,
862 cursor_color) are dependent upon them. */
863 /* Process default font as well, since fringe widths depends on it. */
864 for (p = 0; p < i; p++)
865 {
866 Lisp_Object prop, val;
867
868 prop = parms[p];
869 val = values[p];
870 if (EQ (prop, Qforeground_color)
871 || EQ (prop, Qbackground_color)
872 || EQ (prop, Qfont)
873 || EQ (prop, Qfullscreen))
874 {
875 register Lisp_Object param_index, old_value;
876
877 old_value = get_frame_param (f, prop);
878 fullscreen_is_being_set |= EQ (prop, Qfullscreen);
879
880 if (NILP (Fequal (val, old_value)))
881 {
882 store_frame_param (f, prop, val);
883
884 param_index = Fget (prop, Qx_frame_parameter);
885 if (NATNUMP (param_index)
886 && (XFASTINT (param_index)
887 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
888 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
889 }
890 }
891 }
892
893 /* Now process them in reverse of specified order. */
894 for (i--; i >= 0; i--)
895 {
896 Lisp_Object prop, val;
897
898 prop = parms[i];
899 val = values[i];
900
901 if (EQ (prop, Qwidth) && NUMBERP (val))
902 width = XFASTINT (val);
903 else if (EQ (prop, Qheight) && NUMBERP (val))
904 height = XFASTINT (val);
905 else if (EQ (prop, Qtop))
906 top = val;
907 else if (EQ (prop, Qleft))
908 left = val;
909 else if (EQ (prop, Qicon_top))
910 icon_top = val;
911 else if (EQ (prop, Qicon_left))
912 icon_left = val;
913 else if (EQ (prop, Qforeground_color)
914 || EQ (prop, Qbackground_color)
915 || EQ (prop, Qfont)
916 || EQ (prop, Qfullscreen))
917 /* Processed above. */
918 continue;
919 else
920 {
921 register Lisp_Object param_index, old_value;
922
923 old_value = get_frame_param (f, prop);
924
925 store_frame_param (f, prop, val);
926
927 param_index = Fget (prop, Qx_frame_parameter);
928 if (NATNUMP (param_index)
929 && (XFASTINT (param_index)
930 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
931 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
932 }
933 }
934
935 /* Don't die if just one of these was set. */
936 if (EQ (left, Qunbound))
937 {
938 left_no_change = 1;
939 if (f->output_data.w32->left_pos < 0)
940 left = Fcons (Qplus, Fcons (make_number (f->output_data.w32->left_pos), Qnil));
941 else
942 XSETINT (left, f->output_data.w32->left_pos);
943 }
944 if (EQ (top, Qunbound))
945 {
946 top_no_change = 1;
947 if (f->output_data.w32->top_pos < 0)
948 top = Fcons (Qplus, Fcons (make_number (f->output_data.w32->top_pos), Qnil));
949 else
950 XSETINT (top, f->output_data.w32->top_pos);
951 }
952
953 /* If one of the icon positions was not set, preserve or default it. */
954 if (EQ (icon_left, Qunbound) || ! INTEGERP (icon_left))
955 {
956 icon_left_no_change = 1;
957 icon_left = Fcdr (Fassq (Qicon_left, f->param_alist));
958 if (NILP (icon_left))
959 XSETINT (icon_left, 0);
960 }
961 if (EQ (icon_top, Qunbound) || ! INTEGERP (icon_top))
962 {
963 icon_top_no_change = 1;
964 icon_top = Fcdr (Fassq (Qicon_top, f->param_alist));
965 if (NILP (icon_top))
966 XSETINT (icon_top, 0);
967 }
968
969 if (FRAME_VISIBLE_P (f) && fullscreen_is_being_set)
970 {
971 /* If the frame is visible already and the fullscreen parameter is
972 being set, it is too late to set WM manager hints to specify
973 size and position.
974 Here we first get the width, height and position that applies to
975 fullscreen. We then move the frame to the appropriate
976 position. Resize of the frame is taken care of in the code after
977 this if-statement. */
978 int new_left, new_top;
979
980 x_fullscreen_adjust (f, &width, &height, &new_top, &new_left);
981 x_fullscreen_move (f, new_top, new_left);
982 }
983
984 /* Don't set these parameters unless they've been explicitly
985 specified. The window might be mapped or resized while we're in
986 this function, and we don't want to override that unless the lisp
987 code has asked for it.
988
989 Don't set these parameters unless they actually differ from the
990 window's current parameters; the window may not actually exist
991 yet. */
992 {
993 Lisp_Object frame;
994
995 check_frame_size (f, &height, &width);
996
997 XSETFRAME (frame, f);
998
999 if (width != FRAME_WIDTH (f)
1000 || height != FRAME_HEIGHT (f)
1001 || FRAME_NEW_HEIGHT (f) || FRAME_NEW_WIDTH (f))
1002 Fset_frame_size (frame, make_number (width), make_number (height));
1003
1004 if ((!NILP (left) || !NILP (top))
1005 && ! (left_no_change && top_no_change)
1006 && ! (NUMBERP (left) && XINT (left) == f->output_data.w32->left_pos
1007 && NUMBERP (top) && XINT (top) == f->output_data.w32->top_pos))
1008 {
1009 int leftpos = 0;
1010 int toppos = 0;
1011
1012 /* Record the signs. */
1013 f->output_data.w32->size_hint_flags &= ~ (XNegative | YNegative);
1014 if (EQ (left, Qminus))
1015 f->output_data.w32->size_hint_flags |= XNegative;
1016 else if (INTEGERP (left))
1017 {
1018 leftpos = XINT (left);
1019 if (leftpos < 0)
1020 f->output_data.w32->size_hint_flags |= XNegative;
1021 }
1022 else if (CONSP (left) && EQ (XCAR (left), Qminus)
1023 && CONSP (XCDR (left))
1024 && INTEGERP (XCAR (XCDR (left))))
1025 {
1026 leftpos = - XINT (XCAR (XCDR (left)));
1027 f->output_data.w32->size_hint_flags |= XNegative;
1028 }
1029 else if (CONSP (left) && EQ (XCAR (left), Qplus)
1030 && CONSP (XCDR (left))
1031 && INTEGERP (XCAR (XCDR (left))))
1032 {
1033 leftpos = XINT (XCAR (XCDR (left)));
1034 }
1035
1036 if (EQ (top, Qminus))
1037 f->output_data.w32->size_hint_flags |= YNegative;
1038 else if (INTEGERP (top))
1039 {
1040 toppos = XINT (top);
1041 if (toppos < 0)
1042 f->output_data.w32->size_hint_flags |= YNegative;
1043 }
1044 else if (CONSP (top) && EQ (XCAR (top), Qminus)
1045 && CONSP (XCDR (top))
1046 && INTEGERP (XCAR (XCDR (top))))
1047 {
1048 toppos = - XINT (XCAR (XCDR (top)));
1049 f->output_data.w32->size_hint_flags |= YNegative;
1050 }
1051 else if (CONSP (top) && EQ (XCAR (top), Qplus)
1052 && CONSP (XCDR (top))
1053 && INTEGERP (XCAR (XCDR (top))))
1054 {
1055 toppos = XINT (XCAR (XCDR (top)));
1056 }
1057
1058
1059 /* Store the numeric value of the position. */
1060 f->output_data.w32->top_pos = toppos;
1061 f->output_data.w32->left_pos = leftpos;
1062
1063 f->output_data.w32->win_gravity = NorthWestGravity;
1064
1065 /* Actually set that position, and convert to absolute. */
1066 x_set_offset (f, leftpos, toppos, -1);
1067 }
1068
1069 if ((!NILP (icon_left) || !NILP (icon_top))
1070 && ! (icon_left_no_change && icon_top_no_change))
1071 x_wm_set_icon_position (f, XINT (icon_left), XINT (icon_top));
1072 }
1073
1074 UNGCPRO;
1075 }
1076
1077 /* Store the screen positions of frame F into XPTR and YPTR.
1078 These are the positions of the containing window manager window,
1079 not Emacs's own window. */
1080
1081 void
1082 x_real_positions (f, xptr, yptr)
1083 FRAME_PTR f;
1084 int *xptr, *yptr;
1085 {
1086 POINT pt;
1087 RECT rect;
1088
1089 GetClientRect(FRAME_W32_WINDOW(f), &rect);
1090 AdjustWindowRect(&rect, f->output_data.w32->dwStyle, FRAME_EXTERNAL_MENU_BAR(f));
1091
1092 pt.x = rect.left;
1093 pt.y = rect.top;
1094
1095 ClientToScreen (FRAME_W32_WINDOW(f), &pt);
1096
1097 /* Remember x_pixels_diff and y_pixels_diff. */
1098 f->output_data.w32->x_pixels_diff = pt.x - rect.left;
1099 f->output_data.w32->y_pixels_diff = pt.y - rect.top;
1100
1101 *xptr = pt.x;
1102 *yptr = pt.y;
1103 }
1104
1105 /* Insert a description of internally-recorded parameters of frame X
1106 into the parameter alist *ALISTPTR that is to be given to the user.
1107 Only parameters that are specific to W32
1108 and whose values are not correctly recorded in the frame's
1109 param_alist need to be considered here. */
1110
1111 void
1112 x_report_frame_params (f, alistptr)
1113 struct frame *f;
1114 Lisp_Object *alistptr;
1115 {
1116 char buf[16];
1117 Lisp_Object tem;
1118
1119 /* Represent negative positions (off the top or left screen edge)
1120 in a way that Fmodify_frame_parameters will understand correctly. */
1121 XSETINT (tem, f->output_data.w32->left_pos);
1122 if (f->output_data.w32->left_pos >= 0)
1123 store_in_alist (alistptr, Qleft, tem);
1124 else
1125 store_in_alist (alistptr, Qleft, Fcons (Qplus, Fcons (tem, Qnil)));
1126
1127 XSETINT (tem, f->output_data.w32->top_pos);
1128 if (f->output_data.w32->top_pos >= 0)
1129 store_in_alist (alistptr, Qtop, tem);
1130 else
1131 store_in_alist (alistptr, Qtop, Fcons (Qplus, Fcons (tem, Qnil)));
1132
1133 store_in_alist (alistptr, Qborder_width,
1134 make_number (f->output_data.w32->border_width));
1135 store_in_alist (alistptr, Qinternal_border_width,
1136 make_number (f->output_data.w32->internal_border_width));
1137 store_in_alist (alistptr, Qleft_fringe,
1138 make_number (f->output_data.w32->left_fringe_width));
1139 store_in_alist (alistptr, Qright_fringe,
1140 make_number (f->output_data.w32->right_fringe_width));
1141 store_in_alist (alistptr, Qscroll_bar_width,
1142 make_number (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
1143 ? FRAME_SCROLL_BAR_PIXEL_WIDTH(f)
1144 : 0));
1145 sprintf (buf, "%ld", (long) FRAME_W32_WINDOW (f));
1146 store_in_alist (alistptr, Qwindow_id,
1147 build_string (buf));
1148 store_in_alist (alistptr, Qicon_name, f->icon_name);
1149 FRAME_SAMPLE_VISIBILITY (f);
1150 store_in_alist (alistptr, Qvisibility,
1151 (FRAME_VISIBLE_P (f) ? Qt
1152 : FRAME_ICONIFIED_P (f) ? Qicon : Qnil));
1153 store_in_alist (alistptr, Qdisplay,
1154 XCAR (FRAME_W32_DISPLAY_INFO (f)->name_list_element));
1155 }
1156 \f
1157
1158 DEFUN ("w32-define-rgb-color", Fw32_define_rgb_color,
1159 Sw32_define_rgb_color, 4, 4, 0,
1160 doc: /* Convert RGB numbers to a windows color reference and associate with NAME.
1161 This adds or updates a named color to w32-color-map, making it
1162 available for use. The original entry's RGB ref is returned, or nil
1163 if the entry is new. */)
1164 (red, green, blue, name)
1165 Lisp_Object red, green, blue, name;
1166 {
1167 Lisp_Object rgb;
1168 Lisp_Object oldrgb = Qnil;
1169 Lisp_Object entry;
1170
1171 CHECK_NUMBER (red);
1172 CHECK_NUMBER (green);
1173 CHECK_NUMBER (blue);
1174 CHECK_STRING (name);
1175
1176 XSET (rgb, Lisp_Int, RGB(XUINT (red), XUINT (green), XUINT (blue)));
1177
1178 BLOCK_INPUT;
1179
1180 /* replace existing entry in w32-color-map or add new entry. */
1181 entry = Fassoc (name, Vw32_color_map);
1182 if (NILP (entry))
1183 {
1184 entry = Fcons (name, rgb);
1185 Vw32_color_map = Fcons (entry, Vw32_color_map);
1186 }
1187 else
1188 {
1189 oldrgb = Fcdr (entry);
1190 Fsetcdr (entry, rgb);
1191 }
1192
1193 UNBLOCK_INPUT;
1194
1195 return (oldrgb);
1196 }
1197
1198 DEFUN ("w32-load-color-file", Fw32_load_color_file,
1199 Sw32_load_color_file, 1, 1, 0,
1200 doc: /* Create an alist of color entries from an external file.
1201 Assign this value to w32-color-map to replace the existing color map.
1202
1203 The file should define one named RGB color per line like so:
1204 R G B name
1205 where R,G,B are numbers between 0 and 255 and name is an arbitrary string. */)
1206 (filename)
1207 Lisp_Object filename;
1208 {
1209 FILE *fp;
1210 Lisp_Object cmap = Qnil;
1211 Lisp_Object abspath;
1212
1213 CHECK_STRING (filename);
1214 abspath = Fexpand_file_name (filename, Qnil);
1215
1216 fp = fopen (XSTRING (filename)->data, "rt");
1217 if (fp)
1218 {
1219 char buf[512];
1220 int red, green, blue;
1221 int num;
1222
1223 BLOCK_INPUT;
1224
1225 while (fgets (buf, sizeof (buf), fp) != NULL) {
1226 if (sscanf (buf, "%u %u %u %n", &red, &green, &blue, &num) == 3)
1227 {
1228 char *name = buf + num;
1229 num = strlen (name) - 1;
1230 if (name[num] == '\n')
1231 name[num] = 0;
1232 cmap = Fcons (Fcons (build_string (name),
1233 make_number (RGB (red, green, blue))),
1234 cmap);
1235 }
1236 }
1237 fclose (fp);
1238
1239 UNBLOCK_INPUT;
1240 }
1241
1242 return cmap;
1243 }
1244
1245 /* The default colors for the w32 color map */
1246 typedef struct colormap_t
1247 {
1248 char *name;
1249 COLORREF colorref;
1250 } colormap_t;
1251
1252 colormap_t w32_color_map[] =
1253 {
1254 {"snow" , PALETTERGB (255,250,250)},
1255 {"ghost white" , PALETTERGB (248,248,255)},
1256 {"GhostWhite" , PALETTERGB (248,248,255)},
1257 {"white smoke" , PALETTERGB (245,245,245)},
1258 {"WhiteSmoke" , PALETTERGB (245,245,245)},
1259 {"gainsboro" , PALETTERGB (220,220,220)},
1260 {"floral white" , PALETTERGB (255,250,240)},
1261 {"FloralWhite" , PALETTERGB (255,250,240)},
1262 {"old lace" , PALETTERGB (253,245,230)},
1263 {"OldLace" , PALETTERGB (253,245,230)},
1264 {"linen" , PALETTERGB (250,240,230)},
1265 {"antique white" , PALETTERGB (250,235,215)},
1266 {"AntiqueWhite" , PALETTERGB (250,235,215)},
1267 {"papaya whip" , PALETTERGB (255,239,213)},
1268 {"PapayaWhip" , PALETTERGB (255,239,213)},
1269 {"blanched almond" , PALETTERGB (255,235,205)},
1270 {"BlanchedAlmond" , PALETTERGB (255,235,205)},
1271 {"bisque" , PALETTERGB (255,228,196)},
1272 {"peach puff" , PALETTERGB (255,218,185)},
1273 {"PeachPuff" , PALETTERGB (255,218,185)},
1274 {"navajo white" , PALETTERGB (255,222,173)},
1275 {"NavajoWhite" , PALETTERGB (255,222,173)},
1276 {"moccasin" , PALETTERGB (255,228,181)},
1277 {"cornsilk" , PALETTERGB (255,248,220)},
1278 {"ivory" , PALETTERGB (255,255,240)},
1279 {"lemon chiffon" , PALETTERGB (255,250,205)},
1280 {"LemonChiffon" , PALETTERGB (255,250,205)},
1281 {"seashell" , PALETTERGB (255,245,238)},
1282 {"honeydew" , PALETTERGB (240,255,240)},
1283 {"mint cream" , PALETTERGB (245,255,250)},
1284 {"MintCream" , PALETTERGB (245,255,250)},
1285 {"azure" , PALETTERGB (240,255,255)},
1286 {"alice blue" , PALETTERGB (240,248,255)},
1287 {"AliceBlue" , PALETTERGB (240,248,255)},
1288 {"lavender" , PALETTERGB (230,230,250)},
1289 {"lavender blush" , PALETTERGB (255,240,245)},
1290 {"LavenderBlush" , PALETTERGB (255,240,245)},
1291 {"misty rose" , PALETTERGB (255,228,225)},
1292 {"MistyRose" , PALETTERGB (255,228,225)},
1293 {"white" , PALETTERGB (255,255,255)},
1294 {"black" , PALETTERGB ( 0, 0, 0)},
1295 {"dark slate gray" , PALETTERGB ( 47, 79, 79)},
1296 {"DarkSlateGray" , PALETTERGB ( 47, 79, 79)},
1297 {"dark slate grey" , PALETTERGB ( 47, 79, 79)},
1298 {"DarkSlateGrey" , PALETTERGB ( 47, 79, 79)},
1299 {"dim gray" , PALETTERGB (105,105,105)},
1300 {"DimGray" , PALETTERGB (105,105,105)},
1301 {"dim grey" , PALETTERGB (105,105,105)},
1302 {"DimGrey" , PALETTERGB (105,105,105)},
1303 {"slate gray" , PALETTERGB (112,128,144)},
1304 {"SlateGray" , PALETTERGB (112,128,144)},
1305 {"slate grey" , PALETTERGB (112,128,144)},
1306 {"SlateGrey" , PALETTERGB (112,128,144)},
1307 {"light slate gray" , PALETTERGB (119,136,153)},
1308 {"LightSlateGray" , PALETTERGB (119,136,153)},
1309 {"light slate grey" , PALETTERGB (119,136,153)},
1310 {"LightSlateGrey" , PALETTERGB (119,136,153)},
1311 {"gray" , PALETTERGB (190,190,190)},
1312 {"grey" , PALETTERGB (190,190,190)},
1313 {"light grey" , PALETTERGB (211,211,211)},
1314 {"LightGrey" , PALETTERGB (211,211,211)},
1315 {"light gray" , PALETTERGB (211,211,211)},
1316 {"LightGray" , PALETTERGB (211,211,211)},
1317 {"midnight blue" , PALETTERGB ( 25, 25,112)},
1318 {"MidnightBlue" , PALETTERGB ( 25, 25,112)},
1319 {"navy" , PALETTERGB ( 0, 0,128)},
1320 {"navy blue" , PALETTERGB ( 0, 0,128)},
1321 {"NavyBlue" , PALETTERGB ( 0, 0,128)},
1322 {"cornflower blue" , PALETTERGB (100,149,237)},
1323 {"CornflowerBlue" , PALETTERGB (100,149,237)},
1324 {"dark slate blue" , PALETTERGB ( 72, 61,139)},
1325 {"DarkSlateBlue" , PALETTERGB ( 72, 61,139)},
1326 {"slate blue" , PALETTERGB (106, 90,205)},
1327 {"SlateBlue" , PALETTERGB (106, 90,205)},
1328 {"medium slate blue" , PALETTERGB (123,104,238)},
1329 {"MediumSlateBlue" , PALETTERGB (123,104,238)},
1330 {"light slate blue" , PALETTERGB (132,112,255)},
1331 {"LightSlateBlue" , PALETTERGB (132,112,255)},
1332 {"medium blue" , PALETTERGB ( 0, 0,205)},
1333 {"MediumBlue" , PALETTERGB ( 0, 0,205)},
1334 {"royal blue" , PALETTERGB ( 65,105,225)},
1335 {"RoyalBlue" , PALETTERGB ( 65,105,225)},
1336 {"blue" , PALETTERGB ( 0, 0,255)},
1337 {"dodger blue" , PALETTERGB ( 30,144,255)},
1338 {"DodgerBlue" , PALETTERGB ( 30,144,255)},
1339 {"deep sky blue" , PALETTERGB ( 0,191,255)},
1340 {"DeepSkyBlue" , PALETTERGB ( 0,191,255)},
1341 {"sky blue" , PALETTERGB (135,206,235)},
1342 {"SkyBlue" , PALETTERGB (135,206,235)},
1343 {"light sky blue" , PALETTERGB (135,206,250)},
1344 {"LightSkyBlue" , PALETTERGB (135,206,250)},
1345 {"steel blue" , PALETTERGB ( 70,130,180)},
1346 {"SteelBlue" , PALETTERGB ( 70,130,180)},
1347 {"light steel blue" , PALETTERGB (176,196,222)},
1348 {"LightSteelBlue" , PALETTERGB (176,196,222)},
1349 {"light blue" , PALETTERGB (173,216,230)},
1350 {"LightBlue" , PALETTERGB (173,216,230)},
1351 {"powder blue" , PALETTERGB (176,224,230)},
1352 {"PowderBlue" , PALETTERGB (176,224,230)},
1353 {"pale turquoise" , PALETTERGB (175,238,238)},
1354 {"PaleTurquoise" , PALETTERGB (175,238,238)},
1355 {"dark turquoise" , PALETTERGB ( 0,206,209)},
1356 {"DarkTurquoise" , PALETTERGB ( 0,206,209)},
1357 {"medium turquoise" , PALETTERGB ( 72,209,204)},
1358 {"MediumTurquoise" , PALETTERGB ( 72,209,204)},
1359 {"turquoise" , PALETTERGB ( 64,224,208)},
1360 {"cyan" , PALETTERGB ( 0,255,255)},
1361 {"light cyan" , PALETTERGB (224,255,255)},
1362 {"LightCyan" , PALETTERGB (224,255,255)},
1363 {"cadet blue" , PALETTERGB ( 95,158,160)},
1364 {"CadetBlue" , PALETTERGB ( 95,158,160)},
1365 {"medium aquamarine" , PALETTERGB (102,205,170)},
1366 {"MediumAquamarine" , PALETTERGB (102,205,170)},
1367 {"aquamarine" , PALETTERGB (127,255,212)},
1368 {"dark green" , PALETTERGB ( 0,100, 0)},
1369 {"DarkGreen" , PALETTERGB ( 0,100, 0)},
1370 {"dark olive green" , PALETTERGB ( 85,107, 47)},
1371 {"DarkOliveGreen" , PALETTERGB ( 85,107, 47)},
1372 {"dark sea green" , PALETTERGB (143,188,143)},
1373 {"DarkSeaGreen" , PALETTERGB (143,188,143)},
1374 {"sea green" , PALETTERGB ( 46,139, 87)},
1375 {"SeaGreen" , PALETTERGB ( 46,139, 87)},
1376 {"medium sea green" , PALETTERGB ( 60,179,113)},
1377 {"MediumSeaGreen" , PALETTERGB ( 60,179,113)},
1378 {"light sea green" , PALETTERGB ( 32,178,170)},
1379 {"LightSeaGreen" , PALETTERGB ( 32,178,170)},
1380 {"pale green" , PALETTERGB (152,251,152)},
1381 {"PaleGreen" , PALETTERGB (152,251,152)},
1382 {"spring green" , PALETTERGB ( 0,255,127)},
1383 {"SpringGreen" , PALETTERGB ( 0,255,127)},
1384 {"lawn green" , PALETTERGB (124,252, 0)},
1385 {"LawnGreen" , PALETTERGB (124,252, 0)},
1386 {"green" , PALETTERGB ( 0,255, 0)},
1387 {"chartreuse" , PALETTERGB (127,255, 0)},
1388 {"medium spring green" , PALETTERGB ( 0,250,154)},
1389 {"MediumSpringGreen" , PALETTERGB ( 0,250,154)},
1390 {"green yellow" , PALETTERGB (173,255, 47)},
1391 {"GreenYellow" , PALETTERGB (173,255, 47)},
1392 {"lime green" , PALETTERGB ( 50,205, 50)},
1393 {"LimeGreen" , PALETTERGB ( 50,205, 50)},
1394 {"yellow green" , PALETTERGB (154,205, 50)},
1395 {"YellowGreen" , PALETTERGB (154,205, 50)},
1396 {"forest green" , PALETTERGB ( 34,139, 34)},
1397 {"ForestGreen" , PALETTERGB ( 34,139, 34)},
1398 {"olive drab" , PALETTERGB (107,142, 35)},
1399 {"OliveDrab" , PALETTERGB (107,142, 35)},
1400 {"dark khaki" , PALETTERGB (189,183,107)},
1401 {"DarkKhaki" , PALETTERGB (189,183,107)},
1402 {"khaki" , PALETTERGB (240,230,140)},
1403 {"pale goldenrod" , PALETTERGB (238,232,170)},
1404 {"PaleGoldenrod" , PALETTERGB (238,232,170)},
1405 {"light goldenrod yellow" , PALETTERGB (250,250,210)},
1406 {"LightGoldenrodYellow" , PALETTERGB (250,250,210)},
1407 {"light yellow" , PALETTERGB (255,255,224)},
1408 {"LightYellow" , PALETTERGB (255,255,224)},
1409 {"yellow" , PALETTERGB (255,255, 0)},
1410 {"gold" , PALETTERGB (255,215, 0)},
1411 {"light goldenrod" , PALETTERGB (238,221,130)},
1412 {"LightGoldenrod" , PALETTERGB (238,221,130)},
1413 {"goldenrod" , PALETTERGB (218,165, 32)},
1414 {"dark goldenrod" , PALETTERGB (184,134, 11)},
1415 {"DarkGoldenrod" , PALETTERGB (184,134, 11)},
1416 {"rosy brown" , PALETTERGB (188,143,143)},
1417 {"RosyBrown" , PALETTERGB (188,143,143)},
1418 {"indian red" , PALETTERGB (205, 92, 92)},
1419 {"IndianRed" , PALETTERGB (205, 92, 92)},
1420 {"saddle brown" , PALETTERGB (139, 69, 19)},
1421 {"SaddleBrown" , PALETTERGB (139, 69, 19)},
1422 {"sienna" , PALETTERGB (160, 82, 45)},
1423 {"peru" , PALETTERGB (205,133, 63)},
1424 {"burlywood" , PALETTERGB (222,184,135)},
1425 {"beige" , PALETTERGB (245,245,220)},
1426 {"wheat" , PALETTERGB (245,222,179)},
1427 {"sandy brown" , PALETTERGB (244,164, 96)},
1428 {"SandyBrown" , PALETTERGB (244,164, 96)},
1429 {"tan" , PALETTERGB (210,180,140)},
1430 {"chocolate" , PALETTERGB (210,105, 30)},
1431 {"firebrick" , PALETTERGB (178,34, 34)},
1432 {"brown" , PALETTERGB (165,42, 42)},
1433 {"dark salmon" , PALETTERGB (233,150,122)},
1434 {"DarkSalmon" , PALETTERGB (233,150,122)},
1435 {"salmon" , PALETTERGB (250,128,114)},
1436 {"light salmon" , PALETTERGB (255,160,122)},
1437 {"LightSalmon" , PALETTERGB (255,160,122)},
1438 {"orange" , PALETTERGB (255,165, 0)},
1439 {"dark orange" , PALETTERGB (255,140, 0)},
1440 {"DarkOrange" , PALETTERGB (255,140, 0)},
1441 {"coral" , PALETTERGB (255,127, 80)},
1442 {"light coral" , PALETTERGB (240,128,128)},
1443 {"LightCoral" , PALETTERGB (240,128,128)},
1444 {"tomato" , PALETTERGB (255, 99, 71)},
1445 {"orange red" , PALETTERGB (255, 69, 0)},
1446 {"OrangeRed" , PALETTERGB (255, 69, 0)},
1447 {"red" , PALETTERGB (255, 0, 0)},
1448 {"hot pink" , PALETTERGB (255,105,180)},
1449 {"HotPink" , PALETTERGB (255,105,180)},
1450 {"deep pink" , PALETTERGB (255, 20,147)},
1451 {"DeepPink" , PALETTERGB (255, 20,147)},
1452 {"pink" , PALETTERGB (255,192,203)},
1453 {"light pink" , PALETTERGB (255,182,193)},
1454 {"LightPink" , PALETTERGB (255,182,193)},
1455 {"pale violet red" , PALETTERGB (219,112,147)},
1456 {"PaleVioletRed" , PALETTERGB (219,112,147)},
1457 {"maroon" , PALETTERGB (176, 48, 96)},
1458 {"medium violet red" , PALETTERGB (199, 21,133)},
1459 {"MediumVioletRed" , PALETTERGB (199, 21,133)},
1460 {"violet red" , PALETTERGB (208, 32,144)},
1461 {"VioletRed" , PALETTERGB (208, 32,144)},
1462 {"magenta" , PALETTERGB (255, 0,255)},
1463 {"violet" , PALETTERGB (238,130,238)},
1464 {"plum" , PALETTERGB (221,160,221)},
1465 {"orchid" , PALETTERGB (218,112,214)},
1466 {"medium orchid" , PALETTERGB (186, 85,211)},
1467 {"MediumOrchid" , PALETTERGB (186, 85,211)},
1468 {"dark orchid" , PALETTERGB (153, 50,204)},
1469 {"DarkOrchid" , PALETTERGB (153, 50,204)},
1470 {"dark violet" , PALETTERGB (148, 0,211)},
1471 {"DarkViolet" , PALETTERGB (148, 0,211)},
1472 {"blue violet" , PALETTERGB (138, 43,226)},
1473 {"BlueViolet" , PALETTERGB (138, 43,226)},
1474 {"purple" , PALETTERGB (160, 32,240)},
1475 {"medium purple" , PALETTERGB (147,112,219)},
1476 {"MediumPurple" , PALETTERGB (147,112,219)},
1477 {"thistle" , PALETTERGB (216,191,216)},
1478 {"gray0" , PALETTERGB ( 0, 0, 0)},
1479 {"grey0" , PALETTERGB ( 0, 0, 0)},
1480 {"dark grey" , PALETTERGB (169,169,169)},
1481 {"DarkGrey" , PALETTERGB (169,169,169)},
1482 {"dark gray" , PALETTERGB (169,169,169)},
1483 {"DarkGray" , PALETTERGB (169,169,169)},
1484 {"dark blue" , PALETTERGB ( 0, 0,139)},
1485 {"DarkBlue" , PALETTERGB ( 0, 0,139)},
1486 {"dark cyan" , PALETTERGB ( 0,139,139)},
1487 {"DarkCyan" , PALETTERGB ( 0,139,139)},
1488 {"dark magenta" , PALETTERGB (139, 0,139)},
1489 {"DarkMagenta" , PALETTERGB (139, 0,139)},
1490 {"dark red" , PALETTERGB (139, 0, 0)},
1491 {"DarkRed" , PALETTERGB (139, 0, 0)},
1492 {"light green" , PALETTERGB (144,238,144)},
1493 {"LightGreen" , PALETTERGB (144,238,144)},
1494 };
1495
1496 DEFUN ("w32-default-color-map", Fw32_default_color_map, Sw32_default_color_map,
1497 0, 0, 0, doc: /* Return the default color map. */)
1498 ()
1499 {
1500 int i;
1501 colormap_t *pc = w32_color_map;
1502 Lisp_Object cmap;
1503
1504 BLOCK_INPUT;
1505
1506 cmap = Qnil;
1507
1508 for (i = 0; i < sizeof (w32_color_map) / sizeof (w32_color_map[0]);
1509 pc++, i++)
1510 cmap = Fcons (Fcons (build_string (pc->name),
1511 make_number (pc->colorref)),
1512 cmap);
1513
1514 UNBLOCK_INPUT;
1515
1516 return (cmap);
1517 }
1518
1519 Lisp_Object
1520 w32_to_x_color (rgb)
1521 Lisp_Object rgb;
1522 {
1523 Lisp_Object color;
1524
1525 CHECK_NUMBER (rgb);
1526
1527 BLOCK_INPUT;
1528
1529 color = Frassq (rgb, Vw32_color_map);
1530
1531 UNBLOCK_INPUT;
1532
1533 if (!NILP (color))
1534 return (Fcar (color));
1535 else
1536 return Qnil;
1537 }
1538
1539 COLORREF
1540 w32_color_map_lookup (colorname)
1541 char *colorname;
1542 {
1543 Lisp_Object tail, ret = Qnil;
1544
1545 BLOCK_INPUT;
1546
1547 for (tail = Vw32_color_map; !NILP (tail); tail = Fcdr (tail))
1548 {
1549 register Lisp_Object elt, tem;
1550
1551 elt = Fcar (tail);
1552 if (!CONSP (elt)) continue;
1553
1554 tem = Fcar (elt);
1555
1556 if (lstrcmpi (XSTRING (tem)->data, colorname) == 0)
1557 {
1558 ret = XUINT (Fcdr (elt));
1559 break;
1560 }
1561
1562 QUIT;
1563 }
1564
1565
1566 UNBLOCK_INPUT;
1567
1568 return ret;
1569 }
1570
1571 COLORREF
1572 x_to_w32_color (colorname)
1573 char * colorname;
1574 {
1575 register Lisp_Object ret = Qnil;
1576
1577 BLOCK_INPUT;
1578
1579 if (colorname[0] == '#')
1580 {
1581 /* Could be an old-style RGB Device specification. */
1582 char *color;
1583 int size;
1584 color = colorname + 1;
1585
1586 size = strlen(color);
1587 if (size == 3 || size == 6 || size == 9 || size == 12)
1588 {
1589 UINT colorval;
1590 int i, pos;
1591 pos = 0;
1592 size /= 3;
1593 colorval = 0;
1594
1595 for (i = 0; i < 3; i++)
1596 {
1597 char *end;
1598 char t;
1599 unsigned long value;
1600
1601 /* The check for 'x' in the following conditional takes into
1602 account the fact that strtol allows a "0x" in front of
1603 our numbers, and we don't. */
1604 if (!isxdigit(color[0]) || color[1] == 'x')
1605 break;
1606 t = color[size];
1607 color[size] = '\0';
1608 value = strtoul(color, &end, 16);
1609 color[size] = t;
1610 if (errno == ERANGE || end - color != size)
1611 break;
1612 switch (size)
1613 {
1614 case 1:
1615 value = value * 0x10;
1616 break;
1617 case 2:
1618 break;
1619 case 3:
1620 value /= 0x10;
1621 break;
1622 case 4:
1623 value /= 0x100;
1624 break;
1625 }
1626 colorval |= (value << pos);
1627 pos += 0x8;
1628 if (i == 2)
1629 {
1630 UNBLOCK_INPUT;
1631 return (colorval);
1632 }
1633 color = end;
1634 }
1635 }
1636 }
1637 else if (strnicmp(colorname, "rgb:", 4) == 0)
1638 {
1639 char *color;
1640 UINT colorval;
1641 int i, pos;
1642 pos = 0;
1643
1644 colorval = 0;
1645 color = colorname + 4;
1646 for (i = 0; i < 3; i++)
1647 {
1648 char *end;
1649 unsigned long value;
1650
1651 /* The check for 'x' in the following conditional takes into
1652 account the fact that strtol allows a "0x" in front of
1653 our numbers, and we don't. */
1654 if (!isxdigit(color[0]) || color[1] == 'x')
1655 break;
1656 value = strtoul(color, &end, 16);
1657 if (errno == ERANGE)
1658 break;
1659 switch (end - color)
1660 {
1661 case 1:
1662 value = value * 0x10 + value;
1663 break;
1664 case 2:
1665 break;
1666 case 3:
1667 value /= 0x10;
1668 break;
1669 case 4:
1670 value /= 0x100;
1671 break;
1672 default:
1673 value = ULONG_MAX;
1674 }
1675 if (value == ULONG_MAX)
1676 break;
1677 colorval |= (value << pos);
1678 pos += 0x8;
1679 if (i == 2)
1680 {
1681 if (*end != '\0')
1682 break;
1683 UNBLOCK_INPUT;
1684 return (colorval);
1685 }
1686 if (*end != '/')
1687 break;
1688 color = end + 1;
1689 }
1690 }
1691 else if (strnicmp(colorname, "rgbi:", 5) == 0)
1692 {
1693 /* This is an RGB Intensity specification. */
1694 char *color;
1695 UINT colorval;
1696 int i, pos;
1697 pos = 0;
1698
1699 colorval = 0;
1700 color = colorname + 5;
1701 for (i = 0; i < 3; i++)
1702 {
1703 char *end;
1704 double value;
1705 UINT val;
1706
1707 value = strtod(color, &end);
1708 if (errno == ERANGE)
1709 break;
1710 if (value < 0.0 || value > 1.0)
1711 break;
1712 val = (UINT)(0x100 * value);
1713 /* We used 0x100 instead of 0xFF to give an continuous
1714 range between 0.0 and 1.0 inclusive. The next statement
1715 fixes the 1.0 case. */
1716 if (val == 0x100)
1717 val = 0xFF;
1718 colorval |= (val << pos);
1719 pos += 0x8;
1720 if (i == 2)
1721 {
1722 if (*end != '\0')
1723 break;
1724 UNBLOCK_INPUT;
1725 return (colorval);
1726 }
1727 if (*end != '/')
1728 break;
1729 color = end + 1;
1730 }
1731 }
1732 /* I am not going to attempt to handle any of the CIE color schemes
1733 or TekHVC, since I don't know the algorithms for conversion to
1734 RGB. */
1735
1736 /* If we fail to lookup the color name in w32_color_map, then check the
1737 colorname to see if it can be crudely approximated: If the X color
1738 ends in a number (e.g., "darkseagreen2"), strip the number and
1739 return the result of looking up the base color name. */
1740 ret = w32_color_map_lookup (colorname);
1741 if (NILP (ret))
1742 {
1743 int len = strlen (colorname);
1744
1745 if (isdigit (colorname[len - 1]))
1746 {
1747 char *ptr, *approx = alloca (len + 1);
1748
1749 strcpy (approx, colorname);
1750 ptr = &approx[len - 1];
1751 while (ptr > approx && isdigit (*ptr))
1752 *ptr-- = '\0';
1753
1754 ret = w32_color_map_lookup (approx);
1755 }
1756 }
1757
1758 UNBLOCK_INPUT;
1759 return ret;
1760 }
1761
1762
1763 void
1764 w32_regenerate_palette (FRAME_PTR f)
1765 {
1766 struct w32_palette_entry * list;
1767 LOGPALETTE * log_palette;
1768 HPALETTE new_palette;
1769 int i;
1770
1771 /* don't bother trying to create palette if not supported */
1772 if (! FRAME_W32_DISPLAY_INFO (f)->has_palette)
1773 return;
1774
1775 log_palette = (LOGPALETTE *)
1776 alloca (sizeof (LOGPALETTE) +
1777 FRAME_W32_DISPLAY_INFO (f)->num_colors * sizeof (PALETTEENTRY));
1778 log_palette->palVersion = 0x300;
1779 log_palette->palNumEntries = FRAME_W32_DISPLAY_INFO (f)->num_colors;
1780
1781 list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1782 for (i = 0;
1783 i < FRAME_W32_DISPLAY_INFO (f)->num_colors;
1784 i++, list = list->next)
1785 log_palette->palPalEntry[i] = list->entry;
1786
1787 new_palette = CreatePalette (log_palette);
1788
1789 enter_crit ();
1790
1791 if (FRAME_W32_DISPLAY_INFO (f)->palette)
1792 DeleteObject (FRAME_W32_DISPLAY_INFO (f)->palette);
1793 FRAME_W32_DISPLAY_INFO (f)->palette = new_palette;
1794
1795 /* Realize display palette and garbage all frames. */
1796 release_frame_dc (f, get_frame_dc (f));
1797
1798 leave_crit ();
1799 }
1800
1801 #define W32_COLOR(pe) RGB (pe.peRed, pe.peGreen, pe.peBlue)
1802 #define SET_W32_COLOR(pe, color) \
1803 do \
1804 { \
1805 pe.peRed = GetRValue (color); \
1806 pe.peGreen = GetGValue (color); \
1807 pe.peBlue = GetBValue (color); \
1808 pe.peFlags = 0; \
1809 } while (0)
1810
1811 #if 0
1812 /* Keep these around in case we ever want to track color usage. */
1813 void
1814 w32_map_color (FRAME_PTR f, COLORREF color)
1815 {
1816 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1817
1818 if (NILP (Vw32_enable_palette))
1819 return;
1820
1821 /* check if color is already mapped */
1822 while (list)
1823 {
1824 if (W32_COLOR (list->entry) == color)
1825 {
1826 ++list->refcount;
1827 return;
1828 }
1829 list = list->next;
1830 }
1831
1832 /* not already mapped, so add to list and recreate Windows palette */
1833 list = (struct w32_palette_entry *)
1834 xmalloc (sizeof (struct w32_palette_entry));
1835 SET_W32_COLOR (list->entry, color);
1836 list->refcount = 1;
1837 list->next = FRAME_W32_DISPLAY_INFO (f)->color_list;
1838 FRAME_W32_DISPLAY_INFO (f)->color_list = list;
1839 FRAME_W32_DISPLAY_INFO (f)->num_colors++;
1840
1841 /* set flag that palette must be regenerated */
1842 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
1843 }
1844
1845 void
1846 w32_unmap_color (FRAME_PTR f, COLORREF color)
1847 {
1848 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1849 struct w32_palette_entry **prev = &FRAME_W32_DISPLAY_INFO (f)->color_list;
1850
1851 if (NILP (Vw32_enable_palette))
1852 return;
1853
1854 /* check if color is already mapped */
1855 while (list)
1856 {
1857 if (W32_COLOR (list->entry) == color)
1858 {
1859 if (--list->refcount == 0)
1860 {
1861 *prev = list->next;
1862 xfree (list);
1863 FRAME_W32_DISPLAY_INFO (f)->num_colors--;
1864 break;
1865 }
1866 else
1867 return;
1868 }
1869 prev = &list->next;
1870 list = list->next;
1871 }
1872
1873 /* set flag that palette must be regenerated */
1874 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
1875 }
1876 #endif
1877
1878
1879 /* Gamma-correct COLOR on frame F. */
1880
1881 void
1882 gamma_correct (f, color)
1883 struct frame *f;
1884 COLORREF *color;
1885 {
1886 if (f->gamma)
1887 {
1888 *color = PALETTERGB (
1889 pow (GetRValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1890 pow (GetGValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1891 pow (GetBValue (*color) / 255.0, f->gamma) * 255.0 + 0.5);
1892 }
1893 }
1894
1895
1896 /* Decide if color named COLOR is valid for the display associated with
1897 the selected frame; if so, return the rgb values in COLOR_DEF.
1898 If ALLOC is nonzero, allocate a new colormap cell. */
1899
1900 int
1901 w32_defined_color (f, color, color_def, alloc)
1902 FRAME_PTR f;
1903 char *color;
1904 XColor *color_def;
1905 int alloc;
1906 {
1907 register Lisp_Object tem;
1908 COLORREF w32_color_ref;
1909
1910 tem = x_to_w32_color (color);
1911
1912 if (!NILP (tem))
1913 {
1914 if (f)
1915 {
1916 /* Apply gamma correction. */
1917 w32_color_ref = XUINT (tem);
1918 gamma_correct (f, &w32_color_ref);
1919 XSETINT (tem, w32_color_ref);
1920 }
1921
1922 /* Map this color to the palette if it is enabled. */
1923 if (!NILP (Vw32_enable_palette))
1924 {
1925 struct w32_palette_entry * entry =
1926 one_w32_display_info.color_list;
1927 struct w32_palette_entry ** prev =
1928 &one_w32_display_info.color_list;
1929
1930 /* check if color is already mapped */
1931 while (entry)
1932 {
1933 if (W32_COLOR (entry->entry) == XUINT (tem))
1934 break;
1935 prev = &entry->next;
1936 entry = entry->next;
1937 }
1938
1939 if (entry == NULL && alloc)
1940 {
1941 /* not already mapped, so add to list */
1942 entry = (struct w32_palette_entry *)
1943 xmalloc (sizeof (struct w32_palette_entry));
1944 SET_W32_COLOR (entry->entry, XUINT (tem));
1945 entry->next = NULL;
1946 *prev = entry;
1947 one_w32_display_info.num_colors++;
1948
1949 /* set flag that palette must be regenerated */
1950 one_w32_display_info.regen_palette = TRUE;
1951 }
1952 }
1953 /* Ensure COLORREF value is snapped to nearest color in (default)
1954 palette by simulating the PALETTERGB macro. This works whether
1955 or not the display device has a palette. */
1956 w32_color_ref = XUINT (tem) | 0x2000000;
1957
1958 color_def->pixel = w32_color_ref;
1959 color_def->red = GetRValue (w32_color_ref);
1960 color_def->green = GetGValue (w32_color_ref);
1961 color_def->blue = GetBValue (w32_color_ref);
1962
1963 return 1;
1964 }
1965 else
1966 {
1967 return 0;
1968 }
1969 }
1970
1971 /* Given a string ARG naming a color, compute a pixel value from it
1972 suitable for screen F.
1973 If F is not a color screen, return DEF (default) regardless of what
1974 ARG says. */
1975
1976 int
1977 x_decode_color (f, arg, def)
1978 FRAME_PTR f;
1979 Lisp_Object arg;
1980 int def;
1981 {
1982 XColor cdef;
1983
1984 CHECK_STRING (arg);
1985
1986 if (strcmp (XSTRING (arg)->data, "black") == 0)
1987 return BLACK_PIX_DEFAULT (f);
1988 else if (strcmp (XSTRING (arg)->data, "white") == 0)
1989 return WHITE_PIX_DEFAULT (f);
1990
1991 if ((FRAME_W32_DISPLAY_INFO (f)->n_planes * FRAME_W32_DISPLAY_INFO (f)->n_cbits) == 1)
1992 return def;
1993
1994 /* w32_defined_color is responsible for coping with failures
1995 by looking for a near-miss. */
1996 if (w32_defined_color (f, XSTRING (arg)->data, &cdef, 1))
1997 return cdef.pixel;
1998
1999 /* defined_color failed; return an ultimate default. */
2000 return def;
2001 }
2002 \f
2003 /* Change the `line-spacing' frame parameter of frame F. OLD_VALUE is
2004 the previous value of that parameter, NEW_VALUE is the new value. */
2005
2006 static void
2007 x_set_line_spacing (f, new_value, old_value)
2008 struct frame *f;
2009 Lisp_Object new_value, old_value;
2010 {
2011 if (NILP (new_value))
2012 f->extra_line_spacing = 0;
2013 else if (NATNUMP (new_value))
2014 f->extra_line_spacing = XFASTINT (new_value);
2015 else
2016 Fsignal (Qerror, Fcons (build_string ("Invalid line-spacing"),
2017 Fcons (new_value, Qnil)));
2018 if (FRAME_VISIBLE_P (f))
2019 redraw_frame (f);
2020 }
2021
2022
2023 /* Change the `fullscreen' frame parameter of frame F. OLD_VALUE is
2024 the previous value of that parameter, NEW_VALUE is the new value. */
2025
2026 static void
2027 x_set_fullscreen (f, new_value, old_value)
2028 struct frame *f;
2029 Lisp_Object new_value, old_value;
2030 {
2031 if (NILP (new_value))
2032 f->output_data.w32->want_fullscreen = FULLSCREEN_NONE;
2033 else if (EQ (new_value, Qfullboth))
2034 f->output_data.w32->want_fullscreen = FULLSCREEN_BOTH;
2035 else if (EQ (new_value, Qfullwidth))
2036 f->output_data.w32->want_fullscreen = FULLSCREEN_WIDTH;
2037 else if (EQ (new_value, Qfullheight))
2038 f->output_data.w32->want_fullscreen = FULLSCREEN_HEIGHT;
2039 }
2040
2041
2042 /* Change the `screen-gamma' frame parameter of frame F. OLD_VALUE is
2043 the previous value of that parameter, NEW_VALUE is the new value. */
2044
2045 static void
2046 x_set_screen_gamma (f, new_value, old_value)
2047 struct frame *f;
2048 Lisp_Object new_value, old_value;
2049 {
2050 if (NILP (new_value))
2051 f->gamma = 0;
2052 else if (NUMBERP (new_value) && XFLOATINT (new_value) > 0)
2053 /* The value 0.4545 is the normal viewing gamma. */
2054 f->gamma = 1.0 / (0.4545 * XFLOATINT (new_value));
2055 else
2056 Fsignal (Qerror, Fcons (build_string ("Invalid screen-gamma"),
2057 Fcons (new_value, Qnil)));
2058
2059 clear_face_cache (0);
2060 }
2061
2062
2063 /* Functions called only from `x_set_frame_param'
2064 to set individual parameters.
2065
2066 If FRAME_W32_WINDOW (f) is 0,
2067 the frame is being created and its window does not exist yet.
2068 In that case, just record the parameter's new value
2069 in the standard place; do not attempt to change the window. */
2070
2071 void
2072 x_set_foreground_color (f, arg, oldval)
2073 struct frame *f;
2074 Lisp_Object arg, oldval;
2075 {
2076 struct w32_output *x = f->output_data.w32;
2077 PIX_TYPE fg, old_fg;
2078
2079 fg = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2080 old_fg = FRAME_FOREGROUND_PIXEL (f);
2081 FRAME_FOREGROUND_PIXEL (f) = fg;
2082
2083 if (FRAME_W32_WINDOW (f) != 0)
2084 {
2085 if (x->cursor_pixel == old_fg)
2086 x->cursor_pixel = fg;
2087
2088 update_face_from_frame_parameter (f, Qforeground_color, arg);
2089 if (FRAME_VISIBLE_P (f))
2090 redraw_frame (f);
2091 }
2092 }
2093
2094 void
2095 x_set_background_color (f, arg, oldval)
2096 struct frame *f;
2097 Lisp_Object arg, oldval;
2098 {
2099 FRAME_BACKGROUND_PIXEL (f)
2100 = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
2101
2102 if (FRAME_W32_WINDOW (f) != 0)
2103 {
2104 SetWindowLong (FRAME_W32_WINDOW (f), WND_BACKGROUND_INDEX,
2105 FRAME_BACKGROUND_PIXEL (f));
2106
2107 update_face_from_frame_parameter (f, Qbackground_color, arg);
2108
2109 if (FRAME_VISIBLE_P (f))
2110 redraw_frame (f);
2111 }
2112 }
2113
2114 void
2115 x_set_mouse_color (f, arg, oldval)
2116 struct frame *f;
2117 Lisp_Object arg, oldval;
2118 {
2119 Cursor cursor, nontext_cursor, mode_cursor, cross_cursor;
2120 int count;
2121 int mask_color;
2122
2123 if (!EQ (Qnil, arg))
2124 f->output_data.w32->mouse_pixel
2125 = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2126 mask_color = FRAME_BACKGROUND_PIXEL (f);
2127
2128 /* Don't let pointers be invisible. */
2129 if (mask_color == f->output_data.w32->mouse_pixel
2130 && mask_color == FRAME_BACKGROUND_PIXEL (f))
2131 f->output_data.w32->mouse_pixel = FRAME_FOREGROUND_PIXEL (f);
2132
2133 #if 0 /* TODO : cursor changes */
2134 BLOCK_INPUT;
2135
2136 /* It's not okay to crash if the user selects a screwy cursor. */
2137 count = x_catch_errors (FRAME_W32_DISPLAY (f));
2138
2139 if (!EQ (Qnil, Vx_pointer_shape))
2140 {
2141 CHECK_NUMBER (Vx_pointer_shape);
2142 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XINT (Vx_pointer_shape));
2143 }
2144 else
2145 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2146 x_check_errors (FRAME_W32_DISPLAY (f), "bad text pointer cursor: %s");
2147
2148 if (!EQ (Qnil, Vx_nontext_pointer_shape))
2149 {
2150 CHECK_NUMBER (Vx_nontext_pointer_shape);
2151 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2152 XINT (Vx_nontext_pointer_shape));
2153 }
2154 else
2155 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_left_ptr);
2156 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
2157
2158 if (!EQ (Qnil, Vx_hourglass_pointer_shape))
2159 {
2160 CHECK_NUMBER (Vx_hourglass_pointer_shape);
2161 hourglass_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2162 XINT (Vx_hourglass_pointer_shape));
2163 }
2164 else
2165 hourglass_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_watch);
2166 x_check_errors (FRAME_W32_DISPLAY (f), "bad busy pointer cursor: %s");
2167
2168 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
2169 if (!EQ (Qnil, Vx_mode_pointer_shape))
2170 {
2171 CHECK_NUMBER (Vx_mode_pointer_shape);
2172 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2173 XINT (Vx_mode_pointer_shape));
2174 }
2175 else
2176 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2177 x_check_errors (FRAME_W32_DISPLAY (f), "bad modeline pointer cursor: %s");
2178
2179 if (!EQ (Qnil, Vx_sensitive_text_pointer_shape))
2180 {
2181 CHECK_NUMBER (Vx_sensitive_text_pointer_shape);
2182 cross_cursor
2183 = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2184 XINT (Vx_sensitive_text_pointer_shape));
2185 }
2186 else
2187 cross_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_crosshair);
2188
2189 if (!NILP (Vx_window_horizontal_drag_shape))
2190 {
2191 CHECK_NUMBER (Vx_window_horizontal_drag_shape);
2192 horizontal_drag_cursor
2193 = XCreateFontCursor (FRAME_X_DISPLAY (f),
2194 XINT (Vx_window_horizontal_drag_shape));
2195 }
2196 else
2197 horizontal_drag_cursor
2198 = XCreateFontCursor (FRAME_X_DISPLAY (f), XC_sb_h_double_arrow);
2199
2200 /* Check and report errors with the above calls. */
2201 x_check_errors (FRAME_W32_DISPLAY (f), "can't set cursor shape: %s");
2202 x_uncatch_errors (FRAME_W32_DISPLAY (f), count);
2203
2204 {
2205 XColor fore_color, back_color;
2206
2207 fore_color.pixel = f->output_data.w32->mouse_pixel;
2208 back_color.pixel = mask_color;
2209 XQueryColor (FRAME_W32_DISPLAY (f),
2210 DefaultColormap (FRAME_W32_DISPLAY (f),
2211 DefaultScreen (FRAME_W32_DISPLAY (f))),
2212 &fore_color);
2213 XQueryColor (FRAME_W32_DISPLAY (f),
2214 DefaultColormap (FRAME_W32_DISPLAY (f),
2215 DefaultScreen (FRAME_W32_DISPLAY (f))),
2216 &back_color);
2217 XRecolorCursor (FRAME_W32_DISPLAY (f), cursor,
2218 &fore_color, &back_color);
2219 XRecolorCursor (FRAME_W32_DISPLAY (f), nontext_cursor,
2220 &fore_color, &back_color);
2221 XRecolorCursor (FRAME_W32_DISPLAY (f), mode_cursor,
2222 &fore_color, &back_color);
2223 XRecolorCursor (FRAME_W32_DISPLAY (f), cross_cursor,
2224 &fore_color, &back_color);
2225 XRecolorCursor (FRAME_W32_DISPLAY (f), hourglass_cursor,
2226 &fore_color, &back_color);
2227 }
2228
2229 if (FRAME_W32_WINDOW (f) != 0)
2230 XDefineCursor (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), cursor);
2231
2232 if (cursor != f->output_data.w32->text_cursor && f->output_data.w32->text_cursor != 0)
2233 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->text_cursor);
2234 f->output_data.w32->text_cursor = cursor;
2235
2236 if (nontext_cursor != f->output_data.w32->nontext_cursor
2237 && f->output_data.w32->nontext_cursor != 0)
2238 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->nontext_cursor);
2239 f->output_data.w32->nontext_cursor = nontext_cursor;
2240
2241 if (hourglass_cursor != f->output_data.w32->hourglass_cursor
2242 && f->output_data.w32->hourglass_cursor != 0)
2243 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->hourglass_cursor);
2244 f->output_data.w32->hourglass_cursor = hourglass_cursor;
2245
2246 if (mode_cursor != f->output_data.w32->modeline_cursor
2247 && f->output_data.w32->modeline_cursor != 0)
2248 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->modeline_cursor);
2249 f->output_data.w32->modeline_cursor = mode_cursor;
2250
2251 if (cross_cursor != f->output_data.w32->cross_cursor
2252 && f->output_data.w32->cross_cursor != 0)
2253 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->cross_cursor);
2254 f->output_data.w32->cross_cursor = cross_cursor;
2255
2256 XFlush (FRAME_W32_DISPLAY (f));
2257 UNBLOCK_INPUT;
2258
2259 update_face_from_frame_parameter (f, Qmouse_color, arg);
2260 #endif /* TODO */
2261 }
2262
2263 /* Defined in w32term.c. */
2264 void x_update_cursor (struct frame *f, int on_p);
2265
2266 void
2267 x_set_cursor_color (f, arg, oldval)
2268 struct frame *f;
2269 Lisp_Object arg, oldval;
2270 {
2271 unsigned long fore_pixel, pixel;
2272
2273 if (!NILP (Vx_cursor_fore_pixel))
2274 fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel,
2275 WHITE_PIX_DEFAULT (f));
2276 else
2277 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
2278
2279 pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2280
2281 /* Make sure that the cursor color differs from the background color. */
2282 if (pixel == FRAME_BACKGROUND_PIXEL (f))
2283 {
2284 pixel = f->output_data.w32->mouse_pixel;
2285 if (pixel == fore_pixel)
2286 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
2287 }
2288
2289 f->output_data.w32->cursor_foreground_pixel = fore_pixel;
2290 f->output_data.w32->cursor_pixel = pixel;
2291
2292 if (FRAME_W32_WINDOW (f) != 0)
2293 {
2294 BLOCK_INPUT;
2295 /* Update frame's cursor_gc. */
2296 f->output_data.w32->cursor_gc->foreground = fore_pixel;
2297 f->output_data.w32->cursor_gc->background = pixel;
2298
2299 UNBLOCK_INPUT;
2300
2301 if (FRAME_VISIBLE_P (f))
2302 {
2303 x_update_cursor (f, 0);
2304 x_update_cursor (f, 1);
2305 }
2306 }
2307
2308 update_face_from_frame_parameter (f, Qcursor_color, arg);
2309 }
2310
2311 /* Set the border-color of frame F to pixel value PIX.
2312 Note that this does not fully take effect if done before
2313 F has an window. */
2314 void
2315 x_set_border_pixel (f, pix)
2316 struct frame *f;
2317 int pix;
2318 {
2319 f->output_data.w32->border_pixel = pix;
2320
2321 if (FRAME_W32_WINDOW (f) != 0 && f->output_data.w32->border_width > 0)
2322 {
2323 if (FRAME_VISIBLE_P (f))
2324 redraw_frame (f);
2325 }
2326 }
2327
2328 /* Set the border-color of frame F to value described by ARG.
2329 ARG can be a string naming a color.
2330 The border-color is used for the border that is drawn by the server.
2331 Note that this does not fully take effect if done before
2332 F has a window; it must be redone when the window is created. */
2333
2334 void
2335 x_set_border_color (f, arg, oldval)
2336 struct frame *f;
2337 Lisp_Object arg, oldval;
2338 {
2339 int pix;
2340
2341 CHECK_STRING (arg);
2342 pix = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2343 x_set_border_pixel (f, pix);
2344 update_face_from_frame_parameter (f, Qborder_color, arg);
2345 }
2346
2347 /* Value is the internal representation of the specified cursor type
2348 ARG. If type is BAR_CURSOR, return in *WIDTH the specified width
2349 of the bar cursor. */
2350
2351 enum text_cursor_kinds
2352 x_specified_cursor_type (arg, width)
2353 Lisp_Object arg;
2354 int *width;
2355 {
2356 enum text_cursor_kinds type;
2357
2358 if (EQ (arg, Qbar))
2359 {
2360 type = BAR_CURSOR;
2361 *width = 2;
2362 }
2363 else if (CONSP (arg)
2364 && EQ (XCAR (arg), Qbar)
2365 && INTEGERP (XCDR (arg))
2366 && XINT (XCDR (arg)) >= 0)
2367 {
2368 type = BAR_CURSOR;
2369 *width = XINT (XCDR (arg));
2370 }
2371 else if (NILP (arg))
2372 type = NO_CURSOR;
2373 else
2374 /* Treat anything unknown as "box cursor".
2375 It was bad to signal an error; people have trouble fixing
2376 .Xdefaults with Emacs, when it has something bad in it. */
2377 type = FILLED_BOX_CURSOR;
2378
2379 return type;
2380 }
2381
2382 void
2383 x_set_cursor_type (f, arg, oldval)
2384 FRAME_PTR f;
2385 Lisp_Object arg, oldval;
2386 {
2387 int width;
2388
2389 FRAME_DESIRED_CURSOR (f) = x_specified_cursor_type (arg, &width);
2390 f->output_data.w32->cursor_width = width;
2391
2392 /* Make sure the cursor gets redrawn. This is overkill, but how
2393 often do people change cursor types? */
2394 update_mode_lines++;
2395 }
2396 \f
2397 void
2398 x_set_icon_type (f, arg, oldval)
2399 struct frame *f;
2400 Lisp_Object arg, oldval;
2401 {
2402 int result;
2403
2404 if (NILP (arg) && NILP (oldval))
2405 return;
2406
2407 if (STRINGP (arg) && STRINGP (oldval)
2408 && EQ (Fstring_equal (oldval, arg), Qt))
2409 return;
2410
2411 if (SYMBOLP (arg) && SYMBOLP (oldval) && EQ (arg, oldval))
2412 return;
2413
2414 BLOCK_INPUT;
2415
2416 result = x_bitmap_icon (f, arg);
2417 if (result)
2418 {
2419 UNBLOCK_INPUT;
2420 error ("No icon window available");
2421 }
2422
2423 UNBLOCK_INPUT;
2424 }
2425
2426 /* Return non-nil if frame F wants a bitmap icon. */
2427
2428 Lisp_Object
2429 x_icon_type (f)
2430 FRAME_PTR f;
2431 {
2432 Lisp_Object tem;
2433
2434 tem = assq_no_quit (Qicon_type, f->param_alist);
2435 if (CONSP (tem))
2436 return XCDR (tem);
2437 else
2438 return Qnil;
2439 }
2440
2441 void
2442 x_set_icon_name (f, arg, oldval)
2443 struct frame *f;
2444 Lisp_Object arg, oldval;
2445 {
2446 if (STRINGP (arg))
2447 {
2448 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
2449 return;
2450 }
2451 else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
2452 return;
2453
2454 f->icon_name = arg;
2455
2456 #if 0
2457 if (f->output_data.w32->icon_bitmap != 0)
2458 return;
2459
2460 BLOCK_INPUT;
2461
2462 result = x_text_icon (f,
2463 (char *) XSTRING ((!NILP (f->icon_name)
2464 ? f->icon_name
2465 : !NILP (f->title)
2466 ? f->title
2467 : f->name))->data);
2468
2469 if (result)
2470 {
2471 UNBLOCK_INPUT;
2472 error ("No icon window available");
2473 }
2474
2475 /* If the window was unmapped (and its icon was mapped),
2476 the new icon is not mapped, so map the window in its stead. */
2477 if (FRAME_VISIBLE_P (f))
2478 {
2479 #ifdef USE_X_TOOLKIT
2480 XtPopup (f->output_data.w32->widget, XtGrabNone);
2481 #endif
2482 XMapWindow (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f));
2483 }
2484
2485 XFlush (FRAME_W32_DISPLAY (f));
2486 UNBLOCK_INPUT;
2487 #endif
2488 }
2489
2490 extern Lisp_Object x_new_font ();
2491 extern Lisp_Object x_new_fontset();
2492
2493 void
2494 x_set_font (f, arg, oldval)
2495 struct frame *f;
2496 Lisp_Object arg, oldval;
2497 {
2498 Lisp_Object result;
2499 Lisp_Object fontset_name;
2500 Lisp_Object frame;
2501 int old_fontset = FRAME_FONTSET(f);
2502
2503 CHECK_STRING (arg);
2504
2505 fontset_name = Fquery_fontset (arg, Qnil);
2506
2507 BLOCK_INPUT;
2508 result = (STRINGP (fontset_name)
2509 ? x_new_fontset (f, XSTRING (fontset_name)->data)
2510 : x_new_font (f, XSTRING (arg)->data));
2511 UNBLOCK_INPUT;
2512
2513 if (EQ (result, Qnil))
2514 error ("Font `%s' is not defined", XSTRING (arg)->data);
2515 else if (EQ (result, Qt))
2516 error ("The characters of the given font have varying widths");
2517 else if (STRINGP (result))
2518 {
2519 if (STRINGP (fontset_name))
2520 {
2521 /* Fontset names are built from ASCII font names, so the
2522 names may be equal despite there was a change. */
2523 if (old_fontset == FRAME_FONTSET (f))
2524 return;
2525 }
2526 else if (!NILP (Fequal (result, oldval)))
2527 return;
2528
2529 store_frame_param (f, Qfont, result);
2530 recompute_basic_faces (f);
2531 }
2532 else
2533 abort ();
2534
2535 do_pending_window_change (0);
2536
2537 /* Don't call `face-set-after-frame-default' when faces haven't been
2538 initialized yet. This is the case when called from
2539 Fx_create_frame. In that case, the X widget or window doesn't
2540 exist either, and we can end up in x_report_frame_params with a
2541 null widget which gives a segfault. */
2542 if (FRAME_FACE_CACHE (f))
2543 {
2544 XSETFRAME (frame, f);
2545 call1 (Qface_set_after_frame_default, frame);
2546 }
2547 }
2548
2549 static void
2550 x_set_fringe_width (f, new_value, old_value)
2551 struct frame *f;
2552 Lisp_Object new_value, old_value;
2553 {
2554 x_compute_fringe_widths (f, 1);
2555 }
2556
2557 void
2558 x_set_border_width (f, arg, oldval)
2559 struct frame *f;
2560 Lisp_Object arg, oldval;
2561 {
2562 CHECK_NUMBER (arg);
2563
2564 if (XINT (arg) == f->output_data.w32->border_width)
2565 return;
2566
2567 if (FRAME_W32_WINDOW (f) != 0)
2568 error ("Cannot change the border width of a window");
2569
2570 f->output_data.w32->border_width = XINT (arg);
2571 }
2572
2573 void
2574 x_set_internal_border_width (f, arg, oldval)
2575 struct frame *f;
2576 Lisp_Object arg, oldval;
2577 {
2578 int old = f->output_data.w32->internal_border_width;
2579
2580 CHECK_NUMBER (arg);
2581 f->output_data.w32->internal_border_width = XINT (arg);
2582 if (f->output_data.w32->internal_border_width < 0)
2583 f->output_data.w32->internal_border_width = 0;
2584
2585 if (f->output_data.w32->internal_border_width == old)
2586 return;
2587
2588 if (FRAME_W32_WINDOW (f) != 0)
2589 {
2590 x_set_window_size (f, 0, f->width, f->height);
2591 SET_FRAME_GARBAGED (f);
2592 do_pending_window_change (0);
2593 }
2594 else
2595 SET_FRAME_GARBAGED (f);
2596 }
2597
2598 void
2599 x_set_visibility (f, value, oldval)
2600 struct frame *f;
2601 Lisp_Object value, oldval;
2602 {
2603 Lisp_Object frame;
2604 XSETFRAME (frame, f);
2605
2606 if (NILP (value))
2607 Fmake_frame_invisible (frame, Qt);
2608 else if (EQ (value, Qicon))
2609 Ficonify_frame (frame);
2610 else
2611 Fmake_frame_visible (frame);
2612 }
2613
2614 \f
2615 /* Change window heights in windows rooted in WINDOW by N lines. */
2616
2617 static void
2618 x_change_window_heights (window, n)
2619 Lisp_Object window;
2620 int n;
2621 {
2622 struct window *w = XWINDOW (window);
2623
2624 XSETFASTINT (w->top, XFASTINT (w->top) + n);
2625 XSETFASTINT (w->height, XFASTINT (w->height) - n);
2626
2627 if (INTEGERP (w->orig_top))
2628 XSETFASTINT (w->orig_top, XFASTINT (w->orig_top) + n);
2629 if (INTEGERP (w->orig_height))
2630 XSETFASTINT (w->orig_height, XFASTINT (w->orig_height) - n);
2631
2632 /* Handle just the top child in a vertical split. */
2633 if (!NILP (w->vchild))
2634 x_change_window_heights (w->vchild, n);
2635
2636 /* Adjust all children in a horizontal split. */
2637 for (window = w->hchild; !NILP (window); window = w->next)
2638 {
2639 w = XWINDOW (window);
2640 x_change_window_heights (window, n);
2641 }
2642 }
2643
2644 void
2645 x_set_menu_bar_lines (f, value, oldval)
2646 struct frame *f;
2647 Lisp_Object value, oldval;
2648 {
2649 int nlines;
2650 int olines = FRAME_MENU_BAR_LINES (f);
2651
2652 /* Right now, menu bars don't work properly in minibuf-only frames;
2653 most of the commands try to apply themselves to the minibuffer
2654 frame itself, and get an error because you can't switch buffers
2655 in or split the minibuffer window. */
2656 if (FRAME_MINIBUF_ONLY_P (f))
2657 return;
2658
2659 if (INTEGERP (value))
2660 nlines = XINT (value);
2661 else
2662 nlines = 0;
2663
2664 FRAME_MENU_BAR_LINES (f) = 0;
2665 if (nlines)
2666 FRAME_EXTERNAL_MENU_BAR (f) = 1;
2667 else
2668 {
2669 if (FRAME_EXTERNAL_MENU_BAR (f) == 1)
2670 free_frame_menubar (f);
2671 FRAME_EXTERNAL_MENU_BAR (f) = 0;
2672
2673 /* Adjust the frame size so that the client (text) dimensions
2674 remain the same. This depends on FRAME_EXTERNAL_MENU_BAR being
2675 set correctly. */
2676 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2677 do_pending_window_change (0);
2678 }
2679 adjust_glyphs (f);
2680 }
2681
2682
2683 /* Set the number of lines used for the tool bar of frame F to VALUE.
2684 VALUE not an integer, or < 0 means set the lines to zero. OLDVAL
2685 is the old number of tool bar lines. This function changes the
2686 height of all windows on frame F to match the new tool bar height.
2687 The frame's height doesn't change. */
2688
2689 void
2690 x_set_tool_bar_lines (f, value, oldval)
2691 struct frame *f;
2692 Lisp_Object value, oldval;
2693 {
2694 int delta, nlines, root_height;
2695 Lisp_Object root_window;
2696
2697 /* Treat tool bars like menu bars. */
2698 if (FRAME_MINIBUF_ONLY_P (f))
2699 return;
2700
2701 /* Use VALUE only if an integer >= 0. */
2702 if (INTEGERP (value) && XINT (value) >= 0)
2703 nlines = XFASTINT (value);
2704 else
2705 nlines = 0;
2706
2707 /* Make sure we redisplay all windows in this frame. */
2708 ++windows_or_buffers_changed;
2709
2710 delta = nlines - FRAME_TOOL_BAR_LINES (f);
2711
2712 /* Don't resize the tool-bar to more than we have room for. */
2713 root_window = FRAME_ROOT_WINDOW (f);
2714 root_height = XINT (XWINDOW (root_window)->height);
2715 if (root_height - delta < 1)
2716 {
2717 delta = root_height - 1;
2718 nlines = FRAME_TOOL_BAR_LINES (f) + delta;
2719 }
2720
2721 FRAME_TOOL_BAR_LINES (f) = nlines;
2722 x_change_window_heights (root_window, delta);
2723 adjust_glyphs (f);
2724
2725 /* We also have to make sure that the internal border at the top of
2726 the frame, below the menu bar or tool bar, is redrawn when the
2727 tool bar disappears. This is so because the internal border is
2728 below the tool bar if one is displayed, but is below the menu bar
2729 if there isn't a tool bar. The tool bar draws into the area
2730 below the menu bar. */
2731 if (FRAME_W32_WINDOW (f) && FRAME_TOOL_BAR_LINES (f) == 0)
2732 {
2733 updating_frame = f;
2734 clear_frame ();
2735 clear_current_matrices (f);
2736 updating_frame = NULL;
2737 }
2738
2739 /* If the tool bar gets smaller, the internal border below it
2740 has to be cleared. It was formerly part of the display
2741 of the larger tool bar, and updating windows won't clear it. */
2742 if (delta < 0)
2743 {
2744 int height = FRAME_INTERNAL_BORDER_WIDTH (f);
2745 int width = PIXEL_WIDTH (f);
2746 int y = nlines * CANON_Y_UNIT (f);
2747
2748 BLOCK_INPUT;
2749 {
2750 HDC hdc = get_frame_dc (f);
2751 w32_clear_area (f, hdc, 0, y, width, height);
2752 release_frame_dc (f, hdc);
2753 }
2754 UNBLOCK_INPUT;
2755
2756 if (WINDOWP (f->tool_bar_window))
2757 clear_glyph_matrix (XWINDOW (f->tool_bar_window)->current_matrix);
2758 }
2759 }
2760
2761
2762 /* Change the name of frame F to NAME. If NAME is nil, set F's name to
2763 w32_id_name.
2764
2765 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2766 name; if NAME is a string, set F's name to NAME and set
2767 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2768
2769 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2770 suggesting a new name, which lisp code should override; if
2771 F->explicit_name is set, ignore the new name; otherwise, set it. */
2772
2773 void
2774 x_set_name (f, name, explicit)
2775 struct frame *f;
2776 Lisp_Object name;
2777 int explicit;
2778 {
2779 /* Make sure that requests from lisp code override requests from
2780 Emacs redisplay code. */
2781 if (explicit)
2782 {
2783 /* If we're switching from explicit to implicit, we had better
2784 update the mode lines and thereby update the title. */
2785 if (f->explicit_name && NILP (name))
2786 update_mode_lines = 1;
2787
2788 f->explicit_name = ! NILP (name);
2789 }
2790 else if (f->explicit_name)
2791 return;
2792
2793 /* If NAME is nil, set the name to the w32_id_name. */
2794 if (NILP (name))
2795 {
2796 /* Check for no change needed in this very common case
2797 before we do any consing. */
2798 if (!strcmp (FRAME_W32_DISPLAY_INFO (f)->w32_id_name,
2799 XSTRING (f->name)->data))
2800 return;
2801 name = build_string (FRAME_W32_DISPLAY_INFO (f)->w32_id_name);
2802 }
2803 else
2804 CHECK_STRING (name);
2805
2806 /* Don't change the name if it's already NAME. */
2807 if (! NILP (Fstring_equal (name, f->name)))
2808 return;
2809
2810 f->name = name;
2811
2812 /* For setting the frame title, the title parameter should override
2813 the name parameter. */
2814 if (! NILP (f->title))
2815 name = f->title;
2816
2817 if (FRAME_W32_WINDOW (f))
2818 {
2819 if (STRING_MULTIBYTE (name))
2820 name = ENCODE_SYSTEM (name);
2821
2822 BLOCK_INPUT;
2823 SetWindowText(FRAME_W32_WINDOW (f), XSTRING (name)->data);
2824 UNBLOCK_INPUT;
2825 }
2826 }
2827
2828 /* This function should be called when the user's lisp code has
2829 specified a name for the frame; the name will override any set by the
2830 redisplay code. */
2831 void
2832 x_explicitly_set_name (f, arg, oldval)
2833 FRAME_PTR f;
2834 Lisp_Object arg, oldval;
2835 {
2836 x_set_name (f, arg, 1);
2837 }
2838
2839 /* This function should be called by Emacs redisplay code to set the
2840 name; names set this way will never override names set by the user's
2841 lisp code. */
2842 void
2843 x_implicitly_set_name (f, arg, oldval)
2844 FRAME_PTR f;
2845 Lisp_Object arg, oldval;
2846 {
2847 x_set_name (f, arg, 0);
2848 }
2849 \f
2850 /* Change the title of frame F to NAME.
2851 If NAME is nil, use the frame name as the title.
2852
2853 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2854 name; if NAME is a string, set F's name to NAME and set
2855 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2856
2857 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2858 suggesting a new name, which lisp code should override; if
2859 F->explicit_name is set, ignore the new name; otherwise, set it. */
2860
2861 void
2862 x_set_title (f, name, old_name)
2863 struct frame *f;
2864 Lisp_Object name, old_name;
2865 {
2866 /* Don't change the title if it's already NAME. */
2867 if (EQ (name, f->title))
2868 return;
2869
2870 update_mode_lines = 1;
2871
2872 f->title = name;
2873
2874 if (NILP (name))
2875 name = f->name;
2876
2877 if (FRAME_W32_WINDOW (f))
2878 {
2879 if (STRING_MULTIBYTE (name))
2880 name = ENCODE_SYSTEM (name);
2881
2882 BLOCK_INPUT;
2883 SetWindowText(FRAME_W32_WINDOW (f), XSTRING (name)->data);
2884 UNBLOCK_INPUT;
2885 }
2886 }
2887 \f
2888 void
2889 x_set_autoraise (f, arg, oldval)
2890 struct frame *f;
2891 Lisp_Object arg, oldval;
2892 {
2893 f->auto_raise = !EQ (Qnil, arg);
2894 }
2895
2896 void
2897 x_set_autolower (f, arg, oldval)
2898 struct frame *f;
2899 Lisp_Object arg, oldval;
2900 {
2901 f->auto_lower = !EQ (Qnil, arg);
2902 }
2903
2904 void
2905 x_set_unsplittable (f, arg, oldval)
2906 struct frame *f;
2907 Lisp_Object arg, oldval;
2908 {
2909 f->no_split = !NILP (arg);
2910 }
2911
2912 void
2913 x_set_vertical_scroll_bars (f, arg, oldval)
2914 struct frame *f;
2915 Lisp_Object arg, oldval;
2916 {
2917 if ((EQ (arg, Qleft) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
2918 || (EQ (arg, Qright) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
2919 || (NILP (arg) && FRAME_HAS_VERTICAL_SCROLL_BARS (f))
2920 || (!NILP (arg) && ! FRAME_HAS_VERTICAL_SCROLL_BARS (f)))
2921 {
2922 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = NILP (arg) ?
2923 vertical_scroll_bar_none :
2924 /* Put scroll bars on the right by default, as is conventional
2925 on MS-Windows. */
2926 EQ (Qleft, arg)
2927 ? vertical_scroll_bar_left
2928 : vertical_scroll_bar_right;
2929
2930 /* We set this parameter before creating the window for the
2931 frame, so we can get the geometry right from the start.
2932 However, if the window hasn't been created yet, we shouldn't
2933 call x_set_window_size. */
2934 if (FRAME_W32_WINDOW (f))
2935 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2936 do_pending_window_change (0);
2937 }
2938 }
2939
2940 void
2941 x_set_scroll_bar_width (f, arg, oldval)
2942 struct frame *f;
2943 Lisp_Object arg, oldval;
2944 {
2945 int wid = FONT_WIDTH (f->output_data.w32->font);
2946
2947 if (NILP (arg))
2948 {
2949 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = GetSystemMetrics (SM_CXVSCROLL);
2950 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) +
2951 wid - 1) / wid;
2952 if (FRAME_W32_WINDOW (f))
2953 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2954 do_pending_window_change (0);
2955 }
2956 else if (INTEGERP (arg) && XINT (arg) > 0
2957 && XFASTINT (arg) != FRAME_SCROLL_BAR_PIXEL_WIDTH (f))
2958 {
2959 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = XFASTINT (arg);
2960 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
2961 + wid-1) / wid;
2962 if (FRAME_W32_WINDOW (f))
2963 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2964 do_pending_window_change (0);
2965 }
2966 change_frame_size (f, 0, FRAME_WIDTH (f), 0, 0, 0);
2967 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.hpos = 0;
2968 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.x = 0;
2969 }
2970 \f
2971 /* Subroutines of creating an frame. */
2972
2973 /* Make sure that Vx_resource_name is set to a reasonable value.
2974 Fix it up, or set it to `emacs' if it is too hopeless. */
2975
2976 static void
2977 validate_x_resource_name ()
2978 {
2979 int len = 0;
2980 /* Number of valid characters in the resource name. */
2981 int good_count = 0;
2982 /* Number of invalid characters in the resource name. */
2983 int bad_count = 0;
2984 Lisp_Object new;
2985 int i;
2986
2987 if (STRINGP (Vx_resource_name))
2988 {
2989 unsigned char *p = XSTRING (Vx_resource_name)->data;
2990 int i;
2991
2992 len = STRING_BYTES (XSTRING (Vx_resource_name));
2993
2994 /* Only letters, digits, - and _ are valid in resource names.
2995 Count the valid characters and count the invalid ones. */
2996 for (i = 0; i < len; i++)
2997 {
2998 int c = p[i];
2999 if (! ((c >= 'a' && c <= 'z')
3000 || (c >= 'A' && c <= 'Z')
3001 || (c >= '0' && c <= '9')
3002 || c == '-' || c == '_'))
3003 bad_count++;
3004 else
3005 good_count++;
3006 }
3007 }
3008 else
3009 /* Not a string => completely invalid. */
3010 bad_count = 5, good_count = 0;
3011
3012 /* If name is valid already, return. */
3013 if (bad_count == 0)
3014 return;
3015
3016 /* If name is entirely invalid, or nearly so, use `emacs'. */
3017 if (good_count == 0
3018 || (good_count == 1 && bad_count > 0))
3019 {
3020 Vx_resource_name = build_string ("emacs");
3021 return;
3022 }
3023
3024 /* Name is partly valid. Copy it and replace the invalid characters
3025 with underscores. */
3026
3027 Vx_resource_name = new = Fcopy_sequence (Vx_resource_name);
3028
3029 for (i = 0; i < len; i++)
3030 {
3031 int c = XSTRING (new)->data[i];
3032 if (! ((c >= 'a' && c <= 'z')
3033 || (c >= 'A' && c <= 'Z')
3034 || (c >= '0' && c <= '9')
3035 || c == '-' || c == '_'))
3036 XSTRING (new)->data[i] = '_';
3037 }
3038 }
3039
3040
3041 extern char *x_get_string_resource ();
3042
3043 DEFUN ("x-get-resource", Fx_get_resource, Sx_get_resource, 2, 4, 0,
3044 doc: /* Return the value of ATTRIBUTE, of class CLASS, from the X defaults database.
3045 This uses `INSTANCE.ATTRIBUTE' as the key and `Emacs.CLASS' as the
3046 class, where INSTANCE is the name under which Emacs was invoked, or
3047 the name specified by the `-name' or `-rn' command-line arguments.
3048
3049 The optional arguments COMPONENT and SUBCLASS add to the key and the
3050 class, respectively. You must specify both of them or neither.
3051 If you specify them, the key is `INSTANCE.COMPONENT.ATTRIBUTE'
3052 and the class is `Emacs.CLASS.SUBCLASS'. */)
3053 (attribute, class, component, subclass)
3054 Lisp_Object attribute, class, component, subclass;
3055 {
3056 register char *value;
3057 char *name_key;
3058 char *class_key;
3059
3060 CHECK_STRING (attribute);
3061 CHECK_STRING (class);
3062
3063 if (!NILP (component))
3064 CHECK_STRING (component);
3065 if (!NILP (subclass))
3066 CHECK_STRING (subclass);
3067 if (NILP (component) != NILP (subclass))
3068 error ("x-get-resource: must specify both COMPONENT and SUBCLASS or neither");
3069
3070 validate_x_resource_name ();
3071
3072 /* Allocate space for the components, the dots which separate them,
3073 and the final '\0'. Make them big enough for the worst case. */
3074 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vx_resource_name))
3075 + (STRINGP (component)
3076 ? STRING_BYTES (XSTRING (component)) : 0)
3077 + STRING_BYTES (XSTRING (attribute))
3078 + 3);
3079
3080 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
3081 + STRING_BYTES (XSTRING (class))
3082 + (STRINGP (subclass)
3083 ? STRING_BYTES (XSTRING (subclass)) : 0)
3084 + 3);
3085
3086 /* Start with emacs.FRAMENAME for the name (the specific one)
3087 and with `Emacs' for the class key (the general one). */
3088 strcpy (name_key, XSTRING (Vx_resource_name)->data);
3089 strcpy (class_key, EMACS_CLASS);
3090
3091 strcat (class_key, ".");
3092 strcat (class_key, XSTRING (class)->data);
3093
3094 if (!NILP (component))
3095 {
3096 strcat (class_key, ".");
3097 strcat (class_key, XSTRING (subclass)->data);
3098
3099 strcat (name_key, ".");
3100 strcat (name_key, XSTRING (component)->data);
3101 }
3102
3103 strcat (name_key, ".");
3104 strcat (name_key, XSTRING (attribute)->data);
3105
3106 value = x_get_string_resource (Qnil,
3107 name_key, class_key);
3108
3109 if (value != (char *) 0)
3110 return build_string (value);
3111 else
3112 return Qnil;
3113 }
3114
3115 /* Used when C code wants a resource value. */
3116
3117 char *
3118 x_get_resource_string (attribute, class)
3119 char *attribute, *class;
3120 {
3121 char *name_key;
3122 char *class_key;
3123 struct frame *sf = SELECTED_FRAME ();
3124
3125 /* Allocate space for the components, the dots which separate them,
3126 and the final '\0'. */
3127 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vinvocation_name))
3128 + strlen (attribute) + 2);
3129 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
3130 + strlen (class) + 2);
3131
3132 sprintf (name_key, "%s.%s",
3133 XSTRING (Vinvocation_name)->data,
3134 attribute);
3135 sprintf (class_key, "%s.%s", EMACS_CLASS, class);
3136
3137 return x_get_string_resource (sf, name_key, class_key);
3138 }
3139
3140 /* Types we might convert a resource string into. */
3141 enum resource_types
3142 {
3143 RES_TYPE_NUMBER,
3144 RES_TYPE_FLOAT,
3145 RES_TYPE_BOOLEAN,
3146 RES_TYPE_STRING,
3147 RES_TYPE_SYMBOL
3148 };
3149
3150 /* Return the value of parameter PARAM.
3151
3152 First search ALIST, then Vdefault_frame_alist, then the X defaults
3153 database, using ATTRIBUTE as the attribute name and CLASS as its class.
3154
3155 Convert the resource to the type specified by desired_type.
3156
3157 If no default is specified, return Qunbound. If you call
3158 w32_get_arg, make sure you deal with Qunbound in a reasonable way,
3159 and don't let it get stored in any Lisp-visible variables! */
3160
3161 static Lisp_Object
3162 w32_get_arg (alist, param, attribute, class, type)
3163 Lisp_Object alist, param;
3164 char *attribute;
3165 char *class;
3166 enum resource_types type;
3167 {
3168 register Lisp_Object tem;
3169
3170 tem = Fassq (param, alist);
3171 if (EQ (tem, Qnil))
3172 tem = Fassq (param, Vdefault_frame_alist);
3173 if (EQ (tem, Qnil))
3174 {
3175
3176 if (attribute)
3177 {
3178 tem = Fx_get_resource (build_string (attribute),
3179 build_string (class),
3180 Qnil, Qnil);
3181
3182 if (NILP (tem))
3183 return Qunbound;
3184
3185 switch (type)
3186 {
3187 case RES_TYPE_NUMBER:
3188 return make_number (atoi (XSTRING (tem)->data));
3189
3190 case RES_TYPE_FLOAT:
3191 return make_float (atof (XSTRING (tem)->data));
3192
3193 case RES_TYPE_BOOLEAN:
3194 tem = Fdowncase (tem);
3195 if (!strcmp (XSTRING (tem)->data, "on")
3196 || !strcmp (XSTRING (tem)->data, "true"))
3197 return Qt;
3198 else
3199 return Qnil;
3200
3201 case RES_TYPE_STRING:
3202 return tem;
3203
3204 case RES_TYPE_SYMBOL:
3205 /* As a special case, we map the values `true' and `on'
3206 to Qt, and `false' and `off' to Qnil. */
3207 {
3208 Lisp_Object lower;
3209 lower = Fdowncase (tem);
3210 if (!strcmp (XSTRING (lower)->data, "on")
3211 || !strcmp (XSTRING (lower)->data, "true"))
3212 return Qt;
3213 else if (!strcmp (XSTRING (lower)->data, "off")
3214 || !strcmp (XSTRING (lower)->data, "false"))
3215 return Qnil;
3216 else
3217 return Fintern (tem, Qnil);
3218 }
3219
3220 default:
3221 abort ();
3222 }
3223 }
3224 else
3225 return Qunbound;
3226 }
3227 return Fcdr (tem);
3228 }
3229
3230 /* Record in frame F the specified or default value according to ALIST
3231 of the parameter named PROP (a Lisp symbol).
3232 If no value is specified for PROP, look for an X default for XPROP
3233 on the frame named NAME.
3234 If that is not found either, use the value DEFLT. */
3235
3236 static Lisp_Object
3237 x_default_parameter (f, alist, prop, deflt, xprop, xclass, type)
3238 struct frame *f;
3239 Lisp_Object alist;
3240 Lisp_Object prop;
3241 Lisp_Object deflt;
3242 char *xprop;
3243 char *xclass;
3244 enum resource_types type;
3245 {
3246 Lisp_Object tem;
3247
3248 tem = w32_get_arg (alist, prop, xprop, xclass, type);
3249 if (EQ (tem, Qunbound))
3250 tem = deflt;
3251 x_set_frame_parameters (f, Fcons (Fcons (prop, tem), Qnil));
3252 return tem;
3253 }
3254 \f
3255 DEFUN ("x-parse-geometry", Fx_parse_geometry, Sx_parse_geometry, 1, 1, 0,
3256 doc: /* Parse an X-style geometry string STRING.
3257 Returns an alist of the form ((top . TOP), (left . LEFT) ... ).
3258 The properties returned may include `top', `left', `height', and `width'.
3259 The value of `left' or `top' may be an integer,
3260 or a list (+ N) meaning N pixels relative to top/left corner,
3261 or a list (- N) meaning -N pixels relative to bottom/right corner. */)
3262 (string)
3263 Lisp_Object string;
3264 {
3265 int geometry, x, y;
3266 unsigned int width, height;
3267 Lisp_Object result;
3268
3269 CHECK_STRING (string);
3270
3271 geometry = XParseGeometry ((char *) XSTRING (string)->data,
3272 &x, &y, &width, &height);
3273
3274 result = Qnil;
3275 if (geometry & XValue)
3276 {
3277 Lisp_Object element;
3278
3279 if (x >= 0 && (geometry & XNegative))
3280 element = Fcons (Qleft, Fcons (Qminus, Fcons (make_number (-x), Qnil)));
3281 else if (x < 0 && ! (geometry & XNegative))
3282 element = Fcons (Qleft, Fcons (Qplus, Fcons (make_number (x), Qnil)));
3283 else
3284 element = Fcons (Qleft, make_number (x));
3285 result = Fcons (element, result);
3286 }
3287
3288 if (geometry & YValue)
3289 {
3290 Lisp_Object element;
3291
3292 if (y >= 0 && (geometry & YNegative))
3293 element = Fcons (Qtop, Fcons (Qminus, Fcons (make_number (-y), Qnil)));
3294 else if (y < 0 && ! (geometry & YNegative))
3295 element = Fcons (Qtop, Fcons (Qplus, Fcons (make_number (y), Qnil)));
3296 else
3297 element = Fcons (Qtop, make_number (y));
3298 result = Fcons (element, result);
3299 }
3300
3301 if (geometry & WidthValue)
3302 result = Fcons (Fcons (Qwidth, make_number (width)), result);
3303 if (geometry & HeightValue)
3304 result = Fcons (Fcons (Qheight, make_number (height)), result);
3305
3306 return result;
3307 }
3308
3309 /* Calculate the desired size and position of this window,
3310 and return the flags saying which aspects were specified.
3311
3312 This function does not make the coordinates positive. */
3313
3314 #define DEFAULT_ROWS 40
3315 #define DEFAULT_COLS 80
3316
3317 static int
3318 x_figure_window_size (f, parms)
3319 struct frame *f;
3320 Lisp_Object parms;
3321 {
3322 register Lisp_Object tem0, tem1, tem2;
3323 long window_prompting = 0;
3324
3325 /* Default values if we fall through.
3326 Actually, if that happens we should get
3327 window manager prompting. */
3328 SET_FRAME_WIDTH (f, DEFAULT_COLS);
3329 f->height = DEFAULT_ROWS;
3330 /* Window managers expect that if program-specified
3331 positions are not (0,0), they're intentional, not defaults. */
3332 f->output_data.w32->top_pos = 0;
3333 f->output_data.w32->left_pos = 0;
3334
3335 /* Ensure that old new_width and new_height will not override the
3336 values set here. */
3337 FRAME_NEW_WIDTH (f) = 0;
3338 FRAME_NEW_HEIGHT (f) = 0;
3339
3340 tem0 = w32_get_arg (parms, Qheight, 0, 0, RES_TYPE_NUMBER);
3341 tem1 = w32_get_arg (parms, Qwidth, 0, 0, RES_TYPE_NUMBER);
3342 tem2 = w32_get_arg (parms, Quser_size, 0, 0, RES_TYPE_NUMBER);
3343 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3344 {
3345 if (!EQ (tem0, Qunbound))
3346 {
3347 CHECK_NUMBER (tem0);
3348 f->height = XINT (tem0);
3349 }
3350 if (!EQ (tem1, Qunbound))
3351 {
3352 CHECK_NUMBER (tem1);
3353 SET_FRAME_WIDTH (f, XINT (tem1));
3354 }
3355 if (!NILP (tem2) && !EQ (tem2, Qunbound))
3356 window_prompting |= USSize;
3357 else
3358 window_prompting |= PSize;
3359 }
3360
3361 f->output_data.w32->vertical_scroll_bar_extra
3362 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
3363 ? 0
3364 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
3365 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
3366 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.w32->font)));
3367
3368 x_compute_fringe_widths (f, 0);
3369
3370 f->output_data.w32->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
3371 f->output_data.w32->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
3372
3373 tem0 = w32_get_arg (parms, Qtop, 0, 0, RES_TYPE_NUMBER);
3374 tem1 = w32_get_arg (parms, Qleft, 0, 0, RES_TYPE_NUMBER);
3375 tem2 = w32_get_arg (parms, Quser_position, 0, 0, RES_TYPE_NUMBER);
3376 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3377 {
3378 if (EQ (tem0, Qminus))
3379 {
3380 f->output_data.w32->top_pos = 0;
3381 window_prompting |= YNegative;
3382 }
3383 else if (CONSP (tem0) && EQ (XCAR (tem0), Qminus)
3384 && CONSP (XCDR (tem0))
3385 && INTEGERP (XCAR (XCDR (tem0))))
3386 {
3387 f->output_data.w32->top_pos = - XINT (XCAR (XCDR (tem0)));
3388 window_prompting |= YNegative;
3389 }
3390 else if (CONSP (tem0) && EQ (XCAR (tem0), Qplus)
3391 && CONSP (XCDR (tem0))
3392 && INTEGERP (XCAR (XCDR (tem0))))
3393 {
3394 f->output_data.w32->top_pos = XINT (XCAR (XCDR (tem0)));
3395 }
3396 else if (EQ (tem0, Qunbound))
3397 f->output_data.w32->top_pos = 0;
3398 else
3399 {
3400 CHECK_NUMBER (tem0);
3401 f->output_data.w32->top_pos = XINT (tem0);
3402 if (f->output_data.w32->top_pos < 0)
3403 window_prompting |= YNegative;
3404 }
3405
3406 if (EQ (tem1, Qminus))
3407 {
3408 f->output_data.w32->left_pos = 0;
3409 window_prompting |= XNegative;
3410 }
3411 else if (CONSP (tem1) && EQ (XCAR (tem1), Qminus)
3412 && CONSP (XCDR (tem1))
3413 && INTEGERP (XCAR (XCDR (tem1))))
3414 {
3415 f->output_data.w32->left_pos = - XINT (XCAR (XCDR (tem1)));
3416 window_prompting |= XNegative;
3417 }
3418 else if (CONSP (tem1) && EQ (XCAR (tem1), Qplus)
3419 && CONSP (XCDR (tem1))
3420 && INTEGERP (XCAR (XCDR (tem1))))
3421 {
3422 f->output_data.w32->left_pos = XINT (XCAR (XCDR (tem1)));
3423 }
3424 else if (EQ (tem1, Qunbound))
3425 f->output_data.w32->left_pos = 0;
3426 else
3427 {
3428 CHECK_NUMBER (tem1);
3429 f->output_data.w32->left_pos = XINT (tem1);
3430 if (f->output_data.w32->left_pos < 0)
3431 window_prompting |= XNegative;
3432 }
3433
3434 if (!NILP (tem2) && ! EQ (tem2, Qunbound))
3435 window_prompting |= USPosition;
3436 else
3437 window_prompting |= PPosition;
3438 }
3439
3440 if (f->output_data.w32->want_fullscreen != FULLSCREEN_NONE)
3441 {
3442 int left, top;
3443 int width, height;
3444
3445 /* It takes both for some WM:s to place it where we want */
3446 window_prompting = USPosition | PPosition;
3447 x_fullscreen_adjust (f, &width, &height, &top, &left);
3448 f->width = width;
3449 f->height = height;
3450 f->output_data.w32->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
3451 f->output_data.w32->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
3452 f->output_data.w32->left_pos = left;
3453 f->output_data.w32->top_pos = top;
3454 }
3455
3456 return window_prompting;
3457 }
3458
3459 \f
3460
3461 extern LRESULT CALLBACK w32_wnd_proc ();
3462
3463 BOOL
3464 w32_init_class (hinst)
3465 HINSTANCE hinst;
3466 {
3467 WNDCLASS wc;
3468
3469 wc.style = CS_HREDRAW | CS_VREDRAW;
3470 wc.lpfnWndProc = (WNDPROC) w32_wnd_proc;
3471 wc.cbClsExtra = 0;
3472 wc.cbWndExtra = WND_EXTRA_BYTES;
3473 wc.hInstance = hinst;
3474 wc.hIcon = LoadIcon (hinst, EMACS_CLASS);
3475 wc.hCursor = LoadCursor (NULL, IDC_ARROW);
3476 wc.hbrBackground = NULL; /* GetStockObject (WHITE_BRUSH); */
3477 wc.lpszMenuName = NULL;
3478 wc.lpszClassName = EMACS_CLASS;
3479
3480 return (RegisterClass (&wc));
3481 }
3482
3483 HWND
3484 w32_createscrollbar (f, bar)
3485 struct frame *f;
3486 struct scroll_bar * bar;
3487 {
3488 return (CreateWindow ("SCROLLBAR", "", SBS_VERT | WS_CHILD | WS_VISIBLE,
3489 /* Position and size of scroll bar. */
3490 XINT(bar->left) + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
3491 XINT(bar->top),
3492 XINT(bar->width) - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
3493 XINT(bar->height),
3494 FRAME_W32_WINDOW (f),
3495 NULL,
3496 hinst,
3497 NULL));
3498 }
3499
3500 void
3501 w32_createwindow (f)
3502 struct frame *f;
3503 {
3504 HWND hwnd;
3505 RECT rect;
3506
3507 rect.left = rect.top = 0;
3508 rect.right = PIXEL_WIDTH (f);
3509 rect.bottom = PIXEL_HEIGHT (f);
3510
3511 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
3512 FRAME_EXTERNAL_MENU_BAR (f));
3513
3514 /* Do first time app init */
3515
3516 if (!hprevinst)
3517 {
3518 w32_init_class (hinst);
3519 }
3520
3521 FRAME_W32_WINDOW (f) = hwnd
3522 = CreateWindow (EMACS_CLASS,
3523 f->namebuf,
3524 f->output_data.w32->dwStyle | WS_CLIPCHILDREN,
3525 f->output_data.w32->left_pos,
3526 f->output_data.w32->top_pos,
3527 rect.right - rect.left,
3528 rect.bottom - rect.top,
3529 NULL,
3530 NULL,
3531 hinst,
3532 NULL);
3533
3534 if (hwnd)
3535 {
3536 SetWindowLong (hwnd, WND_FONTWIDTH_INDEX, FONT_WIDTH (f->output_data.w32->font));
3537 SetWindowLong (hwnd, WND_LINEHEIGHT_INDEX, f->output_data.w32->line_height);
3538 SetWindowLong (hwnd, WND_BORDER_INDEX, f->output_data.w32->internal_border_width);
3539 SetWindowLong (hwnd, WND_SCROLLBAR_INDEX, f->output_data.w32->vertical_scroll_bar_extra);
3540 SetWindowLong (hwnd, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f));
3541
3542 /* Enable drag-n-drop. */
3543 DragAcceptFiles (hwnd, TRUE);
3544
3545 /* Do this to discard the default setting specified by our parent. */
3546 ShowWindow (hwnd, SW_HIDE);
3547 }
3548 }
3549
3550 void
3551 my_post_msg (wmsg, hwnd, msg, wParam, lParam)
3552 W32Msg * wmsg;
3553 HWND hwnd;
3554 UINT msg;
3555 WPARAM wParam;
3556 LPARAM lParam;
3557 {
3558 wmsg->msg.hwnd = hwnd;
3559 wmsg->msg.message = msg;
3560 wmsg->msg.wParam = wParam;
3561 wmsg->msg.lParam = lParam;
3562 wmsg->msg.time = GetMessageTime ();
3563
3564 post_msg (wmsg);
3565 }
3566
3567 /* GetKeyState and MapVirtualKey on Windows 95 do not actually distinguish
3568 between left and right keys as advertised. We test for this
3569 support dynamically, and set a flag when the support is absent. If
3570 absent, we keep track of the left and right control and alt keys
3571 ourselves. This is particularly necessary on keyboards that rely
3572 upon the AltGr key, which is represented as having the left control
3573 and right alt keys pressed. For these keyboards, we need to know
3574 when the left alt key has been pressed in addition to the AltGr key
3575 so that we can properly support M-AltGr-key sequences (such as M-@
3576 on Swedish keyboards). */
3577
3578 #define EMACS_LCONTROL 0
3579 #define EMACS_RCONTROL 1
3580 #define EMACS_LMENU 2
3581 #define EMACS_RMENU 3
3582
3583 static int modifiers[4];
3584 static int modifiers_recorded;
3585 static int modifier_key_support_tested;
3586
3587 static void
3588 test_modifier_support (unsigned int wparam)
3589 {
3590 unsigned int l, r;
3591
3592 if (wparam != VK_CONTROL && wparam != VK_MENU)
3593 return;
3594 if (wparam == VK_CONTROL)
3595 {
3596 l = VK_LCONTROL;
3597 r = VK_RCONTROL;
3598 }
3599 else
3600 {
3601 l = VK_LMENU;
3602 r = VK_RMENU;
3603 }
3604 if (!(GetKeyState (l) & 0x8000) && !(GetKeyState (r) & 0x8000))
3605 modifiers_recorded = 1;
3606 else
3607 modifiers_recorded = 0;
3608 modifier_key_support_tested = 1;
3609 }
3610
3611 static void
3612 record_keydown (unsigned int wparam, unsigned int lparam)
3613 {
3614 int i;
3615
3616 if (!modifier_key_support_tested)
3617 test_modifier_support (wparam);
3618
3619 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3620 return;
3621
3622 if (wparam == VK_CONTROL)
3623 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3624 else
3625 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3626
3627 modifiers[i] = 1;
3628 }
3629
3630 static void
3631 record_keyup (unsigned int wparam, unsigned int lparam)
3632 {
3633 int i;
3634
3635 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3636 return;
3637
3638 if (wparam == VK_CONTROL)
3639 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3640 else
3641 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3642
3643 modifiers[i] = 0;
3644 }
3645
3646 /* Emacs can lose focus while a modifier key has been pressed. When
3647 it regains focus, be conservative and clear all modifiers since
3648 we cannot reconstruct the left and right modifier state. */
3649 static void
3650 reset_modifiers ()
3651 {
3652 SHORT ctrl, alt;
3653
3654 if (GetFocus () == NULL)
3655 /* Emacs doesn't have keyboard focus. Do nothing. */
3656 return;
3657
3658 ctrl = GetAsyncKeyState (VK_CONTROL);
3659 alt = GetAsyncKeyState (VK_MENU);
3660
3661 if (!(ctrl & 0x08000))
3662 /* Clear any recorded control modifier state. */
3663 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3664
3665 if (!(alt & 0x08000))
3666 /* Clear any recorded alt modifier state. */
3667 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3668
3669 /* Update the state of all modifier keys, because modifiers used in
3670 hot-key combinations can get stuck on if Emacs loses focus as a
3671 result of a hot-key being pressed. */
3672 {
3673 BYTE keystate[256];
3674
3675 #define CURRENT_STATE(key) ((GetAsyncKeyState (key) & 0x8000) >> 8)
3676
3677 GetKeyboardState (keystate);
3678 keystate[VK_SHIFT] = CURRENT_STATE (VK_SHIFT);
3679 keystate[VK_CONTROL] = CURRENT_STATE (VK_CONTROL);
3680 keystate[VK_LCONTROL] = CURRENT_STATE (VK_LCONTROL);
3681 keystate[VK_RCONTROL] = CURRENT_STATE (VK_RCONTROL);
3682 keystate[VK_MENU] = CURRENT_STATE (VK_MENU);
3683 keystate[VK_LMENU] = CURRENT_STATE (VK_LMENU);
3684 keystate[VK_RMENU] = CURRENT_STATE (VK_RMENU);
3685 keystate[VK_LWIN] = CURRENT_STATE (VK_LWIN);
3686 keystate[VK_RWIN] = CURRENT_STATE (VK_RWIN);
3687 keystate[VK_APPS] = CURRENT_STATE (VK_APPS);
3688 SetKeyboardState (keystate);
3689 }
3690 }
3691
3692 /* Synchronize modifier state with what is reported with the current
3693 keystroke. Even if we cannot distinguish between left and right
3694 modifier keys, we know that, if no modifiers are set, then neither
3695 the left or right modifier should be set. */
3696 static void
3697 sync_modifiers ()
3698 {
3699 if (!modifiers_recorded)
3700 return;
3701
3702 if (!(GetKeyState (VK_CONTROL) & 0x8000))
3703 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3704
3705 if (!(GetKeyState (VK_MENU) & 0x8000))
3706 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3707 }
3708
3709 static int
3710 modifier_set (int vkey)
3711 {
3712 if (vkey == VK_CAPITAL || vkey == VK_SCROLL)
3713 return (GetKeyState (vkey) & 0x1);
3714 if (!modifiers_recorded)
3715 return (GetKeyState (vkey) & 0x8000);
3716
3717 switch (vkey)
3718 {
3719 case VK_LCONTROL:
3720 return modifiers[EMACS_LCONTROL];
3721 case VK_RCONTROL:
3722 return modifiers[EMACS_RCONTROL];
3723 case VK_LMENU:
3724 return modifiers[EMACS_LMENU];
3725 case VK_RMENU:
3726 return modifiers[EMACS_RMENU];
3727 }
3728 return (GetKeyState (vkey) & 0x8000);
3729 }
3730
3731 /* Convert between the modifier bits W32 uses and the modifier bits
3732 Emacs uses. */
3733
3734 unsigned int
3735 w32_key_to_modifier (int key)
3736 {
3737 Lisp_Object key_mapping;
3738
3739 switch (key)
3740 {
3741 case VK_LWIN:
3742 key_mapping = Vw32_lwindow_modifier;
3743 break;
3744 case VK_RWIN:
3745 key_mapping = Vw32_rwindow_modifier;
3746 break;
3747 case VK_APPS:
3748 key_mapping = Vw32_apps_modifier;
3749 break;
3750 case VK_SCROLL:
3751 key_mapping = Vw32_scroll_lock_modifier;
3752 break;
3753 default:
3754 key_mapping = Qnil;
3755 }
3756
3757 /* NB. This code runs in the input thread, asychronously to the lisp
3758 thread, so we must be careful to ensure access to lisp data is
3759 thread-safe. The following code is safe because the modifier
3760 variable values are updated atomically from lisp and symbols are
3761 not relocated by GC. Also, we don't have to worry about seeing GC
3762 markbits here. */
3763 if (EQ (key_mapping, Qhyper))
3764 return hyper_modifier;
3765 if (EQ (key_mapping, Qsuper))
3766 return super_modifier;
3767 if (EQ (key_mapping, Qmeta))
3768 return meta_modifier;
3769 if (EQ (key_mapping, Qalt))
3770 return alt_modifier;
3771 if (EQ (key_mapping, Qctrl))
3772 return ctrl_modifier;
3773 if (EQ (key_mapping, Qcontrol)) /* synonym for ctrl */
3774 return ctrl_modifier;
3775 if (EQ (key_mapping, Qshift))
3776 return shift_modifier;
3777
3778 /* Don't generate any modifier if not explicitly requested. */
3779 return 0;
3780 }
3781
3782 unsigned int
3783 w32_get_modifiers ()
3784 {
3785 return ((modifier_set (VK_SHIFT) ? shift_modifier : 0) |
3786 (modifier_set (VK_CONTROL) ? ctrl_modifier : 0) |
3787 (modifier_set (VK_LWIN) ? w32_key_to_modifier (VK_LWIN) : 0) |
3788 (modifier_set (VK_RWIN) ? w32_key_to_modifier (VK_RWIN) : 0) |
3789 (modifier_set (VK_APPS) ? w32_key_to_modifier (VK_APPS) : 0) |
3790 (modifier_set (VK_SCROLL) ? w32_key_to_modifier (VK_SCROLL) : 0) |
3791 (modifier_set (VK_MENU) ?
3792 ((NILP (Vw32_alt_is_meta)) ? alt_modifier : meta_modifier) : 0));
3793 }
3794
3795 /* We map the VK_* modifiers into console modifier constants
3796 so that we can use the same routines to handle both console
3797 and window input. */
3798
3799 static int
3800 construct_console_modifiers ()
3801 {
3802 int mods;
3803
3804 mods = 0;
3805 mods |= (modifier_set (VK_SHIFT)) ? SHIFT_PRESSED : 0;
3806 mods |= (modifier_set (VK_CAPITAL)) ? CAPSLOCK_ON : 0;
3807 mods |= (modifier_set (VK_SCROLL)) ? SCROLLLOCK_ON : 0;
3808 mods |= (modifier_set (VK_NUMLOCK)) ? NUMLOCK_ON : 0;
3809 mods |= (modifier_set (VK_LCONTROL)) ? LEFT_CTRL_PRESSED : 0;
3810 mods |= (modifier_set (VK_RCONTROL)) ? RIGHT_CTRL_PRESSED : 0;
3811 mods |= (modifier_set (VK_LMENU)) ? LEFT_ALT_PRESSED : 0;
3812 mods |= (modifier_set (VK_RMENU)) ? RIGHT_ALT_PRESSED : 0;
3813 mods |= (modifier_set (VK_LWIN)) ? LEFT_WIN_PRESSED : 0;
3814 mods |= (modifier_set (VK_RWIN)) ? RIGHT_WIN_PRESSED : 0;
3815 mods |= (modifier_set (VK_APPS)) ? APPS_PRESSED : 0;
3816
3817 return mods;
3818 }
3819
3820 static int
3821 w32_get_key_modifiers (unsigned int wparam, unsigned int lparam)
3822 {
3823 int mods;
3824
3825 /* Convert to emacs modifiers. */
3826 mods = w32_kbd_mods_to_emacs (construct_console_modifiers (), wparam);
3827
3828 return mods;
3829 }
3830
3831 unsigned int
3832 map_keypad_keys (unsigned int virt_key, unsigned int extended)
3833 {
3834 if (virt_key < VK_CLEAR || virt_key > VK_DELETE)
3835 return virt_key;
3836
3837 if (virt_key == VK_RETURN)
3838 return (extended ? VK_NUMPAD_ENTER : VK_RETURN);
3839
3840 if (virt_key >= VK_PRIOR && virt_key <= VK_DOWN)
3841 return (!extended ? (VK_NUMPAD_PRIOR + (virt_key - VK_PRIOR)) : virt_key);
3842
3843 if (virt_key == VK_INSERT || virt_key == VK_DELETE)
3844 return (!extended ? (VK_NUMPAD_INSERT + (virt_key - VK_INSERT)) : virt_key);
3845
3846 if (virt_key == VK_CLEAR)
3847 return (!extended ? VK_NUMPAD_CLEAR : virt_key);
3848
3849 return virt_key;
3850 }
3851
3852 /* List of special key combinations which w32 would normally capture,
3853 but emacs should grab instead. Not directly visible to lisp, to
3854 simplify synchronization. Each item is an integer encoding a virtual
3855 key code and modifier combination to capture. */
3856 Lisp_Object w32_grabbed_keys;
3857
3858 #define HOTKEY(vk,mods) make_number (((vk) & 255) | ((mods) << 8))
3859 #define HOTKEY_ID(k) (XFASTINT (k) & 0xbfff)
3860 #define HOTKEY_VK_CODE(k) (XFASTINT (k) & 255)
3861 #define HOTKEY_MODIFIERS(k) (XFASTINT (k) >> 8)
3862
3863 /* Register hot-keys for reserved key combinations when Emacs has
3864 keyboard focus, since this is the only way Emacs can receive key
3865 combinations like Alt-Tab which are used by the system. */
3866
3867 static void
3868 register_hot_keys (hwnd)
3869 HWND hwnd;
3870 {
3871 Lisp_Object keylist;
3872
3873 /* Use GC_CONSP, since we are called asynchronously. */
3874 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3875 {
3876 Lisp_Object key = XCAR (keylist);
3877
3878 /* Deleted entries get set to nil. */
3879 if (!INTEGERP (key))
3880 continue;
3881
3882 RegisterHotKey (hwnd, HOTKEY_ID (key),
3883 HOTKEY_MODIFIERS (key), HOTKEY_VK_CODE (key));
3884 }
3885 }
3886
3887 static void
3888 unregister_hot_keys (hwnd)
3889 HWND hwnd;
3890 {
3891 Lisp_Object keylist;
3892
3893 /* Use GC_CONSP, since we are called asynchronously. */
3894 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3895 {
3896 Lisp_Object key = XCAR (keylist);
3897
3898 if (!INTEGERP (key))
3899 continue;
3900
3901 UnregisterHotKey (hwnd, HOTKEY_ID (key));
3902 }
3903 }
3904
3905 /* Main message dispatch loop. */
3906
3907 static void
3908 w32_msg_pump (deferred_msg * msg_buf)
3909 {
3910 MSG msg;
3911 int result;
3912 HWND focus_window;
3913
3914 msh_mousewheel = RegisterWindowMessage (MSH_MOUSEWHEEL);
3915
3916 while (GetMessage (&msg, NULL, 0, 0))
3917 {
3918 if (msg.hwnd == NULL)
3919 {
3920 switch (msg.message)
3921 {
3922 case WM_NULL:
3923 /* Produced by complete_deferred_msg; just ignore. */
3924 break;
3925 case WM_EMACS_CREATEWINDOW:
3926 w32_createwindow ((struct frame *) msg.wParam);
3927 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3928 abort ();
3929 break;
3930 case WM_EMACS_SETLOCALE:
3931 SetThreadLocale (msg.wParam);
3932 /* Reply is not expected. */
3933 break;
3934 case WM_EMACS_SETKEYBOARDLAYOUT:
3935 result = (int) ActivateKeyboardLayout ((HKL) msg.wParam, 0);
3936 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
3937 result, 0))
3938 abort ();
3939 break;
3940 case WM_EMACS_REGISTER_HOT_KEY:
3941 focus_window = GetFocus ();
3942 if (focus_window != NULL)
3943 RegisterHotKey (focus_window,
3944 HOTKEY_ID (msg.wParam),
3945 HOTKEY_MODIFIERS (msg.wParam),
3946 HOTKEY_VK_CODE (msg.wParam));
3947 /* Reply is not expected. */
3948 break;
3949 case WM_EMACS_UNREGISTER_HOT_KEY:
3950 focus_window = GetFocus ();
3951 if (focus_window != NULL)
3952 UnregisterHotKey (focus_window, HOTKEY_ID (msg.wParam));
3953 /* Mark item as erased. NB: this code must be
3954 thread-safe. The next line is okay because the cons
3955 cell is never made into garbage and is not relocated by
3956 GC. */
3957 XSETCAR ((Lisp_Object) msg.lParam, Qnil);
3958 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3959 abort ();
3960 break;
3961 case WM_EMACS_TOGGLE_LOCK_KEY:
3962 {
3963 int vk_code = (int) msg.wParam;
3964 int cur_state = (GetKeyState (vk_code) & 1);
3965 Lisp_Object new_state = (Lisp_Object) msg.lParam;
3966
3967 /* NB: This code must be thread-safe. It is safe to
3968 call NILP because symbols are not relocated by GC,
3969 and pointer here is not touched by GC (so the markbit
3970 can't be set). Numbers are safe because they are
3971 immediate values. */
3972 if (NILP (new_state)
3973 || (NUMBERP (new_state)
3974 && ((XUINT (new_state)) & 1) != cur_state))
3975 {
3976 one_w32_display_info.faked_key = vk_code;
3977
3978 keybd_event ((BYTE) vk_code,
3979 (BYTE) MapVirtualKey (vk_code, 0),
3980 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3981 keybd_event ((BYTE) vk_code,
3982 (BYTE) MapVirtualKey (vk_code, 0),
3983 KEYEVENTF_EXTENDEDKEY | 0, 0);
3984 keybd_event ((BYTE) vk_code,
3985 (BYTE) MapVirtualKey (vk_code, 0),
3986 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3987 cur_state = !cur_state;
3988 }
3989 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
3990 cur_state, 0))
3991 abort ();
3992 }
3993 break;
3994 default:
3995 DebPrint (("msg %x not expected by w32_msg_pump\n", msg.message));
3996 }
3997 }
3998 else
3999 {
4000 DispatchMessage (&msg);
4001 }
4002
4003 /* Exit nested loop when our deferred message has completed. */
4004 if (msg_buf->completed)
4005 break;
4006 }
4007 }
4008
4009 deferred_msg * deferred_msg_head;
4010
4011 static deferred_msg *
4012 find_deferred_msg (HWND hwnd, UINT msg)
4013 {
4014 deferred_msg * item;
4015
4016 /* Don't actually need synchronization for read access, since
4017 modification of single pointer is always atomic. */
4018 /* enter_crit (); */
4019
4020 for (item = deferred_msg_head; item != NULL; item = item->next)
4021 if (item->w32msg.msg.hwnd == hwnd
4022 && item->w32msg.msg.message == msg)
4023 break;
4024
4025 /* leave_crit (); */
4026
4027 return item;
4028 }
4029
4030 static LRESULT
4031 send_deferred_msg (deferred_msg * msg_buf,
4032 HWND hwnd,
4033 UINT msg,
4034 WPARAM wParam,
4035 LPARAM lParam)
4036 {
4037 /* Only input thread can send deferred messages. */
4038 if (GetCurrentThreadId () != dwWindowsThreadId)
4039 abort ();
4040
4041 /* It is an error to send a message that is already deferred. */
4042 if (find_deferred_msg (hwnd, msg) != NULL)
4043 abort ();
4044
4045 /* Enforced synchronization is not needed because this is the only
4046 function that alters deferred_msg_head, and the following critical
4047 section is guaranteed to only be serially reentered (since only the
4048 input thread can call us). */
4049
4050 /* enter_crit (); */
4051
4052 msg_buf->completed = 0;
4053 msg_buf->next = deferred_msg_head;
4054 deferred_msg_head = msg_buf;
4055 my_post_msg (&msg_buf->w32msg, hwnd, msg, wParam, lParam);
4056
4057 /* leave_crit (); */
4058
4059 /* Start a new nested message loop to process other messages until
4060 this one is completed. */
4061 w32_msg_pump (msg_buf);
4062
4063 deferred_msg_head = msg_buf->next;
4064
4065 return msg_buf->result;
4066 }
4067
4068 void
4069 complete_deferred_msg (HWND hwnd, UINT msg, LRESULT result)
4070 {
4071 deferred_msg * msg_buf = find_deferred_msg (hwnd, msg);
4072
4073 if (msg_buf == NULL)
4074 /* Message may have been cancelled, so don't abort(). */
4075 return;
4076
4077 msg_buf->result = result;
4078 msg_buf->completed = 1;
4079
4080 /* Ensure input thread is woken so it notices the completion. */
4081 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
4082 }
4083
4084 void
4085 cancel_all_deferred_msgs ()
4086 {
4087 deferred_msg * item;
4088
4089 /* Don't actually need synchronization for read access, since
4090 modification of single pointer is always atomic. */
4091 /* enter_crit (); */
4092
4093 for (item = deferred_msg_head; item != NULL; item = item->next)
4094 {
4095 item->result = 0;
4096 item->completed = 1;
4097 }
4098
4099 /* leave_crit (); */
4100
4101 /* Ensure input thread is woken so it notices the completion. */
4102 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
4103 }
4104
4105 DWORD
4106 w32_msg_worker (dw)
4107 DWORD dw;
4108 {
4109 MSG msg;
4110 deferred_msg dummy_buf;
4111
4112 /* Ensure our message queue is created */
4113
4114 PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
4115
4116 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
4117 abort ();
4118
4119 memset (&dummy_buf, 0, sizeof (dummy_buf));
4120 dummy_buf.w32msg.msg.hwnd = NULL;
4121 dummy_buf.w32msg.msg.message = WM_NULL;
4122
4123 /* This is the inital message loop which should only exit when the
4124 application quits. */
4125 w32_msg_pump (&dummy_buf);
4126
4127 return 0;
4128 }
4129
4130 static void
4131 post_character_message (hwnd, msg, wParam, lParam, modifiers)
4132 HWND hwnd;
4133 UINT msg;
4134 WPARAM wParam;
4135 LPARAM lParam;
4136 DWORD modifiers;
4137
4138 {
4139 W32Msg wmsg;
4140
4141 wmsg.dwModifiers = modifiers;
4142
4143 /* Detect quit_char and set quit-flag directly. Note that we
4144 still need to post a message to ensure the main thread will be
4145 woken up if blocked in sys_select(), but we do NOT want to post
4146 the quit_char message itself (because it will usually be as if
4147 the user had typed quit_char twice). Instead, we post a dummy
4148 message that has no particular effect. */
4149 {
4150 int c = wParam;
4151 if (isalpha (c) && wmsg.dwModifiers == ctrl_modifier)
4152 c = make_ctrl_char (c) & 0377;
4153 if (c == quit_char
4154 || (wmsg.dwModifiers == 0 &&
4155 XFASTINT (Vw32_quit_key) && wParam == XFASTINT (Vw32_quit_key)))
4156 {
4157 Vquit_flag = Qt;
4158
4159 /* The choice of message is somewhat arbitrary, as long as
4160 the main thread handler just ignores it. */
4161 msg = WM_NULL;
4162
4163 /* Interrupt any blocking system calls. */
4164 signal_quit ();
4165
4166 /* As a safety precaution, forcibly complete any deferred
4167 messages. This is a kludge, but I don't see any particularly
4168 clean way to handle the situation where a deferred message is
4169 "dropped" in the lisp thread, and will thus never be
4170 completed, eg. by the user trying to activate the menubar
4171 when the lisp thread is busy, and then typing C-g when the
4172 menubar doesn't open promptly (with the result that the
4173 menubar never responds at all because the deferred
4174 WM_INITMENU message is never completed). Another problem
4175 situation is when the lisp thread calls SendMessage (to send
4176 a window manager command) when a message has been deferred;
4177 the lisp thread gets blocked indefinitely waiting for the
4178 deferred message to be completed, which itself is waiting for
4179 the lisp thread to respond.
4180
4181 Note that we don't want to block the input thread waiting for
4182 a reponse from the lisp thread (although that would at least
4183 solve the deadlock problem above), because we want to be able
4184 to receive C-g to interrupt the lisp thread. */
4185 cancel_all_deferred_msgs ();
4186 }
4187 }
4188
4189 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4190 }
4191
4192 /* Main window procedure */
4193
4194 LRESULT CALLBACK
4195 w32_wnd_proc (hwnd, msg, wParam, lParam)
4196 HWND hwnd;
4197 UINT msg;
4198 WPARAM wParam;
4199 LPARAM lParam;
4200 {
4201 struct frame *f;
4202 struct w32_display_info *dpyinfo = &one_w32_display_info;
4203 W32Msg wmsg;
4204 int windows_translate;
4205 int key;
4206
4207 /* Note that it is okay to call x_window_to_frame, even though we are
4208 not running in the main lisp thread, because frame deletion
4209 requires the lisp thread to synchronize with this thread. Thus, if
4210 a frame struct is returned, it can be used without concern that the
4211 lisp thread might make it disappear while we are using it.
4212
4213 NB. Walking the frame list in this thread is safe (as long as
4214 writes of Lisp_Object slots are atomic, which they are on Windows).
4215 Although delete-frame can destructively modify the frame list while
4216 we are walking it, a garbage collection cannot occur until after
4217 delete-frame has synchronized with this thread.
4218
4219 It is also safe to use functions that make GDI calls, such as
4220 w32_clear_rect, because these functions must obtain a DC handle
4221 from the frame struct using get_frame_dc which is thread-aware. */
4222
4223 switch (msg)
4224 {
4225 case WM_ERASEBKGND:
4226 f = x_window_to_frame (dpyinfo, hwnd);
4227 if (f)
4228 {
4229 HDC hdc = get_frame_dc (f);
4230 GetUpdateRect (hwnd, &wmsg.rect, FALSE);
4231 w32_clear_rect (f, hdc, &wmsg.rect);
4232 release_frame_dc (f, hdc);
4233
4234 #if defined (W32_DEBUG_DISPLAY)
4235 DebPrint (("WM_ERASEBKGND (frame %p): erasing %d,%d-%d,%d\n",
4236 f,
4237 wmsg.rect.left, wmsg.rect.top,
4238 wmsg.rect.right, wmsg.rect.bottom));
4239 #endif /* W32_DEBUG_DISPLAY */
4240 }
4241 return 1;
4242 case WM_PALETTECHANGED:
4243 /* ignore our own changes */
4244 if ((HWND)wParam != hwnd)
4245 {
4246 f = x_window_to_frame (dpyinfo, hwnd);
4247 if (f)
4248 /* get_frame_dc will realize our palette and force all
4249 frames to be redrawn if needed. */
4250 release_frame_dc (f, get_frame_dc (f));
4251 }
4252 return 0;
4253 case WM_PAINT:
4254 {
4255 PAINTSTRUCT paintStruct;
4256 RECT update_rect;
4257 bzero (&update_rect, sizeof (update_rect));
4258
4259 f = x_window_to_frame (dpyinfo, hwnd);
4260 if (f == 0)
4261 {
4262 DebPrint (("WM_PAINT received for unknown window %p\n", hwnd));
4263 return 0;
4264 }
4265
4266 /* MSDN Docs say not to call BeginPaint if GetUpdateRect
4267 fails. Apparently this can happen under some
4268 circumstances. */
4269 if (GetUpdateRect (hwnd, &update_rect, FALSE) || !w32_strict_painting)
4270 {
4271 enter_crit ();
4272 BeginPaint (hwnd, &paintStruct);
4273
4274 /* The rectangles returned by GetUpdateRect and BeginPaint
4275 do not always match. Play it safe by assuming both areas
4276 are invalid. */
4277 UnionRect (&(wmsg.rect), &update_rect, &(paintStruct.rcPaint));
4278
4279 #if defined (W32_DEBUG_DISPLAY)
4280 DebPrint (("WM_PAINT (frame %p): painting %d,%d-%d,%d\n",
4281 f,
4282 wmsg.rect.left, wmsg.rect.top,
4283 wmsg.rect.right, wmsg.rect.bottom));
4284 DebPrint ((" [update region is %d,%d-%d,%d]\n",
4285 update_rect.left, update_rect.top,
4286 update_rect.right, update_rect.bottom));
4287 #endif
4288 EndPaint (hwnd, &paintStruct);
4289 leave_crit ();
4290
4291 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4292
4293 return 0;
4294 }
4295
4296 /* If GetUpdateRect returns 0 (meaning there is no update
4297 region), assume the whole window needs to be repainted. */
4298 GetClientRect(hwnd, &wmsg.rect);
4299 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4300 return 0;
4301 }
4302
4303 case WM_INPUTLANGCHANGE:
4304 /* Inform lisp thread of keyboard layout changes. */
4305 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4306
4307 /* Clear dead keys in the keyboard state; for simplicity only
4308 preserve modifier key states. */
4309 {
4310 int i;
4311 BYTE keystate[256];
4312
4313 GetKeyboardState (keystate);
4314 for (i = 0; i < 256; i++)
4315 if (1
4316 && i != VK_SHIFT
4317 && i != VK_LSHIFT
4318 && i != VK_RSHIFT
4319 && i != VK_CAPITAL
4320 && i != VK_NUMLOCK
4321 && i != VK_SCROLL
4322 && i != VK_CONTROL
4323 && i != VK_LCONTROL
4324 && i != VK_RCONTROL
4325 && i != VK_MENU
4326 && i != VK_LMENU
4327 && i != VK_RMENU
4328 && i != VK_LWIN
4329 && i != VK_RWIN)
4330 keystate[i] = 0;
4331 SetKeyboardState (keystate);
4332 }
4333 goto dflt;
4334
4335 case WM_HOTKEY:
4336 /* Synchronize hot keys with normal input. */
4337 PostMessage (hwnd, WM_KEYDOWN, HIWORD (lParam), 0);
4338 return (0);
4339
4340 case WM_KEYUP:
4341 case WM_SYSKEYUP:
4342 record_keyup (wParam, lParam);
4343 goto dflt;
4344
4345 case WM_KEYDOWN:
4346 case WM_SYSKEYDOWN:
4347 /* Ignore keystrokes we fake ourself; see below. */
4348 if (dpyinfo->faked_key == wParam)
4349 {
4350 dpyinfo->faked_key = 0;
4351 /* Make sure TranslateMessage sees them though (as long as
4352 they don't produce WM_CHAR messages). This ensures that
4353 indicator lights are toggled promptly on Windows 9x, for
4354 example. */
4355 if (lispy_function_keys[wParam] != 0)
4356 {
4357 windows_translate = 1;
4358 goto translate;
4359 }
4360 return 0;
4361 }
4362
4363 /* Synchronize modifiers with current keystroke. */
4364 sync_modifiers ();
4365 record_keydown (wParam, lParam);
4366 wParam = map_keypad_keys (wParam, (lParam & 0x1000000L) != 0);
4367
4368 windows_translate = 0;
4369
4370 switch (wParam)
4371 {
4372 case VK_LWIN:
4373 if (NILP (Vw32_pass_lwindow_to_system))
4374 {
4375 /* Prevent system from acting on keyup (which opens the
4376 Start menu if no other key was pressed) by simulating a
4377 press of Space which we will ignore. */
4378 if (GetAsyncKeyState (wParam) & 1)
4379 {
4380 if (NUMBERP (Vw32_phantom_key_code))
4381 key = XUINT (Vw32_phantom_key_code) & 255;
4382 else
4383 key = VK_SPACE;
4384 dpyinfo->faked_key = key;
4385 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
4386 }
4387 }
4388 if (!NILP (Vw32_lwindow_modifier))
4389 return 0;
4390 break;
4391 case VK_RWIN:
4392 if (NILP (Vw32_pass_rwindow_to_system))
4393 {
4394 if (GetAsyncKeyState (wParam) & 1)
4395 {
4396 if (NUMBERP (Vw32_phantom_key_code))
4397 key = XUINT (Vw32_phantom_key_code) & 255;
4398 else
4399 key = VK_SPACE;
4400 dpyinfo->faked_key = key;
4401 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
4402 }
4403 }
4404 if (!NILP (Vw32_rwindow_modifier))
4405 return 0;
4406 break;
4407 case VK_APPS:
4408 if (!NILP (Vw32_apps_modifier))
4409 return 0;
4410 break;
4411 case VK_MENU:
4412 if (NILP (Vw32_pass_alt_to_system))
4413 /* Prevent DefWindowProc from activating the menu bar if an
4414 Alt key is pressed and released by itself. */
4415 return 0;
4416 windows_translate = 1;
4417 break;
4418 case VK_CAPITAL:
4419 /* Decide whether to treat as modifier or function key. */
4420 if (NILP (Vw32_enable_caps_lock))
4421 goto disable_lock_key;
4422 windows_translate = 1;
4423 break;
4424 case VK_NUMLOCK:
4425 /* Decide whether to treat as modifier or function key. */
4426 if (NILP (Vw32_enable_num_lock))
4427 goto disable_lock_key;
4428 windows_translate = 1;
4429 break;
4430 case VK_SCROLL:
4431 /* Decide whether to treat as modifier or function key. */
4432 if (NILP (Vw32_scroll_lock_modifier))
4433 goto disable_lock_key;
4434 windows_translate = 1;
4435 break;
4436 disable_lock_key:
4437 /* Ensure the appropriate lock key state (and indicator light)
4438 remains in the same state. We do this by faking another
4439 press of the relevant key. Apparently, this really is the
4440 only way to toggle the state of the indicator lights. */
4441 dpyinfo->faked_key = wParam;
4442 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4443 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4444 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4445 KEYEVENTF_EXTENDEDKEY | 0, 0);
4446 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4447 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4448 /* Ensure indicator lights are updated promptly on Windows 9x
4449 (TranslateMessage apparently does this), after forwarding
4450 input event. */
4451 post_character_message (hwnd, msg, wParam, lParam,
4452 w32_get_key_modifiers (wParam, lParam));
4453 windows_translate = 1;
4454 break;
4455 case VK_CONTROL:
4456 case VK_SHIFT:
4457 case VK_PROCESSKEY: /* Generated by IME. */
4458 windows_translate = 1;
4459 break;
4460 case VK_CANCEL:
4461 /* Windows maps Ctrl-Pause (aka Ctrl-Break) into VK_CANCEL,
4462 which is confusing for purposes of key binding; convert
4463 VK_CANCEL events into VK_PAUSE events. */
4464 wParam = VK_PAUSE;
4465 break;
4466 case VK_PAUSE:
4467 /* Windows maps Ctrl-NumLock into VK_PAUSE, which is confusing
4468 for purposes of key binding; convert these back into
4469 VK_NUMLOCK events, at least when we want to see NumLock key
4470 presses. (Note that there is never any possibility that
4471 VK_PAUSE with Ctrl really is C-Pause as per above.) */
4472 if (NILP (Vw32_enable_num_lock) && modifier_set (VK_CONTROL))
4473 wParam = VK_NUMLOCK;
4474 break;
4475 default:
4476 /* If not defined as a function key, change it to a WM_CHAR message. */
4477 if (lispy_function_keys[wParam] == 0)
4478 {
4479 DWORD modifiers = construct_console_modifiers ();
4480
4481 if (!NILP (Vw32_recognize_altgr)
4482 && modifier_set (VK_LCONTROL) && modifier_set (VK_RMENU))
4483 {
4484 /* Always let TranslateMessage handle AltGr key chords;
4485 for some reason, ToAscii doesn't always process AltGr
4486 chords correctly. */
4487 windows_translate = 1;
4488 }
4489 else if ((modifiers & (~SHIFT_PRESSED & ~CAPSLOCK_ON)) != 0)
4490 {
4491 /* Handle key chords including any modifiers other
4492 than shift directly, in order to preserve as much
4493 modifier information as possible. */
4494 if ('A' <= wParam && wParam <= 'Z')
4495 {
4496 /* Don't translate modified alphabetic keystrokes,
4497 so the user doesn't need to constantly switch
4498 layout to type control or meta keystrokes when
4499 the normal layout translates alphabetic
4500 characters to non-ascii characters. */
4501 if (!modifier_set (VK_SHIFT))
4502 wParam += ('a' - 'A');
4503 msg = WM_CHAR;
4504 }
4505 else
4506 {
4507 /* Try to handle other keystrokes by determining the
4508 base character (ie. translating the base key plus
4509 shift modifier). */
4510 int add;
4511 int isdead = 0;
4512 KEY_EVENT_RECORD key;
4513
4514 key.bKeyDown = TRUE;
4515 key.wRepeatCount = 1;
4516 key.wVirtualKeyCode = wParam;
4517 key.wVirtualScanCode = (lParam & 0xFF0000) >> 16;
4518 key.uChar.AsciiChar = 0;
4519 key.dwControlKeyState = modifiers;
4520
4521 add = w32_kbd_patch_key (&key);
4522 /* 0 means an unrecognised keycode, negative means
4523 dead key. Ignore both. */
4524 while (--add >= 0)
4525 {
4526 /* Forward asciified character sequence. */
4527 post_character_message
4528 (hwnd, WM_CHAR, key.uChar.AsciiChar, lParam,
4529 w32_get_key_modifiers (wParam, lParam));
4530 w32_kbd_patch_key (&key);
4531 }
4532 return 0;
4533 }
4534 }
4535 else
4536 {
4537 /* Let TranslateMessage handle everything else. */
4538 windows_translate = 1;
4539 }
4540 }
4541 }
4542
4543 translate:
4544 if (windows_translate)
4545 {
4546 MSG windows_msg = { hwnd, msg, wParam, lParam, 0, {0,0} };
4547
4548 windows_msg.time = GetMessageTime ();
4549 TranslateMessage (&windows_msg);
4550 goto dflt;
4551 }
4552
4553 /* Fall through */
4554
4555 case WM_SYSCHAR:
4556 case WM_CHAR:
4557 post_character_message (hwnd, msg, wParam, lParam,
4558 w32_get_key_modifiers (wParam, lParam));
4559 break;
4560
4561 /* Simulate middle mouse button events when left and right buttons
4562 are used together, but only if user has two button mouse. */
4563 case WM_LBUTTONDOWN:
4564 case WM_RBUTTONDOWN:
4565 if (XINT (Vw32_num_mouse_buttons) > 2)
4566 goto handle_plain_button;
4567
4568 {
4569 int this = (msg == WM_LBUTTONDOWN) ? LMOUSE : RMOUSE;
4570 int other = (msg == WM_LBUTTONDOWN) ? RMOUSE : LMOUSE;
4571
4572 if (button_state & this)
4573 return 0;
4574
4575 if (button_state == 0)
4576 SetCapture (hwnd);
4577
4578 button_state |= this;
4579
4580 if (button_state & other)
4581 {
4582 if (mouse_button_timer)
4583 {
4584 KillTimer (hwnd, mouse_button_timer);
4585 mouse_button_timer = 0;
4586
4587 /* Generate middle mouse event instead. */
4588 msg = WM_MBUTTONDOWN;
4589 button_state |= MMOUSE;
4590 }
4591 else if (button_state & MMOUSE)
4592 {
4593 /* Ignore button event if we've already generated a
4594 middle mouse down event. This happens if the
4595 user releases and press one of the two buttons
4596 after we've faked a middle mouse event. */
4597 return 0;
4598 }
4599 else
4600 {
4601 /* Flush out saved message. */
4602 post_msg (&saved_mouse_button_msg);
4603 }
4604 wmsg.dwModifiers = w32_get_modifiers ();
4605 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4606
4607 /* Clear message buffer. */
4608 saved_mouse_button_msg.msg.hwnd = 0;
4609 }
4610 else
4611 {
4612 /* Hold onto message for now. */
4613 mouse_button_timer =
4614 SetTimer (hwnd, MOUSE_BUTTON_ID,
4615 XINT (Vw32_mouse_button_tolerance), NULL);
4616 saved_mouse_button_msg.msg.hwnd = hwnd;
4617 saved_mouse_button_msg.msg.message = msg;
4618 saved_mouse_button_msg.msg.wParam = wParam;
4619 saved_mouse_button_msg.msg.lParam = lParam;
4620 saved_mouse_button_msg.msg.time = GetMessageTime ();
4621 saved_mouse_button_msg.dwModifiers = w32_get_modifiers ();
4622 }
4623 }
4624 return 0;
4625
4626 case WM_LBUTTONUP:
4627 case WM_RBUTTONUP:
4628 if (XINT (Vw32_num_mouse_buttons) > 2)
4629 goto handle_plain_button;
4630
4631 {
4632 int this = (msg == WM_LBUTTONUP) ? LMOUSE : RMOUSE;
4633 int other = (msg == WM_LBUTTONUP) ? RMOUSE : LMOUSE;
4634
4635 if ((button_state & this) == 0)
4636 return 0;
4637
4638 button_state &= ~this;
4639
4640 if (button_state & MMOUSE)
4641 {
4642 /* Only generate event when second button is released. */
4643 if ((button_state & other) == 0)
4644 {
4645 msg = WM_MBUTTONUP;
4646 button_state &= ~MMOUSE;
4647
4648 if (button_state) abort ();
4649 }
4650 else
4651 return 0;
4652 }
4653 else
4654 {
4655 /* Flush out saved message if necessary. */
4656 if (saved_mouse_button_msg.msg.hwnd)
4657 {
4658 post_msg (&saved_mouse_button_msg);
4659 }
4660 }
4661 wmsg.dwModifiers = w32_get_modifiers ();
4662 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4663
4664 /* Always clear message buffer and cancel timer. */
4665 saved_mouse_button_msg.msg.hwnd = 0;
4666 KillTimer (hwnd, mouse_button_timer);
4667 mouse_button_timer = 0;
4668
4669 if (button_state == 0)
4670 ReleaseCapture ();
4671 }
4672 return 0;
4673
4674 case WM_XBUTTONDOWN:
4675 case WM_XBUTTONUP:
4676 if (w32_pass_extra_mouse_buttons_to_system)
4677 goto dflt;
4678 /* else fall through and process them. */
4679 case WM_MBUTTONDOWN:
4680 case WM_MBUTTONUP:
4681 handle_plain_button:
4682 {
4683 BOOL up;
4684 int button;
4685
4686 if (parse_button (msg, HIWORD (wParam), &button, &up))
4687 {
4688 if (up) ReleaseCapture ();
4689 else SetCapture (hwnd);
4690 button = (button == 0) ? LMOUSE :
4691 ((button == 1) ? MMOUSE : RMOUSE);
4692 if (up)
4693 button_state &= ~button;
4694 else
4695 button_state |= button;
4696 }
4697 }
4698
4699 wmsg.dwModifiers = w32_get_modifiers ();
4700 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4701
4702 /* Need to return true for XBUTTON messages, false for others,
4703 to indicate that we processed the message. */
4704 return (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONUP);
4705
4706 case WM_MOUSEMOVE:
4707 /* If the mouse has just moved into the frame, start tracking
4708 it, so we will be notified when it leaves the frame. Mouse
4709 tracking only works under W98 and NT4 and later. On earlier
4710 versions, there is no way of telling when the mouse leaves the
4711 frame, so we just have to put up with help-echo and mouse
4712 highlighting remaining while the frame is not active. */
4713 if (track_mouse_event_fn && !track_mouse_window)
4714 {
4715 TRACKMOUSEEVENT tme;
4716 tme.cbSize = sizeof (tme);
4717 tme.dwFlags = TME_LEAVE;
4718 tme.hwndTrack = hwnd;
4719
4720 track_mouse_event_fn (&tme);
4721 track_mouse_window = hwnd;
4722 }
4723 case WM_VSCROLL:
4724 if (XINT (Vw32_mouse_move_interval) <= 0
4725 || (msg == WM_MOUSEMOVE && button_state == 0))
4726 {
4727 wmsg.dwModifiers = w32_get_modifiers ();
4728 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4729 return 0;
4730 }
4731
4732 /* Hang onto mouse move and scroll messages for a bit, to avoid
4733 sending such events to Emacs faster than it can process them.
4734 If we get more events before the timer from the first message
4735 expires, we just replace the first message. */
4736
4737 if (saved_mouse_move_msg.msg.hwnd == 0)
4738 mouse_move_timer =
4739 SetTimer (hwnd, MOUSE_MOVE_ID,
4740 XINT (Vw32_mouse_move_interval), NULL);
4741
4742 /* Hold onto message for now. */
4743 saved_mouse_move_msg.msg.hwnd = hwnd;
4744 saved_mouse_move_msg.msg.message = msg;
4745 saved_mouse_move_msg.msg.wParam = wParam;
4746 saved_mouse_move_msg.msg.lParam = lParam;
4747 saved_mouse_move_msg.msg.time = GetMessageTime ();
4748 saved_mouse_move_msg.dwModifiers = w32_get_modifiers ();
4749
4750 return 0;
4751
4752 case WM_MOUSEWHEEL:
4753 wmsg.dwModifiers = w32_get_modifiers ();
4754 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4755 return 0;
4756
4757 case WM_DROPFILES:
4758 wmsg.dwModifiers = w32_get_modifiers ();
4759 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4760 return 0;
4761
4762 case WM_TIMER:
4763 /* Flush out saved messages if necessary. */
4764 if (wParam == mouse_button_timer)
4765 {
4766 if (saved_mouse_button_msg.msg.hwnd)
4767 {
4768 post_msg (&saved_mouse_button_msg);
4769 saved_mouse_button_msg.msg.hwnd = 0;
4770 }
4771 KillTimer (hwnd, mouse_button_timer);
4772 mouse_button_timer = 0;
4773 }
4774 else if (wParam == mouse_move_timer)
4775 {
4776 if (saved_mouse_move_msg.msg.hwnd)
4777 {
4778 post_msg (&saved_mouse_move_msg);
4779 saved_mouse_move_msg.msg.hwnd = 0;
4780 }
4781 KillTimer (hwnd, mouse_move_timer);
4782 mouse_move_timer = 0;
4783 }
4784 else if (wParam == menu_free_timer)
4785 {
4786 KillTimer (hwnd, menu_free_timer);
4787 menu_free_timer = 0;
4788 f = x_window_to_frame (dpyinfo, hwnd);
4789 if (!f->output_data.w32->menu_command_in_progress)
4790 {
4791 /* Free memory used by owner-drawn and help-echo strings. */
4792 w32_free_menu_strings (hwnd);
4793 f->output_data.w32->menubar_active = 0;
4794 }
4795 }
4796 return 0;
4797
4798 case WM_NCACTIVATE:
4799 /* Windows doesn't send us focus messages when putting up and
4800 taking down a system popup dialog as for Ctrl-Alt-Del on Windows 95.
4801 The only indication we get that something happened is receiving
4802 this message afterwards. So this is a good time to reset our
4803 keyboard modifiers' state. */
4804 reset_modifiers ();
4805 goto dflt;
4806
4807 case WM_INITMENU:
4808 button_state = 0;
4809 ReleaseCapture ();
4810 /* We must ensure menu bar is fully constructed and up to date
4811 before allowing user interaction with it. To achieve this
4812 we send this message to the lisp thread and wait for a
4813 reply (whose value is not actually needed) to indicate that
4814 the menu bar is now ready for use, so we can now return.
4815
4816 To remain responsive in the meantime, we enter a nested message
4817 loop that can process all other messages.
4818
4819 However, we skip all this if the message results from calling
4820 TrackPopupMenu - in fact, we must NOT attempt to send the lisp
4821 thread a message because it is blocked on us at this point. We
4822 set menubar_active before calling TrackPopupMenu to indicate
4823 this (there is no possibility of confusion with real menubar
4824 being active). */
4825
4826 f = x_window_to_frame (dpyinfo, hwnd);
4827 if (f
4828 && (f->output_data.w32->menubar_active
4829 /* We can receive this message even in the absence of a
4830 menubar (ie. when the system menu is activated) - in this
4831 case we do NOT want to forward the message, otherwise it
4832 will cause the menubar to suddenly appear when the user
4833 had requested it to be turned off! */
4834 || f->output_data.w32->menubar_widget == NULL))
4835 return 0;
4836
4837 {
4838 deferred_msg msg_buf;
4839
4840 /* Detect if message has already been deferred; in this case
4841 we cannot return any sensible value to ignore this. */
4842 if (find_deferred_msg (hwnd, msg) != NULL)
4843 abort ();
4844
4845 return send_deferred_msg (&msg_buf, hwnd, msg, wParam, lParam);
4846 }
4847
4848 case WM_EXITMENULOOP:
4849 f = x_window_to_frame (dpyinfo, hwnd);
4850
4851 /* If a menu command is not already in progress, check again
4852 after a short delay, since Windows often (always?) sends the
4853 WM_EXITMENULOOP before the corresponding WM_COMMAND message. */
4854 if (f && !f->output_data.w32->menu_command_in_progress)
4855 menu_free_timer = SetTimer (hwnd, MENU_FREE_ID, MENU_FREE_DELAY, NULL);
4856 goto dflt;
4857
4858 case WM_MENUSELECT:
4859 /* Direct handling of help_echo in menus. Should be safe now
4860 that we generate the help_echo by placing a help event in the
4861 keyboard buffer. */
4862 {
4863 HMENU menu = (HMENU) lParam;
4864 UINT menu_item = (UINT) LOWORD (wParam);
4865 UINT flags = (UINT) HIWORD (wParam);
4866
4867 w32_menu_display_help (hwnd, menu, menu_item, flags);
4868 }
4869 return 0;
4870
4871 case WM_MEASUREITEM:
4872 f = x_window_to_frame (dpyinfo, hwnd);
4873 if (f)
4874 {
4875 MEASUREITEMSTRUCT * pMis = (MEASUREITEMSTRUCT *) lParam;
4876
4877 if (pMis->CtlType == ODT_MENU)
4878 {
4879 /* Work out dimensions for popup menu titles. */
4880 char * title = (char *) pMis->itemData;
4881 HDC hdc = GetDC (hwnd);
4882 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4883 LOGFONT menu_logfont;
4884 HFONT old_font;
4885 SIZE size;
4886
4887 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4888 menu_logfont.lfWeight = FW_BOLD;
4889 menu_font = CreateFontIndirect (&menu_logfont);
4890 old_font = SelectObject (hdc, menu_font);
4891
4892 pMis->itemHeight = GetSystemMetrics (SM_CYMENUSIZE);
4893 if (title)
4894 {
4895 GetTextExtentPoint32 (hdc, title, strlen (title), &size);
4896 pMis->itemWidth = size.cx;
4897 if (pMis->itemHeight < size.cy)
4898 pMis->itemHeight = size.cy;
4899 }
4900 else
4901 pMis->itemWidth = 0;
4902
4903 SelectObject (hdc, old_font);
4904 DeleteObject (menu_font);
4905 ReleaseDC (hwnd, hdc);
4906 return TRUE;
4907 }
4908 }
4909 return 0;
4910
4911 case WM_DRAWITEM:
4912 f = x_window_to_frame (dpyinfo, hwnd);
4913 if (f)
4914 {
4915 DRAWITEMSTRUCT * pDis = (DRAWITEMSTRUCT *) lParam;
4916
4917 if (pDis->CtlType == ODT_MENU)
4918 {
4919 /* Draw popup menu title. */
4920 char * title = (char *) pDis->itemData;
4921 if (title)
4922 {
4923 HDC hdc = pDis->hDC;
4924 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4925 LOGFONT menu_logfont;
4926 HFONT old_font;
4927
4928 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4929 menu_logfont.lfWeight = FW_BOLD;
4930 menu_font = CreateFontIndirect (&menu_logfont);
4931 old_font = SelectObject (hdc, menu_font);
4932
4933 /* Always draw title as if not selected. */
4934 ExtTextOut (hdc,
4935 pDis->rcItem.left
4936 + GetSystemMetrics (SM_CXMENUCHECK),
4937 pDis->rcItem.top,
4938 ETO_OPAQUE, &pDis->rcItem,
4939 title, strlen (title), NULL);
4940
4941 SelectObject (hdc, old_font);
4942 DeleteObject (menu_font);
4943 }
4944 return TRUE;
4945 }
4946 }
4947 return 0;
4948
4949 #if 0
4950 /* Still not right - can't distinguish between clicks in the
4951 client area of the frame from clicks forwarded from the scroll
4952 bars - may have to hook WM_NCHITTEST to remember the mouse
4953 position and then check if it is in the client area ourselves. */
4954 case WM_MOUSEACTIVATE:
4955 /* Discard the mouse click that activates a frame, allowing the
4956 user to click anywhere without changing point (or worse!).
4957 Don't eat mouse clicks on scrollbars though!! */
4958 if (LOWORD (lParam) == HTCLIENT )
4959 return MA_ACTIVATEANDEAT;
4960 goto dflt;
4961 #endif
4962
4963 case WM_MOUSELEAVE:
4964 /* No longer tracking mouse. */
4965 track_mouse_window = NULL;
4966
4967 case WM_ACTIVATEAPP:
4968 case WM_ACTIVATE:
4969 case WM_WINDOWPOSCHANGED:
4970 case WM_SHOWWINDOW:
4971 /* Inform lisp thread that a frame might have just been obscured
4972 or exposed, so should recheck visibility of all frames. */
4973 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4974 goto dflt;
4975
4976 case WM_SETFOCUS:
4977 dpyinfo->faked_key = 0;
4978 reset_modifiers ();
4979 register_hot_keys (hwnd);
4980 goto command;
4981 case WM_KILLFOCUS:
4982 unregister_hot_keys (hwnd);
4983 button_state = 0;
4984 ReleaseCapture ();
4985 /* Relinquish the system caret. */
4986 if (w32_system_caret_hwnd)
4987 {
4988 w32_visible_system_caret_hwnd = NULL;
4989 w32_system_caret_hwnd = NULL;
4990 DestroyCaret ();
4991 }
4992 goto command;
4993 case WM_COMMAND:
4994 f = x_window_to_frame (dpyinfo, hwnd);
4995 if (f && HIWORD (wParam) == 0)
4996 {
4997 f->output_data.w32->menu_command_in_progress = 1;
4998 if (menu_free_timer)
4999 {
5000 KillTimer (hwnd, menu_free_timer);
5001 menu_free_timer = 0;
5002 }
5003 }
5004 case WM_MOVE:
5005 case WM_SIZE:
5006 command:
5007 wmsg.dwModifiers = w32_get_modifiers ();
5008 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
5009 goto dflt;
5010
5011 case WM_CLOSE:
5012 wmsg.dwModifiers = w32_get_modifiers ();
5013 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
5014 return 0;
5015
5016 case WM_WINDOWPOSCHANGING:
5017 /* Don't restrict the sizing of tip frames. */
5018 if (hwnd == tip_window)
5019 return 0;
5020 {
5021 WINDOWPLACEMENT wp;
5022 LPWINDOWPOS lppos = (WINDOWPOS *) lParam;
5023
5024 wp.length = sizeof (WINDOWPLACEMENT);
5025 GetWindowPlacement (hwnd, &wp);
5026
5027 if (wp.showCmd != SW_SHOWMINIMIZED && (lppos->flags & SWP_NOSIZE) == 0)
5028 {
5029 RECT rect;
5030 int wdiff;
5031 int hdiff;
5032 DWORD font_width;
5033 DWORD line_height;
5034 DWORD internal_border;
5035 DWORD scrollbar_extra;
5036 RECT wr;
5037
5038 wp.length = sizeof(wp);
5039 GetWindowRect (hwnd, &wr);
5040
5041 enter_crit ();
5042
5043 font_width = GetWindowLong (hwnd, WND_FONTWIDTH_INDEX);
5044 line_height = GetWindowLong (hwnd, WND_LINEHEIGHT_INDEX);
5045 internal_border = GetWindowLong (hwnd, WND_BORDER_INDEX);
5046 scrollbar_extra = GetWindowLong (hwnd, WND_SCROLLBAR_INDEX);
5047
5048 leave_crit ();
5049
5050 memset (&rect, 0, sizeof (rect));
5051 AdjustWindowRect (&rect, GetWindowLong (hwnd, GWL_STYLE),
5052 GetMenu (hwnd) != NULL);
5053
5054 /* Force width and height of client area to be exact
5055 multiples of the character cell dimensions. */
5056 wdiff = (lppos->cx - (rect.right - rect.left)
5057 - 2 * internal_border - scrollbar_extra)
5058 % font_width;
5059 hdiff = (lppos->cy - (rect.bottom - rect.top)
5060 - 2 * internal_border)
5061 % line_height;
5062
5063 if (wdiff || hdiff)
5064 {
5065 /* For right/bottom sizing we can just fix the sizes.
5066 However for top/left sizing we will need to fix the X
5067 and Y positions as well. */
5068
5069 lppos->cx -= wdiff;
5070 lppos->cy -= hdiff;
5071
5072 if (wp.showCmd != SW_SHOWMAXIMIZED
5073 && (lppos->flags & SWP_NOMOVE) == 0)
5074 {
5075 if (lppos->x != wr.left || lppos->y != wr.top)
5076 {
5077 lppos->x += wdiff;
5078 lppos->y += hdiff;
5079 }
5080 else
5081 {
5082 lppos->flags |= SWP_NOMOVE;
5083 }
5084 }
5085
5086 return 0;
5087 }
5088 }
5089 }
5090
5091 goto dflt;
5092
5093 case WM_GETMINMAXINFO:
5094 /* Hack to correct bug that allows Emacs frames to be resized
5095 below the Minimum Tracking Size. */
5096 ((LPMINMAXINFO) lParam)->ptMinTrackSize.y++;
5097 /* Hack to allow resizing the Emacs frame above the screen size.
5098 Note that Windows 9x limits coordinates to 16-bits. */
5099 ((LPMINMAXINFO) lParam)->ptMaxTrackSize.x = 32767;
5100 ((LPMINMAXINFO) lParam)->ptMaxTrackSize.y = 32767;
5101 return 0;
5102
5103 case WM_EMACS_CREATESCROLLBAR:
5104 return (LRESULT) w32_createscrollbar ((struct frame *) wParam,
5105 (struct scroll_bar *) lParam);
5106
5107 case WM_EMACS_SHOWWINDOW:
5108 return ShowWindow ((HWND) wParam, (WPARAM) lParam);
5109
5110 case WM_EMACS_SETFOREGROUND:
5111 {
5112 HWND foreground_window;
5113 DWORD foreground_thread, retval;
5114
5115 /* On NT 5.0, and apparently Windows 98, it is necessary to
5116 attach to the thread that currently has focus in order to
5117 pull the focus away from it. */
5118 foreground_window = GetForegroundWindow ();
5119 foreground_thread = GetWindowThreadProcessId (foreground_window, NULL);
5120 if (!foreground_window
5121 || foreground_thread == GetCurrentThreadId ()
5122 || !AttachThreadInput (GetCurrentThreadId (),
5123 foreground_thread, TRUE))
5124 foreground_thread = 0;
5125
5126 retval = SetForegroundWindow ((HWND) wParam);
5127
5128 /* Detach from the previous foreground thread. */
5129 if (foreground_thread)
5130 AttachThreadInput (GetCurrentThreadId (),
5131 foreground_thread, FALSE);
5132
5133 return retval;
5134 }
5135
5136 case WM_EMACS_SETWINDOWPOS:
5137 {
5138 WINDOWPOS * pos = (WINDOWPOS *) wParam;
5139 return SetWindowPos (hwnd, pos->hwndInsertAfter,
5140 pos->x, pos->y, pos->cx, pos->cy, pos->flags);
5141 }
5142
5143 case WM_EMACS_DESTROYWINDOW:
5144 DragAcceptFiles ((HWND) wParam, FALSE);
5145 return DestroyWindow ((HWND) wParam);
5146
5147 case WM_EMACS_HIDE_CARET:
5148 return HideCaret (hwnd);
5149
5150 case WM_EMACS_SHOW_CARET:
5151 return ShowCaret (hwnd);
5152
5153 case WM_EMACS_DESTROY_CARET:
5154 w32_system_caret_hwnd = NULL;
5155 w32_visible_system_caret_hwnd = NULL;
5156 return DestroyCaret ();
5157
5158 case WM_EMACS_TRACK_CARET:
5159 /* If there is currently no system caret, create one. */
5160 if (w32_system_caret_hwnd == NULL)
5161 {
5162 /* Use the default caret width, and avoid changing it
5163 unneccesarily, as it confuses screen reader software. */
5164 w32_system_caret_hwnd = hwnd;
5165 CreateCaret (hwnd, NULL, 0,
5166 w32_system_caret_height);
5167 }
5168
5169 if (!SetCaretPos (w32_system_caret_x, w32_system_caret_y))
5170 return 0;
5171 /* Ensure visible caret gets turned on when requested. */
5172 else if (w32_use_visible_system_caret
5173 && w32_visible_system_caret_hwnd != hwnd)
5174 {
5175 w32_visible_system_caret_hwnd = hwnd;
5176 return ShowCaret (hwnd);
5177 }
5178 /* Ensure visible caret gets turned off when requested. */
5179 else if (!w32_use_visible_system_caret
5180 && w32_visible_system_caret_hwnd)
5181 {
5182 w32_visible_system_caret_hwnd = NULL;
5183 return HideCaret (hwnd);
5184 }
5185 else
5186 return 1;
5187
5188 case WM_EMACS_TRACKPOPUPMENU:
5189 {
5190 UINT flags;
5191 POINT *pos;
5192 int retval;
5193 pos = (POINT *)lParam;
5194 flags = TPM_CENTERALIGN;
5195 if (button_state & LMOUSE)
5196 flags |= TPM_LEFTBUTTON;
5197 else if (button_state & RMOUSE)
5198 flags |= TPM_RIGHTBUTTON;
5199
5200 /* Remember we did a SetCapture on the initial mouse down event,
5201 so for safety, we make sure the capture is cancelled now. */
5202 ReleaseCapture ();
5203 button_state = 0;
5204
5205 /* Use menubar_active to indicate that WM_INITMENU is from
5206 TrackPopupMenu below, and should be ignored. */
5207 f = x_window_to_frame (dpyinfo, hwnd);
5208 if (f)
5209 f->output_data.w32->menubar_active = 1;
5210
5211 if (TrackPopupMenu ((HMENU)wParam, flags, pos->x, pos->y,
5212 0, hwnd, NULL))
5213 {
5214 MSG amsg;
5215 /* Eat any mouse messages during popupmenu */
5216 while (PeekMessage (&amsg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST,
5217 PM_REMOVE));
5218 /* Get the menu selection, if any */
5219 if (PeekMessage (&amsg, hwnd, WM_COMMAND, WM_COMMAND, PM_REMOVE))
5220 {
5221 retval = LOWORD (amsg.wParam);
5222 }
5223 else
5224 {
5225 retval = 0;
5226 }
5227 }
5228 else
5229 {
5230 retval = -1;
5231 }
5232
5233 return retval;
5234 }
5235
5236 default:
5237 /* Check for messages registered at runtime. */
5238 if (msg == msh_mousewheel)
5239 {
5240 wmsg.dwModifiers = w32_get_modifiers ();
5241 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
5242 return 0;
5243 }
5244
5245 dflt:
5246 return DefWindowProc (hwnd, msg, wParam, lParam);
5247 }
5248
5249
5250 /* The most common default return code for handled messages is 0. */
5251 return 0;
5252 }
5253
5254 void
5255 my_create_window (f)
5256 struct frame * f;
5257 {
5258 MSG msg;
5259
5260 if (!PostThreadMessage (dwWindowsThreadId, WM_EMACS_CREATEWINDOW, (WPARAM)f, 0))
5261 abort ();
5262 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
5263 }
5264
5265
5266 /* Create a tooltip window. Unlike my_create_window, we do not do this
5267 indirectly via the Window thread, as we do not need to process Window
5268 messages for the tooltip. Creating tooltips indirectly also creates
5269 deadlocks when tooltips are created for menu items. */
5270 void
5271 my_create_tip_window (f)
5272 struct frame *f;
5273 {
5274 RECT rect;
5275
5276 rect.left = rect.top = 0;
5277 rect.right = PIXEL_WIDTH (f);
5278 rect.bottom = PIXEL_HEIGHT (f);
5279
5280 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
5281 FRAME_EXTERNAL_MENU_BAR (f));
5282
5283 tip_window = FRAME_W32_WINDOW (f)
5284 = CreateWindow (EMACS_CLASS,
5285 f->namebuf,
5286 f->output_data.w32->dwStyle,
5287 f->output_data.w32->left_pos,
5288 f->output_data.w32->top_pos,
5289 rect.right - rect.left,
5290 rect.bottom - rect.top,
5291 FRAME_W32_WINDOW (SELECTED_FRAME ()), /* owner */
5292 NULL,
5293 hinst,
5294 NULL);
5295
5296 if (tip_window)
5297 {
5298 SetWindowLong (tip_window, WND_FONTWIDTH_INDEX, FONT_WIDTH (f->output_data.w32->font));
5299 SetWindowLong (tip_window, WND_LINEHEIGHT_INDEX, f->output_data.w32->line_height);
5300 SetWindowLong (tip_window, WND_BORDER_INDEX, f->output_data.w32->internal_border_width);
5301 SetWindowLong (tip_window, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f));
5302
5303 /* Tip frames have no scrollbars. */
5304 SetWindowLong (tip_window, WND_SCROLLBAR_INDEX, 0);
5305
5306 /* Do this to discard the default setting specified by our parent. */
5307 ShowWindow (tip_window, SW_HIDE);
5308 }
5309 }
5310
5311
5312 /* Create and set up the w32 window for frame F. */
5313
5314 static void
5315 w32_window (f, window_prompting, minibuffer_only)
5316 struct frame *f;
5317 long window_prompting;
5318 int minibuffer_only;
5319 {
5320 BLOCK_INPUT;
5321
5322 /* Use the resource name as the top-level window name
5323 for looking up resources. Make a non-Lisp copy
5324 for the window manager, so GC relocation won't bother it.
5325
5326 Elsewhere we specify the window name for the window manager. */
5327
5328 {
5329 char *str = (char *) XSTRING (Vx_resource_name)->data;
5330 f->namebuf = (char *) xmalloc (strlen (str) + 1);
5331 strcpy (f->namebuf, str);
5332 }
5333
5334 my_create_window (f);
5335
5336 validate_x_resource_name ();
5337
5338 /* x_set_name normally ignores requests to set the name if the
5339 requested name is the same as the current name. This is the one
5340 place where that assumption isn't correct; f->name is set, but
5341 the server hasn't been told. */
5342 {
5343 Lisp_Object name;
5344 int explicit = f->explicit_name;
5345
5346 f->explicit_name = 0;
5347 name = f->name;
5348 f->name = Qnil;
5349 x_set_name (f, name, explicit);
5350 }
5351
5352 UNBLOCK_INPUT;
5353
5354 if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f))
5355 initialize_frame_menubar (f);
5356
5357 if (FRAME_W32_WINDOW (f) == 0)
5358 error ("Unable to create window");
5359 }
5360
5361 /* Handle the icon stuff for this window. Perhaps later we might
5362 want an x_set_icon_position which can be called interactively as
5363 well. */
5364
5365 static void
5366 x_icon (f, parms)
5367 struct frame *f;
5368 Lisp_Object parms;
5369 {
5370 Lisp_Object icon_x, icon_y;
5371
5372 /* Set the position of the icon. Note that Windows 95 groups all
5373 icons in the tray. */
5374 icon_x = w32_get_arg (parms, Qicon_left, 0, 0, RES_TYPE_NUMBER);
5375 icon_y = w32_get_arg (parms, Qicon_top, 0, 0, RES_TYPE_NUMBER);
5376 if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
5377 {
5378 CHECK_NUMBER (icon_x);
5379 CHECK_NUMBER (icon_y);
5380 }
5381 else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
5382 error ("Both left and top icon corners of icon must be specified");
5383
5384 BLOCK_INPUT;
5385
5386 if (! EQ (icon_x, Qunbound))
5387 x_wm_set_icon_position (f, XINT (icon_x), XINT (icon_y));
5388
5389 #if 0 /* TODO */
5390 /* Start up iconic or window? */
5391 x_wm_set_window_state
5392 (f, (EQ (w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL), Qicon)
5393 ? IconicState
5394 : NormalState));
5395
5396 x_text_icon (f, (char *) XSTRING ((!NILP (f->icon_name)
5397 ? f->icon_name
5398 : f->name))->data);
5399 #endif
5400
5401 UNBLOCK_INPUT;
5402 }
5403
5404
5405 static void
5406 x_make_gc (f)
5407 struct frame *f;
5408 {
5409 XGCValues gc_values;
5410
5411 BLOCK_INPUT;
5412
5413 /* Create the GC's of this frame.
5414 Note that many default values are used. */
5415
5416 /* Normal video */
5417 gc_values.font = f->output_data.w32->font;
5418
5419 /* Cursor has cursor-color background, background-color foreground. */
5420 gc_values.foreground = FRAME_BACKGROUND_PIXEL (f);
5421 gc_values.background = f->output_data.w32->cursor_pixel;
5422 f->output_data.w32->cursor_gc
5423 = XCreateGC (NULL, FRAME_W32_WINDOW (f),
5424 (GCFont | GCForeground | GCBackground),
5425 &gc_values);
5426
5427 /* Reliefs. */
5428 f->output_data.w32->white_relief.gc = 0;
5429 f->output_data.w32->black_relief.gc = 0;
5430
5431 UNBLOCK_INPUT;
5432 }
5433
5434
5435 /* Handler for signals raised during x_create_frame and
5436 x_create_top_frame. FRAME is the frame which is partially
5437 constructed. */
5438
5439 static Lisp_Object
5440 unwind_create_frame (frame)
5441 Lisp_Object frame;
5442 {
5443 struct frame *f = XFRAME (frame);
5444
5445 /* If frame is ``official'', nothing to do. */
5446 if (!CONSP (Vframe_list) || !EQ (XCAR (Vframe_list), frame))
5447 {
5448 #ifdef GLYPH_DEBUG
5449 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
5450 #endif
5451
5452 x_free_frame_resources (f);
5453
5454 /* Check that reference counts are indeed correct. */
5455 xassert (dpyinfo->reference_count == dpyinfo_refcount);
5456 xassert (dpyinfo->image_cache->refcount == image_cache_refcount);
5457
5458 return Qt;
5459 }
5460
5461 return Qnil;
5462 }
5463
5464
5465 DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
5466 1, 1, 0,
5467 doc: /* Make a new window, which is called a \"frame\" in Emacs terms.
5468 Returns an Emacs frame object.
5469 ALIST is an alist of frame parameters.
5470 If the parameters specify that the frame should not have a minibuffer,
5471 and do not specify a specific minibuffer window to use,
5472 then `default-minibuffer-frame' must be a frame whose minibuffer can
5473 be shared by the new frame.
5474
5475 This function is an internal primitive--use `make-frame' instead. */)
5476 (parms)
5477 Lisp_Object parms;
5478 {
5479 struct frame *f;
5480 Lisp_Object frame, tem;
5481 Lisp_Object name;
5482 int minibuffer_only = 0;
5483 long window_prompting = 0;
5484 int width, height;
5485 int count = BINDING_STACK_SIZE ();
5486 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
5487 Lisp_Object display;
5488 struct w32_display_info *dpyinfo = NULL;
5489 Lisp_Object parent;
5490 struct kboard *kb;
5491
5492 check_w32 ();
5493
5494 /* Use this general default value to start with
5495 until we know if this frame has a specified name. */
5496 Vx_resource_name = Vinvocation_name;
5497
5498 display = w32_get_arg (parms, Qdisplay, 0, 0, RES_TYPE_STRING);
5499 if (EQ (display, Qunbound))
5500 display = Qnil;
5501 dpyinfo = check_x_display_info (display);
5502 #ifdef MULTI_KBOARD
5503 kb = dpyinfo->kboard;
5504 #else
5505 kb = &the_only_kboard;
5506 #endif
5507
5508 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
5509 if (!STRINGP (name)
5510 && ! EQ (name, Qunbound)
5511 && ! NILP (name))
5512 error ("Invalid frame name--not a string or nil");
5513
5514 if (STRINGP (name))
5515 Vx_resource_name = name;
5516
5517 /* See if parent window is specified. */
5518 parent = w32_get_arg (parms, Qparent_id, NULL, NULL, RES_TYPE_NUMBER);
5519 if (EQ (parent, Qunbound))
5520 parent = Qnil;
5521 if (! NILP (parent))
5522 CHECK_NUMBER (parent);
5523
5524 /* make_frame_without_minibuffer can run Lisp code and garbage collect. */
5525 /* No need to protect DISPLAY because that's not used after passing
5526 it to make_frame_without_minibuffer. */
5527 frame = Qnil;
5528 GCPRO4 (parms, parent, name, frame);
5529 tem = w32_get_arg (parms, Qminibuffer, "minibuffer", "Minibuffer",
5530 RES_TYPE_SYMBOL);
5531 if (EQ (tem, Qnone) || NILP (tem))
5532 f = make_frame_without_minibuffer (Qnil, kb, display);
5533 else if (EQ (tem, Qonly))
5534 {
5535 f = make_minibuffer_frame ();
5536 minibuffer_only = 1;
5537 }
5538 else if (WINDOWP (tem))
5539 f = make_frame_without_minibuffer (tem, kb, display);
5540 else
5541 f = make_frame (1);
5542
5543 XSETFRAME (frame, f);
5544
5545 /* Note that Windows does support scroll bars. */
5546 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
5547 /* By default, make scrollbars the system standard width. */
5548 f->scroll_bar_pixel_width = GetSystemMetrics (SM_CXVSCROLL);
5549
5550 f->output_method = output_w32;
5551 f->output_data.w32 =
5552 (struct w32_output *) xmalloc (sizeof (struct w32_output));
5553 bzero (f->output_data.w32, sizeof (struct w32_output));
5554 FRAME_FONTSET (f) = -1;
5555 record_unwind_protect (unwind_create_frame, frame);
5556
5557 f->icon_name
5558 = w32_get_arg (parms, Qicon_name, "iconName", "Title", RES_TYPE_STRING);
5559 if (! STRINGP (f->icon_name))
5560 f->icon_name = Qnil;
5561
5562 /* FRAME_W32_DISPLAY_INFO (f) = dpyinfo; */
5563 #ifdef MULTI_KBOARD
5564 FRAME_KBOARD (f) = kb;
5565 #endif
5566
5567 /* Specify the parent under which to make this window. */
5568
5569 if (!NILP (parent))
5570 {
5571 f->output_data.w32->parent_desc = (Window) XFASTINT (parent);
5572 f->output_data.w32->explicit_parent = 1;
5573 }
5574 else
5575 {
5576 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
5577 f->output_data.w32->explicit_parent = 0;
5578 }
5579
5580 /* Set the name; the functions to which we pass f expect the name to
5581 be set. */
5582 if (EQ (name, Qunbound) || NILP (name))
5583 {
5584 f->name = build_string (dpyinfo->w32_id_name);
5585 f->explicit_name = 0;
5586 }
5587 else
5588 {
5589 f->name = name;
5590 f->explicit_name = 1;
5591 /* use the frame's title when getting resources for this frame. */
5592 specbind (Qx_resource_name, name);
5593 }
5594
5595 /* Extract the window parameters from the supplied values
5596 that are needed to determine window geometry. */
5597 {
5598 Lisp_Object font;
5599
5600 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
5601
5602 BLOCK_INPUT;
5603 /* First, try whatever font the caller has specified. */
5604 if (STRINGP (font))
5605 {
5606 tem = Fquery_fontset (font, Qnil);
5607 if (STRINGP (tem))
5608 font = x_new_fontset (f, XSTRING (tem)->data);
5609 else
5610 font = x_new_font (f, XSTRING (font)->data);
5611 }
5612 /* Try out a font which we hope has bold and italic variations. */
5613 if (!STRINGP (font))
5614 font = x_new_font (f, "-*-Courier New-normal-r-*-*-*-100-*-*-c-*-iso8859-1");
5615 if (! STRINGP (font))
5616 font = x_new_font (f, "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
5617 /* If those didn't work, look for something which will at least work. */
5618 if (! STRINGP (font))
5619 font = x_new_font (f, "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1");
5620 UNBLOCK_INPUT;
5621 if (! STRINGP (font))
5622 font = build_string ("Fixedsys");
5623
5624 x_default_parameter (f, parms, Qfont, font,
5625 "font", "Font", RES_TYPE_STRING);
5626 }
5627
5628 x_default_parameter (f, parms, Qborder_width, make_number (2),
5629 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
5630 /* This defaults to 2 in order to match xterm. We recognize either
5631 internalBorderWidth or internalBorder (which is what xterm calls
5632 it). */
5633 if (NILP (Fassq (Qinternal_border_width, parms)))
5634 {
5635 Lisp_Object value;
5636
5637 value = w32_get_arg (parms, Qinternal_border_width,
5638 "internalBorder", "InternalBorder", RES_TYPE_NUMBER);
5639 if (! EQ (value, Qunbound))
5640 parms = Fcons (Fcons (Qinternal_border_width, value),
5641 parms);
5642 }
5643 /* Default internalBorderWidth to 0 on Windows to match other programs. */
5644 x_default_parameter (f, parms, Qinternal_border_width, make_number (0),
5645 "internalBorderWidth", "InternalBorder", RES_TYPE_NUMBER);
5646 x_default_parameter (f, parms, Qvertical_scroll_bars, Qright,
5647 "verticalScrollBars", "ScrollBars", RES_TYPE_SYMBOL);
5648
5649 /* Also do the stuff which must be set before the window exists. */
5650 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
5651 "foreground", "Foreground", RES_TYPE_STRING);
5652 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
5653 "background", "Background", RES_TYPE_STRING);
5654 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
5655 "pointerColor", "Foreground", RES_TYPE_STRING);
5656 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
5657 "cursorColor", "Foreground", RES_TYPE_STRING);
5658 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
5659 "borderColor", "BorderColor", RES_TYPE_STRING);
5660 x_default_parameter (f, parms, Qscreen_gamma, Qnil,
5661 "screenGamma", "ScreenGamma", RES_TYPE_FLOAT);
5662 x_default_parameter (f, parms, Qline_spacing, Qnil,
5663 "lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
5664 x_default_parameter (f, parms, Qleft_fringe, Qnil,
5665 "leftFringe", "LeftFringe", RES_TYPE_NUMBER);
5666 x_default_parameter (f, parms, Qright_fringe, Qnil,
5667 "rightFringe", "RightFringe", RES_TYPE_NUMBER);
5668
5669
5670 /* Init faces before x_default_parameter is called for scroll-bar
5671 parameters because that function calls x_set_scroll_bar_width,
5672 which calls change_frame_size, which calls Fset_window_buffer,
5673 which runs hooks, which call Fvertical_motion. At the end, we
5674 end up in init_iterator with a null face cache, which should not
5675 happen. */
5676 init_frame_faces (f);
5677
5678 x_default_parameter (f, parms, Qmenu_bar_lines, make_number (1),
5679 "menuBar", "MenuBar", RES_TYPE_NUMBER);
5680 x_default_parameter (f, parms, Qtool_bar_lines, make_number (HAVE_IMAGES),
5681 "toolBar", "ToolBar", RES_TYPE_NUMBER);
5682 x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
5683 "bufferPredicate", "BufferPredicate", RES_TYPE_SYMBOL);
5684 x_default_parameter (f, parms, Qtitle, Qnil,
5685 "title", "Title", RES_TYPE_STRING);
5686 x_default_parameter (f, parms, Qfullscreen, Qnil,
5687 "fullscreen", "Fullscreen", RES_TYPE_SYMBOL);
5688
5689 f->output_data.w32->dwStyle = WS_OVERLAPPEDWINDOW;
5690 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
5691
5692 /* Add the tool-bar height to the initial frame height so that the
5693 user gets a text display area of the size he specified with -g or
5694 via .Xdefaults. Later changes of the tool-bar height don't
5695 change the frame size. This is done so that users can create
5696 tall Emacs frames without having to guess how tall the tool-bar
5697 will get. */
5698 if (FRAME_TOOL_BAR_LINES (f))
5699 {
5700 int margin, relief, bar_height;
5701
5702 relief = (tool_bar_button_relief >= 0
5703 ? tool_bar_button_relief
5704 : DEFAULT_TOOL_BAR_BUTTON_RELIEF);
5705
5706 if (INTEGERP (Vtool_bar_button_margin)
5707 && XINT (Vtool_bar_button_margin) > 0)
5708 margin = XFASTINT (Vtool_bar_button_margin);
5709 else if (CONSP (Vtool_bar_button_margin)
5710 && INTEGERP (XCDR (Vtool_bar_button_margin))
5711 && XINT (XCDR (Vtool_bar_button_margin)) > 0)
5712 margin = XFASTINT (XCDR (Vtool_bar_button_margin));
5713 else
5714 margin = 0;
5715
5716 bar_height = DEFAULT_TOOL_BAR_IMAGE_HEIGHT + 2 * margin + 2 * relief;
5717 f->height += (bar_height + CANON_Y_UNIT (f) - 1) / CANON_Y_UNIT (f);
5718 }
5719
5720 window_prompting = x_figure_window_size (f, parms);
5721
5722 if (window_prompting & XNegative)
5723 {
5724 if (window_prompting & YNegative)
5725 f->output_data.w32->win_gravity = SouthEastGravity;
5726 else
5727 f->output_data.w32->win_gravity = NorthEastGravity;
5728 }
5729 else
5730 {
5731 if (window_prompting & YNegative)
5732 f->output_data.w32->win_gravity = SouthWestGravity;
5733 else
5734 f->output_data.w32->win_gravity = NorthWestGravity;
5735 }
5736
5737 f->output_data.w32->size_hint_flags = window_prompting;
5738
5739 tem = w32_get_arg (parms, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN);
5740 f->no_split = minibuffer_only || EQ (tem, Qt);
5741
5742 w32_window (f, window_prompting, minibuffer_only);
5743 x_icon (f, parms);
5744
5745 x_make_gc (f);
5746
5747 /* Now consider the frame official. */
5748 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
5749 Vframe_list = Fcons (frame, Vframe_list);
5750
5751 /* We need to do this after creating the window, so that the
5752 icon-creation functions can say whose icon they're describing. */
5753 x_default_parameter (f, parms, Qicon_type, Qnil,
5754 "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL);
5755
5756 x_default_parameter (f, parms, Qauto_raise, Qnil,
5757 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
5758 x_default_parameter (f, parms, Qauto_lower, Qnil,
5759 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
5760 x_default_parameter (f, parms, Qcursor_type, Qbox,
5761 "cursorType", "CursorType", RES_TYPE_SYMBOL);
5762 x_default_parameter (f, parms, Qscroll_bar_width, Qnil,
5763 "scrollBarWidth", "ScrollBarWidth", RES_TYPE_NUMBER);
5764
5765 /* Dimensions, especially f->height, must be done via change_frame_size.
5766 Change will not be effected unless different from the current
5767 f->height. */
5768 width = f->width;
5769 height = f->height;
5770
5771 f->height = 0;
5772 SET_FRAME_WIDTH (f, 0);
5773 change_frame_size (f, height, width, 1, 0, 0);
5774
5775 /* Tell the server what size and position, etc, we want, and how
5776 badly we want them. This should be done after we have the menu
5777 bar so that its size can be taken into account. */
5778 BLOCK_INPUT;
5779 x_wm_set_size_hint (f, window_prompting, 0);
5780 UNBLOCK_INPUT;
5781
5782 /* Avoid a bug that causes the new frame to never become visible if
5783 an echo area message is displayed during the following call1. */
5784 specbind(Qredisplay_dont_pause, Qt);
5785
5786 /* Set up faces after all frame parameters are known. This call
5787 also merges in face attributes specified for new frames. If we
5788 don't do this, the `menu' face for instance won't have the right
5789 colors, and the menu bar won't appear in the specified colors for
5790 new frames. */
5791 call1 (Qface_set_after_frame_default, frame);
5792
5793 /* Make the window appear on the frame and enable display, unless
5794 the caller says not to. However, with explicit parent, Emacs
5795 cannot control visibility, so don't try. */
5796 if (! f->output_data.w32->explicit_parent)
5797 {
5798 Lisp_Object visibility;
5799
5800 visibility = w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL);
5801 if (EQ (visibility, Qunbound))
5802 visibility = Qt;
5803
5804 if (EQ (visibility, Qicon))
5805 x_iconify_frame (f);
5806 else if (! NILP (visibility))
5807 x_make_frame_visible (f);
5808 else
5809 /* Must have been Qnil. */
5810 ;
5811 }
5812 UNGCPRO;
5813
5814 /* Make sure windows on this frame appear in calls to next-window
5815 and similar functions. */
5816 Vwindow_list = Qnil;
5817
5818 return unbind_to (count, frame);
5819 }
5820
5821 /* FRAME is used only to get a handle on the X display. We don't pass the
5822 display info directly because we're called from frame.c, which doesn't
5823 know about that structure. */
5824 Lisp_Object
5825 x_get_focus_frame (frame)
5826 struct frame *frame;
5827 {
5828 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (frame);
5829 Lisp_Object xfocus;
5830 if (! dpyinfo->w32_focus_frame)
5831 return Qnil;
5832
5833 XSETFRAME (xfocus, dpyinfo->w32_focus_frame);
5834 return xfocus;
5835 }
5836
5837 DEFUN ("w32-focus-frame", Fw32_focus_frame, Sw32_focus_frame, 1, 1, 0,
5838 doc: /* Give FRAME input focus, raising to foreground if necessary. */)
5839 (frame)
5840 Lisp_Object frame;
5841 {
5842 x_focus_on_frame (check_x_frame (frame));
5843 return Qnil;
5844 }
5845
5846 \f
5847 /* Return the charset portion of a font name. */
5848 char * xlfd_charset_of_font (char * fontname)
5849 {
5850 char *charset, *encoding;
5851
5852 encoding = strrchr(fontname, '-');
5853 if (!encoding || encoding == fontname)
5854 return NULL;
5855
5856 for (charset = encoding - 1; charset >= fontname; charset--)
5857 if (*charset == '-')
5858 break;
5859
5860 if (charset == fontname || strcmp(charset, "-*-*") == 0)
5861 return NULL;
5862
5863 return charset + 1;
5864 }
5865
5866 struct font_info *w32_load_bdf_font (struct frame *f, char *fontname,
5867 int size, char* filename);
5868 static Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names);
5869 static BOOL w32_to_x_font (LOGFONT * lplf, char * lpxstr, int len,
5870 char * charset);
5871 static BOOL x_to_w32_font (char *lpxstr, LOGFONT *lplogfont);
5872
5873 static struct font_info *
5874 w32_load_system_font (f,fontname,size)
5875 struct frame *f;
5876 char * fontname;
5877 int size;
5878 {
5879 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
5880 Lisp_Object font_names;
5881
5882 /* Get a list of all the fonts that match this name. Once we
5883 have a list of matching fonts, we compare them against the fonts
5884 we already have loaded by comparing names. */
5885 font_names = w32_list_fonts (f, build_string (fontname), size, 100);
5886
5887 if (!NILP (font_names))
5888 {
5889 Lisp_Object tail;
5890 int i;
5891
5892 /* First check if any are already loaded, as that is cheaper
5893 than loading another one. */
5894 for (i = 0; i < dpyinfo->n_fonts; i++)
5895 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
5896 if (dpyinfo->font_table[i].name
5897 && (!strcmp (dpyinfo->font_table[i].name,
5898 XSTRING (XCAR (tail))->data)
5899 || !strcmp (dpyinfo->font_table[i].full_name,
5900 XSTRING (XCAR (tail))->data)))
5901 return (dpyinfo->font_table + i);
5902
5903 fontname = (char *) XSTRING (XCAR (font_names))->data;
5904 }
5905 else if (w32_strict_fontnames)
5906 {
5907 /* If EnumFontFamiliesEx was available, we got a full list of
5908 fonts back so stop now to avoid the possibility of loading a
5909 random font. If we had to fall back to EnumFontFamilies, the
5910 list is incomplete, so continue whether the font we want was
5911 listed or not. */
5912 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
5913 FARPROC enum_font_families_ex
5914 = GetProcAddress (gdi32, "EnumFontFamiliesExA");
5915 if (enum_font_families_ex)
5916 return NULL;
5917 }
5918
5919 /* Load the font and add it to the table. */
5920 {
5921 char *full_name, *encoding, *charset;
5922 XFontStruct *font;
5923 struct font_info *fontp;
5924 LOGFONT lf;
5925 BOOL ok;
5926 int codepage;
5927 int i;
5928
5929 if (!fontname || !x_to_w32_font (fontname, &lf))
5930 return (NULL);
5931
5932 if (!*lf.lfFaceName)
5933 /* If no name was specified for the font, we get a random font
5934 from CreateFontIndirect - this is not particularly
5935 desirable, especially since CreateFontIndirect does not
5936 fill out the missing name in lf, so we never know what we
5937 ended up with. */
5938 return NULL;
5939
5940 /* Specify anti-aliasing to prevent Cleartype fonts being used,
5941 since those fonts leave garbage behind. */
5942 lf.lfQuality = ANTIALIASED_QUALITY;
5943
5944 font = (XFontStruct *) xmalloc (sizeof (XFontStruct));
5945 bzero (font, sizeof (*font));
5946
5947 /* Set bdf to NULL to indicate that this is a Windows font. */
5948 font->bdf = NULL;
5949
5950 BLOCK_INPUT;
5951
5952 font->hfont = CreateFontIndirect (&lf);
5953
5954 if (font->hfont == NULL)
5955 {
5956 ok = FALSE;
5957 }
5958 else
5959 {
5960 HDC hdc;
5961 HANDLE oldobj;
5962
5963 codepage = w32_codepage_for_font (fontname);
5964
5965 hdc = GetDC (dpyinfo->root_window);
5966 oldobj = SelectObject (hdc, font->hfont);
5967
5968 ok = GetTextMetrics (hdc, &font->tm);
5969 if (codepage == CP_UNICODE)
5970 font->double_byte_p = 1;
5971 else
5972 {
5973 /* Unfortunately, some fonts (eg. MingLiU, a big5 ttf font)
5974 don't report themselves as double byte fonts, when
5975 patently they are. So instead of trusting
5976 GetFontLanguageInfo, we check the properties of the
5977 codepage directly, since that is ultimately what we are
5978 working from anyway. */
5979 /* font->double_byte_p = GetFontLanguageInfo(hdc) & GCP_DBCS; */
5980 CPINFO cpi = {0};
5981 GetCPInfo (codepage, &cpi);
5982 font->double_byte_p = cpi.MaxCharSize > 1;
5983 }
5984
5985 SelectObject (hdc, oldobj);
5986 ReleaseDC (dpyinfo->root_window, hdc);
5987 /* Fill out details in lf according to the font that was
5988 actually loaded. */
5989 lf.lfHeight = font->tm.tmInternalLeading - font->tm.tmHeight;
5990 lf.lfWidth = font->tm.tmAveCharWidth;
5991 lf.lfWeight = font->tm.tmWeight;
5992 lf.lfItalic = font->tm.tmItalic;
5993 lf.lfCharSet = font->tm.tmCharSet;
5994 lf.lfPitchAndFamily = ((font->tm.tmPitchAndFamily & TMPF_FIXED_PITCH)
5995 ? VARIABLE_PITCH : FIXED_PITCH);
5996 lf.lfOutPrecision = ((font->tm.tmPitchAndFamily & TMPF_VECTOR)
5997 ? OUT_STROKE_PRECIS : OUT_STRING_PRECIS);
5998
5999 w32_cache_char_metrics (font);
6000 }
6001
6002 UNBLOCK_INPUT;
6003
6004 if (!ok)
6005 {
6006 w32_unload_font (dpyinfo, font);
6007 return (NULL);
6008 }
6009
6010 /* Find a free slot in the font table. */
6011 for (i = 0; i < dpyinfo->n_fonts; ++i)
6012 if (dpyinfo->font_table[i].name == NULL)
6013 break;
6014
6015 /* If no free slot found, maybe enlarge the font table. */
6016 if (i == dpyinfo->n_fonts
6017 && dpyinfo->n_fonts == dpyinfo->font_table_size)
6018 {
6019 int sz;
6020 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
6021 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
6022 dpyinfo->font_table
6023 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
6024 }
6025
6026 fontp = dpyinfo->font_table + i;
6027 if (i == dpyinfo->n_fonts)
6028 ++dpyinfo->n_fonts;
6029
6030 /* Now fill in the slots of *FONTP. */
6031 BLOCK_INPUT;
6032 fontp->font = font;
6033 fontp->font_idx = i;
6034 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
6035 bcopy (fontname, fontp->name, strlen (fontname) + 1);
6036
6037 charset = xlfd_charset_of_font (fontname);
6038
6039 /* Cache the W32 codepage for a font. This makes w32_encode_char
6040 (called for every glyph during redisplay) much faster. */
6041 fontp->codepage = codepage;
6042
6043 /* Work out the font's full name. */
6044 full_name = (char *)xmalloc (100);
6045 if (full_name && w32_to_x_font (&lf, full_name, 100, charset))
6046 fontp->full_name = full_name;
6047 else
6048 {
6049 /* If all else fails - just use the name we used to load it. */
6050 xfree (full_name);
6051 fontp->full_name = fontp->name;
6052 }
6053
6054 fontp->size = FONT_WIDTH (font);
6055 fontp->height = FONT_HEIGHT (font);
6056
6057 /* The slot `encoding' specifies how to map a character
6058 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
6059 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
6060 (0:0x20..0x7F, 1:0xA0..0xFF,
6061 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
6062 2:0xA020..0xFF7F). For the moment, we don't know which charset
6063 uses this font. So, we set information in fontp->encoding[1]
6064 which is never used by any charset. If mapping can't be
6065 decided, set FONT_ENCODING_NOT_DECIDED. */
6066
6067 /* SJIS fonts need to be set to type 4, all others seem to work as
6068 type FONT_ENCODING_NOT_DECIDED. */
6069 encoding = strrchr (fontp->name, '-');
6070 if (encoding && strnicmp (encoding+1, "sjis", 4) == 0)
6071 fontp->encoding[1] = 4;
6072 else
6073 fontp->encoding[1] = FONT_ENCODING_NOT_DECIDED;
6074
6075 /* The following three values are set to 0 under W32, which is
6076 what they get set to if XGetFontProperty fails under X. */
6077 fontp->baseline_offset = 0;
6078 fontp->relative_compose = 0;
6079 fontp->default_ascent = 0;
6080
6081 /* Set global flag fonts_changed_p to non-zero if the font loaded
6082 has a character with a smaller width than any other character
6083 before, or if the font loaded has a smaller height than any
6084 other font loaded before. If this happens, it will make a
6085 glyph matrix reallocation necessary. */
6086 fonts_changed_p |= x_compute_min_glyph_bounds (f);
6087 UNBLOCK_INPUT;
6088 return fontp;
6089 }
6090 }
6091
6092 /* Load font named FONTNAME of size SIZE for frame F, and return a
6093 pointer to the structure font_info while allocating it dynamically.
6094 If loading fails, return NULL. */
6095 struct font_info *
6096 w32_load_font (f,fontname,size)
6097 struct frame *f;
6098 char * fontname;
6099 int size;
6100 {
6101 Lisp_Object bdf_fonts;
6102 struct font_info *retval = NULL;
6103
6104 bdf_fonts = w32_list_bdf_fonts (build_string (fontname), 1);
6105
6106 while (!retval && CONSP (bdf_fonts))
6107 {
6108 char *bdf_name, *bdf_file;
6109 Lisp_Object bdf_pair;
6110
6111 bdf_name = XSTRING (XCAR (bdf_fonts))->data;
6112 bdf_pair = Fassoc (XCAR (bdf_fonts), Vw32_bdf_filename_alist);
6113 bdf_file = XSTRING (XCDR (bdf_pair))->data;
6114
6115 retval = w32_load_bdf_font (f, bdf_name, size, bdf_file);
6116
6117 bdf_fonts = XCDR (bdf_fonts);
6118 }
6119
6120 if (retval)
6121 return retval;
6122
6123 return w32_load_system_font(f, fontname, size);
6124 }
6125
6126
6127 void
6128 w32_unload_font (dpyinfo, font)
6129 struct w32_display_info *dpyinfo;
6130 XFontStruct * font;
6131 {
6132 if (font)
6133 {
6134 if (font->per_char) xfree (font->per_char);
6135 if (font->bdf) w32_free_bdf_font (font->bdf);
6136
6137 if (font->hfont) DeleteObject(font->hfont);
6138 xfree (font);
6139 }
6140 }
6141
6142 /* The font conversion stuff between x and w32 */
6143
6144 /* X font string is as follows (from faces.el)
6145 * (let ((- "[-?]")
6146 * (foundry "[^-]+")
6147 * (family "[^-]+")
6148 * (weight "\\(bold\\|demibold\\|medium\\)") ; 1
6149 * (weight\? "\\([^-]*\\)") ; 1
6150 * (slant "\\([ior]\\)") ; 2
6151 * (slant\? "\\([^-]?\\)") ; 2
6152 * (swidth "\\([^-]*\\)") ; 3
6153 * (adstyle "[^-]*") ; 4
6154 * (pixelsize "[0-9]+")
6155 * (pointsize "[0-9][0-9]+")
6156 * (resx "[0-9][0-9]+")
6157 * (resy "[0-9][0-9]+")
6158 * (spacing "[cmp?*]")
6159 * (avgwidth "[0-9]+")
6160 * (registry "[^-]+")
6161 * (encoding "[^-]+")
6162 * )
6163 */
6164
6165 static LONG
6166 x_to_w32_weight (lpw)
6167 char * lpw;
6168 {
6169 if (!lpw) return (FW_DONTCARE);
6170
6171 if (stricmp (lpw,"heavy") == 0) return FW_HEAVY;
6172 else if (stricmp (lpw,"extrabold") == 0) return FW_EXTRABOLD;
6173 else if (stricmp (lpw,"bold") == 0) return FW_BOLD;
6174 else if (stricmp (lpw,"demibold") == 0) return FW_SEMIBOLD;
6175 else if (stricmp (lpw,"semibold") == 0) return FW_SEMIBOLD;
6176 else if (stricmp (lpw,"medium") == 0) return FW_MEDIUM;
6177 else if (stricmp (lpw,"normal") == 0) return FW_NORMAL;
6178 else if (stricmp (lpw,"light") == 0) return FW_LIGHT;
6179 else if (stricmp (lpw,"extralight") == 0) return FW_EXTRALIGHT;
6180 else if (stricmp (lpw,"thin") == 0) return FW_THIN;
6181 else
6182 return FW_DONTCARE;
6183 }
6184
6185
6186 static char *
6187 w32_to_x_weight (fnweight)
6188 int fnweight;
6189 {
6190 if (fnweight >= FW_HEAVY) return "heavy";
6191 if (fnweight >= FW_EXTRABOLD) return "extrabold";
6192 if (fnweight >= FW_BOLD) return "bold";
6193 if (fnweight >= FW_SEMIBOLD) return "demibold";
6194 if (fnweight >= FW_MEDIUM) return "medium";
6195 if (fnweight >= FW_NORMAL) return "normal";
6196 if (fnweight >= FW_LIGHT) return "light";
6197 if (fnweight >= FW_EXTRALIGHT) return "extralight";
6198 if (fnweight >= FW_THIN) return "thin";
6199 else
6200 return "*";
6201 }
6202
6203 static LONG
6204 x_to_w32_charset (lpcs)
6205 char * lpcs;
6206 {
6207 Lisp_Object this_entry, w32_charset;
6208 char *charset;
6209 int len = strlen (lpcs);
6210
6211 /* Support "*-#nnn" format for unknown charsets. */
6212 if (strncmp (lpcs, "*-#", 3) == 0)
6213 return atoi (lpcs + 3);
6214
6215 /* Handle wildcards by ignoring them; eg. treat "big5*-*" as "big5". */
6216 charset = alloca (len + 1);
6217 strcpy (charset, lpcs);
6218 lpcs = strchr (charset, '*');
6219 if (lpcs)
6220 *lpcs = 0;
6221
6222 /* Look through w32-charset-info-alist for the character set.
6223 Format of each entry is
6224 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
6225 */
6226 this_entry = Fassoc (build_string(charset), Vw32_charset_info_alist);
6227
6228 if (NILP(this_entry))
6229 {
6230 /* At startup, we want iso8859-1 fonts to come up properly. */
6231 if (stricmp(charset, "iso8859-1") == 0)
6232 return ANSI_CHARSET;
6233 else
6234 return DEFAULT_CHARSET;
6235 }
6236
6237 w32_charset = Fcar (Fcdr (this_entry));
6238
6239 /* Translate Lisp symbol to number. */
6240 if (w32_charset == Qw32_charset_ansi)
6241 return ANSI_CHARSET;
6242 if (w32_charset == Qw32_charset_symbol)
6243 return SYMBOL_CHARSET;
6244 if (w32_charset == Qw32_charset_shiftjis)
6245 return SHIFTJIS_CHARSET;
6246 if (w32_charset == Qw32_charset_hangeul)
6247 return HANGEUL_CHARSET;
6248 if (w32_charset == Qw32_charset_chinesebig5)
6249 return CHINESEBIG5_CHARSET;
6250 if (w32_charset == Qw32_charset_gb2312)
6251 return GB2312_CHARSET;
6252 if (w32_charset == Qw32_charset_oem)
6253 return OEM_CHARSET;
6254 #ifdef JOHAB_CHARSET
6255 if (w32_charset == Qw32_charset_johab)
6256 return JOHAB_CHARSET;
6257 if (w32_charset == Qw32_charset_easteurope)
6258 return EASTEUROPE_CHARSET;
6259 if (w32_charset == Qw32_charset_turkish)
6260 return TURKISH_CHARSET;
6261 if (w32_charset == Qw32_charset_baltic)
6262 return BALTIC_CHARSET;
6263 if (w32_charset == Qw32_charset_russian)
6264 return RUSSIAN_CHARSET;
6265 if (w32_charset == Qw32_charset_arabic)
6266 return ARABIC_CHARSET;
6267 if (w32_charset == Qw32_charset_greek)
6268 return GREEK_CHARSET;
6269 if (w32_charset == Qw32_charset_hebrew)
6270 return HEBREW_CHARSET;
6271 if (w32_charset == Qw32_charset_vietnamese)
6272 return VIETNAMESE_CHARSET;
6273 if (w32_charset == Qw32_charset_thai)
6274 return THAI_CHARSET;
6275 if (w32_charset == Qw32_charset_mac)
6276 return MAC_CHARSET;
6277 #endif /* JOHAB_CHARSET */
6278 #ifdef UNICODE_CHARSET
6279 if (w32_charset == Qw32_charset_unicode)
6280 return UNICODE_CHARSET;
6281 #endif
6282
6283 return DEFAULT_CHARSET;
6284 }
6285
6286
6287 static char *
6288 w32_to_x_charset (fncharset)
6289 int fncharset;
6290 {
6291 static char buf[32];
6292 Lisp_Object charset_type;
6293
6294 switch (fncharset)
6295 {
6296 case ANSI_CHARSET:
6297 /* Handle startup case of w32-charset-info-alist not
6298 being set up yet. */
6299 if (NILP(Vw32_charset_info_alist))
6300 return "iso8859-1";
6301 charset_type = Qw32_charset_ansi;
6302 break;
6303 case DEFAULT_CHARSET:
6304 charset_type = Qw32_charset_default;
6305 break;
6306 case SYMBOL_CHARSET:
6307 charset_type = Qw32_charset_symbol;
6308 break;
6309 case SHIFTJIS_CHARSET:
6310 charset_type = Qw32_charset_shiftjis;
6311 break;
6312 case HANGEUL_CHARSET:
6313 charset_type = Qw32_charset_hangeul;
6314 break;
6315 case GB2312_CHARSET:
6316 charset_type = Qw32_charset_gb2312;
6317 break;
6318 case CHINESEBIG5_CHARSET:
6319 charset_type = Qw32_charset_chinesebig5;
6320 break;
6321 case OEM_CHARSET:
6322 charset_type = Qw32_charset_oem;
6323 break;
6324
6325 /* More recent versions of Windows (95 and NT4.0) define more
6326 character sets. */
6327 #ifdef EASTEUROPE_CHARSET
6328 case EASTEUROPE_CHARSET:
6329 charset_type = Qw32_charset_easteurope;
6330 break;
6331 case TURKISH_CHARSET:
6332 charset_type = Qw32_charset_turkish;
6333 break;
6334 case BALTIC_CHARSET:
6335 charset_type = Qw32_charset_baltic;
6336 break;
6337 case RUSSIAN_CHARSET:
6338 charset_type = Qw32_charset_russian;
6339 break;
6340 case ARABIC_CHARSET:
6341 charset_type = Qw32_charset_arabic;
6342 break;
6343 case GREEK_CHARSET:
6344 charset_type = Qw32_charset_greek;
6345 break;
6346 case HEBREW_CHARSET:
6347 charset_type = Qw32_charset_hebrew;
6348 break;
6349 case VIETNAMESE_CHARSET:
6350 charset_type = Qw32_charset_vietnamese;
6351 break;
6352 case THAI_CHARSET:
6353 charset_type = Qw32_charset_thai;
6354 break;
6355 case MAC_CHARSET:
6356 charset_type = Qw32_charset_mac;
6357 break;
6358 case JOHAB_CHARSET:
6359 charset_type = Qw32_charset_johab;
6360 break;
6361 #endif
6362
6363 #ifdef UNICODE_CHARSET
6364 case UNICODE_CHARSET:
6365 charset_type = Qw32_charset_unicode;
6366 break;
6367 #endif
6368 default:
6369 /* Encode numerical value of unknown charset. */
6370 sprintf (buf, "*-#%u", fncharset);
6371 return buf;
6372 }
6373
6374 {
6375 Lisp_Object rest;
6376 char * best_match = NULL;
6377
6378 /* Look through w32-charset-info-alist for the character set.
6379 Prefer ISO codepages, and prefer lower numbers in the ISO
6380 range. Only return charsets for codepages which are installed.
6381
6382 Format of each entry is
6383 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
6384 */
6385 for (rest = Vw32_charset_info_alist; CONSP (rest); rest = XCDR (rest))
6386 {
6387 char * x_charset;
6388 Lisp_Object w32_charset;
6389 Lisp_Object codepage;
6390
6391 Lisp_Object this_entry = XCAR (rest);
6392
6393 /* Skip invalid entries in alist. */
6394 if (!CONSP (this_entry) || !STRINGP (XCAR (this_entry))
6395 || !CONSP (XCDR (this_entry))
6396 || !SYMBOLP (XCAR (XCDR (this_entry))))
6397 continue;
6398
6399 x_charset = XSTRING (XCAR (this_entry))->data;
6400 w32_charset = XCAR (XCDR (this_entry));
6401 codepage = XCDR (XCDR (this_entry));
6402
6403 /* Look for Same charset and a valid codepage (or non-int
6404 which means ignore). */
6405 if (w32_charset == charset_type
6406 && (!INTEGERP (codepage) || codepage == CP_DEFAULT
6407 || IsValidCodePage (XINT (codepage))))
6408 {
6409 /* If we don't have a match already, then this is the
6410 best. */
6411 if (!best_match)
6412 best_match = x_charset;
6413 /* If this is an ISO codepage, and the best so far isn't,
6414 then this is better. */
6415 else if (strnicmp (best_match, "iso", 3) != 0
6416 && strnicmp (x_charset, "iso", 3) == 0)
6417 best_match = x_charset;
6418 /* If both are ISO8859 codepages, choose the one with the
6419 lowest number in the encoding field. */
6420 else if (strnicmp (best_match, "iso8859-", 8) == 0
6421 && strnicmp (x_charset, "iso8859-", 8) == 0)
6422 {
6423 int best_enc = atoi (best_match + 8);
6424 int this_enc = atoi (x_charset + 8);
6425 if (this_enc > 0 && this_enc < best_enc)
6426 best_match = x_charset;
6427 }
6428 }
6429 }
6430
6431 /* If no match, encode the numeric value. */
6432 if (!best_match)
6433 {
6434 sprintf (buf, "*-#%u", fncharset);
6435 return buf;
6436 }
6437
6438 strncpy(buf, best_match, 31);
6439 buf[31] = '\0';
6440 return buf;
6441 }
6442 }
6443
6444
6445 /* Return all the X charsets that map to a font. */
6446 static Lisp_Object
6447 w32_to_all_x_charsets (fncharset)
6448 int fncharset;
6449 {
6450 static char buf[32];
6451 Lisp_Object charset_type;
6452 Lisp_Object retval = Qnil;
6453
6454 switch (fncharset)
6455 {
6456 case ANSI_CHARSET:
6457 /* Handle startup case of w32-charset-info-alist not
6458 being set up yet. */
6459 if (NILP(Vw32_charset_info_alist))
6460 return Fcons (build_string ("iso8859-1"), Qnil);
6461
6462 charset_type = Qw32_charset_ansi;
6463 break;
6464 case DEFAULT_CHARSET:
6465 charset_type = Qw32_charset_default;
6466 break;
6467 case SYMBOL_CHARSET:
6468 charset_type = Qw32_charset_symbol;
6469 break;
6470 case SHIFTJIS_CHARSET:
6471 charset_type = Qw32_charset_shiftjis;
6472 break;
6473 case HANGEUL_CHARSET:
6474 charset_type = Qw32_charset_hangeul;
6475 break;
6476 case GB2312_CHARSET:
6477 charset_type = Qw32_charset_gb2312;
6478 break;
6479 case CHINESEBIG5_CHARSET:
6480 charset_type = Qw32_charset_chinesebig5;
6481 break;
6482 case OEM_CHARSET:
6483 charset_type = Qw32_charset_oem;
6484 break;
6485
6486 /* More recent versions of Windows (95 and NT4.0) define more
6487 character sets. */
6488 #ifdef EASTEUROPE_CHARSET
6489 case EASTEUROPE_CHARSET:
6490 charset_type = Qw32_charset_easteurope;
6491 break;
6492 case TURKISH_CHARSET:
6493 charset_type = Qw32_charset_turkish;
6494 break;
6495 case BALTIC_CHARSET:
6496 charset_type = Qw32_charset_baltic;
6497 break;
6498 case RUSSIAN_CHARSET:
6499 charset_type = Qw32_charset_russian;
6500 break;
6501 case ARABIC_CHARSET:
6502 charset_type = Qw32_charset_arabic;
6503 break;
6504 case GREEK_CHARSET:
6505 charset_type = Qw32_charset_greek;
6506 break;
6507 case HEBREW_CHARSET:
6508 charset_type = Qw32_charset_hebrew;
6509 break;
6510 case VIETNAMESE_CHARSET:
6511 charset_type = Qw32_charset_vietnamese;
6512 break;
6513 case THAI_CHARSET:
6514 charset_type = Qw32_charset_thai;
6515 break;
6516 case MAC_CHARSET:
6517 charset_type = Qw32_charset_mac;
6518 break;
6519 case JOHAB_CHARSET:
6520 charset_type = Qw32_charset_johab;
6521 break;
6522 #endif
6523
6524 #ifdef UNICODE_CHARSET
6525 case UNICODE_CHARSET:
6526 charset_type = Qw32_charset_unicode;
6527 break;
6528 #endif
6529 default:
6530 /* Encode numerical value of unknown charset. */
6531 sprintf (buf, "*-#%u", fncharset);
6532 return Fcons (build_string (buf), Qnil);
6533 }
6534
6535 {
6536 Lisp_Object rest;
6537 /* Look through w32-charset-info-alist for the character set.
6538 Only return charsets for codepages which are installed.
6539
6540 Format of each entry in Vw32_charset_info_alist is
6541 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
6542 */
6543 for (rest = Vw32_charset_info_alist; CONSP (rest); rest = XCDR (rest))
6544 {
6545 Lisp_Object x_charset;
6546 Lisp_Object w32_charset;
6547 Lisp_Object codepage;
6548
6549 Lisp_Object this_entry = XCAR (rest);
6550
6551 /* Skip invalid entries in alist. */
6552 if (!CONSP (this_entry) || !STRINGP (XCAR (this_entry))
6553 || !CONSP (XCDR (this_entry))
6554 || !SYMBOLP (XCAR (XCDR (this_entry))))
6555 continue;
6556
6557 x_charset = XCAR (this_entry);
6558 w32_charset = XCAR (XCDR (this_entry));
6559 codepage = XCDR (XCDR (this_entry));
6560
6561 /* Look for Same charset and a valid codepage (or non-int
6562 which means ignore). */
6563 if (w32_charset == charset_type
6564 && (!INTEGERP (codepage) || codepage == CP_DEFAULT
6565 || IsValidCodePage (XINT (codepage))))
6566 {
6567 retval = Fcons (x_charset, retval);
6568 }
6569 }
6570
6571 /* If no match, encode the numeric value. */
6572 if (NILP (retval))
6573 {
6574 sprintf (buf, "*-#%u", fncharset);
6575 return Fcons (build_string (buf), Qnil);
6576 }
6577
6578 return retval;
6579 }
6580 }
6581
6582 /* Get the Windows codepage corresponding to the specified font. The
6583 charset info in the font name is used to look up
6584 w32-charset-to-codepage-alist. */
6585 int
6586 w32_codepage_for_font (char *fontname)
6587 {
6588 Lisp_Object codepage, entry;
6589 char *charset_str, *charset, *end;
6590
6591 if (NILP (Vw32_charset_info_alist))
6592 return CP_DEFAULT;
6593
6594 /* Extract charset part of font string. */
6595 charset = xlfd_charset_of_font (fontname);
6596
6597 if (!charset)
6598 return CP_UNKNOWN;
6599
6600 charset_str = (char *) alloca (strlen (charset) + 1);
6601 strcpy (charset_str, charset);
6602
6603 #if 0
6604 /* Remove leading "*-". */
6605 if (strncmp ("*-", charset_str, 2) == 0)
6606 charset = charset_str + 2;
6607 else
6608 #endif
6609 charset = charset_str;
6610
6611 /* Stop match at wildcard (including preceding '-'). */
6612 if (end = strchr (charset, '*'))
6613 {
6614 if (end > charset && *(end-1) == '-')
6615 end--;
6616 *end = '\0';
6617 }
6618
6619 entry = Fassoc (build_string(charset), Vw32_charset_info_alist);
6620 if (NILP (entry))
6621 return CP_UNKNOWN;
6622
6623 codepage = Fcdr (Fcdr (entry));
6624
6625 if (NILP (codepage))
6626 return CP_8BIT;
6627 else if (XFASTINT (codepage) == XFASTINT (Qt))
6628 return CP_UNICODE;
6629 else if (INTEGERP (codepage))
6630 return XINT (codepage);
6631 else
6632 return CP_UNKNOWN;
6633 }
6634
6635
6636 static BOOL
6637 w32_to_x_font (lplogfont, lpxstr, len, specific_charset)
6638 LOGFONT * lplogfont;
6639 char * lpxstr;
6640 int len;
6641 char * specific_charset;
6642 {
6643 char* fonttype;
6644 char *fontname;
6645 char height_pixels[8];
6646 char height_dpi[8];
6647 char width_pixels[8];
6648 char *fontname_dash;
6649 int display_resy = (int) one_w32_display_info.resy;
6650 int display_resx = (int) one_w32_display_info.resx;
6651 int bufsz;
6652 struct coding_system coding;
6653
6654 if (!lpxstr) abort ();
6655
6656 if (!lplogfont)
6657 return FALSE;
6658
6659 if (lplogfont->lfOutPrecision == OUT_STRING_PRECIS)
6660 fonttype = "raster";
6661 else if (lplogfont->lfOutPrecision == OUT_STROKE_PRECIS)
6662 fonttype = "outline";
6663 else
6664 fonttype = "unknown";
6665
6666 setup_coding_system (Fcheck_coding_system (Vlocale_coding_system),
6667 &coding);
6668 coding.src_multibyte = 0;
6669 coding.dst_multibyte = 1;
6670 coding.mode |= CODING_MODE_LAST_BLOCK;
6671 bufsz = decoding_buffer_size (&coding, LF_FACESIZE);
6672
6673 fontname = alloca(sizeof(*fontname) * bufsz);
6674 decode_coding (&coding, lplogfont->lfFaceName, fontname,
6675 strlen(lplogfont->lfFaceName), bufsz - 1);
6676 *(fontname + coding.produced) = '\0';
6677
6678 /* Replace dashes with underscores so the dashes are not
6679 misinterpreted. */
6680 fontname_dash = fontname;
6681 while (fontname_dash = strchr (fontname_dash, '-'))
6682 *fontname_dash = '_';
6683
6684 if (lplogfont->lfHeight)
6685 {
6686 sprintf (height_pixels, "%u", abs (lplogfont->lfHeight));
6687 sprintf (height_dpi, "%u",
6688 abs (lplogfont->lfHeight) * 720 / display_resy);
6689 }
6690 else
6691 {
6692 strcpy (height_pixels, "*");
6693 strcpy (height_dpi, "*");
6694 }
6695 if (lplogfont->lfWidth)
6696 sprintf (width_pixels, "%u", lplogfont->lfWidth * 10);
6697 else
6698 strcpy (width_pixels, "*");
6699
6700 _snprintf (lpxstr, len - 1,
6701 "-%s-%s-%s-%c-normal-normal-%s-%s-%d-%d-%c-%s-%s",
6702 fonttype, /* foundry */
6703 fontname, /* family */
6704 w32_to_x_weight (lplogfont->lfWeight), /* weight */
6705 lplogfont->lfItalic?'i':'r', /* slant */
6706 /* setwidth name */
6707 /* add style name */
6708 height_pixels, /* pixel size */
6709 height_dpi, /* point size */
6710 display_resx, /* resx */
6711 display_resy, /* resy */
6712 ((lplogfont->lfPitchAndFamily & 0x3) == VARIABLE_PITCH)
6713 ? 'p' : 'c', /* spacing */
6714 width_pixels, /* avg width */
6715 specific_charset ? specific_charset
6716 : w32_to_x_charset (lplogfont->lfCharSet)
6717 /* charset registry and encoding */
6718 );
6719
6720 lpxstr[len - 1] = 0; /* just to be sure */
6721 return (TRUE);
6722 }
6723
6724 static BOOL
6725 x_to_w32_font (lpxstr, lplogfont)
6726 char * lpxstr;
6727 LOGFONT * lplogfont;
6728 {
6729 struct coding_system coding;
6730
6731 if (!lplogfont) return (FALSE);
6732
6733 memset (lplogfont, 0, sizeof (*lplogfont));
6734
6735 /* Set default value for each field. */
6736 #if 1
6737 lplogfont->lfOutPrecision = OUT_DEFAULT_PRECIS;
6738 lplogfont->lfClipPrecision = CLIP_DEFAULT_PRECIS;
6739 lplogfont->lfQuality = DEFAULT_QUALITY;
6740 #else
6741 /* go for maximum quality */
6742 lplogfont->lfOutPrecision = OUT_STROKE_PRECIS;
6743 lplogfont->lfClipPrecision = CLIP_STROKE_PRECIS;
6744 lplogfont->lfQuality = PROOF_QUALITY;
6745 #endif
6746
6747 lplogfont->lfCharSet = DEFAULT_CHARSET;
6748 lplogfont->lfWeight = FW_DONTCARE;
6749 lplogfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
6750
6751 if (!lpxstr)
6752 return FALSE;
6753
6754 /* Provide a simple escape mechanism for specifying Windows font names
6755 * directly -- if font spec does not beginning with '-', assume this
6756 * format:
6757 * "<font name>[:height in pixels[:width in pixels[:weight]]]"
6758 */
6759
6760 if (*lpxstr == '-')
6761 {
6762 int fields, tem;
6763 char name[50], weight[20], slant, pitch, pixels[10], height[10],
6764 width[10], resy[10], remainder[50];
6765 char * encoding;
6766 int dpi = (int) one_w32_display_info.resy;
6767
6768 fields = sscanf (lpxstr,
6769 "-%*[^-]-%49[^-]-%19[^-]-%c-%*[^-]-%*[^-]-%9[^-]-%9[^-]-%*[^-]-%9[^-]-%c-%9[^-]-%49s",
6770 name, weight, &slant, pixels, height, resy, &pitch, width, remainder);
6771 if (fields == EOF)
6772 return (FALSE);
6773
6774 /* In the general case when wildcards cover more than one field,
6775 we don't know which field is which, so don't fill any in.
6776 However, we need to cope with this particular form, which is
6777 generated by font_list_1 (invoked by try_font_list):
6778 "-raster-6x10-*-gb2312*-*"
6779 and make sure to correctly parse the charset field. */
6780 if (fields == 3)
6781 {
6782 fields = sscanf (lpxstr,
6783 "-%*[^-]-%49[^-]-*-%49s",
6784 name, remainder);
6785 }
6786 else if (fields < 9)
6787 {
6788 fields = 0;
6789 remainder[0] = 0;
6790 }
6791
6792 if (fields > 0 && name[0] != '*')
6793 {
6794 int bufsize;
6795 unsigned char *buf;
6796
6797 setup_coding_system
6798 (Fcheck_coding_system (Vlocale_coding_system), &coding);
6799 coding.src_multibyte = 1;
6800 coding.dst_multibyte = 1;
6801 bufsize = encoding_buffer_size (&coding, strlen (name));
6802 buf = (unsigned char *) alloca (bufsize);
6803 coding.mode |= CODING_MODE_LAST_BLOCK;
6804 encode_coding (&coding, name, buf, strlen (name), bufsize);
6805 if (coding.produced >= LF_FACESIZE)
6806 coding.produced = LF_FACESIZE - 1;
6807 buf[coding.produced] = 0;
6808 strcpy (lplogfont->lfFaceName, buf);
6809 }
6810 else
6811 {
6812 lplogfont->lfFaceName[0] = '\0';
6813 }
6814
6815 fields--;
6816
6817 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
6818
6819 fields--;
6820
6821 lplogfont->lfItalic = (fields > 0 && slant == 'i');
6822
6823 fields--;
6824
6825 if (fields > 0 && pixels[0] != '*')
6826 lplogfont->lfHeight = atoi (pixels);
6827
6828 fields--;
6829 fields--;
6830 if (fields > 0 && resy[0] != '*')
6831 {
6832 tem = atoi (resy);
6833 if (tem > 0) dpi = tem;
6834 }
6835
6836 if (fields > -1 && lplogfont->lfHeight == 0 && height[0] != '*')
6837 lplogfont->lfHeight = atoi (height) * dpi / 720;
6838
6839 if (fields > 0)
6840 lplogfont->lfPitchAndFamily =
6841 (fields > 0 && pitch == 'p') ? VARIABLE_PITCH : FIXED_PITCH;
6842
6843 fields--;
6844
6845 if (fields > 0 && width[0] != '*')
6846 lplogfont->lfWidth = atoi (width) / 10;
6847
6848 fields--;
6849
6850 /* Strip the trailing '-' if present. (it shouldn't be, as it
6851 fails the test against xlfd-tight-regexp in fontset.el). */
6852 {
6853 int len = strlen (remainder);
6854 if (len > 0 && remainder[len-1] == '-')
6855 remainder[len-1] = 0;
6856 }
6857 encoding = remainder;
6858 #if 0
6859 if (strncmp (encoding, "*-", 2) == 0)
6860 encoding += 2;
6861 #endif
6862 lplogfont->lfCharSet = x_to_w32_charset (encoding);
6863 }
6864 else
6865 {
6866 int fields;
6867 char name[100], height[10], width[10], weight[20];
6868
6869 fields = sscanf (lpxstr,
6870 "%99[^:]:%9[^:]:%9[^:]:%19s",
6871 name, height, width, weight);
6872
6873 if (fields == EOF) return (FALSE);
6874
6875 if (fields > 0)
6876 {
6877 strncpy (lplogfont->lfFaceName,name, LF_FACESIZE);
6878 lplogfont->lfFaceName[LF_FACESIZE-1] = 0;
6879 }
6880 else
6881 {
6882 lplogfont->lfFaceName[0] = 0;
6883 }
6884
6885 fields--;
6886
6887 if (fields > 0)
6888 lplogfont->lfHeight = atoi (height);
6889
6890 fields--;
6891
6892 if (fields > 0)
6893 lplogfont->lfWidth = atoi (width);
6894
6895 fields--;
6896
6897 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
6898 }
6899
6900 /* This makes TrueType fonts work better. */
6901 lplogfont->lfHeight = - abs (lplogfont->lfHeight);
6902
6903 return (TRUE);
6904 }
6905
6906 /* Strip the pixel height and point height from the given xlfd, and
6907 return the pixel height. If no pixel height is specified, calculate
6908 one from the point height, or if that isn't defined either, return
6909 0 (which usually signifies a scalable font).
6910 */
6911 static int
6912 xlfd_strip_height (char *fontname)
6913 {
6914 int pixel_height, field_number;
6915 char *read_from, *write_to;
6916
6917 xassert (fontname);
6918
6919 pixel_height = field_number = 0;
6920 write_to = NULL;
6921
6922 /* Look for height fields. */
6923 for (read_from = fontname; *read_from; read_from++)
6924 {
6925 if (*read_from == '-')
6926 {
6927 field_number++;
6928 if (field_number == 7) /* Pixel height. */
6929 {
6930 read_from++;
6931 write_to = read_from;
6932
6933 /* Find end of field. */
6934 for (;*read_from && *read_from != '-'; read_from++)
6935 ;
6936
6937 /* Split the fontname at end of field. */
6938 if (*read_from)
6939 {
6940 *read_from = '\0';
6941 read_from++;
6942 }
6943 pixel_height = atoi (write_to);
6944 /* Blank out field. */
6945 if (read_from > write_to)
6946 {
6947 *write_to = '-';
6948 write_to++;
6949 }
6950 /* If the pixel height field is at the end (partial xlfd),
6951 return now. */
6952 else
6953 return pixel_height;
6954
6955 /* If we got a pixel height, the point height can be
6956 ignored. Just blank it out and break now. */
6957 if (pixel_height)
6958 {
6959 /* Find end of point size field. */
6960 for (; *read_from && *read_from != '-'; read_from++)
6961 ;
6962
6963 if (*read_from)
6964 read_from++;
6965
6966 /* Blank out the point size field. */
6967 if (read_from > write_to)
6968 {
6969 *write_to = '-';
6970 write_to++;
6971 }
6972 else
6973 return pixel_height;
6974
6975 break;
6976 }
6977 /* If the point height is already blank, break now. */
6978 if (*read_from == '-')
6979 {
6980 read_from++;
6981 break;
6982 }
6983 }
6984 else if (field_number == 8)
6985 {
6986 /* If we didn't get a pixel height, try to get the point
6987 height and convert that. */
6988 int point_size;
6989 char *point_size_start = read_from++;
6990
6991 /* Find end of field. */
6992 for (; *read_from && *read_from != '-'; read_from++)
6993 ;
6994
6995 if (*read_from)
6996 {
6997 *read_from = '\0';
6998 read_from++;
6999 }
7000
7001 point_size = atoi (point_size_start);
7002
7003 /* Convert to pixel height. */
7004 pixel_height = point_size
7005 * one_w32_display_info.height_in / 720;
7006
7007 /* Blank out this field and break. */
7008 *write_to = '-';
7009 write_to++;
7010 break;
7011 }
7012 }
7013 }
7014
7015 /* Shift the rest of the font spec into place. */
7016 if (write_to && read_from > write_to)
7017 {
7018 for (; *read_from; read_from++, write_to++)
7019 *write_to = *read_from;
7020 *write_to = '\0';
7021 }
7022
7023 return pixel_height;
7024 }
7025
7026 /* Assume parameter 1 is fully qualified, no wildcards. */
7027 static BOOL
7028 w32_font_match (fontname, pattern)
7029 char * fontname;
7030 char * pattern;
7031 {
7032 char *regex = alloca (strlen (pattern) * 2 + 3);
7033 char *font_name_copy = alloca (strlen (fontname) + 1);
7034 char *ptr;
7035
7036 /* Copy fontname so we can modify it during comparison. */
7037 strcpy (font_name_copy, fontname);
7038
7039 ptr = regex;
7040 *ptr++ = '^';
7041
7042 /* Turn pattern into a regexp and do a regexp match. */
7043 for (; *pattern; pattern++)
7044 {
7045 if (*pattern == '?')
7046 *ptr++ = '.';
7047 else if (*pattern == '*')
7048 {
7049 *ptr++ = '.';
7050 *ptr++ = '*';
7051 }
7052 else
7053 *ptr++ = *pattern;
7054 }
7055 *ptr = '$';
7056 *(ptr + 1) = '\0';
7057
7058 /* Strip out font heights and compare them seperately, since
7059 rounding error can cause mismatches. This also allows a
7060 comparison between a font that declares only a pixel height and a
7061 pattern that declares the point height.
7062 */
7063 {
7064 int font_height, pattern_height;
7065
7066 font_height = xlfd_strip_height (font_name_copy);
7067 pattern_height = xlfd_strip_height (regex);
7068
7069 /* Compare now, and don't bother doing expensive regexp matching
7070 if the heights differ. */
7071 if (font_height && pattern_height && (font_height != pattern_height))
7072 return FALSE;
7073 }
7074
7075 return (fast_c_string_match_ignore_case (build_string (regex),
7076 font_name_copy) >= 0);
7077 }
7078
7079 /* Callback functions, and a structure holding info they need, for
7080 listing system fonts on W32. We need one set of functions to do the
7081 job properly, but these don't work on NT 3.51 and earlier, so we
7082 have a second set which don't handle character sets properly to
7083 fall back on.
7084
7085 In both cases, there are two passes made. The first pass gets one
7086 font from each family, the second pass lists all the fonts from
7087 each family. */
7088
7089 typedef struct enumfont_t
7090 {
7091 HDC hdc;
7092 int numFonts;
7093 LOGFONT logfont;
7094 XFontStruct *size_ref;
7095 Lisp_Object *pattern;
7096 Lisp_Object list;
7097 Lisp_Object *tail;
7098 } enumfont_t;
7099
7100
7101 static void
7102 enum_font_maybe_add_to_list (enumfont_t *, LOGFONT *, char *, Lisp_Object);
7103
7104
7105 static int CALLBACK
7106 enum_font_cb2 (lplf, lptm, FontType, lpef)
7107 ENUMLOGFONT * lplf;
7108 NEWTEXTMETRIC * lptm;
7109 int FontType;
7110 enumfont_t * lpef;
7111 {
7112 /* Ignore struck out and underlined versions of fonts. */
7113 if (lplf->elfLogFont.lfStrikeOut || lplf->elfLogFont.lfUnderline)
7114 return 1;
7115
7116 /* Only return fonts with names starting with @ if they were
7117 explicitly specified, since Microsoft uses an initial @ to
7118 denote fonts for vertical writing, without providing a more
7119 convenient way of identifying them. */
7120 if (lplf->elfLogFont.lfFaceName[0] == '@'
7121 && lpef->logfont.lfFaceName[0] != '@')
7122 return 1;
7123
7124 /* Check that the character set matches if it was specified */
7125 if (lpef->logfont.lfCharSet != DEFAULT_CHARSET &&
7126 lplf->elfLogFont.lfCharSet != lpef->logfont.lfCharSet)
7127 return 1;
7128
7129 {
7130 char buf[100];
7131 Lisp_Object width = Qnil;
7132 Lisp_Object charset_list = Qnil;
7133 char *charset = NULL;
7134
7135 /* Truetype fonts do not report their true metrics until loaded */
7136 if (FontType != RASTER_FONTTYPE)
7137 {
7138 if (!NILP (*(lpef->pattern)))
7139 {
7140 /* Scalable fonts are as big as you want them to be. */
7141 lplf->elfLogFont.lfHeight = lpef->logfont.lfHeight;
7142 lplf->elfLogFont.lfWidth = lpef->logfont.lfWidth;
7143 width = make_number (lpef->logfont.lfWidth);
7144 }
7145 else
7146 {
7147 lplf->elfLogFont.lfHeight = 0;
7148 lplf->elfLogFont.lfWidth = 0;
7149 }
7150 }
7151
7152 /* Make sure the height used here is the same as everywhere
7153 else (ie character height, not cell height). */
7154 if (lplf->elfLogFont.lfHeight > 0)
7155 {
7156 /* lptm can be trusted for RASTER fonts, but not scalable ones. */
7157 if (FontType == RASTER_FONTTYPE)
7158 lplf->elfLogFont.lfHeight = lptm->tmInternalLeading - lptm->tmHeight;
7159 else
7160 lplf->elfLogFont.lfHeight = -lplf->elfLogFont.lfHeight;
7161 }
7162
7163 if (!NILP (*(lpef->pattern)))
7164 {
7165 charset = xlfd_charset_of_font (XSTRING(*(lpef->pattern))->data);
7166
7167 /* We already checked charsets above, but DEFAULT_CHARSET
7168 slipped through. So only allow exact matches for DEFAULT_CHARSET. */
7169 if (charset
7170 && strncmp (charset, "*-*", 3) != 0
7171 && lpef->logfont.lfCharSet == DEFAULT_CHARSET
7172 && strcmp (charset, w32_to_x_charset (DEFAULT_CHARSET)) != 0)
7173 return 1;
7174 }
7175
7176 if (charset)
7177 charset_list = Fcons (build_string (charset), Qnil);
7178 else
7179 charset_list = w32_to_all_x_charsets (lplf->elfLogFont.lfCharSet);
7180
7181 /* Loop through the charsets. */
7182 for ( ; CONSP (charset_list); charset_list = Fcdr (charset_list))
7183 {
7184 Lisp_Object this_charset = Fcar (charset_list);
7185 charset = XSTRING (this_charset)->data;
7186
7187 /* List bold and italic variations if w32-enable-synthesized-fonts
7188 is non-nil and this is a plain font. */
7189 if (w32_enable_synthesized_fonts
7190 && lplf->elfLogFont.lfWeight == FW_NORMAL
7191 && lplf->elfLogFont.lfItalic == FALSE)
7192 {
7193 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7194 charset, width);
7195 /* bold. */
7196 lplf->elfLogFont.lfWeight = FW_BOLD;
7197 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7198 charset, width);
7199 /* bold italic. */
7200 lplf->elfLogFont.lfItalic = TRUE;
7201 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7202 charset, width);
7203 /* italic. */
7204 lplf->elfLogFont.lfWeight = FW_NORMAL;
7205 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7206 charset, width);
7207 }
7208 else
7209 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7210 charset, width);
7211 }
7212 }
7213
7214 return 1;
7215 }
7216
7217 static void
7218 enum_font_maybe_add_to_list (lpef, logfont, match_charset, width)
7219 enumfont_t * lpef;
7220 LOGFONT * logfont;
7221 char * match_charset;
7222 Lisp_Object width;
7223 {
7224 char buf[100];
7225
7226 if (!w32_to_x_font (logfont, buf, 100, match_charset))
7227 return;
7228
7229 if (NILP (*(lpef->pattern))
7230 || w32_font_match (buf, XSTRING (*(lpef->pattern))->data))
7231 {
7232 /* Check if we already listed this font. This may happen if
7233 w32_enable_synthesized_fonts is non-nil, and there are real
7234 bold and italic versions of the font. */
7235 Lisp_Object font_name = build_string (buf);
7236 if (NILP (Fmember (font_name, lpef->list)))
7237 {
7238 *lpef->tail = Fcons (Fcons (build_string (buf), width), Qnil);
7239 lpef->tail = &(XCDR (*lpef->tail));
7240 lpef->numFonts++;
7241 }
7242 }
7243 }
7244
7245
7246 static int CALLBACK
7247 enum_font_cb1 (lplf, lptm, FontType, lpef)
7248 ENUMLOGFONT * lplf;
7249 NEWTEXTMETRIC * lptm;
7250 int FontType;
7251 enumfont_t * lpef;
7252 {
7253 return EnumFontFamilies (lpef->hdc,
7254 lplf->elfLogFont.lfFaceName,
7255 (FONTENUMPROC) enum_font_cb2,
7256 (LPARAM) lpef);
7257 }
7258
7259
7260 static int CALLBACK
7261 enum_fontex_cb2 (lplf, lptm, font_type, lpef)
7262 ENUMLOGFONTEX * lplf;
7263 NEWTEXTMETRICEX * lptm;
7264 int font_type;
7265 enumfont_t * lpef;
7266 {
7267 /* We are not interested in the extra info we get back from the 'Ex
7268 version - only the fact that we get character set variations
7269 enumerated seperately. */
7270 return enum_font_cb2 ((ENUMLOGFONT *) lplf, (NEWTEXTMETRIC *) lptm,
7271 font_type, lpef);
7272 }
7273
7274 static int CALLBACK
7275 enum_fontex_cb1 (lplf, lptm, font_type, lpef)
7276 ENUMLOGFONTEX * lplf;
7277 NEWTEXTMETRICEX * lptm;
7278 int font_type;
7279 enumfont_t * lpef;
7280 {
7281 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
7282 FARPROC enum_font_families_ex
7283 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
7284 /* We don't really expect EnumFontFamiliesEx to disappear once we
7285 get here, so don't bother handling it gracefully. */
7286 if (enum_font_families_ex == NULL)
7287 error ("gdi32.dll has disappeared!");
7288 return enum_font_families_ex (lpef->hdc,
7289 &lplf->elfLogFont,
7290 (FONTENUMPROC) enum_fontex_cb2,
7291 (LPARAM) lpef, 0);
7292 }
7293
7294 /* Interface to fontset handler. (adapted from mw32font.c in Meadow
7295 and xterm.c in Emacs 20.3) */
7296
7297 static Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names)
7298 {
7299 char *fontname, *ptnstr;
7300 Lisp_Object list, tem, newlist = Qnil;
7301 int n_fonts = 0;
7302
7303 list = Vw32_bdf_filename_alist;
7304 ptnstr = XSTRING (pattern)->data;
7305
7306 for ( ; CONSP (list); list = XCDR (list))
7307 {
7308 tem = XCAR (list);
7309 if (CONSP (tem))
7310 fontname = XSTRING (XCAR (tem))->data;
7311 else if (STRINGP (tem))
7312 fontname = XSTRING (tem)->data;
7313 else
7314 continue;
7315
7316 if (w32_font_match (fontname, ptnstr))
7317 {
7318 newlist = Fcons (XCAR (tem), newlist);
7319 n_fonts++;
7320 if (n_fonts >= max_names)
7321 break;
7322 }
7323 }
7324
7325 return newlist;
7326 }
7327
7328
7329 /* Return a list of names of available fonts matching PATTERN on frame
7330 F. If SIZE is not 0, it is the size (maximum bound width) of fonts
7331 to be listed. Frame F NULL means we have not yet created any
7332 frame, which means we can't get proper size info, as we don't have
7333 a device context to use for GetTextMetrics.
7334 MAXNAMES sets a limit on how many fonts to match. */
7335
7336 Lisp_Object
7337 w32_list_fonts (f, pattern, size, maxnames)
7338 struct frame *f;
7339 Lisp_Object pattern;
7340 int size;
7341 int maxnames;
7342 {
7343 Lisp_Object patterns, key = Qnil, tem, tpat;
7344 Lisp_Object list = Qnil, newlist = Qnil, second_best = Qnil;
7345 struct w32_display_info *dpyinfo = &one_w32_display_info;
7346 int n_fonts = 0;
7347
7348 patterns = Fassoc (pattern, Valternate_fontname_alist);
7349 if (NILP (patterns))
7350 patterns = Fcons (pattern, Qnil);
7351
7352 for (; CONSP (patterns); patterns = XCDR (patterns))
7353 {
7354 enumfont_t ef;
7355 int codepage;
7356
7357 tpat = XCAR (patterns);
7358
7359 if (!STRINGP (tpat))
7360 continue;
7361
7362 /* Avoid expensive EnumFontFamilies functions if we are not
7363 going to be able to output one of these anyway. */
7364 codepage = w32_codepage_for_font (XSTRING (tpat)->data);
7365 if (codepage != CP_8BIT && codepage != CP_UNICODE
7366 && codepage != CP_DEFAULT && codepage != CP_UNKNOWN
7367 && !IsValidCodePage(codepage))
7368 continue;
7369
7370 /* See if we cached the result for this particular query.
7371 The cache is an alist of the form:
7372 ((PATTERN (FONTNAME . WIDTH) ...) ...)
7373 */
7374 if (tem = XCDR (dpyinfo->name_list_element),
7375 !NILP (list = Fassoc (tpat, tem)))
7376 {
7377 list = Fcdr_safe (list);
7378 /* We have a cached list. Don't have to get the list again. */
7379 goto label_cached;
7380 }
7381
7382 BLOCK_INPUT;
7383 /* At first, put PATTERN in the cache. */
7384 list = Qnil;
7385 ef.pattern = &tpat;
7386 ef.list = list;
7387 ef.tail = &list;
7388 ef.numFonts = 0;
7389
7390 /* Use EnumFontFamiliesEx where it is available, as it knows
7391 about character sets. Fall back to EnumFontFamilies for
7392 older versions of NT that don't support the 'Ex function. */
7393 x_to_w32_font (XSTRING (tpat)->data, &ef.logfont);
7394 {
7395 LOGFONT font_match_pattern;
7396 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
7397 FARPROC enum_font_families_ex
7398 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
7399
7400 /* We do our own pattern matching so we can handle wildcards. */
7401 font_match_pattern.lfFaceName[0] = 0;
7402 font_match_pattern.lfPitchAndFamily = 0;
7403 /* We can use the charset, because if it is a wildcard it will
7404 be DEFAULT_CHARSET anyway. */
7405 font_match_pattern.lfCharSet = ef.logfont.lfCharSet;
7406
7407 ef.hdc = GetDC (dpyinfo->root_window);
7408
7409 if (enum_font_families_ex)
7410 enum_font_families_ex (ef.hdc,
7411 &font_match_pattern,
7412 (FONTENUMPROC) enum_fontex_cb1,
7413 (LPARAM) &ef, 0);
7414 else
7415 EnumFontFamilies (ef.hdc, NULL, (FONTENUMPROC) enum_font_cb1,
7416 (LPARAM)&ef);
7417
7418 ReleaseDC (dpyinfo->root_window, ef.hdc);
7419 }
7420
7421 UNBLOCK_INPUT;
7422
7423 /* Make a list of the fonts we got back.
7424 Store that in the font cache for the display. */
7425 XSETCDR (dpyinfo->name_list_element,
7426 Fcons (Fcons (tpat, list),
7427 XCDR (dpyinfo->name_list_element)));
7428
7429 label_cached:
7430 if (NILP (list)) continue; /* Try the remaining alternatives. */
7431
7432 newlist = second_best = Qnil;
7433
7434 /* Make a list of the fonts that have the right width. */
7435 for (; CONSP (list); list = XCDR (list))
7436 {
7437 int found_size;
7438 tem = XCAR (list);
7439
7440 if (!CONSP (tem))
7441 continue;
7442 if (NILP (XCAR (tem)))
7443 continue;
7444 if (!size)
7445 {
7446 newlist = Fcons (XCAR (tem), newlist);
7447 n_fonts++;
7448 if (n_fonts >= maxnames)
7449 break;
7450 else
7451 continue;
7452 }
7453 if (!INTEGERP (XCDR (tem)))
7454 {
7455 /* Since we don't yet know the size of the font, we must
7456 load it and try GetTextMetrics. */
7457 W32FontStruct thisinfo;
7458 LOGFONT lf;
7459 HDC hdc;
7460 HANDLE oldobj;
7461
7462 if (!x_to_w32_font (XSTRING (XCAR (tem))->data, &lf))
7463 continue;
7464
7465 BLOCK_INPUT;
7466 thisinfo.bdf = NULL;
7467 thisinfo.hfont = CreateFontIndirect (&lf);
7468 if (thisinfo.hfont == NULL)
7469 continue;
7470
7471 hdc = GetDC (dpyinfo->root_window);
7472 oldobj = SelectObject (hdc, thisinfo.hfont);
7473 if (GetTextMetrics (hdc, &thisinfo.tm))
7474 XSETCDR (tem, make_number (FONT_WIDTH (&thisinfo)));
7475 else
7476 XSETCDR (tem, make_number (0));
7477 SelectObject (hdc, oldobj);
7478 ReleaseDC (dpyinfo->root_window, hdc);
7479 DeleteObject(thisinfo.hfont);
7480 UNBLOCK_INPUT;
7481 }
7482 found_size = XINT (XCDR (tem));
7483 if (found_size == size)
7484 {
7485 newlist = Fcons (XCAR (tem), newlist);
7486 n_fonts++;
7487 if (n_fonts >= maxnames)
7488 break;
7489 }
7490 /* keep track of the closest matching size in case
7491 no exact match is found. */
7492 else if (found_size > 0)
7493 {
7494 if (NILP (second_best))
7495 second_best = tem;
7496
7497 else if (found_size < size)
7498 {
7499 if (XINT (XCDR (second_best)) > size
7500 || XINT (XCDR (second_best)) < found_size)
7501 second_best = tem;
7502 }
7503 else
7504 {
7505 if (XINT (XCDR (second_best)) > size
7506 && XINT (XCDR (second_best)) >
7507 found_size)
7508 second_best = tem;
7509 }
7510 }
7511 }
7512
7513 if (!NILP (newlist))
7514 break;
7515 else if (!NILP (second_best))
7516 {
7517 newlist = Fcons (XCAR (second_best), Qnil);
7518 break;
7519 }
7520 }
7521
7522 /* Include any bdf fonts. */
7523 if (n_fonts < maxnames)
7524 {
7525 Lisp_Object combined[2];
7526 combined[0] = w32_list_bdf_fonts (pattern, maxnames - n_fonts);
7527 combined[1] = newlist;
7528 newlist = Fnconc(2, combined);
7529 }
7530
7531 return newlist;
7532 }
7533
7534
7535 /* Return a pointer to struct font_info of font FONT_IDX of frame F. */
7536 struct font_info *
7537 w32_get_font_info (f, font_idx)
7538 FRAME_PTR f;
7539 int font_idx;
7540 {
7541 return (FRAME_W32_FONT_TABLE (f) + font_idx);
7542 }
7543
7544
7545 struct font_info*
7546 w32_query_font (struct frame *f, char *fontname)
7547 {
7548 int i;
7549 struct font_info *pfi;
7550
7551 pfi = FRAME_W32_FONT_TABLE (f);
7552
7553 for (i = 0; i < one_w32_display_info.n_fonts ;i++, pfi++)
7554 {
7555 if (strcmp(pfi->name, fontname) == 0) return pfi;
7556 }
7557
7558 return NULL;
7559 }
7560
7561 /* Find a CCL program for a font specified by FONTP, and set the member
7562 `encoder' of the structure. */
7563
7564 void
7565 w32_find_ccl_program (fontp)
7566 struct font_info *fontp;
7567 {
7568 Lisp_Object list, elt;
7569
7570 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
7571 {
7572 elt = XCAR (list);
7573 if (CONSP (elt)
7574 && STRINGP (XCAR (elt))
7575 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
7576 >= 0))
7577 break;
7578 }
7579 if (! NILP (list))
7580 {
7581 struct ccl_program *ccl
7582 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
7583
7584 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
7585 xfree (ccl);
7586 else
7587 fontp->font_encoder = ccl;
7588 }
7589 }
7590
7591 \f
7592 /* Find BDF files in a specified directory. (use GCPRO when calling,
7593 as this calls lisp to get a directory listing). */
7594 static Lisp_Object
7595 w32_find_bdf_fonts_in_dir (Lisp_Object directory)
7596 {
7597 Lisp_Object filelist, list = Qnil;
7598 char fontname[100];
7599
7600 if (!STRINGP(directory))
7601 return Qnil;
7602
7603 filelist = Fdirectory_files (directory, Qt,
7604 build_string (".*\\.[bB][dD][fF]"), Qt);
7605
7606 for ( ; CONSP(filelist); filelist = XCDR (filelist))
7607 {
7608 Lisp_Object filename = XCAR (filelist);
7609 if (w32_BDF_to_x_font (XSTRING (filename)->data, fontname, 100))
7610 store_in_alist (&list, build_string (fontname), filename);
7611 }
7612 return list;
7613 }
7614
7615 DEFUN ("w32-find-bdf-fonts", Fw32_find_bdf_fonts, Sw32_find_bdf_fonts,
7616 1, 1, 0,
7617 doc: /* Return a list of BDF fonts in DIR.
7618 The list is suitable for appending to w32-bdf-filename-alist. Fonts
7619 which do not contain an xlfd description will not be included in the
7620 list. DIR may be a list of directories. */)
7621 (directory)
7622 Lisp_Object directory;
7623 {
7624 Lisp_Object list = Qnil;
7625 struct gcpro gcpro1, gcpro2;
7626
7627 if (!CONSP (directory))
7628 return w32_find_bdf_fonts_in_dir (directory);
7629
7630 for ( ; CONSP (directory); directory = XCDR (directory))
7631 {
7632 Lisp_Object pair[2];
7633 pair[0] = list;
7634 pair[1] = Qnil;
7635 GCPRO2 (directory, list);
7636 pair[1] = w32_find_bdf_fonts_in_dir( XCAR (directory) );
7637 list = Fnconc( 2, pair );
7638 UNGCPRO;
7639 }
7640 return list;
7641 }
7642
7643 \f
7644 DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
7645 doc: /* Internal function called by `color-defined-p', which see. */)
7646 (color, frame)
7647 Lisp_Object color, frame;
7648 {
7649 XColor foo;
7650 FRAME_PTR f = check_x_frame (frame);
7651
7652 CHECK_STRING (color);
7653
7654 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
7655 return Qt;
7656 else
7657 return Qnil;
7658 }
7659
7660 DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
7661 doc: /* Internal function called by `color-values', which see. */)
7662 (color, frame)
7663 Lisp_Object color, frame;
7664 {
7665 XColor foo;
7666 FRAME_PTR f = check_x_frame (frame);
7667
7668 CHECK_STRING (color);
7669
7670 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
7671 {
7672 Lisp_Object rgb[3];
7673
7674 rgb[0] = make_number ((GetRValue (foo.pixel) << 8)
7675 | GetRValue (foo.pixel));
7676 rgb[1] = make_number ((GetGValue (foo.pixel) << 8)
7677 | GetGValue (foo.pixel));
7678 rgb[2] = make_number ((GetBValue (foo.pixel) << 8)
7679 | GetBValue (foo.pixel));
7680 return Flist (3, rgb);
7681 }
7682 else
7683 return Qnil;
7684 }
7685
7686 DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
7687 doc: /* Internal function called by `display-color-p', which see. */)
7688 (display)
7689 Lisp_Object display;
7690 {
7691 struct w32_display_info *dpyinfo = check_x_display_info (display);
7692
7693 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 2)
7694 return Qnil;
7695
7696 return Qt;
7697 }
7698
7699 DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p,
7700 Sx_display_grayscale_p, 0, 1, 0,
7701 doc: /* Return t if the X display supports shades of gray.
7702 Note that color displays do support shades of gray.
7703 The optional argument DISPLAY specifies which display to ask about.
7704 DISPLAY should be either a frame or a display name (a string).
7705 If omitted or nil, that stands for the selected frame's display. */)
7706 (display)
7707 Lisp_Object display;
7708 {
7709 struct w32_display_info *dpyinfo = check_x_display_info (display);
7710
7711 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 1)
7712 return Qnil;
7713
7714 return Qt;
7715 }
7716
7717 DEFUN ("x-display-pixel-width", Fx_display_pixel_width,
7718 Sx_display_pixel_width, 0, 1, 0,
7719 doc: /* Returns the width in pixels of DISPLAY.
7720 The optional argument DISPLAY specifies which display to ask about.
7721 DISPLAY should be either a frame or a display name (a string).
7722 If omitted or nil, that stands for the selected frame's display. */)
7723 (display)
7724 Lisp_Object display;
7725 {
7726 struct w32_display_info *dpyinfo = check_x_display_info (display);
7727
7728 return make_number (dpyinfo->width);
7729 }
7730
7731 DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
7732 Sx_display_pixel_height, 0, 1, 0,
7733 doc: /* Returns the height in pixels of DISPLAY.
7734 The optional argument DISPLAY specifies which display to ask about.
7735 DISPLAY should be either a frame or a display name (a string).
7736 If omitted or nil, that stands for the selected frame's display. */)
7737 (display)
7738 Lisp_Object display;
7739 {
7740 struct w32_display_info *dpyinfo = check_x_display_info (display);
7741
7742 return make_number (dpyinfo->height);
7743 }
7744
7745 DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
7746 0, 1, 0,
7747 doc: /* Returns the number of bitplanes of DISPLAY.
7748 The optional argument DISPLAY specifies which display to ask about.
7749 DISPLAY should be either a frame or a display name (a string).
7750 If omitted or nil, that stands for the selected frame's display. */)
7751 (display)
7752 Lisp_Object display;
7753 {
7754 struct w32_display_info *dpyinfo = check_x_display_info (display);
7755
7756 return make_number (dpyinfo->n_planes * dpyinfo->n_cbits);
7757 }
7758
7759 DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
7760 0, 1, 0,
7761 doc: /* Returns the number of color cells of DISPLAY.
7762 The optional argument DISPLAY specifies which display to ask about.
7763 DISPLAY should be either a frame or a display name (a string).
7764 If omitted or nil, that stands for the selected frame's display. */)
7765 (display)
7766 Lisp_Object display;
7767 {
7768 struct w32_display_info *dpyinfo = check_x_display_info (display);
7769 HDC hdc;
7770 int cap;
7771
7772 hdc = GetDC (dpyinfo->root_window);
7773 if (dpyinfo->has_palette)
7774 cap = GetDeviceCaps (hdc,SIZEPALETTE);
7775 else
7776 cap = GetDeviceCaps (hdc,NUMCOLORS);
7777
7778 /* We force 24+ bit depths to 24-bit, both to prevent an overflow
7779 and because probably is more meaningful on Windows anyway */
7780 if (cap < 0)
7781 cap = 1 << min(dpyinfo->n_planes * dpyinfo->n_cbits, 24);
7782
7783 ReleaseDC (dpyinfo->root_window, hdc);
7784
7785 return make_number (cap);
7786 }
7787
7788 DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
7789 Sx_server_max_request_size,
7790 0, 1, 0,
7791 doc: /* Returns the maximum request size of the server of DISPLAY.
7792 The optional argument DISPLAY specifies which display to ask about.
7793 DISPLAY should be either a frame or a display name (a string).
7794 If omitted or nil, that stands for the selected frame's display. */)
7795 (display)
7796 Lisp_Object display;
7797 {
7798 struct w32_display_info *dpyinfo = check_x_display_info (display);
7799
7800 return make_number (1);
7801 }
7802
7803 DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
7804 doc: /* Returns the vendor ID string of the W32 system (Microsoft).
7805 The optional argument DISPLAY specifies which display to ask about.
7806 DISPLAY should be either a frame or a display name (a string).
7807 If omitted or nil, that stands for the selected frame's display. */)
7808 (display)
7809 Lisp_Object display;
7810 {
7811 return build_string ("Microsoft Corp.");
7812 }
7813
7814 DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
7815 doc: /* Returns the version numbers of the server of DISPLAY.
7816 The value is a list of three integers: the major and minor
7817 version numbers, and the vendor-specific release
7818 number. See also the function `x-server-vendor'.
7819
7820 The optional argument DISPLAY specifies which display to ask about.
7821 DISPLAY should be either a frame or a display name (a string).
7822 If omitted or nil, that stands for the selected frame's display. */)
7823 (display)
7824 Lisp_Object display;
7825 {
7826 return Fcons (make_number (w32_major_version),
7827 Fcons (make_number (w32_minor_version),
7828 Fcons (make_number (w32_build_number), Qnil)));
7829 }
7830
7831 DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
7832 doc: /* Returns the number of screens on the server of DISPLAY.
7833 The optional argument DISPLAY specifies which display to ask about.
7834 DISPLAY should be either a frame or a display name (a string).
7835 If omitted or nil, that stands for the selected frame's display. */)
7836 (display)
7837 Lisp_Object display;
7838 {
7839 return make_number (1);
7840 }
7841
7842 DEFUN ("x-display-mm-height", Fx_display_mm_height,
7843 Sx_display_mm_height, 0, 1, 0,
7844 doc: /* Returns the height in millimeters of DISPLAY.
7845 The optional argument DISPLAY specifies which display to ask about.
7846 DISPLAY should be either a frame or a display name (a string).
7847 If omitted or nil, that stands for the selected frame's display. */)
7848 (display)
7849 Lisp_Object display;
7850 {
7851 struct w32_display_info *dpyinfo = check_x_display_info (display);
7852 HDC hdc;
7853 int cap;
7854
7855 hdc = GetDC (dpyinfo->root_window);
7856
7857 cap = GetDeviceCaps (hdc, VERTSIZE);
7858
7859 ReleaseDC (dpyinfo->root_window, hdc);
7860
7861 return make_number (cap);
7862 }
7863
7864 DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
7865 doc: /* Returns the width in millimeters of DISPLAY.
7866 The optional argument DISPLAY specifies which display to ask about.
7867 DISPLAY should be either a frame or a display name (a string).
7868 If omitted or nil, that stands for the selected frame's display. */)
7869 (display)
7870 Lisp_Object display;
7871 {
7872 struct w32_display_info *dpyinfo = check_x_display_info (display);
7873
7874 HDC hdc;
7875 int cap;
7876
7877 hdc = GetDC (dpyinfo->root_window);
7878
7879 cap = GetDeviceCaps (hdc, HORZSIZE);
7880
7881 ReleaseDC (dpyinfo->root_window, hdc);
7882
7883 return make_number (cap);
7884 }
7885
7886 DEFUN ("x-display-backing-store", Fx_display_backing_store,
7887 Sx_display_backing_store, 0, 1, 0,
7888 doc: /* Returns an indication of whether DISPLAY does backing store.
7889 The value may be `always', `when-mapped', or `not-useful'.
7890 The optional argument DISPLAY specifies which display to ask about.
7891 DISPLAY should be either a frame or a display name (a string).
7892 If omitted or nil, that stands for the selected frame's display. */)
7893 (display)
7894 Lisp_Object display;
7895 {
7896 return intern ("not-useful");
7897 }
7898
7899 DEFUN ("x-display-visual-class", Fx_display_visual_class,
7900 Sx_display_visual_class, 0, 1, 0,
7901 doc: /* Returns the visual class of DISPLAY.
7902 The value is one of the symbols `static-gray', `gray-scale',
7903 `static-color', `pseudo-color', `true-color', or `direct-color'.
7904
7905 The optional argument DISPLAY specifies which display to ask about.
7906 DISPLAY should be either a frame or a display name (a string).
7907 If omitted or nil, that stands for the selected frame's display. */)
7908 (display)
7909 Lisp_Object display;
7910 {
7911 struct w32_display_info *dpyinfo = check_x_display_info (display);
7912 Lisp_Object result = Qnil;
7913
7914 if (dpyinfo->has_palette)
7915 result = intern ("pseudo-color");
7916 else if (dpyinfo->n_planes * dpyinfo->n_cbits == 1)
7917 result = intern ("static-grey");
7918 else if (dpyinfo->n_planes * dpyinfo->n_cbits == 4)
7919 result = intern ("static-color");
7920 else if (dpyinfo->n_planes * dpyinfo->n_cbits > 8)
7921 result = intern ("true-color");
7922
7923 return result;
7924 }
7925
7926 DEFUN ("x-display-save-under", Fx_display_save_under,
7927 Sx_display_save_under, 0, 1, 0,
7928 doc: /* Returns t if DISPLAY supports the save-under feature.
7929 The optional argument DISPLAY specifies which display to ask about.
7930 DISPLAY should be either a frame or a display name (a string).
7931 If omitted or nil, that stands for the selected frame's display. */)
7932 (display)
7933 Lisp_Object display;
7934 {
7935 return Qnil;
7936 }
7937 \f
7938 int
7939 x_pixel_width (f)
7940 register struct frame *f;
7941 {
7942 return PIXEL_WIDTH (f);
7943 }
7944
7945 int
7946 x_pixel_height (f)
7947 register struct frame *f;
7948 {
7949 return PIXEL_HEIGHT (f);
7950 }
7951
7952 int
7953 x_char_width (f)
7954 register struct frame *f;
7955 {
7956 return FONT_WIDTH (f->output_data.w32->font);
7957 }
7958
7959 int
7960 x_char_height (f)
7961 register struct frame *f;
7962 {
7963 return f->output_data.w32->line_height;
7964 }
7965
7966 int
7967 x_screen_planes (f)
7968 register struct frame *f;
7969 {
7970 return FRAME_W32_DISPLAY_INFO (f)->n_planes;
7971 }
7972 \f
7973 /* Return the display structure for the display named NAME.
7974 Open a new connection if necessary. */
7975
7976 struct w32_display_info *
7977 x_display_info_for_name (name)
7978 Lisp_Object name;
7979 {
7980 Lisp_Object names;
7981 struct w32_display_info *dpyinfo;
7982
7983 CHECK_STRING (name);
7984
7985 for (dpyinfo = &one_w32_display_info, names = w32_display_name_list;
7986 dpyinfo;
7987 dpyinfo = dpyinfo->next, names = XCDR (names))
7988 {
7989 Lisp_Object tem;
7990 tem = Fstring_equal (XCAR (XCAR (names)), name);
7991 if (!NILP (tem))
7992 return dpyinfo;
7993 }
7994
7995 /* Use this general default value to start with. */
7996 Vx_resource_name = Vinvocation_name;
7997
7998 validate_x_resource_name ();
7999
8000 dpyinfo = w32_term_init (name, (unsigned char *)0,
8001 (char *) XSTRING (Vx_resource_name)->data);
8002
8003 if (dpyinfo == 0)
8004 error ("Cannot connect to server %s", XSTRING (name)->data);
8005
8006 w32_in_use = 1;
8007 XSETFASTINT (Vwindow_system_version, 3);
8008
8009 return dpyinfo;
8010 }
8011
8012 DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
8013 1, 3, 0, doc: /* Open a connection to a server.
8014 DISPLAY is the name of the display to connect to.
8015 Optional second arg XRM-STRING is a string of resources in xrdb format.
8016 If the optional third arg MUST-SUCCEED is non-nil,
8017 terminate Emacs if we can't open the connection. */)
8018 (display, xrm_string, must_succeed)
8019 Lisp_Object display, xrm_string, must_succeed;
8020 {
8021 unsigned char *xrm_option;
8022 struct w32_display_info *dpyinfo;
8023
8024 /* If initialization has already been done, return now to avoid
8025 overwriting critical parts of one_w32_display_info. */
8026 if (w32_in_use)
8027 return Qnil;
8028
8029 CHECK_STRING (display);
8030 if (! NILP (xrm_string))
8031 CHECK_STRING (xrm_string);
8032
8033 if (! EQ (Vwindow_system, intern ("w32")))
8034 error ("Not using Microsoft Windows");
8035
8036 /* Allow color mapping to be defined externally; first look in user's
8037 HOME directory, then in Emacs etc dir for a file called rgb.txt. */
8038 {
8039 Lisp_Object color_file;
8040 struct gcpro gcpro1;
8041
8042 color_file = build_string("~/rgb.txt");
8043
8044 GCPRO1 (color_file);
8045
8046 if (NILP (Ffile_readable_p (color_file)))
8047 color_file =
8048 Fexpand_file_name (build_string ("rgb.txt"),
8049 Fsymbol_value (intern ("data-directory")));
8050
8051 Vw32_color_map = Fw32_load_color_file (color_file);
8052
8053 UNGCPRO;
8054 }
8055 if (NILP (Vw32_color_map))
8056 Vw32_color_map = Fw32_default_color_map ();
8057
8058 if (! NILP (xrm_string))
8059 xrm_option = (unsigned char *) XSTRING (xrm_string)->data;
8060 else
8061 xrm_option = (unsigned char *) 0;
8062
8063 /* Use this general default value to start with. */
8064 /* First remove .exe suffix from invocation-name - it looks ugly. */
8065 {
8066 char basename[ MAX_PATH ], *str;
8067
8068 strcpy (basename, XSTRING (Vinvocation_name)->data);
8069 str = strrchr (basename, '.');
8070 if (str) *str = 0;
8071 Vinvocation_name = build_string (basename);
8072 }
8073 Vx_resource_name = Vinvocation_name;
8074
8075 validate_x_resource_name ();
8076
8077 /* This is what opens the connection and sets x_current_display.
8078 This also initializes many symbols, such as those used for input. */
8079 dpyinfo = w32_term_init (display, xrm_option,
8080 (char *) XSTRING (Vx_resource_name)->data);
8081
8082 if (dpyinfo == 0)
8083 {
8084 if (!NILP (must_succeed))
8085 fatal ("Cannot connect to server %s.\n",
8086 XSTRING (display)->data);
8087 else
8088 error ("Cannot connect to server %s", XSTRING (display)->data);
8089 }
8090
8091 w32_in_use = 1;
8092
8093 XSETFASTINT (Vwindow_system_version, 3);
8094 return Qnil;
8095 }
8096
8097 DEFUN ("x-close-connection", Fx_close_connection,
8098 Sx_close_connection, 1, 1, 0,
8099 doc: /* Close the connection to DISPLAY's server.
8100 For DISPLAY, specify either a frame or a display name (a string).
8101 If DISPLAY is nil, that stands for the selected frame's display. */)
8102 (display)
8103 Lisp_Object display;
8104 {
8105 struct w32_display_info *dpyinfo = check_x_display_info (display);
8106 int i;
8107
8108 if (dpyinfo->reference_count > 0)
8109 error ("Display still has frames on it");
8110
8111 BLOCK_INPUT;
8112 /* Free the fonts in the font table. */
8113 for (i = 0; i < dpyinfo->n_fonts; i++)
8114 if (dpyinfo->font_table[i].name)
8115 {
8116 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
8117 xfree (dpyinfo->font_table[i].full_name);
8118 xfree (dpyinfo->font_table[i].name);
8119 w32_unload_font (dpyinfo, dpyinfo->font_table[i].font);
8120 }
8121 x_destroy_all_bitmaps (dpyinfo);
8122
8123 x_delete_display (dpyinfo);
8124 UNBLOCK_INPUT;
8125
8126 return Qnil;
8127 }
8128
8129 DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
8130 doc: /* Return the list of display names that Emacs has connections to. */)
8131 ()
8132 {
8133 Lisp_Object tail, result;
8134
8135 result = Qnil;
8136 for (tail = w32_display_name_list; ! NILP (tail); tail = XCDR (tail))
8137 result = Fcons (XCAR (XCAR (tail)), result);
8138
8139 return result;
8140 }
8141
8142 DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0,
8143 doc: /* This is a noop on W32 systems. */)
8144 (on, display)
8145 Lisp_Object display, on;
8146 {
8147 return Qnil;
8148 }
8149
8150 \f
8151 /***********************************************************************
8152 Image types
8153 ***********************************************************************/
8154
8155 /* Value is the number of elements of vector VECTOR. */
8156
8157 #define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))
8158
8159 /* List of supported image types. Use define_image_type to add new
8160 types. Use lookup_image_type to find a type for a given symbol. */
8161
8162 static struct image_type *image_types;
8163
8164 /* The symbol `image' which is the car of the lists used to represent
8165 images in Lisp. */
8166
8167 extern Lisp_Object Qimage;
8168
8169 /* The symbol `xbm' which is used as the type symbol for XBM images. */
8170
8171 Lisp_Object Qxbm;
8172
8173 /* Keywords. */
8174
8175 extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
8176 extern Lisp_Object QCdata, QCtype;
8177 Lisp_Object QCascent, QCmargin, QCrelief;
8178 Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask;
8179 Lisp_Object QCindex, QCmatrix, QCcolor_adjustment, QCmask;
8180
8181 /* Other symbols. */
8182
8183 Lisp_Object Qlaplace, Qemboss, Qedge_detection, Qheuristic;
8184
8185 /* Time in seconds after which images should be removed from the cache
8186 if not displayed. */
8187
8188 Lisp_Object Vimage_cache_eviction_delay;
8189
8190 /* Function prototypes. */
8191
8192 static void define_image_type P_ ((struct image_type *type));
8193 static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
8194 static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
8195 static void x_laplace P_ ((struct frame *, struct image *));
8196 static void x_emboss P_ ((struct frame *, struct image *));
8197 static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
8198 Lisp_Object));
8199
8200
8201 /* Define a new image type from TYPE. This adds a copy of TYPE to
8202 image_types and adds the symbol *TYPE->type to Vimage_types. */
8203
8204 static void
8205 define_image_type (type)
8206 struct image_type *type;
8207 {
8208 /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
8209 The initialized data segment is read-only. */
8210 struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
8211 bcopy (type, p, sizeof *p);
8212 p->next = image_types;
8213 image_types = p;
8214 Vimage_types = Fcons (*p->type, Vimage_types);
8215 }
8216
8217
8218 /* Look up image type SYMBOL, and return a pointer to its image_type
8219 structure. Value is null if SYMBOL is not a known image type. */
8220
8221 static INLINE struct image_type *
8222 lookup_image_type (symbol)
8223 Lisp_Object symbol;
8224 {
8225 struct image_type *type;
8226
8227 for (type = image_types; type; type = type->next)
8228 if (EQ (symbol, *type->type))
8229 break;
8230
8231 return type;
8232 }
8233
8234
8235 /* Value is non-zero if OBJECT is a valid Lisp image specification. A
8236 valid image specification is a list whose car is the symbol
8237 `image', and whose rest is a property list. The property list must
8238 contain a value for key `:type'. That value must be the name of a
8239 supported image type. The rest of the property list depends on the
8240 image type. */
8241
8242 int
8243 valid_image_p (object)
8244 Lisp_Object object;
8245 {
8246 int valid_p = 0;
8247
8248 if (CONSP (object) && EQ (XCAR (object), Qimage))
8249 {
8250 Lisp_Object tem;
8251
8252 for (tem = XCDR (object); CONSP (tem); tem = XCDR (tem))
8253 if (EQ (XCAR (tem), QCtype))
8254 {
8255 tem = XCDR (tem);
8256 if (CONSP (tem) && SYMBOLP (XCAR (tem)))
8257 {
8258 struct image_type *type;
8259 type = lookup_image_type (XCAR (tem));
8260 if (type)
8261 valid_p = type->valid_p (object);
8262 }
8263
8264 break;
8265 }
8266 }
8267
8268 return valid_p;
8269 }
8270
8271
8272 /* Log error message with format string FORMAT and argument ARG.
8273 Signaling an error, e.g. when an image cannot be loaded, is not a
8274 good idea because this would interrupt redisplay, and the error
8275 message display would lead to another redisplay. This function
8276 therefore simply displays a message. */
8277
8278 static void
8279 image_error (format, arg1, arg2)
8280 char *format;
8281 Lisp_Object arg1, arg2;
8282 {
8283 add_to_log (format, arg1, arg2);
8284 }
8285
8286
8287 \f
8288 /***********************************************************************
8289 Image specifications
8290 ***********************************************************************/
8291
8292 enum image_value_type
8293 {
8294 IMAGE_DONT_CHECK_VALUE_TYPE,
8295 IMAGE_STRING_VALUE,
8296 IMAGE_STRING_OR_NIL_VALUE,
8297 IMAGE_SYMBOL_VALUE,
8298 IMAGE_POSITIVE_INTEGER_VALUE,
8299 IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,
8300 IMAGE_NON_NEGATIVE_INTEGER_VALUE,
8301 IMAGE_ASCENT_VALUE,
8302 IMAGE_INTEGER_VALUE,
8303 IMAGE_FUNCTION_VALUE,
8304 IMAGE_NUMBER_VALUE,
8305 IMAGE_BOOL_VALUE
8306 };
8307
8308 /* Structure used when parsing image specifications. */
8309
8310 struct image_keyword
8311 {
8312 /* Name of keyword. */
8313 char *name;
8314
8315 /* The type of value allowed. */
8316 enum image_value_type type;
8317
8318 /* Non-zero means key must be present. */
8319 int mandatory_p;
8320
8321 /* Used to recognize duplicate keywords in a property list. */
8322 int count;
8323
8324 /* The value that was found. */
8325 Lisp_Object value;
8326 };
8327
8328
8329 static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
8330 int, Lisp_Object));
8331 static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
8332
8333
8334 /* Parse image spec SPEC according to KEYWORDS. A valid image spec
8335 has the format (image KEYWORD VALUE ...). One of the keyword/
8336 value pairs must be `:type TYPE'. KEYWORDS is a vector of
8337 image_keywords structures of size NKEYWORDS describing other
8338 allowed keyword/value pairs. Value is non-zero if SPEC is valid. */
8339
8340 static int
8341 parse_image_spec (spec, keywords, nkeywords, type)
8342 Lisp_Object spec;
8343 struct image_keyword *keywords;
8344 int nkeywords;
8345 Lisp_Object type;
8346 {
8347 int i;
8348 Lisp_Object plist;
8349
8350 if (!CONSP (spec) || !EQ (XCAR (spec), Qimage))
8351 return 0;
8352
8353 plist = XCDR (spec);
8354 while (CONSP (plist))
8355 {
8356 Lisp_Object key, value;
8357
8358 /* First element of a pair must be a symbol. */
8359 key = XCAR (plist);
8360 plist = XCDR (plist);
8361 if (!SYMBOLP (key))
8362 return 0;
8363
8364 /* There must follow a value. */
8365 if (!CONSP (plist))
8366 return 0;
8367 value = XCAR (plist);
8368 plist = XCDR (plist);
8369
8370 /* Find key in KEYWORDS. Error if not found. */
8371 for (i = 0; i < nkeywords; ++i)
8372 if (strcmp (keywords[i].name, XSYMBOL (key)->name->data) == 0)
8373 break;
8374
8375 if (i == nkeywords)
8376 continue;
8377
8378 /* Record that we recognized the keyword. If a keywords
8379 was found more than once, it's an error. */
8380 keywords[i].value = value;
8381 ++keywords[i].count;
8382
8383 if (keywords[i].count > 1)
8384 return 0;
8385
8386 /* Check type of value against allowed type. */
8387 switch (keywords[i].type)
8388 {
8389 case IMAGE_STRING_VALUE:
8390 if (!STRINGP (value))
8391 return 0;
8392 break;
8393
8394 case IMAGE_STRING_OR_NIL_VALUE:
8395 if (!STRINGP (value) && !NILP (value))
8396 return 0;
8397 break;
8398
8399 case IMAGE_SYMBOL_VALUE:
8400 if (!SYMBOLP (value))
8401 return 0;
8402 break;
8403
8404 case IMAGE_POSITIVE_INTEGER_VALUE:
8405 if (!INTEGERP (value) || XINT (value) <= 0)
8406 return 0;
8407 break;
8408
8409 case IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR:
8410 if (INTEGERP (value) && XINT (value) >= 0)
8411 break;
8412 if (CONSP (value)
8413 && INTEGERP (XCAR (value)) && INTEGERP (XCDR (value))
8414 && XINT (XCAR (value)) >= 0 && XINT (XCDR (value)) >= 0)
8415 break;
8416 return 0;
8417
8418 case IMAGE_ASCENT_VALUE:
8419 if (SYMBOLP (value) && EQ (value, Qcenter))
8420 break;
8421 else if (INTEGERP (value)
8422 && XINT (value) >= 0
8423 && XINT (value) <= 100)
8424 break;
8425 return 0;
8426
8427 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
8428 if (!INTEGERP (value) || XINT (value) < 0)
8429 return 0;
8430 break;
8431
8432 case IMAGE_DONT_CHECK_VALUE_TYPE:
8433 break;
8434
8435 case IMAGE_FUNCTION_VALUE:
8436 value = indirect_function (value);
8437 if (SUBRP (value)
8438 || COMPILEDP (value)
8439 || (CONSP (value) && EQ (XCAR (value), Qlambda)))
8440 break;
8441 return 0;
8442
8443 case IMAGE_NUMBER_VALUE:
8444 if (!INTEGERP (value) && !FLOATP (value))
8445 return 0;
8446 break;
8447
8448 case IMAGE_INTEGER_VALUE:
8449 if (!INTEGERP (value))
8450 return 0;
8451 break;
8452
8453 case IMAGE_BOOL_VALUE:
8454 if (!NILP (value) && !EQ (value, Qt))
8455 return 0;
8456 break;
8457
8458 default:
8459 abort ();
8460 break;
8461 }
8462
8463 if (EQ (key, QCtype) && !EQ (type, value))
8464 return 0;
8465 }
8466
8467 /* Check that all mandatory fields are present. */
8468 for (i = 0; i < nkeywords; ++i)
8469 if (keywords[i].mandatory_p && keywords[i].count == 0)
8470 return 0;
8471
8472 return NILP (plist);
8473 }
8474
8475
8476 /* Return the value of KEY in image specification SPEC. Value is nil
8477 if KEY is not present in SPEC. if FOUND is not null, set *FOUND
8478 to 1 if KEY was found in SPEC, set it to 0 otherwise. */
8479
8480 static Lisp_Object
8481 image_spec_value (spec, key, found)
8482 Lisp_Object spec, key;
8483 int *found;
8484 {
8485 Lisp_Object tail;
8486
8487 xassert (valid_image_p (spec));
8488
8489 for (tail = XCDR (spec);
8490 CONSP (tail) && CONSP (XCDR (tail));
8491 tail = XCDR (XCDR (tail)))
8492 {
8493 if (EQ (XCAR (tail), key))
8494 {
8495 if (found)
8496 *found = 1;
8497 return XCAR (XCDR (tail));
8498 }
8499 }
8500
8501 if (found)
8502 *found = 0;
8503 return Qnil;
8504 }
8505
8506
8507 #ifdef HAVE_IMAGES
8508 DEFUN ("image-size", Fimage_size, Simage_size, 1, 3, 0,
8509 doc: /* Return the size of image SPEC as pair (WIDTH . HEIGHT).
8510 PIXELS non-nil means return the size in pixels, otherwise return the
8511 size in canonical character units.
8512 FRAME is the frame on which the image will be displayed. FRAME nil
8513 or omitted means use the selected frame. */)
8514 (spec, pixels, frame)
8515 Lisp_Object spec, pixels, frame;
8516 {
8517 Lisp_Object size;
8518
8519 size = Qnil;
8520 if (valid_image_p (spec))
8521 {
8522 struct frame *f = check_x_frame (frame);
8523 int id = lookup_image (f, spec);
8524 struct image *img = IMAGE_FROM_ID (f, id);
8525 int width = img->width + 2 * img->hmargin;
8526 int height = img->height + 2 * img->vmargin;
8527
8528 if (NILP (pixels))
8529 size = Fcons (make_float ((double) width / CANON_X_UNIT (f)),
8530 make_float ((double) height / CANON_Y_UNIT (f)));
8531 else
8532 size = Fcons (make_number (width), make_number (height));
8533 }
8534 else
8535 error ("Invalid image specification");
8536
8537 return size;
8538 }
8539
8540
8541 DEFUN ("image-mask-p", Fimage_mask_p, Simage_mask_p, 1, 2, 0,
8542 doc: /* Return t if image SPEC has a mask bitmap.
8543 FRAME is the frame on which the image will be displayed. FRAME nil
8544 or omitted means use the selected frame. */)
8545 (spec, frame)
8546 Lisp_Object spec, frame;
8547 {
8548 Lisp_Object mask;
8549
8550 mask = Qnil;
8551 if (valid_image_p (spec))
8552 {
8553 struct frame *f = check_x_frame (frame);
8554 int id = lookup_image (f, spec);
8555 struct image *img = IMAGE_FROM_ID (f, id);
8556 if (img->mask)
8557 mask = Qt;
8558 }
8559 else
8560 error ("Invalid image specification");
8561
8562 return mask;
8563 }
8564 #endif
8565
8566 \f
8567 /***********************************************************************
8568 Image type independent image structures
8569 ***********************************************************************/
8570
8571 static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
8572 static void free_image P_ ((struct frame *f, struct image *img));
8573
8574
8575 /* Allocate and return a new image structure for image specification
8576 SPEC. SPEC has a hash value of HASH. */
8577
8578 static struct image *
8579 make_image (spec, hash)
8580 Lisp_Object spec;
8581 unsigned hash;
8582 {
8583 struct image *img = (struct image *) xmalloc (sizeof *img);
8584
8585 xassert (valid_image_p (spec));
8586 bzero (img, sizeof *img);
8587 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
8588 xassert (img->type != NULL);
8589 img->spec = spec;
8590 img->data.lisp_val = Qnil;
8591 img->ascent = DEFAULT_IMAGE_ASCENT;
8592 img->hash = hash;
8593 return img;
8594 }
8595
8596
8597 /* Free image IMG which was used on frame F, including its resources. */
8598
8599 static void
8600 free_image (f, img)
8601 struct frame *f;
8602 struct image *img;
8603 {
8604 if (img)
8605 {
8606 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8607
8608 /* Remove IMG from the hash table of its cache. */
8609 if (img->prev)
8610 img->prev->next = img->next;
8611 else
8612 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
8613
8614 if (img->next)
8615 img->next->prev = img->prev;
8616
8617 c->images[img->id] = NULL;
8618
8619 /* Free resources, then free IMG. */
8620 img->type->free (f, img);
8621 xfree (img);
8622 }
8623 }
8624
8625
8626 /* Prepare image IMG for display on frame F. Must be called before
8627 drawing an image. */
8628
8629 void
8630 prepare_image_for_display (f, img)
8631 struct frame *f;
8632 struct image *img;
8633 {
8634 EMACS_TIME t;
8635
8636 /* We're about to display IMG, so set its timestamp to `now'. */
8637 EMACS_GET_TIME (t);
8638 img->timestamp = EMACS_SECS (t);
8639
8640 /* If IMG doesn't have a pixmap yet, load it now, using the image
8641 type dependent loader function. */
8642 if (img->pixmap == 0 && !img->load_failed_p)
8643 img->load_failed_p = img->type->load (f, img) == 0;
8644 }
8645
8646
8647 /* Value is the number of pixels for the ascent of image IMG when
8648 drawn in face FACE. */
8649
8650 int
8651 image_ascent (img, face)
8652 struct image *img;
8653 struct face *face;
8654 {
8655 int height = img->height + img->vmargin;
8656 int ascent;
8657
8658 if (img->ascent == CENTERED_IMAGE_ASCENT)
8659 {
8660 if (face->font)
8661 ascent = height / 2 - (FONT_DESCENT(face->font)
8662 - FONT_BASE(face->font)) / 2;
8663 else
8664 ascent = height / 2;
8665 }
8666 else
8667 ascent = (int) (height * img->ascent / 100.0);
8668
8669 return ascent;
8670 }
8671
8672
8673 \f
8674 /* Image background colors. */
8675
8676 /* Find the "best" corner color of a bitmap. XIMG is assumed to a device
8677 context with the bitmap selected. */
8678 static COLORREF
8679 four_corners_best (ximg, width, height)
8680 HDC ximg;
8681 unsigned long width, height;
8682 {
8683 COLORREF corners[4], best;
8684 int i, best_count;
8685
8686 /* Get the colors at the corners of ximg. */
8687 corners[0] = GetPixel (ximg, 0, 0);
8688 corners[1] = GetPixel (ximg, width - 1, 0);
8689 corners[2] = GetPixel (ximg, width - 1, height - 1);
8690 corners[3] = GetPixel (ximg, 0, height - 1);
8691
8692 /* Choose the most frequently found color as background. */
8693 for (i = best_count = 0; i < 4; ++i)
8694 {
8695 int j, n;
8696
8697 for (j = n = 0; j < 4; ++j)
8698 if (corners[i] == corners[j])
8699 ++n;
8700
8701 if (n > best_count)
8702 best = corners[i], best_count = n;
8703 }
8704
8705 return best;
8706 }
8707
8708 /* Return the `background' field of IMG. If IMG doesn't have one yet,
8709 it is guessed heuristically. If non-zero, XIMG is an existing XImage
8710 object to use for the heuristic. */
8711
8712 unsigned long
8713 image_background (img, f, ximg)
8714 struct image *img;
8715 struct frame *f;
8716 XImage *ximg;
8717 {
8718 if (! img->background_valid)
8719 /* IMG doesn't have a background yet, try to guess a reasonable value. */
8720 {
8721 #if 0 /* TODO: Image support. */
8722 int free_ximg = !ximg;
8723
8724 if (! ximg)
8725 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
8726 0, 0, img->width, img->height, ~0, ZPixmap);
8727
8728 img->background = four_corners_best (ximg, img->width, img->height);
8729
8730 if (free_ximg)
8731 XDestroyImage (ximg);
8732
8733 img->background_valid = 1;
8734 #endif
8735 }
8736
8737 return img->background;
8738 }
8739
8740 /* Return the `background_transparent' field of IMG. If IMG doesn't
8741 have one yet, it is guessed heuristically. If non-zero, MASK is an
8742 existing XImage object to use for the heuristic. */
8743
8744 int
8745 image_background_transparent (img, f, mask)
8746 struct image *img;
8747 struct frame *f;
8748 XImage *mask;
8749 {
8750 if (! img->background_transparent_valid)
8751 /* IMG doesn't have a background yet, try to guess a reasonable value. */
8752 {
8753 #if 0 /* TODO: Image support. */
8754 if (img->mask)
8755 {
8756 int free_mask = !mask;
8757
8758 if (! mask)
8759 mask = XGetImage (FRAME_X_DISPLAY (f), img->mask,
8760 0, 0, img->width, img->height, ~0, ZPixmap);
8761
8762 img->background_transparent
8763 = !four_corners_best (mask, img->width, img->height);
8764
8765 if (free_mask)
8766 XDestroyImage (mask);
8767 }
8768 else
8769 #endif
8770 img->background_transparent = 0;
8771
8772 img->background_transparent_valid = 1;
8773 }
8774
8775 return img->background_transparent;
8776 }
8777
8778 \f
8779 /***********************************************************************
8780 Helper functions for X image types
8781 ***********************************************************************/
8782
8783 static void x_clear_image_1 P_ ((struct frame *, struct image *, int,
8784 int, int));
8785 static void x_clear_image P_ ((struct frame *f, struct image *img));
8786 static unsigned long x_alloc_image_color P_ ((struct frame *f,
8787 struct image *img,
8788 Lisp_Object color_name,
8789 unsigned long dflt));
8790
8791
8792 /* Clear X resources of image IMG on frame F. PIXMAP_P non-zero means
8793 free the pixmap if any. MASK_P non-zero means clear the mask
8794 pixmap if any. COLORS_P non-zero means free colors allocated for
8795 the image, if any. */
8796
8797 static void
8798 x_clear_image_1 (f, img, pixmap_p, mask_p, colors_p)
8799 struct frame *f;
8800 struct image *img;
8801 int pixmap_p, mask_p, colors_p;
8802 {
8803 if (pixmap_p && img->pixmap)
8804 {
8805 DeleteObject (img->pixmap);
8806 img->pixmap = NULL;
8807 img->background_valid = 0;
8808 }
8809
8810 if (mask_p && img->mask)
8811 {
8812 DeleteObject (img->mask);
8813 img->mask = NULL;
8814 img->background_transparent_valid = 0;
8815 }
8816
8817 if (colors_p && img->ncolors)
8818 {
8819 #if 0 /* TODO: color table support. */
8820 x_free_colors (f, img->colors, img->ncolors);
8821 #endif
8822 xfree (img->colors);
8823 img->colors = NULL;
8824 img->ncolors = 0;
8825 }
8826 }
8827
8828 /* Free X resources of image IMG which is used on frame F. */
8829
8830 static void
8831 x_clear_image (f, img)
8832 struct frame *f;
8833 struct image *img;
8834 {
8835 if (img->pixmap)
8836 {
8837 BLOCK_INPUT;
8838 DeleteObject (img->pixmap);
8839 img->pixmap = 0;
8840 UNBLOCK_INPUT;
8841 }
8842
8843 if (img->ncolors)
8844 {
8845 #if 0 /* TODO: color table support */
8846
8847 int class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
8848
8849 /* If display has an immutable color map, freeing colors is not
8850 necessary and some servers don't allow it. So don't do it. */
8851 if (class != StaticColor
8852 && class != StaticGray
8853 && class != TrueColor)
8854 {
8855 Colormap cmap;
8856 BLOCK_INPUT;
8857 cmap = DefaultColormapOfScreen (FRAME_W32_DISPLAY_INFO (f)->screen);
8858 XFreeColors (FRAME_W32_DISPLAY (f), cmap, img->colors,
8859 img->ncolors, 0);
8860 UNBLOCK_INPUT;
8861 }
8862 #endif
8863
8864 xfree (img->colors);
8865 img->colors = NULL;
8866 img->ncolors = 0;
8867 }
8868 }
8869
8870
8871 /* Allocate color COLOR_NAME for image IMG on frame F. If color
8872 cannot be allocated, use DFLT. Add a newly allocated color to
8873 IMG->colors, so that it can be freed again. Value is the pixel
8874 color. */
8875
8876 static unsigned long
8877 x_alloc_image_color (f, img, color_name, dflt)
8878 struct frame *f;
8879 struct image *img;
8880 Lisp_Object color_name;
8881 unsigned long dflt;
8882 {
8883 XColor color;
8884 unsigned long result;
8885
8886 xassert (STRINGP (color_name));
8887
8888 if (w32_defined_color (f, XSTRING (color_name)->data, &color, 1))
8889 {
8890 /* This isn't called frequently so we get away with simply
8891 reallocating the color vector to the needed size, here. */
8892 ++img->ncolors;
8893 img->colors =
8894 (unsigned long *) xrealloc (img->colors,
8895 img->ncolors * sizeof *img->colors);
8896 img->colors[img->ncolors - 1] = color.pixel;
8897 result = color.pixel;
8898 }
8899 else
8900 result = dflt;
8901 return result;
8902 }
8903
8904
8905 \f
8906 /***********************************************************************
8907 Image Cache
8908 ***********************************************************************/
8909
8910 static void cache_image P_ ((struct frame *f, struct image *img));
8911 static void postprocess_image P_ ((struct frame *, struct image *));
8912
8913
8914 /* Return a new, initialized image cache that is allocated from the
8915 heap. Call free_image_cache to free an image cache. */
8916
8917 struct image_cache *
8918 make_image_cache ()
8919 {
8920 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
8921 int size;
8922
8923 bzero (c, sizeof *c);
8924 c->size = 50;
8925 c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
8926 size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
8927 c->buckets = (struct image **) xmalloc (size);
8928 bzero (c->buckets, size);
8929 return c;
8930 }
8931
8932
8933 /* Free image cache of frame F. Be aware that X frames share images
8934 caches. */
8935
8936 void
8937 free_image_cache (f)
8938 struct frame *f;
8939 {
8940 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8941 if (c)
8942 {
8943 int i;
8944
8945 /* Cache should not be referenced by any frame when freed. */
8946 xassert (c->refcount == 0);
8947
8948 for (i = 0; i < c->used; ++i)
8949 free_image (f, c->images[i]);
8950 xfree (c->images);
8951 xfree (c);
8952 xfree (c->buckets);
8953 FRAME_X_IMAGE_CACHE (f) = NULL;
8954 }
8955 }
8956
8957
8958 /* Clear image cache of frame F. FORCE_P non-zero means free all
8959 images. FORCE_P zero means clear only images that haven't been
8960 displayed for some time. Should be called from time to time to
8961 reduce the number of loaded images. If image-eviction-seconds is
8962 non-nil, this frees images in the cache which weren't displayed for
8963 at least that many seconds. */
8964
8965 void
8966 clear_image_cache (f, force_p)
8967 struct frame *f;
8968 int force_p;
8969 {
8970 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8971
8972 if (c && INTEGERP (Vimage_cache_eviction_delay))
8973 {
8974 EMACS_TIME t;
8975 unsigned long old;
8976 int i, nfreed;
8977
8978 EMACS_GET_TIME (t);
8979 old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
8980
8981 /* Block input so that we won't be interrupted by a SIGIO
8982 while being in an inconsistent state. */
8983 BLOCK_INPUT;
8984
8985 for (i = nfreed = 0; i < c->used; ++i)
8986 {
8987 struct image *img = c->images[i];
8988 if (img != NULL
8989 && (force_p || (img->timestamp < old)))
8990 {
8991 free_image (f, img);
8992 ++nfreed;
8993 }
8994 }
8995
8996 /* We may be clearing the image cache because, for example,
8997 Emacs was iconified for a longer period of time. In that
8998 case, current matrices may still contain references to
8999 images freed above. So, clear these matrices. */
9000 if (nfreed)
9001 {
9002 Lisp_Object tail, frame;
9003
9004 FOR_EACH_FRAME (tail, frame)
9005 {
9006 struct frame *f = XFRAME (frame);
9007 if (FRAME_W32_P (f)
9008 && FRAME_X_IMAGE_CACHE (f) == c)
9009 clear_current_matrices (f);
9010 }
9011
9012 ++windows_or_buffers_changed;
9013 }
9014
9015 UNBLOCK_INPUT;
9016 }
9017 }
9018
9019
9020 DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
9021 0, 1, 0,
9022 doc: /* Clear the image cache of FRAME.
9023 FRAME nil or omitted means use the selected frame.
9024 FRAME t means clear the image caches of all frames. */)
9025 (frame)
9026 Lisp_Object frame;
9027 {
9028 if (EQ (frame, Qt))
9029 {
9030 Lisp_Object tail;
9031
9032 FOR_EACH_FRAME (tail, frame)
9033 if (FRAME_W32_P (XFRAME (frame)))
9034 clear_image_cache (XFRAME (frame), 1);
9035 }
9036 else
9037 clear_image_cache (check_x_frame (frame), 1);
9038
9039 return Qnil;
9040 }
9041
9042
9043 /* Compute masks and transform image IMG on frame F, as specified
9044 by the image's specification, */
9045
9046 static void
9047 postprocess_image (f, img)
9048 struct frame *f;
9049 struct image *img;
9050 {
9051 #if 0 /* TODO: image support. */
9052 /* Manipulation of the image's mask. */
9053 if (img->pixmap)
9054 {
9055 Lisp_Object conversion, spec;
9056 Lisp_Object mask;
9057
9058 spec = img->spec;
9059
9060 /* `:heuristic-mask t'
9061 `:mask heuristic'
9062 means build a mask heuristically.
9063 `:heuristic-mask (R G B)'
9064 `:mask (heuristic (R G B))'
9065 means build a mask from color (R G B) in the
9066 image.
9067 `:mask nil'
9068 means remove a mask, if any. */
9069
9070 mask = image_spec_value (spec, QCheuristic_mask, NULL);
9071 if (!NILP (mask))
9072 x_build_heuristic_mask (f, img, mask);
9073 else
9074 {
9075 int found_p;
9076
9077 mask = image_spec_value (spec, QCmask, &found_p);
9078
9079 if (EQ (mask, Qheuristic))
9080 x_build_heuristic_mask (f, img, Qt);
9081 else if (CONSP (mask)
9082 && EQ (XCAR (mask), Qheuristic))
9083 {
9084 if (CONSP (XCDR (mask)))
9085 x_build_heuristic_mask (f, img, XCAR (XCDR (mask)));
9086 else
9087 x_build_heuristic_mask (f, img, XCDR (mask));
9088 }
9089 else if (NILP (mask) && found_p && img->mask)
9090 {
9091 DeleteObject (img->mask);
9092 img->mask = NULL;
9093 }
9094 }
9095
9096
9097 /* Should we apply an image transformation algorithm? */
9098 conversion = image_spec_value (spec, QCconversion, NULL);
9099 if (EQ (conversion, Qdisabled))
9100 x_disable_image (f, img);
9101 else if (EQ (conversion, Qlaplace))
9102 x_laplace (f, img);
9103 else if (EQ (conversion, Qemboss))
9104 x_emboss (f, img);
9105 else if (CONSP (conversion)
9106 && EQ (XCAR (conversion), Qedge_detection))
9107 {
9108 Lisp_Object tem;
9109 tem = XCDR (conversion);
9110 if (CONSP (tem))
9111 x_edge_detection (f, img,
9112 Fplist_get (tem, QCmatrix),
9113 Fplist_get (tem, QCcolor_adjustment));
9114 }
9115 }
9116 #endif
9117 }
9118
9119
9120 /* Return the id of image with Lisp specification SPEC on frame F.
9121 SPEC must be a valid Lisp image specification (see valid_image_p). */
9122
9123 int
9124 lookup_image (f, spec)
9125 struct frame *f;
9126 Lisp_Object spec;
9127 {
9128 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
9129 struct image *img;
9130 int i;
9131 unsigned hash;
9132 struct gcpro gcpro1;
9133 EMACS_TIME now;
9134
9135 /* F must be a window-system frame, and SPEC must be a valid image
9136 specification. */
9137 xassert (FRAME_WINDOW_P (f));
9138 xassert (valid_image_p (spec));
9139
9140 GCPRO1 (spec);
9141
9142 /* Look up SPEC in the hash table of the image cache. */
9143 hash = sxhash (spec, 0);
9144 i = hash % IMAGE_CACHE_BUCKETS_SIZE;
9145
9146 for (img = c->buckets[i]; img; img = img->next)
9147 if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
9148 break;
9149
9150 /* If not found, create a new image and cache it. */
9151 if (img == NULL)
9152 {
9153 extern Lisp_Object Qpostscript;
9154
9155 BLOCK_INPUT;
9156 img = make_image (spec, hash);
9157 cache_image (f, img);
9158 img->load_failed_p = img->type->load (f, img) == 0;
9159
9160 /* If we can't load the image, and we don't have a width and
9161 height, use some arbitrary width and height so that we can
9162 draw a rectangle for it. */
9163 if (img->load_failed_p)
9164 {
9165 Lisp_Object value;
9166
9167 value = image_spec_value (spec, QCwidth, NULL);
9168 img->width = (INTEGERP (value)
9169 ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH);
9170 value = image_spec_value (spec, QCheight, NULL);
9171 img->height = (INTEGERP (value)
9172 ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT);
9173 }
9174 else
9175 {
9176 /* Handle image type independent image attributes
9177 `:ascent PERCENT', `:margin MARGIN', `:relief RELIEF',
9178 `:background COLOR'. */
9179 Lisp_Object ascent, margin, relief, bg;
9180
9181 ascent = image_spec_value (spec, QCascent, NULL);
9182 if (INTEGERP (ascent))
9183 img->ascent = XFASTINT (ascent);
9184 else if (EQ (ascent, Qcenter))
9185 img->ascent = CENTERED_IMAGE_ASCENT;
9186
9187 margin = image_spec_value (spec, QCmargin, NULL);
9188 if (INTEGERP (margin) && XINT (margin) >= 0)
9189 img->vmargin = img->hmargin = XFASTINT (margin);
9190 else if (CONSP (margin) && INTEGERP (XCAR (margin))
9191 && INTEGERP (XCDR (margin)))
9192 {
9193 if (XINT (XCAR (margin)) > 0)
9194 img->hmargin = XFASTINT (XCAR (margin));
9195 if (XINT (XCDR (margin)) > 0)
9196 img->vmargin = XFASTINT (XCDR (margin));
9197 }
9198
9199 relief = image_spec_value (spec, QCrelief, NULL);
9200 if (INTEGERP (relief))
9201 {
9202 img->relief = XINT (relief);
9203 img->hmargin += abs (img->relief);
9204 img->vmargin += abs (img->relief);
9205 }
9206
9207 if (! img->background_valid)
9208 {
9209 bg = image_spec_value (img->spec, QCbackground, NULL);
9210 if (!NILP (bg))
9211 {
9212 img->background
9213 = x_alloc_image_color (f, img, bg,
9214 FRAME_BACKGROUND_PIXEL (f));
9215 img->background_valid = 1;
9216 }
9217 }
9218
9219 /* Do image transformations and compute masks, unless we
9220 don't have the image yet. */
9221 if (!EQ (*img->type->type, Qpostscript))
9222 postprocess_image (f, img);
9223 }
9224
9225 UNBLOCK_INPUT;
9226 xassert (!interrupt_input_blocked);
9227 }
9228
9229 /* We're using IMG, so set its timestamp to `now'. */
9230 EMACS_GET_TIME (now);
9231 img->timestamp = EMACS_SECS (now);
9232
9233 UNGCPRO;
9234
9235 /* Value is the image id. */
9236 return img->id;
9237 }
9238
9239
9240 /* Cache image IMG in the image cache of frame F. */
9241
9242 static void
9243 cache_image (f, img)
9244 struct frame *f;
9245 struct image *img;
9246 {
9247 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
9248 int i;
9249
9250 /* Find a free slot in c->images. */
9251 for (i = 0; i < c->used; ++i)
9252 if (c->images[i] == NULL)
9253 break;
9254
9255 /* If no free slot found, maybe enlarge c->images. */
9256 if (i == c->used && c->used == c->size)
9257 {
9258 c->size *= 2;
9259 c->images = (struct image **) xrealloc (c->images,
9260 c->size * sizeof *c->images);
9261 }
9262
9263 /* Add IMG to c->images, and assign IMG an id. */
9264 c->images[i] = img;
9265 img->id = i;
9266 if (i == c->used)
9267 ++c->used;
9268
9269 /* Add IMG to the cache's hash table. */
9270 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
9271 img->next = c->buckets[i];
9272 if (img->next)
9273 img->next->prev = img;
9274 img->prev = NULL;
9275 c->buckets[i] = img;
9276 }
9277
9278
9279 /* Call FN on every image in the image cache of frame F. Used to mark
9280 Lisp Objects in the image cache. */
9281
9282 void
9283 forall_images_in_image_cache (f, fn)
9284 struct frame *f;
9285 void (*fn) P_ ((struct image *img));
9286 {
9287 if (FRAME_LIVE_P (f) && FRAME_W32_P (f))
9288 {
9289 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
9290 if (c)
9291 {
9292 int i;
9293 for (i = 0; i < c->used; ++i)
9294 if (c->images[i])
9295 fn (c->images[i]);
9296 }
9297 }
9298 }
9299
9300
9301 \f
9302 /***********************************************************************
9303 W32 support code
9304 ***********************************************************************/
9305
9306 static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
9307 XImage **, Pixmap *));
9308 static void x_destroy_x_image P_ ((XImage *));
9309 static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
9310
9311
9312 /* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
9313 frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created.
9314 Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
9315 via xmalloc. DEPTH of zero signifies a 24 bit image, otherwise
9316 DEPTH should indicate the bit depth of the image. Print error
9317 messages via image_error if an error occurs. Value is non-zero if
9318 successful. */
9319
9320 static int
9321 x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
9322 struct frame *f;
9323 int width, height, depth;
9324 XImage **ximg;
9325 Pixmap *pixmap;
9326 {
9327 BITMAPINFOHEADER *header;
9328 HDC hdc;
9329 int scanline_width_bits;
9330 int remainder;
9331 int palette_colors = 0;
9332
9333 if (depth == 0)
9334 depth = 24;
9335
9336 if (depth != 1 && depth != 4 && depth != 8
9337 && depth != 16 && depth != 24 && depth != 32)
9338 {
9339 image_error ("Invalid image bit depth specified", Qnil, Qnil);
9340 return 0;
9341 }
9342
9343 scanline_width_bits = width * depth;
9344 remainder = scanline_width_bits % 32;
9345
9346 if (remainder)
9347 scanline_width_bits += 32 - remainder;
9348
9349 /* Bitmaps with a depth less than 16 need a palette. */
9350 /* BITMAPINFO structure already contains the first RGBQUAD. */
9351 if (depth < 16)
9352 palette_colors = 1 << depth - 1;
9353
9354 *ximg = xmalloc (sizeof (XImage) + palette_colors * sizeof (RGBQUAD));
9355 if (*ximg == NULL)
9356 {
9357 image_error ("Unable to allocate memory for XImage", Qnil, Qnil);
9358 return 0;
9359 }
9360
9361 header = &((*ximg)->info.bmiHeader);
9362 bzero (&((*ximg)->info), sizeof (BITMAPINFO));
9363 header->biSize = sizeof (*header);
9364 header->biWidth = width;
9365 header->biHeight = -height; /* negative indicates a top-down bitmap. */
9366 header->biPlanes = 1;
9367 header->biBitCount = depth;
9368 header->biCompression = BI_RGB;
9369 header->biClrUsed = palette_colors;
9370
9371 hdc = get_frame_dc (f);
9372
9373 /* Create a DIBSection and raster array for the bitmap,
9374 and store its handle in *pixmap. */
9375 *pixmap = CreateDIBSection (hdc, &((*ximg)->info), DIB_RGB_COLORS,
9376 &((*ximg)->data), NULL, 0);
9377
9378 /* Realize display palette and garbage all frames. */
9379 release_frame_dc (f, hdc);
9380
9381 if (*pixmap == NULL)
9382 {
9383 DWORD err = GetLastError();
9384 Lisp_Object errcode;
9385 /* All system errors are < 10000, so the following is safe. */
9386 XSETINT (errcode, (int) err);
9387 image_error ("Unable to create bitmap, error code %d", errcode, Qnil);
9388 x_destroy_x_image (*ximg);
9389 return 0;
9390 }
9391
9392 return 1;
9393 }
9394
9395
9396 /* Destroy XImage XIMG. Free XIMG->data. */
9397
9398 static void
9399 x_destroy_x_image (ximg)
9400 XImage *ximg;
9401 {
9402 xassert (interrupt_input_blocked);
9403 if (ximg)
9404 {
9405 /* Data will be freed by DestroyObject. */
9406 ximg->data = NULL;
9407 xfree (ximg);
9408 }
9409 }
9410
9411
9412 /* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT
9413 are width and height of both the image and pixmap. */
9414
9415 static void
9416 x_put_x_image (f, ximg, pixmap, width, height)
9417 struct frame *f;
9418 XImage *ximg;
9419 Pixmap pixmap;
9420 {
9421
9422 #if TODO /* W32 specific image code. */
9423 GC gc;
9424
9425 xassert (interrupt_input_blocked);
9426 gc = XCreateGC (NULL, pixmap, 0, NULL);
9427 XPutImage (NULL, pixmap, gc, ximg, 0, 0, 0, 0, width, height);
9428 XFreeGC (NULL, gc);
9429 #endif
9430 }
9431
9432 \f
9433 /***********************************************************************
9434 File Handling
9435 ***********************************************************************/
9436
9437 static Lisp_Object x_find_image_file P_ ((Lisp_Object));
9438 static char *slurp_file P_ ((char *, int *));
9439
9440
9441 /* Find image file FILE. Look in data-directory, then
9442 x-bitmap-file-path. Value is the full name of the file found, or
9443 nil if not found. */
9444
9445 static Lisp_Object
9446 x_find_image_file (file)
9447 Lisp_Object file;
9448 {
9449 Lisp_Object file_found, search_path;
9450 struct gcpro gcpro1, gcpro2;
9451 int fd;
9452
9453 file_found = Qnil;
9454 search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
9455 GCPRO2 (file_found, search_path);
9456
9457 /* Try to find FILE in data-directory, then x-bitmap-file-path. */
9458 fd = openp (search_path, file, Qnil, &file_found, 0);
9459
9460 if (fd == -1)
9461 file_found = Qnil;
9462 else
9463 close (fd);
9464
9465 UNGCPRO;
9466 return file_found;
9467 }
9468
9469
9470 /* Read FILE into memory. Value is a pointer to a buffer allocated
9471 with xmalloc holding FILE's contents. Value is null if an error
9472 occurred. *SIZE is set to the size of the file. */
9473
9474 static char *
9475 slurp_file (file, size)
9476 char *file;
9477 int *size;
9478 {
9479 FILE *fp = NULL;
9480 char *buf = NULL;
9481 struct stat st;
9482
9483 if (stat (file, &st) == 0
9484 && (fp = fopen (file, "r")) != NULL
9485 && (buf = (char *) xmalloc (st.st_size),
9486 fread (buf, 1, st.st_size, fp) == st.st_size))
9487 {
9488 *size = st.st_size;
9489 fclose (fp);
9490 }
9491 else
9492 {
9493 if (fp)
9494 fclose (fp);
9495 if (buf)
9496 {
9497 xfree (buf);
9498 buf = NULL;
9499 }
9500 }
9501
9502 return buf;
9503 }
9504
9505
9506 \f
9507 /***********************************************************************
9508 XBM images
9509 ***********************************************************************/
9510
9511 static int xbm_load P_ ((struct frame *f, struct image *img));
9512 static int xbm_load_image_from_file P_ ((struct frame *f, struct image *img,
9513 Lisp_Object file));
9514 static int xbm_image_p P_ ((Lisp_Object object));
9515 static int xbm_read_bitmap_file_data P_ ((char *, int *, int *,
9516 unsigned char **));
9517
9518
9519 /* Indices of image specification fields in xbm_format, below. */
9520
9521 enum xbm_keyword_index
9522 {
9523 XBM_TYPE,
9524 XBM_FILE,
9525 XBM_WIDTH,
9526 XBM_HEIGHT,
9527 XBM_DATA,
9528 XBM_FOREGROUND,
9529 XBM_BACKGROUND,
9530 XBM_ASCENT,
9531 XBM_MARGIN,
9532 XBM_RELIEF,
9533 XBM_ALGORITHM,
9534 XBM_HEURISTIC_MASK,
9535 XBM_MASK,
9536 XBM_LAST
9537 };
9538
9539 /* Vector of image_keyword structures describing the format
9540 of valid XBM image specifications. */
9541
9542 static struct image_keyword xbm_format[XBM_LAST] =
9543 {
9544 {":type", IMAGE_SYMBOL_VALUE, 1},
9545 {":file", IMAGE_STRING_VALUE, 0},
9546 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9547 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9548 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9549 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
9550 {":background", IMAGE_STRING_OR_NIL_VALUE, 0},
9551 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
9552 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
9553 {":relief", IMAGE_INTEGER_VALUE, 0},
9554 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9555 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
9556 };
9557
9558 /* Structure describing the image type XBM. */
9559
9560 static struct image_type xbm_type =
9561 {
9562 &Qxbm,
9563 xbm_image_p,
9564 xbm_load,
9565 x_clear_image,
9566 NULL
9567 };
9568
9569 /* Tokens returned from xbm_scan. */
9570
9571 enum xbm_token
9572 {
9573 XBM_TK_IDENT = 256,
9574 XBM_TK_NUMBER
9575 };
9576
9577
9578 /* Return non-zero if OBJECT is a valid XBM-type image specification.
9579 A valid specification is a list starting with the symbol `image'
9580 The rest of the list is a property list which must contain an
9581 entry `:type xbm..
9582
9583 If the specification specifies a file to load, it must contain
9584 an entry `:file FILENAME' where FILENAME is a string.
9585
9586 If the specification is for a bitmap loaded from memory it must
9587 contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
9588 WIDTH and HEIGHT are integers > 0. DATA may be:
9589
9590 1. a string large enough to hold the bitmap data, i.e. it must
9591 have a size >= (WIDTH + 7) / 8 * HEIGHT
9592
9593 2. a bool-vector of size >= WIDTH * HEIGHT
9594
9595 3. a vector of strings or bool-vectors, one for each line of the
9596 bitmap.
9597
9598 Both the file and data forms may contain the additional entries
9599 `:background COLOR' and `:foreground COLOR'. If not present,
9600 foreground and background of the frame on which the image is
9601 displayed, is used. */
9602
9603 static int
9604 xbm_image_p (object)
9605 Lisp_Object object;
9606 {
9607 struct image_keyword kw[XBM_LAST];
9608
9609 bcopy (xbm_format, kw, sizeof kw);
9610 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
9611 return 0;
9612
9613 xassert (EQ (kw[XBM_TYPE].value, Qxbm));
9614
9615 if (kw[XBM_FILE].count)
9616 {
9617 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
9618 return 0;
9619 }
9620 else
9621 {
9622 Lisp_Object data;
9623 int width, height;
9624
9625 /* Entries for `:width', `:height' and `:data' must be present. */
9626 if (!kw[XBM_WIDTH].count
9627 || !kw[XBM_HEIGHT].count
9628 || !kw[XBM_DATA].count)
9629 return 0;
9630
9631 data = kw[XBM_DATA].value;
9632 width = XFASTINT (kw[XBM_WIDTH].value);
9633 height = XFASTINT (kw[XBM_HEIGHT].value);
9634
9635 /* Check type of data, and width and height against contents of
9636 data. */
9637 if (VECTORP (data))
9638 {
9639 int i;
9640
9641 /* Number of elements of the vector must be >= height. */
9642 if (XVECTOR (data)->size < height)
9643 return 0;
9644
9645 /* Each string or bool-vector in data must be large enough
9646 for one line of the image. */
9647 for (i = 0; i < height; ++i)
9648 {
9649 Lisp_Object elt = XVECTOR (data)->contents[i];
9650
9651 if (STRINGP (elt))
9652 {
9653 if (XSTRING (elt)->size
9654 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
9655 return 0;
9656 }
9657 else if (BOOL_VECTOR_P (elt))
9658 {
9659 if (XBOOL_VECTOR (elt)->size < width)
9660 return 0;
9661 }
9662 else
9663 return 0;
9664 }
9665 }
9666 else if (STRINGP (data))
9667 {
9668 if (XSTRING (data)->size
9669 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
9670 return 0;
9671 }
9672 else if (BOOL_VECTOR_P (data))
9673 {
9674 if (XBOOL_VECTOR (data)->size < width * height)
9675 return 0;
9676 }
9677 else
9678 return 0;
9679 }
9680
9681 /* Baseline must be a value between 0 and 100 (a percentage). */
9682 if (kw[XBM_ASCENT].count
9683 && XFASTINT (kw[XBM_ASCENT].value) > 100)
9684 return 0;
9685
9686 return 1;
9687 }
9688
9689
9690 /* Scan a bitmap file. FP is the stream to read from. Value is
9691 either an enumerator from enum xbm_token, or a character for a
9692 single-character token, or 0 at end of file. If scanning an
9693 identifier, store the lexeme of the identifier in SVAL. If
9694 scanning a number, store its value in *IVAL. */
9695
9696 static int
9697 xbm_scan (s, end, sval, ival)
9698 char **s, *end;
9699 char *sval;
9700 int *ival;
9701 {
9702 int c;
9703
9704 loop:
9705
9706 /* Skip white space. */
9707 while (*s < end &&(c = *(*s)++, isspace (c)))
9708 ;
9709
9710 if (*s >= end)
9711 c = 0;
9712 else if (isdigit (c))
9713 {
9714 int value = 0, digit;
9715
9716 if (c == '0' && *s < end)
9717 {
9718 c = *(*s)++;
9719 if (c == 'x' || c == 'X')
9720 {
9721 while (*s < end)
9722 {
9723 c = *(*s)++;
9724 if (isdigit (c))
9725 digit = c - '0';
9726 else if (c >= 'a' && c <= 'f')
9727 digit = c - 'a' + 10;
9728 else if (c >= 'A' && c <= 'F')
9729 digit = c - 'A' + 10;
9730 else
9731 break;
9732 value = 16 * value + digit;
9733 }
9734 }
9735 else if (isdigit (c))
9736 {
9737 value = c - '0';
9738 while (*s < end
9739 && (c = *(*s)++, isdigit (c)))
9740 value = 8 * value + c - '0';
9741 }
9742 }
9743 else
9744 {
9745 value = c - '0';
9746 while (*s < end
9747 && (c = *(*s)++, isdigit (c)))
9748 value = 10 * value + c - '0';
9749 }
9750
9751 if (*s < end)
9752 *s = *s - 1;
9753 *ival = value;
9754 c = XBM_TK_NUMBER;
9755 }
9756 else if (isalpha (c) || c == '_')
9757 {
9758 *sval++ = c;
9759 while (*s < end
9760 && (c = *(*s)++, (isalnum (c) || c == '_')))
9761 *sval++ = c;
9762 *sval = 0;
9763 if (*s < end)
9764 *s = *s - 1;
9765 c = XBM_TK_IDENT;
9766 }
9767 else if (c == '/' && **s == '*')
9768 {
9769 /* C-style comment. */
9770 ++*s;
9771 while (**s && (**s != '*' || *(*s + 1) != '/'))
9772 ++*s;
9773 if (**s)
9774 {
9775 *s += 2;
9776 goto loop;
9777 }
9778 }
9779
9780 return c;
9781 }
9782
9783
9784 /* Replacement for XReadBitmapFileData which isn't available under old
9785 X versions. CONTENTS is a pointer to a buffer to parse; END is the
9786 buffer's end. Set *WIDTH and *HEIGHT to the width and height of
9787 the image. Return in *DATA the bitmap data allocated with xmalloc.
9788 Value is non-zero if successful. DATA null means just test if
9789 CONTENTS looks like an in-memory XBM file. */
9790
9791 static int
9792 xbm_read_bitmap_data (contents, end, width, height, data)
9793 char *contents, *end;
9794 int *width, *height;
9795 unsigned char **data;
9796 {
9797 char *s = contents;
9798 char buffer[BUFSIZ];
9799 int padding_p = 0;
9800 int v10 = 0;
9801 int bytes_per_line, i, nbytes;
9802 unsigned char *p;
9803 int value;
9804 int LA1;
9805
9806 #define match() \
9807 LA1 = xbm_scan (contents, end, buffer, &value)
9808
9809 #define expect(TOKEN) \
9810 if (LA1 != (TOKEN)) \
9811 goto failure; \
9812 else \
9813 match ()
9814
9815 #define expect_ident(IDENT) \
9816 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
9817 match (); \
9818 else \
9819 goto failure
9820
9821 *width = *height = -1;
9822 if (data)
9823 *data = NULL;
9824 LA1 = xbm_scan (&s, end, buffer, &value);
9825
9826 /* Parse defines for width, height and hot-spots. */
9827 while (LA1 == '#')
9828 {
9829 match ();
9830 expect_ident ("define");
9831 expect (XBM_TK_IDENT);
9832
9833 if (LA1 == XBM_TK_NUMBER);
9834 {
9835 char *p = strrchr (buffer, '_');
9836 p = p ? p + 1 : buffer;
9837 if (strcmp (p, "width") == 0)
9838 *width = value;
9839 else if (strcmp (p, "height") == 0)
9840 *height = value;
9841 }
9842 expect (XBM_TK_NUMBER);
9843 }
9844
9845 if (*width < 0 || *height < 0)
9846 goto failure;
9847 else if (data == NULL)
9848 goto success;
9849
9850 /* Parse bits. Must start with `static'. */
9851 expect_ident ("static");
9852 if (LA1 == XBM_TK_IDENT)
9853 {
9854 if (strcmp (buffer, "unsigned") == 0)
9855 {
9856 match ();
9857 expect_ident ("char");
9858 }
9859 else if (strcmp (buffer, "short") == 0)
9860 {
9861 match ();
9862 v10 = 1;
9863 if (*width % 16 && *width % 16 < 9)
9864 padding_p = 1;
9865 }
9866 else if (strcmp (buffer, "char") == 0)
9867 match ();
9868 else
9869 goto failure;
9870 }
9871 else
9872 goto failure;
9873
9874 expect (XBM_TK_IDENT);
9875 expect ('[');
9876 expect (']');
9877 expect ('=');
9878 expect ('{');
9879
9880 bytes_per_line = (*width + 7) / 8 + padding_p;
9881 nbytes = bytes_per_line * *height;
9882 p = *data = (char *) xmalloc (nbytes);
9883
9884 if (v10)
9885 {
9886
9887 for (i = 0; i < nbytes; i += 2)
9888 {
9889 int val = value;
9890 expect (XBM_TK_NUMBER);
9891
9892 *p++ = val;
9893 if (!padding_p || ((i + 2) % bytes_per_line))
9894 *p++ = value >> 8;
9895
9896 if (LA1 == ',' || LA1 == '}')
9897 match ();
9898 else
9899 goto failure;
9900 }
9901 }
9902 else
9903 {
9904 for (i = 0; i < nbytes; ++i)
9905 {
9906 int val = value;
9907 expect (XBM_TK_NUMBER);
9908
9909 *p++ = val;
9910
9911 if (LA1 == ',' || LA1 == '}')
9912 match ();
9913 else
9914 goto failure;
9915 }
9916 }
9917
9918 success:
9919 return 1;
9920
9921 failure:
9922
9923 if (data && *data)
9924 {
9925 xfree (*data);
9926 *data = NULL;
9927 }
9928 return 0;
9929
9930 #undef match
9931 #undef expect
9932 #undef expect_ident
9933 }
9934
9935
9936 /* Load XBM image IMG which will be displayed on frame F from buffer
9937 CONTENTS. END is the end of the buffer. Value is non-zero if
9938 successful. */
9939
9940 static int
9941 xbm_load_image (f, img, contents, end)
9942 struct frame *f;
9943 struct image *img;
9944 char *contents, *end;
9945 {
9946 int rc;
9947 unsigned char *data;
9948 int success_p = 0;
9949
9950 rc = xbm_read_bitmap_data (contents, end, &img->width, &img->height, &data);
9951 if (rc)
9952 {
9953 int depth = one_w32_display_info.n_cbits;
9954 int planes = one_w32_display_info.n_planes;
9955
9956 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
9957 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
9958 Lisp_Object value;
9959
9960 xassert (img->width > 0 && img->height > 0);
9961
9962 /* Get foreground and background colors, maybe allocate colors. */
9963 value = image_spec_value (img->spec, QCforeground, NULL);
9964 if (!NILP (value))
9965 foreground = x_alloc_image_color (f, img, value, foreground);
9966 value = image_spec_value (img->spec, QCbackground, NULL);
9967 if (!NILP (value))
9968 {
9969 background = x_alloc_image_color (f, img, value, background);
9970 img->background = background;
9971 img->background_valid = 1;
9972 }
9973 img->pixmap
9974 = CreateBitmap (img->width, img->height, planes, depth, data);
9975
9976 xfree (data);
9977
9978 if (img->pixmap == 0)
9979 {
9980 x_clear_image (f, img);
9981 image_error ("Unable to create X pixmap for `%s'", img->spec, Qnil);
9982 }
9983 else
9984 success_p = 1;
9985 }
9986 else
9987 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
9988
9989 return success_p;
9990 }
9991
9992
9993 /* Value is non-zero if DATA looks like an in-memory XBM file. */
9994
9995 static int
9996 xbm_file_p (data)
9997 Lisp_Object data;
9998 {
9999 int w, h;
10000 return (STRINGP (data)
10001 && xbm_read_bitmap_data (XSTRING (data)->data,
10002 (XSTRING (data)->data
10003 + STRING_BYTES (XSTRING (data))),
10004 &w, &h, NULL));
10005 }
10006
10007
10008 /* Fill image IMG which is used on frame F with pixmap data. Value is
10009 non-zero if successful. */
10010
10011 static int
10012 xbm_load (f, img)
10013 struct frame *f;
10014 struct image *img;
10015 {
10016 int success_p = 0;
10017 Lisp_Object file_name;
10018
10019 xassert (xbm_image_p (img->spec));
10020
10021 /* If IMG->spec specifies a file name, create a non-file spec from it. */
10022 file_name = image_spec_value (img->spec, QCfile, NULL);
10023 if (STRINGP (file_name))
10024 {
10025 Lisp_Object file;
10026 char *contents;
10027 int size;
10028 struct gcpro gcpro1;
10029
10030 file = x_find_image_file (file_name);
10031 GCPRO1 (file);
10032 if (!STRINGP (file))
10033 {
10034 image_error ("Cannot find image file `%s'", file_name, Qnil);
10035 UNGCPRO;
10036 return 0;
10037 }
10038
10039 contents = slurp_file (XSTRING (file)->data, &size);
10040 if (contents == NULL)
10041 {
10042 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
10043 UNGCPRO;
10044 return 0;
10045 }
10046
10047 success_p = xbm_load_image (f, img, contents, contents + size);
10048 UNGCPRO;
10049 }
10050 else
10051 {
10052 struct image_keyword fmt[XBM_LAST];
10053 Lisp_Object data;
10054 int depth;
10055 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
10056 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
10057 char *bits;
10058 int parsed_p;
10059 int in_memory_file_p = 0;
10060
10061 /* See if data looks like an in-memory XBM file. */
10062 data = image_spec_value (img->spec, QCdata, NULL);
10063 in_memory_file_p = xbm_file_p (data);
10064
10065 /* Parse the list specification. */
10066 bcopy (xbm_format, fmt, sizeof fmt);
10067 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
10068 xassert (parsed_p);
10069
10070 /* Get specified width, and height. */
10071 if (!in_memory_file_p)
10072 {
10073 img->width = XFASTINT (fmt[XBM_WIDTH].value);
10074 img->height = XFASTINT (fmt[XBM_HEIGHT].value);
10075 xassert (img->width > 0 && img->height > 0);
10076 }
10077 /* Get foreground and background colors, maybe allocate colors. */
10078 if (fmt[XBM_FOREGROUND].count
10079 && STRINGP (fmt[XBM_FOREGROUND].value))
10080 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
10081 foreground);
10082 if (fmt[XBM_BACKGROUND].count
10083 && STRINGP (fmt[XBM_BACKGROUND].value))
10084 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
10085 background);
10086
10087 if (in_memory_file_p)
10088 success_p = xbm_load_image (f, img, XSTRING (data)->data,
10089 (XSTRING (data)->data
10090 + STRING_BYTES (XSTRING (data))));
10091 else
10092 {
10093 if (VECTORP (data))
10094 {
10095 int i;
10096 char *p;
10097 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
10098
10099 p = bits = (char *) alloca (nbytes * img->height);
10100 for (i = 0; i < img->height; ++i, p += nbytes)
10101 {
10102 Lisp_Object line = XVECTOR (data)->contents[i];
10103 if (STRINGP (line))
10104 bcopy (XSTRING (line)->data, p, nbytes);
10105 else
10106 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
10107 }
10108 }
10109 else if (STRINGP (data))
10110 bits = XSTRING (data)->data;
10111 else
10112 bits = XBOOL_VECTOR (data)->data;
10113 #ifdef TODO /* image support. */
10114 /* Create the pixmap. */
10115 depth = one_w32_display_info.n_cbits;
10116 img->pixmap
10117 = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
10118 FRAME_X_WINDOW (f),
10119 bits,
10120 img->width, img->height,
10121 foreground, background,
10122 depth);
10123 #endif
10124 if (img->pixmap)
10125 success_p = 1;
10126 else
10127 {
10128 image_error ("Unable to create pixmap for XBM image `%s'",
10129 img->spec, Qnil);
10130 x_clear_image (f, img);
10131 }
10132 }
10133 }
10134
10135 return success_p;
10136 }
10137
10138
10139 \f
10140 /***********************************************************************
10141 XPM images
10142 ***********************************************************************/
10143
10144 #if HAVE_XPM
10145
10146 static int xpm_image_p P_ ((Lisp_Object object));
10147 static int xpm_load P_ ((struct frame *f, struct image *img));
10148 static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
10149
10150 #include "X11/xpm.h"
10151
10152 /* The symbol `xpm' identifying XPM-format images. */
10153
10154 Lisp_Object Qxpm;
10155
10156 /* Indices of image specification fields in xpm_format, below. */
10157
10158 enum xpm_keyword_index
10159 {
10160 XPM_TYPE,
10161 XPM_FILE,
10162 XPM_DATA,
10163 XPM_ASCENT,
10164 XPM_MARGIN,
10165 XPM_RELIEF,
10166 XPM_ALGORITHM,
10167 XPM_HEURISTIC_MASK,
10168 XPM_MASK,
10169 XPM_COLOR_SYMBOLS,
10170 XPM_BACKGROUND,
10171 XPM_LAST
10172 };
10173
10174 /* Vector of image_keyword structures describing the format
10175 of valid XPM image specifications. */
10176
10177 static struct image_keyword xpm_format[XPM_LAST] =
10178 {
10179 {":type", IMAGE_SYMBOL_VALUE, 1},
10180 {":file", IMAGE_STRING_VALUE, 0},
10181 {":data", IMAGE_STRING_VALUE, 0},
10182 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
10183 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
10184 {":relief", IMAGE_INTEGER_VALUE, 0},
10185 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10186 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10187 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10188 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10189 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
10190 };
10191
10192 /* Structure describing the image type XBM. */
10193
10194 static struct image_type xpm_type =
10195 {
10196 &Qxpm,
10197 xpm_image_p,
10198 xpm_load,
10199 x_clear_image,
10200 NULL
10201 };
10202
10203
10204 /* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
10205 for XPM images. Such a list must consist of conses whose car and
10206 cdr are strings. */
10207
10208 static int
10209 xpm_valid_color_symbols_p (color_symbols)
10210 Lisp_Object color_symbols;
10211 {
10212 while (CONSP (color_symbols))
10213 {
10214 Lisp_Object sym = XCAR (color_symbols);
10215 if (!CONSP (sym)
10216 || !STRINGP (XCAR (sym))
10217 || !STRINGP (XCDR (sym)))
10218 break;
10219 color_symbols = XCDR (color_symbols);
10220 }
10221
10222 return NILP (color_symbols);
10223 }
10224
10225
10226 /* Value is non-zero if OBJECT is a valid XPM image specification. */
10227
10228 static int
10229 xpm_image_p (object)
10230 Lisp_Object object;
10231 {
10232 struct image_keyword fmt[XPM_LAST];
10233 bcopy (xpm_format, fmt, sizeof fmt);
10234 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
10235 /* Either `:file' or `:data' must be present. */
10236 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
10237 /* Either no `:color-symbols' or it's a list of conses
10238 whose car and cdr are strings. */
10239 && (fmt[XPM_COLOR_SYMBOLS].count == 0
10240 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value))
10241 && (fmt[XPM_ASCENT].count == 0
10242 || XFASTINT (fmt[XPM_ASCENT].value) < 100));
10243 }
10244
10245
10246 /* Load image IMG which will be displayed on frame F. Value is
10247 non-zero if successful. */
10248
10249 static int
10250 xpm_load (f, img)
10251 struct frame *f;
10252 struct image *img;
10253 {
10254 int rc, i;
10255 XpmAttributes attrs;
10256 Lisp_Object specified_file, color_symbols;
10257
10258 /* Configure the XPM lib. Use the visual of frame F. Allocate
10259 close colors. Return colors allocated. */
10260 bzero (&attrs, sizeof attrs);
10261 attrs.visual = FRAME_X_VISUAL (f);
10262 attrs.colormap = FRAME_X_COLORMAP (f);
10263 attrs.valuemask |= XpmVisual;
10264 attrs.valuemask |= XpmColormap;
10265 attrs.valuemask |= XpmReturnAllocPixels;
10266 #ifdef XpmAllocCloseColors
10267 attrs.alloc_close_colors = 1;
10268 attrs.valuemask |= XpmAllocCloseColors;
10269 #else
10270 attrs.closeness = 600;
10271 attrs.valuemask |= XpmCloseness;
10272 #endif
10273
10274 /* If image specification contains symbolic color definitions, add
10275 these to `attrs'. */
10276 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
10277 if (CONSP (color_symbols))
10278 {
10279 Lisp_Object tail;
10280 XpmColorSymbol *xpm_syms;
10281 int i, size;
10282
10283 attrs.valuemask |= XpmColorSymbols;
10284
10285 /* Count number of symbols. */
10286 attrs.numsymbols = 0;
10287 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
10288 ++attrs.numsymbols;
10289
10290 /* Allocate an XpmColorSymbol array. */
10291 size = attrs.numsymbols * sizeof *xpm_syms;
10292 xpm_syms = (XpmColorSymbol *) alloca (size);
10293 bzero (xpm_syms, size);
10294 attrs.colorsymbols = xpm_syms;
10295
10296 /* Fill the color symbol array. */
10297 for (tail = color_symbols, i = 0;
10298 CONSP (tail);
10299 ++i, tail = XCDR (tail))
10300 {
10301 Lisp_Object name = XCAR (XCAR (tail));
10302 Lisp_Object color = XCDR (XCAR (tail));
10303 xpm_syms[i].name = (char *) alloca (XSTRING (name)->size + 1);
10304 strcpy (xpm_syms[i].name, XSTRING (name)->data);
10305 xpm_syms[i].value = (char *) alloca (XSTRING (color)->size + 1);
10306 strcpy (xpm_syms[i].value, XSTRING (color)->data);
10307 }
10308 }
10309
10310 /* Create a pixmap for the image, either from a file, or from a
10311 string buffer containing data in the same format as an XPM file. */
10312 BLOCK_INPUT;
10313 specified_file = image_spec_value (img->spec, QCfile, NULL);
10314 if (STRINGP (specified_file))
10315 {
10316 Lisp_Object file = x_find_image_file (specified_file);
10317 if (!STRINGP (file))
10318 {
10319 image_error ("Cannot find image file `%s'", specified_file, Qnil);
10320 UNBLOCK_INPUT;
10321 return 0;
10322 }
10323
10324 rc = XpmReadFileToPixmap (NULL, FRAME_W32_WINDOW (f),
10325 XSTRING (file)->data, &img->pixmap, &img->mask,
10326 &attrs);
10327 }
10328 else
10329 {
10330 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
10331 rc = XpmCreatePixmapFromBuffer (NULL, FRAME_W32_WINDOW (f),
10332 XSTRING (buffer)->data,
10333 &img->pixmap, &img->mask,
10334 &attrs);
10335 }
10336 UNBLOCK_INPUT;
10337
10338 if (rc == XpmSuccess)
10339 {
10340 /* Remember allocated colors. */
10341 img->ncolors = attrs.nalloc_pixels;
10342 img->colors = (unsigned long *) xmalloc (img->ncolors
10343 * sizeof *img->colors);
10344 for (i = 0; i < attrs.nalloc_pixels; ++i)
10345 img->colors[i] = attrs.alloc_pixels[i];
10346
10347 img->width = attrs.width;
10348 img->height = attrs.height;
10349 xassert (img->width > 0 && img->height > 0);
10350
10351 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
10352 BLOCK_INPUT;
10353 XpmFreeAttributes (&attrs);
10354 UNBLOCK_INPUT;
10355 }
10356 else
10357 {
10358 switch (rc)
10359 {
10360 case XpmOpenFailed:
10361 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
10362 break;
10363
10364 case XpmFileInvalid:
10365 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
10366 break;
10367
10368 case XpmNoMemory:
10369 image_error ("Out of memory (%s)", img->spec, Qnil);
10370 break;
10371
10372 case XpmColorFailed:
10373 image_error ("Color allocation error (%s)", img->spec, Qnil);
10374 break;
10375
10376 default:
10377 image_error ("Unknown error (%s)", img->spec, Qnil);
10378 break;
10379 }
10380 }
10381
10382 return rc == XpmSuccess;
10383 }
10384
10385 #endif /* HAVE_XPM != 0 */
10386
10387 \f
10388 #if 0 /* TODO : Color tables on W32. */
10389 /***********************************************************************
10390 Color table
10391 ***********************************************************************/
10392
10393 /* An entry in the color table mapping an RGB color to a pixel color. */
10394
10395 struct ct_color
10396 {
10397 int r, g, b;
10398 unsigned long pixel;
10399
10400 /* Next in color table collision list. */
10401 struct ct_color *next;
10402 };
10403
10404 /* The bucket vector size to use. Must be prime. */
10405
10406 #define CT_SIZE 101
10407
10408 /* Value is a hash of the RGB color given by R, G, and B. */
10409
10410 #define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
10411
10412 /* The color hash table. */
10413
10414 struct ct_color **ct_table;
10415
10416 /* Number of entries in the color table. */
10417
10418 int ct_colors_allocated;
10419
10420 /* Function prototypes. */
10421
10422 static void init_color_table P_ ((void));
10423 static void free_color_table P_ ((void));
10424 static unsigned long *colors_in_color_table P_ ((int *n));
10425 static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
10426 static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
10427
10428
10429 /* Initialize the color table. */
10430
10431 static void
10432 init_color_table ()
10433 {
10434 int size = CT_SIZE * sizeof (*ct_table);
10435 ct_table = (struct ct_color **) xmalloc (size);
10436 bzero (ct_table, size);
10437 ct_colors_allocated = 0;
10438 }
10439
10440
10441 /* Free memory associated with the color table. */
10442
10443 static void
10444 free_color_table ()
10445 {
10446 int i;
10447 struct ct_color *p, *next;
10448
10449 for (i = 0; i < CT_SIZE; ++i)
10450 for (p = ct_table[i]; p; p = next)
10451 {
10452 next = p->next;
10453 xfree (p);
10454 }
10455
10456 xfree (ct_table);
10457 ct_table = NULL;
10458 }
10459
10460
10461 /* Value is a pixel color for RGB color R, G, B on frame F. If an
10462 entry for that color already is in the color table, return the
10463 pixel color of that entry. Otherwise, allocate a new color for R,
10464 G, B, and make an entry in the color table. */
10465
10466 static unsigned long
10467 lookup_rgb_color (f, r, g, b)
10468 struct frame *f;
10469 int r, g, b;
10470 {
10471 unsigned hash = CT_HASH_RGB (r, g, b);
10472 int i = hash % CT_SIZE;
10473 struct ct_color *p;
10474
10475 for (p = ct_table[i]; p; p = p->next)
10476 if (p->r == r && p->g == g && p->b == b)
10477 break;
10478
10479 if (p == NULL)
10480 {
10481 COLORREF color;
10482 Colormap cmap;
10483 int rc;
10484
10485 color = PALETTERGB (r, g, b);
10486
10487 ++ct_colors_allocated;
10488
10489 p = (struct ct_color *) xmalloc (sizeof *p);
10490 p->r = r;
10491 p->g = g;
10492 p->b = b;
10493 p->pixel = color;
10494 p->next = ct_table[i];
10495 ct_table[i] = p;
10496 }
10497
10498 return p->pixel;
10499 }
10500
10501
10502 /* Look up pixel color PIXEL which is used on frame F in the color
10503 table. If not already present, allocate it. Value is PIXEL. */
10504
10505 static unsigned long
10506 lookup_pixel_color (f, pixel)
10507 struct frame *f;
10508 unsigned long pixel;
10509 {
10510 int i = pixel % CT_SIZE;
10511 struct ct_color *p;
10512
10513 for (p = ct_table[i]; p; p = p->next)
10514 if (p->pixel == pixel)
10515 break;
10516
10517 if (p == NULL)
10518 {
10519 XColor color;
10520 Colormap cmap;
10521 int rc;
10522
10523 BLOCK_INPUT;
10524
10525 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
10526 color.pixel = pixel;
10527 XQueryColor (NULL, cmap, &color);
10528 rc = x_alloc_nearest_color (f, cmap, &color);
10529 UNBLOCK_INPUT;
10530
10531 if (rc)
10532 {
10533 ++ct_colors_allocated;
10534
10535 p = (struct ct_color *) xmalloc (sizeof *p);
10536 p->r = color.red;
10537 p->g = color.green;
10538 p->b = color.blue;
10539 p->pixel = pixel;
10540 p->next = ct_table[i];
10541 ct_table[i] = p;
10542 }
10543 else
10544 return FRAME_FOREGROUND_PIXEL (f);
10545 }
10546 return p->pixel;
10547 }
10548
10549
10550 /* Value is a vector of all pixel colors contained in the color table,
10551 allocated via xmalloc. Set *N to the number of colors. */
10552
10553 static unsigned long *
10554 colors_in_color_table (n)
10555 int *n;
10556 {
10557 int i, j;
10558 struct ct_color *p;
10559 unsigned long *colors;
10560
10561 if (ct_colors_allocated == 0)
10562 {
10563 *n = 0;
10564 colors = NULL;
10565 }
10566 else
10567 {
10568 colors = (unsigned long *) xmalloc (ct_colors_allocated
10569 * sizeof *colors);
10570 *n = ct_colors_allocated;
10571
10572 for (i = j = 0; i < CT_SIZE; ++i)
10573 for (p = ct_table[i]; p; p = p->next)
10574 colors[j++] = p->pixel;
10575 }
10576
10577 return colors;
10578 }
10579
10580 #endif /* TODO */
10581
10582 \f
10583 #ifdef HAVE_IMAGES /* TODO */
10584 /***********************************************************************
10585 Algorithms
10586 ***********************************************************************/
10587 static XColor *x_to_xcolors P_ ((struct frame *, struct image *, int));
10588 static void x_from_xcolors P_ ((struct frame *, struct image *, XColor *));
10589 static void x_detect_edges P_ ((struct frame *, struct image *, int[9], int));
10590 static void XPutPixel (XImage *, int, int, COLORREF);
10591
10592 /* Non-zero means draw a cross on images having `:conversion
10593 disabled'. */
10594
10595 int cross_disabled_images;
10596
10597 /* Edge detection matrices for different edge-detection
10598 strategies. */
10599
10600 static int emboss_matrix[9] = {
10601 /* x - 1 x x + 1 */
10602 2, -1, 0, /* y - 1 */
10603 -1, 0, 1, /* y */
10604 0, 1, -2 /* y + 1 */
10605 };
10606
10607 static int laplace_matrix[9] = {
10608 /* x - 1 x x + 1 */
10609 1, 0, 0, /* y - 1 */
10610 0, 0, 0, /* y */
10611 0, 0, -1 /* y + 1 */
10612 };
10613
10614 /* Value is the intensity of the color whose red/green/blue values
10615 are R, G, and B. */
10616
10617 #define COLOR_INTENSITY(R, G, B) ((2 * (R) + 3 * (G) + (B)) / 6)
10618
10619
10620 /* On frame F, return an array of XColor structures describing image
10621 IMG->pixmap. Each XColor structure has its pixel color set. RGB_P
10622 non-zero means also fill the red/green/blue members of the XColor
10623 structures. Value is a pointer to the array of XColors structures,
10624 allocated with xmalloc; it must be freed by the caller. */
10625
10626 static XColor *
10627 x_to_xcolors (f, img, rgb_p)
10628 struct frame *f;
10629 struct image *img;
10630 int rgb_p;
10631 {
10632 int x, y;
10633 XColor *colors, *p;
10634 XImage *ximg;
10635
10636 colors = (XColor *) xmalloc (img->width * img->height * sizeof *colors);
10637 #if 0 /* TODO: implement image colors. */
10638 /* Get the X image IMG->pixmap. */
10639 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
10640 0, 0, img->width, img->height, ~0, ZPixmap);
10641
10642 /* Fill the `pixel' members of the XColor array. I wished there
10643 were an easy and portable way to circumvent XGetPixel. */
10644 p = colors;
10645 for (y = 0; y < img->height; ++y)
10646 {
10647 XColor *row = p;
10648
10649 for (x = 0; x < img->width; ++x, ++p)
10650 p->pixel = XGetPixel (ximg, x, y);
10651
10652 if (rgb_p)
10653 x_query_colors (f, row, img->width);
10654 }
10655
10656 XDestroyImage (ximg);
10657 #endif
10658 return colors;
10659 }
10660
10661 /* Put a pixel of COLOR at position X, Y in XIMG. XIMG must have been
10662 created with CreateDIBSection, with the pointer to the bit values
10663 stored in ximg->data. */
10664
10665 static void XPutPixel (ximg, x, y, color)
10666 XImage * ximg;
10667 int x, y;
10668 COLORREF color;
10669 {
10670 int width = ximg->info.bmiHeader.biWidth;
10671 int height = ximg->info.bmiHeader.biHeight;
10672 int rowbytes = width * 3;
10673 unsigned char * pixel;
10674
10675 /* Don't support putting pixels in images with palettes. */
10676 xassert (ximg->info.bmiHeader.biBitCount == 24);
10677
10678 /* Ensure scanlines are aligned on 4 byte boundaries. */
10679 if (rowbytes % 4)
10680 rowbytes += 4 - (rowbytes % 4);
10681
10682 pixel = ximg->data + y * rowbytes + x * 3;
10683 *pixel = 255 - GetRValue (color);
10684 *(pixel + 1) = 255 - GetGValue (color);
10685 *(pixel + 2) = 255 - GetBValue (color);
10686 }
10687
10688
10689 /* Create IMG->pixmap from an array COLORS of XColor structures, whose
10690 RGB members are set. F is the frame on which this all happens.
10691 COLORS will be freed; an existing IMG->pixmap will be freed, too. */
10692
10693 static void
10694 x_from_xcolors (f, img, colors)
10695 struct frame *f;
10696 struct image *img;
10697 XColor *colors;
10698 {
10699 int x, y;
10700 XImage *oimg;
10701 Pixmap pixmap;
10702 XColor *p;
10703 #if 0 /* TODO: color tables. */
10704 init_color_table ();
10705 #endif
10706 x_create_x_image_and_pixmap (f, img->width, img->height, 0,
10707 &oimg, &pixmap);
10708 p = colors;
10709 for (y = 0; y < img->height; ++y)
10710 for (x = 0; x < img->width; ++x, ++p)
10711 {
10712 unsigned long pixel;
10713 #if 0 /* TODO: color tables. */
10714 pixel = lookup_rgb_color (f, p->red, p->green, p->blue);
10715 #else
10716 pixel = PALETTERGB (p->red, p->green, p->blue);
10717 #endif
10718 XPutPixel (oimg, x, y, pixel);
10719 }
10720
10721 xfree (colors);
10722 x_clear_image_1 (f, img, 1, 0, 1);
10723
10724 x_put_x_image (f, oimg, pixmap, img->width, img->height);
10725 x_destroy_x_image (oimg);
10726 img->pixmap = pixmap;
10727 #if 0 /* TODO: color tables. */
10728 img->colors = colors_in_color_table (&img->ncolors);
10729 free_color_table ();
10730 #endif
10731 }
10732
10733
10734 /* On frame F, perform edge-detection on image IMG.
10735
10736 MATRIX is a nine-element array specifying the transformation
10737 matrix. See emboss_matrix for an example.
10738
10739 COLOR_ADJUST is a color adjustment added to each pixel of the
10740 outgoing image. */
10741
10742 static void
10743 x_detect_edges (f, img, matrix, color_adjust)
10744 struct frame *f;
10745 struct image *img;
10746 int matrix[9], color_adjust;
10747 {
10748 XColor *colors = x_to_xcolors (f, img, 1);
10749 XColor *new, *p;
10750 int x, y, i, sum;
10751
10752 for (i = sum = 0; i < 9; ++i)
10753 sum += abs (matrix[i]);
10754
10755 #define COLOR(A, X, Y) ((A) + (Y) * img->width + (X))
10756
10757 new = (XColor *) xmalloc (img->width * img->height * sizeof *new);
10758
10759 for (y = 0; y < img->height; ++y)
10760 {
10761 p = COLOR (new, 0, y);
10762 p->red = p->green = p->blue = 0xffff/2;
10763 p = COLOR (new, img->width - 1, y);
10764 p->red = p->green = p->blue = 0xffff/2;
10765 }
10766
10767 for (x = 1; x < img->width - 1; ++x)
10768 {
10769 p = COLOR (new, x, 0);
10770 p->red = p->green = p->blue = 0xffff/2;
10771 p = COLOR (new, x, img->height - 1);
10772 p->red = p->green = p->blue = 0xffff/2;
10773 }
10774
10775 for (y = 1; y < img->height - 1; ++y)
10776 {
10777 p = COLOR (new, 1, y);
10778
10779 for (x = 1; x < img->width - 1; ++x, ++p)
10780 {
10781 int r, g, b, y1, x1;
10782
10783 r = g = b = i = 0;
10784 for (y1 = y - 1; y1 < y + 2; ++y1)
10785 for (x1 = x - 1; x1 < x + 2; ++x1, ++i)
10786 if (matrix[i])
10787 {
10788 XColor *t = COLOR (colors, x1, y1);
10789 r += matrix[i] * t->red;
10790 g += matrix[i] * t->green;
10791 b += matrix[i] * t->blue;
10792 }
10793
10794 r = (r / sum + color_adjust) & 0xffff;
10795 g = (g / sum + color_adjust) & 0xffff;
10796 b = (b / sum + color_adjust) & 0xffff;
10797 p->red = p->green = p->blue = COLOR_INTENSITY (r, g, b);
10798 }
10799 }
10800
10801 xfree (colors);
10802 x_from_xcolors (f, img, new);
10803
10804 #undef COLOR
10805 }
10806
10807
10808 /* Perform the pre-defined `emboss' edge-detection on image IMG
10809 on frame F. */
10810
10811 static void
10812 x_emboss (f, img)
10813 struct frame *f;
10814 struct image *img;
10815 {
10816 x_detect_edges (f, img, emboss_matrix, 0xffff / 2);
10817 }
10818
10819
10820 /* Transform image IMG which is used on frame F with a Laplace
10821 edge-detection algorithm. The result is an image that can be used
10822 to draw disabled buttons, for example. */
10823
10824 static void
10825 x_laplace (f, img)
10826 struct frame *f;
10827 struct image *img;
10828 {
10829 x_detect_edges (f, img, laplace_matrix, 45000);
10830 }
10831
10832
10833 /* Perform edge-detection on image IMG on frame F, with specified
10834 transformation matrix MATRIX and color-adjustment COLOR_ADJUST.
10835
10836 MATRIX must be either
10837
10838 - a list of at least 9 numbers in row-major form
10839 - a vector of at least 9 numbers
10840
10841 COLOR_ADJUST nil means use a default; otherwise it must be a
10842 number. */
10843
10844 static void
10845 x_edge_detection (f, img, matrix, color_adjust)
10846 struct frame *f;
10847 struct image *img;
10848 Lisp_Object matrix, color_adjust;
10849 {
10850 int i = 0;
10851 int trans[9];
10852
10853 if (CONSP (matrix))
10854 {
10855 for (i = 0;
10856 i < 9 && CONSP (matrix) && NUMBERP (XCAR (matrix));
10857 ++i, matrix = XCDR (matrix))
10858 trans[i] = XFLOATINT (XCAR (matrix));
10859 }
10860 else if (VECTORP (matrix) && ASIZE (matrix) >= 9)
10861 {
10862 for (i = 0; i < 9 && NUMBERP (AREF (matrix, i)); ++i)
10863 trans[i] = XFLOATINT (AREF (matrix, i));
10864 }
10865
10866 if (NILP (color_adjust))
10867 color_adjust = make_number (0xffff / 2);
10868
10869 if (i == 9 && NUMBERP (color_adjust))
10870 x_detect_edges (f, img, trans, (int) XFLOATINT (color_adjust));
10871 }
10872
10873
10874 /* Transform image IMG on frame F so that it looks disabled. */
10875
10876 static void
10877 x_disable_image (f, img)
10878 struct frame *f;
10879 struct image *img;
10880 {
10881 struct w32_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
10882
10883 if (dpyinfo->n_planes * dpyinfo->n_cbits >= 2)
10884 {
10885 /* Color (or grayscale). Convert to gray, and equalize. Just
10886 drawing such images with a stipple can look very odd, so
10887 we're using this method instead. */
10888 XColor *colors = x_to_xcolors (f, img, 1);
10889 XColor *p, *end;
10890 const int h = 15000;
10891 const int l = 30000;
10892
10893 for (p = colors, end = colors + img->width * img->height;
10894 p < end;
10895 ++p)
10896 {
10897 int i = COLOR_INTENSITY (p->red, p->green, p->blue);
10898 int i2 = (0xffff - h - l) * i / 0xffff + l;
10899 p->red = p->green = p->blue = i2;
10900 }
10901
10902 x_from_xcolors (f, img, colors);
10903 }
10904
10905 /* Draw a cross over the disabled image, if we must or if we
10906 should. */
10907 if (dpyinfo->n_planes * dpyinfo->n_cbits < 2 || cross_disabled_images)
10908 {
10909 #if 0 /* TODO: full image support */
10910 Display *dpy = FRAME_X_DISPLAY (f);
10911 GC gc;
10912
10913 gc = XCreateGC (dpy, img->pixmap, 0, NULL);
10914 XSetForeground (dpy, gc, BLACK_PIX_DEFAULT (f));
10915 XDrawLine (dpy, img->pixmap, gc, 0, 0,
10916 img->width - 1, img->height - 1);
10917 XDrawLine (dpy, img->pixmap, gc, 0, img->height - 1,
10918 img->width - 1, 0);
10919 XFreeGC (dpy, gc);
10920
10921 if (img->mask)
10922 {
10923 gc = XCreateGC (dpy, img->mask, 0, NULL);
10924 XSetForeground (dpy, gc, WHITE_PIX_DEFAULT (f));
10925 XDrawLine (dpy, img->mask, gc, 0, 0,
10926 img->width - 1, img->height - 1);
10927 XDrawLine (dpy, img->mask, gc, 0, img->height - 1,
10928 img->width - 1, 0);
10929 XFreeGC (dpy, gc);
10930 }
10931 #endif
10932 }
10933 }
10934
10935
10936 /* Build a mask for image IMG which is used on frame F. FILE is the
10937 name of an image file, for error messages. HOW determines how to
10938 determine the background color of IMG. If it is a list '(R G B)',
10939 with R, G, and B being integers >= 0, take that as the color of the
10940 background. Otherwise, determine the background color of IMG
10941 heuristically. Value is non-zero if successful. */
10942
10943 static int
10944 x_build_heuristic_mask (f, img, how)
10945 struct frame *f;
10946 struct image *img;
10947 Lisp_Object how;
10948 {
10949 #if 0 /* TODO: full image support. */
10950 Display *dpy = FRAME_W32_DISPLAY (f);
10951 XImage *ximg, *mask_img;
10952 int x, y, rc, use_img_background;
10953 unsigned long bg = 0;
10954
10955 if (img->mask)
10956 {
10957 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
10958 img->mask = None;
10959 img->background_transparent_valid = 0;
10960 }
10961
10962 /* Create an image and pixmap serving as mask. */
10963 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
10964 &mask_img, &img->mask);
10965 if (!rc)
10966 return 0;
10967
10968 /* Get the X image of IMG->pixmap. */
10969 ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height,
10970 ~0, ZPixmap);
10971
10972 /* Determine the background color of ximg. If HOW is `(R G B)'
10973 take that as color. Otherwise, use the image's background color. */
10974 use_img_background = 1;
10975
10976 if (CONSP (how))
10977 {
10978 int rgb[3], i;
10979
10980 for (i = 0; i < 3 && CONSP (how) && NATNUMP (XCAR (how)); ++i)
10981 {
10982 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
10983 how = XCDR (how);
10984 }
10985
10986 if (i == 3 && NILP (how))
10987 {
10988 char color_name[30];
10989 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
10990 bg = x_alloc_image_color (f, img, build_string (color_name), 0);
10991 use_img_background = 0;
10992 }
10993 }
10994
10995 if (use_img_background)
10996 bg = four_corners_best (ximg, img->width, img->height);
10997
10998 /* Set all bits in mask_img to 1 whose color in ximg is different
10999 from the background color bg. */
11000 for (y = 0; y < img->height; ++y)
11001 for (x = 0; x < img->width; ++x)
11002 XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg);
11003
11004 /* Fill in the background_transparent field while we have the mask handy. */
11005 image_background_transparent (img, f, mask_img);
11006
11007 /* Put mask_img into img->mask. */
11008 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
11009 x_destroy_x_image (mask_img);
11010 XDestroyImage (ximg);
11011
11012 return 1;
11013 #else
11014 return 0;
11015 #endif
11016 }
11017 #endif
11018 \f
11019 /***********************************************************************
11020 PBM (mono, gray, color)
11021 ***********************************************************************/
11022 #ifdef HAVE_PBM
11023
11024 static int pbm_image_p P_ ((Lisp_Object object));
11025 static int pbm_load P_ ((struct frame *f, struct image *img));
11026 static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
11027
11028 /* The symbol `pbm' identifying images of this type. */
11029
11030 Lisp_Object Qpbm;
11031
11032 /* Indices of image specification fields in gs_format, below. */
11033
11034 enum pbm_keyword_index
11035 {
11036 PBM_TYPE,
11037 PBM_FILE,
11038 PBM_DATA,
11039 PBM_ASCENT,
11040 PBM_MARGIN,
11041 PBM_RELIEF,
11042 PBM_ALGORITHM,
11043 PBM_HEURISTIC_MASK,
11044 PBM_MASK,
11045 PBM_FOREGROUND,
11046 PBM_BACKGROUND,
11047 PBM_LAST
11048 };
11049
11050 /* Vector of image_keyword structures describing the format
11051 of valid user-defined image specifications. */
11052
11053 static struct image_keyword pbm_format[PBM_LAST] =
11054 {
11055 {":type", IMAGE_SYMBOL_VALUE, 1},
11056 {":file", IMAGE_STRING_VALUE, 0},
11057 {":data", IMAGE_STRING_VALUE, 0},
11058 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
11059 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
11060 {":relief", IMAGE_INTEGER_VALUE, 0},
11061 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11062 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11063 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11064 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
11065 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
11066 };
11067
11068 /* Structure describing the image type `pbm'. */
11069
11070 static struct image_type pbm_type =
11071 {
11072 &Qpbm,
11073 pbm_image_p,
11074 pbm_load,
11075 x_clear_image,
11076 NULL
11077 };
11078
11079
11080 /* Return non-zero if OBJECT is a valid PBM image specification. */
11081
11082 static int
11083 pbm_image_p (object)
11084 Lisp_Object object;
11085 {
11086 struct image_keyword fmt[PBM_LAST];
11087
11088 bcopy (pbm_format, fmt, sizeof fmt);
11089
11090 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm)
11091 || (fmt[PBM_ASCENT].count
11092 && XFASTINT (fmt[PBM_ASCENT].value) > 100))
11093 return 0;
11094
11095 /* Must specify either :data or :file. */
11096 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
11097 }
11098
11099
11100 /* Scan a decimal number from *S and return it. Advance *S while
11101 reading the number. END is the end of the string. Value is -1 at
11102 end of input. */
11103
11104 static int
11105 pbm_scan_number (s, end)
11106 unsigned char **s, *end;
11107 {
11108 int c, val = -1;
11109
11110 while (*s < end)
11111 {
11112 /* Skip white-space. */
11113 while (*s < end && (c = *(*s)++, isspace (c)))
11114 ;
11115
11116 if (c == '#')
11117 {
11118 /* Skip comment to end of line. */
11119 while (*s < end && (c = *(*s)++, c != '\n'))
11120 ;
11121 }
11122 else if (isdigit (c))
11123 {
11124 /* Read decimal number. */
11125 val = c - '0';
11126 while (*s < end && (c = *(*s)++, isdigit (c)))
11127 val = 10 * val + c - '0';
11128 break;
11129 }
11130 else
11131 break;
11132 }
11133
11134 return val;
11135 }
11136
11137
11138 /* Read FILE into memory. Value is a pointer to a buffer allocated
11139 with xmalloc holding FILE's contents. Value is null if an error
11140 occured. *SIZE is set to the size of the file. */
11141
11142 static char *
11143 pbm_read_file (file, size)
11144 Lisp_Object file;
11145 int *size;
11146 {
11147 FILE *fp = NULL;
11148 char *buf = NULL;
11149 struct stat st;
11150
11151 if (stat (XSTRING (file)->data, &st) == 0
11152 && (fp = fopen (XSTRING (file)->data, "r")) != NULL
11153 && (buf = (char *) xmalloc (st.st_size),
11154 fread (buf, 1, st.st_size, fp) == st.st_size))
11155 {
11156 *size = st.st_size;
11157 fclose (fp);
11158 }
11159 else
11160 {
11161 if (fp)
11162 fclose (fp);
11163 if (buf)
11164 {
11165 xfree (buf);
11166 buf = NULL;
11167 }
11168 }
11169
11170 return buf;
11171 }
11172
11173
11174 /* Load PBM image IMG for use on frame F. */
11175
11176 static int
11177 pbm_load (f, img)
11178 struct frame *f;
11179 struct image *img;
11180 {
11181 int raw_p, x, y;
11182 int width, height, max_color_idx = 0;
11183 XImage *ximg;
11184 Lisp_Object file, specified_file;
11185 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
11186 struct gcpro gcpro1;
11187 unsigned char *contents = NULL;
11188 unsigned char *end, *p;
11189 int size;
11190
11191 specified_file = image_spec_value (img->spec, QCfile, NULL);
11192 file = Qnil;
11193 GCPRO1 (file);
11194
11195 if (STRINGP (specified_file))
11196 {
11197 file = x_find_image_file (specified_file);
11198 if (!STRINGP (file))
11199 {
11200 image_error ("Cannot find image file `%s'", specified_file, Qnil);
11201 UNGCPRO;
11202 return 0;
11203 }
11204
11205 contents = slurp_file (XSTRING (file)->data, &size);
11206 if (contents == NULL)
11207 {
11208 image_error ("Error reading `%s'", file, Qnil);
11209 UNGCPRO;
11210 return 0;
11211 }
11212
11213 p = contents;
11214 end = contents + size;
11215 }
11216 else
11217 {
11218 Lisp_Object data;
11219 data = image_spec_value (img->spec, QCdata, NULL);
11220 p = XSTRING (data)->data;
11221 end = p + STRING_BYTES (XSTRING (data));
11222 }
11223
11224 /* Check magic number. */
11225 if (end - p < 2 || *p++ != 'P')
11226 {
11227 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
11228 error:
11229 xfree (contents);
11230 UNGCPRO;
11231 return 0;
11232 }
11233
11234 switch (*p++)
11235 {
11236 case '1':
11237 raw_p = 0, type = PBM_MONO;
11238 break;
11239
11240 case '2':
11241 raw_p = 0, type = PBM_GRAY;
11242 break;
11243
11244 case '3':
11245 raw_p = 0, type = PBM_COLOR;
11246 break;
11247
11248 case '4':
11249 raw_p = 1, type = PBM_MONO;
11250 break;
11251
11252 case '5':
11253 raw_p = 1, type = PBM_GRAY;
11254 break;
11255
11256 case '6':
11257 raw_p = 1, type = PBM_COLOR;
11258 break;
11259
11260 default:
11261 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
11262 goto error;
11263 }
11264
11265 /* Read width, height, maximum color-component. Characters
11266 starting with `#' up to the end of a line are ignored. */
11267 width = pbm_scan_number (&p, end);
11268 height = pbm_scan_number (&p, end);
11269
11270 if (type != PBM_MONO)
11271 {
11272 max_color_idx = pbm_scan_number (&p, end);
11273 if (raw_p && max_color_idx > 255)
11274 max_color_idx = 255;
11275 }
11276
11277 if (width < 0
11278 || height < 0
11279 || (type != PBM_MONO && max_color_idx < 0))
11280 goto error;
11281
11282 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
11283 goto error;
11284
11285 #if 0 /* TODO: color tables. */
11286 /* Initialize the color hash table. */
11287 init_color_table ();
11288 #endif
11289
11290 if (type == PBM_MONO)
11291 {
11292 int c = 0, g;
11293 struct image_keyword fmt[PBM_LAST];
11294 unsigned long fg = FRAME_FOREGROUND_PIXEL (f);
11295 unsigned long bg = FRAME_BACKGROUND_PIXEL (f);
11296
11297 /* Parse the image specification. */
11298 bcopy (pbm_format, fmt, sizeof fmt);
11299 parse_image_spec (img->spec, fmt, PBM_LAST, Qpbm);
11300
11301 /* Get foreground and background colors, maybe allocate colors. */
11302 if (fmt[PBM_FOREGROUND].count
11303 && STRINGP (fmt[PBM_FOREGROUND].value))
11304 fg = x_alloc_image_color (f, img, fmt[PBM_FOREGROUND].value, fg);
11305 if (fmt[PBM_BACKGROUND].count
11306 && STRINGP (fmt[PBM_BACKGROUND].value))
11307 {
11308 bg = x_alloc_image_color (f, img, fmt[PBM_BACKGROUND].value, bg);
11309 img->background = bg;
11310 img->background_valid = 1;
11311 }
11312
11313 for (y = 0; y < height; ++y)
11314 for (x = 0; x < width; ++x)
11315 {
11316 if (raw_p)
11317 {
11318 if ((x & 7) == 0)
11319 c = *p++;
11320 g = c & 0x80;
11321 c <<= 1;
11322 }
11323 else
11324 g = pbm_scan_number (&p, end);
11325
11326 XPutPixel (ximg, x, y, g ? fg : bg);
11327 }
11328 }
11329 else
11330 {
11331 for (y = 0; y < height; ++y)
11332 for (x = 0; x < width; ++x)
11333 {
11334 int r, g, b;
11335
11336 if (type == PBM_GRAY)
11337 r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
11338 else if (raw_p)
11339 {
11340 r = *p++;
11341 g = *p++;
11342 b = *p++;
11343 }
11344 else
11345 {
11346 r = pbm_scan_number (&p, end);
11347 g = pbm_scan_number (&p, end);
11348 b = pbm_scan_number (&p, end);
11349 }
11350
11351 if (r < 0 || g < 0 || b < 0)
11352 {
11353 x_destroy_x_image (ximg);
11354 image_error ("Invalid pixel value in image `%s'",
11355 img->spec, Qnil);
11356 goto error;
11357 }
11358
11359 /* RGB values are now in the range 0..max_color_idx.
11360 Scale this to the range 0..0xff supported by W32. */
11361 r = (int) ((double) r * 255 / max_color_idx);
11362 g = (int) ((double) g * 255 / max_color_idx);
11363 b = (int) ((double) b * 255 / max_color_idx);
11364 XPutPixel (ximg, x, y,
11365 #if 0 /* TODO: color tables. */
11366 lookup_rgb_color (f, r, g, b));
11367 #else
11368 PALETTERGB (r, g, b));
11369 #endif
11370 }
11371 }
11372
11373 #if 0 /* TODO: color tables. */
11374 /* Store in IMG->colors the colors allocated for the image, and
11375 free the color table. */
11376 img->colors = colors_in_color_table (&img->ncolors);
11377 free_color_table ();
11378 #endif
11379 /* Maybe fill in the background field while we have ximg handy. */
11380 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
11381 IMAGE_BACKGROUND (img, f, ximg);
11382
11383 /* Put the image into a pixmap. */
11384 x_put_x_image (f, ximg, img->pixmap, width, height);
11385 x_destroy_x_image (ximg);
11386
11387 img->width = width;
11388 img->height = height;
11389
11390 UNGCPRO;
11391 xfree (contents);
11392 return 1;
11393 }
11394 #endif /* HAVE_PBM */
11395
11396 \f
11397 /***********************************************************************
11398 PNG
11399 ***********************************************************************/
11400
11401 #if HAVE_PNG
11402
11403 #include <png.h>
11404
11405 /* Function prototypes. */
11406
11407 static int png_image_p P_ ((Lisp_Object object));
11408 static int png_load P_ ((struct frame *f, struct image *img));
11409
11410 /* The symbol `png' identifying images of this type. */
11411
11412 Lisp_Object Qpng;
11413
11414 /* Indices of image specification fields in png_format, below. */
11415
11416 enum png_keyword_index
11417 {
11418 PNG_TYPE,
11419 PNG_DATA,
11420 PNG_FILE,
11421 PNG_ASCENT,
11422 PNG_MARGIN,
11423 PNG_RELIEF,
11424 PNG_ALGORITHM,
11425 PNG_HEURISTIC_MASK,
11426 PNG_MASK,
11427 PNG_BACKGROUND,
11428 PNG_LAST
11429 };
11430
11431 /* Vector of image_keyword structures describing the format
11432 of valid user-defined image specifications. */
11433
11434 static struct image_keyword png_format[PNG_LAST] =
11435 {
11436 {":type", IMAGE_SYMBOL_VALUE, 1},
11437 {":data", IMAGE_STRING_VALUE, 0},
11438 {":file", IMAGE_STRING_VALUE, 0},
11439 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
11440 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
11441 {":relief", IMAGE_INTEGER_VALUE, 0},
11442 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11443 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11444 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11445 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
11446 };
11447
11448 /* Structure describing the image type `png'. */
11449
11450 static struct image_type png_type =
11451 {
11452 &Qpng,
11453 png_image_p,
11454 png_load,
11455 x_clear_image,
11456 NULL
11457 };
11458
11459
11460 /* Return non-zero if OBJECT is a valid PNG image specification. */
11461
11462 static int
11463 png_image_p (object)
11464 Lisp_Object object;
11465 {
11466 struct image_keyword fmt[PNG_LAST];
11467 bcopy (png_format, fmt, sizeof fmt);
11468
11469 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng)
11470 || (fmt[PNG_ASCENT].count
11471 && XFASTINT (fmt[PNG_ASCENT].value) > 100))
11472 return 0;
11473
11474 /* Must specify either the :data or :file keyword. */
11475 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
11476 }
11477
11478
11479 /* Error and warning handlers installed when the PNG library
11480 is initialized. */
11481
11482 static void
11483 my_png_error (png_ptr, msg)
11484 png_struct *png_ptr;
11485 char *msg;
11486 {
11487 xassert (png_ptr != NULL);
11488 image_error ("PNG error: %s", build_string (msg), Qnil);
11489 longjmp (png_ptr->jmpbuf, 1);
11490 }
11491
11492
11493 static void
11494 my_png_warning (png_ptr, msg)
11495 png_struct *png_ptr;
11496 char *msg;
11497 {
11498 xassert (png_ptr != NULL);
11499 image_error ("PNG warning: %s", build_string (msg), Qnil);
11500 }
11501
11502 /* Memory source for PNG decoding. */
11503
11504 struct png_memory_storage
11505 {
11506 unsigned char *bytes; /* The data */
11507 size_t len; /* How big is it? */
11508 int index; /* Where are we? */
11509 };
11510
11511
11512 /* Function set as reader function when reading PNG image from memory.
11513 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
11514 bytes from the input to DATA. */
11515
11516 static void
11517 png_read_from_memory (png_ptr, data, length)
11518 png_structp png_ptr;
11519 png_bytep data;
11520 png_size_t length;
11521 {
11522 struct png_memory_storage *tbr
11523 = (struct png_memory_storage *) png_get_io_ptr (png_ptr);
11524
11525 if (length > tbr->len - tbr->index)
11526 png_error (png_ptr, "Read error");
11527
11528 bcopy (tbr->bytes + tbr->index, data, length);
11529 tbr->index = tbr->index + length;
11530 }
11531
11532 /* Load PNG image IMG for use on frame F. Value is non-zero if
11533 successful. */
11534
11535 static int
11536 png_load (f, img)
11537 struct frame *f;
11538 struct image *img;
11539 {
11540 Lisp_Object file, specified_file;
11541 Lisp_Object specified_data;
11542 int x, y, i;
11543 XImage *ximg, *mask_img = NULL;
11544 struct gcpro gcpro1;
11545 png_struct *png_ptr = NULL;
11546 png_info *info_ptr = NULL, *end_info = NULL;
11547 FILE *volatile fp = NULL;
11548 png_byte sig[8];
11549 png_byte *volatile pixels = NULL;
11550 png_byte **volatile rows = NULL;
11551 png_uint_32 width, height;
11552 int bit_depth, color_type, interlace_type;
11553 png_byte channels;
11554 png_uint_32 row_bytes;
11555 int transparent_p;
11556 char *gamma_str;
11557 double screen_gamma, image_gamma;
11558 int intent;
11559 struct png_memory_storage tbr; /* Data to be read */
11560
11561 /* Find out what file to load. */
11562 specified_file = image_spec_value (img->spec, QCfile, NULL);
11563 specified_data = image_spec_value (img->spec, QCdata, NULL);
11564 file = Qnil;
11565 GCPRO1 (file);
11566
11567 if (NILP (specified_data))
11568 {
11569 file = x_find_image_file (specified_file);
11570 if (!STRINGP (file))
11571 {
11572 image_error ("Cannot find image file `%s'", specified_file, Qnil);
11573 UNGCPRO;
11574 return 0;
11575 }
11576
11577 /* Open the image file. */
11578 fp = fopen (XSTRING (file)->data, "rb");
11579 if (!fp)
11580 {
11581 image_error ("Cannot open image file `%s'", file, Qnil);
11582 UNGCPRO;
11583 fclose (fp);
11584 return 0;
11585 }
11586
11587 /* Check PNG signature. */
11588 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
11589 || !png_check_sig (sig, sizeof sig))
11590 {
11591 image_error ("Not a PNG file:` %s'", file, Qnil);
11592 UNGCPRO;
11593 fclose (fp);
11594 return 0;
11595 }
11596 }
11597 else
11598 {
11599 /* Read from memory. */
11600 tbr.bytes = XSTRING (specified_data)->data;
11601 tbr.len = STRING_BYTES (XSTRING (specified_data));
11602 tbr.index = 0;
11603
11604 /* Check PNG signature. */
11605 if (tbr.len < sizeof sig
11606 || !png_check_sig (tbr.bytes, sizeof sig))
11607 {
11608 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
11609 UNGCPRO;
11610 return 0;
11611 }
11612
11613 /* Need to skip past the signature. */
11614 tbr.bytes += sizeof (sig);
11615 }
11616
11617 /* Initialize read and info structs for PNG lib. */
11618 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
11619 my_png_error, my_png_warning);
11620 if (!png_ptr)
11621 {
11622 if (fp) fclose (fp);
11623 UNGCPRO;
11624 return 0;
11625 }
11626
11627 info_ptr = png_create_info_struct (png_ptr);
11628 if (!info_ptr)
11629 {
11630 png_destroy_read_struct (&png_ptr, NULL, NULL);
11631 if (fp) fclose (fp);
11632 UNGCPRO;
11633 return 0;
11634 }
11635
11636 end_info = png_create_info_struct (png_ptr);
11637 if (!end_info)
11638 {
11639 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
11640 if (fp) fclose (fp);
11641 UNGCPRO;
11642 return 0;
11643 }
11644
11645 /* Set error jump-back. We come back here when the PNG library
11646 detects an error. */
11647 if (setjmp (png_ptr->jmpbuf))
11648 {
11649 error:
11650 if (png_ptr)
11651 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
11652 xfree (pixels);
11653 xfree (rows);
11654 if (fp) fclose (fp);
11655 UNGCPRO;
11656 return 0;
11657 }
11658
11659 /* Read image info. */
11660 if (!NILP (specified_data))
11661 png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
11662 else
11663 png_init_io (png_ptr, fp);
11664
11665 png_set_sig_bytes (png_ptr, sizeof sig);
11666 png_read_info (png_ptr, info_ptr);
11667 png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
11668 &interlace_type, NULL, NULL);
11669
11670 /* If image contains simply transparency data, we prefer to
11671 construct a clipping mask. */
11672 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
11673 transparent_p = 1;
11674 else
11675 transparent_p = 0;
11676
11677 /* This function is easier to write if we only have to handle
11678 one data format: RGB or RGBA with 8 bits per channel. Let's
11679 transform other formats into that format. */
11680
11681 /* Strip more than 8 bits per channel. */
11682 if (bit_depth == 16)
11683 png_set_strip_16 (png_ptr);
11684
11685 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
11686 if available. */
11687 png_set_expand (png_ptr);
11688
11689 /* Convert grayscale images to RGB. */
11690 if (color_type == PNG_COLOR_TYPE_GRAY
11691 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
11692 png_set_gray_to_rgb (png_ptr);
11693
11694 /* The value 2.2 is a guess for PC monitors from PNG example.c. */
11695 gamma_str = getenv ("SCREEN_GAMMA");
11696 screen_gamma = gamma_str ? atof (gamma_str) : 2.2;
11697
11698 /* Tell the PNG lib to handle gamma correction for us. */
11699
11700 #if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
11701 if (png_get_sRGB (png_ptr, info_ptr, &intent))
11702 /* There is a special chunk in the image specifying the gamma. */
11703 png_set_sRGB (png_ptr, info_ptr, intent);
11704 else
11705 #endif
11706 if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
11707 /* Image contains gamma information. */
11708 png_set_gamma (png_ptr, screen_gamma, image_gamma);
11709 else
11710 /* Use a default of 0.5 for the image gamma. */
11711 png_set_gamma (png_ptr, screen_gamma, 0.5);
11712
11713 /* Handle alpha channel by combining the image with a background
11714 color. Do this only if a real alpha channel is supplied. For
11715 simple transparency, we prefer a clipping mask. */
11716 if (!transparent_p)
11717 {
11718 png_color_16 *image_background;
11719 Lisp_Object specified_bg
11720 = image_spec_value (img->spec, QCbackground, NULL);
11721
11722
11723 if (STRINGP (specified_bg))
11724 /* The user specified `:background', use that. */
11725 {
11726 COLORREF color;
11727 if (w32_defined_color (f, XSTRING (specified_bg)->data, &color, 0))
11728 {
11729 png_color_16 user_bg;
11730
11731 bzero (&user_bg, sizeof user_bg);
11732 user_bg.red = color.red;
11733 user_bg.green = color.green;
11734 user_bg.blue = color.blue;
11735
11736 png_set_background (png_ptr, &user_bg,
11737 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
11738 }
11739 }
11740 else if (png_get_bKGD (png_ptr, info_ptr, &image_background))
11741 /* Image contains a background color with which to
11742 combine the image. */
11743 png_set_background (png_ptr, image_background,
11744 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
11745 else
11746 {
11747 /* Image does not contain a background color with which
11748 to combine the image data via an alpha channel. Use
11749 the frame's background instead. */
11750 XColor color;
11751 Colormap cmap;
11752 png_color_16 frame_background;
11753
11754 cmap = FRAME_X_COLORMAP (f);
11755 color.pixel = FRAME_BACKGROUND_PIXEL (f);
11756 x_query_color (f, &color);
11757
11758 bzero (&frame_background, sizeof frame_background);
11759 frame_background.red = color.red;
11760 frame_background.green = color.green;
11761 frame_background.blue = color.blue;
11762
11763 png_set_background (png_ptr, &frame_background,
11764 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
11765 }
11766 }
11767
11768 /* Update info structure. */
11769 png_read_update_info (png_ptr, info_ptr);
11770
11771 /* Get number of channels. Valid values are 1 for grayscale images
11772 and images with a palette, 2 for grayscale images with transparency
11773 information (alpha channel), 3 for RGB images, and 4 for RGB
11774 images with alpha channel, i.e. RGBA. If conversions above were
11775 sufficient we should only have 3 or 4 channels here. */
11776 channels = png_get_channels (png_ptr, info_ptr);
11777 xassert (channels == 3 || channels == 4);
11778
11779 /* Number of bytes needed for one row of the image. */
11780 row_bytes = png_get_rowbytes (png_ptr, info_ptr);
11781
11782 /* Allocate memory for the image. */
11783 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
11784 rows = (png_byte **) xmalloc (height * sizeof *rows);
11785 for (i = 0; i < height; ++i)
11786 rows[i] = pixels + i * row_bytes;
11787
11788 /* Read the entire image. */
11789 png_read_image (png_ptr, rows);
11790 png_read_end (png_ptr, info_ptr);
11791 if (fp)
11792 {
11793 fclose (fp);
11794 fp = NULL;
11795 }
11796
11797 /* Create the X image and pixmap. */
11798 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
11799 &img->pixmap))
11800 goto error;
11801
11802 /* Create an image and pixmap serving as mask if the PNG image
11803 contains an alpha channel. */
11804 if (channels == 4
11805 && !transparent_p
11806 && !x_create_x_image_and_pixmap (f, width, height, 1,
11807 &mask_img, &img->mask))
11808 {
11809 x_destroy_x_image (ximg);
11810 XFreePixmap (FRAME_W32_DISPLAY (f), img->pixmap);
11811 img->pixmap = 0;
11812 goto error;
11813 }
11814
11815 /* Fill the X image and mask from PNG data. */
11816 init_color_table ();
11817
11818 for (y = 0; y < height; ++y)
11819 {
11820 png_byte *p = rows[y];
11821
11822 for (x = 0; x < width; ++x)
11823 {
11824 unsigned r, g, b;
11825
11826 r = *p++ << 8;
11827 g = *p++ << 8;
11828 b = *p++ << 8;
11829 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
11830
11831 /* An alpha channel, aka mask channel, associates variable
11832 transparency with an image. Where other image formats
11833 support binary transparency---fully transparent or fully
11834 opaque---PNG allows up to 254 levels of partial transparency.
11835 The PNG library implements partial transparency by combining
11836 the image with a specified background color.
11837
11838 I'm not sure how to handle this here nicely: because the
11839 background on which the image is displayed may change, for
11840 real alpha channel support, it would be necessary to create
11841 a new image for each possible background.
11842
11843 What I'm doing now is that a mask is created if we have
11844 boolean transparency information. Otherwise I'm using
11845 the frame's background color to combine the image with. */
11846
11847 if (channels == 4)
11848 {
11849 if (mask_img)
11850 XPutPixel (mask_img, x, y, *p > 0);
11851 ++p;
11852 }
11853 }
11854 }
11855
11856 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
11857 /* Set IMG's background color from the PNG image, unless the user
11858 overrode it. */
11859 {
11860 png_color_16 *bg;
11861 if (png_get_bKGD (png_ptr, info_ptr, &bg))
11862 {
11863 img->background = lookup_rgb_color (f, bg->red, bg->green, bg->blue);
11864 img->background_valid = 1;
11865 }
11866 }
11867
11868 /* Remember colors allocated for this image. */
11869 img->colors = colors_in_color_table (&img->ncolors);
11870 free_color_table ();
11871
11872 /* Clean up. */
11873 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
11874 xfree (rows);
11875 xfree (pixels);
11876
11877 img->width = width;
11878 img->height = height;
11879
11880 /* Maybe fill in the background field while we have ximg handy. */
11881 IMAGE_BACKGROUND (img, f, ximg);
11882
11883 /* Put the image into the pixmap, then free the X image and its buffer. */
11884 x_put_x_image (f, ximg, img->pixmap, width, height);
11885 x_destroy_x_image (ximg);
11886
11887 /* Same for the mask. */
11888 if (mask_img)
11889 {
11890 /* Fill in the background_transparent field while we have the mask
11891 handy. */
11892 image_background_transparent (img, f, mask_img);
11893
11894 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
11895 x_destroy_x_image (mask_img);
11896 }
11897
11898 UNGCPRO;
11899 return 1;
11900 }
11901
11902 #endif /* HAVE_PNG != 0 */
11903
11904
11905 \f
11906 /***********************************************************************
11907 JPEG
11908 ***********************************************************************/
11909
11910 #if HAVE_JPEG
11911
11912 /* Work around a warning about HAVE_STDLIB_H being redefined in
11913 jconfig.h. */
11914 #ifdef HAVE_STDLIB_H
11915 #define HAVE_STDLIB_H_1
11916 #undef HAVE_STDLIB_H
11917 #endif /* HAVE_STLIB_H */
11918
11919 #include <jpeglib.h>
11920 #include <jerror.h>
11921 #include <setjmp.h>
11922
11923 #ifdef HAVE_STLIB_H_1
11924 #define HAVE_STDLIB_H 1
11925 #endif
11926
11927 static int jpeg_image_p P_ ((Lisp_Object object));
11928 static int jpeg_load P_ ((struct frame *f, struct image *img));
11929
11930 /* The symbol `jpeg' identifying images of this type. */
11931
11932 Lisp_Object Qjpeg;
11933
11934 /* Indices of image specification fields in gs_format, below. */
11935
11936 enum jpeg_keyword_index
11937 {
11938 JPEG_TYPE,
11939 JPEG_DATA,
11940 JPEG_FILE,
11941 JPEG_ASCENT,
11942 JPEG_MARGIN,
11943 JPEG_RELIEF,
11944 JPEG_ALGORITHM,
11945 JPEG_HEURISTIC_MASK,
11946 JPEG_MASK,
11947 JPEG_BACKGROUND,
11948 JPEG_LAST
11949 };
11950
11951 /* Vector of image_keyword structures describing the format
11952 of valid user-defined image specifications. */
11953
11954 static struct image_keyword jpeg_format[JPEG_LAST] =
11955 {
11956 {":type", IMAGE_SYMBOL_VALUE, 1},
11957 {":data", IMAGE_STRING_VALUE, 0},
11958 {":file", IMAGE_STRING_VALUE, 0},
11959 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
11960 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
11961 {":relief", IMAGE_INTEGER_VALUE, 0},
11962 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11963 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11964 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11965 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
11966 };
11967
11968 /* Structure describing the image type `jpeg'. */
11969
11970 static struct image_type jpeg_type =
11971 {
11972 &Qjpeg,
11973 jpeg_image_p,
11974 jpeg_load,
11975 x_clear_image,
11976 NULL
11977 };
11978
11979
11980 /* Return non-zero if OBJECT is a valid JPEG image specification. */
11981
11982 static int
11983 jpeg_image_p (object)
11984 Lisp_Object object;
11985 {
11986 struct image_keyword fmt[JPEG_LAST];
11987
11988 bcopy (jpeg_format, fmt, sizeof fmt);
11989
11990 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg)
11991 || (fmt[JPEG_ASCENT].count
11992 && XFASTINT (fmt[JPEG_ASCENT].value) > 100))
11993 return 0;
11994
11995 /* Must specify either the :data or :file keyword. */
11996 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
11997 }
11998
11999
12000 struct my_jpeg_error_mgr
12001 {
12002 struct jpeg_error_mgr pub;
12003 jmp_buf setjmp_buffer;
12004 };
12005
12006 static void
12007 my_error_exit (cinfo)
12008 j_common_ptr cinfo;
12009 {
12010 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
12011 longjmp (mgr->setjmp_buffer, 1);
12012 }
12013
12014 /* Init source method for JPEG data source manager. Called by
12015 jpeg_read_header() before any data is actually read. See
12016 libjpeg.doc from the JPEG lib distribution. */
12017
12018 static void
12019 our_init_source (cinfo)
12020 j_decompress_ptr cinfo;
12021 {
12022 }
12023
12024
12025 /* Fill input buffer method for JPEG data source manager. Called
12026 whenever more data is needed. We read the whole image in one step,
12027 so this only adds a fake end of input marker at the end. */
12028
12029 static boolean
12030 our_fill_input_buffer (cinfo)
12031 j_decompress_ptr cinfo;
12032 {
12033 /* Insert a fake EOI marker. */
12034 struct jpeg_source_mgr *src = cinfo->src;
12035 static JOCTET buffer[2];
12036
12037 buffer[0] = (JOCTET) 0xFF;
12038 buffer[1] = (JOCTET) JPEG_EOI;
12039
12040 src->next_input_byte = buffer;
12041 src->bytes_in_buffer = 2;
12042 return TRUE;
12043 }
12044
12045
12046 /* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
12047 is the JPEG data source manager. */
12048
12049 static void
12050 our_skip_input_data (cinfo, num_bytes)
12051 j_decompress_ptr cinfo;
12052 long num_bytes;
12053 {
12054 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
12055
12056 if (src)
12057 {
12058 if (num_bytes > src->bytes_in_buffer)
12059 ERREXIT (cinfo, JERR_INPUT_EOF);
12060
12061 src->bytes_in_buffer -= num_bytes;
12062 src->next_input_byte += num_bytes;
12063 }
12064 }
12065
12066
12067 /* Method to terminate data source. Called by
12068 jpeg_finish_decompress() after all data has been processed. */
12069
12070 static void
12071 our_term_source (cinfo)
12072 j_decompress_ptr cinfo;
12073 {
12074 }
12075
12076
12077 /* Set up the JPEG lib for reading an image from DATA which contains
12078 LEN bytes. CINFO is the decompression info structure created for
12079 reading the image. */
12080
12081 static void
12082 jpeg_memory_src (cinfo, data, len)
12083 j_decompress_ptr cinfo;
12084 JOCTET *data;
12085 unsigned int len;
12086 {
12087 struct jpeg_source_mgr *src;
12088
12089 if (cinfo->src == NULL)
12090 {
12091 /* First time for this JPEG object? */
12092 cinfo->src = (struct jpeg_source_mgr *)
12093 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
12094 sizeof (struct jpeg_source_mgr));
12095 src = (struct jpeg_source_mgr *) cinfo->src;
12096 src->next_input_byte = data;
12097 }
12098
12099 src = (struct jpeg_source_mgr *) cinfo->src;
12100 src->init_source = our_init_source;
12101 src->fill_input_buffer = our_fill_input_buffer;
12102 src->skip_input_data = our_skip_input_data;
12103 src->resync_to_restart = jpeg_resync_to_restart; /* Use default method. */
12104 src->term_source = our_term_source;
12105 src->bytes_in_buffer = len;
12106 src->next_input_byte = data;
12107 }
12108
12109
12110 /* Load image IMG for use on frame F. Patterned after example.c
12111 from the JPEG lib. */
12112
12113 static int
12114 jpeg_load (f, img)
12115 struct frame *f;
12116 struct image *img;
12117 {
12118 struct jpeg_decompress_struct cinfo;
12119 struct my_jpeg_error_mgr mgr;
12120 Lisp_Object file, specified_file;
12121 Lisp_Object specified_data;
12122 FILE * volatile fp = NULL;
12123 JSAMPARRAY buffer;
12124 int row_stride, x, y;
12125 XImage *ximg = NULL;
12126 int rc;
12127 unsigned long *colors;
12128 int width, height;
12129 struct gcpro gcpro1;
12130
12131 /* Open the JPEG file. */
12132 specified_file = image_spec_value (img->spec, QCfile, NULL);
12133 specified_data = image_spec_value (img->spec, QCdata, NULL);
12134 file = Qnil;
12135 GCPRO1 (file);
12136
12137 if (NILP (specified_data))
12138 {
12139 file = x_find_image_file (specified_file);
12140 if (!STRINGP (file))
12141 {
12142 image_error ("Cannot find image file `%s'", specified_file, Qnil);
12143 UNGCPRO;
12144 return 0;
12145 }
12146
12147 fp = fopen (XSTRING (file)->data, "r");
12148 if (fp == NULL)
12149 {
12150 image_error ("Cannot open `%s'", file, Qnil);
12151 UNGCPRO;
12152 return 0;
12153 }
12154 }
12155
12156 /* Customize libjpeg's error handling to call my_error_exit when an
12157 error is detected. This function will perform a longjmp. */
12158 cinfo.err = jpeg_std_error (&mgr.pub);
12159 mgr.pub.error_exit = my_error_exit;
12160
12161 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
12162 {
12163 if (rc == 1)
12164 {
12165 /* Called from my_error_exit. Display a JPEG error. */
12166 char buffer[JMSG_LENGTH_MAX];
12167 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
12168 image_error ("Error reading JPEG image `%s': %s", img->spec,
12169 build_string (buffer));
12170 }
12171
12172 /* Close the input file and destroy the JPEG object. */
12173 if (fp)
12174 fclose (fp);
12175 jpeg_destroy_decompress (&cinfo);
12176
12177 /* If we already have an XImage, free that. */
12178 x_destroy_x_image (ximg);
12179
12180 /* Free pixmap and colors. */
12181 x_clear_image (f, img);
12182
12183 UNGCPRO;
12184 return 0;
12185 }
12186
12187 /* Create the JPEG decompression object. Let it read from fp.
12188 Read the JPEG image header. */
12189 jpeg_create_decompress (&cinfo);
12190
12191 if (NILP (specified_data))
12192 jpeg_stdio_src (&cinfo, fp);
12193 else
12194 jpeg_memory_src (&cinfo, XSTRING (specified_data)->data,
12195 STRING_BYTES (XSTRING (specified_data)));
12196
12197 jpeg_read_header (&cinfo, TRUE);
12198
12199 /* Customize decompression so that color quantization will be used.
12200 Start decompression. */
12201 cinfo.quantize_colors = TRUE;
12202 jpeg_start_decompress (&cinfo);
12203 width = img->width = cinfo.output_width;
12204 height = img->height = cinfo.output_height;
12205
12206 /* Create X image and pixmap. */
12207 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
12208 &img->pixmap))
12209 longjmp (mgr.setjmp_buffer, 2);
12210
12211 /* Allocate colors. When color quantization is used,
12212 cinfo.actual_number_of_colors has been set with the number of
12213 colors generated, and cinfo.colormap is a two-dimensional array
12214 of color indices in the range 0..cinfo.actual_number_of_colors.
12215 No more than 255 colors will be generated. */
12216 {
12217 int i, ir, ig, ib;
12218
12219 if (cinfo.out_color_components > 2)
12220 ir = 0, ig = 1, ib = 2;
12221 else if (cinfo.out_color_components > 1)
12222 ir = 0, ig = 1, ib = 0;
12223 else
12224 ir = 0, ig = 0, ib = 0;
12225
12226 /* Use the color table mechanism because it handles colors that
12227 cannot be allocated nicely. Such colors will be replaced with
12228 a default color, and we don't have to care about which colors
12229 can be freed safely, and which can't. */
12230 init_color_table ();
12231 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
12232 * sizeof *colors);
12233
12234 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
12235 {
12236 /* Multiply RGB values with 255 because X expects RGB values
12237 in the range 0..0xffff. */
12238 int r = cinfo.colormap[ir][i] << 8;
12239 int g = cinfo.colormap[ig][i] << 8;
12240 int b = cinfo.colormap[ib][i] << 8;
12241 colors[i] = lookup_rgb_color (f, r, g, b);
12242 }
12243
12244 /* Remember those colors actually allocated. */
12245 img->colors = colors_in_color_table (&img->ncolors);
12246 free_color_table ();
12247 }
12248
12249 /* Read pixels. */
12250 row_stride = width * cinfo.output_components;
12251 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
12252 row_stride, 1);
12253 for (y = 0; y < height; ++y)
12254 {
12255 jpeg_read_scanlines (&cinfo, buffer, 1);
12256 for (x = 0; x < cinfo.output_width; ++x)
12257 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
12258 }
12259
12260 /* Clean up. */
12261 jpeg_finish_decompress (&cinfo);
12262 jpeg_destroy_decompress (&cinfo);
12263 if (fp)
12264 fclose (fp);
12265
12266 /* Maybe fill in the background field while we have ximg handy. */
12267 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
12268 IMAGE_BACKGROUND (img, f, ximg);
12269
12270 /* Put the image into the pixmap. */
12271 x_put_x_image (f, ximg, img->pixmap, width, height);
12272 x_destroy_x_image (ximg);
12273 UNBLOCK_INPUT;
12274 UNGCPRO;
12275 return 1;
12276 }
12277
12278 #endif /* HAVE_JPEG */
12279
12280
12281 \f
12282 /***********************************************************************
12283 TIFF
12284 ***********************************************************************/
12285
12286 #if HAVE_TIFF
12287
12288 #include <tiffio.h>
12289
12290 static int tiff_image_p P_ ((Lisp_Object object));
12291 static int tiff_load P_ ((struct frame *f, struct image *img));
12292
12293 /* The symbol `tiff' identifying images of this type. */
12294
12295 Lisp_Object Qtiff;
12296
12297 /* Indices of image specification fields in tiff_format, below. */
12298
12299 enum tiff_keyword_index
12300 {
12301 TIFF_TYPE,
12302 TIFF_DATA,
12303 TIFF_FILE,
12304 TIFF_ASCENT,
12305 TIFF_MARGIN,
12306 TIFF_RELIEF,
12307 TIFF_ALGORITHM,
12308 TIFF_HEURISTIC_MASK,
12309 TIFF_MASK,
12310 TIFF_BACKGROUND,
12311 TIFF_LAST
12312 };
12313
12314 /* Vector of image_keyword structures describing the format
12315 of valid user-defined image specifications. */
12316
12317 static struct image_keyword tiff_format[TIFF_LAST] =
12318 {
12319 {":type", IMAGE_SYMBOL_VALUE, 1},
12320 {":data", IMAGE_STRING_VALUE, 0},
12321 {":file", IMAGE_STRING_VALUE, 0},
12322 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
12323 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
12324 {":relief", IMAGE_INTEGER_VALUE, 0},
12325 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12326 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12327 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12328 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
12329 };
12330
12331 /* Structure describing the image type `tiff'. */
12332
12333 static struct image_type tiff_type =
12334 {
12335 &Qtiff,
12336 tiff_image_p,
12337 tiff_load,
12338 x_clear_image,
12339 NULL
12340 };
12341
12342
12343 /* Return non-zero if OBJECT is a valid TIFF image specification. */
12344
12345 static int
12346 tiff_image_p (object)
12347 Lisp_Object object;
12348 {
12349 struct image_keyword fmt[TIFF_LAST];
12350 bcopy (tiff_format, fmt, sizeof fmt);
12351
12352 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff)
12353 || (fmt[TIFF_ASCENT].count
12354 && XFASTINT (fmt[TIFF_ASCENT].value) > 100))
12355 return 0;
12356
12357 /* Must specify either the :data or :file keyword. */
12358 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
12359 }
12360
12361
12362 /* Reading from a memory buffer for TIFF images Based on the PNG
12363 memory source, but we have to provide a lot of extra functions.
12364 Blah.
12365
12366 We really only need to implement read and seek, but I am not
12367 convinced that the TIFF library is smart enough not to destroy
12368 itself if we only hand it the function pointers we need to
12369 override. */
12370
12371 typedef struct
12372 {
12373 unsigned char *bytes;
12374 size_t len;
12375 int index;
12376 }
12377 tiff_memory_source;
12378
12379 static size_t
12380 tiff_read_from_memory (data, buf, size)
12381 thandle_t data;
12382 tdata_t buf;
12383 tsize_t size;
12384 {
12385 tiff_memory_source *src = (tiff_memory_source *) data;
12386
12387 if (size > src->len - src->index)
12388 return (size_t) -1;
12389 bcopy (src->bytes + src->index, buf, size);
12390 src->index += size;
12391 return size;
12392 }
12393
12394 static size_t
12395 tiff_write_from_memory (data, buf, size)
12396 thandle_t data;
12397 tdata_t buf;
12398 tsize_t size;
12399 {
12400 return (size_t) -1;
12401 }
12402
12403 static toff_t
12404 tiff_seek_in_memory (data, off, whence)
12405 thandle_t data;
12406 toff_t off;
12407 int whence;
12408 {
12409 tiff_memory_source *src = (tiff_memory_source *) data;
12410 int idx;
12411
12412 switch (whence)
12413 {
12414 case SEEK_SET: /* Go from beginning of source. */
12415 idx = off;
12416 break;
12417
12418 case SEEK_END: /* Go from end of source. */
12419 idx = src->len + off;
12420 break;
12421
12422 case SEEK_CUR: /* Go from current position. */
12423 idx = src->index + off;
12424 break;
12425
12426 default: /* Invalid `whence'. */
12427 return -1;
12428 }
12429
12430 if (idx > src->len || idx < 0)
12431 return -1;
12432
12433 src->index = idx;
12434 return src->index;
12435 }
12436
12437 static int
12438 tiff_close_memory (data)
12439 thandle_t data;
12440 {
12441 /* NOOP */
12442 return 0;
12443 }
12444
12445 static int
12446 tiff_mmap_memory (data, pbase, psize)
12447 thandle_t data;
12448 tdata_t *pbase;
12449 toff_t *psize;
12450 {
12451 /* It is already _IN_ memory. */
12452 return 0;
12453 }
12454
12455 static void
12456 tiff_unmap_memory (data, base, size)
12457 thandle_t data;
12458 tdata_t base;
12459 toff_t size;
12460 {
12461 /* We don't need to do this. */
12462 }
12463
12464 static toff_t
12465 tiff_size_of_memory (data)
12466 thandle_t data;
12467 {
12468 return ((tiff_memory_source *) data)->len;
12469 }
12470
12471
12472 static void
12473 tiff_error_handler (title, format, ap)
12474 const char *title, *format;
12475 va_list ap;
12476 {
12477 char buf[512];
12478 int len;
12479
12480 len = sprintf (buf, "TIFF error: %s ", title);
12481 vsprintf (buf + len, format, ap);
12482 add_to_log (buf, Qnil, Qnil);
12483 }
12484
12485
12486 static void
12487 tiff_warning_handler (title, format, ap)
12488 const char *title, *format;
12489 va_list ap;
12490 {
12491 char buf[512];
12492 int len;
12493
12494 len = sprintf (buf, "TIFF warning: %s ", title);
12495 vsprintf (buf + len, format, ap);
12496 add_to_log (buf, Qnil, Qnil);
12497 }
12498
12499
12500 /* Load TIFF image IMG for use on frame F. Value is non-zero if
12501 successful. */
12502
12503 static int
12504 tiff_load (f, img)
12505 struct frame *f;
12506 struct image *img;
12507 {
12508 Lisp_Object file, specified_file;
12509 Lisp_Object specified_data;
12510 TIFF *tiff;
12511 int width, height, x, y;
12512 uint32 *buf;
12513 int rc;
12514 XImage *ximg;
12515 struct gcpro gcpro1;
12516 tiff_memory_source memsrc;
12517
12518 specified_file = image_spec_value (img->spec, QCfile, NULL);
12519 specified_data = image_spec_value (img->spec, QCdata, NULL);
12520 file = Qnil;
12521 GCPRO1 (file);
12522
12523 TIFFSetErrorHandler (tiff_error_handler);
12524 TIFFSetWarningHandler (tiff_warning_handler);
12525
12526 if (NILP (specified_data))
12527 {
12528 /* Read from a file */
12529 file = x_find_image_file (specified_file);
12530 if (!STRINGP (file))
12531 {
12532 image_error ("Cannot find image file `%s'", file, Qnil);
12533 UNGCPRO;
12534 return 0;
12535 }
12536
12537 /* Try to open the image file. */
12538 tiff = TIFFOpen (XSTRING (file)->data, "r");
12539 if (tiff == NULL)
12540 {
12541 image_error ("Cannot open `%s'", file, Qnil);
12542 UNGCPRO;
12543 return 0;
12544 }
12545 }
12546 else
12547 {
12548 /* Memory source! */
12549 memsrc.bytes = XSTRING (specified_data)->data;
12550 memsrc.len = STRING_BYTES (XSTRING (specified_data));
12551 memsrc.index = 0;
12552
12553 tiff = TIFFClientOpen ("memory_source", "r", &memsrc,
12554 (TIFFReadWriteProc) tiff_read_from_memory,
12555 (TIFFReadWriteProc) tiff_write_from_memory,
12556 tiff_seek_in_memory,
12557 tiff_close_memory,
12558 tiff_size_of_memory,
12559 tiff_mmap_memory,
12560 tiff_unmap_memory);
12561
12562 if (!tiff)
12563 {
12564 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
12565 UNGCPRO;
12566 return 0;
12567 }
12568 }
12569
12570 /* Get width and height of the image, and allocate a raster buffer
12571 of width x height 32-bit values. */
12572 TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
12573 TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
12574 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
12575
12576 rc = TIFFReadRGBAImage (tiff, width, height, buf, 0);
12577 TIFFClose (tiff);
12578 if (!rc)
12579 {
12580 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
12581 xfree (buf);
12582 UNGCPRO;
12583 return 0;
12584 }
12585
12586 /* Create the X image and pixmap. */
12587 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
12588 {
12589 xfree (buf);
12590 UNGCPRO;
12591 return 0;
12592 }
12593
12594 /* Initialize the color table. */
12595 init_color_table ();
12596
12597 /* Process the pixel raster. Origin is in the lower-left corner. */
12598 for (y = 0; y < height; ++y)
12599 {
12600 uint32 *row = buf + y * width;
12601
12602 for (x = 0; x < width; ++x)
12603 {
12604 uint32 abgr = row[x];
12605 int r = TIFFGetR (abgr) << 8;
12606 int g = TIFFGetG (abgr) << 8;
12607 int b = TIFFGetB (abgr) << 8;
12608 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
12609 }
12610 }
12611
12612 /* Remember the colors allocated for the image. Free the color table. */
12613 img->colors = colors_in_color_table (&img->ncolors);
12614 free_color_table ();
12615
12616 img->width = width;
12617 img->height = height;
12618
12619 /* Maybe fill in the background field while we have ximg handy. */
12620 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
12621 IMAGE_BACKGROUND (img, f, ximg);
12622
12623 /* Put the image into the pixmap, then free the X image and its buffer. */
12624 x_put_x_image (f, ximg, img->pixmap, width, height);
12625 x_destroy_x_image (ximg);
12626 xfree (buf);
12627
12628 UNGCPRO;
12629 return 1;
12630 }
12631
12632 #endif /* HAVE_TIFF != 0 */
12633
12634
12635 \f
12636 /***********************************************************************
12637 GIF
12638 ***********************************************************************/
12639
12640 #if HAVE_GIF
12641
12642 #include <gif_lib.h>
12643
12644 static int gif_image_p P_ ((Lisp_Object object));
12645 static int gif_load P_ ((struct frame *f, struct image *img));
12646
12647 /* The symbol `gif' identifying images of this type. */
12648
12649 Lisp_Object Qgif;
12650
12651 /* Indices of image specification fields in gif_format, below. */
12652
12653 enum gif_keyword_index
12654 {
12655 GIF_TYPE,
12656 GIF_DATA,
12657 GIF_FILE,
12658 GIF_ASCENT,
12659 GIF_MARGIN,
12660 GIF_RELIEF,
12661 GIF_ALGORITHM,
12662 GIF_HEURISTIC_MASK,
12663 GIF_MASK,
12664 GIF_IMAGE,
12665 GIF_BACKGROUND,
12666 GIF_LAST
12667 };
12668
12669 /* Vector of image_keyword structures describing the format
12670 of valid user-defined image specifications. */
12671
12672 static struct image_keyword gif_format[GIF_LAST] =
12673 {
12674 {":type", IMAGE_SYMBOL_VALUE, 1},
12675 {":data", IMAGE_STRING_VALUE, 0},
12676 {":file", IMAGE_STRING_VALUE, 0},
12677 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
12678 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
12679 {":relief", IMAGE_INTEGER_VALUE, 0},
12680 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12681 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12682 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12683 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
12684 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
12685 };
12686
12687 /* Structure describing the image type `gif'. */
12688
12689 static struct image_type gif_type =
12690 {
12691 &Qgif,
12692 gif_image_p,
12693 gif_load,
12694 x_clear_image,
12695 NULL
12696 };
12697
12698 /* Return non-zero if OBJECT is a valid GIF image specification. */
12699
12700 static int
12701 gif_image_p (object)
12702 Lisp_Object object;
12703 {
12704 struct image_keyword fmt[GIF_LAST];
12705 bcopy (gif_format, fmt, sizeof fmt);
12706
12707 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif)
12708 || (fmt[GIF_ASCENT].count
12709 && XFASTINT (fmt[GIF_ASCENT].value) > 100))
12710 return 0;
12711
12712 /* Must specify either the :data or :file keyword. */
12713 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
12714 }
12715
12716 /* Reading a GIF image from memory
12717 Based on the PNG memory stuff to a certain extent. */
12718
12719 typedef struct
12720 {
12721 unsigned char *bytes;
12722 size_t len;
12723 int index;
12724 }
12725 gif_memory_source;
12726
12727 /* Make the current memory source available to gif_read_from_memory.
12728 It's done this way because not all versions of libungif support
12729 a UserData field in the GifFileType structure. */
12730 static gif_memory_source *current_gif_memory_src;
12731
12732 static int
12733 gif_read_from_memory (file, buf, len)
12734 GifFileType *file;
12735 GifByteType *buf;
12736 int len;
12737 {
12738 gif_memory_source *src = current_gif_memory_src;
12739
12740 if (len > src->len - src->index)
12741 return -1;
12742
12743 bcopy (src->bytes + src->index, buf, len);
12744 src->index += len;
12745 return len;
12746 }
12747
12748
12749 /* Load GIF image IMG for use on frame F. Value is non-zero if
12750 successful. */
12751
12752 static int
12753 gif_load (f, img)
12754 struct frame *f;
12755 struct image *img;
12756 {
12757 Lisp_Object file, specified_file;
12758 Lisp_Object specified_data;
12759 int rc, width, height, x, y, i;
12760 XImage *ximg;
12761 ColorMapObject *gif_color_map;
12762 unsigned long pixel_colors[256];
12763 GifFileType *gif;
12764 struct gcpro gcpro1;
12765 Lisp_Object image;
12766 int ino, image_left, image_top, image_width, image_height;
12767 gif_memory_source memsrc;
12768 unsigned char *raster;
12769
12770 specified_file = image_spec_value (img->spec, QCfile, NULL);
12771 specified_data = image_spec_value (img->spec, QCdata, NULL);
12772 file = Qnil;
12773 GCPRO1 (file);
12774
12775 if (NILP (specified_data))
12776 {
12777 file = x_find_image_file (specified_file);
12778 if (!STRINGP (file))
12779 {
12780 image_error ("Cannot find image file `%s'", specified_file, Qnil);
12781 UNGCPRO;
12782 return 0;
12783 }
12784
12785 /* Open the GIF file. */
12786 gif = DGifOpenFileName (XSTRING (file)->data);
12787 if (gif == NULL)
12788 {
12789 image_error ("Cannot open `%s'", file, Qnil);
12790 UNGCPRO;
12791 return 0;
12792 }
12793 }
12794 else
12795 {
12796 /* Read from memory! */
12797 current_gif_memory_src = &memsrc;
12798 memsrc.bytes = XSTRING (specified_data)->data;
12799 memsrc.len = STRING_BYTES (XSTRING (specified_data));
12800 memsrc.index = 0;
12801
12802 gif = DGifOpen(&memsrc, gif_read_from_memory);
12803 if (!gif)
12804 {
12805 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
12806 UNGCPRO;
12807 return 0;
12808 }
12809 }
12810
12811 /* Read entire contents. */
12812 rc = DGifSlurp (gif);
12813 if (rc == GIF_ERROR)
12814 {
12815 image_error ("Error reading `%s'", img->spec, Qnil);
12816 DGifCloseFile (gif);
12817 UNGCPRO;
12818 return 0;
12819 }
12820
12821 image = image_spec_value (img->spec, QCindex, NULL);
12822 ino = INTEGERP (image) ? XFASTINT (image) : 0;
12823 if (ino >= gif->ImageCount)
12824 {
12825 image_error ("Invalid image number `%s' in image `%s'",
12826 image, img->spec);
12827 DGifCloseFile (gif);
12828 UNGCPRO;
12829 return 0;
12830 }
12831
12832 width = img->width = gif->SWidth;
12833 height = img->height = gif->SHeight;
12834
12835 /* Create the X image and pixmap. */
12836 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
12837 {
12838 DGifCloseFile (gif);
12839 UNGCPRO;
12840 return 0;
12841 }
12842
12843 /* Allocate colors. */
12844 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
12845 if (!gif_color_map)
12846 gif_color_map = gif->SColorMap;
12847 init_color_table ();
12848 bzero (pixel_colors, sizeof pixel_colors);
12849
12850 for (i = 0; i < gif_color_map->ColorCount; ++i)
12851 {
12852 int r = gif_color_map->Colors[i].Red << 8;
12853 int g = gif_color_map->Colors[i].Green << 8;
12854 int b = gif_color_map->Colors[i].Blue << 8;
12855 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
12856 }
12857
12858 img->colors = colors_in_color_table (&img->ncolors);
12859 free_color_table ();
12860
12861 /* Clear the part of the screen image that are not covered by
12862 the image from the GIF file. Full animated GIF support
12863 requires more than can be done here (see the gif89 spec,
12864 disposal methods). Let's simply assume that the part
12865 not covered by a sub-image is in the frame's background color. */
12866 image_top = gif->SavedImages[ino].ImageDesc.Top;
12867 image_left = gif->SavedImages[ino].ImageDesc.Left;
12868 image_width = gif->SavedImages[ino].ImageDesc.Width;
12869 image_height = gif->SavedImages[ino].ImageDesc.Height;
12870
12871 for (y = 0; y < image_top; ++y)
12872 for (x = 0; x < width; ++x)
12873 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12874
12875 for (y = image_top + image_height; y < height; ++y)
12876 for (x = 0; x < width; ++x)
12877 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12878
12879 for (y = image_top; y < image_top + image_height; ++y)
12880 {
12881 for (x = 0; x < image_left; ++x)
12882 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12883 for (x = image_left + image_width; x < width; ++x)
12884 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12885 }
12886
12887 /* Read the GIF image into the X image. We use a local variable
12888 `raster' here because RasterBits below is a char *, and invites
12889 problems with bytes >= 0x80. */
12890 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
12891
12892 if (gif->SavedImages[ino].ImageDesc.Interlace)
12893 {
12894 static int interlace_start[] = {0, 4, 2, 1};
12895 static int interlace_increment[] = {8, 8, 4, 2};
12896 int pass;
12897 int row = interlace_start[0];
12898
12899 pass = 0;
12900
12901 for (y = 0; y < image_height; y++)
12902 {
12903 if (row >= image_height)
12904 {
12905 row = interlace_start[++pass];
12906 while (row >= image_height)
12907 row = interlace_start[++pass];
12908 }
12909
12910 for (x = 0; x < image_width; x++)
12911 {
12912 int i = raster[(y * image_width) + x];
12913 XPutPixel (ximg, x + image_left, row + image_top,
12914 pixel_colors[i]);
12915 }
12916
12917 row += interlace_increment[pass];
12918 }
12919 }
12920 else
12921 {
12922 for (y = 0; y < image_height; ++y)
12923 for (x = 0; x < image_width; ++x)
12924 {
12925 int i = raster[y* image_width + x];
12926 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
12927 }
12928 }
12929
12930 DGifCloseFile (gif);
12931
12932 /* Maybe fill in the background field while we have ximg handy. */
12933 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
12934 IMAGE_BACKGROUND (img, f, ximg);
12935
12936 /* Put the image into the pixmap, then free the X image and its buffer. */
12937 x_put_x_image (f, ximg, img->pixmap, width, height);
12938 x_destroy_x_image (ximg);
12939
12940 UNGCPRO;
12941 return 1;
12942 }
12943
12944 #endif /* HAVE_GIF != 0 */
12945
12946
12947 \f
12948 /***********************************************************************
12949 Ghostscript
12950 ***********************************************************************/
12951
12952 Lisp_Object Qpostscript;
12953
12954 #ifdef HAVE_GHOSTSCRIPT
12955 static int gs_image_p P_ ((Lisp_Object object));
12956 static int gs_load P_ ((struct frame *f, struct image *img));
12957 static void gs_clear_image P_ ((struct frame *f, struct image *img));
12958
12959 /* The symbol `postscript' identifying images of this type. */
12960
12961 /* Keyword symbols. */
12962
12963 Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
12964
12965 /* Indices of image specification fields in gs_format, below. */
12966
12967 enum gs_keyword_index
12968 {
12969 GS_TYPE,
12970 GS_PT_WIDTH,
12971 GS_PT_HEIGHT,
12972 GS_FILE,
12973 GS_LOADER,
12974 GS_BOUNDING_BOX,
12975 GS_ASCENT,
12976 GS_MARGIN,
12977 GS_RELIEF,
12978 GS_ALGORITHM,
12979 GS_HEURISTIC_MASK,
12980 GS_MASK,
12981 GS_BACKGROUND,
12982 GS_LAST
12983 };
12984
12985 /* Vector of image_keyword structures describing the format
12986 of valid user-defined image specifications. */
12987
12988 static struct image_keyword gs_format[GS_LAST] =
12989 {
12990 {":type", IMAGE_SYMBOL_VALUE, 1},
12991 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
12992 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
12993 {":file", IMAGE_STRING_VALUE, 1},
12994 {":loader", IMAGE_FUNCTION_VALUE, 0},
12995 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
12996 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
12997 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
12998 {":relief", IMAGE_INTEGER_VALUE, 0},
12999 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
13000 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
13001 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
13002 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
13003 };
13004
13005 /* Structure describing the image type `ghostscript'. */
13006
13007 static struct image_type gs_type =
13008 {
13009 &Qpostscript,
13010 gs_image_p,
13011 gs_load,
13012 gs_clear_image,
13013 NULL
13014 };
13015
13016
13017 /* Free X resources of Ghostscript image IMG which is used on frame F. */
13018
13019 static void
13020 gs_clear_image (f, img)
13021 struct frame *f;
13022 struct image *img;
13023 {
13024 /* IMG->data.ptr_val may contain a recorded colormap. */
13025 xfree (img->data.ptr_val);
13026 x_clear_image (f, img);
13027 }
13028
13029
13030 /* Return non-zero if OBJECT is a valid Ghostscript image
13031 specification. */
13032
13033 static int
13034 gs_image_p (object)
13035 Lisp_Object object;
13036 {
13037 struct image_keyword fmt[GS_LAST];
13038 Lisp_Object tem;
13039 int i;
13040
13041 bcopy (gs_format, fmt, sizeof fmt);
13042
13043 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript)
13044 || (fmt[GS_ASCENT].count
13045 && XFASTINT (fmt[GS_ASCENT].value) > 100))
13046 return 0;
13047
13048 /* Bounding box must be a list or vector containing 4 integers. */
13049 tem = fmt[GS_BOUNDING_BOX].value;
13050 if (CONSP (tem))
13051 {
13052 for (i = 0; i < 4; ++i, tem = XCDR (tem))
13053 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
13054 return 0;
13055 if (!NILP (tem))
13056 return 0;
13057 }
13058 else if (VECTORP (tem))
13059 {
13060 if (XVECTOR (tem)->size != 4)
13061 return 0;
13062 for (i = 0; i < 4; ++i)
13063 if (!INTEGERP (XVECTOR (tem)->contents[i]))
13064 return 0;
13065 }
13066 else
13067 return 0;
13068
13069 return 1;
13070 }
13071
13072
13073 /* Load Ghostscript image IMG for use on frame F. Value is non-zero
13074 if successful. */
13075
13076 static int
13077 gs_load (f, img)
13078 struct frame *f;
13079 struct image *img;
13080 {
13081 char buffer[100];
13082 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
13083 struct gcpro gcpro1, gcpro2;
13084 Lisp_Object frame;
13085 double in_width, in_height;
13086 Lisp_Object pixel_colors = Qnil;
13087
13088 /* Compute pixel size of pixmap needed from the given size in the
13089 image specification. Sizes in the specification are in pt. 1 pt
13090 = 1/72 in, xdpi and ydpi are stored in the frame's X display
13091 info. */
13092 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
13093 in_width = XFASTINT (pt_width) / 72.0;
13094 img->width = in_width * FRAME_W32_DISPLAY_INFO (f)->resx;
13095 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
13096 in_height = XFASTINT (pt_height) / 72.0;
13097 img->height = in_height * FRAME_W32_DISPLAY_INFO (f)->resy;
13098
13099 /* Create the pixmap. */
13100 BLOCK_INPUT;
13101 xassert (img->pixmap == 0);
13102 img->pixmap = XCreatePixmap (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
13103 img->width, img->height,
13104 one_w32_display_info.n_cbits);
13105 UNBLOCK_INPUT;
13106
13107 if (!img->pixmap)
13108 {
13109 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
13110 return 0;
13111 }
13112
13113 /* Call the loader to fill the pixmap. It returns a process object
13114 if successful. We do not record_unwind_protect here because
13115 other places in redisplay like calling window scroll functions
13116 don't either. Let the Lisp loader use `unwind-protect' instead. */
13117 GCPRO2 (window_and_pixmap_id, pixel_colors);
13118
13119 sprintf (buffer, "%lu %lu",
13120 (unsigned long) FRAME_W32_WINDOW (f),
13121 (unsigned long) img->pixmap);
13122 window_and_pixmap_id = build_string (buffer);
13123
13124 sprintf (buffer, "%lu %lu",
13125 FRAME_FOREGROUND_PIXEL (f),
13126 FRAME_BACKGROUND_PIXEL (f));
13127 pixel_colors = build_string (buffer);
13128
13129 XSETFRAME (frame, f);
13130 loader = image_spec_value (img->spec, QCloader, NULL);
13131 if (NILP (loader))
13132 loader = intern ("gs-load-image");
13133
13134 img->data.lisp_val = call6 (loader, frame, img->spec,
13135 make_number (img->width),
13136 make_number (img->height),
13137 window_and_pixmap_id,
13138 pixel_colors);
13139 UNGCPRO;
13140 return PROCESSP (img->data.lisp_val);
13141 }
13142
13143
13144 /* Kill the Ghostscript process that was started to fill PIXMAP on
13145 frame F. Called from XTread_socket when receiving an event
13146 telling Emacs that Ghostscript has finished drawing. */
13147
13148 void
13149 x_kill_gs_process (pixmap, f)
13150 Pixmap pixmap;
13151 struct frame *f;
13152 {
13153 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
13154 int class, i;
13155 struct image *img;
13156
13157 /* Find the image containing PIXMAP. */
13158 for (i = 0; i < c->used; ++i)
13159 if (c->images[i]->pixmap == pixmap)
13160 break;
13161
13162 /* Should someone in between have cleared the image cache, for
13163 instance, give up. */
13164 if (i == c->used)
13165 return;
13166
13167 /* Kill the GS process. We should have found PIXMAP in the image
13168 cache and its image should contain a process object. */
13169 img = c->images[i];
13170 xassert (PROCESSP (img->data.lisp_val));
13171 Fkill_process (img->data.lisp_val, Qnil);
13172 img->data.lisp_val = Qnil;
13173
13174 /* On displays with a mutable colormap, figure out the colors
13175 allocated for the image by looking at the pixels of an XImage for
13176 img->pixmap. */
13177 class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
13178 if (class != StaticColor && class != StaticGray && class != TrueColor)
13179 {
13180 XImage *ximg;
13181
13182 BLOCK_INPUT;
13183
13184 /* Try to get an XImage for img->pixmep. */
13185 ximg = XGetImage (FRAME_W32_DISPLAY (f), img->pixmap,
13186 0, 0, img->width, img->height, ~0, ZPixmap);
13187 if (ximg)
13188 {
13189 int x, y;
13190
13191 /* Initialize the color table. */
13192 init_color_table ();
13193
13194 /* For each pixel of the image, look its color up in the
13195 color table. After having done so, the color table will
13196 contain an entry for each color used by the image. */
13197 for (y = 0; y < img->height; ++y)
13198 for (x = 0; x < img->width; ++x)
13199 {
13200 unsigned long pixel = XGetPixel (ximg, x, y);
13201 lookup_pixel_color (f, pixel);
13202 }
13203
13204 /* Record colors in the image. Free color table and XImage. */
13205 img->colors = colors_in_color_table (&img->ncolors);
13206 free_color_table ();
13207 XDestroyImage (ximg);
13208
13209 #if 0 /* This doesn't seem to be the case. If we free the colors
13210 here, we get a BadAccess later in x_clear_image when
13211 freeing the colors. */
13212 /* We have allocated colors once, but Ghostscript has also
13213 allocated colors on behalf of us. So, to get the
13214 reference counts right, free them once. */
13215 if (img->ncolors)
13216 x_free_colors (FRAME_W32_DISPLAY (f), cmap,
13217 img->colors, img->ncolors, 0);
13218 #endif
13219 }
13220 else
13221 image_error ("Cannot get X image of `%s'; colors will not be freed",
13222 img->spec, Qnil);
13223
13224 UNBLOCK_INPUT;
13225 }
13226
13227 /* Now that we have the pixmap, compute mask and transform the
13228 image if requested. */
13229 BLOCK_INPUT;
13230 postprocess_image (f, img);
13231 UNBLOCK_INPUT;
13232 }
13233
13234 #endif /* HAVE_GHOSTSCRIPT */
13235
13236 \f
13237 /***********************************************************************
13238 Window properties
13239 ***********************************************************************/
13240
13241 DEFUN ("x-change-window-property", Fx_change_window_property,
13242 Sx_change_window_property, 2, 3, 0,
13243 doc: /* Change window property PROP to VALUE on the X window of FRAME.
13244 PROP and VALUE must be strings. FRAME nil or omitted means use the
13245 selected frame. Value is VALUE. */)
13246 (prop, value, frame)
13247 Lisp_Object frame, prop, value;
13248 {
13249 #if 0 /* TODO : port window properties to W32 */
13250 struct frame *f = check_x_frame (frame);
13251 Atom prop_atom;
13252
13253 CHECK_STRING (prop);
13254 CHECK_STRING (value);
13255
13256 BLOCK_INPUT;
13257 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
13258 XChangeProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
13259 prop_atom, XA_STRING, 8, PropModeReplace,
13260 XSTRING (value)->data, XSTRING (value)->size);
13261
13262 /* Make sure the property is set when we return. */
13263 XFlush (FRAME_W32_DISPLAY (f));
13264 UNBLOCK_INPUT;
13265
13266 #endif /* TODO */
13267
13268 return value;
13269 }
13270
13271
13272 DEFUN ("x-delete-window-property", Fx_delete_window_property,
13273 Sx_delete_window_property, 1, 2, 0,
13274 doc: /* Remove window property PROP from X window of FRAME.
13275 FRAME nil or omitted means use the selected frame. Value is PROP. */)
13276 (prop, frame)
13277 Lisp_Object prop, frame;
13278 {
13279 #if 0 /* TODO : port window properties to W32 */
13280
13281 struct frame *f = check_x_frame (frame);
13282 Atom prop_atom;
13283
13284 CHECK_STRING (prop);
13285 BLOCK_INPUT;
13286 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
13287 XDeleteProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), prop_atom);
13288
13289 /* Make sure the property is removed when we return. */
13290 XFlush (FRAME_W32_DISPLAY (f));
13291 UNBLOCK_INPUT;
13292 #endif /* TODO */
13293
13294 return prop;
13295 }
13296
13297
13298 DEFUN ("x-window-property", Fx_window_property, Sx_window_property,
13299 1, 2, 0,
13300 doc: /* Value is the value of window property PROP on FRAME.
13301 If FRAME is nil or omitted, use the selected frame. Value is nil
13302 if FRAME hasn't a property with name PROP or if PROP has no string
13303 value. */)
13304 (prop, frame)
13305 Lisp_Object prop, frame;
13306 {
13307 #if 0 /* TODO : port window properties to W32 */
13308
13309 struct frame *f = check_x_frame (frame);
13310 Atom prop_atom;
13311 int rc;
13312 Lisp_Object prop_value = Qnil;
13313 char *tmp_data = NULL;
13314 Atom actual_type;
13315 int actual_format;
13316 unsigned long actual_size, bytes_remaining;
13317
13318 CHECK_STRING (prop);
13319 BLOCK_INPUT;
13320 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
13321 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
13322 prop_atom, 0, 0, False, XA_STRING,
13323 &actual_type, &actual_format, &actual_size,
13324 &bytes_remaining, (unsigned char **) &tmp_data);
13325 if (rc == Success)
13326 {
13327 int size = bytes_remaining;
13328
13329 XFree (tmp_data);
13330 tmp_data = NULL;
13331
13332 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
13333 prop_atom, 0, bytes_remaining,
13334 False, XA_STRING,
13335 &actual_type, &actual_format,
13336 &actual_size, &bytes_remaining,
13337 (unsigned char **) &tmp_data);
13338 if (rc == Success)
13339 prop_value = make_string (tmp_data, size);
13340
13341 XFree (tmp_data);
13342 }
13343
13344 UNBLOCK_INPUT;
13345
13346 return prop_value;
13347
13348 #endif /* TODO */
13349 return Qnil;
13350 }
13351
13352
13353 \f
13354 /***********************************************************************
13355 Busy cursor
13356 ***********************************************************************/
13357
13358 /* If non-null, an asynchronous timer that, when it expires, displays
13359 an hourglass cursor on all frames. */
13360
13361 static struct atimer *hourglass_atimer;
13362
13363 /* Non-zero means an hourglass cursor is currently shown. */
13364
13365 static int hourglass_shown_p;
13366
13367 /* Number of seconds to wait before displaying an hourglass cursor. */
13368
13369 static Lisp_Object Vhourglass_delay;
13370
13371 /* Default number of seconds to wait before displaying an hourglass
13372 cursor. */
13373
13374 #define DEFAULT_HOURGLASS_DELAY 1
13375
13376 /* Function prototypes. */
13377
13378 static void show_hourglass P_ ((struct atimer *));
13379 static void hide_hourglass P_ ((void));
13380
13381
13382 /* Cancel a currently active hourglass timer, and start a new one. */
13383
13384 void
13385 start_hourglass ()
13386 {
13387 #if 0 /* TODO: cursor shape changes. */
13388 EMACS_TIME delay;
13389 int secs, usecs = 0;
13390
13391 cancel_hourglass ();
13392
13393 if (INTEGERP (Vhourglass_delay)
13394 && XINT (Vhourglass_delay) > 0)
13395 secs = XFASTINT (Vhourglass_delay);
13396 else if (FLOATP (Vhourglass_delay)
13397 && XFLOAT_DATA (Vhourglass_delay) > 0)
13398 {
13399 Lisp_Object tem;
13400 tem = Ftruncate (Vhourglass_delay, Qnil);
13401 secs = XFASTINT (tem);
13402 usecs = (XFLOAT_DATA (Vhourglass_delay) - secs) * 1000000;
13403 }
13404 else
13405 secs = DEFAULT_HOURGLASS_DELAY;
13406
13407 EMACS_SET_SECS_USECS (delay, secs, usecs);
13408 hourglass_atimer = start_atimer (ATIMER_RELATIVE, delay,
13409 show_hourglass, NULL);
13410 #endif
13411 }
13412
13413
13414 /* Cancel the hourglass cursor timer if active, hide an hourglass
13415 cursor if shown. */
13416
13417 void
13418 cancel_hourglass ()
13419 {
13420 if (hourglass_atimer)
13421 {
13422 cancel_atimer (hourglass_atimer);
13423 hourglass_atimer = NULL;
13424 }
13425
13426 if (hourglass_shown_p)
13427 hide_hourglass ();
13428 }
13429
13430
13431 /* Timer function of hourglass_atimer. TIMER is equal to
13432 hourglass_atimer.
13433
13434 Display an hourglass cursor on all frames by mapping the frames'
13435 hourglass_window. Set the hourglass_p flag in the frames'
13436 output_data.x structure to indicate that an hourglass cursor is
13437 shown on the frames. */
13438
13439 static void
13440 show_hourglass (timer)
13441 struct atimer *timer;
13442 {
13443 #if 0 /* TODO: cursor shape changes. */
13444 /* The timer implementation will cancel this timer automatically
13445 after this function has run. Set hourglass_atimer to null
13446 so that we know the timer doesn't have to be canceled. */
13447 hourglass_atimer = NULL;
13448
13449 if (!hourglass_shown_p)
13450 {
13451 Lisp_Object rest, frame;
13452
13453 BLOCK_INPUT;
13454
13455 FOR_EACH_FRAME (rest, frame)
13456 if (FRAME_W32_P (XFRAME (frame)))
13457 {
13458 struct frame *f = XFRAME (frame);
13459
13460 f->output_data.w32->hourglass_p = 1;
13461
13462 if (!f->output_data.w32->hourglass_window)
13463 {
13464 unsigned long mask = CWCursor;
13465 XSetWindowAttributes attrs;
13466
13467 attrs.cursor = f->output_data.w32->hourglass_cursor;
13468
13469 f->output_data.w32->hourglass_window
13470 = XCreateWindow (FRAME_X_DISPLAY (f),
13471 FRAME_OUTER_WINDOW (f),
13472 0, 0, 32000, 32000, 0, 0,
13473 InputOnly,
13474 CopyFromParent,
13475 mask, &attrs);
13476 }
13477
13478 XMapRaised (FRAME_X_DISPLAY (f),
13479 f->output_data.w32->hourglass_window);
13480 XFlush (FRAME_X_DISPLAY (f));
13481 }
13482
13483 hourglass_shown_p = 1;
13484 UNBLOCK_INPUT;
13485 }
13486 #endif
13487 }
13488
13489
13490 /* Hide the hourglass cursor on all frames, if it is currently shown. */
13491
13492 static void
13493 hide_hourglass ()
13494 {
13495 #if 0 /* TODO: cursor shape changes. */
13496 if (hourglass_shown_p)
13497 {
13498 Lisp_Object rest, frame;
13499
13500 BLOCK_INPUT;
13501 FOR_EACH_FRAME (rest, frame)
13502 {
13503 struct frame *f = XFRAME (frame);
13504
13505 if (FRAME_W32_P (f)
13506 /* Watch out for newly created frames. */
13507 && f->output_data.x->hourglass_window)
13508 {
13509 XUnmapWindow (FRAME_X_DISPLAY (f),
13510 f->output_data.x->hourglass_window);
13511 /* Sync here because XTread_socket looks at the
13512 hourglass_p flag that is reset to zero below. */
13513 XSync (FRAME_X_DISPLAY (f), False);
13514 f->output_data.x->hourglass_p = 0;
13515 }
13516 }
13517
13518 hourglass_shown_p = 0;
13519 UNBLOCK_INPUT;
13520 }
13521 #endif
13522 }
13523
13524
13525 \f
13526 /***********************************************************************
13527 Tool tips
13528 ***********************************************************************/
13529
13530 static Lisp_Object x_create_tip_frame P_ ((struct w32_display_info *,
13531 Lisp_Object, Lisp_Object));
13532 static void compute_tip_xy P_ ((struct frame *, Lisp_Object, Lisp_Object,
13533 Lisp_Object, int, int, int *, int *));
13534
13535 /* The frame of a currently visible tooltip. */
13536
13537 Lisp_Object tip_frame;
13538
13539 /* If non-nil, a timer started that hides the last tooltip when it
13540 fires. */
13541
13542 Lisp_Object tip_timer;
13543 Window tip_window;
13544
13545 /* If non-nil, a vector of 3 elements containing the last args
13546 with which x-show-tip was called. See there. */
13547
13548 Lisp_Object last_show_tip_args;
13549
13550 /* Maximum size for tooltips; a cons (COLUMNS . ROWS). */
13551
13552 Lisp_Object Vx_max_tooltip_size;
13553
13554
13555 static Lisp_Object
13556 unwind_create_tip_frame (frame)
13557 Lisp_Object frame;
13558 {
13559 Lisp_Object deleted;
13560
13561 deleted = unwind_create_frame (frame);
13562 if (EQ (deleted, Qt))
13563 {
13564 tip_window = NULL;
13565 tip_frame = Qnil;
13566 }
13567
13568 return deleted;
13569 }
13570
13571
13572 /* Create a frame for a tooltip on the display described by DPYINFO.
13573 PARMS is a list of frame parameters. TEXT is the string to
13574 display in the tip frame. Value is the frame.
13575
13576 Note that functions called here, esp. x_default_parameter can
13577 signal errors, for instance when a specified color name is
13578 undefined. We have to make sure that we're in a consistent state
13579 when this happens. */
13580
13581 static Lisp_Object
13582 x_create_tip_frame (dpyinfo, parms, text)
13583 struct w32_display_info *dpyinfo;
13584 Lisp_Object parms, text;
13585 {
13586 struct frame *f;
13587 Lisp_Object frame, tem;
13588 Lisp_Object name;
13589 long window_prompting = 0;
13590 int width, height;
13591 int count = BINDING_STACK_SIZE ();
13592 struct gcpro gcpro1, gcpro2, gcpro3;
13593 struct kboard *kb;
13594 int face_change_count_before = face_change_count;
13595 Lisp_Object buffer;
13596 struct buffer *old_buffer;
13597
13598 check_w32 ();
13599
13600 /* Use this general default value to start with until we know if
13601 this frame has a specified name. */
13602 Vx_resource_name = Vinvocation_name;
13603
13604 #ifdef MULTI_KBOARD
13605 kb = dpyinfo->kboard;
13606 #else
13607 kb = &the_only_kboard;
13608 #endif
13609
13610 /* Get the name of the frame to use for resource lookup. */
13611 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
13612 if (!STRINGP (name)
13613 && !EQ (name, Qunbound)
13614 && !NILP (name))
13615 error ("Invalid frame name--not a string or nil");
13616 Vx_resource_name = name;
13617
13618 frame = Qnil;
13619 GCPRO3 (parms, name, frame);
13620 /* Make a frame without minibuffer nor mode-line. */
13621 f = make_frame (0);
13622 f->wants_modeline = 0;
13623 XSETFRAME (frame, f);
13624
13625 buffer = Fget_buffer_create (build_string (" *tip*"));
13626 Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer);
13627 old_buffer = current_buffer;
13628 set_buffer_internal_1 (XBUFFER (buffer));
13629 current_buffer->truncate_lines = Qnil;
13630 Ferase_buffer ();
13631 Finsert (1, &text);
13632 set_buffer_internal_1 (old_buffer);
13633
13634 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
13635 record_unwind_protect (unwind_create_tip_frame, frame);
13636
13637 /* By setting the output method, we're essentially saying that
13638 the frame is live, as per FRAME_LIVE_P. If we get a signal
13639 from this point on, x_destroy_window might screw up reference
13640 counts etc. */
13641 f->output_method = output_w32;
13642 f->output_data.w32 =
13643 (struct w32_output *) xmalloc (sizeof (struct w32_output));
13644 bzero (f->output_data.w32, sizeof (struct w32_output));
13645
13646 FRAME_FONTSET (f) = -1;
13647 f->icon_name = Qnil;
13648
13649 #if 0 /* GLYPH_DEBUG TODO: image support. */
13650 image_cache_refcount = FRAME_X_IMAGE_CACHE (f)->refcount;
13651 dpyinfo_refcount = dpyinfo->reference_count;
13652 #endif /* GLYPH_DEBUG */
13653 #ifdef MULTI_KBOARD
13654 FRAME_KBOARD (f) = kb;
13655 #endif
13656 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
13657 f->output_data.w32->explicit_parent = 0;
13658
13659 /* Set the name; the functions to which we pass f expect the name to
13660 be set. */
13661 if (EQ (name, Qunbound) || NILP (name))
13662 {
13663 f->name = build_string (dpyinfo->w32_id_name);
13664 f->explicit_name = 0;
13665 }
13666 else
13667 {
13668 f->name = name;
13669 f->explicit_name = 1;
13670 /* use the frame's title when getting resources for this frame. */
13671 specbind (Qx_resource_name, name);
13672 }
13673
13674 /* Extract the window parameters from the supplied values
13675 that are needed to determine window geometry. */
13676 {
13677 Lisp_Object font;
13678
13679 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
13680
13681 BLOCK_INPUT;
13682 /* First, try whatever font the caller has specified. */
13683 if (STRINGP (font))
13684 {
13685 tem = Fquery_fontset (font, Qnil);
13686 if (STRINGP (tem))
13687 font = x_new_fontset (f, XSTRING (tem)->data);
13688 else
13689 font = x_new_font (f, XSTRING (font)->data);
13690 }
13691
13692 /* Try out a font which we hope has bold and italic variations. */
13693 if (!STRINGP (font))
13694 font = x_new_font (f, "-*-Courier New-normal-r-*-*-*-100-*-*-c-*-iso8859-1");
13695 if (! STRINGP (font))
13696 font = x_new_font (f, "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
13697 /* If those didn't work, look for something which will at least work. */
13698 if (! STRINGP (font))
13699 font = x_new_font (f, "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1");
13700 UNBLOCK_INPUT;
13701 if (! STRINGP (font))
13702 font = build_string ("Fixedsys");
13703
13704 x_default_parameter (f, parms, Qfont, font,
13705 "font", "Font", RES_TYPE_STRING);
13706 }
13707
13708 x_default_parameter (f, parms, Qborder_width, make_number (2),
13709 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
13710 /* This defaults to 2 in order to match xterm. We recognize either
13711 internalBorderWidth or internalBorder (which is what xterm calls
13712 it). */
13713 if (NILP (Fassq (Qinternal_border_width, parms)))
13714 {
13715 Lisp_Object value;
13716
13717 value = w32_get_arg (parms, Qinternal_border_width,
13718 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
13719 if (! EQ (value, Qunbound))
13720 parms = Fcons (Fcons (Qinternal_border_width, value),
13721 parms);
13722 }
13723 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
13724 "internalBorderWidth", "internalBorderWidth",
13725 RES_TYPE_NUMBER);
13726
13727 /* Also do the stuff which must be set before the window exists. */
13728 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
13729 "foreground", "Foreground", RES_TYPE_STRING);
13730 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
13731 "background", "Background", RES_TYPE_STRING);
13732 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
13733 "pointerColor", "Foreground", RES_TYPE_STRING);
13734 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
13735 "cursorColor", "Foreground", RES_TYPE_STRING);
13736 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
13737 "borderColor", "BorderColor", RES_TYPE_STRING);
13738
13739 /* Init faces before x_default_parameter is called for scroll-bar
13740 parameters because that function calls x_set_scroll_bar_width,
13741 which calls change_frame_size, which calls Fset_window_buffer,
13742 which runs hooks, which call Fvertical_motion. At the end, we
13743 end up in init_iterator with a null face cache, which should not
13744 happen. */
13745 init_frame_faces (f);
13746
13747 f->output_data.w32->dwStyle = WS_BORDER | WS_POPUP | WS_DISABLED;
13748 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
13749
13750 window_prompting = x_figure_window_size (f, parms);
13751
13752 /* No fringes on tip frame. */
13753 f->output_data.w32->fringes_extra = 0;
13754 f->output_data.w32->fringe_cols = 0;
13755 f->output_data.w32->left_fringe_width = 0;
13756 f->output_data.w32->right_fringe_width = 0;
13757
13758 if (window_prompting & XNegative)
13759 {
13760 if (window_prompting & YNegative)
13761 f->output_data.w32->win_gravity = SouthEastGravity;
13762 else
13763 f->output_data.w32->win_gravity = NorthEastGravity;
13764 }
13765 else
13766 {
13767 if (window_prompting & YNegative)
13768 f->output_data.w32->win_gravity = SouthWestGravity;
13769 else
13770 f->output_data.w32->win_gravity = NorthWestGravity;
13771 }
13772
13773 f->output_data.w32->size_hint_flags = window_prompting;
13774
13775 BLOCK_INPUT;
13776 my_create_tip_window (f);
13777 UNBLOCK_INPUT;
13778
13779 x_make_gc (f);
13780
13781 x_default_parameter (f, parms, Qauto_raise, Qnil,
13782 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
13783 x_default_parameter (f, parms, Qauto_lower, Qnil,
13784 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
13785 x_default_parameter (f, parms, Qcursor_type, Qbox,
13786 "cursorType", "CursorType", RES_TYPE_SYMBOL);
13787
13788 /* Dimensions, especially f->height, must be done via change_frame_size.
13789 Change will not be effected unless different from the current
13790 f->height. */
13791 width = f->width;
13792 height = f->height;
13793 f->height = 0;
13794 SET_FRAME_WIDTH (f, 0);
13795 change_frame_size (f, height, width, 1, 0, 0);
13796
13797 /* Set up faces after all frame parameters are known. This call
13798 also merges in face attributes specified for new frames.
13799
13800 Frame parameters may be changed if .Xdefaults contains
13801 specifications for the default font. For example, if there is an
13802 `Emacs.default.attributeBackground: pink', the `background-color'
13803 attribute of the frame get's set, which let's the internal border
13804 of the tooltip frame appear in pink. Prevent this. */
13805 {
13806 Lisp_Object bg = Fframe_parameter (frame, Qbackground_color);
13807
13808 /* Set tip_frame here, so that */
13809 tip_frame = frame;
13810 call1 (Qface_set_after_frame_default, frame);
13811
13812 if (!EQ (bg, Fframe_parameter (frame, Qbackground_color)))
13813 Fmodify_frame_parameters (frame, Fcons (Fcons (Qbackground_color, bg),
13814 Qnil));
13815 }
13816
13817 f->no_split = 1;
13818
13819 UNGCPRO;
13820
13821 /* It is now ok to make the frame official even if we get an error
13822 below. And the frame needs to be on Vframe_list or making it
13823 visible won't work. */
13824 Vframe_list = Fcons (frame, Vframe_list);
13825
13826 /* Now that the frame is official, it counts as a reference to
13827 its display. */
13828 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
13829
13830 /* Setting attributes of faces of the tooltip frame from resources
13831 and similar will increment face_change_count, which leads to the
13832 clearing of all current matrices. Since this isn't necessary
13833 here, avoid it by resetting face_change_count to the value it
13834 had before we created the tip frame. */
13835 face_change_count = face_change_count_before;
13836
13837 /* Discard the unwind_protect. */
13838 return unbind_to (count, frame);
13839 }
13840
13841
13842 /* Compute where to display tip frame F. PARMS is the list of frame
13843 parameters for F. DX and DY are specified offsets from the current
13844 location of the mouse. WIDTH and HEIGHT are the width and height
13845 of the tooltip. Return coordinates relative to the root window of
13846 the display in *ROOT_X, and *ROOT_Y. */
13847
13848 static void
13849 compute_tip_xy (f, parms, dx, dy, width, height, root_x, root_y)
13850 struct frame *f;
13851 Lisp_Object parms, dx, dy;
13852 int width, height;
13853 int *root_x, *root_y;
13854 {
13855 Lisp_Object left, top;
13856
13857 /* User-specified position? */
13858 left = Fcdr (Fassq (Qleft, parms));
13859 top = Fcdr (Fassq (Qtop, parms));
13860
13861 /* Move the tooltip window where the mouse pointer is. Resize and
13862 show it. */
13863 if (!INTEGERP (left) || !INTEGERP (top))
13864 {
13865 POINT pt;
13866
13867 BLOCK_INPUT;
13868 GetCursorPos (&pt);
13869 *root_x = pt.x;
13870 *root_y = pt.y;
13871 UNBLOCK_INPUT;
13872 }
13873
13874 if (INTEGERP (top))
13875 *root_y = XINT (top);
13876 else if (*root_y + XINT (dy) - height < 0)
13877 *root_y -= XINT (dy);
13878 else
13879 {
13880 *root_y -= height;
13881 *root_y += XINT (dy);
13882 }
13883
13884 if (INTEGERP (left))
13885 *root_x = XINT (left);
13886 else if (*root_x + XINT (dx) + width <= FRAME_W32_DISPLAY_INFO (f)->width)
13887 /* It fits to the right of the pointer. */
13888 *root_x += XINT (dx);
13889 else if (width + XINT (dx) <= *root_x)
13890 /* It fits to the left of the pointer. */
13891 *root_x -= width + XINT (dx);
13892 else
13893 /* Put it left justified on the screen -- it ought to fit that way. */
13894 *root_x = 0;
13895 }
13896
13897
13898 DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
13899 doc: /* Show STRING in a \"tooltip\" window on frame FRAME.
13900 A tooltip window is a small window displaying a string.
13901
13902 FRAME nil or omitted means use the selected frame.
13903
13904 PARMS is an optional list of frame parameters which can be
13905 used to change the tooltip's appearance.
13906
13907 Automatically hide the tooltip after TIMEOUT seconds. TIMEOUT nil
13908 means use the default timeout of 5 seconds.
13909
13910 If the list of frame parameters PARAMS contains a `left' parameter,
13911 the tooltip is displayed at that x-position. Otherwise it is
13912 displayed at the mouse position, with offset DX added (default is 5 if
13913 DX isn't specified). Likewise for the y-position; if a `top' frame
13914 parameter is specified, it determines the y-position of the tooltip
13915 window, otherwise it is displayed at the mouse position, with offset
13916 DY added (default is -10).
13917
13918 A tooltip's maximum size is specified by `x-max-tooltip-size'.
13919 Text larger than the specified size is clipped. */)
13920 (string, frame, parms, timeout, dx, dy)
13921 Lisp_Object string, frame, parms, timeout, dx, dy;
13922 {
13923 struct frame *f;
13924 struct window *w;
13925 int root_x, root_y;
13926 struct buffer *old_buffer;
13927 struct text_pos pos;
13928 int i, width, height;
13929 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
13930 int old_windows_or_buffers_changed = windows_or_buffers_changed;
13931 int count = BINDING_STACK_SIZE ();
13932
13933 specbind (Qinhibit_redisplay, Qt);
13934
13935 GCPRO4 (string, parms, frame, timeout);
13936
13937 CHECK_STRING (string);
13938 f = check_x_frame (frame);
13939 if (NILP (timeout))
13940 timeout = make_number (5);
13941 else
13942 CHECK_NATNUM (timeout);
13943
13944 if (NILP (dx))
13945 dx = make_number (5);
13946 else
13947 CHECK_NUMBER (dx);
13948
13949 if (NILP (dy))
13950 dy = make_number (-10);
13951 else
13952 CHECK_NUMBER (dy);
13953
13954 if (NILP (last_show_tip_args))
13955 last_show_tip_args = Fmake_vector (make_number (3), Qnil);
13956
13957 if (!NILP (tip_frame))
13958 {
13959 Lisp_Object last_string = AREF (last_show_tip_args, 0);
13960 Lisp_Object last_frame = AREF (last_show_tip_args, 1);
13961 Lisp_Object last_parms = AREF (last_show_tip_args, 2);
13962
13963 if (EQ (frame, last_frame)
13964 && !NILP (Fequal (last_string, string))
13965 && !NILP (Fequal (last_parms, parms)))
13966 {
13967 struct frame *f = XFRAME (tip_frame);
13968
13969 /* Only DX and DY have changed. */
13970 if (!NILP (tip_timer))
13971 {
13972 Lisp_Object timer = tip_timer;
13973 tip_timer = Qnil;
13974 call1 (Qcancel_timer, timer);
13975 }
13976
13977 BLOCK_INPUT;
13978 compute_tip_xy (f, parms, dx, dy, PIXEL_WIDTH (f),
13979 PIXEL_HEIGHT (f), &root_x, &root_y);
13980
13981 /* Put tooltip in topmost group and in position. */
13982 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST,
13983 root_x, root_y, 0, 0,
13984 SWP_NOSIZE | SWP_NOACTIVATE);
13985
13986 /* Ensure tooltip is on top of other topmost windows (eg menus). */
13987 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOP,
13988 0, 0, 0, 0,
13989 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
13990
13991 UNBLOCK_INPUT;
13992 goto start_timer;
13993 }
13994 }
13995
13996 /* Hide a previous tip, if any. */
13997 Fx_hide_tip ();
13998
13999 ASET (last_show_tip_args, 0, string);
14000 ASET (last_show_tip_args, 1, frame);
14001 ASET (last_show_tip_args, 2, parms);
14002
14003 /* Add default values to frame parameters. */
14004 if (NILP (Fassq (Qname, parms)))
14005 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
14006 if (NILP (Fassq (Qinternal_border_width, parms)))
14007 parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
14008 if (NILP (Fassq (Qborder_width, parms)))
14009 parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
14010 if (NILP (Fassq (Qborder_color, parms)))
14011 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
14012 if (NILP (Fassq (Qbackground_color, parms)))
14013 parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
14014 parms);
14015
14016 /* Block input until the tip has been fully drawn, to avoid crashes
14017 when drawing tips in menus. */
14018 BLOCK_INPUT;
14019
14020 /* Create a frame for the tooltip, and record it in the global
14021 variable tip_frame. */
14022 frame = x_create_tip_frame (FRAME_W32_DISPLAY_INFO (f), parms, string);
14023 f = XFRAME (frame);
14024
14025 /* Set up the frame's root window. */
14026 w = XWINDOW (FRAME_ROOT_WINDOW (f));
14027 w->left = w->top = make_number (0);
14028
14029 if (CONSP (Vx_max_tooltip_size)
14030 && INTEGERP (XCAR (Vx_max_tooltip_size))
14031 && XINT (XCAR (Vx_max_tooltip_size)) > 0
14032 && INTEGERP (XCDR (Vx_max_tooltip_size))
14033 && XINT (XCDR (Vx_max_tooltip_size)) > 0)
14034 {
14035 w->width = XCAR (Vx_max_tooltip_size);
14036 w->height = XCDR (Vx_max_tooltip_size);
14037 }
14038 else
14039 {
14040 w->width = make_number (80);
14041 w->height = make_number (40);
14042 }
14043
14044 f->window_width = XINT (w->width);
14045 adjust_glyphs (f);
14046 w->pseudo_window_p = 1;
14047
14048 /* Display the tooltip text in a temporary buffer. */
14049 old_buffer = current_buffer;
14050 set_buffer_internal_1 (XBUFFER (XWINDOW (FRAME_ROOT_WINDOW (f))->buffer));
14051 current_buffer->truncate_lines = Qnil;
14052 clear_glyph_matrix (w->desired_matrix);
14053 clear_glyph_matrix (w->current_matrix);
14054 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
14055 try_window (FRAME_ROOT_WINDOW (f), pos);
14056
14057 /* Compute width and height of the tooltip. */
14058 width = height = 0;
14059 for (i = 0; i < w->desired_matrix->nrows; ++i)
14060 {
14061 struct glyph_row *row = &w->desired_matrix->rows[i];
14062 struct glyph *last;
14063 int row_width;
14064
14065 /* Stop at the first empty row at the end. */
14066 if (!row->enabled_p || !row->displays_text_p)
14067 break;
14068
14069 /* Let the row go over the full width of the frame. */
14070 row->full_width_p = 1;
14071
14072 #ifdef TODO /* Investigate why some fonts need more width than is
14073 calculated for some tooltips. */
14074 /* There's a glyph at the end of rows that is use to place
14075 the cursor there. Don't include the width of this glyph. */
14076 if (row->used[TEXT_AREA])
14077 {
14078 last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
14079 row_width = row->pixel_width - last->pixel_width;
14080 }
14081 else
14082 #endif
14083 row_width = row->pixel_width;
14084
14085 /* TODO: find why tips do not draw along baseline as instructed. */
14086 height += row->height;
14087 width = max (width, row_width);
14088 }
14089
14090 /* Add the frame's internal border to the width and height the X
14091 window should have. */
14092 height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
14093 width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
14094
14095 /* Move the tooltip window where the mouse pointer is. Resize and
14096 show it. */
14097 compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y);
14098
14099 {
14100 /* Adjust Window size to take border into account. */
14101 RECT rect;
14102 rect.left = rect.top = 0;
14103 rect.right = width;
14104 rect.bottom = height;
14105 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
14106 FRAME_EXTERNAL_MENU_BAR (f));
14107
14108 /* Position and size tooltip, and put it in the topmost group. */
14109 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST,
14110 root_x, root_y, rect.right - rect.left,
14111 rect.bottom - rect.top, SWP_NOACTIVATE);
14112
14113 /* Ensure tooltip is on top of other topmost windows (eg menus). */
14114 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOP,
14115 0, 0, 0, 0,
14116 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
14117
14118 /* Let redisplay know that we have made the frame visible already. */
14119 f->async_visible = 1;
14120
14121 ShowWindow (FRAME_W32_WINDOW (f), SW_SHOWNOACTIVATE);
14122 }
14123
14124 /* Draw into the window. */
14125 w->must_be_updated_p = 1;
14126 update_single_window (w, 1);
14127
14128 UNBLOCK_INPUT;
14129
14130 /* Restore original current buffer. */
14131 set_buffer_internal_1 (old_buffer);
14132 windows_or_buffers_changed = old_windows_or_buffers_changed;
14133
14134 start_timer:
14135 /* Let the tip disappear after timeout seconds. */
14136 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
14137 intern ("x-hide-tip"));
14138
14139 UNGCPRO;
14140 return unbind_to (count, Qnil);
14141 }
14142
14143
14144 DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
14145 doc: /* Hide the current tooltip window, if there is any.
14146 Value is t if tooltip was open, nil otherwise. */)
14147 ()
14148 {
14149 int count;
14150 Lisp_Object deleted, frame, timer;
14151 struct gcpro gcpro1, gcpro2;
14152
14153 /* Return quickly if nothing to do. */
14154 if (NILP (tip_timer) && NILP (tip_frame))
14155 return Qnil;
14156
14157 frame = tip_frame;
14158 timer = tip_timer;
14159 GCPRO2 (frame, timer);
14160 tip_frame = tip_timer = deleted = Qnil;
14161
14162 count = BINDING_STACK_SIZE ();
14163 specbind (Qinhibit_redisplay, Qt);
14164 specbind (Qinhibit_quit, Qt);
14165
14166 if (!NILP (timer))
14167 call1 (Qcancel_timer, timer);
14168
14169 if (FRAMEP (frame))
14170 {
14171 Fdelete_frame (frame, Qnil);
14172 deleted = Qt;
14173 }
14174
14175 UNGCPRO;
14176 return unbind_to (count, deleted);
14177 }
14178
14179
14180 \f
14181 /***********************************************************************
14182 File selection dialog
14183 ***********************************************************************/
14184
14185 extern Lisp_Object Qfile_name_history;
14186
14187 DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0,
14188 doc: /* Read file name, prompting with PROMPT in directory DIR.
14189 Use a file selection dialog.
14190 Select DEFAULT-FILENAME in the dialog's file selection box, if
14191 specified. Ensure that file exists if MUSTMATCH is non-nil. */)
14192 (prompt, dir, default_filename, mustmatch)
14193 Lisp_Object prompt, dir, default_filename, mustmatch;
14194 {
14195 struct frame *f = SELECTED_FRAME ();
14196 Lisp_Object file = Qnil;
14197 int count = specpdl_ptr - specpdl;
14198 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
14199 char filename[MAX_PATH + 1];
14200 char init_dir[MAX_PATH + 1];
14201 int use_dialog_p = 1;
14202
14203 GCPRO5 (prompt, dir, default_filename, mustmatch, file);
14204 CHECK_STRING (prompt);
14205 CHECK_STRING (dir);
14206
14207 /* Create the dialog with PROMPT as title, using DIR as initial
14208 directory and using "*" as pattern. */
14209 dir = Fexpand_file_name (dir, Qnil);
14210 strncpy (init_dir, XSTRING (dir)->data, MAX_PATH);
14211 init_dir[MAX_PATH] = '\0';
14212 unixtodos_filename (init_dir);
14213
14214 if (STRINGP (default_filename))
14215 {
14216 char *file_name_only;
14217 char *full_path_name = XSTRING (default_filename)->data;
14218
14219 unixtodos_filename (full_path_name);
14220
14221 file_name_only = strrchr (full_path_name, '\\');
14222 if (!file_name_only)
14223 file_name_only = full_path_name;
14224 else
14225 {
14226 file_name_only++;
14227
14228 /* If default_file_name is a directory, don't use the open
14229 file dialog, as it does not support selecting
14230 directories. */
14231 if (!(*file_name_only))
14232 use_dialog_p = 0;
14233 }
14234
14235 strncpy (filename, file_name_only, MAX_PATH);
14236 filename[MAX_PATH] = '\0';
14237 }
14238 else
14239 filename[0] = '\0';
14240
14241 if (use_dialog_p)
14242 {
14243 OPENFILENAME file_details;
14244
14245 /* Prevent redisplay. */
14246 specbind (Qinhibit_redisplay, Qt);
14247 BLOCK_INPUT;
14248
14249 bzero (&file_details, sizeof (file_details));
14250 file_details.lStructSize = sizeof (file_details);
14251 file_details.hwndOwner = FRAME_W32_WINDOW (f);
14252 /* Undocumented Bug in Common File Dialog:
14253 If a filter is not specified, shell links are not resolved. */
14254 file_details.lpstrFilter = "ALL Files (*.*)\0*.*\0\0";
14255 file_details.lpstrFile = filename;
14256 file_details.nMaxFile = sizeof (filename);
14257 file_details.lpstrInitialDir = init_dir;
14258 file_details.lpstrTitle = XSTRING (prompt)->data;
14259 file_details.Flags = OFN_HIDEREADONLY | OFN_NOCHANGEDIR;
14260
14261 if (!NILP (mustmatch))
14262 file_details.Flags |= OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
14263
14264 if (GetOpenFileName (&file_details))
14265 {
14266 dostounix_filename (filename);
14267 file = build_string (filename);
14268 }
14269 else
14270 file = Qnil;
14271
14272 UNBLOCK_INPUT;
14273 file = unbind_to (count, file);
14274 }
14275 /* Open File dialog will not allow folders to be selected, so resort
14276 to minibuffer completing reads for directories. */
14277 else
14278 file = Fcompleting_read (prompt, intern ("read-file-name-internal"),
14279 dir, mustmatch, dir, Qfile_name_history,
14280 default_filename, Qnil);
14281
14282 UNGCPRO;
14283
14284 /* Make "Cancel" equivalent to C-g. */
14285 if (NILP (file))
14286 Fsignal (Qquit, Qnil);
14287
14288 return unbind_to (count, file);
14289 }
14290
14291
14292 \f
14293 /***********************************************************************
14294 w32 specialized functions
14295 ***********************************************************************/
14296
14297 DEFUN ("w32-select-font", Fw32_select_font, Sw32_select_font, 0, 2, 0,
14298 doc: /* Select a font using the W32 font dialog.
14299 Returns an X font string corresponding to the selection. */)
14300 (frame, include_proportional)
14301 Lisp_Object frame, include_proportional;
14302 {
14303 FRAME_PTR f = check_x_frame (frame);
14304 CHOOSEFONT cf;
14305 LOGFONT lf;
14306 TEXTMETRIC tm;
14307 HDC hdc;
14308 HANDLE oldobj;
14309 char buf[100];
14310
14311 bzero (&cf, sizeof (cf));
14312 bzero (&lf, sizeof (lf));
14313
14314 cf.lStructSize = sizeof (cf);
14315 cf.hwndOwner = FRAME_W32_WINDOW (f);
14316 cf.Flags = CF_FORCEFONTEXIST | CF_SCREENFONTS | CF_NOVERTFONTS;
14317
14318 /* Unless include_proportional is non-nil, limit the selection to
14319 monospaced fonts. */
14320 if (NILP (include_proportional))
14321 cf.Flags |= CF_FIXEDPITCHONLY;
14322
14323 cf.lpLogFont = &lf;
14324
14325 /* Initialize as much of the font details as we can from the current
14326 default font. */
14327 hdc = GetDC (FRAME_W32_WINDOW (f));
14328 oldobj = SelectObject (hdc, FRAME_FONT (f)->hfont);
14329 GetTextFace (hdc, LF_FACESIZE, lf.lfFaceName);
14330 if (GetTextMetrics (hdc, &tm))
14331 {
14332 lf.lfHeight = tm.tmInternalLeading - tm.tmHeight;
14333 lf.lfWeight = tm.tmWeight;
14334 lf.lfItalic = tm.tmItalic;
14335 lf.lfUnderline = tm.tmUnderlined;
14336 lf.lfStrikeOut = tm.tmStruckOut;
14337 lf.lfCharSet = tm.tmCharSet;
14338 cf.Flags |= CF_INITTOLOGFONTSTRUCT;
14339 }
14340 SelectObject (hdc, oldobj);
14341 ReleaseDC (FRAME_W32_WINDOW (f), hdc);
14342
14343 if (!ChooseFont (&cf) || !w32_to_x_font (&lf, buf, 100, NULL))
14344 return Qnil;
14345
14346 return build_string (buf);
14347 }
14348
14349 DEFUN ("w32-send-sys-command", Fw32_send_sys_command,
14350 Sw32_send_sys_command, 1, 2, 0,
14351 doc: /* Send frame a Windows WM_SYSCOMMAND message of type COMMAND.
14352 Some useful values for command are #xf030 to maximise frame (#xf020
14353 to minimize), #xf120 to restore frame to original size, and #xf100
14354 to activate the menubar for keyboard access. #xf140 activates the
14355 screen saver if defined.
14356
14357 If optional parameter FRAME is not specified, use selected frame. */)
14358 (command, frame)
14359 Lisp_Object command, frame;
14360 {
14361 FRAME_PTR f = check_x_frame (frame);
14362
14363 CHECK_NUMBER (command);
14364
14365 PostMessage (FRAME_W32_WINDOW (f), WM_SYSCOMMAND, XINT (command), 0);
14366
14367 return Qnil;
14368 }
14369
14370 DEFUN ("w32-shell-execute", Fw32_shell_execute, Sw32_shell_execute, 2, 4, 0,
14371 doc: /* Get Windows to perform OPERATION on DOCUMENT.
14372 This is a wrapper around the ShellExecute system function, which
14373 invokes the application registered to handle OPERATION for DOCUMENT.
14374 OPERATION is typically \"open\", \"print\" or \"explore\" (but can be
14375 nil for the default action), and DOCUMENT is typically the name of a
14376 document file or URL, but can also be a program executable to run or
14377 a directory to open in the Windows Explorer.
14378
14379 If DOCUMENT is a program executable, PARAMETERS can be a string
14380 containing command line parameters, but otherwise should be nil.
14381
14382 SHOW-FLAG can be used to control whether the invoked application is hidden
14383 or minimized. If SHOW-FLAG is nil, the application is displayed normally,
14384 otherwise it is an integer representing a ShowWindow flag:
14385
14386 0 - start hidden
14387 1 - start normally
14388 3 - start maximized
14389 6 - start minimized */)
14390 (operation, document, parameters, show_flag)
14391 Lisp_Object operation, document, parameters, show_flag;
14392 {
14393 Lisp_Object current_dir;
14394
14395 CHECK_STRING (document);
14396
14397 /* Encode filename and current directory. */
14398 current_dir = ENCODE_FILE (current_buffer->directory);
14399 document = ENCODE_FILE (document);
14400 if ((int) ShellExecute (NULL,
14401 (STRINGP (operation) ?
14402 XSTRING (operation)->data : NULL),
14403 XSTRING (document)->data,
14404 (STRINGP (parameters) ?
14405 XSTRING (parameters)->data : NULL),
14406 XSTRING (current_dir)->data,
14407 (INTEGERP (show_flag) ?
14408 XINT (show_flag) : SW_SHOWDEFAULT))
14409 > 32)
14410 return Qt;
14411 error ("ShellExecute failed: %s", w32_strerror (0));
14412 }
14413
14414 /* Lookup virtual keycode from string representing the name of a
14415 non-ascii keystroke into the corresponding virtual key, using
14416 lispy_function_keys. */
14417 static int
14418 lookup_vk_code (char *key)
14419 {
14420 int i;
14421
14422 for (i = 0; i < 256; i++)
14423 if (lispy_function_keys[i] != 0
14424 && strcmp (lispy_function_keys[i], key) == 0)
14425 return i;
14426
14427 return -1;
14428 }
14429
14430 /* Convert a one-element vector style key sequence to a hot key
14431 definition. */
14432 static int
14433 w32_parse_hot_key (key)
14434 Lisp_Object key;
14435 {
14436 /* Copied from Fdefine_key and store_in_keymap. */
14437 register Lisp_Object c;
14438 int vk_code;
14439 int lisp_modifiers;
14440 int w32_modifiers;
14441 struct gcpro gcpro1;
14442
14443 CHECK_VECTOR (key);
14444
14445 if (XFASTINT (Flength (key)) != 1)
14446 return Qnil;
14447
14448 GCPRO1 (key);
14449
14450 c = Faref (key, make_number (0));
14451
14452 if (CONSP (c) && lucid_event_type_list_p (c))
14453 c = Fevent_convert_list (c);
14454
14455 UNGCPRO;
14456
14457 if (! INTEGERP (c) && ! SYMBOLP (c))
14458 error ("Key definition is invalid");
14459
14460 /* Work out the base key and the modifiers. */
14461 if (SYMBOLP (c))
14462 {
14463 c = parse_modifiers (c);
14464 lisp_modifiers = Fcar (Fcdr (c));
14465 c = Fcar (c);
14466 if (!SYMBOLP (c))
14467 abort ();
14468 vk_code = lookup_vk_code (XSYMBOL (c)->name->data);
14469 }
14470 else if (INTEGERP (c))
14471 {
14472 lisp_modifiers = XINT (c) & ~CHARACTERBITS;
14473 /* Many ascii characters are their own virtual key code. */
14474 vk_code = XINT (c) & CHARACTERBITS;
14475 }
14476
14477 if (vk_code < 0 || vk_code > 255)
14478 return Qnil;
14479
14480 if ((lisp_modifiers & meta_modifier) != 0
14481 && !NILP (Vw32_alt_is_meta))
14482 lisp_modifiers |= alt_modifier;
14483
14484 /* Supply defs missing from mingw32. */
14485 #ifndef MOD_ALT
14486 #define MOD_ALT 0x0001
14487 #define MOD_CONTROL 0x0002
14488 #define MOD_SHIFT 0x0004
14489 #define MOD_WIN 0x0008
14490 #endif
14491
14492 /* Convert lisp modifiers to Windows hot-key form. */
14493 w32_modifiers = (lisp_modifiers & hyper_modifier) ? MOD_WIN : 0;
14494 w32_modifiers |= (lisp_modifiers & alt_modifier) ? MOD_ALT : 0;
14495 w32_modifiers |= (lisp_modifiers & ctrl_modifier) ? MOD_CONTROL : 0;
14496 w32_modifiers |= (lisp_modifiers & shift_modifier) ? MOD_SHIFT : 0;
14497
14498 return HOTKEY (vk_code, w32_modifiers);
14499 }
14500
14501 DEFUN ("w32-register-hot-key", Fw32_register_hot_key,
14502 Sw32_register_hot_key, 1, 1, 0,
14503 doc: /* Register KEY as a hot-key combination.
14504 Certain key combinations like Alt-Tab are reserved for system use on
14505 Windows, and therefore are normally intercepted by the system. However,
14506 most of these key combinations can be received by registering them as
14507 hot-keys, overriding their special meaning.
14508
14509 KEY must be a one element key definition in vector form that would be
14510 acceptable to `define-key' (e.g. [A-tab] for Alt-Tab). The meta
14511 modifier is interpreted as Alt if `w32-alt-is-meta' is t, and hyper
14512 is always interpreted as the Windows modifier keys.
14513
14514 The return value is the hotkey-id if registered, otherwise nil. */)
14515 (key)
14516 Lisp_Object key;
14517 {
14518 key = w32_parse_hot_key (key);
14519
14520 if (NILP (Fmemq (key, w32_grabbed_keys)))
14521 {
14522 /* Reuse an empty slot if possible. */
14523 Lisp_Object item = Fmemq (Qnil, w32_grabbed_keys);
14524
14525 /* Safe to add new key to list, even if we have focus. */
14526 if (NILP (item))
14527 w32_grabbed_keys = Fcons (key, w32_grabbed_keys);
14528 else
14529 XSETCAR (item, key);
14530
14531 /* Notify input thread about new hot-key definition, so that it
14532 takes effect without needing to switch focus. */
14533 PostThreadMessage (dwWindowsThreadId, WM_EMACS_REGISTER_HOT_KEY,
14534 (WPARAM) key, 0);
14535 }
14536
14537 return key;
14538 }
14539
14540 DEFUN ("w32-unregister-hot-key", Fw32_unregister_hot_key,
14541 Sw32_unregister_hot_key, 1, 1, 0,
14542 doc: /* Unregister HOTKEY as a hot-key combination. */)
14543 (key)
14544 Lisp_Object key;
14545 {
14546 Lisp_Object item;
14547
14548 if (!INTEGERP (key))
14549 key = w32_parse_hot_key (key);
14550
14551 item = Fmemq (key, w32_grabbed_keys);
14552
14553 if (!NILP (item))
14554 {
14555 /* Notify input thread about hot-key definition being removed, so
14556 that it takes effect without needing focus switch. */
14557 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_UNREGISTER_HOT_KEY,
14558 (WPARAM) XINT (XCAR (item)), (LPARAM) item))
14559 {
14560 MSG msg;
14561 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
14562 }
14563 return Qt;
14564 }
14565 return Qnil;
14566 }
14567
14568 DEFUN ("w32-registered-hot-keys", Fw32_registered_hot_keys,
14569 Sw32_registered_hot_keys, 0, 0, 0,
14570 doc: /* Return list of registered hot-key IDs. */)
14571 ()
14572 {
14573 return Fcopy_sequence (w32_grabbed_keys);
14574 }
14575
14576 DEFUN ("w32-reconstruct-hot-key", Fw32_reconstruct_hot_key,
14577 Sw32_reconstruct_hot_key, 1, 1, 0,
14578 doc: /* Convert hot-key ID to a lisp key combination. */)
14579 (hotkeyid)
14580 Lisp_Object hotkeyid;
14581 {
14582 int vk_code, w32_modifiers;
14583 Lisp_Object key;
14584
14585 CHECK_NUMBER (hotkeyid);
14586
14587 vk_code = HOTKEY_VK_CODE (hotkeyid);
14588 w32_modifiers = HOTKEY_MODIFIERS (hotkeyid);
14589
14590 if (lispy_function_keys[vk_code])
14591 key = intern (lispy_function_keys[vk_code]);
14592 else
14593 key = make_number (vk_code);
14594
14595 key = Fcons (key, Qnil);
14596 if (w32_modifiers & MOD_SHIFT)
14597 key = Fcons (Qshift, key);
14598 if (w32_modifiers & MOD_CONTROL)
14599 key = Fcons (Qctrl, key);
14600 if (w32_modifiers & MOD_ALT)
14601 key = Fcons (NILP (Vw32_alt_is_meta) ? Qalt : Qmeta, key);
14602 if (w32_modifiers & MOD_WIN)
14603 key = Fcons (Qhyper, key);
14604
14605 return key;
14606 }
14607
14608 DEFUN ("w32-toggle-lock-key", Fw32_toggle_lock_key,
14609 Sw32_toggle_lock_key, 1, 2, 0,
14610 doc: /* Toggle the state of the lock key KEY.
14611 KEY can be `capslock', `kp-numlock', or `scroll'.
14612 If the optional parameter NEW-STATE is a number, then the state of KEY
14613 is set to off if the low bit of NEW-STATE is zero, otherwise on. */)
14614 (key, new_state)
14615 Lisp_Object key, new_state;
14616 {
14617 int vk_code;
14618
14619 if (EQ (key, intern ("capslock")))
14620 vk_code = VK_CAPITAL;
14621 else if (EQ (key, intern ("kp-numlock")))
14622 vk_code = VK_NUMLOCK;
14623 else if (EQ (key, intern ("scroll")))
14624 vk_code = VK_SCROLL;
14625 else
14626 return Qnil;
14627
14628 if (!dwWindowsThreadId)
14629 return make_number (w32_console_toggle_lock_key (vk_code, new_state));
14630
14631 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_TOGGLE_LOCK_KEY,
14632 (WPARAM) vk_code, (LPARAM) new_state))
14633 {
14634 MSG msg;
14635 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
14636 return make_number (msg.wParam);
14637 }
14638 return Qnil;
14639 }
14640 \f
14641 DEFUN ("file-system-info", Ffile_system_info, Sfile_system_info, 1, 1, 0,
14642 doc: /* Return storage information about the file system FILENAME is on.
14643 Value is a list of floats (TOTAL FREE AVAIL), where TOTAL is the total
14644 storage of the file system, FREE is the free storage, and AVAIL is the
14645 storage available to a non-superuser. All 3 numbers are in bytes.
14646 If the underlying system call fails, value is nil. */)
14647 (filename)
14648 Lisp_Object filename;
14649 {
14650 Lisp_Object encoded, value;
14651
14652 CHECK_STRING (filename);
14653 filename = Fexpand_file_name (filename, Qnil);
14654 encoded = ENCODE_FILE (filename);
14655
14656 value = Qnil;
14657
14658 /* Determining the required information on Windows turns out, sadly,
14659 to be more involved than one would hope. The original Win32 api
14660 call for this will return bogus information on some systems, but we
14661 must dynamically probe for the replacement api, since that was
14662 added rather late on. */
14663 {
14664 HMODULE hKernel = GetModuleHandle ("kernel32");
14665 BOOL (*pfn_GetDiskFreeSpaceEx)
14666 (char *, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER)
14667 = (void *) GetProcAddress (hKernel, "GetDiskFreeSpaceEx");
14668
14669 /* On Windows, we may need to specify the root directory of the
14670 volume holding FILENAME. */
14671 char rootname[MAX_PATH];
14672 char *name = XSTRING (encoded)->data;
14673
14674 /* find the root name of the volume if given */
14675 if (isalpha (name[0]) && name[1] == ':')
14676 {
14677 rootname[0] = name[0];
14678 rootname[1] = name[1];
14679 rootname[2] = '\\';
14680 rootname[3] = 0;
14681 }
14682 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
14683 {
14684 char *str = rootname;
14685 int slashes = 4;
14686 do
14687 {
14688 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
14689 break;
14690 *str++ = *name++;
14691 }
14692 while ( *name );
14693
14694 *str++ = '\\';
14695 *str = 0;
14696 }
14697
14698 if (pfn_GetDiskFreeSpaceEx)
14699 {
14700 /* Unsigned large integers cannot be cast to double, so
14701 use signed ones instead. */
14702 LARGE_INTEGER availbytes;
14703 LARGE_INTEGER freebytes;
14704 LARGE_INTEGER totalbytes;
14705
14706 if (pfn_GetDiskFreeSpaceEx(rootname,
14707 (ULARGE_INTEGER *)&availbytes,
14708 (ULARGE_INTEGER *)&totalbytes,
14709 (ULARGE_INTEGER *)&freebytes))
14710 value = list3 (make_float ((double) totalbytes.QuadPart),
14711 make_float ((double) freebytes.QuadPart),
14712 make_float ((double) availbytes.QuadPart));
14713 }
14714 else
14715 {
14716 DWORD sectors_per_cluster;
14717 DWORD bytes_per_sector;
14718 DWORD free_clusters;
14719 DWORD total_clusters;
14720
14721 if (GetDiskFreeSpace(rootname,
14722 &sectors_per_cluster,
14723 &bytes_per_sector,
14724 &free_clusters,
14725 &total_clusters))
14726 value = list3 (make_float ((double) total_clusters
14727 * sectors_per_cluster * bytes_per_sector),
14728 make_float ((double) free_clusters
14729 * sectors_per_cluster * bytes_per_sector),
14730 make_float ((double) free_clusters
14731 * sectors_per_cluster * bytes_per_sector));
14732 }
14733 }
14734
14735 return value;
14736 }
14737 \f
14738 /***********************************************************************
14739 Initialization
14740 ***********************************************************************/
14741
14742 void
14743 syms_of_w32fns ()
14744 {
14745 HMODULE user32_lib = GetModuleHandle ("user32.dll");
14746
14747 /* This is zero if not using MS-Windows. */
14748 w32_in_use = 0;
14749
14750 /* TrackMouseEvent not available in all versions of Windows, so must load
14751 it dynamically. Do it once, here, instead of every time it is used. */
14752 track_mouse_event_fn = GetProcAddress (user32_lib, "TrackMouseEvent");
14753 track_mouse_window = NULL;
14754
14755 w32_visible_system_caret_hwnd = NULL;
14756
14757 Qauto_raise = intern ("auto-raise");
14758 staticpro (&Qauto_raise);
14759 Qauto_lower = intern ("auto-lower");
14760 staticpro (&Qauto_lower);
14761 Qbar = intern ("bar");
14762 staticpro (&Qbar);
14763 Qborder_color = intern ("border-color");
14764 staticpro (&Qborder_color);
14765 Qborder_width = intern ("border-width");
14766 staticpro (&Qborder_width);
14767 Qbox = intern ("box");
14768 staticpro (&Qbox);
14769 Qcursor_color = intern ("cursor-color");
14770 staticpro (&Qcursor_color);
14771 Qcursor_type = intern ("cursor-type");
14772 staticpro (&Qcursor_type);
14773 Qgeometry = intern ("geometry");
14774 staticpro (&Qgeometry);
14775 Qicon_left = intern ("icon-left");
14776 staticpro (&Qicon_left);
14777 Qicon_top = intern ("icon-top");
14778 staticpro (&Qicon_top);
14779 Qicon_type = intern ("icon-type");
14780 staticpro (&Qicon_type);
14781 Qicon_name = intern ("icon-name");
14782 staticpro (&Qicon_name);
14783 Qinternal_border_width = intern ("internal-border-width");
14784 staticpro (&Qinternal_border_width);
14785 Qleft = intern ("left");
14786 staticpro (&Qleft);
14787 Qright = intern ("right");
14788 staticpro (&Qright);
14789 Qmouse_color = intern ("mouse-color");
14790 staticpro (&Qmouse_color);
14791 Qnone = intern ("none");
14792 staticpro (&Qnone);
14793 Qparent_id = intern ("parent-id");
14794 staticpro (&Qparent_id);
14795 Qscroll_bar_width = intern ("scroll-bar-width");
14796 staticpro (&Qscroll_bar_width);
14797 Qsuppress_icon = intern ("suppress-icon");
14798 staticpro (&Qsuppress_icon);
14799 Qundefined_color = intern ("undefined-color");
14800 staticpro (&Qundefined_color);
14801 Qvertical_scroll_bars = intern ("vertical-scroll-bars");
14802 staticpro (&Qvertical_scroll_bars);
14803 Qvisibility = intern ("visibility");
14804 staticpro (&Qvisibility);
14805 Qwindow_id = intern ("window-id");
14806 staticpro (&Qwindow_id);
14807 Qx_frame_parameter = intern ("x-frame-parameter");
14808 staticpro (&Qx_frame_parameter);
14809 Qx_resource_name = intern ("x-resource-name");
14810 staticpro (&Qx_resource_name);
14811 Quser_position = intern ("user-position");
14812 staticpro (&Quser_position);
14813 Quser_size = intern ("user-size");
14814 staticpro (&Quser_size);
14815 Qscreen_gamma = intern ("screen-gamma");
14816 staticpro (&Qscreen_gamma);
14817 Qline_spacing = intern ("line-spacing");
14818 staticpro (&Qline_spacing);
14819 Qcenter = intern ("center");
14820 staticpro (&Qcenter);
14821 Qcancel_timer = intern ("cancel-timer");
14822 staticpro (&Qcancel_timer);
14823 Qfullscreen = intern ("fullscreen");
14824 staticpro (&Qfullscreen);
14825 Qfullwidth = intern ("fullwidth");
14826 staticpro (&Qfullwidth);
14827 Qfullheight = intern ("fullheight");
14828 staticpro (&Qfullheight);
14829 Qfullboth = intern ("fullboth");
14830 staticpro (&Qfullboth);
14831
14832 Qhyper = intern ("hyper");
14833 staticpro (&Qhyper);
14834 Qsuper = intern ("super");
14835 staticpro (&Qsuper);
14836 Qmeta = intern ("meta");
14837 staticpro (&Qmeta);
14838 Qalt = intern ("alt");
14839 staticpro (&Qalt);
14840 Qctrl = intern ("ctrl");
14841 staticpro (&Qctrl);
14842 Qcontrol = intern ("control");
14843 staticpro (&Qcontrol);
14844 Qshift = intern ("shift");
14845 staticpro (&Qshift);
14846 /* This is the end of symbol initialization. */
14847
14848 /* Text property `display' should be nonsticky by default. */
14849 Vtext_property_default_nonsticky
14850 = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky);
14851
14852
14853 Qlaplace = intern ("laplace");
14854 staticpro (&Qlaplace);
14855 Qemboss = intern ("emboss");
14856 staticpro (&Qemboss);
14857 Qedge_detection = intern ("edge-detection");
14858 staticpro (&Qedge_detection);
14859 Qheuristic = intern ("heuristic");
14860 staticpro (&Qheuristic);
14861 QCmatrix = intern (":matrix");
14862 staticpro (&QCmatrix);
14863 QCcolor_adjustment = intern (":color-adjustment");
14864 staticpro (&QCcolor_adjustment);
14865 QCmask = intern (":mask");
14866 staticpro (&QCmask);
14867
14868 Qface_set_after_frame_default = intern ("face-set-after-frame-default");
14869 staticpro (&Qface_set_after_frame_default);
14870
14871 Fput (Qundefined_color, Qerror_conditions,
14872 Fcons (Qundefined_color, Fcons (Qerror, Qnil)));
14873 Fput (Qundefined_color, Qerror_message,
14874 build_string ("Undefined color"));
14875
14876 staticpro (&w32_grabbed_keys);
14877 w32_grabbed_keys = Qnil;
14878
14879 DEFVAR_LISP ("w32-color-map", &Vw32_color_map,
14880 doc: /* An array of color name mappings for windows. */);
14881 Vw32_color_map = Qnil;
14882
14883 DEFVAR_LISP ("w32-pass-alt-to-system", &Vw32_pass_alt_to_system,
14884 doc: /* Non-nil if alt key presses are passed on to Windows.
14885 When non-nil, for example, alt pressed and released and then space will
14886 open the System menu. When nil, Emacs silently swallows alt key events. */);
14887 Vw32_pass_alt_to_system = Qnil;
14888
14889 DEFVAR_LISP ("w32-alt-is-meta", &Vw32_alt_is_meta,
14890 doc: /* Non-nil if the alt key is to be considered the same as the meta key.
14891 When nil, Emacs will translate the alt key to the Alt modifier, and not Meta. */);
14892 Vw32_alt_is_meta = Qt;
14893
14894 DEFVAR_INT ("w32-quit-key", &Vw32_quit_key,
14895 doc: /* If non-zero, the virtual key code for an alternative quit key. */);
14896 XSETINT (Vw32_quit_key, 0);
14897
14898 DEFVAR_LISP ("w32-pass-lwindow-to-system",
14899 &Vw32_pass_lwindow_to_system,
14900 doc: /* Non-nil if the left \"Windows\" key is passed on to Windows.
14901 When non-nil, the Start menu is opened by tapping the key. */);
14902 Vw32_pass_lwindow_to_system = Qt;
14903
14904 DEFVAR_LISP ("w32-pass-rwindow-to-system",
14905 &Vw32_pass_rwindow_to_system,
14906 doc: /* Non-nil if the right \"Windows\" key is passed on to Windows.
14907 When non-nil, the Start menu is opened by tapping the key. */);
14908 Vw32_pass_rwindow_to_system = Qt;
14909
14910 DEFVAR_INT ("w32-phantom-key-code",
14911 &Vw32_phantom_key_code,
14912 doc: /* Virtual key code used to generate \"phantom\" key presses.
14913 Value is a number between 0 and 255.
14914
14915 Phantom key presses are generated in order to stop the system from
14916 acting on \"Windows\" key events when `w32-pass-lwindow-to-system' or
14917 `w32-pass-rwindow-to-system' is nil. */);
14918 /* Although 255 is technically not a valid key code, it works and
14919 means that this hack won't interfere with any real key code. */
14920 Vw32_phantom_key_code = 255;
14921
14922 DEFVAR_LISP ("w32-enable-num-lock",
14923 &Vw32_enable_num_lock,
14924 doc: /* Non-nil if Num Lock should act normally.
14925 Set to nil to see Num Lock as the key `kp-numlock'. */);
14926 Vw32_enable_num_lock = Qt;
14927
14928 DEFVAR_LISP ("w32-enable-caps-lock",
14929 &Vw32_enable_caps_lock,
14930 doc: /* Non-nil if Caps Lock should act normally.
14931 Set to nil to see Caps Lock as the key `capslock'. */);
14932 Vw32_enable_caps_lock = Qt;
14933
14934 DEFVAR_LISP ("w32-scroll-lock-modifier",
14935 &Vw32_scroll_lock_modifier,
14936 doc: /* Modifier to use for the Scroll Lock on state.
14937 The value can be hyper, super, meta, alt, control or shift for the
14938 respective modifier, or nil to see Scroll Lock as the key `scroll'.
14939 Any other value will cause the key to be ignored. */);
14940 Vw32_scroll_lock_modifier = Qt;
14941
14942 DEFVAR_LISP ("w32-lwindow-modifier",
14943 &Vw32_lwindow_modifier,
14944 doc: /* Modifier to use for the left \"Windows\" key.
14945 The value can be hyper, super, meta, alt, control or shift for the
14946 respective modifier, or nil to appear as the key `lwindow'.
14947 Any other value will cause the key to be ignored. */);
14948 Vw32_lwindow_modifier = Qnil;
14949
14950 DEFVAR_LISP ("w32-rwindow-modifier",
14951 &Vw32_rwindow_modifier,
14952 doc: /* Modifier to use for the right \"Windows\" key.
14953 The value can be hyper, super, meta, alt, control or shift for the
14954 respective modifier, or nil to appear as the key `rwindow'.
14955 Any other value will cause the key to be ignored. */);
14956 Vw32_rwindow_modifier = Qnil;
14957
14958 DEFVAR_LISP ("w32-apps-modifier",
14959 &Vw32_apps_modifier,
14960 doc: /* Modifier to use for the \"Apps\" key.
14961 The value can be hyper, super, meta, alt, control or shift for the
14962 respective modifier, or nil to appear as the key `apps'.
14963 Any other value will cause the key to be ignored. */);
14964 Vw32_apps_modifier = Qnil;
14965
14966 DEFVAR_BOOL ("w32-enable-synthesized-fonts", &w32_enable_synthesized_fonts,
14967 doc: /* Non-nil enables selection of artificially italicized and bold fonts. */);
14968 w32_enable_synthesized_fonts = 0;
14969
14970 DEFVAR_LISP ("w32-enable-palette", &Vw32_enable_palette,
14971 doc: /* Non-nil enables Windows palette management to map colors exactly. */);
14972 Vw32_enable_palette = Qt;
14973
14974 DEFVAR_INT ("w32-mouse-button-tolerance",
14975 &Vw32_mouse_button_tolerance,
14976 doc: /* Analogue of double click interval for faking middle mouse events.
14977 The value is the minimum time in milliseconds that must elapse between
14978 left/right button down events before they are considered distinct events.
14979 If both mouse buttons are depressed within this interval, a middle mouse
14980 button down event is generated instead. */);
14981 XSETINT (Vw32_mouse_button_tolerance, GetDoubleClickTime () / 2);
14982
14983 DEFVAR_INT ("w32-mouse-move-interval",
14984 &Vw32_mouse_move_interval,
14985 doc: /* Minimum interval between mouse move events.
14986 The value is the minimum time in milliseconds that must elapse between
14987 successive mouse move (or scroll bar drag) events before they are
14988 reported as lisp events. */);
14989 XSETINT (Vw32_mouse_move_interval, 0);
14990
14991 DEFVAR_BOOL ("w32-pass-extra-mouse-buttons-to-system",
14992 &w32_pass_extra_mouse_buttons_to_system,
14993 doc: /* Non-nil if the fourth and fifth mouse buttons are passed to Windows.
14994 Recent versions of Windows support mice with up to five buttons.
14995 Since most applications don't support these extra buttons, most mouse
14996 drivers will allow you to map them to functions at the system level.
14997 If this variable is non-nil, Emacs will pass them on, allowing the
14998 system to handle them. */);
14999 w32_pass_extra_mouse_buttons_to_system = 0;
15000
15001 init_x_parm_symbols ();
15002
15003 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
15004 doc: /* List of directories to search for bitmap files for w32. */);
15005 Vx_bitmap_file_path = decode_env_path ((char *) 0, "PATH");
15006
15007 DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
15008 doc: /* The shape of the pointer when over text.
15009 Changing the value does not affect existing frames
15010 unless you set the mouse color. */);
15011 Vx_pointer_shape = Qnil;
15012
15013 DEFVAR_LISP ("x-resource-name", &Vx_resource_name,
15014 doc: /* The name Emacs uses to look up resources; for internal use only.
15015 `x-get-resource' uses this as the first component of the instance name
15016 when requesting resource values.
15017 Emacs initially sets `x-resource-name' to the name under which Emacs
15018 was invoked, or to the value specified with the `-name' or `-rn'
15019 switches, if present. */);
15020 Vx_resource_name = Qnil;
15021
15022 Vx_nontext_pointer_shape = Qnil;
15023
15024 Vx_mode_pointer_shape = Qnil;
15025
15026 DEFVAR_LISP ("x-hourglass-pointer-shape", &Vx_hourglass_pointer_shape,
15027 doc: /* The shape of the pointer when Emacs is busy.
15028 This variable takes effect when you create a new frame
15029 or when you set the mouse color. */);
15030 Vx_hourglass_pointer_shape = Qnil;
15031
15032 DEFVAR_BOOL ("display-hourglass", &display_hourglass_p,
15033 doc: /* Non-zero means Emacs displays an hourglass pointer on window systems. */);
15034 display_hourglass_p = 1;
15035
15036 DEFVAR_LISP ("hourglass-delay", &Vhourglass_delay,
15037 doc: /* *Seconds to wait before displaying an hourglass pointer.
15038 Value must be an integer or float. */);
15039 Vhourglass_delay = make_number (DEFAULT_HOURGLASS_DELAY);
15040
15041 DEFVAR_LISP ("x-sensitive-text-pointer-shape",
15042 &Vx_sensitive_text_pointer_shape,
15043 doc: /* The shape of the pointer when over mouse-sensitive text.
15044 This variable takes effect when you create a new frame
15045 or when you set the mouse color. */);
15046 Vx_sensitive_text_pointer_shape = Qnil;
15047
15048 DEFVAR_LISP ("x-window-horizontal-drag-cursor",
15049 &Vx_window_horizontal_drag_shape,
15050 doc: /* Pointer shape to use for indicating a window can be dragged horizontally.
15051 This variable takes effect when you create a new frame
15052 or when you set the mouse color. */);
15053 Vx_window_horizontal_drag_shape = Qnil;
15054
15055 DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
15056 doc: /* A string indicating the foreground color of the cursor box. */);
15057 Vx_cursor_fore_pixel = Qnil;
15058
15059 DEFVAR_LISP ("x-max-tooltip-size", &Vx_max_tooltip_size,
15060 doc: /* Maximum size for tooltips.
15061 Value is a pair (COLUMNS . ROWS). Text larger than this is clipped. */);
15062 Vx_max_tooltip_size = Fcons (make_number (80), make_number (40));
15063
15064 DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
15065 doc: /* Non-nil if no window manager is in use.
15066 Emacs doesn't try to figure this out; this is always nil
15067 unless you set it to something else. */);
15068 /* We don't have any way to find this out, so set it to nil
15069 and maybe the user would like to set it to t. */
15070 Vx_no_window_manager = Qnil;
15071
15072 DEFVAR_LISP ("x-pixel-size-width-font-regexp",
15073 &Vx_pixel_size_width_font_regexp,
15074 doc: /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'.
15075
15076 Since Emacs gets width of a font matching with this regexp from
15077 PIXEL_SIZE field of the name, font finding mechanism gets faster for
15078 such a font. This is especially effective for such large fonts as
15079 Chinese, Japanese, and Korean. */);
15080 Vx_pixel_size_width_font_regexp = Qnil;
15081
15082 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
15083 doc: /* Time after which cached images are removed from the cache.
15084 When an image has not been displayed this many seconds, remove it
15085 from the image cache. Value must be an integer or nil with nil
15086 meaning don't clear the cache. */);
15087 Vimage_cache_eviction_delay = make_number (30 * 60);
15088
15089 DEFVAR_LISP ("w32-bdf-filename-alist",
15090 &Vw32_bdf_filename_alist,
15091 doc: /* List of bdf fonts and their corresponding filenames. */);
15092 Vw32_bdf_filename_alist = Qnil;
15093
15094 DEFVAR_BOOL ("w32-strict-fontnames",
15095 &w32_strict_fontnames,
15096 doc: /* Non-nil means only use fonts that are exact matches for those requested.
15097 Default is nil, which allows old fontnames that are not XLFD compliant,
15098 and allows third-party CJK display to work by specifying false charset
15099 fields to trick Emacs into translating to Big5, SJIS etc.
15100 Setting this to t will prevent wrong fonts being selected when
15101 fontsets are automatically created. */);
15102 w32_strict_fontnames = 0;
15103
15104 DEFVAR_BOOL ("w32-strict-painting",
15105 &w32_strict_painting,
15106 doc: /* Non-nil means use strict rules for repainting frames.
15107 Set this to nil to get the old behaviour for repainting; this should
15108 only be necessary if the default setting causes problems. */);
15109 w32_strict_painting = 1;
15110
15111 DEFVAR_LISP ("w32-charset-info-alist",
15112 &Vw32_charset_info_alist,
15113 doc: /* Alist linking Emacs character sets to Windows fonts and codepages.
15114 Each entry should be of the form:
15115
15116 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE))
15117
15118 where CHARSET_NAME is a string used in font names to identify the charset,
15119 WINDOWS_CHARSET is a symbol that can be one of:
15120 w32-charset-ansi, w32-charset-default, w32-charset-symbol,
15121 w32-charset-shiftjis, w32-charset-hangeul, w32-charset-gb2312,
15122 w32-charset-chinesebig5,
15123 #ifdef JOHAB_CHARSET
15124 w32-charset-johab, w32-charset-hebrew,
15125 w32-charset-arabic, w32-charset-greek, w32-charset-turkish,
15126 w32-charset-vietnamese, w32-charset-thai, w32-charset-easteurope,
15127 w32-charset-russian, w32-charset-mac, w32-charset-baltic,
15128 #endif
15129 #ifdef UNICODE_CHARSET
15130 w32-charset-unicode,
15131 #endif
15132 or w32-charset-oem.
15133 CODEPAGE should be an integer specifying the codepage that should be used
15134 to display the character set, t to do no translation and output as Unicode,
15135 or nil to do no translation and output as 8 bit (or multibyte on far-east
15136 versions of Windows) characters. */);
15137 Vw32_charset_info_alist = Qnil;
15138
15139 staticpro (&Qw32_charset_ansi);
15140 Qw32_charset_ansi = intern ("w32-charset-ansi");
15141 staticpro (&Qw32_charset_symbol);
15142 Qw32_charset_symbol = intern ("w32-charset-symbol");
15143 staticpro (&Qw32_charset_shiftjis);
15144 Qw32_charset_shiftjis = intern ("w32-charset-shiftjis");
15145 staticpro (&Qw32_charset_hangeul);
15146 Qw32_charset_hangeul = intern ("w32-charset-hangeul");
15147 staticpro (&Qw32_charset_chinesebig5);
15148 Qw32_charset_chinesebig5 = intern ("w32-charset-chinesebig5");
15149 staticpro (&Qw32_charset_gb2312);
15150 Qw32_charset_gb2312 = intern ("w32-charset-gb2312");
15151 staticpro (&Qw32_charset_oem);
15152 Qw32_charset_oem = intern ("w32-charset-oem");
15153
15154 #ifdef JOHAB_CHARSET
15155 {
15156 static int w32_extra_charsets_defined = 1;
15157 DEFVAR_BOOL ("w32-extra-charsets-defined", &w32_extra_charsets_defined,
15158 doc: /* Internal variable. */);
15159
15160 staticpro (&Qw32_charset_johab);
15161 Qw32_charset_johab = intern ("w32-charset-johab");
15162 staticpro (&Qw32_charset_easteurope);
15163 Qw32_charset_easteurope = intern ("w32-charset-easteurope");
15164 staticpro (&Qw32_charset_turkish);
15165 Qw32_charset_turkish = intern ("w32-charset-turkish");
15166 staticpro (&Qw32_charset_baltic);
15167 Qw32_charset_baltic = intern ("w32-charset-baltic");
15168 staticpro (&Qw32_charset_russian);
15169 Qw32_charset_russian = intern ("w32-charset-russian");
15170 staticpro (&Qw32_charset_arabic);
15171 Qw32_charset_arabic = intern ("w32-charset-arabic");
15172 staticpro (&Qw32_charset_greek);
15173 Qw32_charset_greek = intern ("w32-charset-greek");
15174 staticpro (&Qw32_charset_hebrew);
15175 Qw32_charset_hebrew = intern ("w32-charset-hebrew");
15176 staticpro (&Qw32_charset_vietnamese);
15177 Qw32_charset_vietnamese = intern ("w32-charset-vietnamese");
15178 staticpro (&Qw32_charset_thai);
15179 Qw32_charset_thai = intern ("w32-charset-thai");
15180 staticpro (&Qw32_charset_mac);
15181 Qw32_charset_mac = intern ("w32-charset-mac");
15182 }
15183 #endif
15184
15185 #ifdef UNICODE_CHARSET
15186 {
15187 static int w32_unicode_charset_defined = 1;
15188 DEFVAR_BOOL ("w32-unicode-charset-defined",
15189 &w32_unicode_charset_defined,
15190 doc: /* Internal variable. */);
15191
15192 staticpro (&Qw32_charset_unicode);
15193 Qw32_charset_unicode = intern ("w32-charset-unicode");
15194 #endif
15195
15196 defsubr (&Sx_get_resource);
15197 #if 0 /* TODO: Port to W32 */
15198 defsubr (&Sx_change_window_property);
15199 defsubr (&Sx_delete_window_property);
15200 defsubr (&Sx_window_property);
15201 #endif
15202 defsubr (&Sxw_display_color_p);
15203 defsubr (&Sx_display_grayscale_p);
15204 defsubr (&Sxw_color_defined_p);
15205 defsubr (&Sxw_color_values);
15206 defsubr (&Sx_server_max_request_size);
15207 defsubr (&Sx_server_vendor);
15208 defsubr (&Sx_server_version);
15209 defsubr (&Sx_display_pixel_width);
15210 defsubr (&Sx_display_pixel_height);
15211 defsubr (&Sx_display_mm_width);
15212 defsubr (&Sx_display_mm_height);
15213 defsubr (&Sx_display_screens);
15214 defsubr (&Sx_display_planes);
15215 defsubr (&Sx_display_color_cells);
15216 defsubr (&Sx_display_visual_class);
15217 defsubr (&Sx_display_backing_store);
15218 defsubr (&Sx_display_save_under);
15219 defsubr (&Sx_parse_geometry);
15220 defsubr (&Sx_create_frame);
15221 defsubr (&Sx_open_connection);
15222 defsubr (&Sx_close_connection);
15223 defsubr (&Sx_display_list);
15224 defsubr (&Sx_synchronize);
15225
15226 /* W32 specific functions */
15227
15228 defsubr (&Sw32_focus_frame);
15229 defsubr (&Sw32_select_font);
15230 defsubr (&Sw32_define_rgb_color);
15231 defsubr (&Sw32_default_color_map);
15232 defsubr (&Sw32_load_color_file);
15233 defsubr (&Sw32_send_sys_command);
15234 defsubr (&Sw32_shell_execute);
15235 defsubr (&Sw32_register_hot_key);
15236 defsubr (&Sw32_unregister_hot_key);
15237 defsubr (&Sw32_registered_hot_keys);
15238 defsubr (&Sw32_reconstruct_hot_key);
15239 defsubr (&Sw32_toggle_lock_key);
15240 defsubr (&Sw32_find_bdf_fonts);
15241
15242 defsubr (&Sfile_system_info);
15243
15244 /* Setting callback functions for fontset handler. */
15245 get_font_info_func = w32_get_font_info;
15246
15247 #if 0 /* This function pointer doesn't seem to be used anywhere.
15248 And the pointer assigned has the wrong type, anyway. */
15249 list_fonts_func = w32_list_fonts;
15250 #endif
15251
15252 load_font_func = w32_load_font;
15253 find_ccl_program_func = w32_find_ccl_program;
15254 query_font_func = w32_query_font;
15255 set_frame_fontset_func = x_set_font;
15256 check_window_system_func = check_w32;
15257
15258 #ifdef IMAGES
15259 /* Images. */
15260 Qxbm = intern ("xbm");
15261 staticpro (&Qxbm);
15262 QCconversion = intern (":conversion");
15263 staticpro (&QCconversion);
15264 QCheuristic_mask = intern (":heuristic-mask");
15265 staticpro (&QCheuristic_mask);
15266 QCcolor_symbols = intern (":color-symbols");
15267 staticpro (&QCcolor_symbols);
15268 QCascent = intern (":ascent");
15269 staticpro (&QCascent);
15270 QCmargin = intern (":margin");
15271 staticpro (&QCmargin);
15272 QCrelief = intern (":relief");
15273 staticpro (&QCrelief);
15274 Qpostscript = intern ("postscript");
15275 staticpro (&Qpostscript);
15276 #if 0 /* TODO: These need entries at top of file. */
15277 QCloader = intern (":loader");
15278 staticpro (&QCloader);
15279 QCbounding_box = intern (":bounding-box");
15280 staticpro (&QCbounding_box);
15281 QCpt_width = intern (":pt-width");
15282 staticpro (&QCpt_width);
15283 QCpt_height = intern (":pt-height");
15284 staticpro (&QCpt_height);
15285 #endif
15286 QCindex = intern (":index");
15287 staticpro (&QCindex);
15288 Qpbm = intern ("pbm");
15289 staticpro (&Qpbm);
15290 #endif
15291
15292 #if HAVE_XPM
15293 Qxpm = intern ("xpm");
15294 staticpro (&Qxpm);
15295 #endif
15296
15297 #if HAVE_JPEG
15298 Qjpeg = intern ("jpeg");
15299 staticpro (&Qjpeg);
15300 #endif
15301
15302 #if HAVE_TIFF
15303 Qtiff = intern ("tiff");
15304 staticpro (&Qtiff);
15305 #endif
15306
15307 #if HAVE_GIF
15308 Qgif = intern ("gif");
15309 staticpro (&Qgif);
15310 #endif
15311
15312 #if HAVE_PNG
15313 Qpng = intern ("png");
15314 staticpro (&Qpng);
15315 #endif
15316
15317 #ifdef HAVE_IMAGES
15318 defsubr (&Sclear_image_cache);
15319 defsubr (&Simage_size);
15320 defsubr (&Simage_mask_p);
15321 #endif
15322
15323 #if GLYPH_DEBUG
15324 defsubr (&Simagep);
15325 defsubr (&Slookup_image);
15326 #endif
15327
15328 hourglass_atimer = NULL;
15329 hourglass_shown_p = 0;
15330 defsubr (&Sx_show_tip);
15331 defsubr (&Sx_hide_tip);
15332 tip_timer = Qnil;
15333 staticpro (&tip_timer);
15334 tip_frame = Qnil;
15335 staticpro (&tip_frame);
15336
15337 last_show_tip_args = Qnil;
15338 staticpro (&last_show_tip_args);
15339
15340 defsubr (&Sx_file_dialog);
15341 }
15342
15343
15344 void
15345 init_xfns ()
15346 {
15347 image_types = NULL;
15348 Vimage_types = Qnil;
15349
15350 #if HAVE_PBM
15351 define_image_type (&pbm_type);
15352 #endif
15353
15354 #if 0 /* TODO : Image support for W32 */
15355 define_image_type (&xbm_type);
15356 define_image_type (&gs_type);
15357 #endif
15358
15359 #if HAVE_XPM
15360 define_image_type (&xpm_type);
15361 #endif
15362
15363 #if HAVE_JPEG
15364 define_image_type (&jpeg_type);
15365 #endif
15366
15367 #if HAVE_TIFF
15368 define_image_type (&tiff_type);
15369 #endif
15370
15371 #if HAVE_GIF
15372 define_image_type (&gif_type);
15373 #endif
15374
15375 #if HAVE_PNG
15376 define_image_type (&png_type);
15377 #endif
15378 }
15379
15380 #undef abort
15381
15382 void
15383 w32_abort()
15384 {
15385 int button;
15386 button = MessageBox (NULL,
15387 "A fatal error has occurred!\n\n"
15388 "Select Abort to exit, Retry to debug, Ignore to continue",
15389 "Emacs Abort Dialog",
15390 MB_ICONEXCLAMATION | MB_TASKMODAL
15391 | MB_SETFOREGROUND | MB_ABORTRETRYIGNORE);
15392 switch (button)
15393 {
15394 case IDRETRY:
15395 DebugBreak ();
15396 break;
15397 case IDIGNORE:
15398 break;
15399 case IDABORT:
15400 default:
15401 abort ();
15402 break;
15403 }
15404 }
15405
15406 /* For convenience when debugging. */
15407 int
15408 w32_last_error()
15409 {
15410 return GetLastError ();
15411 }