(w32_createwindow): Remove the WS_CLIPCHILDREN style
[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 #define max(a, b) ((a) > (b) ? (a) : (b))
56
57 extern void free_frame_menubar ();
58 extern double atof ();
59 extern int w32_console_toggle_lock_key (int vk_code, Lisp_Object new_state);
60 extern int quit_char;
61
62 /* A definition of XColor for non-X frames. */
63 #ifndef HAVE_X_WINDOWS
64 typedef struct {
65 unsigned long pixel;
66 unsigned short red, green, blue;
67 char flags;
68 char pad;
69 } XColor;
70 #endif
71
72 extern char *lispy_function_keys[];
73
74 /* The gray bitmap `bitmaps/gray'. This is done because w32term.c uses
75 it, and including `bitmaps/gray' more than once is a problem when
76 config.h defines `static' as an empty replacement string. */
77
78 int gray_bitmap_width = gray_width;
79 int gray_bitmap_height = gray_height;
80 unsigned char *gray_bitmap_bits = gray_bits;
81
82 /* The colormap for converting color names to RGB values */
83 Lisp_Object Vw32_color_map;
84
85 /* Non nil if alt key presses are passed on to Windows. */
86 Lisp_Object Vw32_pass_alt_to_system;
87
88 /* Non nil if alt key is translated to meta_modifier, nil if it is translated
89 to alt_modifier. */
90 Lisp_Object Vw32_alt_is_meta;
91
92 /* If non-zero, the windows virtual key code for an alternative quit key. */
93 Lisp_Object Vw32_quit_key;
94
95 /* Non nil if left window key events are passed on to Windows (this only
96 affects whether "tapping" the key opens the Start menu). */
97 Lisp_Object Vw32_pass_lwindow_to_system;
98
99 /* Non nil if right window key events are passed on to Windows (this
100 only affects whether "tapping" the key opens the Start menu). */
101 Lisp_Object Vw32_pass_rwindow_to_system;
102
103 /* Virtual key code used to generate "phantom" key presses in order
104 to stop system from acting on Windows key events. */
105 Lisp_Object Vw32_phantom_key_code;
106
107 /* Modifier associated with the left "Windows" key, or nil to act as a
108 normal key. */
109 Lisp_Object Vw32_lwindow_modifier;
110
111 /* Modifier associated with the right "Windows" key, or nil to act as a
112 normal key. */
113 Lisp_Object Vw32_rwindow_modifier;
114
115 /* Modifier associated with the "Apps" key, or nil to act as a normal
116 key. */
117 Lisp_Object Vw32_apps_modifier;
118
119 /* Value is nil if Num Lock acts as a function key. */
120 Lisp_Object Vw32_enable_num_lock;
121
122 /* Value is nil if Caps Lock acts as a function key. */
123 Lisp_Object Vw32_enable_caps_lock;
124
125 /* Modifier associated with Scroll Lock, or nil to act as a normal key. */
126 Lisp_Object Vw32_scroll_lock_modifier;
127
128 /* Switch to control whether we inhibit requests for synthesized bold
129 and italic versions of fonts. */
130 Lisp_Object Vw32_enable_synthesized_fonts;
131
132 /* Enable palette management. */
133 Lisp_Object Vw32_enable_palette;
134
135 /* Control how close left/right button down events must be to
136 be converted to a middle button down event. */
137 Lisp_Object Vw32_mouse_button_tolerance;
138
139 /* Minimum interval between mouse movement (and scroll bar drag)
140 events that are passed on to the event loop. */
141 Lisp_Object Vw32_mouse_move_interval;
142
143 /* The name we're using in resource queries. */
144 Lisp_Object Vx_resource_name;
145
146 /* Non nil if no window manager is in use. */
147 Lisp_Object Vx_no_window_manager;
148
149 /* Non-zero means we're allowed to display a hourglass pointer. */
150
151 int display_hourglass_p;
152
153 /* The background and shape of the mouse pointer, and shape when not
154 over text or in the modeline. */
155
156 Lisp_Object Vx_pointer_shape, Vx_nontext_pointer_shape, Vx_mode_pointer_shape;
157 Lisp_Object Vx_hourglass_pointer_shape, Vx_window_horizontal_drag_shape;
158
159 /* The shape when over mouse-sensitive text. */
160
161 Lisp_Object Vx_sensitive_text_pointer_shape;
162
163 /* Color of chars displayed in cursor box. */
164
165 Lisp_Object Vx_cursor_fore_pixel;
166
167 /* Nonzero if using Windows. */
168
169 static int w32_in_use;
170
171 /* Search path for bitmap files. */
172
173 Lisp_Object Vx_bitmap_file_path;
174
175 /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'. */
176
177 Lisp_Object Vx_pixel_size_width_font_regexp;
178
179 /* Alist of bdf fonts and the files that define them. */
180 Lisp_Object Vw32_bdf_filename_alist;
181
182 Lisp_Object Vw32_system_coding_system;
183
184 /* A flag to control whether fonts are matched strictly or not. */
185 int w32_strict_fontnames;
186
187 /* A flag to control whether we should only repaint if GetUpdateRect
188 indicates there is an update region. */
189 int w32_strict_painting;
190
191 /* Associative list linking character set strings to Windows codepages. */
192 Lisp_Object Vw32_charset_info_alist;
193
194 /* VIETNAMESE_CHARSET is not defined in some versions of MSVC. */
195 #ifndef VIETNAMESE_CHARSET
196 #define VIETNAMESE_CHARSET 163
197 #endif
198
199 Lisp_Object Qauto_raise;
200 Lisp_Object Qauto_lower;
201 Lisp_Object Qbar;
202 Lisp_Object Qborder_color;
203 Lisp_Object Qborder_width;
204 Lisp_Object Qbox;
205 Lisp_Object Qcursor_color;
206 Lisp_Object Qcursor_type;
207 Lisp_Object Qgeometry;
208 Lisp_Object Qicon_left;
209 Lisp_Object Qicon_top;
210 Lisp_Object Qicon_type;
211 Lisp_Object Qicon_name;
212 Lisp_Object Qinternal_border_width;
213 Lisp_Object Qleft;
214 Lisp_Object Qright;
215 Lisp_Object Qmouse_color;
216 Lisp_Object Qnone;
217 Lisp_Object Qparent_id;
218 Lisp_Object Qscroll_bar_width;
219 Lisp_Object Qsuppress_icon;
220 Lisp_Object Qundefined_color;
221 Lisp_Object Qvertical_scroll_bars;
222 Lisp_Object Qvisibility;
223 Lisp_Object Qwindow_id;
224 Lisp_Object Qx_frame_parameter;
225 Lisp_Object Qx_resource_name;
226 Lisp_Object Quser_position;
227 Lisp_Object Quser_size;
228 Lisp_Object Qscreen_gamma;
229 Lisp_Object Qline_spacing;
230 Lisp_Object Qcenter;
231 Lisp_Object Qcancel_timer;
232 Lisp_Object Qhyper;
233 Lisp_Object Qsuper;
234 Lisp_Object Qmeta;
235 Lisp_Object Qalt;
236 Lisp_Object Qctrl;
237 Lisp_Object Qcontrol;
238 Lisp_Object Qshift;
239
240 Lisp_Object Qw32_charset_ansi;
241 Lisp_Object Qw32_charset_default;
242 Lisp_Object Qw32_charset_symbol;
243 Lisp_Object Qw32_charset_shiftjis;
244 Lisp_Object Qw32_charset_hangeul;
245 Lisp_Object Qw32_charset_gb2312;
246 Lisp_Object Qw32_charset_chinesebig5;
247 Lisp_Object Qw32_charset_oem;
248
249 #ifndef JOHAB_CHARSET
250 #define JOHAB_CHARSET 130
251 #endif
252 #ifdef JOHAB_CHARSET
253 Lisp_Object Qw32_charset_easteurope;
254 Lisp_Object Qw32_charset_turkish;
255 Lisp_Object Qw32_charset_baltic;
256 Lisp_Object Qw32_charset_russian;
257 Lisp_Object Qw32_charset_arabic;
258 Lisp_Object Qw32_charset_greek;
259 Lisp_Object Qw32_charset_hebrew;
260 Lisp_Object Qw32_charset_vietnamese;
261 Lisp_Object Qw32_charset_thai;
262 Lisp_Object Qw32_charset_johab;
263 Lisp_Object Qw32_charset_mac;
264 #endif
265
266 #ifdef UNICODE_CHARSET
267 Lisp_Object Qw32_charset_unicode;
268 #endif
269
270 extern Lisp_Object Qtop;
271 extern Lisp_Object Qdisplay;
272 extern Lisp_Object Qtool_bar_lines;
273
274 /* State variables for emulating a three button mouse. */
275 #define LMOUSE 1
276 #define MMOUSE 2
277 #define RMOUSE 4
278
279 static int button_state = 0;
280 static W32Msg saved_mouse_button_msg;
281 static unsigned mouse_button_timer; /* non-zero when timer is active */
282 static W32Msg saved_mouse_move_msg;
283 static unsigned mouse_move_timer;
284
285 /* W95 mousewheel handler */
286 unsigned int msh_mousewheel = 0;
287
288 #define MOUSE_BUTTON_ID 1
289 #define MOUSE_MOVE_ID 2
290
291 /* The below are defined in frame.c. */
292
293 extern Lisp_Object Qheight, Qminibuffer, Qname, Qonly, Qwidth;
294 extern Lisp_Object Qunsplittable, Qmenu_bar_lines, Qbuffer_predicate, Qtitle;
295 extern Lisp_Object Qtool_bar_lines;
296
297 extern Lisp_Object Vwindow_system_version;
298
299 Lisp_Object Qface_set_after_frame_default;
300
301 #ifdef GLYPH_DEBUG
302 int image_cache_refcount, dpyinfo_refcount;
303 #endif
304
305
306 /* From w32term.c. */
307 extern Lisp_Object Vw32_num_mouse_buttons;
308 extern Lisp_Object Vw32_recognize_altgr;
309
310 \f
311 /* Error if we are not connected to MS-Windows. */
312 void
313 check_w32 ()
314 {
315 if (! w32_in_use)
316 error ("MS-Windows not in use or not initialized");
317 }
318
319 /* Nonzero if we can use mouse menus.
320 You should not call this unless HAVE_MENUS is defined. */
321
322 int
323 have_menus_p ()
324 {
325 return w32_in_use;
326 }
327
328 /* Extract a frame as a FRAME_PTR, defaulting to the selected frame
329 and checking validity for W32. */
330
331 FRAME_PTR
332 check_x_frame (frame)
333 Lisp_Object frame;
334 {
335 FRAME_PTR f;
336
337 if (NILP (frame))
338 frame = selected_frame;
339 CHECK_LIVE_FRAME (frame, 0);
340 f = XFRAME (frame);
341 if (! FRAME_W32_P (f))
342 error ("non-w32 frame used");
343 return f;
344 }
345
346 /* Let the user specify an display with a frame.
347 nil stands for the selected frame--or, if that is not a w32 frame,
348 the first display on the list. */
349
350 static struct w32_display_info *
351 check_x_display_info (frame)
352 Lisp_Object frame;
353 {
354 if (NILP (frame))
355 {
356 struct frame *sf = XFRAME (selected_frame);
357
358 if (FRAME_W32_P (sf) && FRAME_LIVE_P (sf))
359 return FRAME_W32_DISPLAY_INFO (sf);
360 else
361 return &one_w32_display_info;
362 }
363 else if (STRINGP (frame))
364 return x_display_info_for_name (frame);
365 else
366 {
367 FRAME_PTR f;
368
369 CHECK_LIVE_FRAME (frame, 0);
370 f = XFRAME (frame);
371 if (! FRAME_W32_P (f))
372 error ("non-w32 frame used");
373 return FRAME_W32_DISPLAY_INFO (f);
374 }
375 }
376 \f
377 /* Return the Emacs frame-object corresponding to an w32 window.
378 It could be the frame's main window or an icon window. */
379
380 /* This function can be called during GC, so use GC_xxx type test macros. */
381
382 struct frame *
383 x_window_to_frame (dpyinfo, wdesc)
384 struct w32_display_info *dpyinfo;
385 HWND wdesc;
386 {
387 Lisp_Object tail, frame;
388 struct frame *f;
389
390 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
391 {
392 frame = XCAR (tail);
393 if (!GC_FRAMEP (frame))
394 continue;
395 f = XFRAME (frame);
396 if (!FRAME_W32_P (f) || FRAME_W32_DISPLAY_INFO (f) != dpyinfo)
397 continue;
398 if (f->output_data.w32->hourglass_window == wdesc)
399 return f;
400
401 /* TODO: Check tooltips when supported. */
402 if (FRAME_W32_WINDOW (f) == wdesc)
403 return f;
404 }
405 return 0;
406 }
407
408 \f
409
410 /* Code to deal with bitmaps. Bitmaps are referenced by their bitmap
411 id, which is just an int that this section returns. Bitmaps are
412 reference counted so they can be shared among frames.
413
414 Bitmap indices are guaranteed to be > 0, so a negative number can
415 be used to indicate no bitmap.
416
417 If you use x_create_bitmap_from_data, then you must keep track of
418 the bitmaps yourself. That is, creating a bitmap from the same
419 data more than once will not be caught. */
420
421
422 /* Functions to access the contents of a bitmap, given an id. */
423
424 int
425 x_bitmap_height (f, id)
426 FRAME_PTR f;
427 int id;
428 {
429 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].height;
430 }
431
432 int
433 x_bitmap_width (f, id)
434 FRAME_PTR f;
435 int id;
436 {
437 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].width;
438 }
439
440 int
441 x_bitmap_pixmap (f, id)
442 FRAME_PTR f;
443 int id;
444 {
445 return (int) FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
446 }
447
448
449 /* Allocate a new bitmap record. Returns index of new record. */
450
451 static int
452 x_allocate_bitmap_record (f)
453 FRAME_PTR f;
454 {
455 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
456 int i;
457
458 if (dpyinfo->bitmaps == NULL)
459 {
460 dpyinfo->bitmaps_size = 10;
461 dpyinfo->bitmaps
462 = (struct w32_bitmap_record *) xmalloc (dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
463 dpyinfo->bitmaps_last = 1;
464 return 1;
465 }
466
467 if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size)
468 return ++dpyinfo->bitmaps_last;
469
470 for (i = 0; i < dpyinfo->bitmaps_size; ++i)
471 if (dpyinfo->bitmaps[i].refcount == 0)
472 return i + 1;
473
474 dpyinfo->bitmaps_size *= 2;
475 dpyinfo->bitmaps
476 = (struct w32_bitmap_record *) xrealloc (dpyinfo->bitmaps,
477 dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
478 return ++dpyinfo->bitmaps_last;
479 }
480
481 /* Add one reference to the reference count of the bitmap with id ID. */
482
483 void
484 x_reference_bitmap (f, id)
485 FRAME_PTR f;
486 int id;
487 {
488 ++FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
489 }
490
491 /* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at BITS. */
492
493 int
494 x_create_bitmap_from_data (f, bits, width, height)
495 struct frame *f;
496 char *bits;
497 unsigned int width, height;
498 {
499 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
500 Pixmap bitmap;
501 int id;
502
503 bitmap = CreateBitmap (width, height,
504 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_planes,
505 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_cbits,
506 bits);
507
508 if (! bitmap)
509 return -1;
510
511 id = x_allocate_bitmap_record (f);
512 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
513 dpyinfo->bitmaps[id - 1].file = NULL;
514 dpyinfo->bitmaps[id - 1].hinst = NULL;
515 dpyinfo->bitmaps[id - 1].refcount = 1;
516 dpyinfo->bitmaps[id - 1].depth = 1;
517 dpyinfo->bitmaps[id - 1].height = height;
518 dpyinfo->bitmaps[id - 1].width = width;
519
520 return id;
521 }
522
523 /* Create bitmap from file FILE for frame F. */
524
525 int
526 x_create_bitmap_from_file (f, file)
527 struct frame *f;
528 Lisp_Object file;
529 {
530 return -1;
531 #if 0 /* TODO : bitmap support */
532 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
533 unsigned int width, height;
534 HBITMAP bitmap;
535 int xhot, yhot, result, id;
536 Lisp_Object found;
537 int fd;
538 char *filename;
539 HINSTANCE hinst;
540
541 /* Look for an existing bitmap with the same name. */
542 for (id = 0; id < dpyinfo->bitmaps_last; ++id)
543 {
544 if (dpyinfo->bitmaps[id].refcount
545 && dpyinfo->bitmaps[id].file
546 && !strcmp (dpyinfo->bitmaps[id].file, (char *) XSTRING (file)->data))
547 {
548 ++dpyinfo->bitmaps[id].refcount;
549 return id + 1;
550 }
551 }
552
553 /* Search bitmap-file-path for the file, if appropriate. */
554 fd = openp (Vx_bitmap_file_path, file, "", &found, 0);
555 if (fd < 0)
556 return -1;
557 emacs_close (fd);
558
559 filename = (char *) XSTRING (found)->data;
560
561 hinst = LoadLibraryEx (filename, NULL, LOAD_LIBRARY_AS_DATAFILE);
562
563 if (hinst == NULL)
564 return -1;
565
566
567 result = XReadBitmapFile (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
568 filename, &width, &height, &bitmap, &xhot, &yhot);
569 if (result != BitmapSuccess)
570 return -1;
571
572 id = x_allocate_bitmap_record (f);
573 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
574 dpyinfo->bitmaps[id - 1].refcount = 1;
575 dpyinfo->bitmaps[id - 1].file = (char *) xmalloc (XSTRING (file)->size + 1);
576 dpyinfo->bitmaps[id - 1].depth = 1;
577 dpyinfo->bitmaps[id - 1].height = height;
578 dpyinfo->bitmaps[id - 1].width = width;
579 strcpy (dpyinfo->bitmaps[id - 1].file, XSTRING (file)->data);
580
581 return id;
582 #endif /* TODO */
583 }
584
585 /* Remove reference to bitmap with id number ID. */
586
587 void
588 x_destroy_bitmap (f, id)
589 FRAME_PTR f;
590 int id;
591 {
592 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
593
594 if (id > 0)
595 {
596 --dpyinfo->bitmaps[id - 1].refcount;
597 if (dpyinfo->bitmaps[id - 1].refcount == 0)
598 {
599 BLOCK_INPUT;
600 DeleteObject (dpyinfo->bitmaps[id - 1].pixmap);
601 if (dpyinfo->bitmaps[id - 1].file)
602 {
603 xfree (dpyinfo->bitmaps[id - 1].file);
604 dpyinfo->bitmaps[id - 1].file = NULL;
605 }
606 UNBLOCK_INPUT;
607 }
608 }
609 }
610
611 /* Free all the bitmaps for the display specified by DPYINFO. */
612
613 static void
614 x_destroy_all_bitmaps (dpyinfo)
615 struct w32_display_info *dpyinfo;
616 {
617 int i;
618 for (i = 0; i < dpyinfo->bitmaps_last; i++)
619 if (dpyinfo->bitmaps[i].refcount > 0)
620 {
621 DeleteObject (dpyinfo->bitmaps[i].pixmap);
622 if (dpyinfo->bitmaps[i].file)
623 xfree (dpyinfo->bitmaps[i].file);
624 }
625 dpyinfo->bitmaps_last = 0;
626 }
627 \f
628 /* Connect the frame-parameter names for W32 frames
629 to the ways of passing the parameter values to the window system.
630
631 The name of a parameter, as a Lisp symbol,
632 has an `x-frame-parameter' property which is an integer in Lisp
633 but can be interpreted as an `enum x_frame_parm' in C. */
634
635 enum x_frame_parm
636 {
637 X_PARM_FOREGROUND_COLOR,
638 X_PARM_BACKGROUND_COLOR,
639 X_PARM_MOUSE_COLOR,
640 X_PARM_CURSOR_COLOR,
641 X_PARM_BORDER_COLOR,
642 X_PARM_ICON_TYPE,
643 X_PARM_FONT,
644 X_PARM_BORDER_WIDTH,
645 X_PARM_INTERNAL_BORDER_WIDTH,
646 X_PARM_NAME,
647 X_PARM_AUTORAISE,
648 X_PARM_AUTOLOWER,
649 X_PARM_VERT_SCROLL_BAR,
650 X_PARM_VISIBILITY,
651 X_PARM_MENU_BAR_LINES
652 };
653
654
655 struct x_frame_parm_table
656 {
657 char *name;
658 void (*setter) P_ ((struct frame *, Lisp_Object, Lisp_Object));
659 };
660
661 static Lisp_Object unwind_create_frame P_ ((Lisp_Object));
662 static Lisp_Object unwind_create_tip_frame P_ ((Lisp_Object));
663 static void x_change_window_heights P_ ((Lisp_Object, int));
664 /* TODO: Native Input Method support; see x_create_im. */
665 void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
666 static void x_set_line_spacing P_ ((struct frame *, Lisp_Object, Lisp_Object));
667 void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
668 void x_set_mouse_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
669 void x_set_cursor_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
670 void x_set_border_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
671 void x_set_cursor_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
672 void x_set_icon_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
673 void x_set_icon_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
674 void x_set_font P_ ((struct frame *, Lisp_Object, Lisp_Object));
675 void x_set_border_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
676 void x_set_internal_border_width P_ ((struct frame *, Lisp_Object,
677 Lisp_Object));
678 void x_explicitly_set_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
679 void x_set_autoraise P_ ((struct frame *, Lisp_Object, Lisp_Object));
680 void x_set_autolower P_ ((struct frame *, Lisp_Object, Lisp_Object));
681 void x_set_vertical_scroll_bars P_ ((struct frame *, Lisp_Object,
682 Lisp_Object));
683 void x_set_visibility P_ ((struct frame *, Lisp_Object, Lisp_Object));
684 void x_set_menu_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
685 void x_set_scroll_bar_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
686 void x_set_title P_ ((struct frame *, Lisp_Object, Lisp_Object));
687 void x_set_unsplittable P_ ((struct frame *, Lisp_Object, Lisp_Object));
688 void x_set_tool_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
689 static void x_set_screen_gamma P_ ((struct frame *, Lisp_Object, Lisp_Object));
690
691 static struct x_frame_parm_table x_frame_parms[] =
692 {
693 "auto-raise", x_set_autoraise,
694 "auto-lower", x_set_autolower,
695 "background-color", x_set_background_color,
696 "border-color", x_set_border_color,
697 "border-width", x_set_border_width,
698 "cursor-color", x_set_cursor_color,
699 "cursor-type", x_set_cursor_type,
700 "font", x_set_font,
701 "foreground-color", x_set_foreground_color,
702 "icon-name", x_set_icon_name,
703 "icon-type", x_set_icon_type,
704 "internal-border-width", x_set_internal_border_width,
705 "menu-bar-lines", x_set_menu_bar_lines,
706 "mouse-color", x_set_mouse_color,
707 "name", x_explicitly_set_name,
708 "scroll-bar-width", x_set_scroll_bar_width,
709 "title", x_set_title,
710 "unsplittable", x_set_unsplittable,
711 "vertical-scroll-bars", x_set_vertical_scroll_bars,
712 "visibility", x_set_visibility,
713 "tool-bar-lines", x_set_tool_bar_lines,
714 "screen-gamma", x_set_screen_gamma,
715 "line-spacing", x_set_line_spacing
716 };
717
718 /* Attach the `x-frame-parameter' properties to
719 the Lisp symbol names of parameters relevant to W32. */
720
721 void
722 init_x_parm_symbols ()
723 {
724 int i;
725
726 for (i = 0; i < sizeof (x_frame_parms) / sizeof (x_frame_parms[0]); i++)
727 Fput (intern (x_frame_parms[i].name), Qx_frame_parameter,
728 make_number (i));
729 }
730 \f
731 /* Change the parameters of frame F as specified by ALIST.
732 If a parameter is not specially recognized, do nothing;
733 otherwise call the `x_set_...' function for that parameter. */
734
735 void
736 x_set_frame_parameters (f, alist)
737 FRAME_PTR f;
738 Lisp_Object alist;
739 {
740 Lisp_Object tail;
741
742 /* If both of these parameters are present, it's more efficient to
743 set them both at once. So we wait until we've looked at the
744 entire list before we set them. */
745 int width, height;
746
747 /* Same here. */
748 Lisp_Object left, top;
749
750 /* Same with these. */
751 Lisp_Object icon_left, icon_top;
752
753 /* Record in these vectors all the parms specified. */
754 Lisp_Object *parms;
755 Lisp_Object *values;
756 int i, p;
757 int left_no_change = 0, top_no_change = 0;
758 int icon_left_no_change = 0, icon_top_no_change = 0;
759
760 struct gcpro gcpro1, gcpro2;
761
762 i = 0;
763 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
764 i++;
765
766 parms = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
767 values = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
768
769 /* Extract parm names and values into those vectors. */
770
771 i = 0;
772 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
773 {
774 Lisp_Object elt;
775
776 elt = Fcar (tail);
777 parms[i] = Fcar (elt);
778 values[i] = Fcdr (elt);
779 i++;
780 }
781 /* TAIL and ALIST are not used again below here. */
782 alist = tail = Qnil;
783
784 GCPRO2 (*parms, *values);
785 gcpro1.nvars = i;
786 gcpro2.nvars = i;
787
788 /* There is no need to gcpro LEFT, TOP, ICON_LEFT, or ICON_TOP,
789 because their values appear in VALUES and strings are not valid. */
790 top = left = Qunbound;
791 icon_left = icon_top = Qunbound;
792
793 /* Provide default values for HEIGHT and WIDTH. */
794 if (FRAME_NEW_WIDTH (f))
795 width = FRAME_NEW_WIDTH (f);
796 else
797 width = FRAME_WIDTH (f);
798
799 if (FRAME_NEW_HEIGHT (f))
800 height = FRAME_NEW_HEIGHT (f);
801 else
802 height = FRAME_HEIGHT (f);
803
804 /* Process foreground_color and background_color before anything else.
805 They are independent of other properties, but other properties (e.g.,
806 cursor_color) are dependent upon them. */
807 for (p = 0; p < i; p++)
808 {
809 Lisp_Object prop, val;
810
811 prop = parms[p];
812 val = values[p];
813 if (EQ (prop, Qforeground_color) || EQ (prop, Qbackground_color))
814 {
815 register Lisp_Object param_index, old_value;
816
817 param_index = Fget (prop, Qx_frame_parameter);
818 old_value = get_frame_param (f, prop);
819 store_frame_param (f, prop, val);
820 if (NATNUMP (param_index)
821 && (XFASTINT (param_index)
822 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
823 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
824 }
825 }
826
827 /* Now process them in reverse of specified order. */
828 for (i--; i >= 0; i--)
829 {
830 Lisp_Object prop, val;
831
832 prop = parms[i];
833 val = values[i];
834
835 if (EQ (prop, Qwidth) && NUMBERP (val))
836 width = XFASTINT (val);
837 else if (EQ (prop, Qheight) && NUMBERP (val))
838 height = XFASTINT (val);
839 else if (EQ (prop, Qtop))
840 top = val;
841 else if (EQ (prop, Qleft))
842 left = val;
843 else if (EQ (prop, Qicon_top))
844 icon_top = val;
845 else if (EQ (prop, Qicon_left))
846 icon_left = val;
847 else if (EQ (prop, Qforeground_color) || EQ (prop, Qbackground_color))
848 /* Processed above. */
849 continue;
850 else
851 {
852 register Lisp_Object param_index, old_value;
853
854 param_index = Fget (prop, Qx_frame_parameter);
855 old_value = get_frame_param (f, prop);
856 store_frame_param (f, prop, val);
857 if (NATNUMP (param_index)
858 && (XFASTINT (param_index)
859 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
860 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
861 }
862 }
863
864 /* Don't die if just one of these was set. */
865 if (EQ (left, Qunbound))
866 {
867 left_no_change = 1;
868 if (f->output_data.w32->left_pos < 0)
869 left = Fcons (Qplus, Fcons (make_number (f->output_data.w32->left_pos), Qnil));
870 else
871 XSETINT (left, f->output_data.w32->left_pos);
872 }
873 if (EQ (top, Qunbound))
874 {
875 top_no_change = 1;
876 if (f->output_data.w32->top_pos < 0)
877 top = Fcons (Qplus, Fcons (make_number (f->output_data.w32->top_pos), Qnil));
878 else
879 XSETINT (top, f->output_data.w32->top_pos);
880 }
881
882 /* If one of the icon positions was not set, preserve or default it. */
883 if (EQ (icon_left, Qunbound) || ! INTEGERP (icon_left))
884 {
885 icon_left_no_change = 1;
886 icon_left = Fcdr (Fassq (Qicon_left, f->param_alist));
887 if (NILP (icon_left))
888 XSETINT (icon_left, 0);
889 }
890 if (EQ (icon_top, Qunbound) || ! INTEGERP (icon_top))
891 {
892 icon_top_no_change = 1;
893 icon_top = Fcdr (Fassq (Qicon_top, f->param_alist));
894 if (NILP (icon_top))
895 XSETINT (icon_top, 0);
896 }
897
898 /* Don't set these parameters unless they've been explicitly
899 specified. The window might be mapped or resized while we're in
900 this function, and we don't want to override that unless the lisp
901 code has asked for it.
902
903 Don't set these parameters unless they actually differ from the
904 window's current parameters; the window may not actually exist
905 yet. */
906 {
907 Lisp_Object frame;
908
909 check_frame_size (f, &height, &width);
910
911 XSETFRAME (frame, f);
912
913 if (width != FRAME_WIDTH (f)
914 || height != FRAME_HEIGHT (f)
915 || FRAME_NEW_HEIGHT (f) || FRAME_NEW_WIDTH (f))
916 Fset_frame_size (frame, make_number (width), make_number (height));
917
918 if ((!NILP (left) || !NILP (top))
919 && ! (left_no_change && top_no_change)
920 && ! (NUMBERP (left) && XINT (left) == f->output_data.w32->left_pos
921 && NUMBERP (top) && XINT (top) == f->output_data.w32->top_pos))
922 {
923 int leftpos = 0;
924 int toppos = 0;
925
926 /* Record the signs. */
927 f->output_data.w32->size_hint_flags &= ~ (XNegative | YNegative);
928 if (EQ (left, Qminus))
929 f->output_data.w32->size_hint_flags |= XNegative;
930 else if (INTEGERP (left))
931 {
932 leftpos = XINT (left);
933 if (leftpos < 0)
934 f->output_data.w32->size_hint_flags |= XNegative;
935 }
936 else if (CONSP (left) && EQ (XCAR (left), Qminus)
937 && CONSP (XCDR (left))
938 && INTEGERP (XCAR (XCDR (left))))
939 {
940 leftpos = - XINT (XCAR (XCDR (left)));
941 f->output_data.w32->size_hint_flags |= XNegative;
942 }
943 else if (CONSP (left) && EQ (XCAR (left), Qplus)
944 && CONSP (XCDR (left))
945 && INTEGERP (XCAR (XCDR (left))))
946 {
947 leftpos = XINT (XCAR (XCDR (left)));
948 }
949
950 if (EQ (top, Qminus))
951 f->output_data.w32->size_hint_flags |= YNegative;
952 else if (INTEGERP (top))
953 {
954 toppos = XINT (top);
955 if (toppos < 0)
956 f->output_data.w32->size_hint_flags |= YNegative;
957 }
958 else if (CONSP (top) && EQ (XCAR (top), Qminus)
959 && CONSP (XCDR (top))
960 && INTEGERP (XCAR (XCDR (top))))
961 {
962 toppos = - XINT (XCAR (XCDR (top)));
963 f->output_data.w32->size_hint_flags |= YNegative;
964 }
965 else if (CONSP (top) && EQ (XCAR (top), Qplus)
966 && CONSP (XCDR (top))
967 && INTEGERP (XCAR (XCDR (top))))
968 {
969 toppos = XINT (XCAR (XCDR (top)));
970 }
971
972
973 /* Store the numeric value of the position. */
974 f->output_data.w32->top_pos = toppos;
975 f->output_data.w32->left_pos = leftpos;
976
977 f->output_data.w32->win_gravity = NorthWestGravity;
978
979 /* Actually set that position, and convert to absolute. */
980 x_set_offset (f, leftpos, toppos, -1);
981 }
982
983 if ((!NILP (icon_left) || !NILP (icon_top))
984 && ! (icon_left_no_change && icon_top_no_change))
985 x_wm_set_icon_position (f, XINT (icon_left), XINT (icon_top));
986 }
987
988 UNGCPRO;
989 }
990
991 /* Store the screen positions of frame F into XPTR and YPTR.
992 These are the positions of the containing window manager window,
993 not Emacs's own window. */
994
995 void
996 x_real_positions (f, xptr, yptr)
997 FRAME_PTR f;
998 int *xptr, *yptr;
999 {
1000 POINT pt;
1001
1002 {
1003 RECT rect;
1004
1005 GetClientRect(FRAME_W32_WINDOW(f), &rect);
1006 AdjustWindowRect(&rect, f->output_data.w32->dwStyle, FRAME_EXTERNAL_MENU_BAR(f));
1007
1008 pt.x = rect.left;
1009 pt.y = rect.top;
1010 }
1011
1012 ClientToScreen (FRAME_W32_WINDOW(f), &pt);
1013
1014 *xptr = pt.x;
1015 *yptr = pt.y;
1016 }
1017
1018 /* Insert a description of internally-recorded parameters of frame X
1019 into the parameter alist *ALISTPTR that is to be given to the user.
1020 Only parameters that are specific to W32
1021 and whose values are not correctly recorded in the frame's
1022 param_alist need to be considered here. */
1023
1024 void
1025 x_report_frame_params (f, alistptr)
1026 struct frame *f;
1027 Lisp_Object *alistptr;
1028 {
1029 char buf[16];
1030 Lisp_Object tem;
1031
1032 /* Represent negative positions (off the top or left screen edge)
1033 in a way that Fmodify_frame_parameters will understand correctly. */
1034 XSETINT (tem, f->output_data.w32->left_pos);
1035 if (f->output_data.w32->left_pos >= 0)
1036 store_in_alist (alistptr, Qleft, tem);
1037 else
1038 store_in_alist (alistptr, Qleft, Fcons (Qplus, Fcons (tem, Qnil)));
1039
1040 XSETINT (tem, f->output_data.w32->top_pos);
1041 if (f->output_data.w32->top_pos >= 0)
1042 store_in_alist (alistptr, Qtop, tem);
1043 else
1044 store_in_alist (alistptr, Qtop, Fcons (Qplus, Fcons (tem, Qnil)));
1045
1046 store_in_alist (alistptr, Qborder_width,
1047 make_number (f->output_data.w32->border_width));
1048 store_in_alist (alistptr, Qinternal_border_width,
1049 make_number (f->output_data.w32->internal_border_width));
1050 sprintf (buf, "%ld", (long) FRAME_W32_WINDOW (f));
1051 store_in_alist (alistptr, Qwindow_id,
1052 build_string (buf));
1053 store_in_alist (alistptr, Qicon_name, f->icon_name);
1054 FRAME_SAMPLE_VISIBILITY (f);
1055 store_in_alist (alistptr, Qvisibility,
1056 (FRAME_VISIBLE_P (f) ? Qt
1057 : FRAME_ICONIFIED_P (f) ? Qicon : Qnil));
1058 store_in_alist (alistptr, Qdisplay,
1059 XCAR (FRAME_W32_DISPLAY_INFO (f)->name_list_element));
1060 }
1061 \f
1062
1063 DEFUN ("w32-define-rgb-color", Fw32_define_rgb_color, Sw32_define_rgb_color, 4, 4, 0,
1064 "Convert RGB numbers to a windows color reference and associate with NAME (a string).\n\
1065 This adds or updates a named color to w32-color-map, making it available for use.\n\
1066 The original entry's RGB ref is returned, or nil if the entry is new.")
1067 (red, green, blue, name)
1068 Lisp_Object red, green, blue, name;
1069 {
1070 Lisp_Object rgb;
1071 Lisp_Object oldrgb = Qnil;
1072 Lisp_Object entry;
1073
1074 CHECK_NUMBER (red, 0);
1075 CHECK_NUMBER (green, 0);
1076 CHECK_NUMBER (blue, 0);
1077 CHECK_STRING (name, 0);
1078
1079 XSET (rgb, Lisp_Int, RGB(XUINT (red), XUINT (green), XUINT (blue)));
1080
1081 BLOCK_INPUT;
1082
1083 /* replace existing entry in w32-color-map or add new entry. */
1084 entry = Fassoc (name, Vw32_color_map);
1085 if (NILP (entry))
1086 {
1087 entry = Fcons (name, rgb);
1088 Vw32_color_map = Fcons (entry, Vw32_color_map);
1089 }
1090 else
1091 {
1092 oldrgb = Fcdr (entry);
1093 Fsetcdr (entry, rgb);
1094 }
1095
1096 UNBLOCK_INPUT;
1097
1098 return (oldrgb);
1099 }
1100
1101 DEFUN ("w32-load-color-file", Fw32_load_color_file, Sw32_load_color_file, 1, 1, 0,
1102 "Create an alist of color entries from an external file (ie. rgb.txt).\n\
1103 Assign this value to w32-color-map to replace the existing color map.\n\
1104 \
1105 The file should define one named RGB color per line like so:\
1106 R G B name\n\
1107 where R,G,B are numbers between 0 and 255 and name is an arbitrary string.")
1108 (filename)
1109 Lisp_Object filename;
1110 {
1111 FILE *fp;
1112 Lisp_Object cmap = Qnil;
1113 Lisp_Object abspath;
1114
1115 CHECK_STRING (filename, 0);
1116 abspath = Fexpand_file_name (filename, Qnil);
1117
1118 fp = fopen (XSTRING (filename)->data, "rt");
1119 if (fp)
1120 {
1121 char buf[512];
1122 int red, green, blue;
1123 int num;
1124
1125 BLOCK_INPUT;
1126
1127 while (fgets (buf, sizeof (buf), fp) != NULL) {
1128 if (sscanf (buf, "%u %u %u %n", &red, &green, &blue, &num) == 3)
1129 {
1130 char *name = buf + num;
1131 num = strlen (name) - 1;
1132 if (name[num] == '\n')
1133 name[num] = 0;
1134 cmap = Fcons (Fcons (build_string (name),
1135 make_number (RGB (red, green, blue))),
1136 cmap);
1137 }
1138 }
1139 fclose (fp);
1140
1141 UNBLOCK_INPUT;
1142 }
1143
1144 return cmap;
1145 }
1146
1147 /* The default colors for the w32 color map */
1148 typedef struct colormap_t
1149 {
1150 char *name;
1151 COLORREF colorref;
1152 } colormap_t;
1153
1154 colormap_t w32_color_map[] =
1155 {
1156 {"snow" , PALETTERGB (255,250,250)},
1157 {"ghost white" , PALETTERGB (248,248,255)},
1158 {"GhostWhite" , PALETTERGB (248,248,255)},
1159 {"white smoke" , PALETTERGB (245,245,245)},
1160 {"WhiteSmoke" , PALETTERGB (245,245,245)},
1161 {"gainsboro" , PALETTERGB (220,220,220)},
1162 {"floral white" , PALETTERGB (255,250,240)},
1163 {"FloralWhite" , PALETTERGB (255,250,240)},
1164 {"old lace" , PALETTERGB (253,245,230)},
1165 {"OldLace" , PALETTERGB (253,245,230)},
1166 {"linen" , PALETTERGB (250,240,230)},
1167 {"antique white" , PALETTERGB (250,235,215)},
1168 {"AntiqueWhite" , PALETTERGB (250,235,215)},
1169 {"papaya whip" , PALETTERGB (255,239,213)},
1170 {"PapayaWhip" , PALETTERGB (255,239,213)},
1171 {"blanched almond" , PALETTERGB (255,235,205)},
1172 {"BlanchedAlmond" , PALETTERGB (255,235,205)},
1173 {"bisque" , PALETTERGB (255,228,196)},
1174 {"peach puff" , PALETTERGB (255,218,185)},
1175 {"PeachPuff" , PALETTERGB (255,218,185)},
1176 {"navajo white" , PALETTERGB (255,222,173)},
1177 {"NavajoWhite" , PALETTERGB (255,222,173)},
1178 {"moccasin" , PALETTERGB (255,228,181)},
1179 {"cornsilk" , PALETTERGB (255,248,220)},
1180 {"ivory" , PALETTERGB (255,255,240)},
1181 {"lemon chiffon" , PALETTERGB (255,250,205)},
1182 {"LemonChiffon" , PALETTERGB (255,250,205)},
1183 {"seashell" , PALETTERGB (255,245,238)},
1184 {"honeydew" , PALETTERGB (240,255,240)},
1185 {"mint cream" , PALETTERGB (245,255,250)},
1186 {"MintCream" , PALETTERGB (245,255,250)},
1187 {"azure" , PALETTERGB (240,255,255)},
1188 {"alice blue" , PALETTERGB (240,248,255)},
1189 {"AliceBlue" , PALETTERGB (240,248,255)},
1190 {"lavender" , PALETTERGB (230,230,250)},
1191 {"lavender blush" , PALETTERGB (255,240,245)},
1192 {"LavenderBlush" , PALETTERGB (255,240,245)},
1193 {"misty rose" , PALETTERGB (255,228,225)},
1194 {"MistyRose" , PALETTERGB (255,228,225)},
1195 {"white" , PALETTERGB (255,255,255)},
1196 {"black" , PALETTERGB ( 0, 0, 0)},
1197 {"dark slate gray" , PALETTERGB ( 47, 79, 79)},
1198 {"DarkSlateGray" , PALETTERGB ( 47, 79, 79)},
1199 {"dark slate grey" , PALETTERGB ( 47, 79, 79)},
1200 {"DarkSlateGrey" , PALETTERGB ( 47, 79, 79)},
1201 {"dim gray" , PALETTERGB (105,105,105)},
1202 {"DimGray" , PALETTERGB (105,105,105)},
1203 {"dim grey" , PALETTERGB (105,105,105)},
1204 {"DimGrey" , PALETTERGB (105,105,105)},
1205 {"slate gray" , PALETTERGB (112,128,144)},
1206 {"SlateGray" , PALETTERGB (112,128,144)},
1207 {"slate grey" , PALETTERGB (112,128,144)},
1208 {"SlateGrey" , PALETTERGB (112,128,144)},
1209 {"light slate gray" , PALETTERGB (119,136,153)},
1210 {"LightSlateGray" , PALETTERGB (119,136,153)},
1211 {"light slate grey" , PALETTERGB (119,136,153)},
1212 {"LightSlateGrey" , PALETTERGB (119,136,153)},
1213 {"gray" , PALETTERGB (190,190,190)},
1214 {"grey" , PALETTERGB (190,190,190)},
1215 {"light grey" , PALETTERGB (211,211,211)},
1216 {"LightGrey" , PALETTERGB (211,211,211)},
1217 {"light gray" , PALETTERGB (211,211,211)},
1218 {"LightGray" , PALETTERGB (211,211,211)},
1219 {"midnight blue" , PALETTERGB ( 25, 25,112)},
1220 {"MidnightBlue" , PALETTERGB ( 25, 25,112)},
1221 {"navy" , PALETTERGB ( 0, 0,128)},
1222 {"navy blue" , PALETTERGB ( 0, 0,128)},
1223 {"NavyBlue" , PALETTERGB ( 0, 0,128)},
1224 {"cornflower blue" , PALETTERGB (100,149,237)},
1225 {"CornflowerBlue" , PALETTERGB (100,149,237)},
1226 {"dark slate blue" , PALETTERGB ( 72, 61,139)},
1227 {"DarkSlateBlue" , PALETTERGB ( 72, 61,139)},
1228 {"slate blue" , PALETTERGB (106, 90,205)},
1229 {"SlateBlue" , PALETTERGB (106, 90,205)},
1230 {"medium slate blue" , PALETTERGB (123,104,238)},
1231 {"MediumSlateBlue" , PALETTERGB (123,104,238)},
1232 {"light slate blue" , PALETTERGB (132,112,255)},
1233 {"LightSlateBlue" , PALETTERGB (132,112,255)},
1234 {"medium blue" , PALETTERGB ( 0, 0,205)},
1235 {"MediumBlue" , PALETTERGB ( 0, 0,205)},
1236 {"royal blue" , PALETTERGB ( 65,105,225)},
1237 {"RoyalBlue" , PALETTERGB ( 65,105,225)},
1238 {"blue" , PALETTERGB ( 0, 0,255)},
1239 {"dodger blue" , PALETTERGB ( 30,144,255)},
1240 {"DodgerBlue" , PALETTERGB ( 30,144,255)},
1241 {"deep sky blue" , PALETTERGB ( 0,191,255)},
1242 {"DeepSkyBlue" , PALETTERGB ( 0,191,255)},
1243 {"sky blue" , PALETTERGB (135,206,235)},
1244 {"SkyBlue" , PALETTERGB (135,206,235)},
1245 {"light sky blue" , PALETTERGB (135,206,250)},
1246 {"LightSkyBlue" , PALETTERGB (135,206,250)},
1247 {"steel blue" , PALETTERGB ( 70,130,180)},
1248 {"SteelBlue" , PALETTERGB ( 70,130,180)},
1249 {"light steel blue" , PALETTERGB (176,196,222)},
1250 {"LightSteelBlue" , PALETTERGB (176,196,222)},
1251 {"light blue" , PALETTERGB (173,216,230)},
1252 {"LightBlue" , PALETTERGB (173,216,230)},
1253 {"powder blue" , PALETTERGB (176,224,230)},
1254 {"PowderBlue" , PALETTERGB (176,224,230)},
1255 {"pale turquoise" , PALETTERGB (175,238,238)},
1256 {"PaleTurquoise" , PALETTERGB (175,238,238)},
1257 {"dark turquoise" , PALETTERGB ( 0,206,209)},
1258 {"DarkTurquoise" , PALETTERGB ( 0,206,209)},
1259 {"medium turquoise" , PALETTERGB ( 72,209,204)},
1260 {"MediumTurquoise" , PALETTERGB ( 72,209,204)},
1261 {"turquoise" , PALETTERGB ( 64,224,208)},
1262 {"cyan" , PALETTERGB ( 0,255,255)},
1263 {"light cyan" , PALETTERGB (224,255,255)},
1264 {"LightCyan" , PALETTERGB (224,255,255)},
1265 {"cadet blue" , PALETTERGB ( 95,158,160)},
1266 {"CadetBlue" , PALETTERGB ( 95,158,160)},
1267 {"medium aquamarine" , PALETTERGB (102,205,170)},
1268 {"MediumAquamarine" , PALETTERGB (102,205,170)},
1269 {"aquamarine" , PALETTERGB (127,255,212)},
1270 {"dark green" , PALETTERGB ( 0,100, 0)},
1271 {"DarkGreen" , PALETTERGB ( 0,100, 0)},
1272 {"dark olive green" , PALETTERGB ( 85,107, 47)},
1273 {"DarkOliveGreen" , PALETTERGB ( 85,107, 47)},
1274 {"dark sea green" , PALETTERGB (143,188,143)},
1275 {"DarkSeaGreen" , PALETTERGB (143,188,143)},
1276 {"sea green" , PALETTERGB ( 46,139, 87)},
1277 {"SeaGreen" , PALETTERGB ( 46,139, 87)},
1278 {"medium sea green" , PALETTERGB ( 60,179,113)},
1279 {"MediumSeaGreen" , PALETTERGB ( 60,179,113)},
1280 {"light sea green" , PALETTERGB ( 32,178,170)},
1281 {"LightSeaGreen" , PALETTERGB ( 32,178,170)},
1282 {"pale green" , PALETTERGB (152,251,152)},
1283 {"PaleGreen" , PALETTERGB (152,251,152)},
1284 {"spring green" , PALETTERGB ( 0,255,127)},
1285 {"SpringGreen" , PALETTERGB ( 0,255,127)},
1286 {"lawn green" , PALETTERGB (124,252, 0)},
1287 {"LawnGreen" , PALETTERGB (124,252, 0)},
1288 {"green" , PALETTERGB ( 0,255, 0)},
1289 {"chartreuse" , PALETTERGB (127,255, 0)},
1290 {"medium spring green" , PALETTERGB ( 0,250,154)},
1291 {"MediumSpringGreen" , PALETTERGB ( 0,250,154)},
1292 {"green yellow" , PALETTERGB (173,255, 47)},
1293 {"GreenYellow" , PALETTERGB (173,255, 47)},
1294 {"lime green" , PALETTERGB ( 50,205, 50)},
1295 {"LimeGreen" , PALETTERGB ( 50,205, 50)},
1296 {"yellow green" , PALETTERGB (154,205, 50)},
1297 {"YellowGreen" , PALETTERGB (154,205, 50)},
1298 {"forest green" , PALETTERGB ( 34,139, 34)},
1299 {"ForestGreen" , PALETTERGB ( 34,139, 34)},
1300 {"olive drab" , PALETTERGB (107,142, 35)},
1301 {"OliveDrab" , PALETTERGB (107,142, 35)},
1302 {"dark khaki" , PALETTERGB (189,183,107)},
1303 {"DarkKhaki" , PALETTERGB (189,183,107)},
1304 {"khaki" , PALETTERGB (240,230,140)},
1305 {"pale goldenrod" , PALETTERGB (238,232,170)},
1306 {"PaleGoldenrod" , PALETTERGB (238,232,170)},
1307 {"light goldenrod yellow" , PALETTERGB (250,250,210)},
1308 {"LightGoldenrodYellow" , PALETTERGB (250,250,210)},
1309 {"light yellow" , PALETTERGB (255,255,224)},
1310 {"LightYellow" , PALETTERGB (255,255,224)},
1311 {"yellow" , PALETTERGB (255,255, 0)},
1312 {"gold" , PALETTERGB (255,215, 0)},
1313 {"light goldenrod" , PALETTERGB (238,221,130)},
1314 {"LightGoldenrod" , PALETTERGB (238,221,130)},
1315 {"goldenrod" , PALETTERGB (218,165, 32)},
1316 {"dark goldenrod" , PALETTERGB (184,134, 11)},
1317 {"DarkGoldenrod" , PALETTERGB (184,134, 11)},
1318 {"rosy brown" , PALETTERGB (188,143,143)},
1319 {"RosyBrown" , PALETTERGB (188,143,143)},
1320 {"indian red" , PALETTERGB (205, 92, 92)},
1321 {"IndianRed" , PALETTERGB (205, 92, 92)},
1322 {"saddle brown" , PALETTERGB (139, 69, 19)},
1323 {"SaddleBrown" , PALETTERGB (139, 69, 19)},
1324 {"sienna" , PALETTERGB (160, 82, 45)},
1325 {"peru" , PALETTERGB (205,133, 63)},
1326 {"burlywood" , PALETTERGB (222,184,135)},
1327 {"beige" , PALETTERGB (245,245,220)},
1328 {"wheat" , PALETTERGB (245,222,179)},
1329 {"sandy brown" , PALETTERGB (244,164, 96)},
1330 {"SandyBrown" , PALETTERGB (244,164, 96)},
1331 {"tan" , PALETTERGB (210,180,140)},
1332 {"chocolate" , PALETTERGB (210,105, 30)},
1333 {"firebrick" , PALETTERGB (178,34, 34)},
1334 {"brown" , PALETTERGB (165,42, 42)},
1335 {"dark salmon" , PALETTERGB (233,150,122)},
1336 {"DarkSalmon" , PALETTERGB (233,150,122)},
1337 {"salmon" , PALETTERGB (250,128,114)},
1338 {"light salmon" , PALETTERGB (255,160,122)},
1339 {"LightSalmon" , PALETTERGB (255,160,122)},
1340 {"orange" , PALETTERGB (255,165, 0)},
1341 {"dark orange" , PALETTERGB (255,140, 0)},
1342 {"DarkOrange" , PALETTERGB (255,140, 0)},
1343 {"coral" , PALETTERGB (255,127, 80)},
1344 {"light coral" , PALETTERGB (240,128,128)},
1345 {"LightCoral" , PALETTERGB (240,128,128)},
1346 {"tomato" , PALETTERGB (255, 99, 71)},
1347 {"orange red" , PALETTERGB (255, 69, 0)},
1348 {"OrangeRed" , PALETTERGB (255, 69, 0)},
1349 {"red" , PALETTERGB (255, 0, 0)},
1350 {"hot pink" , PALETTERGB (255,105,180)},
1351 {"HotPink" , PALETTERGB (255,105,180)},
1352 {"deep pink" , PALETTERGB (255, 20,147)},
1353 {"DeepPink" , PALETTERGB (255, 20,147)},
1354 {"pink" , PALETTERGB (255,192,203)},
1355 {"light pink" , PALETTERGB (255,182,193)},
1356 {"LightPink" , PALETTERGB (255,182,193)},
1357 {"pale violet red" , PALETTERGB (219,112,147)},
1358 {"PaleVioletRed" , PALETTERGB (219,112,147)},
1359 {"maroon" , PALETTERGB (176, 48, 96)},
1360 {"medium violet red" , PALETTERGB (199, 21,133)},
1361 {"MediumVioletRed" , PALETTERGB (199, 21,133)},
1362 {"violet red" , PALETTERGB (208, 32,144)},
1363 {"VioletRed" , PALETTERGB (208, 32,144)},
1364 {"magenta" , PALETTERGB (255, 0,255)},
1365 {"violet" , PALETTERGB (238,130,238)},
1366 {"plum" , PALETTERGB (221,160,221)},
1367 {"orchid" , PALETTERGB (218,112,214)},
1368 {"medium orchid" , PALETTERGB (186, 85,211)},
1369 {"MediumOrchid" , PALETTERGB (186, 85,211)},
1370 {"dark orchid" , PALETTERGB (153, 50,204)},
1371 {"DarkOrchid" , PALETTERGB (153, 50,204)},
1372 {"dark violet" , PALETTERGB (148, 0,211)},
1373 {"DarkViolet" , PALETTERGB (148, 0,211)},
1374 {"blue violet" , PALETTERGB (138, 43,226)},
1375 {"BlueViolet" , PALETTERGB (138, 43,226)},
1376 {"purple" , PALETTERGB (160, 32,240)},
1377 {"medium purple" , PALETTERGB (147,112,219)},
1378 {"MediumPurple" , PALETTERGB (147,112,219)},
1379 {"thistle" , PALETTERGB (216,191,216)},
1380 {"gray0" , PALETTERGB ( 0, 0, 0)},
1381 {"grey0" , PALETTERGB ( 0, 0, 0)},
1382 {"dark grey" , PALETTERGB (169,169,169)},
1383 {"DarkGrey" , PALETTERGB (169,169,169)},
1384 {"dark gray" , PALETTERGB (169,169,169)},
1385 {"DarkGray" , PALETTERGB (169,169,169)},
1386 {"dark blue" , PALETTERGB ( 0, 0,139)},
1387 {"DarkBlue" , PALETTERGB ( 0, 0,139)},
1388 {"dark cyan" , PALETTERGB ( 0,139,139)},
1389 {"DarkCyan" , PALETTERGB ( 0,139,139)},
1390 {"dark magenta" , PALETTERGB (139, 0,139)},
1391 {"DarkMagenta" , PALETTERGB (139, 0,139)},
1392 {"dark red" , PALETTERGB (139, 0, 0)},
1393 {"DarkRed" , PALETTERGB (139, 0, 0)},
1394 {"light green" , PALETTERGB (144,238,144)},
1395 {"LightGreen" , PALETTERGB (144,238,144)},
1396 };
1397
1398 DEFUN ("w32-default-color-map", Fw32_default_color_map, Sw32_default_color_map,
1399 0, 0, 0, "Return the default color map.")
1400 ()
1401 {
1402 int i;
1403 colormap_t *pc = w32_color_map;
1404 Lisp_Object cmap;
1405
1406 BLOCK_INPUT;
1407
1408 cmap = Qnil;
1409
1410 for (i = 0; i < sizeof (w32_color_map) / sizeof (w32_color_map[0]);
1411 pc++, i++)
1412 cmap = Fcons (Fcons (build_string (pc->name),
1413 make_number (pc->colorref)),
1414 cmap);
1415
1416 UNBLOCK_INPUT;
1417
1418 return (cmap);
1419 }
1420
1421 Lisp_Object
1422 w32_to_x_color (rgb)
1423 Lisp_Object rgb;
1424 {
1425 Lisp_Object color;
1426
1427 CHECK_NUMBER (rgb, 0);
1428
1429 BLOCK_INPUT;
1430
1431 color = Frassq (rgb, Vw32_color_map);
1432
1433 UNBLOCK_INPUT;
1434
1435 if (!NILP (color))
1436 return (Fcar (color));
1437 else
1438 return Qnil;
1439 }
1440
1441 COLORREF
1442 w32_color_map_lookup (colorname)
1443 char *colorname;
1444 {
1445 Lisp_Object tail, ret = Qnil;
1446
1447 BLOCK_INPUT;
1448
1449 for (tail = Vw32_color_map; !NILP (tail); tail = Fcdr (tail))
1450 {
1451 register Lisp_Object elt, tem;
1452
1453 elt = Fcar (tail);
1454 if (!CONSP (elt)) continue;
1455
1456 tem = Fcar (elt);
1457
1458 if (lstrcmpi (XSTRING (tem)->data, colorname) == 0)
1459 {
1460 ret = XUINT (Fcdr (elt));
1461 break;
1462 }
1463
1464 QUIT;
1465 }
1466
1467
1468 UNBLOCK_INPUT;
1469
1470 return ret;
1471 }
1472
1473 COLORREF
1474 x_to_w32_color (colorname)
1475 char * colorname;
1476 {
1477 register Lisp_Object ret = Qnil;
1478
1479 BLOCK_INPUT;
1480
1481 if (colorname[0] == '#')
1482 {
1483 /* Could be an old-style RGB Device specification. */
1484 char *color;
1485 int size;
1486 color = colorname + 1;
1487
1488 size = strlen(color);
1489 if (size == 3 || size == 6 || size == 9 || size == 12)
1490 {
1491 UINT colorval;
1492 int i, pos;
1493 pos = 0;
1494 size /= 3;
1495 colorval = 0;
1496
1497 for (i = 0; i < 3; i++)
1498 {
1499 char *end;
1500 char t;
1501 unsigned long value;
1502
1503 /* The check for 'x' in the following conditional takes into
1504 account the fact that strtol allows a "0x" in front of
1505 our numbers, and we don't. */
1506 if (!isxdigit(color[0]) || color[1] == 'x')
1507 break;
1508 t = color[size];
1509 color[size] = '\0';
1510 value = strtoul(color, &end, 16);
1511 color[size] = t;
1512 if (errno == ERANGE || end - color != size)
1513 break;
1514 switch (size)
1515 {
1516 case 1:
1517 value = value * 0x10;
1518 break;
1519 case 2:
1520 break;
1521 case 3:
1522 value /= 0x10;
1523 break;
1524 case 4:
1525 value /= 0x100;
1526 break;
1527 }
1528 colorval |= (value << pos);
1529 pos += 0x8;
1530 if (i == 2)
1531 {
1532 UNBLOCK_INPUT;
1533 return (colorval);
1534 }
1535 color = end;
1536 }
1537 }
1538 }
1539 else if (strnicmp(colorname, "rgb:", 4) == 0)
1540 {
1541 char *color;
1542 UINT colorval;
1543 int i, pos;
1544 pos = 0;
1545
1546 colorval = 0;
1547 color = colorname + 4;
1548 for (i = 0; i < 3; i++)
1549 {
1550 char *end;
1551 unsigned long value;
1552
1553 /* The check for 'x' in the following conditional takes into
1554 account the fact that strtol allows a "0x" in front of
1555 our numbers, and we don't. */
1556 if (!isxdigit(color[0]) || color[1] == 'x')
1557 break;
1558 value = strtoul(color, &end, 16);
1559 if (errno == ERANGE)
1560 break;
1561 switch (end - color)
1562 {
1563 case 1:
1564 value = value * 0x10 + value;
1565 break;
1566 case 2:
1567 break;
1568 case 3:
1569 value /= 0x10;
1570 break;
1571 case 4:
1572 value /= 0x100;
1573 break;
1574 default:
1575 value = ULONG_MAX;
1576 }
1577 if (value == ULONG_MAX)
1578 break;
1579 colorval |= (value << pos);
1580 pos += 0x8;
1581 if (i == 2)
1582 {
1583 if (*end != '\0')
1584 break;
1585 UNBLOCK_INPUT;
1586 return (colorval);
1587 }
1588 if (*end != '/')
1589 break;
1590 color = end + 1;
1591 }
1592 }
1593 else if (strnicmp(colorname, "rgbi:", 5) == 0)
1594 {
1595 /* This is an RGB Intensity specification. */
1596 char *color;
1597 UINT colorval;
1598 int i, pos;
1599 pos = 0;
1600
1601 colorval = 0;
1602 color = colorname + 5;
1603 for (i = 0; i < 3; i++)
1604 {
1605 char *end;
1606 double value;
1607 UINT val;
1608
1609 value = strtod(color, &end);
1610 if (errno == ERANGE)
1611 break;
1612 if (value < 0.0 || value > 1.0)
1613 break;
1614 val = (UINT)(0x100 * value);
1615 /* We used 0x100 instead of 0xFF to give an continuous
1616 range between 0.0 and 1.0 inclusive. The next statement
1617 fixes the 1.0 case. */
1618 if (val == 0x100)
1619 val = 0xFF;
1620 colorval |= (val << pos);
1621 pos += 0x8;
1622 if (i == 2)
1623 {
1624 if (*end != '\0')
1625 break;
1626 UNBLOCK_INPUT;
1627 return (colorval);
1628 }
1629 if (*end != '/')
1630 break;
1631 color = end + 1;
1632 }
1633 }
1634 /* I am not going to attempt to handle any of the CIE color schemes
1635 or TekHVC, since I don't know the algorithms for conversion to
1636 RGB. */
1637
1638 /* If we fail to lookup the color name in w32_color_map, then check the
1639 colorname to see if it can be crudely approximated: If the X color
1640 ends in a number (e.g., "darkseagreen2"), strip the number and
1641 return the result of looking up the base color name. */
1642 ret = w32_color_map_lookup (colorname);
1643 if (NILP (ret))
1644 {
1645 int len = strlen (colorname);
1646
1647 if (isdigit (colorname[len - 1]))
1648 {
1649 char *ptr, *approx = alloca (len);
1650
1651 strcpy (approx, colorname);
1652 ptr = &approx[len - 1];
1653 while (ptr > approx && isdigit (*ptr))
1654 *ptr-- = '\0';
1655
1656 ret = w32_color_map_lookup (approx);
1657 }
1658 }
1659
1660 UNBLOCK_INPUT;
1661 return ret;
1662 }
1663
1664
1665 void
1666 w32_regenerate_palette (FRAME_PTR f)
1667 {
1668 struct w32_palette_entry * list;
1669 LOGPALETTE * log_palette;
1670 HPALETTE new_palette;
1671 int i;
1672
1673 /* don't bother trying to create palette if not supported */
1674 if (! FRAME_W32_DISPLAY_INFO (f)->has_palette)
1675 return;
1676
1677 log_palette = (LOGPALETTE *)
1678 alloca (sizeof (LOGPALETTE) +
1679 FRAME_W32_DISPLAY_INFO (f)->num_colors * sizeof (PALETTEENTRY));
1680 log_palette->palVersion = 0x300;
1681 log_palette->palNumEntries = FRAME_W32_DISPLAY_INFO (f)->num_colors;
1682
1683 list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1684 for (i = 0;
1685 i < FRAME_W32_DISPLAY_INFO (f)->num_colors;
1686 i++, list = list->next)
1687 log_palette->palPalEntry[i] = list->entry;
1688
1689 new_palette = CreatePalette (log_palette);
1690
1691 enter_crit ();
1692
1693 if (FRAME_W32_DISPLAY_INFO (f)->palette)
1694 DeleteObject (FRAME_W32_DISPLAY_INFO (f)->palette);
1695 FRAME_W32_DISPLAY_INFO (f)->palette = new_palette;
1696
1697 /* Realize display palette and garbage all frames. */
1698 release_frame_dc (f, get_frame_dc (f));
1699
1700 leave_crit ();
1701 }
1702
1703 #define W32_COLOR(pe) RGB (pe.peRed, pe.peGreen, pe.peBlue)
1704 #define SET_W32_COLOR(pe, color) \
1705 do \
1706 { \
1707 pe.peRed = GetRValue (color); \
1708 pe.peGreen = GetGValue (color); \
1709 pe.peBlue = GetBValue (color); \
1710 pe.peFlags = 0; \
1711 } while (0)
1712
1713 #if 0
1714 /* Keep these around in case we ever want to track color usage. */
1715 void
1716 w32_map_color (FRAME_PTR f, COLORREF color)
1717 {
1718 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1719
1720 if (NILP (Vw32_enable_palette))
1721 return;
1722
1723 /* check if color is already mapped */
1724 while (list)
1725 {
1726 if (W32_COLOR (list->entry) == color)
1727 {
1728 ++list->refcount;
1729 return;
1730 }
1731 list = list->next;
1732 }
1733
1734 /* not already mapped, so add to list and recreate Windows palette */
1735 list = (struct w32_palette_entry *)
1736 xmalloc (sizeof (struct w32_palette_entry));
1737 SET_W32_COLOR (list->entry, color);
1738 list->refcount = 1;
1739 list->next = FRAME_W32_DISPLAY_INFO (f)->color_list;
1740 FRAME_W32_DISPLAY_INFO (f)->color_list = list;
1741 FRAME_W32_DISPLAY_INFO (f)->num_colors++;
1742
1743 /* set flag that palette must be regenerated */
1744 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
1745 }
1746
1747 void
1748 w32_unmap_color (FRAME_PTR f, COLORREF color)
1749 {
1750 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1751 struct w32_palette_entry **prev = &FRAME_W32_DISPLAY_INFO (f)->color_list;
1752
1753 if (NILP (Vw32_enable_palette))
1754 return;
1755
1756 /* check if color is already mapped */
1757 while (list)
1758 {
1759 if (W32_COLOR (list->entry) == color)
1760 {
1761 if (--list->refcount == 0)
1762 {
1763 *prev = list->next;
1764 xfree (list);
1765 FRAME_W32_DISPLAY_INFO (f)->num_colors--;
1766 break;
1767 }
1768 else
1769 return;
1770 }
1771 prev = &list->next;
1772 list = list->next;
1773 }
1774
1775 /* set flag that palette must be regenerated */
1776 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
1777 }
1778 #endif
1779
1780
1781 /* Gamma-correct COLOR on frame F. */
1782
1783 void
1784 gamma_correct (f, color)
1785 struct frame *f;
1786 COLORREF *color;
1787 {
1788 if (f->gamma)
1789 {
1790 *color = PALETTERGB (
1791 pow (GetRValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1792 pow (GetGValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1793 pow (GetBValue (*color) / 255.0, f->gamma) * 255.0 + 0.5);
1794 }
1795 }
1796
1797
1798 /* Decide if color named COLOR is valid for the display associated with
1799 the selected frame; if so, return the rgb values in COLOR_DEF.
1800 If ALLOC is nonzero, allocate a new colormap cell. */
1801
1802 int
1803 w32_defined_color (f, color, color_def, alloc)
1804 FRAME_PTR f;
1805 char *color;
1806 XColor *color_def;
1807 int alloc;
1808 {
1809 register Lisp_Object tem;
1810 COLORREF w32_color_ref;
1811
1812 tem = x_to_w32_color (color);
1813
1814 if (!NILP (tem))
1815 {
1816 if (f)
1817 {
1818 /* Apply gamma correction. */
1819 w32_color_ref = XUINT (tem);
1820 gamma_correct (f, &w32_color_ref);
1821 XSETINT (tem, w32_color_ref);
1822 }
1823
1824 /* Map this color to the palette if it is enabled. */
1825 if (!NILP (Vw32_enable_palette))
1826 {
1827 struct w32_palette_entry * entry =
1828 one_w32_display_info.color_list;
1829 struct w32_palette_entry ** prev =
1830 &one_w32_display_info.color_list;
1831
1832 /* check if color is already mapped */
1833 while (entry)
1834 {
1835 if (W32_COLOR (entry->entry) == XUINT (tem))
1836 break;
1837 prev = &entry->next;
1838 entry = entry->next;
1839 }
1840
1841 if (entry == NULL && alloc)
1842 {
1843 /* not already mapped, so add to list */
1844 entry = (struct w32_palette_entry *)
1845 xmalloc (sizeof (struct w32_palette_entry));
1846 SET_W32_COLOR (entry->entry, XUINT (tem));
1847 entry->next = NULL;
1848 *prev = entry;
1849 one_w32_display_info.num_colors++;
1850
1851 /* set flag that palette must be regenerated */
1852 one_w32_display_info.regen_palette = TRUE;
1853 }
1854 }
1855 /* Ensure COLORREF value is snapped to nearest color in (default)
1856 palette by simulating the PALETTERGB macro. This works whether
1857 or not the display device has a palette. */
1858 w32_color_ref = XUINT (tem) | 0x2000000;
1859
1860 color_def->pixel = w32_color_ref;
1861 color_def->red = GetRValue (w32_color_ref);
1862 color_def->green = GetGValue (w32_color_ref);
1863 color_def->blue = GetBValue (w32_color_ref);
1864
1865 return 1;
1866 }
1867 else
1868 {
1869 return 0;
1870 }
1871 }
1872
1873 /* Given a string ARG naming a color, compute a pixel value from it
1874 suitable for screen F.
1875 If F is not a color screen, return DEF (default) regardless of what
1876 ARG says. */
1877
1878 int
1879 x_decode_color (f, arg, def)
1880 FRAME_PTR f;
1881 Lisp_Object arg;
1882 int def;
1883 {
1884 XColor cdef;
1885
1886 CHECK_STRING (arg, 0);
1887
1888 if (strcmp (XSTRING (arg)->data, "black") == 0)
1889 return BLACK_PIX_DEFAULT (f);
1890 else if (strcmp (XSTRING (arg)->data, "white") == 0)
1891 return WHITE_PIX_DEFAULT (f);
1892
1893 if ((FRAME_W32_DISPLAY_INFO (f)->n_planes * FRAME_W32_DISPLAY_INFO (f)->n_cbits) == 1)
1894 return def;
1895
1896 /* w32_defined_color is responsible for coping with failures
1897 by looking for a near-miss. */
1898 if (w32_defined_color (f, XSTRING (arg)->data, &cdef, 1))
1899 return cdef.pixel;
1900
1901 /* defined_color failed; return an ultimate default. */
1902 return def;
1903 }
1904 \f
1905 /* Change the `line-spacing' frame parameter of frame F. OLD_VALUE is
1906 the previous value of that parameter, NEW_VALUE is the new value. */
1907
1908 static void
1909 x_set_line_spacing (f, new_value, old_value)
1910 struct frame *f;
1911 Lisp_Object new_value, old_value;
1912 {
1913 if (NILP (new_value))
1914 f->extra_line_spacing = 0;
1915 else if (NATNUMP (new_value))
1916 f->extra_line_spacing = XFASTINT (new_value);
1917 else
1918 Fsignal (Qerror, Fcons (build_string ("Invalid line-spacing"),
1919 Fcons (new_value, Qnil)));
1920 if (FRAME_VISIBLE_P (f))
1921 redraw_frame (f);
1922 }
1923
1924
1925 /* Change the `screen-gamma' frame parameter of frame F. OLD_VALUE is
1926 the previous value of that parameter, NEW_VALUE is the new value. */
1927
1928 static void
1929 x_set_screen_gamma (f, new_value, old_value)
1930 struct frame *f;
1931 Lisp_Object new_value, old_value;
1932 {
1933 if (NILP (new_value))
1934 f->gamma = 0;
1935 else if (NUMBERP (new_value) && XFLOATINT (new_value) > 0)
1936 /* The value 0.4545 is the normal viewing gamma. */
1937 f->gamma = 1.0 / (0.4545 * XFLOATINT (new_value));
1938 else
1939 Fsignal (Qerror, Fcons (build_string ("Invalid screen-gamma"),
1940 Fcons (new_value, Qnil)));
1941
1942 clear_face_cache (0);
1943 }
1944
1945
1946 /* Functions called only from `x_set_frame_param'
1947 to set individual parameters.
1948
1949 If FRAME_W32_WINDOW (f) is 0,
1950 the frame is being created and its window does not exist yet.
1951 In that case, just record the parameter's new value
1952 in the standard place; do not attempt to change the window. */
1953
1954 void
1955 x_set_foreground_color (f, arg, oldval)
1956 struct frame *f;
1957 Lisp_Object arg, oldval;
1958 {
1959 FRAME_FOREGROUND_PIXEL (f)
1960 = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
1961
1962 if (FRAME_W32_WINDOW (f) != 0)
1963 {
1964 update_face_from_frame_parameter (f, Qforeground_color, arg);
1965 if (FRAME_VISIBLE_P (f))
1966 redraw_frame (f);
1967 }
1968 }
1969
1970 void
1971 x_set_background_color (f, arg, oldval)
1972 struct frame *f;
1973 Lisp_Object arg, oldval;
1974 {
1975 FRAME_BACKGROUND_PIXEL (f)
1976 = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
1977
1978 if (FRAME_W32_WINDOW (f) != 0)
1979 {
1980 SetWindowLong (FRAME_W32_WINDOW (f), WND_BACKGROUND_INDEX,
1981 FRAME_BACKGROUND_PIXEL (f));
1982
1983 update_face_from_frame_parameter (f, Qbackground_color, arg);
1984
1985 if (FRAME_VISIBLE_P (f))
1986 redraw_frame (f);
1987 }
1988 }
1989
1990 void
1991 x_set_mouse_color (f, arg, oldval)
1992 struct frame *f;
1993 Lisp_Object arg, oldval;
1994 {
1995 Cursor cursor, nontext_cursor, mode_cursor, cross_cursor;
1996 int count;
1997 int mask_color;
1998
1999 if (!EQ (Qnil, arg))
2000 f->output_data.w32->mouse_pixel
2001 = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2002 mask_color = FRAME_BACKGROUND_PIXEL (f);
2003
2004 /* Don't let pointers be invisible. */
2005 if (mask_color == f->output_data.w32->mouse_pixel
2006 && mask_color == FRAME_BACKGROUND_PIXEL (f))
2007 f->output_data.w32->mouse_pixel = FRAME_FOREGROUND_PIXEL (f);
2008
2009 #if 0 /* TODO : cursor changes */
2010 BLOCK_INPUT;
2011
2012 /* It's not okay to crash if the user selects a screwy cursor. */
2013 count = x_catch_errors (FRAME_W32_DISPLAY (f));
2014
2015 if (!EQ (Qnil, Vx_pointer_shape))
2016 {
2017 CHECK_NUMBER (Vx_pointer_shape, 0);
2018 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XINT (Vx_pointer_shape));
2019 }
2020 else
2021 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2022 x_check_errors (FRAME_W32_DISPLAY (f), "bad text pointer cursor: %s");
2023
2024 if (!EQ (Qnil, Vx_nontext_pointer_shape))
2025 {
2026 CHECK_NUMBER (Vx_nontext_pointer_shape, 0);
2027 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2028 XINT (Vx_nontext_pointer_shape));
2029 }
2030 else
2031 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_left_ptr);
2032 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
2033
2034 if (!EQ (Qnil, Vx_hourglass_pointer_shape))
2035 {
2036 CHECK_NUMBER (Vx_hourglass_pointer_shape, 0);
2037 hourglass_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2038 XINT (Vx_hourglass_pointer_shape));
2039 }
2040 else
2041 hourglass_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_watch);
2042 x_check_errors (FRAME_W32_DISPLAY (f), "bad busy pointer cursor: %s");
2043
2044 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
2045 if (!EQ (Qnil, Vx_mode_pointer_shape))
2046 {
2047 CHECK_NUMBER (Vx_mode_pointer_shape, 0);
2048 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2049 XINT (Vx_mode_pointer_shape));
2050 }
2051 else
2052 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2053 x_check_errors (FRAME_W32_DISPLAY (f), "bad modeline pointer cursor: %s");
2054
2055 if (!EQ (Qnil, Vx_sensitive_text_pointer_shape))
2056 {
2057 CHECK_NUMBER (Vx_sensitive_text_pointer_shape, 0);
2058 cross_cursor
2059 = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2060 XINT (Vx_sensitive_text_pointer_shape));
2061 }
2062 else
2063 cross_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_crosshair);
2064
2065 if (!NILP (Vx_window_horizontal_drag_shape))
2066 {
2067 CHECK_NUMBER (Vx_window_horizontal_drag_shape, 0);
2068 horizontal_drag_cursor
2069 = XCreateFontCursor (FRAME_X_DISPLAY (f),
2070 XINT (Vx_window_horizontal_drag_shape));
2071 }
2072 else
2073 horizontal_drag_cursor
2074 = XCreateFontCursor (FRAME_X_DISPLAY (f), XC_sb_h_double_arrow);
2075
2076 /* Check and report errors with the above calls. */
2077 x_check_errors (FRAME_W32_DISPLAY (f), "can't set cursor shape: %s");
2078 x_uncatch_errors (FRAME_W32_DISPLAY (f), count);
2079
2080 {
2081 XColor fore_color, back_color;
2082
2083 fore_color.pixel = f->output_data.w32->mouse_pixel;
2084 back_color.pixel = mask_color;
2085 XQueryColor (FRAME_W32_DISPLAY (f),
2086 DefaultColormap (FRAME_W32_DISPLAY (f),
2087 DefaultScreen (FRAME_W32_DISPLAY (f))),
2088 &fore_color);
2089 XQueryColor (FRAME_W32_DISPLAY (f),
2090 DefaultColormap (FRAME_W32_DISPLAY (f),
2091 DefaultScreen (FRAME_W32_DISPLAY (f))),
2092 &back_color);
2093 XRecolorCursor (FRAME_W32_DISPLAY (f), cursor,
2094 &fore_color, &back_color);
2095 XRecolorCursor (FRAME_W32_DISPLAY (f), nontext_cursor,
2096 &fore_color, &back_color);
2097 XRecolorCursor (FRAME_W32_DISPLAY (f), mode_cursor,
2098 &fore_color, &back_color);
2099 XRecolorCursor (FRAME_W32_DISPLAY (f), cross_cursor,
2100 &fore_color, &back_color);
2101 XRecolorCursor (FRAME_W32_DISPLAY (f), hourglass_cursor,
2102 &fore_color, &back_color);
2103 }
2104
2105 if (FRAME_W32_WINDOW (f) != 0)
2106 XDefineCursor (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), cursor);
2107
2108 if (cursor != f->output_data.w32->text_cursor && f->output_data.w32->text_cursor != 0)
2109 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->text_cursor);
2110 f->output_data.w32->text_cursor = cursor;
2111
2112 if (nontext_cursor != f->output_data.w32->nontext_cursor
2113 && f->output_data.w32->nontext_cursor != 0)
2114 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->nontext_cursor);
2115 f->output_data.w32->nontext_cursor = nontext_cursor;
2116
2117 if (hourglass_cursor != f->output_data.w32->hourglass_cursor
2118 && f->output_data.w32->hourglass_cursor != 0)
2119 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->hourglass_cursor);
2120 f->output_data.w32->hourglass_cursor = hourglass_cursor;
2121
2122 if (mode_cursor != f->output_data.w32->modeline_cursor
2123 && f->output_data.w32->modeline_cursor != 0)
2124 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->modeline_cursor);
2125 f->output_data.w32->modeline_cursor = mode_cursor;
2126
2127 if (cross_cursor != f->output_data.w32->cross_cursor
2128 && f->output_data.w32->cross_cursor != 0)
2129 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->cross_cursor);
2130 f->output_data.w32->cross_cursor = cross_cursor;
2131
2132 XFlush (FRAME_W32_DISPLAY (f));
2133 UNBLOCK_INPUT;
2134
2135 update_face_from_frame_parameter (f, Qmouse_color, arg);
2136 #endif /* TODO */
2137 }
2138
2139 /* Defined in w32term.c. */
2140 void x_update_cursor (struct frame *f, int on_p);
2141
2142 void
2143 x_set_cursor_color (f, arg, oldval)
2144 struct frame *f;
2145 Lisp_Object arg, oldval;
2146 {
2147 unsigned long fore_pixel, pixel;
2148
2149 if (!NILP (Vx_cursor_fore_pixel))
2150 fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel,
2151 WHITE_PIX_DEFAULT (f));
2152 else
2153 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
2154
2155 pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2156
2157 /* Make sure that the cursor color differs from the background color. */
2158 if (pixel == FRAME_BACKGROUND_PIXEL (f))
2159 {
2160 pixel = f->output_data.w32->mouse_pixel;
2161 if (pixel == fore_pixel)
2162 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
2163 }
2164
2165 FRAME_FOREGROUND_PIXEL (f) = fore_pixel;
2166 f->output_data.w32->cursor_pixel = pixel;
2167
2168 if (FRAME_W32_WINDOW (f) != 0)
2169 {
2170 if (FRAME_VISIBLE_P (f))
2171 {
2172 x_update_cursor (f, 0);
2173 x_update_cursor (f, 1);
2174 }
2175 }
2176
2177 update_face_from_frame_parameter (f, Qcursor_color, arg);
2178 }
2179
2180 /* Set the border-color of frame F to pixel value PIX.
2181 Note that this does not fully take effect if done before
2182 F has an window. */
2183 void
2184 x_set_border_pixel (f, pix)
2185 struct frame *f;
2186 int pix;
2187 {
2188 f->output_data.w32->border_pixel = pix;
2189
2190 if (FRAME_W32_WINDOW (f) != 0 && f->output_data.w32->border_width > 0)
2191 {
2192 if (FRAME_VISIBLE_P (f))
2193 redraw_frame (f);
2194 }
2195 }
2196
2197 /* Set the border-color of frame F to value described by ARG.
2198 ARG can be a string naming a color.
2199 The border-color is used for the border that is drawn by the server.
2200 Note that this does not fully take effect if done before
2201 F has a window; it must be redone when the window is created. */
2202
2203 void
2204 x_set_border_color (f, arg, oldval)
2205 struct frame *f;
2206 Lisp_Object arg, oldval;
2207 {
2208 int pix;
2209
2210 CHECK_STRING (arg, 0);
2211 pix = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2212 x_set_border_pixel (f, pix);
2213 update_face_from_frame_parameter (f, Qborder_color, arg);
2214 }
2215
2216 /* Value is the internal representation of the specified cursor type
2217 ARG. If type is BAR_CURSOR, return in *WIDTH the specified width
2218 of the bar cursor. */
2219
2220 enum text_cursor_kinds
2221 x_specified_cursor_type (arg, width)
2222 Lisp_Object arg;
2223 int *width;
2224 {
2225 enum text_cursor_kinds type;
2226
2227 if (EQ (arg, Qbar))
2228 {
2229 type = BAR_CURSOR;
2230 *width = 2;
2231 }
2232 else if (CONSP (arg)
2233 && EQ (XCAR (arg), Qbar)
2234 && INTEGERP (XCDR (arg))
2235 && XINT (XCDR (arg)) >= 0)
2236 {
2237 type = BAR_CURSOR;
2238 *width = XINT (XCDR (arg));
2239 }
2240 else if (NILP (arg))
2241 type = NO_CURSOR;
2242 else
2243 /* Treat anything unknown as "box cursor".
2244 It was bad to signal an error; people have trouble fixing
2245 .Xdefaults with Emacs, when it has something bad in it. */
2246 type = FILLED_BOX_CURSOR;
2247
2248 return type;
2249 }
2250
2251 void
2252 x_set_cursor_type (f, arg, oldval)
2253 FRAME_PTR f;
2254 Lisp_Object arg, oldval;
2255 {
2256 int width;
2257
2258 FRAME_DESIRED_CURSOR (f) = x_specified_cursor_type (arg, &width);
2259 f->output_data.w32->cursor_width = width;
2260
2261 /* Make sure the cursor gets redrawn. This is overkill, but how
2262 often do people change cursor types? */
2263 update_mode_lines++;
2264 }
2265 \f
2266 void
2267 x_set_icon_type (f, arg, oldval)
2268 struct frame *f;
2269 Lisp_Object arg, oldval;
2270 {
2271 int result;
2272
2273 if (NILP (arg) && NILP (oldval))
2274 return;
2275
2276 if (STRINGP (arg) && STRINGP (oldval)
2277 && EQ (Fstring_equal (oldval, arg), Qt))
2278 return;
2279
2280 if (SYMBOLP (arg) && SYMBOLP (oldval) && EQ (arg, oldval))
2281 return;
2282
2283 BLOCK_INPUT;
2284
2285 result = x_bitmap_icon (f, arg);
2286 if (result)
2287 {
2288 UNBLOCK_INPUT;
2289 error ("No icon window available");
2290 }
2291
2292 UNBLOCK_INPUT;
2293 }
2294
2295 /* Return non-nil if frame F wants a bitmap icon. */
2296
2297 Lisp_Object
2298 x_icon_type (f)
2299 FRAME_PTR f;
2300 {
2301 Lisp_Object tem;
2302
2303 tem = assq_no_quit (Qicon_type, f->param_alist);
2304 if (CONSP (tem))
2305 return XCDR (tem);
2306 else
2307 return Qnil;
2308 }
2309
2310 void
2311 x_set_icon_name (f, arg, oldval)
2312 struct frame *f;
2313 Lisp_Object arg, oldval;
2314 {
2315 if (STRINGP (arg))
2316 {
2317 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
2318 return;
2319 }
2320 else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
2321 return;
2322
2323 f->icon_name = arg;
2324
2325 #if 0
2326 if (f->output_data.w32->icon_bitmap != 0)
2327 return;
2328
2329 BLOCK_INPUT;
2330
2331 result = x_text_icon (f,
2332 (char *) XSTRING ((!NILP (f->icon_name)
2333 ? f->icon_name
2334 : !NILP (f->title)
2335 ? f->title
2336 : f->name))->data);
2337
2338 if (result)
2339 {
2340 UNBLOCK_INPUT;
2341 error ("No icon window available");
2342 }
2343
2344 /* If the window was unmapped (and its icon was mapped),
2345 the new icon is not mapped, so map the window in its stead. */
2346 if (FRAME_VISIBLE_P (f))
2347 {
2348 #ifdef USE_X_TOOLKIT
2349 XtPopup (f->output_data.w32->widget, XtGrabNone);
2350 #endif
2351 XMapWindow (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f));
2352 }
2353
2354 XFlush (FRAME_W32_DISPLAY (f));
2355 UNBLOCK_INPUT;
2356 #endif
2357 }
2358
2359 extern Lisp_Object x_new_font ();
2360 extern Lisp_Object x_new_fontset();
2361
2362 void
2363 x_set_font (f, arg, oldval)
2364 struct frame *f;
2365 Lisp_Object arg, oldval;
2366 {
2367 Lisp_Object result;
2368 Lisp_Object fontset_name;
2369 Lisp_Object frame;
2370
2371 CHECK_STRING (arg, 1);
2372
2373 fontset_name = Fquery_fontset (arg, Qnil);
2374
2375 BLOCK_INPUT;
2376 result = (STRINGP (fontset_name)
2377 ? x_new_fontset (f, XSTRING (fontset_name)->data)
2378 : x_new_font (f, XSTRING (arg)->data));
2379 UNBLOCK_INPUT;
2380
2381 if (EQ (result, Qnil))
2382 error ("Font `%s' is not defined", XSTRING (arg)->data);
2383 else if (EQ (result, Qt))
2384 error ("The characters of the given font have varying widths");
2385 else if (STRINGP (result))
2386 {
2387 if (!NILP (Fequal (result, oldval)))
2388 return;
2389 store_frame_param (f, Qfont, result);
2390 recompute_basic_faces (f);
2391 }
2392 else
2393 abort ();
2394
2395 do_pending_window_change (0);
2396
2397 /* Don't call `face-set-after-frame-default' when faces haven't been
2398 initialized yet. This is the case when called from
2399 Fx_create_frame. In that case, the X widget or window doesn't
2400 exist either, and we can end up in x_report_frame_params with a
2401 null widget which gives a segfault. */
2402 if (FRAME_FACE_CACHE (f))
2403 {
2404 XSETFRAME (frame, f);
2405 call1 (Qface_set_after_frame_default, frame);
2406 }
2407 }
2408
2409 void
2410 x_set_border_width (f, arg, oldval)
2411 struct frame *f;
2412 Lisp_Object arg, oldval;
2413 {
2414 CHECK_NUMBER (arg, 0);
2415
2416 if (XINT (arg) == f->output_data.w32->border_width)
2417 return;
2418
2419 if (FRAME_W32_WINDOW (f) != 0)
2420 error ("Cannot change the border width of a window");
2421
2422 f->output_data.w32->border_width = XINT (arg);
2423 }
2424
2425 void
2426 x_set_internal_border_width (f, arg, oldval)
2427 struct frame *f;
2428 Lisp_Object arg, oldval;
2429 {
2430 int old = f->output_data.w32->internal_border_width;
2431
2432 CHECK_NUMBER (arg, 0);
2433 f->output_data.w32->internal_border_width = XINT (arg);
2434 if (f->output_data.w32->internal_border_width < 0)
2435 f->output_data.w32->internal_border_width = 0;
2436
2437 if (f->output_data.w32->internal_border_width == old)
2438 return;
2439
2440 if (FRAME_W32_WINDOW (f) != 0)
2441 {
2442 x_set_window_size (f, 0, f->width, f->height);
2443 SET_FRAME_GARBAGED (f);
2444 do_pending_window_change (0);
2445 }
2446 }
2447
2448 void
2449 x_set_visibility (f, value, oldval)
2450 struct frame *f;
2451 Lisp_Object value, oldval;
2452 {
2453 Lisp_Object frame;
2454 XSETFRAME (frame, f);
2455
2456 if (NILP (value))
2457 Fmake_frame_invisible (frame, Qt);
2458 else if (EQ (value, Qicon))
2459 Ficonify_frame (frame);
2460 else
2461 Fmake_frame_visible (frame);
2462 }
2463
2464 \f
2465 /* Change window heights in windows rooted in WINDOW by N lines. */
2466
2467 static void
2468 x_change_window_heights (window, n)
2469 Lisp_Object window;
2470 int n;
2471 {
2472 struct window *w = XWINDOW (window);
2473
2474 XSETFASTINT (w->top, XFASTINT (w->top) + n);
2475 XSETFASTINT (w->height, XFASTINT (w->height) - n);
2476
2477 if (INTEGERP (w->orig_top))
2478 XSETFASTINT (w->orig_top, XFASTINT (w->orig_top) + n);
2479 if (INTEGERP (w->orig_height))
2480 XSETFASTINT (w->orig_height, XFASTINT (w->orig_height) - n);
2481
2482 /* Handle just the top child in a vertical split. */
2483 if (!NILP (w->vchild))
2484 x_change_window_heights (w->vchild, n);
2485
2486 /* Adjust all children in a horizontal split. */
2487 for (window = w->hchild; !NILP (window); window = w->next)
2488 {
2489 w = XWINDOW (window);
2490 x_change_window_heights (window, n);
2491 }
2492 }
2493
2494 void
2495 x_set_menu_bar_lines (f, value, oldval)
2496 struct frame *f;
2497 Lisp_Object value, oldval;
2498 {
2499 int nlines;
2500 int olines = FRAME_MENU_BAR_LINES (f);
2501
2502 /* Right now, menu bars don't work properly in minibuf-only frames;
2503 most of the commands try to apply themselves to the minibuffer
2504 frame itself, and get an error because you can't switch buffers
2505 in or split the minibuffer window. */
2506 if (FRAME_MINIBUF_ONLY_P (f))
2507 return;
2508
2509 if (INTEGERP (value))
2510 nlines = XINT (value);
2511 else
2512 nlines = 0;
2513
2514 FRAME_MENU_BAR_LINES (f) = 0;
2515 if (nlines)
2516 FRAME_EXTERNAL_MENU_BAR (f) = 1;
2517 else
2518 {
2519 if (FRAME_EXTERNAL_MENU_BAR (f) == 1)
2520 free_frame_menubar (f);
2521 FRAME_EXTERNAL_MENU_BAR (f) = 0;
2522
2523 /* Adjust the frame size so that the client (text) dimensions
2524 remain the same. This depends on FRAME_EXTERNAL_MENU_BAR being
2525 set correctly. */
2526 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2527 do_pending_window_change (0);
2528 }
2529 adjust_glyphs (f);
2530 }
2531
2532
2533 /* Set the number of lines used for the tool bar of frame F to VALUE.
2534 VALUE not an integer, or < 0 means set the lines to zero. OLDVAL
2535 is the old number of tool bar lines. This function changes the
2536 height of all windows on frame F to match the new tool bar height.
2537 The frame's height doesn't change. */
2538
2539 void
2540 x_set_tool_bar_lines (f, value, oldval)
2541 struct frame *f;
2542 Lisp_Object value, oldval;
2543 {
2544 int delta, nlines, root_height;
2545 Lisp_Object root_window;
2546
2547 /* Treat tool bars like menu bars. */
2548 if (FRAME_MINIBUF_ONLY_P (f))
2549 return;
2550
2551 /* Use VALUE only if an integer >= 0. */
2552 if (INTEGERP (value) && XINT (value) >= 0)
2553 nlines = XFASTINT (value);
2554 else
2555 nlines = 0;
2556
2557 /* Make sure we redisplay all windows in this frame. */
2558 ++windows_or_buffers_changed;
2559
2560 delta = nlines - FRAME_TOOL_BAR_LINES (f);
2561
2562 /* Don't resize the tool-bar to more than we have room for. */
2563 root_window = FRAME_ROOT_WINDOW (f);
2564 root_height = XINT (XWINDOW (root_window)->height);
2565 if (root_height - delta < 1)
2566 {
2567 delta = root_height - 1;
2568 nlines = FRAME_TOOL_BAR_LINES (f) + delta;
2569 }
2570
2571 FRAME_TOOL_BAR_LINES (f) = nlines;
2572 x_change_window_heights (root_window, delta);
2573 adjust_glyphs (f);
2574
2575 /* We also have to make sure that the internal border at the top of
2576 the frame, below the menu bar or tool bar, is redrawn when the
2577 tool bar disappears. This is so because the internal border is
2578 below the tool bar if one is displayed, but is below the menu bar
2579 if there isn't a tool bar. The tool bar draws into the area
2580 below the menu bar. */
2581 if (FRAME_W32_WINDOW (f) && FRAME_TOOL_BAR_LINES (f) == 0)
2582 {
2583 updating_frame = f;
2584 clear_frame ();
2585 clear_current_matrices (f);
2586 updating_frame = NULL;
2587 }
2588
2589 /* If the tool bar gets smaller, the internal border below it
2590 has to be cleared. It was formerly part of the display
2591 of the larger tool bar, and updating windows won't clear it. */
2592 if (delta < 0)
2593 {
2594 int height = FRAME_INTERNAL_BORDER_WIDTH (f);
2595 int width = PIXEL_WIDTH (f);
2596 int y = nlines * CANON_Y_UNIT (f);
2597
2598 BLOCK_INPUT;
2599 {
2600 HDC hdc = get_frame_dc (f);
2601 w32_clear_area (f, hdc, 0, y, width, height);
2602 release_frame_dc (f, hdc);
2603 }
2604 UNBLOCK_INPUT;
2605 }
2606 }
2607
2608
2609 /* Change the name of frame F to NAME. If NAME is nil, set F's name to
2610 w32_id_name.
2611
2612 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2613 name; if NAME is a string, set F's name to NAME and set
2614 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2615
2616 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2617 suggesting a new name, which lisp code should override; if
2618 F->explicit_name is set, ignore the new name; otherwise, set it. */
2619
2620 void
2621 x_set_name (f, name, explicit)
2622 struct frame *f;
2623 Lisp_Object name;
2624 int explicit;
2625 {
2626 /* Make sure that requests from lisp code override requests from
2627 Emacs redisplay code. */
2628 if (explicit)
2629 {
2630 /* If we're switching from explicit to implicit, we had better
2631 update the mode lines and thereby update the title. */
2632 if (f->explicit_name && NILP (name))
2633 update_mode_lines = 1;
2634
2635 f->explicit_name = ! NILP (name);
2636 }
2637 else if (f->explicit_name)
2638 return;
2639
2640 /* If NAME is nil, set the name to the w32_id_name. */
2641 if (NILP (name))
2642 {
2643 /* Check for no change needed in this very common case
2644 before we do any consing. */
2645 if (!strcmp (FRAME_W32_DISPLAY_INFO (f)->w32_id_name,
2646 XSTRING (f->name)->data))
2647 return;
2648 name = build_string (FRAME_W32_DISPLAY_INFO (f)->w32_id_name);
2649 }
2650 else
2651 CHECK_STRING (name, 0);
2652
2653 /* Don't change the name if it's already NAME. */
2654 if (! NILP (Fstring_equal (name, f->name)))
2655 return;
2656
2657 f->name = name;
2658
2659 /* For setting the frame title, the title parameter should override
2660 the name parameter. */
2661 if (! NILP (f->title))
2662 name = f->title;
2663
2664 if (FRAME_W32_WINDOW (f))
2665 {
2666 if (STRING_MULTIBYTE (name))
2667 name = ENCODE_SYSTEM (name);
2668
2669 BLOCK_INPUT;
2670 SetWindowText(FRAME_W32_WINDOW (f), XSTRING (name)->data);
2671 UNBLOCK_INPUT;
2672 }
2673 }
2674
2675 /* This function should be called when the user's lisp code has
2676 specified a name for the frame; the name will override any set by the
2677 redisplay code. */
2678 void
2679 x_explicitly_set_name (f, arg, oldval)
2680 FRAME_PTR f;
2681 Lisp_Object arg, oldval;
2682 {
2683 x_set_name (f, arg, 1);
2684 }
2685
2686 /* This function should be called by Emacs redisplay code to set the
2687 name; names set this way will never override names set by the user's
2688 lisp code. */
2689 void
2690 x_implicitly_set_name (f, arg, oldval)
2691 FRAME_PTR f;
2692 Lisp_Object arg, oldval;
2693 {
2694 x_set_name (f, arg, 0);
2695 }
2696 \f
2697 /* Change the title of frame F to NAME.
2698 If NAME is nil, use the frame name as the title.
2699
2700 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2701 name; if NAME is a string, set F's name to NAME and set
2702 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2703
2704 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2705 suggesting a new name, which lisp code should override; if
2706 F->explicit_name is set, ignore the new name; otherwise, set it. */
2707
2708 void
2709 x_set_title (f, name, old_name)
2710 struct frame *f;
2711 Lisp_Object name, old_name;
2712 {
2713 /* Don't change the title if it's already NAME. */
2714 if (EQ (name, f->title))
2715 return;
2716
2717 update_mode_lines = 1;
2718
2719 f->title = name;
2720
2721 if (NILP (name))
2722 name = f->name;
2723
2724 if (FRAME_W32_WINDOW (f))
2725 {
2726 if (STRING_MULTIBYTE (name))
2727 name = ENCODE_SYSTEM (name);
2728
2729 BLOCK_INPUT;
2730 SetWindowText(FRAME_W32_WINDOW (f), XSTRING (name)->data);
2731 UNBLOCK_INPUT;
2732 }
2733 }
2734 \f
2735 void
2736 x_set_autoraise (f, arg, oldval)
2737 struct frame *f;
2738 Lisp_Object arg, oldval;
2739 {
2740 f->auto_raise = !EQ (Qnil, arg);
2741 }
2742
2743 void
2744 x_set_autolower (f, arg, oldval)
2745 struct frame *f;
2746 Lisp_Object arg, oldval;
2747 {
2748 f->auto_lower = !EQ (Qnil, arg);
2749 }
2750
2751 void
2752 x_set_unsplittable (f, arg, oldval)
2753 struct frame *f;
2754 Lisp_Object arg, oldval;
2755 {
2756 f->no_split = !NILP (arg);
2757 }
2758
2759 void
2760 x_set_vertical_scroll_bars (f, arg, oldval)
2761 struct frame *f;
2762 Lisp_Object arg, oldval;
2763 {
2764 if ((EQ (arg, Qleft) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
2765 || (EQ (arg, Qright) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
2766 || (NILP (arg) && FRAME_HAS_VERTICAL_SCROLL_BARS (f))
2767 || (!NILP (arg) && ! FRAME_HAS_VERTICAL_SCROLL_BARS (f)))
2768 {
2769 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = NILP (arg) ?
2770 vertical_scroll_bar_none :
2771 /* Put scroll bars on the right by default, as is conventional
2772 on MS-Windows. */
2773 EQ (Qleft, arg)
2774 ? vertical_scroll_bar_left
2775 : vertical_scroll_bar_right;
2776
2777 /* We set this parameter before creating the window for the
2778 frame, so we can get the geometry right from the start.
2779 However, if the window hasn't been created yet, we shouldn't
2780 call x_set_window_size. */
2781 if (FRAME_W32_WINDOW (f))
2782 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2783 do_pending_window_change (0);
2784 }
2785 }
2786
2787 void
2788 x_set_scroll_bar_width (f, arg, oldval)
2789 struct frame *f;
2790 Lisp_Object arg, oldval;
2791 {
2792 int wid = FONT_WIDTH (f->output_data.w32->font);
2793
2794 if (NILP (arg))
2795 {
2796 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = GetSystemMetrics (SM_CXVSCROLL);
2797 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) +
2798 wid - 1) / wid;
2799 if (FRAME_W32_WINDOW (f))
2800 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2801 do_pending_window_change (0);
2802 }
2803 else if (INTEGERP (arg) && XINT (arg) > 0
2804 && XFASTINT (arg) != FRAME_SCROLL_BAR_PIXEL_WIDTH (f))
2805 {
2806 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = XFASTINT (arg);
2807 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
2808 + wid-1) / wid;
2809 if (FRAME_W32_WINDOW (f))
2810 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2811 do_pending_window_change (0);
2812 }
2813 change_frame_size (f, 0, FRAME_WIDTH (f), 0, 0, 0);
2814 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.hpos = 0;
2815 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.x = 0;
2816 }
2817 \f
2818 /* Subroutines of creating an frame. */
2819
2820 /* Make sure that Vx_resource_name is set to a reasonable value.
2821 Fix it up, or set it to `emacs' if it is too hopeless. */
2822
2823 static void
2824 validate_x_resource_name ()
2825 {
2826 int len = 0;
2827 /* Number of valid characters in the resource name. */
2828 int good_count = 0;
2829 /* Number of invalid characters in the resource name. */
2830 int bad_count = 0;
2831 Lisp_Object new;
2832 int i;
2833
2834 if (STRINGP (Vx_resource_name))
2835 {
2836 unsigned char *p = XSTRING (Vx_resource_name)->data;
2837 int i;
2838
2839 len = STRING_BYTES (XSTRING (Vx_resource_name));
2840
2841 /* Only letters, digits, - and _ are valid in resource names.
2842 Count the valid characters and count the invalid ones. */
2843 for (i = 0; i < len; i++)
2844 {
2845 int c = p[i];
2846 if (! ((c >= 'a' && c <= 'z')
2847 || (c >= 'A' && c <= 'Z')
2848 || (c >= '0' && c <= '9')
2849 || c == '-' || c == '_'))
2850 bad_count++;
2851 else
2852 good_count++;
2853 }
2854 }
2855 else
2856 /* Not a string => completely invalid. */
2857 bad_count = 5, good_count = 0;
2858
2859 /* If name is valid already, return. */
2860 if (bad_count == 0)
2861 return;
2862
2863 /* If name is entirely invalid, or nearly so, use `emacs'. */
2864 if (good_count == 0
2865 || (good_count == 1 && bad_count > 0))
2866 {
2867 Vx_resource_name = build_string ("emacs");
2868 return;
2869 }
2870
2871 /* Name is partly valid. Copy it and replace the invalid characters
2872 with underscores. */
2873
2874 Vx_resource_name = new = Fcopy_sequence (Vx_resource_name);
2875
2876 for (i = 0; i < len; i++)
2877 {
2878 int c = XSTRING (new)->data[i];
2879 if (! ((c >= 'a' && c <= 'z')
2880 || (c >= 'A' && c <= 'Z')
2881 || (c >= '0' && c <= '9')
2882 || c == '-' || c == '_'))
2883 XSTRING (new)->data[i] = '_';
2884 }
2885 }
2886
2887
2888 extern char *x_get_string_resource ();
2889
2890 DEFUN ("x-get-resource", Fx_get_resource, Sx_get_resource, 2, 4, 0,
2891 "Return the value of ATTRIBUTE, of class CLASS, from the X defaults database.\n\
2892 This uses `INSTANCE.ATTRIBUTE' as the key and `Emacs.CLASS' as the\n\
2893 class, where INSTANCE is the name under which Emacs was invoked, or\n\
2894 the name specified by the `-name' or `-rn' command-line arguments.\n\
2895 \n\
2896 The optional arguments COMPONENT and SUBCLASS add to the key and the\n\
2897 class, respectively. You must specify both of them or neither.\n\
2898 If you specify them, the key is `INSTANCE.COMPONENT.ATTRIBUTE'\n\
2899 and the class is `Emacs.CLASS.SUBCLASS'.")
2900 (attribute, class, component, subclass)
2901 Lisp_Object attribute, class, component, subclass;
2902 {
2903 register char *value;
2904 char *name_key;
2905 char *class_key;
2906
2907 CHECK_STRING (attribute, 0);
2908 CHECK_STRING (class, 0);
2909
2910 if (!NILP (component))
2911 CHECK_STRING (component, 1);
2912 if (!NILP (subclass))
2913 CHECK_STRING (subclass, 2);
2914 if (NILP (component) != NILP (subclass))
2915 error ("x-get-resource: must specify both COMPONENT and SUBCLASS or neither");
2916
2917 validate_x_resource_name ();
2918
2919 /* Allocate space for the components, the dots which separate them,
2920 and the final '\0'. Make them big enough for the worst case. */
2921 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vx_resource_name))
2922 + (STRINGP (component)
2923 ? STRING_BYTES (XSTRING (component)) : 0)
2924 + STRING_BYTES (XSTRING (attribute))
2925 + 3);
2926
2927 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
2928 + STRING_BYTES (XSTRING (class))
2929 + (STRINGP (subclass)
2930 ? STRING_BYTES (XSTRING (subclass)) : 0)
2931 + 3);
2932
2933 /* Start with emacs.FRAMENAME for the name (the specific one)
2934 and with `Emacs' for the class key (the general one). */
2935 strcpy (name_key, XSTRING (Vx_resource_name)->data);
2936 strcpy (class_key, EMACS_CLASS);
2937
2938 strcat (class_key, ".");
2939 strcat (class_key, XSTRING (class)->data);
2940
2941 if (!NILP (component))
2942 {
2943 strcat (class_key, ".");
2944 strcat (class_key, XSTRING (subclass)->data);
2945
2946 strcat (name_key, ".");
2947 strcat (name_key, XSTRING (component)->data);
2948 }
2949
2950 strcat (name_key, ".");
2951 strcat (name_key, XSTRING (attribute)->data);
2952
2953 value = x_get_string_resource (Qnil,
2954 name_key, class_key);
2955
2956 if (value != (char *) 0)
2957 return build_string (value);
2958 else
2959 return Qnil;
2960 }
2961
2962 /* Used when C code wants a resource value. */
2963
2964 char *
2965 x_get_resource_string (attribute, class)
2966 char *attribute, *class;
2967 {
2968 char *name_key;
2969 char *class_key;
2970 struct frame *sf = SELECTED_FRAME ();
2971
2972 /* Allocate space for the components, the dots which separate them,
2973 and the final '\0'. */
2974 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vinvocation_name))
2975 + strlen (attribute) + 2);
2976 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
2977 + strlen (class) + 2);
2978
2979 sprintf (name_key, "%s.%s",
2980 XSTRING (Vinvocation_name)->data,
2981 attribute);
2982 sprintf (class_key, "%s.%s", EMACS_CLASS, class);
2983
2984 return x_get_string_resource (sf, name_key, class_key);
2985 }
2986
2987 /* Types we might convert a resource string into. */
2988 enum resource_types
2989 {
2990 RES_TYPE_NUMBER,
2991 RES_TYPE_FLOAT,
2992 RES_TYPE_BOOLEAN,
2993 RES_TYPE_STRING,
2994 RES_TYPE_SYMBOL
2995 };
2996
2997 /* Return the value of parameter PARAM.
2998
2999 First search ALIST, then Vdefault_frame_alist, then the X defaults
3000 database, using ATTRIBUTE as the attribute name and CLASS as its class.
3001
3002 Convert the resource to the type specified by desired_type.
3003
3004 If no default is specified, return Qunbound. If you call
3005 w32_get_arg, make sure you deal with Qunbound in a reasonable way,
3006 and don't let it get stored in any Lisp-visible variables! */
3007
3008 static Lisp_Object
3009 w32_get_arg (alist, param, attribute, class, type)
3010 Lisp_Object alist, param;
3011 char *attribute;
3012 char *class;
3013 enum resource_types type;
3014 {
3015 register Lisp_Object tem;
3016
3017 tem = Fassq (param, alist);
3018 if (EQ (tem, Qnil))
3019 tem = Fassq (param, Vdefault_frame_alist);
3020 if (EQ (tem, Qnil))
3021 {
3022
3023 if (attribute)
3024 {
3025 tem = Fx_get_resource (build_string (attribute),
3026 build_string (class),
3027 Qnil, Qnil);
3028
3029 if (NILP (tem))
3030 return Qunbound;
3031
3032 switch (type)
3033 {
3034 case RES_TYPE_NUMBER:
3035 return make_number (atoi (XSTRING (tem)->data));
3036
3037 case RES_TYPE_FLOAT:
3038 return make_float (atof (XSTRING (tem)->data));
3039
3040 case RES_TYPE_BOOLEAN:
3041 tem = Fdowncase (tem);
3042 if (!strcmp (XSTRING (tem)->data, "on")
3043 || !strcmp (XSTRING (tem)->data, "true"))
3044 return Qt;
3045 else
3046 return Qnil;
3047
3048 case RES_TYPE_STRING:
3049 return tem;
3050
3051 case RES_TYPE_SYMBOL:
3052 /* As a special case, we map the values `true' and `on'
3053 to Qt, and `false' and `off' to Qnil. */
3054 {
3055 Lisp_Object lower;
3056 lower = Fdowncase (tem);
3057 if (!strcmp (XSTRING (lower)->data, "on")
3058 || !strcmp (XSTRING (lower)->data, "true"))
3059 return Qt;
3060 else if (!strcmp (XSTRING (lower)->data, "off")
3061 || !strcmp (XSTRING (lower)->data, "false"))
3062 return Qnil;
3063 else
3064 return Fintern (tem, Qnil);
3065 }
3066
3067 default:
3068 abort ();
3069 }
3070 }
3071 else
3072 return Qunbound;
3073 }
3074 return Fcdr (tem);
3075 }
3076
3077 /* Record in frame F the specified or default value according to ALIST
3078 of the parameter named PROP (a Lisp symbol).
3079 If no value is specified for PROP, look for an X default for XPROP
3080 on the frame named NAME.
3081 If that is not found either, use the value DEFLT. */
3082
3083 static Lisp_Object
3084 x_default_parameter (f, alist, prop, deflt, xprop, xclass, type)
3085 struct frame *f;
3086 Lisp_Object alist;
3087 Lisp_Object prop;
3088 Lisp_Object deflt;
3089 char *xprop;
3090 char *xclass;
3091 enum resource_types type;
3092 {
3093 Lisp_Object tem;
3094
3095 tem = w32_get_arg (alist, prop, xprop, xclass, type);
3096 if (EQ (tem, Qunbound))
3097 tem = deflt;
3098 x_set_frame_parameters (f, Fcons (Fcons (prop, tem), Qnil));
3099 return tem;
3100 }
3101 \f
3102 DEFUN ("x-parse-geometry", Fx_parse_geometry, Sx_parse_geometry, 1, 1, 0,
3103 "Parse an X-style geometry string STRING.\n\
3104 Returns an alist of the form ((top . TOP), (left . LEFT) ... ).\n\
3105 The properties returned may include `top', `left', `height', and `width'.\n\
3106 The value of `left' or `top' may be an integer,\n\
3107 or a list (+ N) meaning N pixels relative to top/left corner,\n\
3108 or a list (- N) meaning -N pixels relative to bottom/right corner.")
3109 (string)
3110 Lisp_Object string;
3111 {
3112 int geometry, x, y;
3113 unsigned int width, height;
3114 Lisp_Object result;
3115
3116 CHECK_STRING (string, 0);
3117
3118 geometry = XParseGeometry ((char *) XSTRING (string)->data,
3119 &x, &y, &width, &height);
3120
3121 result = Qnil;
3122 if (geometry & XValue)
3123 {
3124 Lisp_Object element;
3125
3126 if (x >= 0 && (geometry & XNegative))
3127 element = Fcons (Qleft, Fcons (Qminus, Fcons (make_number (-x), Qnil)));
3128 else if (x < 0 && ! (geometry & XNegative))
3129 element = Fcons (Qleft, Fcons (Qplus, Fcons (make_number (x), Qnil)));
3130 else
3131 element = Fcons (Qleft, make_number (x));
3132 result = Fcons (element, result);
3133 }
3134
3135 if (geometry & YValue)
3136 {
3137 Lisp_Object element;
3138
3139 if (y >= 0 && (geometry & YNegative))
3140 element = Fcons (Qtop, Fcons (Qminus, Fcons (make_number (-y), Qnil)));
3141 else if (y < 0 && ! (geometry & YNegative))
3142 element = Fcons (Qtop, Fcons (Qplus, Fcons (make_number (y), Qnil)));
3143 else
3144 element = Fcons (Qtop, make_number (y));
3145 result = Fcons (element, result);
3146 }
3147
3148 if (geometry & WidthValue)
3149 result = Fcons (Fcons (Qwidth, make_number (width)), result);
3150 if (geometry & HeightValue)
3151 result = Fcons (Fcons (Qheight, make_number (height)), result);
3152
3153 return result;
3154 }
3155
3156 /* Calculate the desired size and position of this window,
3157 and return the flags saying which aspects were specified.
3158
3159 This function does not make the coordinates positive. */
3160
3161 #define DEFAULT_ROWS 40
3162 #define DEFAULT_COLS 80
3163
3164 static int
3165 x_figure_window_size (f, parms)
3166 struct frame *f;
3167 Lisp_Object parms;
3168 {
3169 register Lisp_Object tem0, tem1, tem2;
3170 long window_prompting = 0;
3171
3172 /* Default values if we fall through.
3173 Actually, if that happens we should get
3174 window manager prompting. */
3175 SET_FRAME_WIDTH (f, DEFAULT_COLS);
3176 f->height = DEFAULT_ROWS;
3177 /* Window managers expect that if program-specified
3178 positions are not (0,0), they're intentional, not defaults. */
3179 f->output_data.w32->top_pos = 0;
3180 f->output_data.w32->left_pos = 0;
3181
3182 /* Ensure that old new_width and new_height will not override the
3183 values set here. */
3184 FRAME_NEW_WIDTH (f) = 0;
3185 FRAME_NEW_HEIGHT (f) = 0;
3186
3187 tem0 = w32_get_arg (parms, Qheight, 0, 0, RES_TYPE_NUMBER);
3188 tem1 = w32_get_arg (parms, Qwidth, 0, 0, RES_TYPE_NUMBER);
3189 tem2 = w32_get_arg (parms, Quser_size, 0, 0, RES_TYPE_NUMBER);
3190 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3191 {
3192 if (!EQ (tem0, Qunbound))
3193 {
3194 CHECK_NUMBER (tem0, 0);
3195 f->height = XINT (tem0);
3196 }
3197 if (!EQ (tem1, Qunbound))
3198 {
3199 CHECK_NUMBER (tem1, 0);
3200 SET_FRAME_WIDTH (f, XINT (tem1));
3201 }
3202 if (!NILP (tem2) && !EQ (tem2, Qunbound))
3203 window_prompting |= USSize;
3204 else
3205 window_prompting |= PSize;
3206 }
3207
3208 f->output_data.w32->vertical_scroll_bar_extra
3209 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
3210 ? 0
3211 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
3212 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
3213 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.w32->font)));
3214 f->output_data.w32->flags_areas_extra
3215 = FRAME_FLAGS_AREA_WIDTH (f);
3216 f->output_data.w32->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
3217 f->output_data.w32->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
3218
3219 tem0 = w32_get_arg (parms, Qtop, 0, 0, RES_TYPE_NUMBER);
3220 tem1 = w32_get_arg (parms, Qleft, 0, 0, RES_TYPE_NUMBER);
3221 tem2 = w32_get_arg (parms, Quser_position, 0, 0, RES_TYPE_NUMBER);
3222 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3223 {
3224 if (EQ (tem0, Qminus))
3225 {
3226 f->output_data.w32->top_pos = 0;
3227 window_prompting |= YNegative;
3228 }
3229 else if (CONSP (tem0) && EQ (XCAR (tem0), Qminus)
3230 && CONSP (XCDR (tem0))
3231 && INTEGERP (XCAR (XCDR (tem0))))
3232 {
3233 f->output_data.w32->top_pos = - XINT (XCAR (XCDR (tem0)));
3234 window_prompting |= YNegative;
3235 }
3236 else if (CONSP (tem0) && EQ (XCAR (tem0), Qplus)
3237 && CONSP (XCDR (tem0))
3238 && INTEGERP (XCAR (XCDR (tem0))))
3239 {
3240 f->output_data.w32->top_pos = XINT (XCAR (XCDR (tem0)));
3241 }
3242 else if (EQ (tem0, Qunbound))
3243 f->output_data.w32->top_pos = 0;
3244 else
3245 {
3246 CHECK_NUMBER (tem0, 0);
3247 f->output_data.w32->top_pos = XINT (tem0);
3248 if (f->output_data.w32->top_pos < 0)
3249 window_prompting |= YNegative;
3250 }
3251
3252 if (EQ (tem1, Qminus))
3253 {
3254 f->output_data.w32->left_pos = 0;
3255 window_prompting |= XNegative;
3256 }
3257 else if (CONSP (tem1) && EQ (XCAR (tem1), Qminus)
3258 && CONSP (XCDR (tem1))
3259 && INTEGERP (XCAR (XCDR (tem1))))
3260 {
3261 f->output_data.w32->left_pos = - XINT (XCAR (XCDR (tem1)));
3262 window_prompting |= XNegative;
3263 }
3264 else if (CONSP (tem1) && EQ (XCAR (tem1), Qplus)
3265 && CONSP (XCDR (tem1))
3266 && INTEGERP (XCAR (XCDR (tem1))))
3267 {
3268 f->output_data.w32->left_pos = XINT (XCAR (XCDR (tem1)));
3269 }
3270 else if (EQ (tem1, Qunbound))
3271 f->output_data.w32->left_pos = 0;
3272 else
3273 {
3274 CHECK_NUMBER (tem1, 0);
3275 f->output_data.w32->left_pos = XINT (tem1);
3276 if (f->output_data.w32->left_pos < 0)
3277 window_prompting |= XNegative;
3278 }
3279
3280 if (!NILP (tem2) && ! EQ (tem2, Qunbound))
3281 window_prompting |= USPosition;
3282 else
3283 window_prompting |= PPosition;
3284 }
3285
3286 return window_prompting;
3287 }
3288
3289 \f
3290
3291 extern LRESULT CALLBACK w32_wnd_proc ();
3292
3293 BOOL
3294 w32_init_class (hinst)
3295 HINSTANCE hinst;
3296 {
3297 WNDCLASS wc;
3298
3299 wc.style = CS_HREDRAW | CS_VREDRAW;
3300 wc.lpfnWndProc = (WNDPROC) w32_wnd_proc;
3301 wc.cbClsExtra = 0;
3302 wc.cbWndExtra = WND_EXTRA_BYTES;
3303 wc.hInstance = hinst;
3304 wc.hIcon = LoadIcon (hinst, EMACS_CLASS);
3305 wc.hCursor = LoadCursor (NULL, IDC_ARROW);
3306 wc.hbrBackground = NULL; /* GetStockObject (WHITE_BRUSH); */
3307 wc.lpszMenuName = NULL;
3308 wc.lpszClassName = EMACS_CLASS;
3309
3310 return (RegisterClass (&wc));
3311 }
3312
3313 HWND
3314 w32_createscrollbar (f, bar)
3315 struct frame *f;
3316 struct scroll_bar * bar;
3317 {
3318 return (CreateWindow ("SCROLLBAR", "", SBS_VERT | WS_CHILD | WS_VISIBLE,
3319 /* Position and size of scroll bar. */
3320 XINT(bar->left) + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
3321 XINT(bar->top),
3322 XINT(bar->width) - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
3323 XINT(bar->height),
3324 FRAME_W32_WINDOW (f),
3325 NULL,
3326 hinst,
3327 NULL));
3328 }
3329
3330 void
3331 w32_createwindow (f)
3332 struct frame *f;
3333 {
3334 HWND hwnd;
3335 RECT rect;
3336
3337 rect.left = rect.top = 0;
3338 rect.right = PIXEL_WIDTH (f);
3339 rect.bottom = PIXEL_HEIGHT (f);
3340
3341 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
3342 FRAME_EXTERNAL_MENU_BAR (f));
3343
3344 /* Do first time app init */
3345
3346 if (!hprevinst)
3347 {
3348 w32_init_class (hinst);
3349 }
3350
3351 FRAME_W32_WINDOW (f) = hwnd
3352 = CreateWindow (EMACS_CLASS,
3353 f->namebuf,
3354 f->output_data.w32->dwStyle,
3355 f->output_data.w32->left_pos,
3356 f->output_data.w32->top_pos,
3357 rect.right - rect.left,
3358 rect.bottom - rect.top,
3359 NULL,
3360 NULL,
3361 hinst,
3362 NULL);
3363
3364 if (hwnd)
3365 {
3366 SetWindowLong (hwnd, WND_FONTWIDTH_INDEX, FONT_WIDTH (f->output_data.w32->font));
3367 SetWindowLong (hwnd, WND_LINEHEIGHT_INDEX, f->output_data.w32->line_height);
3368 SetWindowLong (hwnd, WND_BORDER_INDEX, f->output_data.w32->internal_border_width);
3369 SetWindowLong (hwnd, WND_SCROLLBAR_INDEX, f->output_data.w32->vertical_scroll_bar_extra);
3370 SetWindowLong (hwnd, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f));
3371
3372 /* Enable drag-n-drop. */
3373 DragAcceptFiles (hwnd, TRUE);
3374
3375 /* Do this to discard the default setting specified by our parent. */
3376 ShowWindow (hwnd, SW_HIDE);
3377 }
3378 }
3379
3380 void
3381 my_post_msg (wmsg, hwnd, msg, wParam, lParam)
3382 W32Msg * wmsg;
3383 HWND hwnd;
3384 UINT msg;
3385 WPARAM wParam;
3386 LPARAM lParam;
3387 {
3388 wmsg->msg.hwnd = hwnd;
3389 wmsg->msg.message = msg;
3390 wmsg->msg.wParam = wParam;
3391 wmsg->msg.lParam = lParam;
3392 wmsg->msg.time = GetMessageTime ();
3393
3394 post_msg (wmsg);
3395 }
3396
3397 /* GetKeyState and MapVirtualKey on Windows 95 do not actually distinguish
3398 between left and right keys as advertised. We test for this
3399 support dynamically, and set a flag when the support is absent. If
3400 absent, we keep track of the left and right control and alt keys
3401 ourselves. This is particularly necessary on keyboards that rely
3402 upon the AltGr key, which is represented as having the left control
3403 and right alt keys pressed. For these keyboards, we need to know
3404 when the left alt key has been pressed in addition to the AltGr key
3405 so that we can properly support M-AltGr-key sequences (such as M-@
3406 on Swedish keyboards). */
3407
3408 #define EMACS_LCONTROL 0
3409 #define EMACS_RCONTROL 1
3410 #define EMACS_LMENU 2
3411 #define EMACS_RMENU 3
3412
3413 static int modifiers[4];
3414 static int modifiers_recorded;
3415 static int modifier_key_support_tested;
3416
3417 static void
3418 test_modifier_support (unsigned int wparam)
3419 {
3420 unsigned int l, r;
3421
3422 if (wparam != VK_CONTROL && wparam != VK_MENU)
3423 return;
3424 if (wparam == VK_CONTROL)
3425 {
3426 l = VK_LCONTROL;
3427 r = VK_RCONTROL;
3428 }
3429 else
3430 {
3431 l = VK_LMENU;
3432 r = VK_RMENU;
3433 }
3434 if (!(GetKeyState (l) & 0x8000) && !(GetKeyState (r) & 0x8000))
3435 modifiers_recorded = 1;
3436 else
3437 modifiers_recorded = 0;
3438 modifier_key_support_tested = 1;
3439 }
3440
3441 static void
3442 record_keydown (unsigned int wparam, unsigned int lparam)
3443 {
3444 int i;
3445
3446 if (!modifier_key_support_tested)
3447 test_modifier_support (wparam);
3448
3449 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3450 return;
3451
3452 if (wparam == VK_CONTROL)
3453 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3454 else
3455 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3456
3457 modifiers[i] = 1;
3458 }
3459
3460 static void
3461 record_keyup (unsigned int wparam, unsigned int lparam)
3462 {
3463 int i;
3464
3465 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3466 return;
3467
3468 if (wparam == VK_CONTROL)
3469 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3470 else
3471 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3472
3473 modifiers[i] = 0;
3474 }
3475
3476 /* Emacs can lose focus while a modifier key has been pressed. When
3477 it regains focus, be conservative and clear all modifiers since
3478 we cannot reconstruct the left and right modifier state. */
3479 static void
3480 reset_modifiers ()
3481 {
3482 SHORT ctrl, alt;
3483
3484 if (GetFocus () == NULL)
3485 /* Emacs doesn't have keyboard focus. Do nothing. */
3486 return;
3487
3488 ctrl = GetAsyncKeyState (VK_CONTROL);
3489 alt = GetAsyncKeyState (VK_MENU);
3490
3491 if (!(ctrl & 0x08000))
3492 /* Clear any recorded control modifier state. */
3493 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3494
3495 if (!(alt & 0x08000))
3496 /* Clear any recorded alt modifier state. */
3497 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3498
3499 /* Update the state of all modifier keys, because modifiers used in
3500 hot-key combinations can get stuck on if Emacs loses focus as a
3501 result of a hot-key being pressed. */
3502 {
3503 BYTE keystate[256];
3504
3505 #define CURRENT_STATE(key) ((GetAsyncKeyState (key) & 0x8000) >> 8)
3506
3507 GetKeyboardState (keystate);
3508 keystate[VK_SHIFT] = CURRENT_STATE (VK_SHIFT);
3509 keystate[VK_CONTROL] = CURRENT_STATE (VK_CONTROL);
3510 keystate[VK_LCONTROL] = CURRENT_STATE (VK_LCONTROL);
3511 keystate[VK_RCONTROL] = CURRENT_STATE (VK_RCONTROL);
3512 keystate[VK_MENU] = CURRENT_STATE (VK_MENU);
3513 keystate[VK_LMENU] = CURRENT_STATE (VK_LMENU);
3514 keystate[VK_RMENU] = CURRENT_STATE (VK_RMENU);
3515 keystate[VK_LWIN] = CURRENT_STATE (VK_LWIN);
3516 keystate[VK_RWIN] = CURRENT_STATE (VK_RWIN);
3517 keystate[VK_APPS] = CURRENT_STATE (VK_APPS);
3518 SetKeyboardState (keystate);
3519 }
3520 }
3521
3522 /* Synchronize modifier state with what is reported with the current
3523 keystroke. Even if we cannot distinguish between left and right
3524 modifier keys, we know that, if no modifiers are set, then neither
3525 the left or right modifier should be set. */
3526 static void
3527 sync_modifiers ()
3528 {
3529 if (!modifiers_recorded)
3530 return;
3531
3532 if (!(GetKeyState (VK_CONTROL) & 0x8000))
3533 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3534
3535 if (!(GetKeyState (VK_MENU) & 0x8000))
3536 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3537 }
3538
3539 static int
3540 modifier_set (int vkey)
3541 {
3542 if (vkey == VK_CAPITAL || vkey == VK_SCROLL)
3543 return (GetKeyState (vkey) & 0x1);
3544 if (!modifiers_recorded)
3545 return (GetKeyState (vkey) & 0x8000);
3546
3547 switch (vkey)
3548 {
3549 case VK_LCONTROL:
3550 return modifiers[EMACS_LCONTROL];
3551 case VK_RCONTROL:
3552 return modifiers[EMACS_RCONTROL];
3553 case VK_LMENU:
3554 return modifiers[EMACS_LMENU];
3555 case VK_RMENU:
3556 return modifiers[EMACS_RMENU];
3557 }
3558 return (GetKeyState (vkey) & 0x8000);
3559 }
3560
3561 /* Convert between the modifier bits W32 uses and the modifier bits
3562 Emacs uses. */
3563
3564 unsigned int
3565 w32_key_to_modifier (int key)
3566 {
3567 Lisp_Object key_mapping;
3568
3569 switch (key)
3570 {
3571 case VK_LWIN:
3572 key_mapping = Vw32_lwindow_modifier;
3573 break;
3574 case VK_RWIN:
3575 key_mapping = Vw32_rwindow_modifier;
3576 break;
3577 case VK_APPS:
3578 key_mapping = Vw32_apps_modifier;
3579 break;
3580 case VK_SCROLL:
3581 key_mapping = Vw32_scroll_lock_modifier;
3582 break;
3583 default:
3584 key_mapping = Qnil;
3585 }
3586
3587 /* NB. This code runs in the input thread, asychronously to the lisp
3588 thread, so we must be careful to ensure access to lisp data is
3589 thread-safe. The following code is safe because the modifier
3590 variable values are updated atomically from lisp and symbols are
3591 not relocated by GC. Also, we don't have to worry about seeing GC
3592 markbits here. */
3593 if (EQ (key_mapping, Qhyper))
3594 return hyper_modifier;
3595 if (EQ (key_mapping, Qsuper))
3596 return super_modifier;
3597 if (EQ (key_mapping, Qmeta))
3598 return meta_modifier;
3599 if (EQ (key_mapping, Qalt))
3600 return alt_modifier;
3601 if (EQ (key_mapping, Qctrl))
3602 return ctrl_modifier;
3603 if (EQ (key_mapping, Qcontrol)) /* synonym for ctrl */
3604 return ctrl_modifier;
3605 if (EQ (key_mapping, Qshift))
3606 return shift_modifier;
3607
3608 /* Don't generate any modifier if not explicitly requested. */
3609 return 0;
3610 }
3611
3612 unsigned int
3613 w32_get_modifiers ()
3614 {
3615 return ((modifier_set (VK_SHIFT) ? shift_modifier : 0) |
3616 (modifier_set (VK_CONTROL) ? ctrl_modifier : 0) |
3617 (modifier_set (VK_LWIN) ? w32_key_to_modifier (VK_LWIN) : 0) |
3618 (modifier_set (VK_RWIN) ? w32_key_to_modifier (VK_RWIN) : 0) |
3619 (modifier_set (VK_APPS) ? w32_key_to_modifier (VK_APPS) : 0) |
3620 (modifier_set (VK_SCROLL) ? w32_key_to_modifier (VK_SCROLL) : 0) |
3621 (modifier_set (VK_MENU) ?
3622 ((NILP (Vw32_alt_is_meta)) ? alt_modifier : meta_modifier) : 0));
3623 }
3624
3625 /* We map the VK_* modifiers into console modifier constants
3626 so that we can use the same routines to handle both console
3627 and window input. */
3628
3629 static int
3630 construct_console_modifiers ()
3631 {
3632 int mods;
3633
3634 mods = 0;
3635 mods |= (modifier_set (VK_SHIFT)) ? SHIFT_PRESSED : 0;
3636 mods |= (modifier_set (VK_CAPITAL)) ? CAPSLOCK_ON : 0;
3637 mods |= (modifier_set (VK_SCROLL)) ? SCROLLLOCK_ON : 0;
3638 mods |= (modifier_set (VK_NUMLOCK)) ? NUMLOCK_ON : 0;
3639 mods |= (modifier_set (VK_LCONTROL)) ? LEFT_CTRL_PRESSED : 0;
3640 mods |= (modifier_set (VK_RCONTROL)) ? RIGHT_CTRL_PRESSED : 0;
3641 mods |= (modifier_set (VK_LMENU)) ? LEFT_ALT_PRESSED : 0;
3642 mods |= (modifier_set (VK_RMENU)) ? RIGHT_ALT_PRESSED : 0;
3643 mods |= (modifier_set (VK_LWIN)) ? LEFT_WIN_PRESSED : 0;
3644 mods |= (modifier_set (VK_RWIN)) ? RIGHT_WIN_PRESSED : 0;
3645 mods |= (modifier_set (VK_APPS)) ? APPS_PRESSED : 0;
3646
3647 return mods;
3648 }
3649
3650 static int
3651 w32_get_key_modifiers (unsigned int wparam, unsigned int lparam)
3652 {
3653 int mods;
3654
3655 /* Convert to emacs modifiers. */
3656 mods = w32_kbd_mods_to_emacs (construct_console_modifiers (), wparam);
3657
3658 return mods;
3659 }
3660
3661 unsigned int
3662 map_keypad_keys (unsigned int virt_key, unsigned int extended)
3663 {
3664 if (virt_key < VK_CLEAR || virt_key > VK_DELETE)
3665 return virt_key;
3666
3667 if (virt_key == VK_RETURN)
3668 return (extended ? VK_NUMPAD_ENTER : VK_RETURN);
3669
3670 if (virt_key >= VK_PRIOR && virt_key <= VK_DOWN)
3671 return (!extended ? (VK_NUMPAD_PRIOR + (virt_key - VK_PRIOR)) : virt_key);
3672
3673 if (virt_key == VK_INSERT || virt_key == VK_DELETE)
3674 return (!extended ? (VK_NUMPAD_INSERT + (virt_key - VK_INSERT)) : virt_key);
3675
3676 if (virt_key == VK_CLEAR)
3677 return (!extended ? VK_NUMPAD_CLEAR : virt_key);
3678
3679 return virt_key;
3680 }
3681
3682 /* List of special key combinations which w32 would normally capture,
3683 but emacs should grab instead. Not directly visible to lisp, to
3684 simplify synchronization. Each item is an integer encoding a virtual
3685 key code and modifier combination to capture. */
3686 Lisp_Object w32_grabbed_keys;
3687
3688 #define HOTKEY(vk,mods) make_number (((vk) & 255) | ((mods) << 8))
3689 #define HOTKEY_ID(k) (XFASTINT (k) & 0xbfff)
3690 #define HOTKEY_VK_CODE(k) (XFASTINT (k) & 255)
3691 #define HOTKEY_MODIFIERS(k) (XFASTINT (k) >> 8)
3692
3693 /* Register hot-keys for reserved key combinations when Emacs has
3694 keyboard focus, since this is the only way Emacs can receive key
3695 combinations like Alt-Tab which are used by the system. */
3696
3697 static void
3698 register_hot_keys (hwnd)
3699 HWND hwnd;
3700 {
3701 Lisp_Object keylist;
3702
3703 /* Use GC_CONSP, since we are called asynchronously. */
3704 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3705 {
3706 Lisp_Object key = XCAR (keylist);
3707
3708 /* Deleted entries get set to nil. */
3709 if (!INTEGERP (key))
3710 continue;
3711
3712 RegisterHotKey (hwnd, HOTKEY_ID (key),
3713 HOTKEY_MODIFIERS (key), HOTKEY_VK_CODE (key));
3714 }
3715 }
3716
3717 static void
3718 unregister_hot_keys (hwnd)
3719 HWND hwnd;
3720 {
3721 Lisp_Object keylist;
3722
3723 /* Use GC_CONSP, since we are called asynchronously. */
3724 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3725 {
3726 Lisp_Object key = XCAR (keylist);
3727
3728 if (!INTEGERP (key))
3729 continue;
3730
3731 UnregisterHotKey (hwnd, HOTKEY_ID (key));
3732 }
3733 }
3734
3735 /* Main message dispatch loop. */
3736
3737 static void
3738 w32_msg_pump (deferred_msg * msg_buf)
3739 {
3740 MSG msg;
3741 int result;
3742 HWND focus_window;
3743
3744 msh_mousewheel = RegisterWindowMessage (MSH_MOUSEWHEEL);
3745
3746 while (GetMessage (&msg, NULL, 0, 0))
3747 {
3748 if (msg.hwnd == NULL)
3749 {
3750 switch (msg.message)
3751 {
3752 case WM_NULL:
3753 /* Produced by complete_deferred_msg; just ignore. */
3754 break;
3755 case WM_EMACS_CREATEWINDOW:
3756 w32_createwindow ((struct frame *) msg.wParam);
3757 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3758 abort ();
3759 break;
3760 case WM_EMACS_SETLOCALE:
3761 SetThreadLocale (msg.wParam);
3762 /* Reply is not expected. */
3763 break;
3764 case WM_EMACS_SETKEYBOARDLAYOUT:
3765 result = (int) ActivateKeyboardLayout ((HKL) msg.wParam, 0);
3766 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
3767 result, 0))
3768 abort ();
3769 break;
3770 case WM_EMACS_REGISTER_HOT_KEY:
3771 focus_window = GetFocus ();
3772 if (focus_window != NULL)
3773 RegisterHotKey (focus_window,
3774 HOTKEY_ID (msg.wParam),
3775 HOTKEY_MODIFIERS (msg.wParam),
3776 HOTKEY_VK_CODE (msg.wParam));
3777 /* Reply is not expected. */
3778 break;
3779 case WM_EMACS_UNREGISTER_HOT_KEY:
3780 focus_window = GetFocus ();
3781 if (focus_window != NULL)
3782 UnregisterHotKey (focus_window, HOTKEY_ID (msg.wParam));
3783 /* Mark item as erased. NB: this code must be
3784 thread-safe. The next line is okay because the cons
3785 cell is never made into garbage and is not relocated by
3786 GC. */
3787 XCAR ((Lisp_Object) msg.lParam) = Qnil;
3788 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3789 abort ();
3790 break;
3791 case WM_EMACS_TOGGLE_LOCK_KEY:
3792 {
3793 int vk_code = (int) msg.wParam;
3794 int cur_state = (GetKeyState (vk_code) & 1);
3795 Lisp_Object new_state = (Lisp_Object) msg.lParam;
3796
3797 /* NB: This code must be thread-safe. It is safe to
3798 call NILP because symbols are not relocated by GC,
3799 and pointer here is not touched by GC (so the markbit
3800 can't be set). Numbers are safe because they are
3801 immediate values. */
3802 if (NILP (new_state)
3803 || (NUMBERP (new_state)
3804 && ((XUINT (new_state)) & 1) != cur_state))
3805 {
3806 one_w32_display_info.faked_key = vk_code;
3807
3808 keybd_event ((BYTE) vk_code,
3809 (BYTE) MapVirtualKey (vk_code, 0),
3810 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3811 keybd_event ((BYTE) vk_code,
3812 (BYTE) MapVirtualKey (vk_code, 0),
3813 KEYEVENTF_EXTENDEDKEY | 0, 0);
3814 keybd_event ((BYTE) vk_code,
3815 (BYTE) MapVirtualKey (vk_code, 0),
3816 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3817 cur_state = !cur_state;
3818 }
3819 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
3820 cur_state, 0))
3821 abort ();
3822 }
3823 break;
3824 default:
3825 DebPrint (("msg %x not expected by w32_msg_pump\n", msg.message));
3826 }
3827 }
3828 else
3829 {
3830 DispatchMessage (&msg);
3831 }
3832
3833 /* Exit nested loop when our deferred message has completed. */
3834 if (msg_buf->completed)
3835 break;
3836 }
3837 }
3838
3839 deferred_msg * deferred_msg_head;
3840
3841 static deferred_msg *
3842 find_deferred_msg (HWND hwnd, UINT msg)
3843 {
3844 deferred_msg * item;
3845
3846 /* Don't actually need synchronization for read access, since
3847 modification of single pointer is always atomic. */
3848 /* enter_crit (); */
3849
3850 for (item = deferred_msg_head; item != NULL; item = item->next)
3851 if (item->w32msg.msg.hwnd == hwnd
3852 && item->w32msg.msg.message == msg)
3853 break;
3854
3855 /* leave_crit (); */
3856
3857 return item;
3858 }
3859
3860 static LRESULT
3861 send_deferred_msg (deferred_msg * msg_buf,
3862 HWND hwnd,
3863 UINT msg,
3864 WPARAM wParam,
3865 LPARAM lParam)
3866 {
3867 /* Only input thread can send deferred messages. */
3868 if (GetCurrentThreadId () != dwWindowsThreadId)
3869 abort ();
3870
3871 /* It is an error to send a message that is already deferred. */
3872 if (find_deferred_msg (hwnd, msg) != NULL)
3873 abort ();
3874
3875 /* Enforced synchronization is not needed because this is the only
3876 function that alters deferred_msg_head, and the following critical
3877 section is guaranteed to only be serially reentered (since only the
3878 input thread can call us). */
3879
3880 /* enter_crit (); */
3881
3882 msg_buf->completed = 0;
3883 msg_buf->next = deferred_msg_head;
3884 deferred_msg_head = msg_buf;
3885 my_post_msg (&msg_buf->w32msg, hwnd, msg, wParam, lParam);
3886
3887 /* leave_crit (); */
3888
3889 /* Start a new nested message loop to process other messages until
3890 this one is completed. */
3891 w32_msg_pump (msg_buf);
3892
3893 deferred_msg_head = msg_buf->next;
3894
3895 return msg_buf->result;
3896 }
3897
3898 void
3899 complete_deferred_msg (HWND hwnd, UINT msg, LRESULT result)
3900 {
3901 deferred_msg * msg_buf = find_deferred_msg (hwnd, msg);
3902
3903 if (msg_buf == NULL)
3904 /* Message may have been cancelled, so don't abort(). */
3905 return;
3906
3907 msg_buf->result = result;
3908 msg_buf->completed = 1;
3909
3910 /* Ensure input thread is woken so it notices the completion. */
3911 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
3912 }
3913
3914 void
3915 cancel_all_deferred_msgs ()
3916 {
3917 deferred_msg * item;
3918
3919 /* Don't actually need synchronization for read access, since
3920 modification of single pointer is always atomic. */
3921 /* enter_crit (); */
3922
3923 for (item = deferred_msg_head; item != NULL; item = item->next)
3924 {
3925 item->result = 0;
3926 item->completed = 1;
3927 }
3928
3929 /* leave_crit (); */
3930
3931 /* Ensure input thread is woken so it notices the completion. */
3932 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
3933 }
3934
3935 DWORD
3936 w32_msg_worker (dw)
3937 DWORD dw;
3938 {
3939 MSG msg;
3940 deferred_msg dummy_buf;
3941
3942 /* Ensure our message queue is created */
3943
3944 PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
3945
3946 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3947 abort ();
3948
3949 memset (&dummy_buf, 0, sizeof (dummy_buf));
3950 dummy_buf.w32msg.msg.hwnd = NULL;
3951 dummy_buf.w32msg.msg.message = WM_NULL;
3952
3953 /* This is the inital message loop which should only exit when the
3954 application quits. */
3955 w32_msg_pump (&dummy_buf);
3956
3957 return 0;
3958 }
3959
3960 static void
3961 post_character_message (hwnd, msg, wParam, lParam, modifiers)
3962 HWND hwnd;
3963 UINT msg;
3964 WPARAM wParam;
3965 LPARAM lParam;
3966 DWORD modifiers;
3967
3968 {
3969 W32Msg wmsg;
3970
3971 wmsg.dwModifiers = modifiers;
3972
3973 /* Detect quit_char and set quit-flag directly. Note that we
3974 still need to post a message to ensure the main thread will be
3975 woken up if blocked in sys_select(), but we do NOT want to post
3976 the quit_char message itself (because it will usually be as if
3977 the user had typed quit_char twice). Instead, we post a dummy
3978 message that has no particular effect. */
3979 {
3980 int c = wParam;
3981 if (isalpha (c) && wmsg.dwModifiers == ctrl_modifier)
3982 c = make_ctrl_char (c) & 0377;
3983 if (c == quit_char
3984 || (wmsg.dwModifiers == 0 &&
3985 XFASTINT (Vw32_quit_key) && wParam == XFASTINT (Vw32_quit_key)))
3986 {
3987 Vquit_flag = Qt;
3988
3989 /* The choice of message is somewhat arbitrary, as long as
3990 the main thread handler just ignores it. */
3991 msg = WM_NULL;
3992
3993 /* Interrupt any blocking system calls. */
3994 signal_quit ();
3995
3996 /* As a safety precaution, forcibly complete any deferred
3997 messages. This is a kludge, but I don't see any particularly
3998 clean way to handle the situation where a deferred message is
3999 "dropped" in the lisp thread, and will thus never be
4000 completed, eg. by the user trying to activate the menubar
4001 when the lisp thread is busy, and then typing C-g when the
4002 menubar doesn't open promptly (with the result that the
4003 menubar never responds at all because the deferred
4004 WM_INITMENU message is never completed). Another problem
4005 situation is when the lisp thread calls SendMessage (to send
4006 a window manager command) when a message has been deferred;
4007 the lisp thread gets blocked indefinitely waiting for the
4008 deferred message to be completed, which itself is waiting for
4009 the lisp thread to respond.
4010
4011 Note that we don't want to block the input thread waiting for
4012 a reponse from the lisp thread (although that would at least
4013 solve the deadlock problem above), because we want to be able
4014 to receive C-g to interrupt the lisp thread. */
4015 cancel_all_deferred_msgs ();
4016 }
4017 }
4018
4019 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4020 }
4021
4022 /* Main window procedure */
4023
4024 LRESULT CALLBACK
4025 w32_wnd_proc (hwnd, msg, wParam, lParam)
4026 HWND hwnd;
4027 UINT msg;
4028 WPARAM wParam;
4029 LPARAM lParam;
4030 {
4031 struct frame *f;
4032 struct w32_display_info *dpyinfo = &one_w32_display_info;
4033 W32Msg wmsg;
4034 int windows_translate;
4035 int key;
4036
4037 /* Note that it is okay to call x_window_to_frame, even though we are
4038 not running in the main lisp thread, because frame deletion
4039 requires the lisp thread to synchronize with this thread. Thus, if
4040 a frame struct is returned, it can be used without concern that the
4041 lisp thread might make it disappear while we are using it.
4042
4043 NB. Walking the frame list in this thread is safe (as long as
4044 writes of Lisp_Object slots are atomic, which they are on Windows).
4045 Although delete-frame can destructively modify the frame list while
4046 we are walking it, a garbage collection cannot occur until after
4047 delete-frame has synchronized with this thread.
4048
4049 It is also safe to use functions that make GDI calls, such as
4050 w32_clear_rect, because these functions must obtain a DC handle
4051 from the frame struct using get_frame_dc which is thread-aware. */
4052
4053 switch (msg)
4054 {
4055 case WM_ERASEBKGND:
4056 f = x_window_to_frame (dpyinfo, hwnd);
4057 if (f)
4058 {
4059 HDC hdc = get_frame_dc (f);
4060 GetUpdateRect (hwnd, &wmsg.rect, FALSE);
4061 w32_clear_rect (f, hdc, &wmsg.rect);
4062 release_frame_dc (f, hdc);
4063
4064 #if defined (W32_DEBUG_DISPLAY)
4065 DebPrint (("WM_ERASEBKGND (frame %p): erasing %d,%d-%d,%d\n",
4066 f,
4067 wmsg.rect.left, wmsg.rect.top,
4068 wmsg.rect.right, wmsg.rect.bottom));
4069 #endif /* W32_DEBUG_DISPLAY */
4070 }
4071 return 1;
4072 case WM_PALETTECHANGED:
4073 /* ignore our own changes */
4074 if ((HWND)wParam != hwnd)
4075 {
4076 f = x_window_to_frame (dpyinfo, hwnd);
4077 if (f)
4078 /* get_frame_dc will realize our palette and force all
4079 frames to be redrawn if needed. */
4080 release_frame_dc (f, get_frame_dc (f));
4081 }
4082 return 0;
4083 case WM_PAINT:
4084 {
4085 PAINTSTRUCT paintStruct;
4086 RECT update_rect;
4087
4088 f = x_window_to_frame (dpyinfo, hwnd);
4089 if (f == 0)
4090 {
4091 DebPrint (("WM_PAINT received for unknown window %p\n", hwnd));
4092 return 0;
4093 }
4094
4095 /* MSDN Docs say not to call BeginPaint if GetUpdateRect
4096 fails. Apparently this can happen under some
4097 circumstances. */
4098 if (!w32_strict_painting || GetUpdateRect (hwnd, &update_rect, FALSE))
4099 {
4100 enter_crit ();
4101 BeginPaint (hwnd, &paintStruct);
4102
4103 if (w32_strict_painting)
4104 /* The rectangles returned by GetUpdateRect and BeginPaint
4105 do not always match. GetUpdateRect seems to be the
4106 more reliable of the two. */
4107 wmsg.rect = update_rect;
4108 else
4109 wmsg.rect = paintStruct.rcPaint;
4110
4111 #if defined (W32_DEBUG_DISPLAY)
4112 DebPrint (("WM_PAINT (frame %p): painting %d,%d-%d,%d\n",
4113 f,
4114 wmsg.rect.left, wmsg.rect.top,
4115 wmsg.rect.right, wmsg.rect.bottom));
4116 DebPrint ((" [update region is %d,%d-%d,%d]\n",
4117 update_rect.left, update_rect.top,
4118 update_rect.right, update_rect.bottom));
4119 #endif
4120 EndPaint (hwnd, &paintStruct);
4121 leave_crit ();
4122
4123 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4124
4125 return 0;
4126 }
4127
4128 /* If GetUpdateRect returns 0 (meaning there is no update
4129 region), assume the whole window needs to be repainted. */
4130 GetClientRect(hwnd, &wmsg.rect);
4131 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4132 return 0;
4133 }
4134
4135 case WM_INPUTLANGCHANGE:
4136 /* Inform lisp thread of keyboard layout changes. */
4137 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4138
4139 /* Clear dead keys in the keyboard state; for simplicity only
4140 preserve modifier key states. */
4141 {
4142 int i;
4143 BYTE keystate[256];
4144
4145 GetKeyboardState (keystate);
4146 for (i = 0; i < 256; i++)
4147 if (1
4148 && i != VK_SHIFT
4149 && i != VK_LSHIFT
4150 && i != VK_RSHIFT
4151 && i != VK_CAPITAL
4152 && i != VK_NUMLOCK
4153 && i != VK_SCROLL
4154 && i != VK_CONTROL
4155 && i != VK_LCONTROL
4156 && i != VK_RCONTROL
4157 && i != VK_MENU
4158 && i != VK_LMENU
4159 && i != VK_RMENU
4160 && i != VK_LWIN
4161 && i != VK_RWIN)
4162 keystate[i] = 0;
4163 SetKeyboardState (keystate);
4164 }
4165 goto dflt;
4166
4167 case WM_HOTKEY:
4168 /* Synchronize hot keys with normal input. */
4169 PostMessage (hwnd, WM_KEYDOWN, HIWORD (lParam), 0);
4170 return (0);
4171
4172 case WM_KEYUP:
4173 case WM_SYSKEYUP:
4174 record_keyup (wParam, lParam);
4175 goto dflt;
4176
4177 case WM_KEYDOWN:
4178 case WM_SYSKEYDOWN:
4179 /* Ignore keystrokes we fake ourself; see below. */
4180 if (dpyinfo->faked_key == wParam)
4181 {
4182 dpyinfo->faked_key = 0;
4183 /* Make sure TranslateMessage sees them though (as long as
4184 they don't produce WM_CHAR messages). This ensures that
4185 indicator lights are toggled promptly on Windows 9x, for
4186 example. */
4187 if (lispy_function_keys[wParam] != 0)
4188 {
4189 windows_translate = 1;
4190 goto translate;
4191 }
4192 return 0;
4193 }
4194
4195 /* Synchronize modifiers with current keystroke. */
4196 sync_modifiers ();
4197 record_keydown (wParam, lParam);
4198 wParam = map_keypad_keys (wParam, (lParam & 0x1000000L) != 0);
4199
4200 windows_translate = 0;
4201
4202 switch (wParam)
4203 {
4204 case VK_LWIN:
4205 if (NILP (Vw32_pass_lwindow_to_system))
4206 {
4207 /* Prevent system from acting on keyup (which opens the
4208 Start menu if no other key was pressed) by simulating a
4209 press of Space which we will ignore. */
4210 if (GetAsyncKeyState (wParam) & 1)
4211 {
4212 if (NUMBERP (Vw32_phantom_key_code))
4213 key = XUINT (Vw32_phantom_key_code) & 255;
4214 else
4215 key = VK_SPACE;
4216 dpyinfo->faked_key = key;
4217 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
4218 }
4219 }
4220 if (!NILP (Vw32_lwindow_modifier))
4221 return 0;
4222 break;
4223 case VK_RWIN:
4224 if (NILP (Vw32_pass_rwindow_to_system))
4225 {
4226 if (GetAsyncKeyState (wParam) & 1)
4227 {
4228 if (NUMBERP (Vw32_phantom_key_code))
4229 key = XUINT (Vw32_phantom_key_code) & 255;
4230 else
4231 key = VK_SPACE;
4232 dpyinfo->faked_key = key;
4233 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
4234 }
4235 }
4236 if (!NILP (Vw32_rwindow_modifier))
4237 return 0;
4238 break;
4239 case VK_APPS:
4240 if (!NILP (Vw32_apps_modifier))
4241 return 0;
4242 break;
4243 case VK_MENU:
4244 if (NILP (Vw32_pass_alt_to_system))
4245 /* Prevent DefWindowProc from activating the menu bar if an
4246 Alt key is pressed and released by itself. */
4247 return 0;
4248 windows_translate = 1;
4249 break;
4250 case VK_CAPITAL:
4251 /* Decide whether to treat as modifier or function key. */
4252 if (NILP (Vw32_enable_caps_lock))
4253 goto disable_lock_key;
4254 windows_translate = 1;
4255 break;
4256 case VK_NUMLOCK:
4257 /* Decide whether to treat as modifier or function key. */
4258 if (NILP (Vw32_enable_num_lock))
4259 goto disable_lock_key;
4260 windows_translate = 1;
4261 break;
4262 case VK_SCROLL:
4263 /* Decide whether to treat as modifier or function key. */
4264 if (NILP (Vw32_scroll_lock_modifier))
4265 goto disable_lock_key;
4266 windows_translate = 1;
4267 break;
4268 disable_lock_key:
4269 /* Ensure the appropriate lock key state (and indicator light)
4270 remains in the same state. We do this by faking another
4271 press of the relevant key. Apparently, this really is the
4272 only way to toggle the state of the indicator lights. */
4273 dpyinfo->faked_key = wParam;
4274 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4275 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4276 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4277 KEYEVENTF_EXTENDEDKEY | 0, 0);
4278 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4279 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4280 /* Ensure indicator lights are updated promptly on Windows 9x
4281 (TranslateMessage apparently does this), after forwarding
4282 input event. */
4283 post_character_message (hwnd, msg, wParam, lParam,
4284 w32_get_key_modifiers (wParam, lParam));
4285 windows_translate = 1;
4286 break;
4287 case VK_CONTROL:
4288 case VK_SHIFT:
4289 case VK_PROCESSKEY: /* Generated by IME. */
4290 windows_translate = 1;
4291 break;
4292 case VK_CANCEL:
4293 /* Windows maps Ctrl-Pause (aka Ctrl-Break) into VK_CANCEL,
4294 which is confusing for purposes of key binding; convert
4295 VK_CANCEL events into VK_PAUSE events. */
4296 wParam = VK_PAUSE;
4297 break;
4298 case VK_PAUSE:
4299 /* Windows maps Ctrl-NumLock into VK_PAUSE, which is confusing
4300 for purposes of key binding; convert these back into
4301 VK_NUMLOCK events, at least when we want to see NumLock key
4302 presses. (Note that there is never any possibility that
4303 VK_PAUSE with Ctrl really is C-Pause as per above.) */
4304 if (NILP (Vw32_enable_num_lock) && modifier_set (VK_CONTROL))
4305 wParam = VK_NUMLOCK;
4306 break;
4307 default:
4308 /* If not defined as a function key, change it to a WM_CHAR message. */
4309 if (lispy_function_keys[wParam] == 0)
4310 {
4311 DWORD modifiers = construct_console_modifiers ();
4312
4313 if (!NILP (Vw32_recognize_altgr)
4314 && modifier_set (VK_LCONTROL) && modifier_set (VK_RMENU))
4315 {
4316 /* Always let TranslateMessage handle AltGr key chords;
4317 for some reason, ToAscii doesn't always process AltGr
4318 chords correctly. */
4319 windows_translate = 1;
4320 }
4321 else if ((modifiers & (~SHIFT_PRESSED & ~CAPSLOCK_ON)) != 0)
4322 {
4323 /* Handle key chords including any modifiers other
4324 than shift directly, in order to preserve as much
4325 modifier information as possible. */
4326 if ('A' <= wParam && wParam <= 'Z')
4327 {
4328 /* Don't translate modified alphabetic keystrokes,
4329 so the user doesn't need to constantly switch
4330 layout to type control or meta keystrokes when
4331 the normal layout translates alphabetic
4332 characters to non-ascii characters. */
4333 if (!modifier_set (VK_SHIFT))
4334 wParam += ('a' - 'A');
4335 msg = WM_CHAR;
4336 }
4337 else
4338 {
4339 /* Try to handle other keystrokes by determining the
4340 base character (ie. translating the base key plus
4341 shift modifier). */
4342 int add;
4343 int isdead = 0;
4344 KEY_EVENT_RECORD key;
4345
4346 key.bKeyDown = TRUE;
4347 key.wRepeatCount = 1;
4348 key.wVirtualKeyCode = wParam;
4349 key.wVirtualScanCode = (lParam & 0xFF0000) >> 16;
4350 key.uChar.AsciiChar = 0;
4351 key.dwControlKeyState = modifiers;
4352
4353 add = w32_kbd_patch_key (&key);
4354 /* 0 means an unrecognised keycode, negative means
4355 dead key. Ignore both. */
4356 while (--add >= 0)
4357 {
4358 /* Forward asciified character sequence. */
4359 post_character_message
4360 (hwnd, WM_CHAR, key.uChar.AsciiChar, lParam,
4361 w32_get_key_modifiers (wParam, lParam));
4362 w32_kbd_patch_key (&key);
4363 }
4364 return 0;
4365 }
4366 }
4367 else
4368 {
4369 /* Let TranslateMessage handle everything else. */
4370 windows_translate = 1;
4371 }
4372 }
4373 }
4374
4375 translate:
4376 if (windows_translate)
4377 {
4378 MSG windows_msg = { hwnd, msg, wParam, lParam, 0, {0,0} };
4379
4380 windows_msg.time = GetMessageTime ();
4381 TranslateMessage (&windows_msg);
4382 goto dflt;
4383 }
4384
4385 /* Fall through */
4386
4387 case WM_SYSCHAR:
4388 case WM_CHAR:
4389 post_character_message (hwnd, msg, wParam, lParam,
4390 w32_get_key_modifiers (wParam, lParam));
4391 break;
4392
4393 /* Simulate middle mouse button events when left and right buttons
4394 are used together, but only if user has two button mouse. */
4395 case WM_LBUTTONDOWN:
4396 case WM_RBUTTONDOWN:
4397 if (XINT (Vw32_num_mouse_buttons) > 2)
4398 goto handle_plain_button;
4399
4400 {
4401 int this = (msg == WM_LBUTTONDOWN) ? LMOUSE : RMOUSE;
4402 int other = (msg == WM_LBUTTONDOWN) ? RMOUSE : LMOUSE;
4403
4404 if (button_state & this)
4405 return 0;
4406
4407 if (button_state == 0)
4408 SetCapture (hwnd);
4409
4410 button_state |= this;
4411
4412 if (button_state & other)
4413 {
4414 if (mouse_button_timer)
4415 {
4416 KillTimer (hwnd, mouse_button_timer);
4417 mouse_button_timer = 0;
4418
4419 /* Generate middle mouse event instead. */
4420 msg = WM_MBUTTONDOWN;
4421 button_state |= MMOUSE;
4422 }
4423 else if (button_state & MMOUSE)
4424 {
4425 /* Ignore button event if we've already generated a
4426 middle mouse down event. This happens if the
4427 user releases and press one of the two buttons
4428 after we've faked a middle mouse event. */
4429 return 0;
4430 }
4431 else
4432 {
4433 /* Flush out saved message. */
4434 post_msg (&saved_mouse_button_msg);
4435 }
4436 wmsg.dwModifiers = w32_get_modifiers ();
4437 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4438
4439 /* Clear message buffer. */
4440 saved_mouse_button_msg.msg.hwnd = 0;
4441 }
4442 else
4443 {
4444 /* Hold onto message for now. */
4445 mouse_button_timer =
4446 SetTimer (hwnd, MOUSE_BUTTON_ID,
4447 XINT (Vw32_mouse_button_tolerance), NULL);
4448 saved_mouse_button_msg.msg.hwnd = hwnd;
4449 saved_mouse_button_msg.msg.message = msg;
4450 saved_mouse_button_msg.msg.wParam = wParam;
4451 saved_mouse_button_msg.msg.lParam = lParam;
4452 saved_mouse_button_msg.msg.time = GetMessageTime ();
4453 saved_mouse_button_msg.dwModifiers = w32_get_modifiers ();
4454 }
4455 }
4456 return 0;
4457
4458 case WM_LBUTTONUP:
4459 case WM_RBUTTONUP:
4460 if (XINT (Vw32_num_mouse_buttons) > 2)
4461 goto handle_plain_button;
4462
4463 {
4464 int this = (msg == WM_LBUTTONUP) ? LMOUSE : RMOUSE;
4465 int other = (msg == WM_LBUTTONUP) ? RMOUSE : LMOUSE;
4466
4467 if ((button_state & this) == 0)
4468 return 0;
4469
4470 button_state &= ~this;
4471
4472 if (button_state & MMOUSE)
4473 {
4474 /* Only generate event when second button is released. */
4475 if ((button_state & other) == 0)
4476 {
4477 msg = WM_MBUTTONUP;
4478 button_state &= ~MMOUSE;
4479
4480 if (button_state) abort ();
4481 }
4482 else
4483 return 0;
4484 }
4485 else
4486 {
4487 /* Flush out saved message if necessary. */
4488 if (saved_mouse_button_msg.msg.hwnd)
4489 {
4490 post_msg (&saved_mouse_button_msg);
4491 }
4492 }
4493 wmsg.dwModifiers = w32_get_modifiers ();
4494 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4495
4496 /* Always clear message buffer and cancel timer. */
4497 saved_mouse_button_msg.msg.hwnd = 0;
4498 KillTimer (hwnd, mouse_button_timer);
4499 mouse_button_timer = 0;
4500
4501 if (button_state == 0)
4502 ReleaseCapture ();
4503 }
4504 return 0;
4505
4506 case WM_MBUTTONDOWN:
4507 case WM_MBUTTONUP:
4508 handle_plain_button:
4509 {
4510 BOOL up;
4511 int button;
4512
4513 if (parse_button (msg, &button, &up))
4514 {
4515 if (up) ReleaseCapture ();
4516 else SetCapture (hwnd);
4517 button = (button == 0) ? LMOUSE :
4518 ((button == 1) ? MMOUSE : RMOUSE);
4519 if (up)
4520 button_state &= ~button;
4521 else
4522 button_state |= button;
4523 }
4524 }
4525
4526 wmsg.dwModifiers = w32_get_modifiers ();
4527 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4528 return 0;
4529
4530 case WM_VSCROLL:
4531 case WM_MOUSEMOVE:
4532 if (XINT (Vw32_mouse_move_interval) <= 0
4533 || (msg == WM_MOUSEMOVE && button_state == 0))
4534 {
4535 wmsg.dwModifiers = w32_get_modifiers ();
4536 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4537 return 0;
4538 }
4539
4540 /* Hang onto mouse move and scroll messages for a bit, to avoid
4541 sending such events to Emacs faster than it can process them.
4542 If we get more events before the timer from the first message
4543 expires, we just replace the first message. */
4544
4545 if (saved_mouse_move_msg.msg.hwnd == 0)
4546 mouse_move_timer =
4547 SetTimer (hwnd, MOUSE_MOVE_ID,
4548 XINT (Vw32_mouse_move_interval), NULL);
4549
4550 /* Hold onto message for now. */
4551 saved_mouse_move_msg.msg.hwnd = hwnd;
4552 saved_mouse_move_msg.msg.message = msg;
4553 saved_mouse_move_msg.msg.wParam = wParam;
4554 saved_mouse_move_msg.msg.lParam = lParam;
4555 saved_mouse_move_msg.msg.time = GetMessageTime ();
4556 saved_mouse_move_msg.dwModifiers = w32_get_modifiers ();
4557
4558 return 0;
4559
4560 case WM_MOUSEWHEEL:
4561 wmsg.dwModifiers = w32_get_modifiers ();
4562 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4563 return 0;
4564
4565 case WM_DROPFILES:
4566 wmsg.dwModifiers = w32_get_modifiers ();
4567 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4568 return 0;
4569
4570 case WM_TIMER:
4571 /* Flush out saved messages if necessary. */
4572 if (wParam == mouse_button_timer)
4573 {
4574 if (saved_mouse_button_msg.msg.hwnd)
4575 {
4576 post_msg (&saved_mouse_button_msg);
4577 saved_mouse_button_msg.msg.hwnd = 0;
4578 }
4579 KillTimer (hwnd, mouse_button_timer);
4580 mouse_button_timer = 0;
4581 }
4582 else if (wParam == mouse_move_timer)
4583 {
4584 if (saved_mouse_move_msg.msg.hwnd)
4585 {
4586 post_msg (&saved_mouse_move_msg);
4587 saved_mouse_move_msg.msg.hwnd = 0;
4588 }
4589 KillTimer (hwnd, mouse_move_timer);
4590 mouse_move_timer = 0;
4591 }
4592 return 0;
4593
4594 case WM_NCACTIVATE:
4595 /* Windows doesn't send us focus messages when putting up and
4596 taking down a system popup dialog as for Ctrl-Alt-Del on Windows 95.
4597 The only indication we get that something happened is receiving
4598 this message afterwards. So this is a good time to reset our
4599 keyboard modifiers' state. */
4600 reset_modifiers ();
4601 goto dflt;
4602
4603 case WM_INITMENU:
4604 button_state = 0;
4605 ReleaseCapture ();
4606 /* We must ensure menu bar is fully constructed and up to date
4607 before allowing user interaction with it. To achieve this
4608 we send this message to the lisp thread and wait for a
4609 reply (whose value is not actually needed) to indicate that
4610 the menu bar is now ready for use, so we can now return.
4611
4612 To remain responsive in the meantime, we enter a nested message
4613 loop that can process all other messages.
4614
4615 However, we skip all this if the message results from calling
4616 TrackPopupMenu - in fact, we must NOT attempt to send the lisp
4617 thread a message because it is blocked on us at this point. We
4618 set menubar_active before calling TrackPopupMenu to indicate
4619 this (there is no possibility of confusion with real menubar
4620 being active). */
4621
4622 f = x_window_to_frame (dpyinfo, hwnd);
4623 if (f
4624 && (f->output_data.w32->menubar_active
4625 /* We can receive this message even in the absence of a
4626 menubar (ie. when the system menu is activated) - in this
4627 case we do NOT want to forward the message, otherwise it
4628 will cause the menubar to suddenly appear when the user
4629 had requested it to be turned off! */
4630 || f->output_data.w32->menubar_widget == NULL))
4631 return 0;
4632
4633 {
4634 deferred_msg msg_buf;
4635
4636 /* Detect if message has already been deferred; in this case
4637 we cannot return any sensible value to ignore this. */
4638 if (find_deferred_msg (hwnd, msg) != NULL)
4639 abort ();
4640
4641 return send_deferred_msg (&msg_buf, hwnd, msg, wParam, lParam);
4642 }
4643
4644 case WM_EXITMENULOOP:
4645 f = x_window_to_frame (dpyinfo, hwnd);
4646
4647 /* Indicate that menubar can be modified again. */
4648 if (f)
4649 f->output_data.w32->menubar_active = 0;
4650 goto dflt;
4651
4652 case WM_MENUSELECT:
4653 wmsg.dwModifiers = w32_get_modifiers ();
4654 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4655 return 0;
4656
4657 case WM_MEASUREITEM:
4658 f = x_window_to_frame (dpyinfo, hwnd);
4659 if (f)
4660 {
4661 MEASUREITEMSTRUCT * pMis = (MEASUREITEMSTRUCT *) lParam;
4662
4663 if (pMis->CtlType == ODT_MENU)
4664 {
4665 /* Work out dimensions for popup menu titles. */
4666 char * title = (char *) pMis->itemData;
4667 HDC hdc = GetDC (hwnd);
4668 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4669 LOGFONT menu_logfont;
4670 HFONT old_font;
4671 SIZE size;
4672
4673 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4674 menu_logfont.lfWeight = FW_BOLD;
4675 menu_font = CreateFontIndirect (&menu_logfont);
4676 old_font = SelectObject (hdc, menu_font);
4677
4678 pMis->itemHeight = GetSystemMetrics (SM_CYMENUSIZE);
4679 if (title)
4680 {
4681 GetTextExtentPoint32 (hdc, title, strlen (title), &size);
4682 pMis->itemWidth = size.cx;
4683 if (pMis->itemHeight < size.cy)
4684 pMis->itemHeight = size.cy;
4685 }
4686 else
4687 pMis->itemWidth = 0;
4688
4689 SelectObject (hdc, old_font);
4690 DeleteObject (menu_font);
4691 ReleaseDC (hwnd, hdc);
4692 return TRUE;
4693 }
4694 }
4695 return 0;
4696
4697 case WM_DRAWITEM:
4698 f = x_window_to_frame (dpyinfo, hwnd);
4699 if (f)
4700 {
4701 DRAWITEMSTRUCT * pDis = (DRAWITEMSTRUCT *) lParam;
4702
4703 if (pDis->CtlType == ODT_MENU)
4704 {
4705 /* Draw popup menu title. */
4706 char * title = (char *) pDis->itemData;
4707 if (title)
4708 {
4709 HDC hdc = pDis->hDC;
4710 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4711 LOGFONT menu_logfont;
4712 HFONT old_font;
4713
4714 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4715 menu_logfont.lfWeight = FW_BOLD;
4716 menu_font = CreateFontIndirect (&menu_logfont);
4717 old_font = SelectObject (hdc, menu_font);
4718
4719 /* Always draw title as if not selected. */
4720 ExtTextOut (hdc,
4721 pDis->rcItem.left
4722 + GetSystemMetrics (SM_CXMENUCHECK),
4723 pDis->rcItem.top,
4724 ETO_OPAQUE, &pDis->rcItem,
4725 title, strlen (title), NULL);
4726
4727 SelectObject (hdc, old_font);
4728 DeleteObject (menu_font);
4729 }
4730 return TRUE;
4731 }
4732 }
4733 return 0;
4734
4735 #if 0
4736 /* Still not right - can't distinguish between clicks in the
4737 client area of the frame from clicks forwarded from the scroll
4738 bars - may have to hook WM_NCHITTEST to remember the mouse
4739 position and then check if it is in the client area ourselves. */
4740 case WM_MOUSEACTIVATE:
4741 /* Discard the mouse click that activates a frame, allowing the
4742 user to click anywhere without changing point (or worse!).
4743 Don't eat mouse clicks on scrollbars though!! */
4744 if (LOWORD (lParam) == HTCLIENT )
4745 return MA_ACTIVATEANDEAT;
4746 goto dflt;
4747 #endif
4748
4749 case WM_ACTIVATEAPP:
4750 case WM_ACTIVATE:
4751 case WM_WINDOWPOSCHANGED:
4752 case WM_SHOWWINDOW:
4753 /* Inform lisp thread that a frame might have just been obscured
4754 or exposed, so should recheck visibility of all frames. */
4755 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4756 goto dflt;
4757
4758 case WM_SETFOCUS:
4759 dpyinfo->faked_key = 0;
4760 reset_modifiers ();
4761 register_hot_keys (hwnd);
4762 goto command;
4763 case WM_KILLFOCUS:
4764 unregister_hot_keys (hwnd);
4765 button_state = 0;
4766 ReleaseCapture ();
4767 case WM_MOVE:
4768 case WM_SIZE:
4769 case WM_COMMAND:
4770 command:
4771 wmsg.dwModifiers = w32_get_modifiers ();
4772 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4773 goto dflt;
4774
4775 case WM_CLOSE:
4776 wmsg.dwModifiers = w32_get_modifiers ();
4777 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4778 return 0;
4779
4780 case WM_WINDOWPOSCHANGING:
4781 {
4782 WINDOWPLACEMENT wp;
4783 LPWINDOWPOS lppos = (WINDOWPOS *) lParam;
4784
4785 wp.length = sizeof (WINDOWPLACEMENT);
4786 GetWindowPlacement (hwnd, &wp);
4787
4788 if (wp.showCmd != SW_SHOWMINIMIZED && (lppos->flags & SWP_NOSIZE) == 0)
4789 {
4790 RECT rect;
4791 int wdiff;
4792 int hdiff;
4793 DWORD font_width;
4794 DWORD line_height;
4795 DWORD internal_border;
4796 DWORD scrollbar_extra;
4797 RECT wr;
4798
4799 wp.length = sizeof(wp);
4800 GetWindowRect (hwnd, &wr);
4801
4802 enter_crit ();
4803
4804 font_width = GetWindowLong (hwnd, WND_FONTWIDTH_INDEX);
4805 line_height = GetWindowLong (hwnd, WND_LINEHEIGHT_INDEX);
4806 internal_border = GetWindowLong (hwnd, WND_BORDER_INDEX);
4807 scrollbar_extra = GetWindowLong (hwnd, WND_SCROLLBAR_INDEX);
4808
4809 leave_crit ();
4810
4811 memset (&rect, 0, sizeof (rect));
4812 AdjustWindowRect (&rect, GetWindowLong (hwnd, GWL_STYLE),
4813 GetMenu (hwnd) != NULL);
4814
4815 /* Force width and height of client area to be exact
4816 multiples of the character cell dimensions. */
4817 wdiff = (lppos->cx - (rect.right - rect.left)
4818 - 2 * internal_border - scrollbar_extra)
4819 % font_width;
4820 hdiff = (lppos->cy - (rect.bottom - rect.top)
4821 - 2 * internal_border)
4822 % line_height;
4823
4824 if (wdiff || hdiff)
4825 {
4826 /* For right/bottom sizing we can just fix the sizes.
4827 However for top/left sizing we will need to fix the X
4828 and Y positions as well. */
4829
4830 lppos->cx -= wdiff;
4831 lppos->cy -= hdiff;
4832
4833 if (wp.showCmd != SW_SHOWMAXIMIZED
4834 && (lppos->flags & SWP_NOMOVE) == 0)
4835 {
4836 if (lppos->x != wr.left || lppos->y != wr.top)
4837 {
4838 lppos->x += wdiff;
4839 lppos->y += hdiff;
4840 }
4841 else
4842 {
4843 lppos->flags |= SWP_NOMOVE;
4844 }
4845 }
4846
4847 return 0;
4848 }
4849 }
4850 }
4851
4852 goto dflt;
4853
4854 case WM_GETMINMAXINFO:
4855 /* Hack to correct bug that allows Emacs frames to be resized
4856 below the Minimum Tracking Size. */
4857 ((LPMINMAXINFO) lParam)->ptMinTrackSize.y++;
4858 /* Hack to allow resizing the Emacs frame above the screen size.
4859 Note that Windows 9x limits coordinates to 16-bits. */
4860 ((LPMINMAXINFO) lParam)->ptMaxTrackSize.x = 32767;
4861 ((LPMINMAXINFO) lParam)->ptMaxTrackSize.y = 32767;
4862 return 0;
4863
4864 case WM_EMACS_CREATESCROLLBAR:
4865 return (LRESULT) w32_createscrollbar ((struct frame *) wParam,
4866 (struct scroll_bar *) lParam);
4867
4868 case WM_EMACS_SHOWWINDOW:
4869 return ShowWindow ((HWND) wParam, (WPARAM) lParam);
4870
4871 case WM_EMACS_SETFOREGROUND:
4872 {
4873 HWND foreground_window;
4874 DWORD foreground_thread, retval;
4875
4876 /* On NT 5.0, and apparently Windows 98, it is necessary to
4877 attach to the thread that currently has focus in order to
4878 pull the focus away from it. */
4879 foreground_window = GetForegroundWindow ();
4880 foreground_thread = GetWindowThreadProcessId (foreground_window, NULL);
4881 if (!foreground_window
4882 || foreground_thread == GetCurrentThreadId ()
4883 || !AttachThreadInput (GetCurrentThreadId (),
4884 foreground_thread, TRUE))
4885 foreground_thread = 0;
4886
4887 retval = SetForegroundWindow ((HWND) wParam);
4888
4889 /* Detach from the previous foreground thread. */
4890 if (foreground_thread)
4891 AttachThreadInput (GetCurrentThreadId (),
4892 foreground_thread, FALSE);
4893
4894 return retval;
4895 }
4896
4897 case WM_EMACS_SETWINDOWPOS:
4898 {
4899 WINDOWPOS * pos = (WINDOWPOS *) wParam;
4900 return SetWindowPos (hwnd, pos->hwndInsertAfter,
4901 pos->x, pos->y, pos->cx, pos->cy, pos->flags);
4902 }
4903
4904 case WM_EMACS_DESTROYWINDOW:
4905 DragAcceptFiles ((HWND) wParam, FALSE);
4906 return DestroyWindow ((HWND) wParam);
4907
4908 case WM_EMACS_TRACKPOPUPMENU:
4909 {
4910 UINT flags;
4911 POINT *pos;
4912 int retval;
4913 pos = (POINT *)lParam;
4914 flags = TPM_CENTERALIGN;
4915 if (button_state & LMOUSE)
4916 flags |= TPM_LEFTBUTTON;
4917 else if (button_state & RMOUSE)
4918 flags |= TPM_RIGHTBUTTON;
4919
4920 /* Remember we did a SetCapture on the initial mouse down event,
4921 so for safety, we make sure the capture is cancelled now. */
4922 ReleaseCapture ();
4923 button_state = 0;
4924
4925 /* Use menubar_active to indicate that WM_INITMENU is from
4926 TrackPopupMenu below, and should be ignored. */
4927 f = x_window_to_frame (dpyinfo, hwnd);
4928 if (f)
4929 f->output_data.w32->menubar_active = 1;
4930
4931 if (TrackPopupMenu ((HMENU)wParam, flags, pos->x, pos->y,
4932 0, hwnd, NULL))
4933 {
4934 MSG amsg;
4935 /* Eat any mouse messages during popupmenu */
4936 while (PeekMessage (&amsg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST,
4937 PM_REMOVE));
4938 /* Get the menu selection, if any */
4939 if (PeekMessage (&amsg, hwnd, WM_COMMAND, WM_COMMAND, PM_REMOVE))
4940 {
4941 retval = LOWORD (amsg.wParam);
4942 }
4943 else
4944 {
4945 retval = 0;
4946 }
4947 }
4948 else
4949 {
4950 retval = -1;
4951 }
4952
4953 return retval;
4954 }
4955
4956 default:
4957 /* Check for messages registered at runtime. */
4958 if (msg == msh_mousewheel)
4959 {
4960 wmsg.dwModifiers = w32_get_modifiers ();
4961 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4962 return 0;
4963 }
4964
4965 dflt:
4966 return DefWindowProc (hwnd, msg, wParam, lParam);
4967 }
4968
4969
4970 /* The most common default return code for handled messages is 0. */
4971 return 0;
4972 }
4973
4974 void
4975 my_create_window (f)
4976 struct frame * f;
4977 {
4978 MSG msg;
4979
4980 if (!PostThreadMessage (dwWindowsThreadId, WM_EMACS_CREATEWINDOW, (WPARAM)f, 0))
4981 abort ();
4982 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
4983 }
4984
4985 /* Create and set up the w32 window for frame F. */
4986
4987 static void
4988 w32_window (f, window_prompting, minibuffer_only)
4989 struct frame *f;
4990 long window_prompting;
4991 int minibuffer_only;
4992 {
4993 BLOCK_INPUT;
4994
4995 /* Use the resource name as the top-level window name
4996 for looking up resources. Make a non-Lisp copy
4997 for the window manager, so GC relocation won't bother it.
4998
4999 Elsewhere we specify the window name for the window manager. */
5000
5001 {
5002 char *str = (char *) XSTRING (Vx_resource_name)->data;
5003 f->namebuf = (char *) xmalloc (strlen (str) + 1);
5004 strcpy (f->namebuf, str);
5005 }
5006
5007 my_create_window (f);
5008
5009 validate_x_resource_name ();
5010
5011 /* x_set_name normally ignores requests to set the name if the
5012 requested name is the same as the current name. This is the one
5013 place where that assumption isn't correct; f->name is set, but
5014 the server hasn't been told. */
5015 {
5016 Lisp_Object name;
5017 int explicit = f->explicit_name;
5018
5019 f->explicit_name = 0;
5020 name = f->name;
5021 f->name = Qnil;
5022 x_set_name (f, name, explicit);
5023 }
5024
5025 UNBLOCK_INPUT;
5026
5027 if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f))
5028 initialize_frame_menubar (f);
5029
5030 if (FRAME_W32_WINDOW (f) == 0)
5031 error ("Unable to create window");
5032 }
5033
5034 /* Handle the icon stuff for this window. Perhaps later we might
5035 want an x_set_icon_position which can be called interactively as
5036 well. */
5037
5038 static void
5039 x_icon (f, parms)
5040 struct frame *f;
5041 Lisp_Object parms;
5042 {
5043 Lisp_Object icon_x, icon_y;
5044
5045 /* Set the position of the icon. Note that Windows 95 groups all
5046 icons in the tray. */
5047 icon_x = w32_get_arg (parms, Qicon_left, 0, 0, RES_TYPE_NUMBER);
5048 icon_y = w32_get_arg (parms, Qicon_top, 0, 0, RES_TYPE_NUMBER);
5049 if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
5050 {
5051 CHECK_NUMBER (icon_x, 0);
5052 CHECK_NUMBER (icon_y, 0);
5053 }
5054 else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
5055 error ("Both left and top icon corners of icon must be specified");
5056
5057 BLOCK_INPUT;
5058
5059 if (! EQ (icon_x, Qunbound))
5060 x_wm_set_icon_position (f, XINT (icon_x), XINT (icon_y));
5061
5062 #if 0 /* TODO */
5063 /* Start up iconic or window? */
5064 x_wm_set_window_state
5065 (f, (EQ (w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL), Qicon)
5066 ? IconicState
5067 : NormalState));
5068
5069 x_text_icon (f, (char *) XSTRING ((!NILP (f->icon_name)
5070 ? f->icon_name
5071 : f->name))->data);
5072 #endif
5073
5074 UNBLOCK_INPUT;
5075 }
5076
5077
5078 static void
5079 x_make_gc (f)
5080 struct frame *f;
5081 {
5082 XGCValues gc_values;
5083
5084 BLOCK_INPUT;
5085
5086 /* Create the GC's of this frame.
5087 Note that many default values are used. */
5088
5089 /* Normal video */
5090 gc_values.font = f->output_data.w32->font;
5091
5092 /* Cursor has cursor-color background, background-color foreground. */
5093 gc_values.foreground = FRAME_BACKGROUND_PIXEL (f);
5094 gc_values.background = f->output_data.w32->cursor_pixel;
5095 f->output_data.w32->cursor_gc
5096 = XCreateGC (NULL, FRAME_W32_WINDOW (f),
5097 (GCFont | GCForeground | GCBackground),
5098 &gc_values);
5099
5100 /* Reliefs. */
5101 f->output_data.w32->white_relief.gc = 0;
5102 f->output_data.w32->black_relief.gc = 0;
5103
5104 UNBLOCK_INPUT;
5105 }
5106
5107
5108 /* Handler for signals raised during x_create_frame and
5109 x_create_top_frame. FRAME is the frame which is partially
5110 constructed. */
5111
5112 static Lisp_Object
5113 unwind_create_frame (frame)
5114 Lisp_Object frame;
5115 {
5116 struct frame *f = XFRAME (frame);
5117
5118 /* If frame is ``official'', nothing to do. */
5119 if (!CONSP (Vframe_list) || !EQ (XCAR (Vframe_list), frame))
5120 {
5121 #ifdef GLYPH_DEBUG
5122 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
5123 #endif
5124
5125 x_free_frame_resources (f);
5126
5127 /* Check that reference counts are indeed correct. */
5128 xassert (dpyinfo->reference_count == dpyinfo_refcount);
5129 xassert (dpyinfo->image_cache->refcount == image_cache_refcount);
5130
5131 return Qt;
5132 }
5133
5134 return Qnil;
5135 }
5136
5137
5138 DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
5139 1, 1, 0,
5140 "Make a new window, which is called a \"frame\" in Emacs terms.\n\
5141 Returns an Emacs frame object.\n\
5142 ALIST is an alist of frame parameters.\n\
5143 If the parameters specify that the frame should not have a minibuffer,\n\
5144 and do not specify a specific minibuffer window to use,\n\
5145 then `default-minibuffer-frame' must be a frame whose minibuffer can\n\
5146 be shared by the new frame.\n\
5147 \n\
5148 This function is an internal primitive--use `make-frame' instead.")
5149 (parms)
5150 Lisp_Object parms;
5151 {
5152 struct frame *f;
5153 Lisp_Object frame, tem;
5154 Lisp_Object name;
5155 int minibuffer_only = 0;
5156 long window_prompting = 0;
5157 int width, height;
5158 int count = BINDING_STACK_SIZE ();
5159 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
5160 Lisp_Object display;
5161 struct w32_display_info *dpyinfo = NULL;
5162 Lisp_Object parent;
5163 struct kboard *kb;
5164
5165 check_w32 ();
5166
5167 /* Use this general default value to start with
5168 until we know if this frame has a specified name. */
5169 Vx_resource_name = Vinvocation_name;
5170
5171 display = w32_get_arg (parms, Qdisplay, 0, 0, RES_TYPE_STRING);
5172 if (EQ (display, Qunbound))
5173 display = Qnil;
5174 dpyinfo = check_x_display_info (display);
5175 #ifdef MULTI_KBOARD
5176 kb = dpyinfo->kboard;
5177 #else
5178 kb = &the_only_kboard;
5179 #endif
5180
5181 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
5182 if (!STRINGP (name)
5183 && ! EQ (name, Qunbound)
5184 && ! NILP (name))
5185 error ("Invalid frame name--not a string or nil");
5186
5187 if (STRINGP (name))
5188 Vx_resource_name = name;
5189
5190 /* See if parent window is specified. */
5191 parent = w32_get_arg (parms, Qparent_id, NULL, NULL, RES_TYPE_NUMBER);
5192 if (EQ (parent, Qunbound))
5193 parent = Qnil;
5194 if (! NILP (parent))
5195 CHECK_NUMBER (parent, 0);
5196
5197 /* make_frame_without_minibuffer can run Lisp code and garbage collect. */
5198 /* No need to protect DISPLAY because that's not used after passing
5199 it to make_frame_without_minibuffer. */
5200 frame = Qnil;
5201 GCPRO4 (parms, parent, name, frame);
5202 tem = w32_get_arg (parms, Qminibuffer, "minibuffer", "Minibuffer",
5203 RES_TYPE_SYMBOL);
5204 if (EQ (tem, Qnone) || NILP (tem))
5205 f = make_frame_without_minibuffer (Qnil, kb, display);
5206 else if (EQ (tem, Qonly))
5207 {
5208 f = make_minibuffer_frame ();
5209 minibuffer_only = 1;
5210 }
5211 else if (WINDOWP (tem))
5212 f = make_frame_without_minibuffer (tem, kb, display);
5213 else
5214 f = make_frame (1);
5215
5216 XSETFRAME (frame, f);
5217
5218 /* Note that Windows does support scroll bars. */
5219 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
5220 /* By default, make scrollbars the system standard width. */
5221 f->scroll_bar_pixel_width = GetSystemMetrics (SM_CXVSCROLL);
5222
5223 f->output_method = output_w32;
5224 f->output_data.w32 =
5225 (struct w32_output *) xmalloc (sizeof (struct w32_output));
5226 bzero (f->output_data.w32, sizeof (struct w32_output));
5227 FRAME_FONTSET (f) = -1;
5228 record_unwind_protect (unwind_create_frame, frame);
5229
5230 f->icon_name
5231 = w32_get_arg (parms, Qicon_name, "iconName", "Title", RES_TYPE_STRING);
5232 if (! STRINGP (f->icon_name))
5233 f->icon_name = Qnil;
5234
5235 /* FRAME_W32_DISPLAY_INFO (f) = dpyinfo; */
5236 #ifdef MULTI_KBOARD
5237 FRAME_KBOARD (f) = kb;
5238 #endif
5239
5240 /* Specify the parent under which to make this window. */
5241
5242 if (!NILP (parent))
5243 {
5244 f->output_data.w32->parent_desc = (Window) XFASTINT (parent);
5245 f->output_data.w32->explicit_parent = 1;
5246 }
5247 else
5248 {
5249 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
5250 f->output_data.w32->explicit_parent = 0;
5251 }
5252
5253 /* Set the name; the functions to which we pass f expect the name to
5254 be set. */
5255 if (EQ (name, Qunbound) || NILP (name))
5256 {
5257 f->name = build_string (dpyinfo->w32_id_name);
5258 f->explicit_name = 0;
5259 }
5260 else
5261 {
5262 f->name = name;
5263 f->explicit_name = 1;
5264 /* use the frame's title when getting resources for this frame. */
5265 specbind (Qx_resource_name, name);
5266 }
5267
5268 /* Extract the window parameters from the supplied values
5269 that are needed to determine window geometry. */
5270 {
5271 Lisp_Object font;
5272
5273 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
5274
5275 BLOCK_INPUT;
5276 /* First, try whatever font the caller has specified. */
5277 if (STRINGP (font))
5278 {
5279 tem = Fquery_fontset (font, Qnil);
5280 if (STRINGP (tem))
5281 font = x_new_fontset (f, XSTRING (tem)->data);
5282 else
5283 font = x_new_font (f, XSTRING (font)->data);
5284 }
5285 /* Try out a font which we hope has bold and italic variations. */
5286 if (!STRINGP (font))
5287 font = x_new_font (f, "-*-Courier New-normal-r-*-*-*-100-*-*-c-*-iso8859-1");
5288 if (! STRINGP (font))
5289 font = x_new_font (f, "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
5290 /* If those didn't work, look for something which will at least work. */
5291 if (! STRINGP (font))
5292 font = x_new_font (f, "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1");
5293 UNBLOCK_INPUT;
5294 if (! STRINGP (font))
5295 font = build_string ("Fixedsys");
5296
5297 x_default_parameter (f, parms, Qfont, font,
5298 "font", "Font", RES_TYPE_STRING);
5299 }
5300
5301 x_default_parameter (f, parms, Qborder_width, make_number (2),
5302 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
5303 /* This defaults to 2 in order to match xterm. We recognize either
5304 internalBorderWidth or internalBorder (which is what xterm calls
5305 it). */
5306 if (NILP (Fassq (Qinternal_border_width, parms)))
5307 {
5308 Lisp_Object value;
5309
5310 value = w32_get_arg (parms, Qinternal_border_width,
5311 "internalBorder", "InternalBorder", RES_TYPE_NUMBER);
5312 if (! EQ (value, Qunbound))
5313 parms = Fcons (Fcons (Qinternal_border_width, value),
5314 parms);
5315 }
5316 /* Default internalBorderWidth to 0 on Windows to match other programs. */
5317 x_default_parameter (f, parms, Qinternal_border_width, make_number (0),
5318 "internalBorderWidth", "InternalBorder", RES_TYPE_NUMBER);
5319 x_default_parameter (f, parms, Qvertical_scroll_bars, Qright,
5320 "verticalScrollBars", "ScrollBars", RES_TYPE_SYMBOL);
5321
5322 /* Also do the stuff which must be set before the window exists. */
5323 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
5324 "foreground", "Foreground", RES_TYPE_STRING);
5325 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
5326 "background", "Background", RES_TYPE_STRING);
5327 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
5328 "pointerColor", "Foreground", RES_TYPE_STRING);
5329 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
5330 "cursorColor", "Foreground", RES_TYPE_STRING);
5331 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
5332 "borderColor", "BorderColor", RES_TYPE_STRING);
5333 x_default_parameter (f, parms, Qscreen_gamma, Qnil,
5334 "screenGamma", "ScreenGamma", RES_TYPE_FLOAT);
5335 x_default_parameter (f, parms, Qline_spacing, Qnil,
5336 "lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
5337
5338
5339 /* Init faces before x_default_parameter is called for scroll-bar
5340 parameters because that function calls x_set_scroll_bar_width,
5341 which calls change_frame_size, which calls Fset_window_buffer,
5342 which runs hooks, which call Fvertical_motion. At the end, we
5343 end up in init_iterator with a null face cache, which should not
5344 happen. */
5345 init_frame_faces (f);
5346
5347 x_default_parameter (f, parms, Qmenu_bar_lines, make_number (1),
5348 "menuBar", "MenuBar", RES_TYPE_NUMBER);
5349 x_default_parameter (f, parms, Qtool_bar_lines, make_number (0),
5350 "toolBar", "ToolBar", RES_TYPE_NUMBER);
5351 x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
5352 "bufferPredicate", "BufferPredicate", RES_TYPE_SYMBOL);
5353 x_default_parameter (f, parms, Qtitle, Qnil,
5354 "title", "Title", RES_TYPE_STRING);
5355
5356 f->output_data.w32->dwStyle = WS_OVERLAPPEDWINDOW;
5357 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
5358 window_prompting = x_figure_window_size (f, parms);
5359
5360 if (window_prompting & XNegative)
5361 {
5362 if (window_prompting & YNegative)
5363 f->output_data.w32->win_gravity = SouthEastGravity;
5364 else
5365 f->output_data.w32->win_gravity = NorthEastGravity;
5366 }
5367 else
5368 {
5369 if (window_prompting & YNegative)
5370 f->output_data.w32->win_gravity = SouthWestGravity;
5371 else
5372 f->output_data.w32->win_gravity = NorthWestGravity;
5373 }
5374
5375 f->output_data.w32->size_hint_flags = window_prompting;
5376
5377 tem = w32_get_arg (parms, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN);
5378 f->no_split = minibuffer_only || EQ (tem, Qt);
5379
5380 w32_window (f, window_prompting, minibuffer_only);
5381 x_icon (f, parms);
5382
5383 x_make_gc (f);
5384
5385 /* Now consider the frame official. */
5386 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
5387 Vframe_list = Fcons (frame, Vframe_list);
5388
5389 /* We need to do this after creating the window, so that the
5390 icon-creation functions can say whose icon they're describing. */
5391 x_default_parameter (f, parms, Qicon_type, Qnil,
5392 "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL);
5393
5394 x_default_parameter (f, parms, Qauto_raise, Qnil,
5395 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
5396 x_default_parameter (f, parms, Qauto_lower, Qnil,
5397 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
5398 x_default_parameter (f, parms, Qcursor_type, Qbox,
5399 "cursorType", "CursorType", RES_TYPE_SYMBOL);
5400 x_default_parameter (f, parms, Qscroll_bar_width, Qnil,
5401 "scrollBarWidth", "ScrollBarWidth", RES_TYPE_NUMBER);
5402
5403 /* Dimensions, especially f->height, must be done via change_frame_size.
5404 Change will not be effected unless different from the current
5405 f->height. */
5406 width = f->width;
5407 height = f->height;
5408
5409 /* Add the tool-bar height to the initial frame height so that the
5410 user gets a text display area of the size he specified with -g or
5411 via .Xdefaults. Later changes of the tool-bar height don't
5412 change the frame size. This is done so that users can create
5413 tall Emacs frames without having to guess how tall the tool-bar
5414 will get. */
5415 if (FRAME_TOOL_BAR_LINES (f))
5416 {
5417 int margin, relief, bar_height;
5418
5419 relief = (tool_bar_button_relief > 0
5420 ? tool_bar_button_relief
5421 : DEFAULT_TOOL_BAR_BUTTON_RELIEF);
5422
5423 if (INTEGERP (Vtool_bar_button_margin)
5424 && XINT (Vtool_bar_button_margin) > 0)
5425 margin = XFASTINT (Vtool_bar_button_margin);
5426 else if (CONSP (Vtool_bar_button_margin)
5427 && INTEGERP (XCDR (Vtool_bar_button_margin))
5428 && XINT (XCDR (Vtool_bar_button_margin)) > 0)
5429 margin = XFASTINT (XCDR (Vtool_bar_button_margin));
5430 else
5431 margin = 0;
5432
5433 bar_height = DEFAULT_TOOL_BAR_IMAGE_HEIGHT + 2 * margin + 2 * relief;
5434 height += (bar_height + CANON_Y_UNIT (f) - 1) / CANON_Y_UNIT (f);
5435 }
5436
5437 f->height = 0;
5438 SET_FRAME_WIDTH (f, 0);
5439 change_frame_size (f, height, width, 1, 0, 0);
5440
5441 /* Tell the server what size and position, etc, we want, and how
5442 badly we want them. This should be done after we have the menu
5443 bar so that its size can be taken into account. */
5444 BLOCK_INPUT;
5445 x_wm_set_size_hint (f, window_prompting, 0);
5446 UNBLOCK_INPUT;
5447
5448 /* Set up faces after all frame parameters are known. This call
5449 also merges in face attributes specified for new frames. If we
5450 don't do this, the `menu' face for instance won't have the right
5451 colors, and the menu bar won't appear in the specified colors for
5452 new frames. */
5453 call1 (Qface_set_after_frame_default, frame);
5454
5455 /* Make the window appear on the frame and enable display, unless
5456 the caller says not to. However, with explicit parent, Emacs
5457 cannot control visibility, so don't try. */
5458 if (! f->output_data.w32->explicit_parent)
5459 {
5460 Lisp_Object visibility;
5461
5462 visibility = w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL);
5463 if (EQ (visibility, Qunbound))
5464 visibility = Qt;
5465
5466 if (EQ (visibility, Qicon))
5467 x_iconify_frame (f);
5468 else if (! NILP (visibility))
5469 x_make_frame_visible (f);
5470 else
5471 /* Must have been Qnil. */
5472 ;
5473 }
5474 UNGCPRO;
5475
5476 /* Make sure windows on this frame appear in calls to next-window
5477 and similar functions. */
5478 Vwindow_list = Qnil;
5479
5480 return unbind_to (count, frame);
5481 }
5482
5483 /* FRAME is used only to get a handle on the X display. We don't pass the
5484 display info directly because we're called from frame.c, which doesn't
5485 know about that structure. */
5486 Lisp_Object
5487 x_get_focus_frame (frame)
5488 struct frame *frame;
5489 {
5490 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (frame);
5491 Lisp_Object xfocus;
5492 if (! dpyinfo->w32_focus_frame)
5493 return Qnil;
5494
5495 XSETFRAME (xfocus, dpyinfo->w32_focus_frame);
5496 return xfocus;
5497 }
5498
5499 DEFUN ("w32-focus-frame", Fw32_focus_frame, Sw32_focus_frame, 1, 1, 0,
5500 "Give FRAME input focus, raising to foreground if necessary.")
5501 (frame)
5502 Lisp_Object frame;
5503 {
5504 x_focus_on_frame (check_x_frame (frame));
5505 return Qnil;
5506 }
5507
5508 \f
5509 /* Return the charset portion of a font name. */
5510 char * xlfd_charset_of_font (char * fontname)
5511 {
5512 char *charset, *encoding;
5513
5514 encoding = strrchr(fontname, '-');
5515 if (!encoding || encoding == fontname)
5516 return NULL;
5517
5518 for (charset = encoding - 1; charset >= fontname; charset--)
5519 if (*charset == '-')
5520 break;
5521
5522 if (charset == fontname || strcmp(charset, "-*-*") == 0)
5523 return NULL;
5524
5525 return charset + 1;
5526 }
5527
5528 struct font_info *w32_load_bdf_font (struct frame *f, char *fontname,
5529 int size, char* filename);
5530 static Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names);
5531 static BOOL w32_to_x_font (LOGFONT * lplf, char * lpxstr, int len,
5532 char * charset);
5533 static BOOL x_to_w32_font (char *lpxstr, LOGFONT *lplogfont);
5534
5535 static struct font_info *
5536 w32_load_system_font (f,fontname,size)
5537 struct frame *f;
5538 char * fontname;
5539 int size;
5540 {
5541 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
5542 Lisp_Object font_names;
5543
5544 /* Get a list of all the fonts that match this name. Once we
5545 have a list of matching fonts, we compare them against the fonts
5546 we already have loaded by comparing names. */
5547 font_names = w32_list_fonts (f, build_string (fontname), size, 100);
5548
5549 if (!NILP (font_names))
5550 {
5551 Lisp_Object tail;
5552 int i;
5553
5554 /* First check if any are already loaded, as that is cheaper
5555 than loading another one. */
5556 for (i = 0; i < dpyinfo->n_fonts; i++)
5557 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
5558 if (dpyinfo->font_table[i].name
5559 && (!strcmp (dpyinfo->font_table[i].name,
5560 XSTRING (XCAR (tail))->data)
5561 || !strcmp (dpyinfo->font_table[i].full_name,
5562 XSTRING (XCAR (tail))->data)))
5563 return (dpyinfo->font_table + i);
5564
5565 fontname = (char *) XSTRING (XCAR (font_names))->data;
5566 }
5567 else if (w32_strict_fontnames)
5568 {
5569 /* If EnumFontFamiliesEx was available, we got a full list of
5570 fonts back so stop now to avoid the possibility of loading a
5571 random font. If we had to fall back to EnumFontFamilies, the
5572 list is incomplete, so continue whether the font we want was
5573 listed or not. */
5574 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
5575 FARPROC enum_font_families_ex
5576 = GetProcAddress (gdi32, "EnumFontFamiliesExA");
5577 if (enum_font_families_ex)
5578 return NULL;
5579 }
5580
5581 /* Load the font and add it to the table. */
5582 {
5583 char *full_name, *encoding, *charset;
5584 XFontStruct *font;
5585 struct font_info *fontp;
5586 LOGFONT lf;
5587 BOOL ok;
5588 int i;
5589
5590 if (!fontname || !x_to_w32_font (fontname, &lf))
5591 return (NULL);
5592
5593 if (!*lf.lfFaceName)
5594 /* If no name was specified for the font, we get a random font
5595 from CreateFontIndirect - this is not particularly
5596 desirable, especially since CreateFontIndirect does not
5597 fill out the missing name in lf, so we never know what we
5598 ended up with. */
5599 return NULL;
5600
5601 font = (XFontStruct *) xmalloc (sizeof (XFontStruct));
5602 bzero (font, sizeof (*font));
5603
5604 /* Set bdf to NULL to indicate that this is a Windows font. */
5605 font->bdf = NULL;
5606
5607 BLOCK_INPUT;
5608
5609 font->hfont = CreateFontIndirect (&lf);
5610
5611 if (font->hfont == NULL)
5612 {
5613 ok = FALSE;
5614 }
5615 else
5616 {
5617 HDC hdc;
5618 HANDLE oldobj;
5619 int codepage = w32_codepage_for_font (fontname);
5620
5621 hdc = GetDC (dpyinfo->root_window);
5622 oldobj = SelectObject (hdc, font->hfont);
5623
5624 ok = GetTextMetrics (hdc, &font->tm);
5625 if (codepage == CP_UNICODE)
5626 font->double_byte_p = 1;
5627 else
5628 font->double_byte_p = GetFontLanguageInfo(hdc) & GCP_DBCS;
5629
5630 SelectObject (hdc, oldobj);
5631 ReleaseDC (dpyinfo->root_window, hdc);
5632 /* Fill out details in lf according to the font that was
5633 actually loaded. */
5634 lf.lfHeight = font->tm.tmInternalLeading - font->tm.tmHeight;
5635 lf.lfWidth = font->tm.tmAveCharWidth;
5636 lf.lfWeight = font->tm.tmWeight;
5637 lf.lfItalic = font->tm.tmItalic;
5638 lf.lfCharSet = font->tm.tmCharSet;
5639 lf.lfPitchAndFamily = ((font->tm.tmPitchAndFamily & TMPF_FIXED_PITCH)
5640 ? VARIABLE_PITCH : FIXED_PITCH);
5641 lf.lfOutPrecision = ((font->tm.tmPitchAndFamily & TMPF_VECTOR)
5642 ? OUT_STROKE_PRECIS : OUT_STRING_PRECIS);
5643
5644 w32_cache_char_metrics (font);
5645 }
5646
5647 UNBLOCK_INPUT;
5648
5649 if (!ok)
5650 {
5651 w32_unload_font (dpyinfo, font);
5652 return (NULL);
5653 }
5654
5655 /* Find a free slot in the font table. */
5656 for (i = 0; i < dpyinfo->n_fonts; ++i)
5657 if (dpyinfo->font_table[i].name == NULL)
5658 break;
5659
5660 /* If no free slot found, maybe enlarge the font table. */
5661 if (i == dpyinfo->n_fonts
5662 && dpyinfo->n_fonts == dpyinfo->font_table_size)
5663 {
5664 int sz;
5665 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
5666 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
5667 dpyinfo->font_table
5668 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
5669 }
5670
5671 fontp = dpyinfo->font_table + i;
5672 if (i == dpyinfo->n_fonts)
5673 ++dpyinfo->n_fonts;
5674
5675 /* Now fill in the slots of *FONTP. */
5676 BLOCK_INPUT;
5677 fontp->font = font;
5678 fontp->font_idx = i;
5679 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
5680 bcopy (fontname, fontp->name, strlen (fontname) + 1);
5681
5682 charset = xlfd_charset_of_font (fontname);
5683
5684 /* Work out the font's full name. */
5685 full_name = (char *)xmalloc (100);
5686 if (full_name && w32_to_x_font (&lf, full_name, 100, charset))
5687 fontp->full_name = full_name;
5688 else
5689 {
5690 /* If all else fails - just use the name we used to load it. */
5691 xfree (full_name);
5692 fontp->full_name = fontp->name;
5693 }
5694
5695 fontp->size = FONT_WIDTH (font);
5696 fontp->height = FONT_HEIGHT (font);
5697
5698 /* The slot `encoding' specifies how to map a character
5699 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
5700 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
5701 (0:0x20..0x7F, 1:0xA0..0xFF,
5702 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
5703 2:0xA020..0xFF7F). For the moment, we don't know which charset
5704 uses this font. So, we set information in fontp->encoding[1]
5705 which is never used by any charset. If mapping can't be
5706 decided, set FONT_ENCODING_NOT_DECIDED. */
5707
5708 /* SJIS fonts need to be set to type 4, all others seem to work as
5709 type FONT_ENCODING_NOT_DECIDED. */
5710 encoding = strrchr (fontp->name, '-');
5711 if (encoding && stricmp (encoding+1, "sjis") == 0)
5712 fontp->encoding[1] = 4;
5713 else
5714 fontp->encoding[1] = FONT_ENCODING_NOT_DECIDED;
5715
5716 /* The following three values are set to 0 under W32, which is
5717 what they get set to if XGetFontProperty fails under X. */
5718 fontp->baseline_offset = 0;
5719 fontp->relative_compose = 0;
5720 fontp->default_ascent = 0;
5721
5722 /* Set global flag fonts_changed_p to non-zero if the font loaded
5723 has a character with a smaller width than any other character
5724 before, or if the font loaded has a smalle>r height than any
5725 other font loaded before. If this happens, it will make a
5726 glyph matrix reallocation necessary. */
5727 fonts_changed_p = x_compute_min_glyph_bounds (f);
5728 UNBLOCK_INPUT;
5729 return fontp;
5730 }
5731 }
5732
5733 /* Load font named FONTNAME of size SIZE for frame F, and return a
5734 pointer to the structure font_info while allocating it dynamically.
5735 If loading fails, return NULL. */
5736 struct font_info *
5737 w32_load_font (f,fontname,size)
5738 struct frame *f;
5739 char * fontname;
5740 int size;
5741 {
5742 Lisp_Object bdf_fonts;
5743 struct font_info *retval = NULL;
5744
5745 bdf_fonts = w32_list_bdf_fonts (build_string (fontname), 1);
5746
5747 while (!retval && CONSP (bdf_fonts))
5748 {
5749 char *bdf_name, *bdf_file;
5750 Lisp_Object bdf_pair;
5751
5752 bdf_name = XSTRING (XCAR (bdf_fonts))->data;
5753 bdf_pair = Fassoc (XCAR (bdf_fonts), Vw32_bdf_filename_alist);
5754 bdf_file = XSTRING (XCDR (bdf_pair))->data;
5755
5756 retval = w32_load_bdf_font (f, bdf_name, size, bdf_file);
5757
5758 bdf_fonts = XCDR (bdf_fonts);
5759 }
5760
5761 if (retval)
5762 return retval;
5763
5764 return w32_load_system_font(f, fontname, size);
5765 }
5766
5767
5768 void
5769 w32_unload_font (dpyinfo, font)
5770 struct w32_display_info *dpyinfo;
5771 XFontStruct * font;
5772 {
5773 if (font)
5774 {
5775 if (font->per_char) xfree (font->per_char);
5776 if (font->bdf) w32_free_bdf_font (font->bdf);
5777
5778 if (font->hfont) DeleteObject(font->hfont);
5779 xfree (font);
5780 }
5781 }
5782
5783 /* The font conversion stuff between x and w32 */
5784
5785 /* X font string is as follows (from faces.el)
5786 * (let ((- "[-?]")
5787 * (foundry "[^-]+")
5788 * (family "[^-]+")
5789 * (weight "\\(bold\\|demibold\\|medium\\)") ; 1
5790 * (weight\? "\\([^-]*\\)") ; 1
5791 * (slant "\\([ior]\\)") ; 2
5792 * (slant\? "\\([^-]?\\)") ; 2
5793 * (swidth "\\([^-]*\\)") ; 3
5794 * (adstyle "[^-]*") ; 4
5795 * (pixelsize "[0-9]+")
5796 * (pointsize "[0-9][0-9]+")
5797 * (resx "[0-9][0-9]+")
5798 * (resy "[0-9][0-9]+")
5799 * (spacing "[cmp?*]")
5800 * (avgwidth "[0-9]+")
5801 * (registry "[^-]+")
5802 * (encoding "[^-]+")
5803 * )
5804 */
5805
5806 static LONG
5807 x_to_w32_weight (lpw)
5808 char * lpw;
5809 {
5810 if (!lpw) return (FW_DONTCARE);
5811
5812 if (stricmp (lpw,"heavy") == 0) return FW_HEAVY;
5813 else if (stricmp (lpw,"extrabold") == 0) return FW_EXTRABOLD;
5814 else if (stricmp (lpw,"bold") == 0) return FW_BOLD;
5815 else if (stricmp (lpw,"demibold") == 0) return FW_SEMIBOLD;
5816 else if (stricmp (lpw,"semibold") == 0) return FW_SEMIBOLD;
5817 else if (stricmp (lpw,"medium") == 0) return FW_MEDIUM;
5818 else if (stricmp (lpw,"normal") == 0) return FW_NORMAL;
5819 else if (stricmp (lpw,"light") == 0) return FW_LIGHT;
5820 else if (stricmp (lpw,"extralight") == 0) return FW_EXTRALIGHT;
5821 else if (stricmp (lpw,"thin") == 0) return FW_THIN;
5822 else
5823 return FW_DONTCARE;
5824 }
5825
5826
5827 static char *
5828 w32_to_x_weight (fnweight)
5829 int fnweight;
5830 {
5831 if (fnweight >= FW_HEAVY) return "heavy";
5832 if (fnweight >= FW_EXTRABOLD) return "extrabold";
5833 if (fnweight >= FW_BOLD) return "bold";
5834 if (fnweight >= FW_SEMIBOLD) return "demibold";
5835 if (fnweight >= FW_MEDIUM) return "medium";
5836 if (fnweight >= FW_NORMAL) return "normal";
5837 if (fnweight >= FW_LIGHT) return "light";
5838 if (fnweight >= FW_EXTRALIGHT) return "extralight";
5839 if (fnweight >= FW_THIN) return "thin";
5840 else
5841 return "*";
5842 }
5843
5844 static LONG
5845 x_to_w32_charset (lpcs)
5846 char * lpcs;
5847 {
5848 Lisp_Object this_entry, w32_charset;
5849
5850 /* Look through w32-charset-info-alist for the character set.
5851 Format of each entry is
5852 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
5853 */
5854 this_entry = Fassoc (build_string(lpcs), Vw32_charset_info_alist);
5855
5856 if (NILP(this_entry))
5857 {
5858 /* At startup, we want iso8859-1 fonts to come up properly. */
5859 if (stricmp(lpcs, "iso8859-1") == 0)
5860 return ANSI_CHARSET;
5861 else
5862 return DEFAULT_CHARSET;
5863 }
5864
5865 w32_charset = Fcar (Fcdr (this_entry));
5866
5867 // Translate Lisp symbol to number.
5868 if (w32_charset == Qw32_charset_ansi)
5869 return ANSI_CHARSET;
5870 if (w32_charset == Qw32_charset_symbol)
5871 return SYMBOL_CHARSET;
5872 if (w32_charset == Qw32_charset_shiftjis)
5873 return SHIFTJIS_CHARSET;
5874 if (w32_charset == Qw32_charset_hangeul)
5875 return HANGEUL_CHARSET;
5876 if (w32_charset == Qw32_charset_chinesebig5)
5877 return CHINESEBIG5_CHARSET;
5878 if (w32_charset == Qw32_charset_gb2312)
5879 return GB2312_CHARSET;
5880 if (w32_charset == Qw32_charset_oem)
5881 return OEM_CHARSET;
5882 #ifdef JOHAB_CHARSET
5883 if (w32_charset == Qw32_charset_johab)
5884 return JOHAB_CHARSET;
5885 if (w32_charset == Qw32_charset_easteurope)
5886 return EASTEUROPE_CHARSET;
5887 if (w32_charset == Qw32_charset_turkish)
5888 return TURKISH_CHARSET;
5889 if (w32_charset == Qw32_charset_baltic)
5890 return BALTIC_CHARSET;
5891 if (w32_charset == Qw32_charset_russian)
5892 return RUSSIAN_CHARSET;
5893 if (w32_charset == Qw32_charset_arabic)
5894 return ARABIC_CHARSET;
5895 if (w32_charset == Qw32_charset_greek)
5896 return GREEK_CHARSET;
5897 if (w32_charset == Qw32_charset_hebrew)
5898 return HEBREW_CHARSET;
5899 if (w32_charset == Qw32_charset_vietnamese)
5900 return VIETNAMESE_CHARSET;
5901 if (w32_charset == Qw32_charset_thai)
5902 return THAI_CHARSET;
5903 if (w32_charset == Qw32_charset_mac)
5904 return MAC_CHARSET;
5905 #endif /* JOHAB_CHARSET */
5906 #ifdef UNICODE_CHARSET
5907 if (w32_charset == Qw32_charset_unicode)
5908 return UNICODE_CHARSET;
5909 #endif
5910
5911 return DEFAULT_CHARSET;
5912 }
5913
5914
5915 static char *
5916 w32_to_x_charset (fncharset)
5917 int fncharset;
5918 {
5919 static char buf[16];
5920 Lisp_Object charset_type;
5921
5922 switch (fncharset)
5923 {
5924 case ANSI_CHARSET:
5925 /* Handle startup case of w32-charset-info-alist not
5926 being set up yet. */
5927 if (NILP(Vw32_charset_info_alist))
5928 return "iso8859-1";
5929 charset_type = Qw32_charset_ansi;
5930 break;
5931 case DEFAULT_CHARSET:
5932 charset_type = Qw32_charset_default;
5933 break;
5934 case SYMBOL_CHARSET:
5935 charset_type = Qw32_charset_symbol;
5936 break;
5937 case SHIFTJIS_CHARSET:
5938 charset_type = Qw32_charset_shiftjis;
5939 break;
5940 case HANGEUL_CHARSET:
5941 charset_type = Qw32_charset_hangeul;
5942 break;
5943 case GB2312_CHARSET:
5944 charset_type = Qw32_charset_gb2312;
5945 break;
5946 case CHINESEBIG5_CHARSET:
5947 charset_type = Qw32_charset_chinesebig5;
5948 break;
5949 case OEM_CHARSET:
5950 charset_type = Qw32_charset_oem;
5951 break;
5952
5953 /* More recent versions of Windows (95 and NT4.0) define more
5954 character sets. */
5955 #ifdef EASTEUROPE_CHARSET
5956 case EASTEUROPE_CHARSET:
5957 charset_type = Qw32_charset_easteurope;
5958 break;
5959 case TURKISH_CHARSET:
5960 charset_type = Qw32_charset_turkish;
5961 break;
5962 case BALTIC_CHARSET:
5963 charset_type = Qw32_charset_baltic;
5964 break;
5965 case RUSSIAN_CHARSET:
5966 charset_type = Qw32_charset_russian;
5967 break;
5968 case ARABIC_CHARSET:
5969 charset_type = Qw32_charset_arabic;
5970 break;
5971 case GREEK_CHARSET:
5972 charset_type = Qw32_charset_greek;
5973 break;
5974 case HEBREW_CHARSET:
5975 charset_type = Qw32_charset_hebrew;
5976 break;
5977 case VIETNAMESE_CHARSET:
5978 charset_type = Qw32_charset_vietnamese;
5979 break;
5980 case THAI_CHARSET:
5981 charset_type = Qw32_charset_thai;
5982 break;
5983 case MAC_CHARSET:
5984 charset_type = Qw32_charset_mac;
5985 break;
5986 case JOHAB_CHARSET:
5987 charset_type = Qw32_charset_johab;
5988 break;
5989 #endif
5990
5991 #ifdef UNICODE_CHARSET
5992 case UNICODE_CHARSET:
5993 charset_type = Qw32_charset_unicode;
5994 break;
5995 #endif
5996 default:
5997 /* Encode numerical value of unknown charset. */
5998 sprintf (buf, "*-#%u", fncharset);
5999 return buf;
6000 }
6001
6002 {
6003 Lisp_Object rest;
6004 char * best_match = NULL;
6005
6006 /* Look through w32-charset-info-alist for the character set.
6007 Prefer ISO codepages, and prefer lower numbers in the ISO
6008 range. Only return charsets for codepages which are installed.
6009
6010 Format of each entry is
6011 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
6012 */
6013 for (rest = Vw32_charset_info_alist; CONSP (rest); rest = XCDR (rest))
6014 {
6015 char * x_charset;
6016 Lisp_Object w32_charset;
6017 Lisp_Object codepage;
6018
6019 Lisp_Object this_entry = XCAR (rest);
6020
6021 /* Skip invalid entries in alist. */
6022 if (!CONSP (this_entry) || !STRINGP (XCAR (this_entry))
6023 || !CONSP (XCDR (this_entry))
6024 || !SYMBOLP (XCAR (XCDR (this_entry))))
6025 continue;
6026
6027 x_charset = XSTRING (XCAR (this_entry))->data;
6028 w32_charset = XCAR (XCDR (this_entry));
6029 codepage = XCDR (XCDR (this_entry));
6030
6031 /* Look for Same charset and a valid codepage (or non-int
6032 which means ignore). */
6033 if (w32_charset == charset_type
6034 && (!INTEGERP (codepage) || codepage == CP_DEFAULT
6035 || IsValidCodePage (XINT (codepage))))
6036 {
6037 /* If we don't have a match already, then this is the
6038 best. */
6039 if (!best_match)
6040 best_match = x_charset;
6041 /* If this is an ISO codepage, and the best so far isn't,
6042 then this is better. */
6043 else if (stricmp (best_match, "iso") != 0
6044 && stricmp (x_charset, "iso") == 0)
6045 best_match = x_charset;
6046 /* If both are ISO8859 codepages, choose the one with the
6047 lowest number in the encoding field. */
6048 else if (stricmp (best_match, "iso8859-") == 0
6049 && stricmp (x_charset, "iso8859-") == 0)
6050 {
6051 int best_enc = atoi (best_match + 8);
6052 int this_enc = atoi (x_charset + 8);
6053 if (this_enc > 0 && this_enc < best_enc)
6054 best_match = x_charset;
6055 }
6056 }
6057 }
6058
6059 /* If no match, encode the numeric value. */
6060 if (!best_match)
6061 {
6062 sprintf (buf, "*-#%u", fncharset);
6063 return buf;
6064 }
6065
6066 strncpy(buf, best_match, 15);
6067 buf[15] = '\0';
6068 return buf;
6069 }
6070 }
6071
6072
6073 /* Get the Windows codepage corresponding to the specified font. The
6074 charset info in the font name is used to look up
6075 w32-charset-to-codepage-alist. */
6076 int
6077 w32_codepage_for_font (char *fontname)
6078 {
6079 Lisp_Object codepage, entry;
6080 char *charset_str, *charset, *end;
6081
6082 if (NILP (Vw32_charset_info_alist))
6083 return CP_DEFAULT;
6084
6085 /* Extract charset part of font string. */
6086 charset = xlfd_charset_of_font (fontname);
6087
6088 if (!charset)
6089 return CP_UNKNOWN;
6090
6091 charset_str = (char *) alloca (strlen (charset));
6092 strcpy (charset_str, charset);
6093
6094 /* Remove leading "*-". */
6095 if (strncmp ("*-", charset_str, 2) == 0)
6096 charset = charset_str + 2;
6097 else
6098 charset = charset_str;
6099
6100 /* Stop match at wildcard (including preceding '-'). */
6101 if (end = strchr (charset, '*'))
6102 {
6103 if (end > charset && *(end-1) == '-')
6104 end--;
6105 *end = '\0';
6106 }
6107
6108 entry = Fassoc (build_string(charset), Vw32_charset_info_alist);
6109 if (NILP (entry))
6110 return CP_UNKNOWN;
6111
6112 codepage = Fcdr (Fcdr (entry));
6113
6114 if (NILP (codepage))
6115 return CP_8BIT;
6116 else if (XFASTINT (codepage) == XFASTINT (Qt))
6117 return CP_UNICODE;
6118 else if (INTEGERP (codepage))
6119 return XINT (codepage);
6120 else
6121 return CP_UNKNOWN;
6122 }
6123
6124
6125 static BOOL
6126 w32_to_x_font (lplogfont, lpxstr, len, specific_charset)
6127 LOGFONT * lplogfont;
6128 char * lpxstr;
6129 int len;
6130 char * specific_charset;
6131 {
6132 char* fonttype;
6133 char *fontname;
6134 char height_pixels[8];
6135 char height_dpi[8];
6136 char width_pixels[8];
6137 char *fontname_dash;
6138 int display_resy = one_w32_display_info.resy;
6139 int display_resx = one_w32_display_info.resx;
6140 int bufsz;
6141 struct coding_system coding;
6142
6143 if (!lpxstr) abort ();
6144
6145 if (!lplogfont)
6146 return FALSE;
6147
6148 if (lplogfont->lfOutPrecision == OUT_STRING_PRECIS)
6149 fonttype = "raster";
6150 else if (lplogfont->lfOutPrecision == OUT_STROKE_PRECIS)
6151 fonttype = "outline";
6152 else
6153 fonttype = "unknown";
6154
6155 setup_coding_system (Fcheck_coding_system (Vw32_system_coding_system),
6156 &coding);
6157 coding.src_multibyte = 0;
6158 coding.dst_multibyte = 1;
6159 coding.mode |= CODING_MODE_LAST_BLOCK;
6160 bufsz = decoding_buffer_size (&coding, LF_FACESIZE);
6161
6162 fontname = alloca(sizeof(*fontname) * bufsz);
6163 decode_coding (&coding, lplogfont->lfFaceName, fontname,
6164 strlen(lplogfont->lfFaceName), bufsz - 1);
6165 *(fontname + coding.produced) = '\0';
6166
6167 /* Replace dashes with underscores so the dashes are not
6168 misinterpreted. */
6169 fontname_dash = fontname;
6170 while (fontname_dash = strchr (fontname_dash, '-'))
6171 *fontname_dash = '_';
6172
6173 if (lplogfont->lfHeight)
6174 {
6175 sprintf (height_pixels, "%u", abs (lplogfont->lfHeight));
6176 sprintf (height_dpi, "%u",
6177 abs (lplogfont->lfHeight) * 720 / display_resy);
6178 }
6179 else
6180 {
6181 strcpy (height_pixels, "*");
6182 strcpy (height_dpi, "*");
6183 }
6184 if (lplogfont->lfWidth)
6185 sprintf (width_pixels, "%u", lplogfont->lfWidth * 10);
6186 else
6187 strcpy (width_pixels, "*");
6188
6189 _snprintf (lpxstr, len - 1,
6190 "-%s-%s-%s-%c-normal-normal-%s-%s-%d-%d-%c-%s-%s",
6191 fonttype, /* foundry */
6192 fontname, /* family */
6193 w32_to_x_weight (lplogfont->lfWeight), /* weight */
6194 lplogfont->lfItalic?'i':'r', /* slant */
6195 /* setwidth name */
6196 /* add style name */
6197 height_pixels, /* pixel size */
6198 height_dpi, /* point size */
6199 display_resx, /* resx */
6200 display_resy, /* resy */
6201 ((lplogfont->lfPitchAndFamily & 0x3) == VARIABLE_PITCH)
6202 ? 'p' : 'c', /* spacing */
6203 width_pixels, /* avg width */
6204 specific_charset ? specific_charset
6205 : w32_to_x_charset (lplogfont->lfCharSet)
6206 /* charset registry and encoding */
6207 );
6208
6209 lpxstr[len - 1] = 0; /* just to be sure */
6210 return (TRUE);
6211 }
6212
6213 static BOOL
6214 x_to_w32_font (lpxstr, lplogfont)
6215 char * lpxstr;
6216 LOGFONT * lplogfont;
6217 {
6218 struct coding_system coding;
6219
6220 if (!lplogfont) return (FALSE);
6221
6222 memset (lplogfont, 0, sizeof (*lplogfont));
6223
6224 /* Set default value for each field. */
6225 #if 1
6226 lplogfont->lfOutPrecision = OUT_DEFAULT_PRECIS;
6227 lplogfont->lfClipPrecision = CLIP_DEFAULT_PRECIS;
6228 lplogfont->lfQuality = DEFAULT_QUALITY;
6229 #else
6230 /* go for maximum quality */
6231 lplogfont->lfOutPrecision = OUT_STROKE_PRECIS;
6232 lplogfont->lfClipPrecision = CLIP_STROKE_PRECIS;
6233 lplogfont->lfQuality = PROOF_QUALITY;
6234 #endif
6235
6236 lplogfont->lfCharSet = DEFAULT_CHARSET;
6237 lplogfont->lfWeight = FW_DONTCARE;
6238 lplogfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
6239
6240 if (!lpxstr)
6241 return FALSE;
6242
6243 /* Provide a simple escape mechanism for specifying Windows font names
6244 * directly -- if font spec does not beginning with '-', assume this
6245 * format:
6246 * "<font name>[:height in pixels[:width in pixels[:weight]]]"
6247 */
6248
6249 if (*lpxstr == '-')
6250 {
6251 int fields, tem;
6252 char name[50], weight[20], slant, pitch, pixels[10], height[10],
6253 width[10], resy[10], remainder[20];
6254 char * encoding;
6255 int dpi = one_w32_display_info.resy;
6256
6257 fields = sscanf (lpxstr,
6258 "-%*[^-]-%49[^-]-%19[^-]-%c-%*[^-]-%*[^-]-%9[^-]-%9[^-]-%*[^-]-%9[^-]-%c-%9[^-]-%19s",
6259 name, weight, &slant, pixels, height, resy, &pitch, width, remainder);
6260 if (fields == EOF) return (FALSE);
6261
6262 /* If wildcards cover more than one field, we don't know which
6263 field is which, so don't fill any in. */
6264
6265 if (fields < 9)
6266 fields = 0;
6267
6268 if (fields > 0 && name[0] != '*')
6269 {
6270 int bufsize;
6271 unsigned char *buf;
6272
6273 setup_coding_system
6274 (Fcheck_coding_system (Vw32_system_coding_system), &coding);
6275 coding.src_multibyte = 1;
6276 coding.dst_multibyte = 1;
6277 bufsize = encoding_buffer_size (&coding, strlen (name));
6278 buf = (unsigned char *) alloca (bufsize);
6279 coding.mode |= CODING_MODE_LAST_BLOCK;
6280 encode_coding (&coding, name, buf, strlen (name), bufsize);
6281 if (coding.produced >= LF_FACESIZE)
6282 coding.produced = LF_FACESIZE - 1;
6283 buf[coding.produced] = 0;
6284 strcpy (lplogfont->lfFaceName, buf);
6285 }
6286 else
6287 {
6288 lplogfont->lfFaceName[0] = '\0';
6289 }
6290
6291 fields--;
6292
6293 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
6294
6295 fields--;
6296
6297 lplogfont->lfItalic = (fields > 0 && slant == 'i');
6298
6299 fields--;
6300
6301 if (fields > 0 && pixels[0] != '*')
6302 lplogfont->lfHeight = atoi (pixels);
6303
6304 fields--;
6305 fields--;
6306 if (fields > 0 && resy[0] != '*')
6307 {
6308 tem = atoi (resy);
6309 if (tem > 0) dpi = tem;
6310 }
6311
6312 if (fields > -1 && lplogfont->lfHeight == 0 && height[0] != '*')
6313 lplogfont->lfHeight = atoi (height) * dpi / 720;
6314
6315 if (fields > 0)
6316 lplogfont->lfPitchAndFamily =
6317 (fields > 0 && pitch == 'p') ? VARIABLE_PITCH : FIXED_PITCH;
6318
6319 fields--;
6320
6321 if (fields > 0 && width[0] != '*')
6322 lplogfont->lfWidth = atoi (width) / 10;
6323
6324 fields--;
6325
6326 /* Strip the trailing '-' if present. (it shouldn't be, as it
6327 fails the test against xlfd-tight-regexp in fontset.el). */
6328 {
6329 int len = strlen (remainder);
6330 if (len > 0 && remainder[len-1] == '-')
6331 remainder[len-1] = 0;
6332 }
6333 encoding = remainder;
6334 if (strncmp (encoding, "*-", 2) == 0)
6335 encoding += 2;
6336 lplogfont->lfCharSet = x_to_w32_charset (fields > 0 ? encoding : "");
6337 }
6338 else
6339 {
6340 int fields;
6341 char name[100], height[10], width[10], weight[20];
6342
6343 fields = sscanf (lpxstr,
6344 "%99[^:]:%9[^:]:%9[^:]:%19s",
6345 name, height, width, weight);
6346
6347 if (fields == EOF) return (FALSE);
6348
6349 if (fields > 0)
6350 {
6351 strncpy (lplogfont->lfFaceName,name, LF_FACESIZE);
6352 lplogfont->lfFaceName[LF_FACESIZE-1] = 0;
6353 }
6354 else
6355 {
6356 lplogfont->lfFaceName[0] = 0;
6357 }
6358
6359 fields--;
6360
6361 if (fields > 0)
6362 lplogfont->lfHeight = atoi (height);
6363
6364 fields--;
6365
6366 if (fields > 0)
6367 lplogfont->lfWidth = atoi (width);
6368
6369 fields--;
6370
6371 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
6372 }
6373
6374 /* This makes TrueType fonts work better. */
6375 lplogfont->lfHeight = - abs (lplogfont->lfHeight);
6376
6377 return (TRUE);
6378 }
6379
6380 /* Strip the pixel height and point height from the given xlfd, and
6381 return the pixel height. If no pixel height is specified, calculate
6382 one from the point height, or if that isn't defined either, return
6383 0 (which usually signifies a scalable font).
6384 */
6385 static int
6386 xlfd_strip_height (char *fontname)
6387 {
6388 int pixel_height, field_number;
6389 char *read_from, *write_to;
6390
6391 xassert (fontname);
6392
6393 pixel_height = field_number = 0;
6394 write_to = NULL;
6395
6396 /* Look for height fields. */
6397 for (read_from = fontname; *read_from; read_from++)
6398 {
6399 if (*read_from == '-')
6400 {
6401 field_number++;
6402 if (field_number == 7) /* Pixel height. */
6403 {
6404 read_from++;
6405 write_to = read_from;
6406
6407 /* Find end of field. */
6408 for (;*read_from && *read_from != '-'; read_from++)
6409 ;
6410
6411 /* Split the fontname at end of field. */
6412 if (*read_from)
6413 {
6414 *read_from = '\0';
6415 read_from++;
6416 }
6417 pixel_height = atoi (write_to);
6418 /* Blank out field. */
6419 if (read_from > write_to)
6420 {
6421 *write_to = '-';
6422 write_to++;
6423 }
6424 /* If the pixel height field is at the end (partial xlfd),
6425 return now. */
6426 else
6427 return pixel_height;
6428
6429 /* If we got a pixel height, the point height can be
6430 ignored. Just blank it out and break now. */
6431 if (pixel_height)
6432 {
6433 /* Find end of point size field. */
6434 for (; *read_from && *read_from != '-'; read_from++)
6435 ;
6436
6437 if (*read_from)
6438 read_from++;
6439
6440 /* Blank out the point size field. */
6441 if (read_from > write_to)
6442 {
6443 *write_to = '-';
6444 write_to++;
6445 }
6446 else
6447 return pixel_height;
6448
6449 break;
6450 }
6451 /* If the point height is already blank, break now. */
6452 if (*read_from == '-')
6453 {
6454 read_from++;
6455 break;
6456 }
6457 }
6458 else if (field_number == 8)
6459 {
6460 /* If we didn't get a pixel height, try to get the point
6461 height and convert that. */
6462 int point_size;
6463 char *point_size_start = read_from++;
6464
6465 /* Find end of field. */
6466 for (; *read_from && *read_from != '-'; read_from++)
6467 ;
6468
6469 if (*read_from)
6470 {
6471 *read_from = '\0';
6472 read_from++;
6473 }
6474
6475 point_size = atoi (point_size_start);
6476
6477 /* Convert to pixel height. */
6478 pixel_height = point_size
6479 * one_w32_display_info.height_in / 720;
6480
6481 /* Blank out this field and break. */
6482 *write_to = '-';
6483 write_to++;
6484 break;
6485 }
6486 }
6487 }
6488
6489 /* Shift the rest of the font spec into place. */
6490 if (write_to && read_from > write_to)
6491 {
6492 for (; *read_from; read_from++, write_to++)
6493 *write_to = *read_from;
6494 *write_to = '\0';
6495 }
6496
6497 return pixel_height;
6498 }
6499
6500 /* Assume parameter 1 is fully qualified, no wildcards. */
6501 static BOOL
6502 w32_font_match (fontname, pattern)
6503 char * fontname;
6504 char * pattern;
6505 {
6506 char *regex = alloca (strlen (pattern) * 2 + 3);
6507 char *font_name_copy = alloca (strlen (fontname) + 1);
6508 char *ptr;
6509
6510 /* Copy fontname so we can modify it during comparison. */
6511 strcpy (font_name_copy, fontname);
6512
6513 ptr = regex;
6514 *ptr++ = '^';
6515
6516 /* Turn pattern into a regexp and do a regexp match. */
6517 for (; *pattern; pattern++)
6518 {
6519 if (*pattern == '?')
6520 *ptr++ = '.';
6521 else if (*pattern == '*')
6522 {
6523 *ptr++ = '.';
6524 *ptr++ = '*';
6525 }
6526 else
6527 *ptr++ = *pattern;
6528 }
6529 *ptr = '$';
6530 *(ptr + 1) = '\0';
6531
6532 /* Strip out font heights and compare them seperately, since
6533 rounding error can cause mismatches. This also allows a
6534 comparison between a font that declares only a pixel height and a
6535 pattern that declares the point height.
6536 */
6537 {
6538 int font_height, pattern_height;
6539
6540 font_height = xlfd_strip_height (font_name_copy);
6541 pattern_height = xlfd_strip_height (regex);
6542
6543 /* Compare now, and don't bother doing expensive regexp matching
6544 if the heights differ. */
6545 if (font_height && pattern_height && (font_height != pattern_height))
6546 return FALSE;
6547 }
6548
6549 return (fast_c_string_match_ignore_case (build_string (regex),
6550 font_name_copy) >= 0);
6551 }
6552
6553 /* Callback functions, and a structure holding info they need, for
6554 listing system fonts on W32. We need one set of functions to do the
6555 job properly, but these don't work on NT 3.51 and earlier, so we
6556 have a second set which don't handle character sets properly to
6557 fall back on.
6558
6559 In both cases, there are two passes made. The first pass gets one
6560 font from each family, the second pass lists all the fonts from
6561 each family. */
6562
6563 typedef struct enumfont_t
6564 {
6565 HDC hdc;
6566 int numFonts;
6567 LOGFONT logfont;
6568 XFontStruct *size_ref;
6569 Lisp_Object *pattern;
6570 Lisp_Object *tail;
6571 } enumfont_t;
6572
6573 static int CALLBACK
6574 enum_font_cb2 (lplf, lptm, FontType, lpef)
6575 ENUMLOGFONT * lplf;
6576 NEWTEXTMETRIC * lptm;
6577 int FontType;
6578 enumfont_t * lpef;
6579 {
6580 if (lplf->elfLogFont.lfStrikeOut || lplf->elfLogFont.lfUnderline)
6581 return (1);
6582
6583 /* Check that the character set matches if it was specified */
6584 if (lpef->logfont.lfCharSet != DEFAULT_CHARSET &&
6585 lplf->elfLogFont.lfCharSet != lpef->logfont.lfCharSet)
6586 return (1);
6587
6588 {
6589 char buf[100];
6590 Lisp_Object width = Qnil;
6591 char *charset = NULL;
6592
6593 /* Truetype fonts do not report their true metrics until loaded */
6594 if (FontType != RASTER_FONTTYPE)
6595 {
6596 if (!NILP (*(lpef->pattern)))
6597 {
6598 /* Scalable fonts are as big as you want them to be. */
6599 lplf->elfLogFont.lfHeight = lpef->logfont.lfHeight;
6600 lplf->elfLogFont.lfWidth = lpef->logfont.lfWidth;
6601 width = make_number (lpef->logfont.lfWidth);
6602 }
6603 else
6604 {
6605 lplf->elfLogFont.lfHeight = 0;
6606 lplf->elfLogFont.lfWidth = 0;
6607 }
6608 }
6609
6610 /* Make sure the height used here is the same as everywhere
6611 else (ie character height, not cell height). */
6612 if (lplf->elfLogFont.lfHeight > 0)
6613 {
6614 /* lptm can be trusted for RASTER fonts, but not scalable ones. */
6615 if (FontType == RASTER_FONTTYPE)
6616 lplf->elfLogFont.lfHeight = lptm->tmInternalLeading - lptm->tmHeight;
6617 else
6618 lplf->elfLogFont.lfHeight = -lplf->elfLogFont.lfHeight;
6619 }
6620
6621 if (!NILP (*(lpef->pattern)))
6622 {
6623 charset = xlfd_charset_of_font (XSTRING(*(lpef->pattern))->data);
6624
6625 /* Ensure that charset is valid for this font. */
6626 if (charset
6627 && (x_to_w32_charset (charset) != lplf->elfLogFont.lfCharSet))
6628 charset = NULL;
6629 }
6630
6631 /* TODO: List all relevant charsets if charset not specified. */
6632 if (!w32_to_x_font (&(lplf->elfLogFont), buf, 100, charset))
6633 return (0);
6634
6635 if (NILP (*(lpef->pattern))
6636 || w32_font_match (buf, XSTRING (*(lpef->pattern))->data))
6637 {
6638 *lpef->tail = Fcons (Fcons (build_string (buf), width), Qnil);
6639 lpef->tail = &(XCDR (*lpef->tail));
6640 lpef->numFonts++;
6641 }
6642 }
6643
6644 return (1);
6645 }
6646
6647 static int CALLBACK
6648 enum_font_cb1 (lplf, lptm, FontType, lpef)
6649 ENUMLOGFONT * lplf;
6650 NEWTEXTMETRIC * lptm;
6651 int FontType;
6652 enumfont_t * lpef;
6653 {
6654 return EnumFontFamilies (lpef->hdc,
6655 lplf->elfLogFont.lfFaceName,
6656 (FONTENUMPROC) enum_font_cb2,
6657 (LPARAM) lpef);
6658 }
6659
6660
6661 static int CALLBACK
6662 enum_fontex_cb2 (lplf, lptm, font_type, lpef)
6663 ENUMLOGFONTEX * lplf;
6664 NEWTEXTMETRICEX * lptm;
6665 int font_type;
6666 enumfont_t * lpef;
6667 {
6668 /* We are not interested in the extra info we get back from the 'Ex
6669 version - only the fact that we get character set variations
6670 enumerated seperately. */
6671 return enum_font_cb2 ((ENUMLOGFONT *) lplf, (NEWTEXTMETRIC *) lptm,
6672 font_type, lpef);
6673 }
6674
6675 static int CALLBACK
6676 enum_fontex_cb1 (lplf, lptm, font_type, lpef)
6677 ENUMLOGFONTEX * lplf;
6678 NEWTEXTMETRICEX * lptm;
6679 int font_type;
6680 enumfont_t * lpef;
6681 {
6682 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
6683 FARPROC enum_font_families_ex
6684 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
6685 /* We don't really expect EnumFontFamiliesEx to disappear once we
6686 get here, so don't bother handling it gracefully. */
6687 if (enum_font_families_ex == NULL)
6688 error ("gdi32.dll has disappeared!");
6689 return enum_font_families_ex (lpef->hdc,
6690 &lplf->elfLogFont,
6691 (FONTENUMPROC) enum_fontex_cb2,
6692 (LPARAM) lpef, 0);
6693 }
6694
6695 /* Interface to fontset handler. (adapted from mw32font.c in Meadow
6696 and xterm.c in Emacs 20.3) */
6697
6698 static Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names)
6699 {
6700 char *fontname, *ptnstr;
6701 Lisp_Object list, tem, newlist = Qnil;
6702 int n_fonts = 0;
6703
6704 list = Vw32_bdf_filename_alist;
6705 ptnstr = XSTRING (pattern)->data;
6706
6707 for ( ; CONSP (list); list = XCDR (list))
6708 {
6709 tem = XCAR (list);
6710 if (CONSP (tem))
6711 fontname = XSTRING (XCAR (tem))->data;
6712 else if (STRINGP (tem))
6713 fontname = XSTRING (tem)->data;
6714 else
6715 continue;
6716
6717 if (w32_font_match (fontname, ptnstr))
6718 {
6719 newlist = Fcons (XCAR (tem), newlist);
6720 n_fonts++;
6721 if (n_fonts >= max_names)
6722 break;
6723 }
6724 }
6725
6726 return newlist;
6727 }
6728
6729 static Lisp_Object w32_list_synthesized_fonts (FRAME_PTR f,
6730 Lisp_Object pattern,
6731 int size, int max_names);
6732
6733 /* Return a list of names of available fonts matching PATTERN on frame
6734 F. If SIZE is not 0, it is the size (maximum bound width) of fonts
6735 to be listed. Frame F NULL means we have not yet created any
6736 frame, which means we can't get proper size info, as we don't have
6737 a device context to use for GetTextMetrics.
6738 MAXNAMES sets a limit on how many fonts to match. */
6739
6740 Lisp_Object
6741 w32_list_fonts (f, pattern, size, maxnames)
6742 struct frame *f;
6743 Lisp_Object pattern;
6744 int size;
6745 int maxnames;
6746 {
6747 Lisp_Object patterns, key = Qnil, tem, tpat;
6748 Lisp_Object list = Qnil, newlist = Qnil, second_best = Qnil;
6749 struct w32_display_info *dpyinfo = &one_w32_display_info;
6750 int n_fonts = 0;
6751
6752 patterns = Fassoc (pattern, Valternate_fontname_alist);
6753 if (NILP (patterns))
6754 patterns = Fcons (pattern, Qnil);
6755
6756 for (; CONSP (patterns); patterns = XCDR (patterns))
6757 {
6758 enumfont_t ef;
6759 int codepage;
6760
6761 tpat = XCAR (patterns);
6762
6763 if (!STRINGP (tpat))
6764 continue;
6765
6766 /* Avoid expensive EnumFontFamilies functions if we are not
6767 going to be able to output one of these anyway. */
6768 codepage = w32_codepage_for_font (XSTRING (tpat)->data);
6769 if (codepage != CP_8BIT && codepage != CP_UNICODE
6770 && codepage != CP_DEFAULT && codepage != CP_UNKNOWN
6771 && !IsValidCodePage(codepage))
6772 continue;
6773
6774 /* See if we cached the result for this particular query.
6775 The cache is an alist of the form:
6776 ((PATTERN (FONTNAME . WIDTH) ...) ...)
6777 */
6778 if (tem = XCDR (dpyinfo->name_list_element),
6779 !NILP (list = Fassoc (tpat, tem)))
6780 {
6781 list = Fcdr_safe (list);
6782 /* We have a cached list. Don't have to get the list again. */
6783 goto label_cached;
6784 }
6785
6786 BLOCK_INPUT;
6787 /* At first, put PATTERN in the cache. */
6788 list = Qnil;
6789 ef.pattern = &tpat;
6790 ef.tail = &list;
6791 ef.numFonts = 0;
6792
6793 /* Use EnumFontFamiliesEx where it is available, as it knows
6794 about character sets. Fall back to EnumFontFamilies for
6795 older versions of NT that don't support the 'Ex function. */
6796 x_to_w32_font (XSTRING (tpat)->data, &ef.logfont);
6797 {
6798 LOGFONT font_match_pattern;
6799 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
6800 FARPROC enum_font_families_ex
6801 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
6802
6803 /* We do our own pattern matching so we can handle wildcards. */
6804 font_match_pattern.lfFaceName[0] = 0;
6805 font_match_pattern.lfPitchAndFamily = 0;
6806 /* We can use the charset, because if it is a wildcard it will
6807 be DEFAULT_CHARSET anyway. */
6808 font_match_pattern.lfCharSet = ef.logfont.lfCharSet;
6809
6810 ef.hdc = GetDC (dpyinfo->root_window);
6811
6812 if (enum_font_families_ex)
6813 enum_font_families_ex (ef.hdc,
6814 &font_match_pattern,
6815 (FONTENUMPROC) enum_fontex_cb1,
6816 (LPARAM) &ef, 0);
6817 else
6818 EnumFontFamilies (ef.hdc, NULL, (FONTENUMPROC) enum_font_cb1,
6819 (LPARAM)&ef);
6820
6821 ReleaseDC (dpyinfo->root_window, ef.hdc);
6822 }
6823
6824 UNBLOCK_INPUT;
6825
6826 /* Make a list of the fonts we got back.
6827 Store that in the font cache for the display. */
6828 XCDR (dpyinfo->name_list_element)
6829 = Fcons (Fcons (tpat, list),
6830 XCDR (dpyinfo->name_list_element));
6831
6832 label_cached:
6833 if (NILP (list)) continue; /* Try the remaining alternatives. */
6834
6835 newlist = second_best = Qnil;
6836
6837 /* Make a list of the fonts that have the right width. */
6838 for (; CONSP (list); list = XCDR (list))
6839 {
6840 int found_size;
6841 tem = XCAR (list);
6842
6843 if (!CONSP (tem))
6844 continue;
6845 if (NILP (XCAR (tem)))
6846 continue;
6847 if (!size)
6848 {
6849 newlist = Fcons (XCAR (tem), newlist);
6850 n_fonts++;
6851 if (n_fonts >= maxnames)
6852 break;
6853 else
6854 continue;
6855 }
6856 if (!INTEGERP (XCDR (tem)))
6857 {
6858 /* Since we don't yet know the size of the font, we must
6859 load it and try GetTextMetrics. */
6860 W32FontStruct thisinfo;
6861 LOGFONT lf;
6862 HDC hdc;
6863 HANDLE oldobj;
6864
6865 if (!x_to_w32_font (XSTRING (XCAR (tem))->data, &lf))
6866 continue;
6867
6868 BLOCK_INPUT;
6869 thisinfo.bdf = NULL;
6870 thisinfo.hfont = CreateFontIndirect (&lf);
6871 if (thisinfo.hfont == NULL)
6872 continue;
6873
6874 hdc = GetDC (dpyinfo->root_window);
6875 oldobj = SelectObject (hdc, thisinfo.hfont);
6876 if (GetTextMetrics (hdc, &thisinfo.tm))
6877 XCDR (tem) = make_number (FONT_WIDTH (&thisinfo));
6878 else
6879 XCDR (tem) = make_number (0);
6880 SelectObject (hdc, oldobj);
6881 ReleaseDC (dpyinfo->root_window, hdc);
6882 DeleteObject(thisinfo.hfont);
6883 UNBLOCK_INPUT;
6884 }
6885 found_size = XINT (XCDR (tem));
6886 if (found_size == size)
6887 {
6888 newlist = Fcons (XCAR (tem), newlist);
6889 n_fonts++;
6890 if (n_fonts >= maxnames)
6891 break;
6892 }
6893 /* keep track of the closest matching size in case
6894 no exact match is found. */
6895 else if (found_size > 0)
6896 {
6897 if (NILP (second_best))
6898 second_best = tem;
6899
6900 else if (found_size < size)
6901 {
6902 if (XINT (XCDR (second_best)) > size
6903 || XINT (XCDR (second_best)) < found_size)
6904 second_best = tem;
6905 }
6906 else
6907 {
6908 if (XINT (XCDR (second_best)) > size
6909 && XINT (XCDR (second_best)) >
6910 found_size)
6911 second_best = tem;
6912 }
6913 }
6914 }
6915
6916 if (!NILP (newlist))
6917 break;
6918 else if (!NILP (second_best))
6919 {
6920 newlist = Fcons (XCAR (second_best), Qnil);
6921 break;
6922 }
6923 }
6924
6925 /* Include any bdf fonts. */
6926 if (n_fonts < maxnames)
6927 {
6928 Lisp_Object combined[2];
6929 combined[0] = w32_list_bdf_fonts (pattern, maxnames - n_fonts);
6930 combined[1] = newlist;
6931 newlist = Fnconc(2, combined);
6932 }
6933
6934 /* If we can't find a font that matches, check if Windows would be
6935 able to synthesize it from a different style. */
6936 if (NILP (newlist) && !NILP (Vw32_enable_synthesized_fonts))
6937 newlist = w32_list_synthesized_fonts (f, pattern, size, maxnames);
6938
6939 return newlist;
6940 }
6941
6942 static Lisp_Object
6943 w32_list_synthesized_fonts (f, pattern, size, max_names)
6944 FRAME_PTR f;
6945 Lisp_Object pattern;
6946 int size;
6947 int max_names;
6948 {
6949 int fields;
6950 char *full_pattn, *new_pattn, foundary[50], family[50], *pattn_part2;
6951 char style[20], slant;
6952 Lisp_Object matches, tem, synthed_matches = Qnil;
6953
6954 full_pattn = XSTRING (pattern)->data;
6955
6956 pattn_part2 = alloca (XSTRING (pattern)->size);
6957 /* Allow some space for wildcard expansion. */
6958 new_pattn = alloca (XSTRING (pattern)->size + 100);
6959
6960 fields = sscanf (full_pattn, "-%49[^-]-%49[^-]-%19[^-]-%c-%s",
6961 foundary, family, style, &slant, pattn_part2);
6962 if (fields == EOF || fields < 5)
6963 return Qnil;
6964
6965 /* If the style and slant are wildcards already there is no point
6966 checking again (and we don't want to keep recursing). */
6967 if (*style == '*' && slant == '*')
6968 return Qnil;
6969
6970 sprintf (new_pattn, "-%s-%s-*-*-%s", foundary, family, pattn_part2);
6971
6972 matches = w32_list_fonts (f, build_string (new_pattn), size, max_names);
6973
6974 for ( ; CONSP (matches); matches = XCDR (matches))
6975 {
6976 tem = XCAR (matches);
6977 if (!STRINGP (tem))
6978 continue;
6979
6980 full_pattn = XSTRING (tem)->data;
6981 fields = sscanf (full_pattn, "-%49[^-]-%49[^-]-%*[^-]-%*c-%s",
6982 foundary, family, pattn_part2);
6983 if (fields == EOF || fields < 3)
6984 continue;
6985
6986 sprintf (new_pattn, "-%s-%s-%s-%c-%s", foundary, family, style,
6987 slant, pattn_part2);
6988
6989 synthed_matches = Fcons (build_string (new_pattn),
6990 synthed_matches);
6991 }
6992
6993 return synthed_matches;
6994 }
6995
6996
6997 /* Return a pointer to struct font_info of font FONT_IDX of frame F. */
6998 struct font_info *
6999 w32_get_font_info (f, font_idx)
7000 FRAME_PTR f;
7001 int font_idx;
7002 {
7003 return (FRAME_W32_FONT_TABLE (f) + font_idx);
7004 }
7005
7006
7007 struct font_info*
7008 w32_query_font (struct frame *f, char *fontname)
7009 {
7010 int i;
7011 struct font_info *pfi;
7012
7013 pfi = FRAME_W32_FONT_TABLE (f);
7014
7015 for (i = 0; i < one_w32_display_info.n_fonts ;i++, pfi++)
7016 {
7017 if (strcmp(pfi->name, fontname) == 0) return pfi;
7018 }
7019
7020 return NULL;
7021 }
7022
7023 /* Find a CCL program for a font specified by FONTP, and set the member
7024 `encoder' of the structure. */
7025
7026 void
7027 w32_find_ccl_program (fontp)
7028 struct font_info *fontp;
7029 {
7030 Lisp_Object list, elt;
7031
7032 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
7033 {
7034 elt = XCAR (list);
7035 if (CONSP (elt)
7036 && STRINGP (XCAR (elt))
7037 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
7038 >= 0))
7039 break;
7040 }
7041 if (! NILP (list))
7042 {
7043 struct ccl_program *ccl
7044 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
7045
7046 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
7047 xfree (ccl);
7048 else
7049 fontp->font_encoder = ccl;
7050 }
7051 }
7052
7053 \f
7054 /* Find BDF files in a specified directory. (use GCPRO when calling,
7055 as this calls lisp to get a directory listing). */
7056 static Lisp_Object
7057 w32_find_bdf_fonts_in_dir (Lisp_Object directory)
7058 {
7059 Lisp_Object filelist, list = Qnil;
7060 char fontname[100];
7061
7062 if (!STRINGP(directory))
7063 return Qnil;
7064
7065 filelist = Fdirectory_files (directory, Qt,
7066 build_string (".*\\.[bB][dD][fF]"), Qt);
7067
7068 for ( ; CONSP(filelist); filelist = XCDR (filelist))
7069 {
7070 Lisp_Object filename = XCAR (filelist);
7071 if (w32_BDF_to_x_font (XSTRING (filename)->data, fontname, 100))
7072 store_in_alist (&list, build_string (fontname), filename);
7073 }
7074 return list;
7075 }
7076
7077 DEFUN ("w32-find-bdf-fonts", Fw32_find_bdf_fonts, Sw32_find_bdf_fonts,
7078 1, 1, 0,
7079 "Return a list of BDF fonts in DIR, suitable for appending to\n\
7080 w32-bdf-filename-alist. Fonts which do not contain an xlfd description\n\
7081 will not be included in the list. DIR may be a list of directories.")
7082 (directory)
7083 Lisp_Object directory;
7084 {
7085 Lisp_Object list = Qnil;
7086 struct gcpro gcpro1, gcpro2;
7087
7088 if (!CONSP (directory))
7089 return w32_find_bdf_fonts_in_dir (directory);
7090
7091 for ( ; CONSP (directory); directory = XCDR (directory))
7092 {
7093 Lisp_Object pair[2];
7094 pair[0] = list;
7095 pair[1] = Qnil;
7096 GCPRO2 (directory, list);
7097 pair[1] = w32_find_bdf_fonts_in_dir( XCAR (directory) );
7098 list = Fnconc( 2, pair );
7099 UNGCPRO;
7100 }
7101 return list;
7102 }
7103
7104 \f
7105 DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
7106 "Internal function called by `color-defined-p', which see.")
7107 (color, frame)
7108 Lisp_Object color, frame;
7109 {
7110 XColor foo;
7111 FRAME_PTR f = check_x_frame (frame);
7112
7113 CHECK_STRING (color, 1);
7114
7115 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
7116 return Qt;
7117 else
7118 return Qnil;
7119 }
7120
7121 DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
7122 "Internal function called by `color-values', which see.")
7123 (color, frame)
7124 Lisp_Object color, frame;
7125 {
7126 XColor foo;
7127 FRAME_PTR f = check_x_frame (frame);
7128
7129 CHECK_STRING (color, 1);
7130
7131 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
7132 {
7133 Lisp_Object rgb[3];
7134
7135 rgb[0] = make_number ((GetRValue (foo.pixel) << 8)
7136 | GetRValue (foo.pixel));
7137 rgb[1] = make_number ((GetGValue (foo.pixel) << 8)
7138 | GetGValue (foo.pixel));
7139 rgb[2] = make_number ((GetBValue (foo.pixel) << 8)
7140 | GetBValue (foo.pixel));
7141 return Flist (3, rgb);
7142 }
7143 else
7144 return Qnil;
7145 }
7146
7147 DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
7148 "Internal function called by `display-color-p', which see.")
7149 (display)
7150 Lisp_Object display;
7151 {
7152 struct w32_display_info *dpyinfo = check_x_display_info (display);
7153
7154 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 2)
7155 return Qnil;
7156
7157 return Qt;
7158 }
7159
7160 DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p, Sx_display_grayscale_p,
7161 0, 1, 0,
7162 "Return t if the X display supports shades of gray.\n\
7163 Note that color displays do support shades of gray.\n\
7164 The optional argument DISPLAY specifies which display to ask about.\n\
7165 DISPLAY should be either a frame or a display name (a string).\n\
7166 If omitted or nil, that stands for the selected frame's display.")
7167 (display)
7168 Lisp_Object display;
7169 {
7170 struct w32_display_info *dpyinfo = check_x_display_info (display);
7171
7172 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 1)
7173 return Qnil;
7174
7175 return Qt;
7176 }
7177
7178 DEFUN ("x-display-pixel-width", Fx_display_pixel_width, Sx_display_pixel_width,
7179 0, 1, 0,
7180 "Returns the width in pixels of the X display DISPLAY.\n\
7181 The optional argument DISPLAY specifies which display to ask about.\n\
7182 DISPLAY should be either a frame or a display name (a string).\n\
7183 If omitted or nil, that stands for the selected frame's display.")
7184 (display)
7185 Lisp_Object display;
7186 {
7187 struct w32_display_info *dpyinfo = check_x_display_info (display);
7188
7189 return make_number (dpyinfo->width);
7190 }
7191
7192 DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
7193 Sx_display_pixel_height, 0, 1, 0,
7194 "Returns the height in pixels of the X display DISPLAY.\n\
7195 The optional argument DISPLAY specifies which display to ask about.\n\
7196 DISPLAY should be either a frame or a display name (a string).\n\
7197 If omitted or nil, that stands for the selected frame's display.")
7198 (display)
7199 Lisp_Object display;
7200 {
7201 struct w32_display_info *dpyinfo = check_x_display_info (display);
7202
7203 return make_number (dpyinfo->height);
7204 }
7205
7206 DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
7207 0, 1, 0,
7208 "Returns the number of bitplanes of the display DISPLAY.\n\
7209 The optional argument DISPLAY specifies which display to ask about.\n\
7210 DISPLAY should be either a frame or a display name (a string).\n\
7211 If omitted or nil, that stands for the selected frame's display.")
7212 (display)
7213 Lisp_Object display;
7214 {
7215 struct w32_display_info *dpyinfo = check_x_display_info (display);
7216
7217 return make_number (dpyinfo->n_planes * dpyinfo->n_cbits);
7218 }
7219
7220 DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
7221 0, 1, 0,
7222 "Returns the number of color cells of the display DISPLAY.\n\
7223 The optional argument DISPLAY specifies which display to ask about.\n\
7224 DISPLAY should be either a frame or a display name (a string).\n\
7225 If omitted or nil, that stands for the selected frame's display.")
7226 (display)
7227 Lisp_Object display;
7228 {
7229 struct w32_display_info *dpyinfo = check_x_display_info (display);
7230 HDC hdc;
7231 int cap;
7232
7233 hdc = GetDC (dpyinfo->root_window);
7234 if (dpyinfo->has_palette)
7235 cap = GetDeviceCaps (hdc,SIZEPALETTE);
7236 else
7237 cap = GetDeviceCaps (hdc,NUMCOLORS);
7238
7239 if (cap < 0)
7240 cap = 1 << (dpyinfo->n_planes * dpyinfo->n_cbits);
7241
7242 ReleaseDC (dpyinfo->root_window, hdc);
7243
7244 return make_number (cap);
7245 }
7246
7247 DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
7248 Sx_server_max_request_size,
7249 0, 1, 0,
7250 "Returns the maximum request size of the server of display DISPLAY.\n\
7251 The optional argument DISPLAY specifies which display to ask about.\n\
7252 DISPLAY should be either a frame or a display name (a string).\n\
7253 If omitted or nil, that stands for the selected frame's display.")
7254 (display)
7255 Lisp_Object display;
7256 {
7257 struct w32_display_info *dpyinfo = check_x_display_info (display);
7258
7259 return make_number (1);
7260 }
7261
7262 DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
7263 "Returns the vendor ID string of the W32 system (Microsoft).\n\
7264 The optional argument DISPLAY specifies which display to ask about.\n\
7265 DISPLAY should be either a frame or a display name (a string).\n\
7266 If omitted or nil, that stands for the selected frame's display.")
7267 (display)
7268 Lisp_Object display;
7269 {
7270 return build_string ("Microsoft Corp.");
7271 }
7272
7273 DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
7274 "Returns the version numbers of the server of display DISPLAY.\n\
7275 The value is a list of three integers: the major and minor\n\
7276 version numbers, and the vendor-specific release\n\
7277 number. See also the function `x-server-vendor'.\n\n\
7278 The optional argument DISPLAY specifies which display to ask about.\n\
7279 DISPLAY should be either a frame or a display name (a string).\n\
7280 If omitted or nil, that stands for the selected frame's display.")
7281 (display)
7282 Lisp_Object display;
7283 {
7284 return Fcons (make_number (w32_major_version),
7285 Fcons (make_number (w32_minor_version),
7286 Fcons (make_number (w32_build_number), Qnil)));
7287 }
7288
7289 DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
7290 "Returns the number of screens on the server of display DISPLAY.\n\
7291 The optional argument DISPLAY specifies which display to ask about.\n\
7292 DISPLAY should be either a frame or a display name (a string).\n\
7293 If omitted or nil, that stands for the selected frame's display.")
7294 (display)
7295 Lisp_Object display;
7296 {
7297 return make_number (1);
7298 }
7299
7300 DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height, 0, 1, 0,
7301 "Returns the height in millimeters of the X display DISPLAY.\n\
7302 The optional argument DISPLAY specifies which display to ask about.\n\
7303 DISPLAY should be either a frame or a display name (a string).\n\
7304 If omitted or nil, that stands for the selected frame's display.")
7305 (display)
7306 Lisp_Object display;
7307 {
7308 struct w32_display_info *dpyinfo = check_x_display_info (display);
7309 HDC hdc;
7310 int cap;
7311
7312 hdc = GetDC (dpyinfo->root_window);
7313
7314 cap = GetDeviceCaps (hdc, VERTSIZE);
7315
7316 ReleaseDC (dpyinfo->root_window, hdc);
7317
7318 return make_number (cap);
7319 }
7320
7321 DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
7322 "Returns the width in millimeters of the X display DISPLAY.\n\
7323 The optional argument DISPLAY specifies which display to ask about.\n\
7324 DISPLAY should be either a frame or a display name (a string).\n\
7325 If omitted or nil, that stands for the selected frame's display.")
7326 (display)
7327 Lisp_Object display;
7328 {
7329 struct w32_display_info *dpyinfo = check_x_display_info (display);
7330
7331 HDC hdc;
7332 int cap;
7333
7334 hdc = GetDC (dpyinfo->root_window);
7335
7336 cap = GetDeviceCaps (hdc, HORZSIZE);
7337
7338 ReleaseDC (dpyinfo->root_window, hdc);
7339
7340 return make_number (cap);
7341 }
7342
7343 DEFUN ("x-display-backing-store", Fx_display_backing_store,
7344 Sx_display_backing_store, 0, 1, 0,
7345 "Returns an indication of whether display DISPLAY does backing store.\n\
7346 The value may be `always', `when-mapped', or `not-useful'.\n\
7347 The optional argument DISPLAY specifies which display to ask about.\n\
7348 DISPLAY should be either a frame or a display name (a string).\n\
7349 If omitted or nil, that stands for the selected frame's display.")
7350 (display)
7351 Lisp_Object display;
7352 {
7353 return intern ("not-useful");
7354 }
7355
7356 DEFUN ("x-display-visual-class", Fx_display_visual_class,
7357 Sx_display_visual_class, 0, 1, 0,
7358 "Returns the visual class of the display DISPLAY.\n\
7359 The value is one of the symbols `static-gray', `gray-scale',\n\
7360 `static-color', `pseudo-color', `true-color', or `direct-color'.\n\n\
7361 The optional argument DISPLAY specifies which display to ask about.\n\
7362 DISPLAY should be either a frame or a display name (a string).\n\
7363 If omitted or nil, that stands for the selected frame's display.")
7364 (display)
7365 Lisp_Object display;
7366 {
7367 struct w32_display_info *dpyinfo = check_x_display_info (display);
7368 Lisp_Object result = Qnil;
7369
7370 if (dpyinfo->has_palette)
7371 result = intern ("pseudo-color");
7372 else if (dpyinfo->n_planes * dpyinfo->n_cbits == 1)
7373 result = intern ("static-grey");
7374 else if (dpyinfo->n_planes * dpyinfo->n_cbits == 4)
7375 result = intern ("static-color");
7376 else if (dpyinfo->n_planes * dpyinfo->n_cbits > 8)
7377 result = intern ("true-color");
7378
7379 return result;
7380 }
7381
7382 DEFUN ("x-display-save-under", Fx_display_save_under,
7383 Sx_display_save_under, 0, 1, 0,
7384 "Returns t if the display DISPLAY supports the save-under feature.\n\
7385 The optional argument DISPLAY specifies which display to ask about.\n\
7386 DISPLAY should be either a frame or a display name (a string).\n\
7387 If omitted or nil, that stands for the selected frame's display.")
7388 (display)
7389 Lisp_Object display;
7390 {
7391 return Qnil;
7392 }
7393 \f
7394 int
7395 x_pixel_width (f)
7396 register struct frame *f;
7397 {
7398 return PIXEL_WIDTH (f);
7399 }
7400
7401 int
7402 x_pixel_height (f)
7403 register struct frame *f;
7404 {
7405 return PIXEL_HEIGHT (f);
7406 }
7407
7408 int
7409 x_char_width (f)
7410 register struct frame *f;
7411 {
7412 return FONT_WIDTH (f->output_data.w32->font);
7413 }
7414
7415 int
7416 x_char_height (f)
7417 register struct frame *f;
7418 {
7419 return f->output_data.w32->line_height;
7420 }
7421
7422 int
7423 x_screen_planes (f)
7424 register struct frame *f;
7425 {
7426 return FRAME_W32_DISPLAY_INFO (f)->n_planes;
7427 }
7428 \f
7429 /* Return the display structure for the display named NAME.
7430 Open a new connection if necessary. */
7431
7432 struct w32_display_info *
7433 x_display_info_for_name (name)
7434 Lisp_Object name;
7435 {
7436 Lisp_Object names;
7437 struct w32_display_info *dpyinfo;
7438
7439 CHECK_STRING (name, 0);
7440
7441 for (dpyinfo = &one_w32_display_info, names = w32_display_name_list;
7442 dpyinfo;
7443 dpyinfo = dpyinfo->next, names = XCDR (names))
7444 {
7445 Lisp_Object tem;
7446 tem = Fstring_equal (XCAR (XCAR (names)), name);
7447 if (!NILP (tem))
7448 return dpyinfo;
7449 }
7450
7451 /* Use this general default value to start with. */
7452 Vx_resource_name = Vinvocation_name;
7453
7454 validate_x_resource_name ();
7455
7456 dpyinfo = w32_term_init (name, (unsigned char *)0,
7457 (char *) XSTRING (Vx_resource_name)->data);
7458
7459 if (dpyinfo == 0)
7460 error ("Cannot connect to server %s", XSTRING (name)->data);
7461
7462 w32_in_use = 1;
7463 XSETFASTINT (Vwindow_system_version, 3);
7464
7465 return dpyinfo;
7466 }
7467
7468 DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
7469 1, 3, 0, "Open a connection to a server.\n\
7470 DISPLAY is the name of the display to connect to.\n\
7471 Optional second arg XRM-STRING is a string of resources in xrdb format.\n\
7472 If the optional third arg MUST-SUCCEED is non-nil,\n\
7473 terminate Emacs if we can't open the connection.")
7474 (display, xrm_string, must_succeed)
7475 Lisp_Object display, xrm_string, must_succeed;
7476 {
7477 unsigned char *xrm_option;
7478 struct w32_display_info *dpyinfo;
7479
7480 CHECK_STRING (display, 0);
7481 if (! NILP (xrm_string))
7482 CHECK_STRING (xrm_string, 1);
7483
7484 if (! EQ (Vwindow_system, intern ("w32")))
7485 error ("Not using Microsoft Windows");
7486
7487 /* Allow color mapping to be defined externally; first look in user's
7488 HOME directory, then in Emacs etc dir for a file called rgb.txt. */
7489 {
7490 Lisp_Object color_file;
7491 struct gcpro gcpro1;
7492
7493 color_file = build_string("~/rgb.txt");
7494
7495 GCPRO1 (color_file);
7496
7497 if (NILP (Ffile_readable_p (color_file)))
7498 color_file =
7499 Fexpand_file_name (build_string ("rgb.txt"),
7500 Fsymbol_value (intern ("data-directory")));
7501
7502 Vw32_color_map = Fw32_load_color_file (color_file);
7503
7504 UNGCPRO;
7505 }
7506 if (NILP (Vw32_color_map))
7507 Vw32_color_map = Fw32_default_color_map ();
7508
7509 if (! NILP (xrm_string))
7510 xrm_option = (unsigned char *) XSTRING (xrm_string)->data;
7511 else
7512 xrm_option = (unsigned char *) 0;
7513
7514 /* Use this general default value to start with. */
7515 /* First remove .exe suffix from invocation-name - it looks ugly. */
7516 {
7517 char basename[ MAX_PATH ], *str;
7518
7519 strcpy (basename, XSTRING (Vinvocation_name)->data);
7520 str = strrchr (basename, '.');
7521 if (str) *str = 0;
7522 Vinvocation_name = build_string (basename);
7523 }
7524 Vx_resource_name = Vinvocation_name;
7525
7526 validate_x_resource_name ();
7527
7528 /* This is what opens the connection and sets x_current_display.
7529 This also initializes many symbols, such as those used for input. */
7530 dpyinfo = w32_term_init (display, xrm_option,
7531 (char *) XSTRING (Vx_resource_name)->data);
7532
7533 if (dpyinfo == 0)
7534 {
7535 if (!NILP (must_succeed))
7536 fatal ("Cannot connect to server %s.\n",
7537 XSTRING (display)->data);
7538 else
7539 error ("Cannot connect to server %s", XSTRING (display)->data);
7540 }
7541
7542 w32_in_use = 1;
7543
7544 XSETFASTINT (Vwindow_system_version, 3);
7545 return Qnil;
7546 }
7547
7548 DEFUN ("x-close-connection", Fx_close_connection,
7549 Sx_close_connection, 1, 1, 0,
7550 "Close the connection to DISPLAY's server.\n\
7551 For DISPLAY, specify either a frame or a display name (a string).\n\
7552 If DISPLAY is nil, that stands for the selected frame's display.")
7553 (display)
7554 Lisp_Object display;
7555 {
7556 struct w32_display_info *dpyinfo = check_x_display_info (display);
7557 int i;
7558
7559 if (dpyinfo->reference_count > 0)
7560 error ("Display still has frames on it");
7561
7562 BLOCK_INPUT;
7563 /* Free the fonts in the font table. */
7564 for (i = 0; i < dpyinfo->n_fonts; i++)
7565 if (dpyinfo->font_table[i].name)
7566 {
7567 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
7568 xfree (dpyinfo->font_table[i].full_name);
7569 xfree (dpyinfo->font_table[i].name);
7570 w32_unload_font (dpyinfo, dpyinfo->font_table[i].font);
7571 }
7572 x_destroy_all_bitmaps (dpyinfo);
7573
7574 x_delete_display (dpyinfo);
7575 UNBLOCK_INPUT;
7576
7577 return Qnil;
7578 }
7579
7580 DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
7581 "Return the list of display names that Emacs has connections to.")
7582 ()
7583 {
7584 Lisp_Object tail, result;
7585
7586 result = Qnil;
7587 for (tail = w32_display_name_list; ! NILP (tail); tail = XCDR (tail))
7588 result = Fcons (XCAR (XCAR (tail)), result);
7589
7590 return result;
7591 }
7592
7593 DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0,
7594 "If ON is non-nil, report errors as soon as the erring request is made.\n\
7595 If ON is nil, allow buffering of requests.\n\
7596 This is a noop on W32 systems.\n\
7597 The optional second argument DISPLAY specifies which display to act on.\n\
7598 DISPLAY should be either a frame or a display name (a string).\n\
7599 If DISPLAY is omitted or nil, that stands for the selected frame's display.")
7600 (on, display)
7601 Lisp_Object display, on;
7602 {
7603 return Qnil;
7604 }
7605
7606 \f
7607 \f
7608 /***********************************************************************
7609 Image types
7610 ***********************************************************************/
7611
7612 /* Value is the number of elements of vector VECTOR. */
7613
7614 #define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))
7615
7616 /* List of supported image types. Use define_image_type to add new
7617 types. Use lookup_image_type to find a type for a given symbol. */
7618
7619 static struct image_type *image_types;
7620
7621 /* The symbol `image' which is the car of the lists used to represent
7622 images in Lisp. */
7623
7624 extern Lisp_Object Qimage;
7625
7626 /* The symbol `xbm' which is used as the type symbol for XBM images. */
7627
7628 Lisp_Object Qxbm;
7629
7630 /* Keywords. */
7631
7632 extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
7633 extern Lisp_Object QCdata;
7634 Lisp_Object QCtype, QCascent, QCmargin, QCrelief;
7635 Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask;
7636 Lisp_Object QCindex;
7637
7638 /* Other symbols. */
7639
7640 Lisp_Object Qlaplace;
7641
7642 /* Time in seconds after which images should be removed from the cache
7643 if not displayed. */
7644
7645 Lisp_Object Vimage_cache_eviction_delay;
7646
7647 /* Function prototypes. */
7648
7649 static void define_image_type P_ ((struct image_type *type));
7650 static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
7651 static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
7652 static void x_laplace P_ ((struct frame *, struct image *));
7653 static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
7654 Lisp_Object));
7655
7656
7657 /* Define a new image type from TYPE. This adds a copy of TYPE to
7658 image_types and adds the symbol *TYPE->type to Vimage_types. */
7659
7660 static void
7661 define_image_type (type)
7662 struct image_type *type;
7663 {
7664 /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
7665 The initialized data segment is read-only. */
7666 struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
7667 bcopy (type, p, sizeof *p);
7668 p->next = image_types;
7669 image_types = p;
7670 Vimage_types = Fcons (*p->type, Vimage_types);
7671 }
7672
7673
7674 /* Look up image type SYMBOL, and return a pointer to its image_type
7675 structure. Value is null if SYMBOL is not a known image type. */
7676
7677 static INLINE struct image_type *
7678 lookup_image_type (symbol)
7679 Lisp_Object symbol;
7680 {
7681 struct image_type *type;
7682
7683 for (type = image_types; type; type = type->next)
7684 if (EQ (symbol, *type->type))
7685 break;
7686
7687 return type;
7688 }
7689
7690
7691 /* Value is non-zero if OBJECT is a valid Lisp image specification. A
7692 valid image specification is a list whose car is the symbol
7693 `image', and whose rest is a property list. The property list must
7694 contain a value for key `:type'. That value must be the name of a
7695 supported image type. The rest of the property list depends on the
7696 image type. */
7697
7698 int
7699 valid_image_p (object)
7700 Lisp_Object object;
7701 {
7702 int valid_p = 0;
7703
7704 if (CONSP (object) && EQ (XCAR (object), Qimage))
7705 {
7706 Lisp_Object symbol = Fplist_get (XCDR (object), QCtype);
7707 struct image_type *type = lookup_image_type (symbol);
7708
7709 if (type)
7710 valid_p = type->valid_p (object);
7711 }
7712
7713 return valid_p;
7714 }
7715
7716
7717 /* Log error message with format string FORMAT and argument ARG.
7718 Signaling an error, e.g. when an image cannot be loaded, is not a
7719 good idea because this would interrupt redisplay, and the error
7720 message display would lead to another redisplay. This function
7721 therefore simply displays a message. */
7722
7723 static void
7724 image_error (format, arg1, arg2)
7725 char *format;
7726 Lisp_Object arg1, arg2;
7727 {
7728 add_to_log (format, arg1, arg2);
7729 }
7730
7731
7732 \f
7733 /***********************************************************************
7734 Image specifications
7735 ***********************************************************************/
7736
7737 enum image_value_type
7738 {
7739 IMAGE_DONT_CHECK_VALUE_TYPE,
7740 IMAGE_STRING_VALUE,
7741 IMAGE_SYMBOL_VALUE,
7742 IMAGE_POSITIVE_INTEGER_VALUE,
7743 IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,
7744 IMAGE_NON_NEGATIVE_INTEGER_VALUE,
7745 IMAGE_ASCENT_VALUE,
7746 IMAGE_INTEGER_VALUE,
7747 IMAGE_FUNCTION_VALUE,
7748 IMAGE_NUMBER_VALUE,
7749 IMAGE_BOOL_VALUE
7750 };
7751
7752 /* Structure used when parsing image specifications. */
7753
7754 struct image_keyword
7755 {
7756 /* Name of keyword. */
7757 char *name;
7758
7759 /* The type of value allowed. */
7760 enum image_value_type type;
7761
7762 /* Non-zero means key must be present. */
7763 int mandatory_p;
7764
7765 /* Used to recognize duplicate keywords in a property list. */
7766 int count;
7767
7768 /* The value that was found. */
7769 Lisp_Object value;
7770 };
7771
7772
7773 static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
7774 int, Lisp_Object));
7775 static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
7776
7777
7778 /* Parse image spec SPEC according to KEYWORDS. A valid image spec
7779 has the format (image KEYWORD VALUE ...). One of the keyword/
7780 value pairs must be `:type TYPE'. KEYWORDS is a vector of
7781 image_keywords structures of size NKEYWORDS describing other
7782 allowed keyword/value pairs. Value is non-zero if SPEC is valid. */
7783
7784 static int
7785 parse_image_spec (spec, keywords, nkeywords, type)
7786 Lisp_Object spec;
7787 struct image_keyword *keywords;
7788 int nkeywords;
7789 Lisp_Object type;
7790 {
7791 int i;
7792 Lisp_Object plist;
7793
7794 if (!CONSP (spec) || !EQ (XCAR (spec), Qimage))
7795 return 0;
7796
7797 plist = XCDR (spec);
7798 while (CONSP (plist))
7799 {
7800 Lisp_Object key, value;
7801
7802 /* First element of a pair must be a symbol. */
7803 key = XCAR (plist);
7804 plist = XCDR (plist);
7805 if (!SYMBOLP (key))
7806 return 0;
7807
7808 /* There must follow a value. */
7809 if (!CONSP (plist))
7810 return 0;
7811 value = XCAR (plist);
7812 plist = XCDR (plist);
7813
7814 /* Find key in KEYWORDS. Error if not found. */
7815 for (i = 0; i < nkeywords; ++i)
7816 if (strcmp (keywords[i].name, XSYMBOL (key)->name->data) == 0)
7817 break;
7818
7819 if (i == nkeywords)
7820 continue;
7821
7822 /* Record that we recognized the keyword. If a keywords
7823 was found more than once, it's an error. */
7824 keywords[i].value = value;
7825 ++keywords[i].count;
7826
7827 if (keywords[i].count > 1)
7828 return 0;
7829
7830 /* Check type of value against allowed type. */
7831 switch (keywords[i].type)
7832 {
7833 case IMAGE_STRING_VALUE:
7834 if (!STRINGP (value))
7835 return 0;
7836 break;
7837
7838 case IMAGE_SYMBOL_VALUE:
7839 if (!SYMBOLP (value))
7840 return 0;
7841 break;
7842
7843 case IMAGE_POSITIVE_INTEGER_VALUE:
7844 if (!INTEGERP (value) || XINT (value) <= 0)
7845 return 0;
7846 break;
7847
7848 case IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR:
7849 if (INTEGERP (value) && XINT (value) >= 0)
7850 break;
7851 if (CONSP (value)
7852 && INTEGERP (XCAR (value)) && INTEGERP (XCDR (value))
7853 && XINT (XCAR (value)) >= 0 && XINT (XCDR (value)) >= 0)
7854 break;
7855 return 0;
7856
7857 case IMAGE_ASCENT_VALUE:
7858 if (SYMBOLP (value) && EQ (value, Qcenter))
7859 break;
7860 else if (INTEGERP (value)
7861 && XINT (value) >= 0
7862 && XINT (value) <= 100)
7863 break;
7864 return 0;
7865
7866 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
7867 if (!INTEGERP (value) || XINT (value) < 0)
7868 return 0;
7869 break;
7870
7871 case IMAGE_DONT_CHECK_VALUE_TYPE:
7872 break;
7873
7874 case IMAGE_FUNCTION_VALUE:
7875 value = indirect_function (value);
7876 if (SUBRP (value)
7877 || COMPILEDP (value)
7878 || (CONSP (value) && EQ (XCAR (value), Qlambda)))
7879 break;
7880 return 0;
7881
7882 case IMAGE_NUMBER_VALUE:
7883 if (!INTEGERP (value) && !FLOATP (value))
7884 return 0;
7885 break;
7886
7887 case IMAGE_INTEGER_VALUE:
7888 if (!INTEGERP (value))
7889 return 0;
7890 break;
7891
7892 case IMAGE_BOOL_VALUE:
7893 if (!NILP (value) && !EQ (value, Qt))
7894 return 0;
7895 break;
7896
7897 default:
7898 abort ();
7899 break;
7900 }
7901
7902 if (EQ (key, QCtype) && !EQ (type, value))
7903 return 0;
7904 }
7905
7906 /* Check that all mandatory fields are present. */
7907 for (i = 0; i < nkeywords; ++i)
7908 if (keywords[i].mandatory_p && keywords[i].count == 0)
7909 return 0;
7910
7911 return NILP (plist);
7912 }
7913
7914
7915 /* Return the value of KEY in image specification SPEC. Value is nil
7916 if KEY is not present in SPEC. if FOUND is not null, set *FOUND
7917 to 1 if KEY was found in SPEC, set it to 0 otherwise. */
7918
7919 static Lisp_Object
7920 image_spec_value (spec, key, found)
7921 Lisp_Object spec, key;
7922 int *found;
7923 {
7924 Lisp_Object tail;
7925
7926 xassert (valid_image_p (spec));
7927
7928 for (tail = XCDR (spec);
7929 CONSP (tail) && CONSP (XCDR (tail));
7930 tail = XCDR (XCDR (tail)))
7931 {
7932 if (EQ (XCAR (tail), key))
7933 {
7934 if (found)
7935 *found = 1;
7936 return XCAR (XCDR (tail));
7937 }
7938 }
7939
7940 if (found)
7941 *found = 0;
7942 return Qnil;
7943 }
7944
7945
7946
7947 \f
7948 /***********************************************************************
7949 Image type independent image structures
7950 ***********************************************************************/
7951
7952 static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
7953 static void free_image P_ ((struct frame *f, struct image *img));
7954
7955
7956 /* Allocate and return a new image structure for image specification
7957 SPEC. SPEC has a hash value of HASH. */
7958
7959 static struct image *
7960 make_image (spec, hash)
7961 Lisp_Object spec;
7962 unsigned hash;
7963 {
7964 struct image *img = (struct image *) xmalloc (sizeof *img);
7965
7966 xassert (valid_image_p (spec));
7967 bzero (img, sizeof *img);
7968 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
7969 xassert (img->type != NULL);
7970 img->spec = spec;
7971 img->data.lisp_val = Qnil;
7972 img->ascent = DEFAULT_IMAGE_ASCENT;
7973 img->hash = hash;
7974 return img;
7975 }
7976
7977
7978 /* Free image IMG which was used on frame F, including its resources. */
7979
7980 static void
7981 free_image (f, img)
7982 struct frame *f;
7983 struct image *img;
7984 {
7985 if (img)
7986 {
7987 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
7988
7989 /* Remove IMG from the hash table of its cache. */
7990 if (img->prev)
7991 img->prev->next = img->next;
7992 else
7993 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
7994
7995 if (img->next)
7996 img->next->prev = img->prev;
7997
7998 c->images[img->id] = NULL;
7999
8000 /* Free resources, then free IMG. */
8001 img->type->free (f, img);
8002 xfree (img);
8003 }
8004 }
8005
8006
8007 /* Prepare image IMG for display on frame F. Must be called before
8008 drawing an image. */
8009
8010 void
8011 prepare_image_for_display (f, img)
8012 struct frame *f;
8013 struct image *img;
8014 {
8015 EMACS_TIME t;
8016
8017 /* We're about to display IMG, so set its timestamp to `now'. */
8018 EMACS_GET_TIME (t);
8019 img->timestamp = EMACS_SECS (t);
8020
8021 /* If IMG doesn't have a pixmap yet, load it now, using the image
8022 type dependent loader function. */
8023 if (img->pixmap == 0 && !img->load_failed_p)
8024 img->load_failed_p = img->type->load (f, img) == 0;
8025 }
8026
8027
8028 /* Value is the number of pixels for the ascent of image IMG when
8029 drawn in face FACE. */
8030
8031 int
8032 image_ascent (img, face)
8033 struct image *img;
8034 struct face *face;
8035 {
8036 int height = img->height + img->vmargin;
8037 int ascent;
8038
8039 if (img->ascent == CENTERED_IMAGE_ASCENT)
8040 {
8041 if (face->font)
8042 ascent = height / 2 - (FONT_DESCENT(face->font)
8043 - FONT_BASE(face->font)) / 2;
8044 else
8045 ascent = height / 2;
8046 }
8047 else
8048 ascent = height * img->ascent / 100.0;
8049
8050 return ascent;
8051 }
8052
8053
8054 \f
8055 /***********************************************************************
8056 Helper functions for X image types
8057 ***********************************************************************/
8058
8059 static void x_clear_image P_ ((struct frame *f, struct image *img));
8060 static unsigned long x_alloc_image_color P_ ((struct frame *f,
8061 struct image *img,
8062 Lisp_Object color_name,
8063 unsigned long dflt));
8064
8065 /* Free X resources of image IMG which is used on frame F. */
8066
8067 static void
8068 x_clear_image (f, img)
8069 struct frame *f;
8070 struct image *img;
8071 {
8072 #if 0 /* TODO: W32 image support */
8073
8074 if (img->pixmap)
8075 {
8076 BLOCK_INPUT;
8077 XFreePixmap (NULL, img->pixmap);
8078 img->pixmap = 0;
8079 UNBLOCK_INPUT;
8080 }
8081
8082 if (img->ncolors)
8083 {
8084 int class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
8085
8086 /* If display has an immutable color map, freeing colors is not
8087 necessary and some servers don't allow it. So don't do it. */
8088 if (class != StaticColor
8089 && class != StaticGray
8090 && class != TrueColor)
8091 {
8092 Colormap cmap;
8093 BLOCK_INPUT;
8094 cmap = DefaultColormapOfScreen (FRAME_W32_DISPLAY_INFO (f)->screen);
8095 XFreeColors (FRAME_W32_DISPLAY (f), cmap, img->colors,
8096 img->ncolors, 0);
8097 UNBLOCK_INPUT;
8098 }
8099
8100 xfree (img->colors);
8101 img->colors = NULL;
8102 img->ncolors = 0;
8103 }
8104 #endif
8105 }
8106
8107
8108 /* Allocate color COLOR_NAME for image IMG on frame F. If color
8109 cannot be allocated, use DFLT. Add a newly allocated color to
8110 IMG->colors, so that it can be freed again. Value is the pixel
8111 color. */
8112
8113 static unsigned long
8114 x_alloc_image_color (f, img, color_name, dflt)
8115 struct frame *f;
8116 struct image *img;
8117 Lisp_Object color_name;
8118 unsigned long dflt;
8119 {
8120 #if 0 /* TODO: allocing colors. */
8121 XColor color;
8122 unsigned long result;
8123
8124 xassert (STRINGP (color_name));
8125
8126 if (w32_defined_color (f, XSTRING (color_name)->data, &color, 1))
8127 {
8128 /* This isn't called frequently so we get away with simply
8129 reallocating the color vector to the needed size, here. */
8130 ++img->ncolors;
8131 img->colors =
8132 (unsigned long *) xrealloc (img->colors,
8133 img->ncolors * sizeof *img->colors);
8134 img->colors[img->ncolors - 1] = color.pixel;
8135 result = color.pixel;
8136 }
8137 else
8138 result = dflt;
8139 return result;
8140 #endif
8141 return 0;
8142 }
8143
8144
8145 \f
8146 /***********************************************************************
8147 Image Cache
8148 ***********************************************************************/
8149
8150 static void cache_image P_ ((struct frame *f, struct image *img));
8151
8152
8153 /* Return a new, initialized image cache that is allocated from the
8154 heap. Call free_image_cache to free an image cache. */
8155
8156 struct image_cache *
8157 make_image_cache ()
8158 {
8159 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
8160 int size;
8161
8162 bzero (c, sizeof *c);
8163 c->size = 50;
8164 c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
8165 size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
8166 c->buckets = (struct image **) xmalloc (size);
8167 bzero (c->buckets, size);
8168 return c;
8169 }
8170
8171
8172 /* Free image cache of frame F. Be aware that X frames share images
8173 caches. */
8174
8175 void
8176 free_image_cache (f)
8177 struct frame *f;
8178 {
8179 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8180 if (c)
8181 {
8182 int i;
8183
8184 /* Cache should not be referenced by any frame when freed. */
8185 xassert (c->refcount == 0);
8186
8187 for (i = 0; i < c->used; ++i)
8188 free_image (f, c->images[i]);
8189 xfree (c->images);
8190 xfree (c);
8191 xfree (c->buckets);
8192 FRAME_X_IMAGE_CACHE (f) = NULL;
8193 }
8194 }
8195
8196
8197 /* Clear image cache of frame F. FORCE_P non-zero means free all
8198 images. FORCE_P zero means clear only images that haven't been
8199 displayed for some time. Should be called from time to time to
8200 reduce the number of loaded images. If image-eviction-seconds is
8201 non-nil, this frees images in the cache which weren't displayed for
8202 at least that many seconds. */
8203
8204 void
8205 clear_image_cache (f, force_p)
8206 struct frame *f;
8207 int force_p;
8208 {
8209 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8210
8211 if (c && INTEGERP (Vimage_cache_eviction_delay))
8212 {
8213 EMACS_TIME t;
8214 unsigned long old;
8215 int i, any_freed_p = 0;
8216
8217 EMACS_GET_TIME (t);
8218 old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
8219
8220 for (i = 0; i < c->used; ++i)
8221 {
8222 struct image *img = c->images[i];
8223 if (img != NULL
8224 && (force_p
8225 || (img->timestamp > old)))
8226 {
8227 free_image (f, img);
8228 any_freed_p = 1;
8229 }
8230 }
8231
8232 /* We may be clearing the image cache because, for example,
8233 Emacs was iconified for a longer period of time. In that
8234 case, current matrices may still contain references to
8235 images freed above. So, clear these matrices. */
8236 if (any_freed_p)
8237 {
8238 clear_current_matrices (f);
8239 ++windows_or_buffers_changed;
8240 }
8241 }
8242 }
8243
8244
8245 DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
8246 0, 1, 0,
8247 "Clear the image cache of FRAME.\n\
8248 FRAME nil or omitted means use the selected frame.\n\
8249 FRAME t means clear the image caches of all frames.")
8250 (frame)
8251 Lisp_Object frame;
8252 {
8253 if (EQ (frame, Qt))
8254 {
8255 Lisp_Object tail;
8256
8257 FOR_EACH_FRAME (tail, frame)
8258 if (FRAME_W32_P (XFRAME (frame)))
8259 clear_image_cache (XFRAME (frame), 1);
8260 }
8261 else
8262 clear_image_cache (check_x_frame (frame), 1);
8263
8264 return Qnil;
8265 }
8266
8267
8268 /* Return the id of image with Lisp specification SPEC on frame F.
8269 SPEC must be a valid Lisp image specification (see valid_image_p). */
8270
8271 int
8272 lookup_image (f, spec)
8273 struct frame *f;
8274 Lisp_Object spec;
8275 {
8276 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8277 struct image *img;
8278 int i;
8279 unsigned hash;
8280 struct gcpro gcpro1;
8281 EMACS_TIME now;
8282
8283 /* F must be a window-system frame, and SPEC must be a valid image
8284 specification. */
8285 xassert (FRAME_WINDOW_P (f));
8286 xassert (valid_image_p (spec));
8287
8288 GCPRO1 (spec);
8289
8290 /* Look up SPEC in the hash table of the image cache. */
8291 hash = sxhash (spec, 0);
8292 i = hash % IMAGE_CACHE_BUCKETS_SIZE;
8293
8294 for (img = c->buckets[i]; img; img = img->next)
8295 if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
8296 break;
8297
8298 /* If not found, create a new image and cache it. */
8299 if (img == NULL)
8300 {
8301 BLOCK_INPUT;
8302 img = make_image (spec, hash);
8303 cache_image (f, img);
8304 img->load_failed_p = img->type->load (f, img) == 0;
8305
8306 /* If we can't load the image, and we don't have a width and
8307 height, use some arbitrary width and height so that we can
8308 draw a rectangle for it. */
8309 if (img->load_failed_p)
8310 {
8311 Lisp_Object value;
8312
8313 value = image_spec_value (spec, QCwidth, NULL);
8314 img->width = (INTEGERP (value)
8315 ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH);
8316 value = image_spec_value (spec, QCheight, NULL);
8317 img->height = (INTEGERP (value)
8318 ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT);
8319 }
8320 else
8321 {
8322 /* Handle image type independent image attributes
8323 `:ascent PERCENT', `:margin MARGIN', `:relief RELIEF'. */
8324 Lisp_Object ascent, margin, relief;
8325
8326 ascent = image_spec_value (spec, QCascent, NULL);
8327 if (INTEGERP (ascent))
8328 img->ascent = XFASTINT (ascent);
8329 else if (EQ (ascent, Qcenter))
8330 img->ascent = CENTERED_IMAGE_ASCENT;
8331
8332 margin = image_spec_value (spec, QCmargin, NULL);
8333 if (INTEGERP (margin) && XINT (margin) >= 0)
8334 img->vmargin = img->hmargin = XFASTINT (margin);
8335 else if (CONSP (margin) && INTEGERP (XCAR (margin))
8336 && INTEGERP (XCDR (margin)))
8337 {
8338 if (XINT (XCAR (margin)) > 0)
8339 img->hmargin = XFASTINT (XCAR (margin));
8340 if (XINT (XCDR (margin)) > 0)
8341 img->vmargin = XFASTINT (XCDR (margin));
8342 }
8343
8344 relief = image_spec_value (spec, QCrelief, NULL);
8345 if (INTEGERP (relief))
8346 {
8347 img->relief = XINT (relief);
8348 img->hmargin += abs (img->relief);
8349 img->vmargin += abs (img->relief);
8350 }
8351
8352 #if 0 /* TODO: image mask and algorithm. */
8353 /* Manipulation of the image's mask. */
8354 if (img->pixmap)
8355 {
8356 /* `:heuristic-mask t'
8357 `:mask heuristic'
8358 means build a mask heuristically.
8359 `:heuristic-mask (R G B)'
8360 `:mask (heuristic (R G B))'
8361 means build a mask from color (R G B) in the
8362 image.
8363 `:mask nil'
8364 means remove a mask, if any. */
8365
8366 Lisp_Object mask;
8367
8368 mask = image_spec_value (spec, QCheuristic_mask, NULL);
8369 if (!NILP (mask))
8370 x_build_heuristic_mask (f, img, mask);
8371 else
8372 {
8373 int found_p;
8374
8375 mask = image_spec_value (spec, QCmask, &found_p);
8376
8377 if (EQ (mask, Qheuristic))
8378 x_build_heuristic_mask (f, img, Qt);
8379 else if (CONSP (mask)
8380 && EQ (XCAR (mask), Qheuristic))
8381 {
8382 if (CONSP (XCDR (mask)))
8383 x_build_heuristic_mask (f, img, XCAR (XCDR (mask)));
8384 else
8385 x_build_heuristic_mask (f, img, XCDR (mask));
8386 }
8387 else if (NILP (mask) && found_p && img->mask)
8388 {
8389 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
8390 img->mask = None;
8391 }
8392 }
8393 }
8394
8395 /* Should we apply an image transformation algorithm? */
8396 if (img->pixmap)
8397 {
8398 Lisp_Object conversion;
8399
8400 algorithm = image_spec_value (spec, QCconversion, NULL);
8401 if (EQ (conversion, Qdisabled))
8402 x_disable_image (f, img);
8403 else if (EQ (conversion, Qlaplace))
8404 x_laplace (f, img);
8405 else if (EQ (conversion, Qemboss))
8406 x_emboss (f, img);
8407 else if (CONSP (conversion)
8408 && EQ (XCAR (conversion), Qedge_detection))
8409 {
8410 Lisp_Object tem;
8411 tem = XCDR (conversion);
8412 if (CONSP (tem))
8413 x_edge_detection (f, img,
8414 Fplist_get (tem, QCmatrix),
8415 Fplist_get (tem, QCcolor_adjustment));
8416 }
8417 }
8418 #endif /* TODO. */
8419 }
8420 UNBLOCK_INPUT;
8421 xassert (!interrupt_input_blocked);
8422 }
8423
8424 /* We're using IMG, so set its timestamp to `now'. */
8425 EMACS_GET_TIME (now);
8426 img->timestamp = EMACS_SECS (now);
8427
8428 UNGCPRO;
8429
8430 /* Value is the image id. */
8431 return img->id;
8432 }
8433
8434
8435 /* Cache image IMG in the image cache of frame F. */
8436
8437 static void
8438 cache_image (f, img)
8439 struct frame *f;
8440 struct image *img;
8441 {
8442 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8443 int i;
8444
8445 /* Find a free slot in c->images. */
8446 for (i = 0; i < c->used; ++i)
8447 if (c->images[i] == NULL)
8448 break;
8449
8450 /* If no free slot found, maybe enlarge c->images. */
8451 if (i == c->used && c->used == c->size)
8452 {
8453 c->size *= 2;
8454 c->images = (struct image **) xrealloc (c->images,
8455 c->size * sizeof *c->images);
8456 }
8457
8458 /* Add IMG to c->images, and assign IMG an id. */
8459 c->images[i] = img;
8460 img->id = i;
8461 if (i == c->used)
8462 ++c->used;
8463
8464 /* Add IMG to the cache's hash table. */
8465 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
8466 img->next = c->buckets[i];
8467 if (img->next)
8468 img->next->prev = img;
8469 img->prev = NULL;
8470 c->buckets[i] = img;
8471 }
8472
8473
8474 /* Call FN on every image in the image cache of frame F. Used to mark
8475 Lisp Objects in the image cache. */
8476
8477 void
8478 forall_images_in_image_cache (f, fn)
8479 struct frame *f;
8480 void (*fn) P_ ((struct image *img));
8481 {
8482 if (FRAME_LIVE_P (f) && FRAME_W32_P (f))
8483 {
8484 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8485 if (c)
8486 {
8487 int i;
8488 for (i = 0; i < c->used; ++i)
8489 if (c->images[i])
8490 fn (c->images[i]);
8491 }
8492 }
8493 }
8494
8495
8496 \f
8497 /***********************************************************************
8498 W32 support code
8499 ***********************************************************************/
8500
8501 #if 0 /* TODO: W32 specific image code. */
8502
8503 static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
8504 XImage **, Pixmap *));
8505 static void x_destroy_x_image P_ ((XImage *));
8506 static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
8507
8508
8509 /* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
8510 frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created.
8511 Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
8512 via xmalloc. Print error messages via image_error if an error
8513 occurs. Value is non-zero if successful. */
8514
8515 static int
8516 x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
8517 struct frame *f;
8518 int width, height, depth;
8519 XImage **ximg;
8520 Pixmap *pixmap;
8521 {
8522 #if 0 /* TODO: Image support for W32 */
8523 Display *display = FRAME_W32_DISPLAY (f);
8524 Screen *screen = FRAME_X_SCREEN (f);
8525 Window window = FRAME_W32_WINDOW (f);
8526
8527 xassert (interrupt_input_blocked);
8528
8529 if (depth <= 0)
8530 depth = DefaultDepthOfScreen (screen);
8531 *ximg = XCreateImage (display, DefaultVisualOfScreen (screen),
8532 depth, ZPixmap, 0, NULL, width, height,
8533 depth > 16 ? 32 : depth > 8 ? 16 : 8, 0);
8534 if (*ximg == NULL)
8535 {
8536 image_error ("Unable to allocate X image", Qnil, Qnil);
8537 return 0;
8538 }
8539
8540 /* Allocate image raster. */
8541 (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height);
8542
8543 /* Allocate a pixmap of the same size. */
8544 *pixmap = XCreatePixmap (display, window, width, height, depth);
8545 if (*pixmap == 0)
8546 {
8547 x_destroy_x_image (*ximg);
8548 *ximg = NULL;
8549 image_error ("Unable to create X pixmap", Qnil, Qnil);
8550 return 0;
8551 }
8552 #endif
8553 return 1;
8554 }
8555
8556
8557 /* Destroy XImage XIMG. Free XIMG->data. */
8558
8559 static void
8560 x_destroy_x_image (ximg)
8561 XImage *ximg;
8562 {
8563 xassert (interrupt_input_blocked);
8564 if (ximg)
8565 {
8566 xfree (ximg->data);
8567 ximg->data = NULL;
8568 XDestroyImage (ximg);
8569 }
8570 }
8571
8572
8573 /* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT
8574 are width and height of both the image and pixmap. */
8575
8576 static void
8577 x_put_x_image (f, ximg, pixmap, width, height)
8578 struct frame *f;
8579 XImage *ximg;
8580 Pixmap pixmap;
8581 {
8582 GC gc;
8583
8584 xassert (interrupt_input_blocked);
8585 gc = XCreateGC (NULL, pixmap, 0, NULL);
8586 XPutImage (NULL, pixmap, gc, ximg, 0, 0, 0, 0, width, height);
8587 XFreeGC (NULL, gc);
8588 }
8589
8590 #endif
8591
8592 \f
8593 /***********************************************************************
8594 Searching files
8595 ***********************************************************************/
8596
8597 static Lisp_Object x_find_image_file P_ ((Lisp_Object));
8598
8599 /* Find image file FILE. Look in data-directory, then
8600 x-bitmap-file-path. Value is the full name of the file found, or
8601 nil if not found. */
8602
8603 static Lisp_Object
8604 x_find_image_file (file)
8605 Lisp_Object file;
8606 {
8607 Lisp_Object file_found, search_path;
8608 struct gcpro gcpro1, gcpro2;
8609 int fd;
8610
8611 file_found = Qnil;
8612 search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
8613 GCPRO2 (file_found, search_path);
8614
8615 /* Try to find FILE in data-directory, then x-bitmap-file-path. */
8616 fd = openp (search_path, file, "", &file_found, 0);
8617
8618 if (fd == -1)
8619 file_found = Qnil;
8620 else
8621 close (fd);
8622
8623 UNGCPRO;
8624 return file_found;
8625 }
8626
8627
8628 \f
8629 /***********************************************************************
8630 XBM images
8631 ***********************************************************************/
8632
8633 static int xbm_load P_ ((struct frame *f, struct image *img));
8634 static int xbm_load_image_from_file P_ ((struct frame *f, struct image *img,
8635 Lisp_Object file));
8636 static int xbm_image_p P_ ((Lisp_Object object));
8637 static int xbm_read_bitmap_file_data P_ ((char *, int *, int *,
8638 unsigned char **));
8639
8640
8641 /* Indices of image specification fields in xbm_format, below. */
8642
8643 enum xbm_keyword_index
8644 {
8645 XBM_TYPE,
8646 XBM_FILE,
8647 XBM_WIDTH,
8648 XBM_HEIGHT,
8649 XBM_DATA,
8650 XBM_FOREGROUND,
8651 XBM_BACKGROUND,
8652 XBM_ASCENT,
8653 XBM_MARGIN,
8654 XBM_RELIEF,
8655 XBM_ALGORITHM,
8656 XBM_HEURISTIC_MASK,
8657 XBM_LAST
8658 };
8659
8660 /* Vector of image_keyword structures describing the format
8661 of valid XBM image specifications. */
8662
8663 static struct image_keyword xbm_format[XBM_LAST] =
8664 {
8665 {":type", IMAGE_SYMBOL_VALUE, 1},
8666 {":file", IMAGE_STRING_VALUE, 0},
8667 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
8668 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
8669 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8670 {":foreground", IMAGE_STRING_VALUE, 0},
8671 {":background", IMAGE_STRING_VALUE, 0},
8672 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8673 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
8674 {":relief", IMAGE_INTEGER_VALUE, 0},
8675 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8676 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
8677 };
8678
8679 /* Structure describing the image type XBM. */
8680
8681 static struct image_type xbm_type =
8682 {
8683 &Qxbm,
8684 xbm_image_p,
8685 xbm_load,
8686 x_clear_image,
8687 NULL
8688 };
8689
8690 /* Tokens returned from xbm_scan. */
8691
8692 enum xbm_token
8693 {
8694 XBM_TK_IDENT = 256,
8695 XBM_TK_NUMBER
8696 };
8697
8698
8699 /* Return non-zero if OBJECT is a valid XBM-type image specification.
8700 A valid specification is a list starting with the symbol `image'
8701 The rest of the list is a property list which must contain an
8702 entry `:type xbm..
8703
8704 If the specification specifies a file to load, it must contain
8705 an entry `:file FILENAME' where FILENAME is a string.
8706
8707 If the specification is for a bitmap loaded from memory it must
8708 contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
8709 WIDTH and HEIGHT are integers > 0. DATA may be:
8710
8711 1. a string large enough to hold the bitmap data, i.e. it must
8712 have a size >= (WIDTH + 7) / 8 * HEIGHT
8713
8714 2. a bool-vector of size >= WIDTH * HEIGHT
8715
8716 3. a vector of strings or bool-vectors, one for each line of the
8717 bitmap.
8718
8719 Both the file and data forms may contain the additional entries
8720 `:background COLOR' and `:foreground COLOR'. If not present,
8721 foreground and background of the frame on which the image is
8722 displayed, is used. */
8723
8724 static int
8725 xbm_image_p (object)
8726 Lisp_Object object;
8727 {
8728 struct image_keyword kw[XBM_LAST];
8729
8730 bcopy (xbm_format, kw, sizeof kw);
8731 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
8732 return 0;
8733
8734 xassert (EQ (kw[XBM_TYPE].value, Qxbm));
8735
8736 if (kw[XBM_FILE].count)
8737 {
8738 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
8739 return 0;
8740 }
8741 else
8742 {
8743 Lisp_Object data;
8744 int width, height;
8745
8746 /* Entries for `:width', `:height' and `:data' must be present. */
8747 if (!kw[XBM_WIDTH].count
8748 || !kw[XBM_HEIGHT].count
8749 || !kw[XBM_DATA].count)
8750 return 0;
8751
8752 data = kw[XBM_DATA].value;
8753 width = XFASTINT (kw[XBM_WIDTH].value);
8754 height = XFASTINT (kw[XBM_HEIGHT].value);
8755
8756 /* Check type of data, and width and height against contents of
8757 data. */
8758 if (VECTORP (data))
8759 {
8760 int i;
8761
8762 /* Number of elements of the vector must be >= height. */
8763 if (XVECTOR (data)->size < height)
8764 return 0;
8765
8766 /* Each string or bool-vector in data must be large enough
8767 for one line of the image. */
8768 for (i = 0; i < height; ++i)
8769 {
8770 Lisp_Object elt = XVECTOR (data)->contents[i];
8771
8772 if (STRINGP (elt))
8773 {
8774 if (XSTRING (elt)->size
8775 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
8776 return 0;
8777 }
8778 else if (BOOL_VECTOR_P (elt))
8779 {
8780 if (XBOOL_VECTOR (elt)->size < width)
8781 return 0;
8782 }
8783 else
8784 return 0;
8785 }
8786 }
8787 else if (STRINGP (data))
8788 {
8789 if (XSTRING (data)->size
8790 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
8791 return 0;
8792 }
8793 else if (BOOL_VECTOR_P (data))
8794 {
8795 if (XBOOL_VECTOR (data)->size < width * height)
8796 return 0;
8797 }
8798 else
8799 return 0;
8800 }
8801
8802 /* Baseline must be a value between 0 and 100 (a percentage). */
8803 if (kw[XBM_ASCENT].count
8804 && XFASTINT (kw[XBM_ASCENT].value) > 100)
8805 return 0;
8806
8807 return 1;
8808 }
8809
8810
8811 /* Scan a bitmap file. FP is the stream to read from. Value is
8812 either an enumerator from enum xbm_token, or a character for a
8813 single-character token, or 0 at end of file. If scanning an
8814 identifier, store the lexeme of the identifier in SVAL. If
8815 scanning a number, store its value in *IVAL. */
8816
8817 static int
8818 xbm_scan (fp, sval, ival)
8819 FILE *fp;
8820 char *sval;
8821 int *ival;
8822 {
8823 int c;
8824
8825 /* Skip white space. */
8826 while ((c = fgetc (fp)) != EOF && isspace (c))
8827 ;
8828
8829 if (c == EOF)
8830 c = 0;
8831 else if (isdigit (c))
8832 {
8833 int value = 0, digit;
8834
8835 if (c == '0')
8836 {
8837 c = fgetc (fp);
8838 if (c == 'x' || c == 'X')
8839 {
8840 while ((c = fgetc (fp)) != EOF)
8841 {
8842 if (isdigit (c))
8843 digit = c - '0';
8844 else if (c >= 'a' && c <= 'f')
8845 digit = c - 'a' + 10;
8846 else if (c >= 'A' && c <= 'F')
8847 digit = c - 'A' + 10;
8848 else
8849 break;
8850 value = 16 * value + digit;
8851 }
8852 }
8853 else if (isdigit (c))
8854 {
8855 value = c - '0';
8856 while ((c = fgetc (fp)) != EOF
8857 && isdigit (c))
8858 value = 8 * value + c - '0';
8859 }
8860 }
8861 else
8862 {
8863 value = c - '0';
8864 while ((c = fgetc (fp)) != EOF
8865 && isdigit (c))
8866 value = 10 * value + c - '0';
8867 }
8868
8869 if (c != EOF)
8870 ungetc (c, fp);
8871 *ival = value;
8872 c = XBM_TK_NUMBER;
8873 }
8874 else if (isalpha (c) || c == '_')
8875 {
8876 *sval++ = c;
8877 while ((c = fgetc (fp)) != EOF
8878 && (isalnum (c) || c == '_'))
8879 *sval++ = c;
8880 *sval = 0;
8881 if (c != EOF)
8882 ungetc (c, fp);
8883 c = XBM_TK_IDENT;
8884 }
8885
8886 return c;
8887 }
8888
8889
8890 /* Replacement for XReadBitmapFileData which isn't available under old
8891 X versions. FILE is the name of the bitmap file to read. Set
8892 *WIDTH and *HEIGHT to the width and height of the image. Return in
8893 *DATA the bitmap data allocated with xmalloc. Value is non-zero if
8894 successful. */
8895
8896 static int
8897 xbm_read_bitmap_file_data (file, width, height, data)
8898 char *file;
8899 int *width, *height;
8900 unsigned char **data;
8901 {
8902 FILE *fp;
8903 char buffer[BUFSIZ];
8904 int padding_p = 0;
8905 int v10 = 0;
8906 int bytes_per_line, i, nbytes;
8907 unsigned char *p;
8908 int value;
8909 int LA1;
8910
8911 #define match() \
8912 LA1 = xbm_scan (fp, buffer, &value)
8913
8914 #define expect(TOKEN) \
8915 if (LA1 != (TOKEN)) \
8916 goto failure; \
8917 else \
8918 match ()
8919
8920 #define expect_ident(IDENT) \
8921 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
8922 match (); \
8923 else \
8924 goto failure
8925
8926 fp = fopen (file, "r");
8927 if (fp == NULL)
8928 return 0;
8929
8930 *width = *height = -1;
8931 *data = NULL;
8932 LA1 = xbm_scan (fp, buffer, &value);
8933
8934 /* Parse defines for width, height and hot-spots. */
8935 while (LA1 == '#')
8936 {
8937 match ();
8938 expect_ident ("define");
8939 expect (XBM_TK_IDENT);
8940
8941 if (LA1 == XBM_TK_NUMBER);
8942 {
8943 char *p = strrchr (buffer, '_');
8944 p = p ? p + 1 : buffer;
8945 if (strcmp (p, "width") == 0)
8946 *width = value;
8947 else if (strcmp (p, "height") == 0)
8948 *height = value;
8949 }
8950 expect (XBM_TK_NUMBER);
8951 }
8952
8953 if (*width < 0 || *height < 0)
8954 goto failure;
8955
8956 /* Parse bits. Must start with `static'. */
8957 expect_ident ("static");
8958 if (LA1 == XBM_TK_IDENT)
8959 {
8960 if (strcmp (buffer, "unsigned") == 0)
8961 {
8962 match ();
8963 expect_ident ("char");
8964 }
8965 else if (strcmp (buffer, "short") == 0)
8966 {
8967 match ();
8968 v10 = 1;
8969 if (*width % 16 && *width % 16 < 9)
8970 padding_p = 1;
8971 }
8972 else if (strcmp (buffer, "char") == 0)
8973 match ();
8974 else
8975 goto failure;
8976 }
8977 else
8978 goto failure;
8979
8980 expect (XBM_TK_IDENT);
8981 expect ('[');
8982 expect (']');
8983 expect ('=');
8984 expect ('{');
8985
8986 bytes_per_line = (*width + 7) / 8 + padding_p;
8987 nbytes = bytes_per_line * *height;
8988 p = *data = (char *) xmalloc (nbytes);
8989
8990 if (v10)
8991 {
8992
8993 for (i = 0; i < nbytes; i += 2)
8994 {
8995 int val = value;
8996 expect (XBM_TK_NUMBER);
8997
8998 *p++ = val;
8999 if (!padding_p || ((i + 2) % bytes_per_line))
9000 *p++ = value >> 8;
9001
9002 if (LA1 == ',' || LA1 == '}')
9003 match ();
9004 else
9005 goto failure;
9006 }
9007 }
9008 else
9009 {
9010 for (i = 0; i < nbytes; ++i)
9011 {
9012 int val = value;
9013 expect (XBM_TK_NUMBER);
9014
9015 *p++ = val;
9016
9017 if (LA1 == ',' || LA1 == '}')
9018 match ();
9019 else
9020 goto failure;
9021 }
9022 }
9023
9024 fclose (fp);
9025 return 1;
9026
9027 failure:
9028
9029 fclose (fp);
9030 if (*data)
9031 {
9032 xfree (*data);
9033 *data = NULL;
9034 }
9035 return 0;
9036
9037 #undef match
9038 #undef expect
9039 #undef expect_ident
9040 }
9041
9042
9043 /* Load XBM image IMG which will be displayed on frame F from file
9044 SPECIFIED_FILE. Value is non-zero if successful. */
9045
9046 static int
9047 xbm_load_image_from_file (f, img, specified_file)
9048 struct frame *f;
9049 struct image *img;
9050 Lisp_Object specified_file;
9051 {
9052 int rc;
9053 unsigned char *data;
9054 int success_p = 0;
9055 Lisp_Object file;
9056 struct gcpro gcpro1;
9057
9058 xassert (STRINGP (specified_file));
9059 file = Qnil;
9060 GCPRO1 (file);
9061
9062 file = x_find_image_file (specified_file);
9063 if (!STRINGP (file))
9064 {
9065 image_error ("Cannot find image file `%s'", specified_file, Qnil);
9066 UNGCPRO;
9067 return 0;
9068 }
9069
9070 rc = xbm_read_bitmap_file_data (XSTRING (file)->data, &img->width,
9071 &img->height, &data);
9072 if (rc)
9073 {
9074 int depth = one_w32_display_info.n_cbits;
9075 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
9076 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
9077 Lisp_Object value;
9078
9079 xassert (img->width > 0 && img->height > 0);
9080
9081 /* Get foreground and background colors, maybe allocate colors. */
9082 value = image_spec_value (img->spec, QCforeground, NULL);
9083 if (!NILP (value))
9084 foreground = x_alloc_image_color (f, img, value, foreground);
9085
9086 value = image_spec_value (img->spec, QCbackground, NULL);
9087 if (!NILP (value))
9088 background = x_alloc_image_color (f, img, value, background);
9089
9090 #if 0 /* TODO : Port image display to W32 */
9091 BLOCK_INPUT;
9092 img->pixmap
9093 = XCreatePixmapFromBitmapData (FRAME_W32_DISPLAY (f),
9094 FRAME_W32_WINDOW (f),
9095 data,
9096 img->width, img->height,
9097 foreground, background,
9098 depth);
9099 xfree (data);
9100
9101 if (img->pixmap == 0)
9102 {
9103 x_clear_image (f, img);
9104 image_error ("Unable to create X pixmap for `%s'", file, Qnil);
9105 }
9106 else
9107 success_p = 1;
9108
9109 UNBLOCK_INPUT;
9110 #endif
9111 }
9112 else
9113 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
9114
9115 UNGCPRO;
9116 return success_p;
9117 }
9118
9119
9120 /* Fill image IMG which is used on frame F with pixmap data. Value is
9121 non-zero if successful. */
9122
9123 static int
9124 xbm_load (f, img)
9125 struct frame *f;
9126 struct image *img;
9127 {
9128 int success_p = 0;
9129 Lisp_Object file_name;
9130
9131 xassert (xbm_image_p (img->spec));
9132
9133 /* If IMG->spec specifies a file name, create a non-file spec from it. */
9134 file_name = image_spec_value (img->spec, QCfile, NULL);
9135 if (STRINGP (file_name))
9136 success_p = xbm_load_image_from_file (f, img, file_name);
9137 else
9138 {
9139 struct image_keyword fmt[XBM_LAST];
9140 Lisp_Object data;
9141 int depth;
9142 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
9143 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
9144 char *bits;
9145 int parsed_p;
9146
9147 /* Parse the list specification. */
9148 bcopy (xbm_format, fmt, sizeof fmt);
9149 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
9150 xassert (parsed_p);
9151
9152 /* Get specified width, and height. */
9153 img->width = XFASTINT (fmt[XBM_WIDTH].value);
9154 img->height = XFASTINT (fmt[XBM_HEIGHT].value);
9155 xassert (img->width > 0 && img->height > 0);
9156
9157 BLOCK_INPUT;
9158
9159 if (fmt[XBM_ASCENT].count)
9160 img->ascent = XFASTINT (fmt[XBM_ASCENT].value);
9161
9162 /* Get foreground and background colors, maybe allocate colors. */
9163 if (fmt[XBM_FOREGROUND].count)
9164 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
9165 foreground);
9166 if (fmt[XBM_BACKGROUND].count)
9167 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
9168 background);
9169
9170 /* Set bits to the bitmap image data. */
9171 data = fmt[XBM_DATA].value;
9172 if (VECTORP (data))
9173 {
9174 int i;
9175 char *p;
9176 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
9177
9178 p = bits = (char *) alloca (nbytes * img->height);
9179 for (i = 0; i < img->height; ++i, p += nbytes)
9180 {
9181 Lisp_Object line = XVECTOR (data)->contents[i];
9182 if (STRINGP (line))
9183 bcopy (XSTRING (line)->data, p, nbytes);
9184 else
9185 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
9186 }
9187 }
9188 else if (STRINGP (data))
9189 bits = XSTRING (data)->data;
9190 else
9191 bits = XBOOL_VECTOR (data)->data;
9192
9193 #if 0 /* TODO : W32 XPM code */
9194 /* Create the pixmap. */
9195 depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
9196 img->pixmap
9197 = XCreatePixmapFromBitmapData (FRAME_W32_DISPLAY (f),
9198 FRAME_W32_WINDOW (f),
9199 bits,
9200 img->width, img->height,
9201 foreground, background,
9202 depth);
9203 #endif /* TODO */
9204
9205 if (img->pixmap)
9206 success_p = 1;
9207 else
9208 {
9209 image_error ("Unable to create pixmap for XBM image `%s'",
9210 img->spec, Qnil);
9211 x_clear_image (f, img);
9212 }
9213
9214 UNBLOCK_INPUT;
9215 }
9216
9217 return success_p;
9218 }
9219
9220
9221 \f
9222 /***********************************************************************
9223 XPM images
9224 ***********************************************************************/
9225
9226 #if HAVE_XPM
9227
9228 static int xpm_image_p P_ ((Lisp_Object object));
9229 static int xpm_load P_ ((struct frame *f, struct image *img));
9230 static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
9231
9232 #include "X11/xpm.h"
9233
9234 /* The symbol `xpm' identifying XPM-format images. */
9235
9236 Lisp_Object Qxpm;
9237
9238 /* Indices of image specification fields in xpm_format, below. */
9239
9240 enum xpm_keyword_index
9241 {
9242 XPM_TYPE,
9243 XPM_FILE,
9244 XPM_DATA,
9245 XPM_ASCENT,
9246 XPM_MARGIN,
9247 XPM_RELIEF,
9248 XPM_ALGORITHM,
9249 XPM_HEURISTIC_MASK,
9250 XPM_COLOR_SYMBOLS,
9251 XPM_LAST
9252 };
9253
9254 /* Vector of image_keyword structures describing the format
9255 of valid XPM image specifications. */
9256
9257 static struct image_keyword xpm_format[XPM_LAST] =
9258 {
9259 {":type", IMAGE_SYMBOL_VALUE, 1},
9260 {":file", IMAGE_STRING_VALUE, 0},
9261 {":data", IMAGE_STRING_VALUE, 0},
9262 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
9263 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
9264 {":relief", IMAGE_INTEGER_VALUE, 0},
9265 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9266 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9267 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
9268 };
9269
9270 /* Structure describing the image type XBM. */
9271
9272 static struct image_type xpm_type =
9273 {
9274 &Qxpm,
9275 xpm_image_p,
9276 xpm_load,
9277 x_clear_image,
9278 NULL
9279 };
9280
9281
9282 /* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
9283 for XPM images. Such a list must consist of conses whose car and
9284 cdr are strings. */
9285
9286 static int
9287 xpm_valid_color_symbols_p (color_symbols)
9288 Lisp_Object color_symbols;
9289 {
9290 while (CONSP (color_symbols))
9291 {
9292 Lisp_Object sym = XCAR (color_symbols);
9293 if (!CONSP (sym)
9294 || !STRINGP (XCAR (sym))
9295 || !STRINGP (XCDR (sym)))
9296 break;
9297 color_symbols = XCDR (color_symbols);
9298 }
9299
9300 return NILP (color_symbols);
9301 }
9302
9303
9304 /* Value is non-zero if OBJECT is a valid XPM image specification. */
9305
9306 static int
9307 xpm_image_p (object)
9308 Lisp_Object object;
9309 {
9310 struct image_keyword fmt[XPM_LAST];
9311 bcopy (xpm_format, fmt, sizeof fmt);
9312 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
9313 /* Either `:file' or `:data' must be present. */
9314 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
9315 /* Either no `:color-symbols' or it's a list of conses
9316 whose car and cdr are strings. */
9317 && (fmt[XPM_COLOR_SYMBOLS].count == 0
9318 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value))
9319 && (fmt[XPM_ASCENT].count == 0
9320 || XFASTINT (fmt[XPM_ASCENT].value) < 100));
9321 }
9322
9323
9324 /* Load image IMG which will be displayed on frame F. Value is
9325 non-zero if successful. */
9326
9327 static int
9328 xpm_load (f, img)
9329 struct frame *f;
9330 struct image *img;
9331 {
9332 int rc, i;
9333 XpmAttributes attrs;
9334 Lisp_Object specified_file, color_symbols;
9335
9336 /* Configure the XPM lib. Use the visual of frame F. Allocate
9337 close colors. Return colors allocated. */
9338 bzero (&attrs, sizeof attrs);
9339 attrs.visual = FRAME_X_VISUAL (f);
9340 attrs.colormap = FRAME_X_COLORMAP (f);
9341 attrs.valuemask |= XpmVisual;
9342 attrs.valuemask |= XpmColormap;
9343 attrs.valuemask |= XpmReturnAllocPixels;
9344 #ifdef XpmAllocCloseColors
9345 attrs.alloc_close_colors = 1;
9346 attrs.valuemask |= XpmAllocCloseColors;
9347 #else
9348 attrs.closeness = 600;
9349 attrs.valuemask |= XpmCloseness;
9350 #endif
9351
9352 /* If image specification contains symbolic color definitions, add
9353 these to `attrs'. */
9354 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
9355 if (CONSP (color_symbols))
9356 {
9357 Lisp_Object tail;
9358 XpmColorSymbol *xpm_syms;
9359 int i, size;
9360
9361 attrs.valuemask |= XpmColorSymbols;
9362
9363 /* Count number of symbols. */
9364 attrs.numsymbols = 0;
9365 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
9366 ++attrs.numsymbols;
9367
9368 /* Allocate an XpmColorSymbol array. */
9369 size = attrs.numsymbols * sizeof *xpm_syms;
9370 xpm_syms = (XpmColorSymbol *) alloca (size);
9371 bzero (xpm_syms, size);
9372 attrs.colorsymbols = xpm_syms;
9373
9374 /* Fill the color symbol array. */
9375 for (tail = color_symbols, i = 0;
9376 CONSP (tail);
9377 ++i, tail = XCDR (tail))
9378 {
9379 Lisp_Object name = XCAR (XCAR (tail));
9380 Lisp_Object color = XCDR (XCAR (tail));
9381 xpm_syms[i].name = (char *) alloca (XSTRING (name)->size + 1);
9382 strcpy (xpm_syms[i].name, XSTRING (name)->data);
9383 xpm_syms[i].value = (char *) alloca (XSTRING (color)->size + 1);
9384 strcpy (xpm_syms[i].value, XSTRING (color)->data);
9385 }
9386 }
9387
9388 /* Create a pixmap for the image, either from a file, or from a
9389 string buffer containing data in the same format as an XPM file. */
9390 BLOCK_INPUT;
9391 specified_file = image_spec_value (img->spec, QCfile, NULL);
9392 if (STRINGP (specified_file))
9393 {
9394 Lisp_Object file = x_find_image_file (specified_file);
9395 if (!STRINGP (file))
9396 {
9397 image_error ("Cannot find image file `%s'", specified_file, Qnil);
9398 UNBLOCK_INPUT;
9399 return 0;
9400 }
9401
9402 rc = XpmReadFileToPixmap (NULL, FRAME_W32_WINDOW (f),
9403 XSTRING (file)->data, &img->pixmap, &img->mask,
9404 &attrs);
9405 }
9406 else
9407 {
9408 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
9409 rc = XpmCreatePixmapFromBuffer (NULL, FRAME_W32_WINDOW (f),
9410 XSTRING (buffer)->data,
9411 &img->pixmap, &img->mask,
9412 &attrs);
9413 }
9414 UNBLOCK_INPUT;
9415
9416 if (rc == XpmSuccess)
9417 {
9418 /* Remember allocated colors. */
9419 img->ncolors = attrs.nalloc_pixels;
9420 img->colors = (unsigned long *) xmalloc (img->ncolors
9421 * sizeof *img->colors);
9422 for (i = 0; i < attrs.nalloc_pixels; ++i)
9423 img->colors[i] = attrs.alloc_pixels[i];
9424
9425 img->width = attrs.width;
9426 img->height = attrs.height;
9427 xassert (img->width > 0 && img->height > 0);
9428
9429 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
9430 BLOCK_INPUT;
9431 XpmFreeAttributes (&attrs);
9432 UNBLOCK_INPUT;
9433 }
9434 else
9435 {
9436 switch (rc)
9437 {
9438 case XpmOpenFailed:
9439 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
9440 break;
9441
9442 case XpmFileInvalid:
9443 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
9444 break;
9445
9446 case XpmNoMemory:
9447 image_error ("Out of memory (%s)", img->spec, Qnil);
9448 break;
9449
9450 case XpmColorFailed:
9451 image_error ("Color allocation error (%s)", img->spec, Qnil);
9452 break;
9453
9454 default:
9455 image_error ("Unknown error (%s)", img->spec, Qnil);
9456 break;
9457 }
9458 }
9459
9460 return rc == XpmSuccess;
9461 }
9462
9463 #endif /* HAVE_XPM != 0 */
9464
9465 \f
9466 #if 0 /* TODO : Color tables on W32. */
9467 /***********************************************************************
9468 Color table
9469 ***********************************************************************/
9470
9471 /* An entry in the color table mapping an RGB color to a pixel color. */
9472
9473 struct ct_color
9474 {
9475 int r, g, b;
9476 unsigned long pixel;
9477
9478 /* Next in color table collision list. */
9479 struct ct_color *next;
9480 };
9481
9482 /* The bucket vector size to use. Must be prime. */
9483
9484 #define CT_SIZE 101
9485
9486 /* Value is a hash of the RGB color given by R, G, and B. */
9487
9488 #define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
9489
9490 /* The color hash table. */
9491
9492 struct ct_color **ct_table;
9493
9494 /* Number of entries in the color table. */
9495
9496 int ct_colors_allocated;
9497
9498 /* Function prototypes. */
9499
9500 static void init_color_table P_ ((void));
9501 static void free_color_table P_ ((void));
9502 static unsigned long *colors_in_color_table P_ ((int *n));
9503 static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
9504 static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
9505
9506
9507 /* Initialize the color table. */
9508
9509 static void
9510 init_color_table ()
9511 {
9512 int size = CT_SIZE * sizeof (*ct_table);
9513 ct_table = (struct ct_color **) xmalloc (size);
9514 bzero (ct_table, size);
9515 ct_colors_allocated = 0;
9516 }
9517
9518
9519 /* Free memory associated with the color table. */
9520
9521 static void
9522 free_color_table ()
9523 {
9524 int i;
9525 struct ct_color *p, *next;
9526
9527 for (i = 0; i < CT_SIZE; ++i)
9528 for (p = ct_table[i]; p; p = next)
9529 {
9530 next = p->next;
9531 xfree (p);
9532 }
9533
9534 xfree (ct_table);
9535 ct_table = NULL;
9536 }
9537
9538
9539 /* Value is a pixel color for RGB color R, G, B on frame F. If an
9540 entry for that color already is in the color table, return the
9541 pixel color of that entry. Otherwise, allocate a new color for R,
9542 G, B, and make an entry in the color table. */
9543
9544 static unsigned long
9545 lookup_rgb_color (f, r, g, b)
9546 struct frame *f;
9547 int r, g, b;
9548 {
9549 unsigned hash = CT_HASH_RGB (r, g, b);
9550 int i = hash % CT_SIZE;
9551 struct ct_color *p;
9552
9553 for (p = ct_table[i]; p; p = p->next)
9554 if (p->r == r && p->g == g && p->b == b)
9555 break;
9556
9557 if (p == NULL)
9558 {
9559 COLORREF color;
9560 Colormap cmap;
9561 int rc;
9562
9563 color = PALETTERGB (r, g, b);
9564
9565 ++ct_colors_allocated;
9566
9567 p = (struct ct_color *) xmalloc (sizeof *p);
9568 p->r = r;
9569 p->g = g;
9570 p->b = b;
9571 p->pixel = color;
9572 p->next = ct_table[i];
9573 ct_table[i] = p;
9574 }
9575
9576 return p->pixel;
9577 }
9578
9579
9580 /* Look up pixel color PIXEL which is used on frame F in the color
9581 table. If not already present, allocate it. Value is PIXEL. */
9582
9583 static unsigned long
9584 lookup_pixel_color (f, pixel)
9585 struct frame *f;
9586 unsigned long pixel;
9587 {
9588 int i = pixel % CT_SIZE;
9589 struct ct_color *p;
9590
9591 for (p = ct_table[i]; p; p = p->next)
9592 if (p->pixel == pixel)
9593 break;
9594
9595 if (p == NULL)
9596 {
9597 XColor color;
9598 Colormap cmap;
9599 int rc;
9600
9601 BLOCK_INPUT;
9602
9603 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
9604 color.pixel = pixel;
9605 XQueryColor (NULL, cmap, &color);
9606 rc = x_alloc_nearest_color (f, cmap, &color);
9607 UNBLOCK_INPUT;
9608
9609 if (rc)
9610 {
9611 ++ct_colors_allocated;
9612
9613 p = (struct ct_color *) xmalloc (sizeof *p);
9614 p->r = color.red;
9615 p->g = color.green;
9616 p->b = color.blue;
9617 p->pixel = pixel;
9618 p->next = ct_table[i];
9619 ct_table[i] = p;
9620 }
9621 else
9622 return FRAME_FOREGROUND_PIXEL (f);
9623 }
9624 return p->pixel;
9625 }
9626
9627
9628 /* Value is a vector of all pixel colors contained in the color table,
9629 allocated via xmalloc. Set *N to the number of colors. */
9630
9631 static unsigned long *
9632 colors_in_color_table (n)
9633 int *n;
9634 {
9635 int i, j;
9636 struct ct_color *p;
9637 unsigned long *colors;
9638
9639 if (ct_colors_allocated == 0)
9640 {
9641 *n = 0;
9642 colors = NULL;
9643 }
9644 else
9645 {
9646 colors = (unsigned long *) xmalloc (ct_colors_allocated
9647 * sizeof *colors);
9648 *n = ct_colors_allocated;
9649
9650 for (i = j = 0; i < CT_SIZE; ++i)
9651 for (p = ct_table[i]; p; p = p->next)
9652 colors[j++] = p->pixel;
9653 }
9654
9655 return colors;
9656 }
9657
9658 #endif /* TODO */
9659
9660 \f
9661 /***********************************************************************
9662 Algorithms
9663 ***********************************************************************/
9664
9665 #if 0 /* TODO : W32 versions of low level algorithms */
9666 static void x_laplace_write_row P_ ((struct frame *, long *,
9667 int, XImage *, int));
9668 static void x_laplace_read_row P_ ((struct frame *, Colormap,
9669 XColor *, int, XImage *, int));
9670
9671
9672 /* Fill COLORS with RGB colors from row Y of image XIMG. F is the
9673 frame we operate on, CMAP is the color-map in effect, and WIDTH is
9674 the width of one row in the image. */
9675
9676 static void
9677 x_laplace_read_row (f, cmap, colors, width, ximg, y)
9678 struct frame *f;
9679 Colormap cmap;
9680 XColor *colors;
9681 int width;
9682 XImage *ximg;
9683 int y;
9684 {
9685 int x;
9686
9687 for (x = 0; x < width; ++x)
9688 colors[x].pixel = XGetPixel (ximg, x, y);
9689
9690 XQueryColors (NULL, cmap, colors, width);
9691 }
9692
9693
9694 /* Write row Y of image XIMG. PIXELS is an array of WIDTH longs
9695 containing the pixel colors to write. F is the frame we are
9696 working on. */
9697
9698 static void
9699 x_laplace_write_row (f, pixels, width, ximg, y)
9700 struct frame *f;
9701 long *pixels;
9702 int width;
9703 XImage *ximg;
9704 int y;
9705 {
9706 int x;
9707
9708 for (x = 0; x < width; ++x)
9709 XPutPixel (ximg, x, y, pixels[x]);
9710 }
9711 #endif
9712
9713 /* Transform image IMG which is used on frame F with a Laplace
9714 edge-detection algorithm. The result is an image that can be used
9715 to draw disabled buttons, for example. */
9716
9717 static void
9718 x_laplace (f, img)
9719 struct frame *f;
9720 struct image *img;
9721 {
9722 #if 0 /* TODO : W32 version */
9723 Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
9724 XImage *ximg, *oimg;
9725 XColor *in[3];
9726 long *out;
9727 Pixmap pixmap;
9728 int x, y, i;
9729 long pixel;
9730 int in_y, out_y, rc;
9731 int mv2 = 45000;
9732
9733 BLOCK_INPUT;
9734
9735 /* Get the X image IMG->pixmap. */
9736 ximg = XGetImage (NULL, img->pixmap,
9737 0, 0, img->width, img->height, ~0, ZPixmap);
9738
9739 /* Allocate 3 input rows, and one output row of colors. */
9740 for (i = 0; i < 3; ++i)
9741 in[i] = (XColor *) alloca (img->width * sizeof (XColor));
9742 out = (long *) alloca (img->width * sizeof (long));
9743
9744 /* Create an X image for output. */
9745 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 0,
9746 &oimg, &pixmap);
9747
9748 /* Fill first two rows. */
9749 x_laplace_read_row (f, cmap, in[0], img->width, ximg, 0);
9750 x_laplace_read_row (f, cmap, in[1], img->width, ximg, 1);
9751 in_y = 2;
9752
9753 /* Write first row, all zeros. */
9754 init_color_table ();
9755 pixel = lookup_rgb_color (f, 0, 0, 0);
9756 for (x = 0; x < img->width; ++x)
9757 out[x] = pixel;
9758 x_laplace_write_row (f, out, img->width, oimg, 0);
9759 out_y = 1;
9760
9761 for (y = 2; y < img->height; ++y)
9762 {
9763 int rowa = y % 3;
9764 int rowb = (y + 2) % 3;
9765
9766 x_laplace_read_row (f, cmap, in[rowa], img->width, ximg, in_y++);
9767
9768 for (x = 0; x < img->width - 2; ++x)
9769 {
9770 int r = in[rowa][x].red + mv2 - in[rowb][x + 2].red;
9771 int g = in[rowa][x].green + mv2 - in[rowb][x + 2].green;
9772 int b = in[rowa][x].blue + mv2 - in[rowb][x + 2].blue;
9773
9774 out[x + 1] = lookup_rgb_color (f, r & 0xffff, g & 0xffff,
9775 b & 0xffff);
9776 }
9777
9778 x_laplace_write_row (f, out, img->width, oimg, out_y++);
9779 }
9780
9781 /* Write last line, all zeros. */
9782 for (x = 0; x < img->width; ++x)
9783 out[x] = pixel;
9784 x_laplace_write_row (f, out, img->width, oimg, out_y);
9785
9786 /* Free the input image, and free resources of IMG. */
9787 XDestroyImage (ximg);
9788 x_clear_image (f, img);
9789
9790 /* Put the output image into pixmap, and destroy it. */
9791 x_put_x_image (f, oimg, pixmap, img->width, img->height);
9792 x_destroy_x_image (oimg);
9793
9794 /* Remember new pixmap and colors in IMG. */
9795 img->pixmap = pixmap;
9796 img->colors = colors_in_color_table (&img->ncolors);
9797 free_color_table ();
9798
9799 UNBLOCK_INPUT;
9800 #endif /* TODO */
9801 }
9802
9803
9804 /* Build a mask for image IMG which is used on frame F. FILE is the
9805 name of an image file, for error messages. HOW determines how to
9806 determine the background color of IMG. If it is a list '(R G B)',
9807 with R, G, and B being integers >= 0, take that as the color of the
9808 background. Otherwise, determine the background color of IMG
9809 heuristically. Value is non-zero if successful. */
9810
9811 static int
9812 x_build_heuristic_mask (f, img, how)
9813 struct frame *f;
9814 struct image *img;
9815 Lisp_Object how;
9816 {
9817 #if 0 /* TODO : W32 version */
9818 Display *dpy = FRAME_W32_DISPLAY (f);
9819 XImage *ximg, *mask_img;
9820 int x, y, rc, look_at_corners_p;
9821 unsigned long bg;
9822
9823 BLOCK_INPUT;
9824
9825 /* Create an image and pixmap serving as mask. */
9826 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
9827 &mask_img, &img->mask);
9828 if (!rc)
9829 {
9830 UNBLOCK_INPUT;
9831 return 0;
9832 }
9833
9834 /* Get the X image of IMG->pixmap. */
9835 ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height,
9836 ~0, ZPixmap);
9837
9838 /* Determine the background color of ximg. If HOW is `(R G B)'
9839 take that as color. Otherwise, try to determine the color
9840 heuristically. */
9841 look_at_corners_p = 1;
9842
9843 if (CONSP (how))
9844 {
9845 int rgb[3], i = 0;
9846
9847 while (i < 3
9848 && CONSP (how)
9849 && NATNUMP (XCAR (how)))
9850 {
9851 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
9852 how = XCDR (how);
9853 }
9854
9855 if (i == 3 && NILP (how))
9856 {
9857 char color_name[30];
9858 XColor exact, color;
9859 Colormap cmap;
9860
9861 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
9862
9863 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
9864 if (XLookupColor (dpy, cmap, color_name, &exact, &color))
9865 {
9866 bg = color.pixel;
9867 look_at_corners_p = 0;
9868 }
9869 }
9870 }
9871
9872 if (look_at_corners_p)
9873 {
9874 unsigned long corners[4];
9875 int i, best_count;
9876
9877 /* Get the colors at the corners of ximg. */
9878 corners[0] = XGetPixel (ximg, 0, 0);
9879 corners[1] = XGetPixel (ximg, img->width - 1, 0);
9880 corners[2] = XGetPixel (ximg, img->width - 1, img->height - 1);
9881 corners[3] = XGetPixel (ximg, 0, img->height - 1);
9882
9883 /* Choose the most frequently found color as background. */
9884 for (i = best_count = 0; i < 4; ++i)
9885 {
9886 int j, n;
9887
9888 for (j = n = 0; j < 4; ++j)
9889 if (corners[i] == corners[j])
9890 ++n;
9891
9892 if (n > best_count)
9893 bg = corners[i], best_count = n;
9894 }
9895 }
9896
9897 /* Set all bits in mask_img to 1 whose color in ximg is different
9898 from the background color bg. */
9899 for (y = 0; y < img->height; ++y)
9900 for (x = 0; x < img->width; ++x)
9901 XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg);
9902
9903 /* Put mask_img into img->mask. */
9904 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
9905 x_destroy_x_image (mask_img);
9906 XDestroyImage (ximg);
9907
9908 UNBLOCK_INPUT;
9909 #endif /* TODO */
9910
9911 return 1;
9912 }
9913
9914
9915 \f
9916 /***********************************************************************
9917 PBM (mono, gray, color)
9918 ***********************************************************************/
9919 #ifdef HAVE_PBM
9920
9921 static int pbm_image_p P_ ((Lisp_Object object));
9922 static int pbm_load P_ ((struct frame *f, struct image *img));
9923 static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
9924
9925 /* The symbol `pbm' identifying images of this type. */
9926
9927 Lisp_Object Qpbm;
9928
9929 /* Indices of image specification fields in gs_format, below. */
9930
9931 enum pbm_keyword_index
9932 {
9933 PBM_TYPE,
9934 PBM_FILE,
9935 PBM_DATA,
9936 PBM_ASCENT,
9937 PBM_MARGIN,
9938 PBM_RELIEF,
9939 PBM_ALGORITHM,
9940 PBM_HEURISTIC_MASK,
9941 PBM_LAST
9942 };
9943
9944 /* Vector of image_keyword structures describing the format
9945 of valid user-defined image specifications. */
9946
9947 static struct image_keyword pbm_format[PBM_LAST] =
9948 {
9949 {":type", IMAGE_SYMBOL_VALUE, 1},
9950 {":file", IMAGE_STRING_VALUE, 0},
9951 {":data", IMAGE_STRING_VALUE, 0},
9952 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
9953 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
9954 {":relief", IMAGE_INTEGER_VALUE, 0},
9955 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9956 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
9957 };
9958
9959 /* Structure describing the image type `pbm'. */
9960
9961 static struct image_type pbm_type =
9962 {
9963 &Qpbm,
9964 pbm_image_p,
9965 pbm_load,
9966 x_clear_image,
9967 NULL
9968 };
9969
9970
9971 /* Return non-zero if OBJECT is a valid PBM image specification. */
9972
9973 static int
9974 pbm_image_p (object)
9975 Lisp_Object object;
9976 {
9977 struct image_keyword fmt[PBM_LAST];
9978
9979 bcopy (pbm_format, fmt, sizeof fmt);
9980
9981 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm)
9982 || (fmt[PBM_ASCENT].count
9983 && XFASTINT (fmt[PBM_ASCENT].value) > 100))
9984 return 0;
9985
9986 /* Must specify either :data or :file. */
9987 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
9988 }
9989
9990
9991 /* Scan a decimal number from *S and return it. Advance *S while
9992 reading the number. END is the end of the string. Value is -1 at
9993 end of input. */
9994
9995 static int
9996 pbm_scan_number (s, end)
9997 unsigned char **s, *end;
9998 {
9999 int c, val = -1;
10000
10001 while (*s < end)
10002 {
10003 /* Skip white-space. */
10004 while (*s < end && (c = *(*s)++, isspace (c)))
10005 ;
10006
10007 if (c == '#')
10008 {
10009 /* Skip comment to end of line. */
10010 while (*s < end && (c = *(*s)++, c != '\n'))
10011 ;
10012 }
10013 else if (isdigit (c))
10014 {
10015 /* Read decimal number. */
10016 val = c - '0';
10017 while (*s < end && (c = *(*s)++, isdigit (c)))
10018 val = 10 * val + c - '0';
10019 break;
10020 }
10021 else
10022 break;
10023 }
10024
10025 return val;
10026 }
10027
10028
10029 /* Read FILE into memory. Value is a pointer to a buffer allocated
10030 with xmalloc holding FILE's contents. Value is null if an error
10031 occured. *SIZE is set to the size of the file. */
10032
10033 static char *
10034 pbm_read_file (file, size)
10035 Lisp_Object file;
10036 int *size;
10037 {
10038 FILE *fp = NULL;
10039 char *buf = NULL;
10040 struct stat st;
10041
10042 if (stat (XSTRING (file)->data, &st) == 0
10043 && (fp = fopen (XSTRING (file)->data, "r")) != NULL
10044 && (buf = (char *) xmalloc (st.st_size),
10045 fread (buf, 1, st.st_size, fp) == st.st_size))
10046 {
10047 *size = st.st_size;
10048 fclose (fp);
10049 }
10050 else
10051 {
10052 if (fp)
10053 fclose (fp);
10054 if (buf)
10055 {
10056 xfree (buf);
10057 buf = NULL;
10058 }
10059 }
10060
10061 return buf;
10062 }
10063
10064
10065 /* Load PBM image IMG for use on frame F. */
10066
10067 static int
10068 pbm_load (f, img)
10069 struct frame *f;
10070 struct image *img;
10071 {
10072 int raw_p, x, y;
10073 int width, height, max_color_idx = 0;
10074 XImage *ximg;
10075 Lisp_Object file, specified_file;
10076 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
10077 struct gcpro gcpro1;
10078 unsigned char *contents = NULL;
10079 unsigned char *end, *p;
10080 int size;
10081
10082 specified_file = image_spec_value (img->spec, QCfile, NULL);
10083 file = Qnil;
10084 GCPRO1 (file);
10085
10086 if (STRINGP (specified_file))
10087 {
10088 file = x_find_image_file (specified_file);
10089 if (!STRINGP (file))
10090 {
10091 image_error ("Cannot find image file `%s'", specified_file, Qnil);
10092 UNGCPRO;
10093 return 0;
10094 }
10095
10096 contents = pbm_read_file (file, &size);
10097 if (contents == NULL)
10098 {
10099 image_error ("Error reading `%s'", file, Qnil);
10100 UNGCPRO;
10101 return 0;
10102 }
10103
10104 p = contents;
10105 end = contents + size;
10106 }
10107 else
10108 {
10109 Lisp_Object data;
10110 data = image_spec_value (img->spec, QCdata, NULL);
10111 p = XSTRING (data)->data;
10112 end = p + STRING_BYTES (XSTRING (data));
10113 }
10114
10115 /* Check magic number. */
10116 if (end - p < 2 || *p++ != 'P')
10117 {
10118 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
10119 error:
10120 xfree (contents);
10121 UNGCPRO;
10122 return 0;
10123 }
10124
10125 switch (*p++)
10126 {
10127 case '1':
10128 raw_p = 0, type = PBM_MONO;
10129 break;
10130
10131 case '2':
10132 raw_p = 0, type = PBM_GRAY;
10133 break;
10134
10135 case '3':
10136 raw_p = 0, type = PBM_COLOR;
10137 break;
10138
10139 case '4':
10140 raw_p = 1, type = PBM_MONO;
10141 break;
10142
10143 case '5':
10144 raw_p = 1, type = PBM_GRAY;
10145 break;
10146
10147 case '6':
10148 raw_p = 1, type = PBM_COLOR;
10149 break;
10150
10151 default:
10152 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
10153 goto error;
10154 }
10155
10156 /* Read width, height, maximum color-component. Characters
10157 starting with `#' up to the end of a line are ignored. */
10158 width = pbm_scan_number (&p, end);
10159 height = pbm_scan_number (&p, end);
10160
10161 if (type != PBM_MONO)
10162 {
10163 max_color_idx = pbm_scan_number (&p, end);
10164 if (raw_p && max_color_idx > 255)
10165 max_color_idx = 255;
10166 }
10167
10168 if (width < 0
10169 || height < 0
10170 || (type != PBM_MONO && max_color_idx < 0))
10171 goto error;
10172
10173 BLOCK_INPUT;
10174 if (!x_create_x_image_and_pixmap (f, width, height, 0,
10175 &ximg, &img->pixmap))
10176 {
10177 UNBLOCK_INPUT;
10178 goto error;
10179 }
10180
10181 /* Initialize the color hash table. */
10182 init_color_table ();
10183
10184 if (type == PBM_MONO)
10185 {
10186 int c = 0, g;
10187
10188 for (y = 0; y < height; ++y)
10189 for (x = 0; x < width; ++x)
10190 {
10191 if (raw_p)
10192 {
10193 if ((x & 7) == 0)
10194 c = *p++;
10195 g = c & 0x80;
10196 c <<= 1;
10197 }
10198 else
10199 g = pbm_scan_number (&p, end);
10200
10201 XPutPixel (ximg, x, y, (g
10202 ? FRAME_FOREGROUND_PIXEL (f)
10203 : FRAME_BACKGROUND_PIXEL (f)));
10204 }
10205 }
10206 else
10207 {
10208 for (y = 0; y < height; ++y)
10209 for (x = 0; x < width; ++x)
10210 {
10211 int r, g, b;
10212
10213 if (type == PBM_GRAY)
10214 r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
10215 else if (raw_p)
10216 {
10217 r = *p++;
10218 g = *p++;
10219 b = *p++;
10220 }
10221 else
10222 {
10223 r = pbm_scan_number (&p, end);
10224 g = pbm_scan_number (&p, end);
10225 b = pbm_scan_number (&p, end);
10226 }
10227
10228 if (r < 0 || g < 0 || b < 0)
10229 {
10230 xfree (ximg->data);
10231 ximg->data = NULL;
10232 XDestroyImage (ximg);
10233 UNBLOCK_INPUT;
10234 image_error ("Invalid pixel value in image `%s'",
10235 img->spec, Qnil);
10236 goto error;
10237 }
10238
10239 /* RGB values are now in the range 0..max_color_idx.
10240 Scale this to the range 0..0xffff supported by X. */
10241 r = (double) r * 65535 / max_color_idx;
10242 g = (double) g * 65535 / max_color_idx;
10243 b = (double) b * 65535 / max_color_idx;
10244 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
10245 }
10246 }
10247
10248 /* Store in IMG->colors the colors allocated for the image, and
10249 free the color table. */
10250 img->colors = colors_in_color_table (&img->ncolors);
10251 free_color_table ();
10252
10253 /* Put the image into a pixmap. */
10254 x_put_x_image (f, ximg, img->pixmap, width, height);
10255 x_destroy_x_image (ximg);
10256 UNBLOCK_INPUT;
10257
10258 img->width = width;
10259 img->height = height;
10260
10261 UNGCPRO;
10262 xfree (contents);
10263 return 1;
10264 }
10265 #endif /* HAVE_PBM */
10266
10267 \f
10268 /***********************************************************************
10269 PNG
10270 ***********************************************************************/
10271
10272 #if HAVE_PNG
10273
10274 #include <png.h>
10275
10276 /* Function prototypes. */
10277
10278 static int png_image_p P_ ((Lisp_Object object));
10279 static int png_load P_ ((struct frame *f, struct image *img));
10280
10281 /* The symbol `png' identifying images of this type. */
10282
10283 Lisp_Object Qpng;
10284
10285 /* Indices of image specification fields in png_format, below. */
10286
10287 enum png_keyword_index
10288 {
10289 PNG_TYPE,
10290 PNG_DATA,
10291 PNG_FILE,
10292 PNG_ASCENT,
10293 PNG_MARGIN,
10294 PNG_RELIEF,
10295 PNG_ALGORITHM,
10296 PNG_HEURISTIC_MASK,
10297 PNG_LAST
10298 };
10299
10300 /* Vector of image_keyword structures describing the format
10301 of valid user-defined image specifications. */
10302
10303 static struct image_keyword png_format[PNG_LAST] =
10304 {
10305 {":type", IMAGE_SYMBOL_VALUE, 1},
10306 {":data", IMAGE_STRING_VALUE, 0},
10307 {":file", IMAGE_STRING_VALUE, 0},
10308 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
10309 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
10310 {":relief", IMAGE_INTEGER_VALUE, 0},
10311 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10312 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
10313 };
10314
10315 /* Structure describing the image type `png'. */
10316
10317 static struct image_type png_type =
10318 {
10319 &Qpng,
10320 png_image_p,
10321 png_load,
10322 x_clear_image,
10323 NULL
10324 };
10325
10326
10327 /* Return non-zero if OBJECT is a valid PNG image specification. */
10328
10329 static int
10330 png_image_p (object)
10331 Lisp_Object object;
10332 {
10333 struct image_keyword fmt[PNG_LAST];
10334 bcopy (png_format, fmt, sizeof fmt);
10335
10336 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng)
10337 || (fmt[PNG_ASCENT].count
10338 && XFASTINT (fmt[PNG_ASCENT].value) > 100))
10339 return 0;
10340
10341 /* Must specify either the :data or :file keyword. */
10342 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
10343 }
10344
10345
10346 /* Error and warning handlers installed when the PNG library
10347 is initialized. */
10348
10349 static void
10350 my_png_error (png_ptr, msg)
10351 png_struct *png_ptr;
10352 char *msg;
10353 {
10354 xassert (png_ptr != NULL);
10355 image_error ("PNG error: %s", build_string (msg), Qnil);
10356 longjmp (png_ptr->jmpbuf, 1);
10357 }
10358
10359
10360 static void
10361 my_png_warning (png_ptr, msg)
10362 png_struct *png_ptr;
10363 char *msg;
10364 {
10365 xassert (png_ptr != NULL);
10366 image_error ("PNG warning: %s", build_string (msg), Qnil);
10367 }
10368
10369 /* Memory source for PNG decoding. */
10370
10371 struct png_memory_storage
10372 {
10373 unsigned char *bytes; /* The data */
10374 size_t len; /* How big is it? */
10375 int index; /* Where are we? */
10376 };
10377
10378
10379 /* Function set as reader function when reading PNG image from memory.
10380 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
10381 bytes from the input to DATA. */
10382
10383 static void
10384 png_read_from_memory (png_ptr, data, length)
10385 png_structp png_ptr;
10386 png_bytep data;
10387 png_size_t length;
10388 {
10389 struct png_memory_storage *tbr
10390 = (struct png_memory_storage *) png_get_io_ptr (png_ptr);
10391
10392 if (length > tbr->len - tbr->index)
10393 png_error (png_ptr, "Read error");
10394
10395 bcopy (tbr->bytes + tbr->index, data, length);
10396 tbr->index = tbr->index + length;
10397 }
10398
10399 /* Load PNG image IMG for use on frame F. Value is non-zero if
10400 successful. */
10401
10402 static int
10403 png_load (f, img)
10404 struct frame *f;
10405 struct image *img;
10406 {
10407 Lisp_Object file, specified_file;
10408 Lisp_Object specified_data;
10409 int x, y, i;
10410 XImage *ximg, *mask_img = NULL;
10411 struct gcpro gcpro1;
10412 png_struct *png_ptr = NULL;
10413 png_info *info_ptr = NULL, *end_info = NULL;
10414 FILE *fp = NULL;
10415 png_byte sig[8];
10416 png_byte *pixels = NULL;
10417 png_byte **rows = NULL;
10418 png_uint_32 width, height;
10419 int bit_depth, color_type, interlace_type;
10420 png_byte channels;
10421 png_uint_32 row_bytes;
10422 int transparent_p;
10423 char *gamma_str;
10424 double screen_gamma, image_gamma;
10425 int intent;
10426 struct png_memory_storage tbr; /* Data to be read */
10427
10428 /* Find out what file to load. */
10429 specified_file = image_spec_value (img->spec, QCfile, NULL);
10430 specified_data = image_spec_value (img->spec, QCdata, NULL);
10431 file = Qnil;
10432 GCPRO1 (file);
10433
10434 if (NILP (specified_data))
10435 {
10436 file = x_find_image_file (specified_file);
10437 if (!STRINGP (file))
10438 {
10439 image_error ("Cannot find image file `%s'", specified_file, Qnil);
10440 UNGCPRO;
10441 return 0;
10442 }
10443
10444 /* Open the image file. */
10445 fp = fopen (XSTRING (file)->data, "rb");
10446 if (!fp)
10447 {
10448 image_error ("Cannot open image file `%s'", file, Qnil);
10449 UNGCPRO;
10450 fclose (fp);
10451 return 0;
10452 }
10453
10454 /* Check PNG signature. */
10455 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
10456 || !png_check_sig (sig, sizeof sig))
10457 {
10458 image_error ("Not a PNG file:` %s'", file, Qnil);
10459 UNGCPRO;
10460 fclose (fp);
10461 return 0;
10462 }
10463 }
10464 else
10465 {
10466 /* Read from memory. */
10467 tbr.bytes = XSTRING (specified_data)->data;
10468 tbr.len = STRING_BYTES (XSTRING (specified_data));
10469 tbr.index = 0;
10470
10471 /* Check PNG signature. */
10472 if (tbr.len < sizeof sig
10473 || !png_check_sig (tbr.bytes, sizeof sig))
10474 {
10475 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
10476 UNGCPRO;
10477 return 0;
10478 }
10479
10480 /* Need to skip past the signature. */
10481 tbr.bytes += sizeof (sig);
10482 }
10483
10484 /* Initialize read and info structs for PNG lib. */
10485 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
10486 my_png_error, my_png_warning);
10487 if (!png_ptr)
10488 {
10489 if (fp) fclose (fp);
10490 UNGCPRO;
10491 return 0;
10492 }
10493
10494 info_ptr = png_create_info_struct (png_ptr);
10495 if (!info_ptr)
10496 {
10497 png_destroy_read_struct (&png_ptr, NULL, NULL);
10498 if (fp) fclose (fp);
10499 UNGCPRO;
10500 return 0;
10501 }
10502
10503 end_info = png_create_info_struct (png_ptr);
10504 if (!end_info)
10505 {
10506 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
10507 if (fp) fclose (fp);
10508 UNGCPRO;
10509 return 0;
10510 }
10511
10512 /* Set error jump-back. We come back here when the PNG library
10513 detects an error. */
10514 if (setjmp (png_ptr->jmpbuf))
10515 {
10516 error:
10517 if (png_ptr)
10518 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
10519 xfree (pixels);
10520 xfree (rows);
10521 if (fp) fclose (fp);
10522 UNGCPRO;
10523 return 0;
10524 }
10525
10526 /* Read image info. */
10527 if (!NILP (specified_data))
10528 png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
10529 else
10530 png_init_io (png_ptr, fp);
10531
10532 png_set_sig_bytes (png_ptr, sizeof sig);
10533 png_read_info (png_ptr, info_ptr);
10534 png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
10535 &interlace_type, NULL, NULL);
10536
10537 /* If image contains simply transparency data, we prefer to
10538 construct a clipping mask. */
10539 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
10540 transparent_p = 1;
10541 else
10542 transparent_p = 0;
10543
10544 /* This function is easier to write if we only have to handle
10545 one data format: RGB or RGBA with 8 bits per channel. Let's
10546 transform other formats into that format. */
10547
10548 /* Strip more than 8 bits per channel. */
10549 if (bit_depth == 16)
10550 png_set_strip_16 (png_ptr);
10551
10552 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
10553 if available. */
10554 png_set_expand (png_ptr);
10555
10556 /* Convert grayscale images to RGB. */
10557 if (color_type == PNG_COLOR_TYPE_GRAY
10558 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
10559 png_set_gray_to_rgb (png_ptr);
10560
10561 /* The value 2.2 is a guess for PC monitors from PNG example.c. */
10562 gamma_str = getenv ("SCREEN_GAMMA");
10563 screen_gamma = gamma_str ? atof (gamma_str) : 2.2;
10564
10565 /* Tell the PNG lib to handle gamma correction for us. */
10566
10567 #if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
10568 if (png_get_sRGB (png_ptr, info_ptr, &intent))
10569 /* There is a special chunk in the image specifying the gamma. */
10570 png_set_sRGB (png_ptr, info_ptr, intent);
10571 else
10572 #endif
10573 if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
10574 /* Image contains gamma information. */
10575 png_set_gamma (png_ptr, screen_gamma, image_gamma);
10576 else
10577 /* Use a default of 0.5 for the image gamma. */
10578 png_set_gamma (png_ptr, screen_gamma, 0.5);
10579
10580 /* Handle alpha channel by combining the image with a background
10581 color. Do this only if a real alpha channel is supplied. For
10582 simple transparency, we prefer a clipping mask. */
10583 if (!transparent_p)
10584 {
10585 png_color_16 *image_background;
10586
10587 if (png_get_bKGD (png_ptr, info_ptr, &image_background))
10588 /* Image contains a background color with which to
10589 combine the image. */
10590 png_set_background (png_ptr, image_background,
10591 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
10592 else
10593 {
10594 /* Image does not contain a background color with which
10595 to combine the image data via an alpha channel. Use
10596 the frame's background instead. */
10597 XColor color;
10598 Colormap cmap;
10599 png_color_16 frame_background;
10600
10601 BLOCK_INPUT;
10602 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
10603 color.pixel = FRAME_BACKGROUND_PIXEL (f);
10604 XQueryColor (FRAME_W32_DISPLAY (f), cmap, &color);
10605 UNBLOCK_INPUT;
10606
10607 bzero (&frame_background, sizeof frame_background);
10608 frame_background.red = color.red;
10609 frame_background.green = color.green;
10610 frame_background.blue = color.blue;
10611
10612 png_set_background (png_ptr, &frame_background,
10613 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
10614 }
10615 }
10616
10617 /* Update info structure. */
10618 png_read_update_info (png_ptr, info_ptr);
10619
10620 /* Get number of channels. Valid values are 1 for grayscale images
10621 and images with a palette, 2 for grayscale images with transparency
10622 information (alpha channel), 3 for RGB images, and 4 for RGB
10623 images with alpha channel, i.e. RGBA. If conversions above were
10624 sufficient we should only have 3 or 4 channels here. */
10625 channels = png_get_channels (png_ptr, info_ptr);
10626 xassert (channels == 3 || channels == 4);
10627
10628 /* Number of bytes needed for one row of the image. */
10629 row_bytes = png_get_rowbytes (png_ptr, info_ptr);
10630
10631 /* Allocate memory for the image. */
10632 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
10633 rows = (png_byte **) xmalloc (height * sizeof *rows);
10634 for (i = 0; i < height; ++i)
10635 rows[i] = pixels + i * row_bytes;
10636
10637 /* Read the entire image. */
10638 png_read_image (png_ptr, rows);
10639 png_read_end (png_ptr, info_ptr);
10640 if (fp)
10641 {
10642 fclose (fp);
10643 fp = NULL;
10644 }
10645
10646 BLOCK_INPUT;
10647
10648 /* Create the X image and pixmap. */
10649 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
10650 &img->pixmap))
10651 {
10652 UNBLOCK_INPUT;
10653 goto error;
10654 }
10655
10656 /* Create an image and pixmap serving as mask if the PNG image
10657 contains an alpha channel. */
10658 if (channels == 4
10659 && !transparent_p
10660 && !x_create_x_image_and_pixmap (f, width, height, 1,
10661 &mask_img, &img->mask))
10662 {
10663 x_destroy_x_image (ximg);
10664 XFreePixmap (FRAME_W32_DISPLAY (f), img->pixmap);
10665 img->pixmap = 0;
10666 UNBLOCK_INPUT;
10667 goto error;
10668 }
10669
10670 /* Fill the X image and mask from PNG data. */
10671 init_color_table ();
10672
10673 for (y = 0; y < height; ++y)
10674 {
10675 png_byte *p = rows[y];
10676
10677 for (x = 0; x < width; ++x)
10678 {
10679 unsigned r, g, b;
10680
10681 r = *p++ << 8;
10682 g = *p++ << 8;
10683 b = *p++ << 8;
10684 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
10685
10686 /* An alpha channel, aka mask channel, associates variable
10687 transparency with an image. Where other image formats
10688 support binary transparency---fully transparent or fully
10689 opaque---PNG allows up to 254 levels of partial transparency.
10690 The PNG library implements partial transparency by combining
10691 the image with a specified background color.
10692
10693 I'm not sure how to handle this here nicely: because the
10694 background on which the image is displayed may change, for
10695 real alpha channel support, it would be necessary to create
10696 a new image for each possible background.
10697
10698 What I'm doing now is that a mask is created if we have
10699 boolean transparency information. Otherwise I'm using
10700 the frame's background color to combine the image with. */
10701
10702 if (channels == 4)
10703 {
10704 if (mask_img)
10705 XPutPixel (mask_img, x, y, *p > 0);
10706 ++p;
10707 }
10708 }
10709 }
10710
10711 /* Remember colors allocated for this image. */
10712 img->colors = colors_in_color_table (&img->ncolors);
10713 free_color_table ();
10714
10715 /* Clean up. */
10716 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
10717 xfree (rows);
10718 xfree (pixels);
10719
10720 img->width = width;
10721 img->height = height;
10722
10723 /* Put the image into the pixmap, then free the X image and its buffer. */
10724 x_put_x_image (f, ximg, img->pixmap, width, height);
10725 x_destroy_x_image (ximg);
10726
10727 /* Same for the mask. */
10728 if (mask_img)
10729 {
10730 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
10731 x_destroy_x_image (mask_img);
10732 }
10733
10734 UNBLOCK_INPUT;
10735 UNGCPRO;
10736 return 1;
10737 }
10738
10739 #endif /* HAVE_PNG != 0 */
10740
10741
10742 \f
10743 /***********************************************************************
10744 JPEG
10745 ***********************************************************************/
10746
10747 #if HAVE_JPEG
10748
10749 /* Work around a warning about HAVE_STDLIB_H being redefined in
10750 jconfig.h. */
10751 #ifdef HAVE_STDLIB_H
10752 #define HAVE_STDLIB_H_1
10753 #undef HAVE_STDLIB_H
10754 #endif /* HAVE_STLIB_H */
10755
10756 #include <jpeglib.h>
10757 #include <jerror.h>
10758 #include <setjmp.h>
10759
10760 #ifdef HAVE_STLIB_H_1
10761 #define HAVE_STDLIB_H 1
10762 #endif
10763
10764 static int jpeg_image_p P_ ((Lisp_Object object));
10765 static int jpeg_load P_ ((struct frame *f, struct image *img));
10766
10767 /* The symbol `jpeg' identifying images of this type. */
10768
10769 Lisp_Object Qjpeg;
10770
10771 /* Indices of image specification fields in gs_format, below. */
10772
10773 enum jpeg_keyword_index
10774 {
10775 JPEG_TYPE,
10776 JPEG_DATA,
10777 JPEG_FILE,
10778 JPEG_ASCENT,
10779 JPEG_MARGIN,
10780 JPEG_RELIEF,
10781 JPEG_ALGORITHM,
10782 JPEG_HEURISTIC_MASK,
10783 JPEG_LAST
10784 };
10785
10786 /* Vector of image_keyword structures describing the format
10787 of valid user-defined image specifications. */
10788
10789 static struct image_keyword jpeg_format[JPEG_LAST] =
10790 {
10791 {":type", IMAGE_SYMBOL_VALUE, 1},
10792 {":data", IMAGE_STRING_VALUE, 0},
10793 {":file", IMAGE_STRING_VALUE, 0},
10794 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
10795 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
10796 {":relief", IMAGE_INTEGER_VALUE, 0},
10797 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10798 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
10799 };
10800
10801 /* Structure describing the image type `jpeg'. */
10802
10803 static struct image_type jpeg_type =
10804 {
10805 &Qjpeg,
10806 jpeg_image_p,
10807 jpeg_load,
10808 x_clear_image,
10809 NULL
10810 };
10811
10812
10813 /* Return non-zero if OBJECT is a valid JPEG image specification. */
10814
10815 static int
10816 jpeg_image_p (object)
10817 Lisp_Object object;
10818 {
10819 struct image_keyword fmt[JPEG_LAST];
10820
10821 bcopy (jpeg_format, fmt, sizeof fmt);
10822
10823 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg)
10824 || (fmt[JPEG_ASCENT].count
10825 && XFASTINT (fmt[JPEG_ASCENT].value) > 100))
10826 return 0;
10827
10828 /* Must specify either the :data or :file keyword. */
10829 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
10830 }
10831
10832
10833 struct my_jpeg_error_mgr
10834 {
10835 struct jpeg_error_mgr pub;
10836 jmp_buf setjmp_buffer;
10837 };
10838
10839 static void
10840 my_error_exit (cinfo)
10841 j_common_ptr cinfo;
10842 {
10843 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
10844 longjmp (mgr->setjmp_buffer, 1);
10845 }
10846
10847 /* Init source method for JPEG data source manager. Called by
10848 jpeg_read_header() before any data is actually read. See
10849 libjpeg.doc from the JPEG lib distribution. */
10850
10851 static void
10852 our_init_source (cinfo)
10853 j_decompress_ptr cinfo;
10854 {
10855 }
10856
10857
10858 /* Fill input buffer method for JPEG data source manager. Called
10859 whenever more data is needed. We read the whole image in one step,
10860 so this only adds a fake end of input marker at the end. */
10861
10862 static boolean
10863 our_fill_input_buffer (cinfo)
10864 j_decompress_ptr cinfo;
10865 {
10866 /* Insert a fake EOI marker. */
10867 struct jpeg_source_mgr *src = cinfo->src;
10868 static JOCTET buffer[2];
10869
10870 buffer[0] = (JOCTET) 0xFF;
10871 buffer[1] = (JOCTET) JPEG_EOI;
10872
10873 src->next_input_byte = buffer;
10874 src->bytes_in_buffer = 2;
10875 return TRUE;
10876 }
10877
10878
10879 /* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
10880 is the JPEG data source manager. */
10881
10882 static void
10883 our_skip_input_data (cinfo, num_bytes)
10884 j_decompress_ptr cinfo;
10885 long num_bytes;
10886 {
10887 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
10888
10889 if (src)
10890 {
10891 if (num_bytes > src->bytes_in_buffer)
10892 ERREXIT (cinfo, JERR_INPUT_EOF);
10893
10894 src->bytes_in_buffer -= num_bytes;
10895 src->next_input_byte += num_bytes;
10896 }
10897 }
10898
10899
10900 /* Method to terminate data source. Called by
10901 jpeg_finish_decompress() after all data has been processed. */
10902
10903 static void
10904 our_term_source (cinfo)
10905 j_decompress_ptr cinfo;
10906 {
10907 }
10908
10909
10910 /* Set up the JPEG lib for reading an image from DATA which contains
10911 LEN bytes. CINFO is the decompression info structure created for
10912 reading the image. */
10913
10914 static void
10915 jpeg_memory_src (cinfo, data, len)
10916 j_decompress_ptr cinfo;
10917 JOCTET *data;
10918 unsigned int len;
10919 {
10920 struct jpeg_source_mgr *src;
10921
10922 if (cinfo->src == NULL)
10923 {
10924 /* First time for this JPEG object? */
10925 cinfo->src = (struct jpeg_source_mgr *)
10926 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
10927 sizeof (struct jpeg_source_mgr));
10928 src = (struct jpeg_source_mgr *) cinfo->src;
10929 src->next_input_byte = data;
10930 }
10931
10932 src = (struct jpeg_source_mgr *) cinfo->src;
10933 src->init_source = our_init_source;
10934 src->fill_input_buffer = our_fill_input_buffer;
10935 src->skip_input_data = our_skip_input_data;
10936 src->resync_to_restart = jpeg_resync_to_restart; /* Use default method. */
10937 src->term_source = our_term_source;
10938 src->bytes_in_buffer = len;
10939 src->next_input_byte = data;
10940 }
10941
10942
10943 /* Load image IMG for use on frame F. Patterned after example.c
10944 from the JPEG lib. */
10945
10946 static int
10947 jpeg_load (f, img)
10948 struct frame *f;
10949 struct image *img;
10950 {
10951 struct jpeg_decompress_struct cinfo;
10952 struct my_jpeg_error_mgr mgr;
10953 Lisp_Object file, specified_file;
10954 Lisp_Object specified_data;
10955 FILE *fp = NULL;
10956 JSAMPARRAY buffer;
10957 int row_stride, x, y;
10958 XImage *ximg = NULL;
10959 int rc;
10960 unsigned long *colors;
10961 int width, height;
10962 struct gcpro gcpro1;
10963
10964 /* Open the JPEG file. */
10965 specified_file = image_spec_value (img->spec, QCfile, NULL);
10966 specified_data = image_spec_value (img->spec, QCdata, NULL);
10967 file = Qnil;
10968 GCPRO1 (file);
10969
10970 if (NILP (specified_data))
10971 {
10972 file = x_find_image_file (specified_file);
10973 if (!STRINGP (file))
10974 {
10975 image_error ("Cannot find image file `%s'", specified_file, Qnil);
10976 UNGCPRO;
10977 return 0;
10978 }
10979
10980 fp = fopen (XSTRING (file)->data, "r");
10981 if (fp == NULL)
10982 {
10983 image_error ("Cannot open `%s'", file, Qnil);
10984 UNGCPRO;
10985 return 0;
10986 }
10987 }
10988
10989 /* Customize libjpeg's error handling to call my_error_exit when an
10990 error is detected. This function will perform a longjmp. */
10991 mgr.pub.error_exit = my_error_exit;
10992 cinfo.err = jpeg_std_error (&mgr.pub);
10993
10994 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
10995 {
10996 if (rc == 1)
10997 {
10998 /* Called from my_error_exit. Display a JPEG error. */
10999 char buffer[JMSG_LENGTH_MAX];
11000 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
11001 image_error ("Error reading JPEG image `%s': %s", img->spec,
11002 build_string (buffer));
11003 }
11004
11005 /* Close the input file and destroy the JPEG object. */
11006 if (fp)
11007 fclose (fp);
11008 jpeg_destroy_decompress (&cinfo);
11009
11010 BLOCK_INPUT;
11011
11012 /* If we already have an XImage, free that. */
11013 x_destroy_x_image (ximg);
11014
11015 /* Free pixmap and colors. */
11016 x_clear_image (f, img);
11017
11018 UNBLOCK_INPUT;
11019 UNGCPRO;
11020 return 0;
11021 }
11022
11023 /* Create the JPEG decompression object. Let it read from fp.
11024 Read the JPEG image header. */
11025 jpeg_create_decompress (&cinfo);
11026
11027 if (NILP (specified_data))
11028 jpeg_stdio_src (&cinfo, fp);
11029 else
11030 jpeg_memory_src (&cinfo, XSTRING (specified_data)->data,
11031 STRING_BYTES (XSTRING (specified_data)));
11032
11033 jpeg_read_header (&cinfo, TRUE);
11034
11035 /* Customize decompression so that color quantization will be used.
11036 Start decompression. */
11037 cinfo.quantize_colors = TRUE;
11038 jpeg_start_decompress (&cinfo);
11039 width = img->width = cinfo.output_width;
11040 height = img->height = cinfo.output_height;
11041
11042 BLOCK_INPUT;
11043
11044 /* Create X image and pixmap. */
11045 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
11046 &img->pixmap))
11047 {
11048 UNBLOCK_INPUT;
11049 longjmp (mgr.setjmp_buffer, 2);
11050 }
11051
11052 /* Allocate colors. When color quantization is used,
11053 cinfo.actual_number_of_colors has been set with the number of
11054 colors generated, and cinfo.colormap is a two-dimensional array
11055 of color indices in the range 0..cinfo.actual_number_of_colors.
11056 No more than 255 colors will be generated. */
11057 {
11058 int i, ir, ig, ib;
11059
11060 if (cinfo.out_color_components > 2)
11061 ir = 0, ig = 1, ib = 2;
11062 else if (cinfo.out_color_components > 1)
11063 ir = 0, ig = 1, ib = 0;
11064 else
11065 ir = 0, ig = 0, ib = 0;
11066
11067 /* Use the color table mechanism because it handles colors that
11068 cannot be allocated nicely. Such colors will be replaced with
11069 a default color, and we don't have to care about which colors
11070 can be freed safely, and which can't. */
11071 init_color_table ();
11072 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
11073 * sizeof *colors);
11074
11075 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
11076 {
11077 /* Multiply RGB values with 255 because X expects RGB values
11078 in the range 0..0xffff. */
11079 int r = cinfo.colormap[ir][i] << 8;
11080 int g = cinfo.colormap[ig][i] << 8;
11081 int b = cinfo.colormap[ib][i] << 8;
11082 colors[i] = lookup_rgb_color (f, r, g, b);
11083 }
11084
11085 /* Remember those colors actually allocated. */
11086 img->colors = colors_in_color_table (&img->ncolors);
11087 free_color_table ();
11088 }
11089
11090 /* Read pixels. */
11091 row_stride = width * cinfo.output_components;
11092 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
11093 row_stride, 1);
11094 for (y = 0; y < height; ++y)
11095 {
11096 jpeg_read_scanlines (&cinfo, buffer, 1);
11097 for (x = 0; x < cinfo.output_width; ++x)
11098 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
11099 }
11100
11101 /* Clean up. */
11102 jpeg_finish_decompress (&cinfo);
11103 jpeg_destroy_decompress (&cinfo);
11104 if (fp)
11105 fclose (fp);
11106
11107 /* Put the image into the pixmap. */
11108 x_put_x_image (f, ximg, img->pixmap, width, height);
11109 x_destroy_x_image (ximg);
11110 UNBLOCK_INPUT;
11111 UNGCPRO;
11112 return 1;
11113 }
11114
11115 #endif /* HAVE_JPEG */
11116
11117
11118 \f
11119 /***********************************************************************
11120 TIFF
11121 ***********************************************************************/
11122
11123 #if HAVE_TIFF
11124
11125 #include <tiffio.h>
11126
11127 static int tiff_image_p P_ ((Lisp_Object object));
11128 static int tiff_load P_ ((struct frame *f, struct image *img));
11129
11130 /* The symbol `tiff' identifying images of this type. */
11131
11132 Lisp_Object Qtiff;
11133
11134 /* Indices of image specification fields in tiff_format, below. */
11135
11136 enum tiff_keyword_index
11137 {
11138 TIFF_TYPE,
11139 TIFF_DATA,
11140 TIFF_FILE,
11141 TIFF_ASCENT,
11142 TIFF_MARGIN,
11143 TIFF_RELIEF,
11144 TIFF_ALGORITHM,
11145 TIFF_HEURISTIC_MASK,
11146 TIFF_LAST
11147 };
11148
11149 /* Vector of image_keyword structures describing the format
11150 of valid user-defined image specifications. */
11151
11152 static struct image_keyword tiff_format[TIFF_LAST] =
11153 {
11154 {":type", IMAGE_SYMBOL_VALUE, 1},
11155 {":data", IMAGE_STRING_VALUE, 0},
11156 {":file", IMAGE_STRING_VALUE, 0},
11157 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
11158 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
11159 {":relief", IMAGE_INTEGER_VALUE, 0},
11160 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11161 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
11162 };
11163
11164 /* Structure describing the image type `tiff'. */
11165
11166 static struct image_type tiff_type =
11167 {
11168 &Qtiff,
11169 tiff_image_p,
11170 tiff_load,
11171 x_clear_image,
11172 NULL
11173 };
11174
11175
11176 /* Return non-zero if OBJECT is a valid TIFF image specification. */
11177
11178 static int
11179 tiff_image_p (object)
11180 Lisp_Object object;
11181 {
11182 struct image_keyword fmt[TIFF_LAST];
11183 bcopy (tiff_format, fmt, sizeof fmt);
11184
11185 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff)
11186 || (fmt[TIFF_ASCENT].count
11187 && XFASTINT (fmt[TIFF_ASCENT].value) > 100))
11188 return 0;
11189
11190 /* Must specify either the :data or :file keyword. */
11191 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
11192 }
11193
11194
11195 /* Reading from a memory buffer for TIFF images Based on the PNG
11196 memory source, but we have to provide a lot of extra functions.
11197 Blah.
11198
11199 We really only need to implement read and seek, but I am not
11200 convinced that the TIFF library is smart enough not to destroy
11201 itself if we only hand it the function pointers we need to
11202 override. */
11203
11204 typedef struct
11205 {
11206 unsigned char *bytes;
11207 size_t len;
11208 int index;
11209 }
11210 tiff_memory_source;
11211
11212 static size_t
11213 tiff_read_from_memory (data, buf, size)
11214 thandle_t data;
11215 tdata_t buf;
11216 tsize_t size;
11217 {
11218 tiff_memory_source *src = (tiff_memory_source *) data;
11219
11220 if (size > src->len - src->index)
11221 return (size_t) -1;
11222 bcopy (src->bytes + src->index, buf, size);
11223 src->index += size;
11224 return size;
11225 }
11226
11227 static size_t
11228 tiff_write_from_memory (data, buf, size)
11229 thandle_t data;
11230 tdata_t buf;
11231 tsize_t size;
11232 {
11233 return (size_t) -1;
11234 }
11235
11236 static toff_t
11237 tiff_seek_in_memory (data, off, whence)
11238 thandle_t data;
11239 toff_t off;
11240 int whence;
11241 {
11242 tiff_memory_source *src = (tiff_memory_source *) data;
11243 int idx;
11244
11245 switch (whence)
11246 {
11247 case SEEK_SET: /* Go from beginning of source. */
11248 idx = off;
11249 break;
11250
11251 case SEEK_END: /* Go from end of source. */
11252 idx = src->len + off;
11253 break;
11254
11255 case SEEK_CUR: /* Go from current position. */
11256 idx = src->index + off;
11257 break;
11258
11259 default: /* Invalid `whence'. */
11260 return -1;
11261 }
11262
11263 if (idx > src->len || idx < 0)
11264 return -1;
11265
11266 src->index = idx;
11267 return src->index;
11268 }
11269
11270 static int
11271 tiff_close_memory (data)
11272 thandle_t data;
11273 {
11274 /* NOOP */
11275 return 0;
11276 }
11277
11278 static int
11279 tiff_mmap_memory (data, pbase, psize)
11280 thandle_t data;
11281 tdata_t *pbase;
11282 toff_t *psize;
11283 {
11284 /* It is already _IN_ memory. */
11285 return 0;
11286 }
11287
11288 static void
11289 tiff_unmap_memory (data, base, size)
11290 thandle_t data;
11291 tdata_t base;
11292 toff_t size;
11293 {
11294 /* We don't need to do this. */
11295 }
11296
11297 static toff_t
11298 tiff_size_of_memory (data)
11299 thandle_t data;
11300 {
11301 return ((tiff_memory_source *) data)->len;
11302 }
11303
11304 /* Load TIFF image IMG for use on frame F. Value is non-zero if
11305 successful. */
11306
11307 static int
11308 tiff_load (f, img)
11309 struct frame *f;
11310 struct image *img;
11311 {
11312 Lisp_Object file, specified_file;
11313 Lisp_Object specified_data;
11314 TIFF *tiff;
11315 int width, height, x, y;
11316 uint32 *buf;
11317 int rc;
11318 XImage *ximg;
11319 struct gcpro gcpro1;
11320 tiff_memory_source memsrc;
11321
11322 specified_file = image_spec_value (img->spec, QCfile, NULL);
11323 specified_data = image_spec_value (img->spec, QCdata, NULL);
11324 file = Qnil;
11325 GCPRO1 (file);
11326
11327 if (NILP (specified_data))
11328 {
11329 /* Read from a file */
11330 file = x_find_image_file (specified_file);
11331 if (!STRINGP (file))
11332 {
11333 image_error ("Cannot find image file `%s'", file, Qnil);
11334 UNGCPRO;
11335 return 0;
11336 }
11337
11338 /* Try to open the image file. */
11339 tiff = TIFFOpen (XSTRING (file)->data, "r");
11340 if (tiff == NULL)
11341 {
11342 image_error ("Cannot open `%s'", file, Qnil);
11343 UNGCPRO;
11344 return 0;
11345 }
11346 }
11347 else
11348 {
11349 /* Memory source! */
11350 memsrc.bytes = XSTRING (specified_data)->data;
11351 memsrc.len = STRING_BYTES (XSTRING (specified_data));
11352 memsrc.index = 0;
11353
11354 tiff = TIFFClientOpen ("memory_source", "r", &memsrc,
11355 (TIFFReadWriteProc) tiff_read_from_memory,
11356 (TIFFReadWriteProc) tiff_write_from_memory,
11357 tiff_seek_in_memory,
11358 tiff_close_memory,
11359 tiff_size_of_memory,
11360 tiff_mmap_memory,
11361 tiff_unmap_memory);
11362
11363 if (!tiff)
11364 {
11365 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
11366 UNGCPRO;
11367 return 0;
11368 }
11369 }
11370
11371 /* Get width and height of the image, and allocate a raster buffer
11372 of width x height 32-bit values. */
11373 TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
11374 TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
11375 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
11376
11377 rc = TIFFReadRGBAImage (tiff, width, height, buf, 0);
11378 TIFFClose (tiff);
11379 if (!rc)
11380 {
11381 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
11382 xfree (buf);
11383 UNGCPRO;
11384 return 0;
11385 }
11386
11387 BLOCK_INPUT;
11388
11389 /* Create the X image and pixmap. */
11390 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
11391 {
11392 UNBLOCK_INPUT;
11393 xfree (buf);
11394 UNGCPRO;
11395 return 0;
11396 }
11397
11398 /* Initialize the color table. */
11399 init_color_table ();
11400
11401 /* Process the pixel raster. Origin is in the lower-left corner. */
11402 for (y = 0; y < height; ++y)
11403 {
11404 uint32 *row = buf + y * width;
11405
11406 for (x = 0; x < width; ++x)
11407 {
11408 uint32 abgr = row[x];
11409 int r = TIFFGetR (abgr) << 8;
11410 int g = TIFFGetG (abgr) << 8;
11411 int b = TIFFGetB (abgr) << 8;
11412 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
11413 }
11414 }
11415
11416 /* Remember the colors allocated for the image. Free the color table. */
11417 img->colors = colors_in_color_table (&img->ncolors);
11418 free_color_table ();
11419
11420 /* Put the image into the pixmap, then free the X image and its buffer. */
11421 x_put_x_image (f, ximg, img->pixmap, width, height);
11422 x_destroy_x_image (ximg);
11423 xfree (buf);
11424 UNBLOCK_INPUT;
11425
11426 img->width = width;
11427 img->height = height;
11428
11429 UNGCPRO;
11430 return 1;
11431 }
11432
11433 #endif /* HAVE_TIFF != 0 */
11434
11435
11436 \f
11437 /***********************************************************************
11438 GIF
11439 ***********************************************************************/
11440
11441 #if HAVE_GIF
11442
11443 #include <gif_lib.h>
11444
11445 static int gif_image_p P_ ((Lisp_Object object));
11446 static int gif_load P_ ((struct frame *f, struct image *img));
11447
11448 /* The symbol `gif' identifying images of this type. */
11449
11450 Lisp_Object Qgif;
11451
11452 /* Indices of image specification fields in gif_format, below. */
11453
11454 enum gif_keyword_index
11455 {
11456 GIF_TYPE,
11457 GIF_DATA,
11458 GIF_FILE,
11459 GIF_ASCENT,
11460 GIF_MARGIN,
11461 GIF_RELIEF,
11462 GIF_ALGORITHM,
11463 GIF_HEURISTIC_MASK,
11464 GIF_IMAGE,
11465 GIF_LAST
11466 };
11467
11468 /* Vector of image_keyword structures describing the format
11469 of valid user-defined image specifications. */
11470
11471 static struct image_keyword gif_format[GIF_LAST] =
11472 {
11473 {":type", IMAGE_SYMBOL_VALUE, 1},
11474 {":data", IMAGE_STRING_VALUE, 0},
11475 {":file", IMAGE_STRING_VALUE, 0},
11476 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
11477 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
11478 {":relief", IMAGE_INTEGER_VALUE, 0},
11479 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11480 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11481 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}
11482 };
11483
11484 /* Structure describing the image type `gif'. */
11485
11486 static struct image_type gif_type =
11487 {
11488 &Qgif,
11489 gif_image_p,
11490 gif_load,
11491 x_clear_image,
11492 NULL
11493 };
11494
11495 /* Return non-zero if OBJECT is a valid GIF image specification. */
11496
11497 static int
11498 gif_image_p (object)
11499 Lisp_Object object;
11500 {
11501 struct image_keyword fmt[GIF_LAST];
11502 bcopy (gif_format, fmt, sizeof fmt);
11503
11504 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif)
11505 || (fmt[GIF_ASCENT].count
11506 && XFASTINT (fmt[GIF_ASCENT].value) > 100))
11507 return 0;
11508
11509 /* Must specify either the :data or :file keyword. */
11510 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
11511 }
11512
11513 /* Reading a GIF image from memory
11514 Based on the PNG memory stuff to a certain extent. */
11515
11516 typedef struct
11517 {
11518 unsigned char *bytes;
11519 size_t len;
11520 int index;
11521 }
11522 gif_memory_source;
11523
11524 /* Make the current memory source available to gif_read_from_memory.
11525 It's done this way because not all versions of libungif support
11526 a UserData field in the GifFileType structure. */
11527 static gif_memory_source *current_gif_memory_src;
11528
11529 static int
11530 gif_read_from_memory (file, buf, len)
11531 GifFileType *file;
11532 GifByteType *buf;
11533 int len;
11534 {
11535 gif_memory_source *src = current_gif_memory_src;
11536
11537 if (len > src->len - src->index)
11538 return -1;
11539
11540 bcopy (src->bytes + src->index, buf, len);
11541 src->index += len;
11542 return len;
11543 }
11544
11545
11546 /* Load GIF image IMG for use on frame F. Value is non-zero if
11547 successful. */
11548
11549 static int
11550 gif_load (f, img)
11551 struct frame *f;
11552 struct image *img;
11553 {
11554 Lisp_Object file, specified_file;
11555 Lisp_Object specified_data;
11556 int rc, width, height, x, y, i;
11557 XImage *ximg;
11558 ColorMapObject *gif_color_map;
11559 unsigned long pixel_colors[256];
11560 GifFileType *gif;
11561 struct gcpro gcpro1;
11562 Lisp_Object image;
11563 int ino, image_left, image_top, image_width, image_height;
11564 gif_memory_source memsrc;
11565 unsigned char *raster;
11566
11567 specified_file = image_spec_value (img->spec, QCfile, NULL);
11568 specified_data = image_spec_value (img->spec, QCdata, NULL);
11569 file = Qnil;
11570 GCPRO1 (file);
11571
11572 if (NILP (specified_data))
11573 {
11574 file = x_find_image_file (specified_file);
11575 if (!STRINGP (file))
11576 {
11577 image_error ("Cannot find image file `%s'", specified_file, Qnil);
11578 UNGCPRO;
11579 return 0;
11580 }
11581
11582 /* Open the GIF file. */
11583 gif = DGifOpenFileName (XSTRING (file)->data);
11584 if (gif == NULL)
11585 {
11586 image_error ("Cannot open `%s'", file, Qnil);
11587 UNGCPRO;
11588 return 0;
11589 }
11590 }
11591 else
11592 {
11593 /* Read from memory! */
11594 current_gif_memory_src = &memsrc;
11595 memsrc.bytes = XSTRING (specified_data)->data;
11596 memsrc.len = STRING_BYTES (XSTRING (specified_data));
11597 memsrc.index = 0;
11598
11599 gif = DGifOpen(&memsrc, gif_read_from_memory);
11600 if (!gif)
11601 {
11602 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
11603 UNGCPRO;
11604 return 0;
11605 }
11606 }
11607
11608 /* Read entire contents. */
11609 rc = DGifSlurp (gif);
11610 if (rc == GIF_ERROR)
11611 {
11612 image_error ("Error reading `%s'", img->spec, Qnil);
11613 DGifCloseFile (gif);
11614 UNGCPRO;
11615 return 0;
11616 }
11617
11618 image = image_spec_value (img->spec, QCindex, NULL);
11619 ino = INTEGERP (image) ? XFASTINT (image) : 0;
11620 if (ino >= gif->ImageCount)
11621 {
11622 image_error ("Invalid image number `%s' in image `%s'",
11623 image, img->spec);
11624 DGifCloseFile (gif);
11625 UNGCPRO;
11626 return 0;
11627 }
11628
11629 width = img->width = gif->SWidth;
11630 height = img->height = gif->SHeight;
11631
11632 BLOCK_INPUT;
11633
11634 /* Create the X image and pixmap. */
11635 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
11636 {
11637 UNBLOCK_INPUT;
11638 DGifCloseFile (gif);
11639 UNGCPRO;
11640 return 0;
11641 }
11642
11643 /* Allocate colors. */
11644 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
11645 if (!gif_color_map)
11646 gif_color_map = gif->SColorMap;
11647 init_color_table ();
11648 bzero (pixel_colors, sizeof pixel_colors);
11649
11650 for (i = 0; i < gif_color_map->ColorCount; ++i)
11651 {
11652 int r = gif_color_map->Colors[i].Red << 8;
11653 int g = gif_color_map->Colors[i].Green << 8;
11654 int b = gif_color_map->Colors[i].Blue << 8;
11655 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
11656 }
11657
11658 img->colors = colors_in_color_table (&img->ncolors);
11659 free_color_table ();
11660
11661 /* Clear the part of the screen image that are not covered by
11662 the image from the GIF file. Full animated GIF support
11663 requires more than can be done here (see the gif89 spec,
11664 disposal methods). Let's simply assume that the part
11665 not covered by a sub-image is in the frame's background color. */
11666 image_top = gif->SavedImages[ino].ImageDesc.Top;
11667 image_left = gif->SavedImages[ino].ImageDesc.Left;
11668 image_width = gif->SavedImages[ino].ImageDesc.Width;
11669 image_height = gif->SavedImages[ino].ImageDesc.Height;
11670
11671 for (y = 0; y < image_top; ++y)
11672 for (x = 0; x < width; ++x)
11673 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
11674
11675 for (y = image_top + image_height; y < height; ++y)
11676 for (x = 0; x < width; ++x)
11677 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
11678
11679 for (y = image_top; y < image_top + image_height; ++y)
11680 {
11681 for (x = 0; x < image_left; ++x)
11682 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
11683 for (x = image_left + image_width; x < width; ++x)
11684 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
11685 }
11686
11687 /* Read the GIF image into the X image. We use a local variable
11688 `raster' here because RasterBits below is a char *, and invites
11689 problems with bytes >= 0x80. */
11690 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
11691
11692 if (gif->SavedImages[ino].ImageDesc.Interlace)
11693 {
11694 static int interlace_start[] = {0, 4, 2, 1};
11695 static int interlace_increment[] = {8, 8, 4, 2};
11696 int pass, inc;
11697 int row = interlace_start[0];
11698
11699 pass = 0;
11700
11701 for (y = 0; y < image_height; y++)
11702 {
11703 if (row >= image_height)
11704 {
11705 row = interlace_start[++pass];
11706 while (row >= image_height)
11707 row = interlace_start[++pass];
11708 }
11709
11710 for (x = 0; x < image_width; x++)
11711 {
11712 int i = raster[(y * image_width) + x];
11713 XPutPixel (ximg, x + image_left, row + image_top,
11714 pixel_colors[i]);
11715 }
11716
11717 row += interlace_increment[pass];
11718 }
11719 }
11720 else
11721 {
11722 for (y = 0; y < image_height; ++y)
11723 for (x = 0; x < image_width; ++x)
11724 {
11725 int i = raster[y* image_width + x];
11726 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
11727 }
11728 }
11729
11730 DGifCloseFile (gif);
11731
11732 /* Put the image into the pixmap, then free the X image and its buffer. */
11733 x_put_x_image (f, ximg, img->pixmap, width, height);
11734 x_destroy_x_image (ximg);
11735 UNBLOCK_INPUT;
11736
11737 UNGCPRO;
11738 return 1;
11739 }
11740
11741 #endif /* HAVE_GIF != 0 */
11742
11743
11744 \f
11745 /***********************************************************************
11746 Ghostscript
11747 ***********************************************************************/
11748
11749 #ifdef HAVE_GHOSTSCRIPT
11750 static int gs_image_p P_ ((Lisp_Object object));
11751 static int gs_load P_ ((struct frame *f, struct image *img));
11752 static void gs_clear_image P_ ((struct frame *f, struct image *img));
11753
11754 /* The symbol `postscript' identifying images of this type. */
11755
11756 Lisp_Object Qpostscript;
11757
11758 /* Keyword symbols. */
11759
11760 Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
11761
11762 /* Indices of image specification fields in gs_format, below. */
11763
11764 enum gs_keyword_index
11765 {
11766 GS_TYPE,
11767 GS_PT_WIDTH,
11768 GS_PT_HEIGHT,
11769 GS_FILE,
11770 GS_LOADER,
11771 GS_BOUNDING_BOX,
11772 GS_ASCENT,
11773 GS_MARGIN,
11774 GS_RELIEF,
11775 GS_ALGORITHM,
11776 GS_HEURISTIC_MASK,
11777 GS_LAST
11778 };
11779
11780 /* Vector of image_keyword structures describing the format
11781 of valid user-defined image specifications. */
11782
11783 static struct image_keyword gs_format[GS_LAST] =
11784 {
11785 {":type", IMAGE_SYMBOL_VALUE, 1},
11786 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
11787 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
11788 {":file", IMAGE_STRING_VALUE, 1},
11789 {":loader", IMAGE_FUNCTION_VALUE, 0},
11790 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
11791 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
11792 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
11793 {":relief", IMAGE_INTEGER_VALUE, 0},
11794 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11795 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
11796 };
11797
11798 /* Structure describing the image type `ghostscript'. */
11799
11800 static struct image_type gs_type =
11801 {
11802 &Qpostscript,
11803 gs_image_p,
11804 gs_load,
11805 gs_clear_image,
11806 NULL
11807 };
11808
11809
11810 /* Free X resources of Ghostscript image IMG which is used on frame F. */
11811
11812 static void
11813 gs_clear_image (f, img)
11814 struct frame *f;
11815 struct image *img;
11816 {
11817 /* IMG->data.ptr_val may contain a recorded colormap. */
11818 xfree (img->data.ptr_val);
11819 x_clear_image (f, img);
11820 }
11821
11822
11823 /* Return non-zero if OBJECT is a valid Ghostscript image
11824 specification. */
11825
11826 static int
11827 gs_image_p (object)
11828 Lisp_Object object;
11829 {
11830 struct image_keyword fmt[GS_LAST];
11831 Lisp_Object tem;
11832 int i;
11833
11834 bcopy (gs_format, fmt, sizeof fmt);
11835
11836 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript)
11837 || (fmt[GS_ASCENT].count
11838 && XFASTINT (fmt[GS_ASCENT].value) > 100))
11839 return 0;
11840
11841 /* Bounding box must be a list or vector containing 4 integers. */
11842 tem = fmt[GS_BOUNDING_BOX].value;
11843 if (CONSP (tem))
11844 {
11845 for (i = 0; i < 4; ++i, tem = XCDR (tem))
11846 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
11847 return 0;
11848 if (!NILP (tem))
11849 return 0;
11850 }
11851 else if (VECTORP (tem))
11852 {
11853 if (XVECTOR (tem)->size != 4)
11854 return 0;
11855 for (i = 0; i < 4; ++i)
11856 if (!INTEGERP (XVECTOR (tem)->contents[i]))
11857 return 0;
11858 }
11859 else
11860 return 0;
11861
11862 return 1;
11863 }
11864
11865
11866 /* Load Ghostscript image IMG for use on frame F. Value is non-zero
11867 if successful. */
11868
11869 static int
11870 gs_load (f, img)
11871 struct frame *f;
11872 struct image *img;
11873 {
11874 char buffer[100];
11875 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
11876 struct gcpro gcpro1, gcpro2;
11877 Lisp_Object frame;
11878 double in_width, in_height;
11879 Lisp_Object pixel_colors = Qnil;
11880
11881 /* Compute pixel size of pixmap needed from the given size in the
11882 image specification. Sizes in the specification are in pt. 1 pt
11883 = 1/72 in, xdpi and ydpi are stored in the frame's X display
11884 info. */
11885 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
11886 in_width = XFASTINT (pt_width) / 72.0;
11887 img->width = in_width * FRAME_W32_DISPLAY_INFO (f)->resx;
11888 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
11889 in_height = XFASTINT (pt_height) / 72.0;
11890 img->height = in_height * FRAME_W32_DISPLAY_INFO (f)->resy;
11891
11892 /* Create the pixmap. */
11893 BLOCK_INPUT;
11894 xassert (img->pixmap == 0);
11895 img->pixmap = XCreatePixmap (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
11896 img->width, img->height,
11897 DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
11898 UNBLOCK_INPUT;
11899
11900 if (!img->pixmap)
11901 {
11902 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
11903 return 0;
11904 }
11905
11906 /* Call the loader to fill the pixmap. It returns a process object
11907 if successful. We do not record_unwind_protect here because
11908 other places in redisplay like calling window scroll functions
11909 don't either. Let the Lisp loader use `unwind-protect' instead. */
11910 GCPRO2 (window_and_pixmap_id, pixel_colors);
11911
11912 sprintf (buffer, "%lu %lu",
11913 (unsigned long) FRAME_W32_WINDOW (f),
11914 (unsigned long) img->pixmap);
11915 window_and_pixmap_id = build_string (buffer);
11916
11917 sprintf (buffer, "%lu %lu",
11918 FRAME_FOREGROUND_PIXEL (f),
11919 FRAME_BACKGROUND_PIXEL (f));
11920 pixel_colors = build_string (buffer);
11921
11922 XSETFRAME (frame, f);
11923 loader = image_spec_value (img->spec, QCloader, NULL);
11924 if (NILP (loader))
11925 loader = intern ("gs-load-image");
11926
11927 img->data.lisp_val = call6 (loader, frame, img->spec,
11928 make_number (img->width),
11929 make_number (img->height),
11930 window_and_pixmap_id,
11931 pixel_colors);
11932 UNGCPRO;
11933 return PROCESSP (img->data.lisp_val);
11934 }
11935
11936
11937 /* Kill the Ghostscript process that was started to fill PIXMAP on
11938 frame F. Called from XTread_socket when receiving an event
11939 telling Emacs that Ghostscript has finished drawing. */
11940
11941 void
11942 x_kill_gs_process (pixmap, f)
11943 Pixmap pixmap;
11944 struct frame *f;
11945 {
11946 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
11947 int class, i;
11948 struct image *img;
11949
11950 /* Find the image containing PIXMAP. */
11951 for (i = 0; i < c->used; ++i)
11952 if (c->images[i]->pixmap == pixmap)
11953 break;
11954
11955 /* Kill the GS process. We should have found PIXMAP in the image
11956 cache and its image should contain a process object. */
11957 xassert (i < c->used);
11958 img = c->images[i];
11959 xassert (PROCESSP (img->data.lisp_val));
11960 Fkill_process (img->data.lisp_val, Qnil);
11961 img->data.lisp_val = Qnil;
11962
11963 /* On displays with a mutable colormap, figure out the colors
11964 allocated for the image by looking at the pixels of an XImage for
11965 img->pixmap. */
11966 class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
11967 if (class != StaticColor && class != StaticGray && class != TrueColor)
11968 {
11969 XImage *ximg;
11970
11971 BLOCK_INPUT;
11972
11973 /* Try to get an XImage for img->pixmep. */
11974 ximg = XGetImage (FRAME_W32_DISPLAY (f), img->pixmap,
11975 0, 0, img->width, img->height, ~0, ZPixmap);
11976 if (ximg)
11977 {
11978 int x, y;
11979
11980 /* Initialize the color table. */
11981 init_color_table ();
11982
11983 /* For each pixel of the image, look its color up in the
11984 color table. After having done so, the color table will
11985 contain an entry for each color used by the image. */
11986 for (y = 0; y < img->height; ++y)
11987 for (x = 0; x < img->width; ++x)
11988 {
11989 unsigned long pixel = XGetPixel (ximg, x, y);
11990 lookup_pixel_color (f, pixel);
11991 }
11992
11993 /* Record colors in the image. Free color table and XImage. */
11994 img->colors = colors_in_color_table (&img->ncolors);
11995 free_color_table ();
11996 XDestroyImage (ximg);
11997
11998 #if 0 /* This doesn't seem to be the case. If we free the colors
11999 here, we get a BadAccess later in x_clear_image when
12000 freeing the colors. */
12001 /* We have allocated colors once, but Ghostscript has also
12002 allocated colors on behalf of us. So, to get the
12003 reference counts right, free them once. */
12004 if (img->ncolors)
12005 {
12006 Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
12007 XFreeColors (FRAME_W32_DISPLAY (f), cmap,
12008 img->colors, img->ncolors, 0);
12009 }
12010 #endif
12011 }
12012 else
12013 image_error ("Cannot get X image of `%s'; colors will not be freed",
12014 img->spec, Qnil);
12015
12016 UNBLOCK_INPUT;
12017 }
12018 }
12019
12020 #endif /* HAVE_GHOSTSCRIPT */
12021
12022 \f
12023 /***********************************************************************
12024 Window properties
12025 ***********************************************************************/
12026
12027 DEFUN ("x-change-window-property", Fx_change_window_property,
12028 Sx_change_window_property, 2, 3, 0,
12029 "Change window property PROP to VALUE on the X window of FRAME.\n\
12030 PROP and VALUE must be strings. FRAME nil or omitted means use the\n\
12031 selected frame. Value is VALUE.")
12032 (prop, value, frame)
12033 Lisp_Object frame, prop, value;
12034 {
12035 #if 0 /* TODO : port window properties to W32 */
12036 struct frame *f = check_x_frame (frame);
12037 Atom prop_atom;
12038
12039 CHECK_STRING (prop, 1);
12040 CHECK_STRING (value, 2);
12041
12042 BLOCK_INPUT;
12043 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
12044 XChangeProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
12045 prop_atom, XA_STRING, 8, PropModeReplace,
12046 XSTRING (value)->data, XSTRING (value)->size);
12047
12048 /* Make sure the property is set when we return. */
12049 XFlush (FRAME_W32_DISPLAY (f));
12050 UNBLOCK_INPUT;
12051
12052 #endif /* TODO */
12053
12054 return value;
12055 }
12056
12057
12058 DEFUN ("x-delete-window-property", Fx_delete_window_property,
12059 Sx_delete_window_property, 1, 2, 0,
12060 "Remove window property PROP from X window of FRAME.\n\
12061 FRAME nil or omitted means use the selected frame. Value is PROP.")
12062 (prop, frame)
12063 Lisp_Object prop, frame;
12064 {
12065 #if 0 /* TODO : port window properties to W32 */
12066
12067 struct frame *f = check_x_frame (frame);
12068 Atom prop_atom;
12069
12070 CHECK_STRING (prop, 1);
12071 BLOCK_INPUT;
12072 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
12073 XDeleteProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), prop_atom);
12074
12075 /* Make sure the property is removed when we return. */
12076 XFlush (FRAME_W32_DISPLAY (f));
12077 UNBLOCK_INPUT;
12078 #endif /* TODO */
12079
12080 return prop;
12081 }
12082
12083
12084 DEFUN ("x-window-property", Fx_window_property, Sx_window_property,
12085 1, 2, 0,
12086 "Value is the value of window property PROP on FRAME.\n\
12087 If FRAME is nil or omitted, use the selected frame. Value is nil\n\
12088 if FRAME hasn't a property with name PROP or if PROP has no string\n\
12089 value.")
12090 (prop, frame)
12091 Lisp_Object prop, frame;
12092 {
12093 #if 0 /* TODO : port window properties to W32 */
12094
12095 struct frame *f = check_x_frame (frame);
12096 Atom prop_atom;
12097 int rc;
12098 Lisp_Object prop_value = Qnil;
12099 char *tmp_data = NULL;
12100 Atom actual_type;
12101 int actual_format;
12102 unsigned long actual_size, bytes_remaining;
12103
12104 CHECK_STRING (prop, 1);
12105 BLOCK_INPUT;
12106 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
12107 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
12108 prop_atom, 0, 0, False, XA_STRING,
12109 &actual_type, &actual_format, &actual_size,
12110 &bytes_remaining, (unsigned char **) &tmp_data);
12111 if (rc == Success)
12112 {
12113 int size = bytes_remaining;
12114
12115 XFree (tmp_data);
12116 tmp_data = NULL;
12117
12118 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
12119 prop_atom, 0, bytes_remaining,
12120 False, XA_STRING,
12121 &actual_type, &actual_format,
12122 &actual_size, &bytes_remaining,
12123 (unsigned char **) &tmp_data);
12124 if (rc == Success)
12125 prop_value = make_string (tmp_data, size);
12126
12127 XFree (tmp_data);
12128 }
12129
12130 UNBLOCK_INPUT;
12131
12132 return prop_value;
12133
12134 #endif /* TODO */
12135 return Qnil;
12136 }
12137
12138
12139 \f
12140 /***********************************************************************
12141 Busy cursor
12142 ***********************************************************************/
12143
12144 /* If non-null, an asynchronous timer that, when it expires, displays
12145 an hourglass cursor on all frames. */
12146
12147 static struct atimer *hourglass_atimer;
12148
12149 /* Non-zero means an hourglass cursor is currently shown. */
12150
12151 static int hourglass_shown_p;
12152
12153 /* Number of seconds to wait before displaying an hourglass cursor. */
12154
12155 static Lisp_Object Vhourglass_delay;
12156
12157 /* Default number of seconds to wait before displaying an hourglass
12158 cursor. */
12159
12160 #define DEFAULT_HOURGLASS_DELAY 1
12161
12162 /* Function prototypes. */
12163
12164 static void show_hourglass P_ ((struct atimer *));
12165 static void hide_hourglass P_ ((void));
12166
12167
12168 /* Cancel a currently active hourglass timer, and start a new one. */
12169
12170 void
12171 start_hourglass ()
12172 {
12173 #if 0 /* TODO: cursor shape changes. */
12174 EMACS_TIME delay;
12175 int secs, usecs = 0;
12176
12177 cancel_hourglass ();
12178
12179 if (INTEGERP (Vhourglass_delay)
12180 && XINT (Vhourglass_delay) > 0)
12181 secs = XFASTINT (Vhourglass_delay);
12182 else if (FLOATP (Vhourglass_delay)
12183 && XFLOAT_DATA (Vhourglass_delay) > 0)
12184 {
12185 Lisp_Object tem;
12186 tem = Ftruncate (Vhourglass_delay, Qnil);
12187 secs = XFASTINT (tem);
12188 usecs = (XFLOAT_DATA (Vhourglass_delay) - secs) * 1000000;
12189 }
12190 else
12191 secs = DEFAULT_HOURGLASS_DELAY;
12192
12193 EMACS_SET_SECS_USECS (delay, secs, usecs);
12194 hourglass_atimer = start_atimer (ATIMER_RELATIVE, delay,
12195 show_hourglass, NULL);
12196 #endif
12197 }
12198
12199
12200 /* Cancel the hourglass cursor timer if active, hide an hourglass
12201 cursor if shown. */
12202
12203 void
12204 cancel_hourglass ()
12205 {
12206 if (hourglass_atimer)
12207 {
12208 cancel_atimer (hourglass_atimer);
12209 hourglass_atimer = NULL;
12210 }
12211
12212 if (hourglass_shown_p)
12213 hide_hourglass ();
12214 }
12215
12216
12217 /* Timer function of hourglass_atimer. TIMER is equal to
12218 hourglass_atimer.
12219
12220 Display an hourglass cursor on all frames by mapping the frames'
12221 hourglass_window. Set the hourglass_p flag in the frames'
12222 output_data.x structure to indicate that an hourglass cursor is
12223 shown on the frames. */
12224
12225 static void
12226 show_hourglass (timer)
12227 struct atimer *timer;
12228 {
12229 #if 0 /* TODO: cursor shape changes. */
12230 /* The timer implementation will cancel this timer automatically
12231 after this function has run. Set hourglass_atimer to null
12232 so that we know the timer doesn't have to be canceled. */
12233 hourglass_atimer = NULL;
12234
12235 if (!hourglass_shown_p)
12236 {
12237 Lisp_Object rest, frame;
12238
12239 BLOCK_INPUT;
12240
12241 FOR_EACH_FRAME (rest, frame)
12242 if (FRAME_W32_P (XFRAME (frame)))
12243 {
12244 struct frame *f = XFRAME (frame);
12245
12246 f->output_data.w32->hourglass_p = 1;
12247
12248 if (!f->output_data.w32->hourglass_window)
12249 {
12250 unsigned long mask = CWCursor;
12251 XSetWindowAttributes attrs;
12252
12253 attrs.cursor = f->output_data.w32->hourglass_cursor;
12254
12255 f->output_data.w32->hourglass_window
12256 = XCreateWindow (FRAME_X_DISPLAY (f),
12257 FRAME_OUTER_WINDOW (f),
12258 0, 0, 32000, 32000, 0, 0,
12259 InputOnly,
12260 CopyFromParent,
12261 mask, &attrs);
12262 }
12263
12264 XMapRaised (FRAME_X_DISPLAY (f),
12265 f->output_data.w32->hourglass_window);
12266 XFlush (FRAME_X_DISPLAY (f));
12267 }
12268
12269 hourglass_shown_p = 1;
12270 UNBLOCK_INPUT;
12271 }
12272 #endif
12273 }
12274
12275
12276 /* Hide the hourglass cursor on all frames, if it is currently shown. */
12277
12278 static void
12279 hide_hourglass ()
12280 {
12281 #if 0 /* TODO: cursor shape changes. */
12282 if (hourglass_shown_p)
12283 {
12284 Lisp_Object rest, frame;
12285
12286 BLOCK_INPUT;
12287 FOR_EACH_FRAME (rest, frame)
12288 {
12289 struct frame *f = XFRAME (frame);
12290
12291 if (FRAME_W32_P (f)
12292 /* Watch out for newly created frames. */
12293 && f->output_data.x->hourglass_window)
12294 {
12295 XUnmapWindow (FRAME_X_DISPLAY (f),
12296 f->output_data.x->hourglass_window);
12297 /* Sync here because XTread_socket looks at the
12298 hourglass_p flag that is reset to zero below. */
12299 XSync (FRAME_X_DISPLAY (f), False);
12300 f->output_data.x->hourglass_p = 0;
12301 }
12302 }
12303
12304 hourglass_shown_p = 0;
12305 UNBLOCK_INPUT;
12306 }
12307 #endif
12308 }
12309
12310
12311 \f
12312 /***********************************************************************
12313 Tool tips
12314 ***********************************************************************/
12315
12316 static Lisp_Object x_create_tip_frame P_ ((struct w32_display_info *,
12317 Lisp_Object));
12318
12319 /* The frame of a currently visible tooltip, or null. */
12320
12321 Lisp_Object tip_frame;
12322
12323 /* If non-nil, a timer started that hides the last tooltip when it
12324 fires. */
12325
12326 Lisp_Object tip_timer;
12327 Window tip_window;
12328
12329 static Lisp_Object
12330 unwind_create_tip_frame (frame)
12331 Lisp_Object frame;
12332 {
12333 Lisp_Object deleted;
12334
12335 deleted = unwind_create_frame (frame);
12336 if (EQ (deleted, Qt))
12337 {
12338 tip_window = NULL;
12339 tip_frame = Qnil;
12340 }
12341
12342 return deleted;
12343 }
12344
12345
12346 /* Create a frame for a tooltip on the display described by DPYINFO.
12347 PARMS is a list of frame parameters. Value is the frame.
12348
12349 Note that functions called here, esp. x_default_parameter can
12350 signal errors, for instance when a specified color name is
12351 undefined. We have to make sure that we're in a consistent state
12352 when this happens. */
12353
12354 static Lisp_Object
12355 x_create_tip_frame (dpyinfo, parms)
12356 struct w32_display_info *dpyinfo;
12357 Lisp_Object parms;
12358 {
12359 #if 0 /* TODO : w32 version */
12360 struct frame *f;
12361 Lisp_Object frame, tem;
12362 Lisp_Object name;
12363 long window_prompting = 0;
12364 int width, height;
12365 int count = BINDING_STACK_SIZE ();
12366 struct gcpro gcpro1, gcpro2, gcpro3;
12367 struct kboard *kb;
12368
12369 check_x ();
12370
12371 /* Use this general default value to start with until we know if
12372 this frame has a specified name. */
12373 Vx_resource_name = Vinvocation_name;
12374
12375 #ifdef MULTI_KBOARD
12376 kb = dpyinfo->kboard;
12377 #else
12378 kb = &the_only_kboard;
12379 #endif
12380
12381 /* Get the name of the frame to use for resource lookup. */
12382 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
12383 if (!STRINGP (name)
12384 && !EQ (name, Qunbound)
12385 && !NILP (name))
12386 error ("Invalid frame name--not a string or nil");
12387 Vx_resource_name = name;
12388
12389 frame = Qnil;
12390 GCPRO3 (parms, name, frame);
12391 f = make_frame (1);
12392 XSETFRAME (frame, f);
12393 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
12394 record_unwind_protect (unwind_create_tip_frame, frame);
12395
12396 f->output_method = output_w32;
12397 f->output_data.w32 =
12398 (struct w32_output *) xmalloc (sizeof (struct w32_output));
12399 bzero (f->output_data.w32, sizeof (struct w32_output));
12400 #if 0
12401 f->output_data.w32->icon_bitmap = -1;
12402 #endif
12403 f->output_data.w32->fontset = -1;
12404 f->icon_name = Qnil;
12405
12406 #ifdef GLYPH_DEBUG
12407 image_cache_refcount = FRAME_X_IMAGE_CACHE (f)->refcount;
12408 dpyinfo_refcount = dpyinfo->reference_count;
12409 #endif /* GLYPH_DEBUG */
12410 #ifdef MULTI_KBOARD
12411 FRAME_KBOARD (f) = kb;
12412 #endif
12413 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
12414 f->output_data.w32->explicit_parent = 0;
12415
12416 /* Set the name; the functions to which we pass f expect the name to
12417 be set. */
12418 if (EQ (name, Qunbound) || NILP (name))
12419 {
12420 f->name = build_string (dpyinfo->x_id_name);
12421 f->explicit_name = 0;
12422 }
12423 else
12424 {
12425 f->name = name;
12426 f->explicit_name = 1;
12427 /* use the frame's title when getting resources for this frame. */
12428 specbind (Qx_resource_name, name);
12429 }
12430
12431 /* Extract the window parameters from the supplied values
12432 that are needed to determine window geometry. */
12433 {
12434 Lisp_Object font;
12435
12436 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
12437
12438 BLOCK_INPUT;
12439 /* First, try whatever font the caller has specified. */
12440 if (STRINGP (font))
12441 {
12442 tem = Fquery_fontset (font, Qnil);
12443 if (STRINGP (tem))
12444 font = x_new_fontset (f, XSTRING (tem)->data);
12445 else
12446 font = x_new_font (f, XSTRING (font)->data);
12447 }
12448
12449 /* Try out a font which we hope has bold and italic variations. */
12450 if (!STRINGP (font))
12451 font = x_new_font (f, "-*-courier new-normal-r-*-*-*-100-*-*-*-*-iso8859-1");
12452 if (!STRINGP (font))
12453 font = x_new_font (f, "-misc-fixed-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
12454 if (! STRINGP (font))
12455 font = x_new_font (f, "-*-*-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
12456 if (! STRINGP (font))
12457 /* This was formerly the first thing tried, but it finds too many fonts
12458 and takes too long. */
12459 font = x_new_font (f, "-*-*-medium-r-*-*-*-*-*-*-c-*-iso8859-1");
12460 /* If those didn't work, look for something which will at least work. */
12461 if (! STRINGP (font))
12462 font = x_new_font (f, "-*-fixed-*-*-*-*-*-140-*-*-c-*-iso8859-1");
12463 UNBLOCK_INPUT;
12464 if (! STRINGP (font))
12465 font = build_string ("fixed");
12466
12467 x_default_parameter (f, parms, Qfont, font,
12468 "font", "Font", RES_TYPE_STRING);
12469 }
12470
12471 x_default_parameter (f, parms, Qborder_width, make_number (2),
12472 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
12473
12474 /* This defaults to 2 in order to match xterm. We recognize either
12475 internalBorderWidth or internalBorder (which is what xterm calls
12476 it). */
12477 if (NILP (Fassq (Qinternal_border_width, parms)))
12478 {
12479 Lisp_Object value;
12480
12481 value = w32_get_arg (parms, Qinternal_border_width,
12482 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
12483 if (! EQ (value, Qunbound))
12484 parms = Fcons (Fcons (Qinternal_border_width, value),
12485 parms);
12486 }
12487
12488 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
12489 "internalBorderWidth", "internalBorderWidth",
12490 RES_TYPE_NUMBER);
12491
12492 /* Also do the stuff which must be set before the window exists. */
12493 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
12494 "foreground", "Foreground", RES_TYPE_STRING);
12495 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
12496 "background", "Background", RES_TYPE_STRING);
12497 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
12498 "pointerColor", "Foreground", RES_TYPE_STRING);
12499 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
12500 "cursorColor", "Foreground", RES_TYPE_STRING);
12501 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
12502 "borderColor", "BorderColor", RES_TYPE_STRING);
12503
12504 /* Init faces before x_default_parameter is called for scroll-bar
12505 parameters because that function calls x_set_scroll_bar_width,
12506 which calls change_frame_size, which calls Fset_window_buffer,
12507 which runs hooks, which call Fvertical_motion. At the end, we
12508 end up in init_iterator with a null face cache, which should not
12509 happen. */
12510 init_frame_faces (f);
12511
12512 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
12513 window_prompting = x_figure_window_size (f, parms);
12514
12515 if (window_prompting & XNegative)
12516 {
12517 if (window_prompting & YNegative)
12518 f->output_data.w32->win_gravity = SouthEastGravity;
12519 else
12520 f->output_data.w32->win_gravity = NorthEastGravity;
12521 }
12522 else
12523 {
12524 if (window_prompting & YNegative)
12525 f->output_data.w32->win_gravity = SouthWestGravity;
12526 else
12527 f->output_data.w32->win_gravity = NorthWestGravity;
12528 }
12529
12530 f->output_data.w32->size_hint_flags = window_prompting;
12531 {
12532 XSetWindowAttributes attrs;
12533 unsigned long mask;
12534
12535 BLOCK_INPUT;
12536 mask = CWBackPixel | CWOverrideRedirect | CWSaveUnder | CWEventMask;
12537 /* Window managers looks at the override-redirect flag to
12538 determine whether or net to give windows a decoration (Xlib
12539 3.2.8). */
12540 attrs.override_redirect = True;
12541 attrs.save_under = True;
12542 attrs.background_pixel = FRAME_BACKGROUND_PIXEL (f);
12543 /* Arrange for getting MapNotify and UnmapNotify events. */
12544 attrs.event_mask = StructureNotifyMask;
12545 tip_window
12546 = FRAME_W32_WINDOW (f)
12547 = XCreateWindow (FRAME_W32_DISPLAY (f),
12548 FRAME_W32_DISPLAY_INFO (f)->root_window,
12549 /* x, y, width, height */
12550 0, 0, 1, 1,
12551 /* Border. */
12552 1,
12553 CopyFromParent, InputOutput, CopyFromParent,
12554 mask, &attrs);
12555 UNBLOCK_INPUT;
12556 }
12557
12558 x_make_gc (f);
12559
12560 x_default_parameter (f, parms, Qauto_raise, Qnil,
12561 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
12562 x_default_parameter (f, parms, Qauto_lower, Qnil,
12563 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
12564 x_default_parameter (f, parms, Qcursor_type, Qbox,
12565 "cursorType", "CursorType", RES_TYPE_SYMBOL);
12566
12567 /* Dimensions, especially f->height, must be done via change_frame_size.
12568 Change will not be effected unless different from the current
12569 f->height. */
12570 width = f->width;
12571 height = f->height;
12572 f->height = 0;
12573 SET_FRAME_WIDTH (f, 0);
12574 change_frame_size (f, height, width, 1, 0, 0);
12575
12576 f->no_split = 1;
12577
12578 UNGCPRO;
12579
12580 /* It is now ok to make the frame official even if we get an error
12581 below. And the frame needs to be on Vframe_list or making it
12582 visible won't work. */
12583 Vframe_list = Fcons (frame, Vframe_list);
12584 tip_frame = frame;
12585
12586 /* Now that the frame is official, it counts as a reference to
12587 its display. */
12588 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
12589
12590 return unbind_to (count, frame);
12591 #endif /* TODO */
12592 return Qnil;
12593 }
12594
12595 #ifdef TODO /* Tooltip support not complete. */
12596 DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
12597 "Show STRING in a \"tooltip\" window on frame FRAME.\n\
12598 A tooltip window is a small window displaying a string.\n\
12599 \n\
12600 FRAME nil or omitted means use the selected frame.\n\
12601 \n\
12602 PARMS is an optional list of frame parameters which can be\n\
12603 used to change the tooltip's appearance.\n\
12604 \n\
12605 Automatically hide the tooltip after TIMEOUT seconds.\n\
12606 TIMEOUT nil means use the default timeout of 5 seconds.\n\
12607 \n\
12608 If the list of frame parameters PARAMS contains a `left' parameters,\n\
12609 the tooltip is displayed at that x-position. Otherwise it is\n\
12610 displayed at the mouse position, with offset DX added (default is 5 if\n\
12611 DX isn't specified). Likewise for the y-position; if a `top' frame\n\
12612 parameter is specified, it determines the y-position of the tooltip\n\
12613 window, otherwise it is displayed at the mouse position, with offset\n\
12614 DY added (default is 10).")
12615 (string, frame, parms, timeout, dx, dy)
12616 Lisp_Object string, frame, parms, timeout, dx, dy;
12617 {
12618 struct frame *f;
12619 struct window *w;
12620 Window root, child;
12621 Lisp_Object buffer, top, left;
12622 struct buffer *old_buffer;
12623 struct text_pos pos;
12624 int i, width, height;
12625 int root_x, root_y, win_x, win_y;
12626 unsigned pmask;
12627 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
12628 int old_windows_or_buffers_changed = windows_or_buffers_changed;
12629 int count = specpdl_ptr - specpdl;
12630
12631 specbind (Qinhibit_redisplay, Qt);
12632
12633 GCPRO4 (string, parms, frame, timeout);
12634
12635 CHECK_STRING (string, 0);
12636 f = check_x_frame (frame);
12637 if (NILP (timeout))
12638 timeout = make_number (5);
12639 else
12640 CHECK_NATNUM (timeout, 2);
12641
12642 if (NILP (dx))
12643 dx = make_number (5);
12644 else
12645 CHECK_NUMBER (dx, 5);
12646
12647 if (NILP (dy))
12648 dy = make_number (-10);
12649 else
12650 CHECK_NUMBER (dy, 6);
12651
12652 if (NILP (last_show_tip_args))
12653 last_show_tip_args = Fmake_vector (make_number (3), Qnil);
12654
12655 if (!NILP (tip_frame))
12656 {
12657 Lisp_Object last_string = AREF (last_show_tip_args, 0);
12658 Lisp_Object last_frame = AREF (last_show_tip_args, 1);
12659 Lisp_Object last_parms = AREF (last_show_tip_args, 2);
12660
12661 if (EQ (frame, last_frame)
12662 && !NILP (Fequal (last_string, string))
12663 && !NILP (Fequal (last_parms, parms)))
12664 {
12665 struct frame *f = XFRAME (tip_frame);
12666
12667 /* Only DX and DY have changed. */
12668 if (!NILP (tip_timer))
12669 {
12670 Lisp_Object timer = tip_timer;
12671 tip_timer = Qnil;
12672 call1 (Qcancel_timer, timer);
12673 }
12674
12675 BLOCK_INPUT;
12676 compute_tip_xy (f, parms, dx, dy, &root_x, &root_y);
12677 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
12678 root_x, root_y - PIXEL_HEIGHT (f));
12679 UNBLOCK_INPUT;
12680 goto start_timer;
12681 }
12682 }
12683
12684 /* Hide a previous tip, if any. */
12685 Fx_hide_tip ();
12686
12687 ASET (last_show_tip_args, 0, string);
12688 ASET (last_show_tip_args, 1, frame);
12689 ASET (last_show_tip_args, 2, parms);
12690
12691 /* Add default values to frame parameters. */
12692 if (NILP (Fassq (Qname, parms)))
12693 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
12694 if (NILP (Fassq (Qinternal_border_width, parms)))
12695 parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
12696 if (NILP (Fassq (Qborder_width, parms)))
12697 parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
12698 if (NILP (Fassq (Qborder_color, parms)))
12699 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
12700 if (NILP (Fassq (Qbackground_color, parms)))
12701 parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
12702 parms);
12703
12704 /* Create a frame for the tooltip, and record it in the global
12705 variable tip_frame. */
12706 frame = x_create_tip_frame (FRAME_W32_DISPLAY_INFO (f), parms);
12707 f = XFRAME (frame);
12708
12709 /* Set up the frame's root window. Currently we use a size of 80
12710 columns x 40 lines. If someone wants to show a larger tip, he
12711 will loose. I don't think this is a realistic case. */
12712 w = XWINDOW (FRAME_ROOT_WINDOW (f));
12713 w->left = w->top = make_number (0);
12714 w->width = make_number (80);
12715 w->height = make_number (40);
12716 adjust_glyphs (f);
12717 w->pseudo_window_p = 1;
12718
12719 /* Display the tooltip text in a temporary buffer. */
12720 buffer = Fget_buffer_create (build_string (" *tip*"));
12721 Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer);
12722 old_buffer = current_buffer;
12723 set_buffer_internal_1 (XBUFFER (buffer));
12724 Ferase_buffer ();
12725 Finsert (1, &string);
12726 clear_glyph_matrix (w->desired_matrix);
12727 clear_glyph_matrix (w->current_matrix);
12728 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
12729 try_window (FRAME_ROOT_WINDOW (f), pos);
12730
12731 /* Compute width and height of the tooltip. */
12732 width = height = 0;
12733 for (i = 0; i < w->desired_matrix->nrows; ++i)
12734 {
12735 struct glyph_row *row = &w->desired_matrix->rows[i];
12736 struct glyph *last;
12737 int row_width;
12738
12739 /* Stop at the first empty row at the end. */
12740 if (!row->enabled_p || !row->displays_text_p)
12741 break;
12742
12743 /* Let the row go over the full width of the frame. */
12744 row->full_width_p = 1;
12745
12746 /* There's a glyph at the end of rows that is use to place
12747 the cursor there. Don't include the width of this glyph. */
12748 if (row->used[TEXT_AREA])
12749 {
12750 last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
12751 row_width = row->pixel_width - last->pixel_width;
12752 }
12753 else
12754 row_width = row->pixel_width;
12755
12756 height += row->height;
12757 width = max (width, row_width);
12758 }
12759
12760 /* Add the frame's internal border to the width and height the X
12761 window should have. */
12762 height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
12763 width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
12764
12765 /* Move the tooltip window where the mouse pointer is. Resize and
12766 show it. */
12767 compute_tip_xy (f, parms, dx, dy, &root_x, &root_y);
12768
12769 #if 0 /* TODO : W32 specifics */
12770 BLOCK_INPUT;
12771 XMoveResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
12772 root_x, root_y - height, width, height);
12773 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
12774 UNBLOCK_INPUT;
12775 #endif /* TODO */
12776
12777 /* Draw into the window. */
12778 w->must_be_updated_p = 1;
12779 update_single_window (w, 1);
12780
12781 /* Restore original current buffer. */
12782 set_buffer_internal_1 (old_buffer);
12783 windows_or_buffers_changed = old_windows_or_buffers_changed;
12784
12785 start_timer:
12786 /* Let the tip disappear after timeout seconds. */
12787 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
12788 intern ("x-hide-tip"));
12789
12790 UNGCPRO;
12791 return unbind_to (count, Qnil);
12792 }
12793
12794
12795 DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
12796 "Hide the current tooltip window, if there is any.\n\
12797 Value is t is tooltip was open, nil otherwise.")
12798 ()
12799 {
12800 int count;
12801 Lisp_Object deleted, frame, timer;
12802 struct gcpro gcpro1, gcpro2;
12803
12804 /* Return quickly if nothing to do. */
12805 if (NILP (tip_timer) && NILP (tip_frame))
12806 return Qnil;
12807
12808 frame = tip_frame;
12809 timer = tip_timer;
12810 GCPRO2 (frame, timer);
12811 tip_frame = tip_timer = deleted = Qnil;
12812
12813 count = BINDING_STACK_SIZE ();
12814 specbind (Qinhibit_redisplay, Qt);
12815 specbind (Qinhibit_quit, Qt);
12816
12817 if (!NILP (timer))
12818 call1 (Qcancel_timer, timer);
12819
12820 if (FRAMEP (frame))
12821 {
12822 Fdelete_frame (frame, Qnil);
12823 deleted = Qt;
12824 }
12825
12826 UNGCPRO;
12827 return unbind_to (count, deleted);
12828 }
12829 #endif
12830
12831
12832 \f
12833 /***********************************************************************
12834 File selection dialog
12835 ***********************************************************************/
12836
12837 extern Lisp_Object Qfile_name_history;
12838
12839 DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0,
12840 "Read file name, prompting with PROMPT in directory DIR.\n\
12841 Use a file selection dialog.\n\
12842 Select DEFAULT-FILENAME in the dialog's file selection box, if\n\
12843 specified. Don't let the user enter a file name in the file\n\
12844 selection dialog's entry field, if MUSTMATCH is non-nil.")
12845 (prompt, dir, default_filename, mustmatch)
12846 Lisp_Object prompt, dir, default_filename, mustmatch;
12847 {
12848 struct frame *f = SELECTED_FRAME ();
12849 Lisp_Object file = Qnil;
12850 int count = specpdl_ptr - specpdl;
12851 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
12852 char filename[MAX_PATH + 1];
12853 char init_dir[MAX_PATH + 1];
12854 int use_dialog_p = 1;
12855
12856 GCPRO5 (prompt, dir, default_filename, mustmatch, file);
12857 CHECK_STRING (prompt, 0);
12858 CHECK_STRING (dir, 1);
12859
12860 /* Create the dialog with PROMPT as title, using DIR as initial
12861 directory and using "*" as pattern. */
12862 dir = Fexpand_file_name (dir, Qnil);
12863 strncpy (init_dir, XSTRING (dir)->data, MAX_PATH);
12864 init_dir[MAX_PATH] = '\0';
12865 unixtodos_filename (init_dir);
12866
12867 if (STRINGP (default_filename))
12868 {
12869 char *file_name_only;
12870 char *full_path_name = XSTRING (default_filename)->data;
12871
12872 unixtodos_filename (full_path_name);
12873
12874 file_name_only = strrchr (full_path_name, '\\');
12875 if (!file_name_only)
12876 file_name_only = full_path_name;
12877 else
12878 {
12879 file_name_only++;
12880
12881 /* If default_file_name is a directory, don't use the open
12882 file dialog, as it does not support selecting
12883 directories. */
12884 if (!(*file_name_only))
12885 use_dialog_p = 0;
12886 }
12887
12888 strncpy (filename, file_name_only, MAX_PATH);
12889 filename[MAX_PATH] = '\0';
12890 }
12891 else
12892 filename[0] = '\0';
12893
12894 if (use_dialog_p)
12895 {
12896 OPENFILENAME file_details;
12897
12898 /* Prevent redisplay. */
12899 specbind (Qinhibit_redisplay, Qt);
12900 BLOCK_INPUT;
12901
12902 bzero (&file_details, sizeof (file_details));
12903 file_details.lStructSize = sizeof (file_details);
12904 file_details.hwndOwner = FRAME_W32_WINDOW (f);
12905 file_details.lpstrFile = filename;
12906 file_details.nMaxFile = sizeof (filename);
12907 file_details.lpstrInitialDir = init_dir;
12908 file_details.lpstrTitle = XSTRING (prompt)->data;
12909 file_details.Flags = OFN_HIDEREADONLY | OFN_NOCHANGEDIR;
12910
12911 if (!NILP (mustmatch))
12912 file_details.Flags |= OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
12913
12914 if (GetOpenFileName (&file_details))
12915 {
12916 dostounix_filename (filename);
12917 file = build_string (filename);
12918 }
12919 else
12920 file = Qnil;
12921
12922 UNBLOCK_INPUT;
12923 file = unbind_to (count, file);
12924 }
12925 /* Open File dialog will not allow folders to be selected, so resort
12926 to minibuffer completing reads for directories. */
12927 else
12928 file = Fcompleting_read (prompt, intern ("read-file-name-internal"),
12929 dir, mustmatch, dir, Qfile_name_history,
12930 default_filename, Qnil);
12931
12932 UNGCPRO;
12933
12934 /* Make "Cancel" equivalent to C-g. */
12935 if (NILP (file))
12936 Fsignal (Qquit, Qnil);
12937
12938 return unbind_to (count, file);
12939 }
12940
12941
12942 \f
12943 /***********************************************************************
12944 Tests
12945 ***********************************************************************/
12946
12947 #if GLYPH_DEBUG
12948
12949 DEFUN ("imagep", Fimagep, Simagep, 1, 1, 0,
12950 "Value is non-nil if SPEC is a valid image specification.")
12951 (spec)
12952 Lisp_Object spec;
12953 {
12954 return valid_image_p (spec) ? Qt : Qnil;
12955 }
12956
12957
12958 DEFUN ("lookup-image", Flookup_image, Slookup_image, 1, 1, 0, "")
12959 (spec)
12960 Lisp_Object spec;
12961 {
12962 int id = -1;
12963
12964 if (valid_image_p (spec))
12965 id = lookup_image (SELECTED_FRAME (), spec);
12966
12967 debug_print (spec);
12968 return make_number (id);
12969 }
12970
12971 #endif /* GLYPH_DEBUG != 0 */
12972
12973
12974 \f
12975 /***********************************************************************
12976 w32 specialized functions
12977 ***********************************************************************/
12978
12979 DEFUN ("w32-select-font", Fw32_select_font, Sw32_select_font, 0, 1, 0,
12980 "This will display the W32 font dialog and return an X font string corresponding to the selection.")
12981 (frame)
12982 Lisp_Object frame;
12983 {
12984 FRAME_PTR f = check_x_frame (frame);
12985 CHOOSEFONT cf;
12986 LOGFONT lf;
12987 TEXTMETRIC tm;
12988 HDC hdc;
12989 HANDLE oldobj;
12990 char buf[100];
12991
12992 bzero (&cf, sizeof (cf));
12993 bzero (&lf, sizeof (lf));
12994
12995 cf.lStructSize = sizeof (cf);
12996 cf.hwndOwner = FRAME_W32_WINDOW (f);
12997 cf.Flags = CF_FORCEFONTEXIST | CF_SCREENFONTS;
12998 cf.lpLogFont = &lf;
12999
13000 /* Initialize as much of the font details as we can from the current
13001 default font. */
13002 hdc = GetDC (FRAME_W32_WINDOW (f));
13003 oldobj = SelectObject (hdc, FRAME_FONT (f)->hfont);
13004 GetTextFace (hdc, LF_FACESIZE, lf.lfFaceName);
13005 if (GetTextMetrics (hdc, &tm))
13006 {
13007 lf.lfHeight = tm.tmInternalLeading - tm.tmHeight;
13008 lf.lfWeight = tm.tmWeight;
13009 lf.lfItalic = tm.tmItalic;
13010 lf.lfUnderline = tm.tmUnderlined;
13011 lf.lfStrikeOut = tm.tmStruckOut;
13012 lf.lfCharSet = tm.tmCharSet;
13013 cf.Flags |= CF_INITTOLOGFONTSTRUCT;
13014 }
13015 SelectObject (hdc, oldobj);
13016 ReleaseDC (FRAME_W32_WINDOW (f), hdc);
13017
13018 if (!ChooseFont (&cf) || !w32_to_x_font (&lf, buf, 100, NULL))
13019 return Qnil;
13020
13021 return build_string (buf);
13022 }
13023
13024 DEFUN ("w32-send-sys-command", Fw32_send_sys_command, Sw32_send_sys_command, 1, 2, 0,
13025 "Send frame a Windows WM_SYSCOMMAND message of type COMMAND.\n\
13026 Some useful values for command are 0xf030 to maximise frame (0xf020\n\
13027 to minimize), 0xf120 to restore frame to original size, and 0xf100\n\
13028 to activate the menubar for keyboard access. 0xf140 activates the\n\
13029 screen saver if defined.\n\
13030 \n\
13031 If optional parameter FRAME is not specified, use selected frame.")
13032 (command, frame)
13033 Lisp_Object command, frame;
13034 {
13035 FRAME_PTR f = check_x_frame (frame);
13036
13037 CHECK_NUMBER (command, 0);
13038
13039 PostMessage (FRAME_W32_WINDOW (f), WM_SYSCOMMAND, XINT (command), 0);
13040
13041 return Qnil;
13042 }
13043
13044 DEFUN ("w32-shell-execute", Fw32_shell_execute, Sw32_shell_execute, 2, 4, 0,
13045 "Get Windows to perform OPERATION on DOCUMENT.\n\
13046 This is a wrapper around the ShellExecute system function, which\n\
13047 invokes the application registered to handle OPERATION for DOCUMENT.\n\
13048 OPERATION is typically \"open\", \"print\" or \"explore\" (but can be\n\
13049 nil for the default action), and DOCUMENT is typically the name of a\n\
13050 document file or URL, but can also be a program executable to run or\n\
13051 a directory to open in the Windows Explorer.\n\
13052 \n\
13053 If DOCUMENT is a program executable, PARAMETERS can be a string\n\
13054 containing command line parameters, but otherwise should be nil.\n\
13055 \n\
13056 SHOW-FLAG can be used to control whether the invoked application is hidden\n\
13057 or minimized. If SHOW-FLAG is nil, the application is displayed normally,\n\
13058 otherwise it is an integer representing a ShowWindow flag:\n\
13059 \n\
13060 0 - start hidden\n\
13061 1 - start normally\n\
13062 3 - start maximized\n\
13063 6 - start minimized")
13064 (operation, document, parameters, show_flag)
13065 Lisp_Object operation, document, parameters, show_flag;
13066 {
13067 Lisp_Object current_dir;
13068
13069 CHECK_STRING (document, 0);
13070
13071 /* Encode filename and current directory. */
13072 current_dir = ENCODE_FILE (current_buffer->directory);
13073 document = ENCODE_FILE (document);
13074 if ((int) ShellExecute (NULL,
13075 (STRINGP (operation) ?
13076 XSTRING (operation)->data : NULL),
13077 XSTRING (document)->data,
13078 (STRINGP (parameters) ?
13079 XSTRING (parameters)->data : NULL),
13080 XSTRING (current_dir)->data,
13081 (INTEGERP (show_flag) ?
13082 XINT (show_flag) : SW_SHOWDEFAULT))
13083 > 32)
13084 return Qt;
13085 error ("ShellExecute failed: %s", w32_strerror (0));
13086 }
13087
13088 /* Lookup virtual keycode from string representing the name of a
13089 non-ascii keystroke into the corresponding virtual key, using
13090 lispy_function_keys. */
13091 static int
13092 lookup_vk_code (char *key)
13093 {
13094 int i;
13095
13096 for (i = 0; i < 256; i++)
13097 if (lispy_function_keys[i] != 0
13098 && strcmp (lispy_function_keys[i], key) == 0)
13099 return i;
13100
13101 return -1;
13102 }
13103
13104 /* Convert a one-element vector style key sequence to a hot key
13105 definition. */
13106 static int
13107 w32_parse_hot_key (key)
13108 Lisp_Object key;
13109 {
13110 /* Copied from Fdefine_key and store_in_keymap. */
13111 register Lisp_Object c;
13112 int vk_code;
13113 int lisp_modifiers;
13114 int w32_modifiers;
13115 struct gcpro gcpro1;
13116
13117 CHECK_VECTOR (key, 0);
13118
13119 if (XFASTINT (Flength (key)) != 1)
13120 return Qnil;
13121
13122 GCPRO1 (key);
13123
13124 c = Faref (key, make_number (0));
13125
13126 if (CONSP (c) && lucid_event_type_list_p (c))
13127 c = Fevent_convert_list (c);
13128
13129 UNGCPRO;
13130
13131 if (! INTEGERP (c) && ! SYMBOLP (c))
13132 error ("Key definition is invalid");
13133
13134 /* Work out the base key and the modifiers. */
13135 if (SYMBOLP (c))
13136 {
13137 c = parse_modifiers (c);
13138 lisp_modifiers = Fcar (Fcdr (c));
13139 c = Fcar (c);
13140 if (!SYMBOLP (c))
13141 abort ();
13142 vk_code = lookup_vk_code (XSYMBOL (c)->name->data);
13143 }
13144 else if (INTEGERP (c))
13145 {
13146 lisp_modifiers = XINT (c) & ~CHARACTERBITS;
13147 /* Many ascii characters are their own virtual key code. */
13148 vk_code = XINT (c) & CHARACTERBITS;
13149 }
13150
13151 if (vk_code < 0 || vk_code > 255)
13152 return Qnil;
13153
13154 if ((lisp_modifiers & meta_modifier) != 0
13155 && !NILP (Vw32_alt_is_meta))
13156 lisp_modifiers |= alt_modifier;
13157
13158 /* Supply defs missing from mingw32. */
13159 #ifndef MOD_ALT
13160 #define MOD_ALT 0x0001
13161 #define MOD_CONTROL 0x0002
13162 #define MOD_SHIFT 0x0004
13163 #define MOD_WIN 0x0008
13164 #endif
13165
13166 /* Convert lisp modifiers to Windows hot-key form. */
13167 w32_modifiers = (lisp_modifiers & hyper_modifier) ? MOD_WIN : 0;
13168 w32_modifiers |= (lisp_modifiers & alt_modifier) ? MOD_ALT : 0;
13169 w32_modifiers |= (lisp_modifiers & ctrl_modifier) ? MOD_CONTROL : 0;
13170 w32_modifiers |= (lisp_modifiers & shift_modifier) ? MOD_SHIFT : 0;
13171
13172 return HOTKEY (vk_code, w32_modifiers);
13173 }
13174
13175 DEFUN ("w32-register-hot-key", Fw32_register_hot_key, Sw32_register_hot_key, 1, 1, 0,
13176 "Register KEY as a hot-key combination.\n\
13177 Certain key combinations like Alt-Tab are reserved for system use on\n\
13178 Windows, and therefore are normally intercepted by the system. However,\n\
13179 most of these key combinations can be received by registering them as\n\
13180 hot-keys, overriding their special meaning.\n\
13181 \n\
13182 KEY must be a one element key definition in vector form that would be\n\
13183 acceptable to `define-key' (e.g. [A-tab] for Alt-Tab). The meta\n\
13184 modifier is interpreted as Alt if `w32-alt-is-meta' is t, and hyper\n\
13185 is always interpreted as the Windows modifier keys.\n\
13186 \n\
13187 The return value is the hotkey-id if registered, otherwise nil.")
13188 (key)
13189 Lisp_Object key;
13190 {
13191 key = w32_parse_hot_key (key);
13192
13193 if (NILP (Fmemq (key, w32_grabbed_keys)))
13194 {
13195 /* Reuse an empty slot if possible. */
13196 Lisp_Object item = Fmemq (Qnil, w32_grabbed_keys);
13197
13198 /* Safe to add new key to list, even if we have focus. */
13199 if (NILP (item))
13200 w32_grabbed_keys = Fcons (key, w32_grabbed_keys);
13201 else
13202 XCAR (item) = key;
13203
13204 /* Notify input thread about new hot-key definition, so that it
13205 takes effect without needing to switch focus. */
13206 PostThreadMessage (dwWindowsThreadId, WM_EMACS_REGISTER_HOT_KEY,
13207 (WPARAM) key, 0);
13208 }
13209
13210 return key;
13211 }
13212
13213 DEFUN ("w32-unregister-hot-key", Fw32_unregister_hot_key, Sw32_unregister_hot_key, 1, 1, 0,
13214 "Unregister HOTKEY as a hot-key combination.")
13215 (key)
13216 Lisp_Object key;
13217 {
13218 Lisp_Object item;
13219
13220 if (!INTEGERP (key))
13221 key = w32_parse_hot_key (key);
13222
13223 item = Fmemq (key, w32_grabbed_keys);
13224
13225 if (!NILP (item))
13226 {
13227 /* Notify input thread about hot-key definition being removed, so
13228 that it takes effect without needing focus switch. */
13229 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_UNREGISTER_HOT_KEY,
13230 (WPARAM) XINT (XCAR (item)), (LPARAM) item))
13231 {
13232 MSG msg;
13233 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
13234 }
13235 return Qt;
13236 }
13237 return Qnil;
13238 }
13239
13240 DEFUN ("w32-registered-hot-keys", Fw32_registered_hot_keys, Sw32_registered_hot_keys, 0, 0, 0,
13241 "Return list of registered hot-key IDs.")
13242 ()
13243 {
13244 return Fcopy_sequence (w32_grabbed_keys);
13245 }
13246
13247 DEFUN ("w32-reconstruct-hot-key", Fw32_reconstruct_hot_key, Sw32_reconstruct_hot_key, 1, 1, 0,
13248 "Convert hot-key ID to a lisp key combination.")
13249 (hotkeyid)
13250 Lisp_Object hotkeyid;
13251 {
13252 int vk_code, w32_modifiers;
13253 Lisp_Object key;
13254
13255 CHECK_NUMBER (hotkeyid, 0);
13256
13257 vk_code = HOTKEY_VK_CODE (hotkeyid);
13258 w32_modifiers = HOTKEY_MODIFIERS (hotkeyid);
13259
13260 if (lispy_function_keys[vk_code])
13261 key = intern (lispy_function_keys[vk_code]);
13262 else
13263 key = make_number (vk_code);
13264
13265 key = Fcons (key, Qnil);
13266 if (w32_modifiers & MOD_SHIFT)
13267 key = Fcons (Qshift, key);
13268 if (w32_modifiers & MOD_CONTROL)
13269 key = Fcons (Qctrl, key);
13270 if (w32_modifiers & MOD_ALT)
13271 key = Fcons (NILP (Vw32_alt_is_meta) ? Qalt : Qmeta, key);
13272 if (w32_modifiers & MOD_WIN)
13273 key = Fcons (Qhyper, key);
13274
13275 return key;
13276 }
13277
13278 DEFUN ("w32-toggle-lock-key", Fw32_toggle_lock_key, Sw32_toggle_lock_key, 1, 2, 0,
13279 "Toggle the state of the lock key KEY.\n\
13280 KEY can be `capslock', `kp-numlock', or `scroll'.\n\
13281 If the optional parameter NEW-STATE is a number, then the state of KEY\n\
13282 is set to off if the low bit of NEW-STATE is zero, otherwise on.")
13283 (key, new_state)
13284 Lisp_Object key, new_state;
13285 {
13286 int vk_code;
13287
13288 if (EQ (key, intern ("capslock")))
13289 vk_code = VK_CAPITAL;
13290 else if (EQ (key, intern ("kp-numlock")))
13291 vk_code = VK_NUMLOCK;
13292 else if (EQ (key, intern ("scroll")))
13293 vk_code = VK_SCROLL;
13294 else
13295 return Qnil;
13296
13297 if (!dwWindowsThreadId)
13298 return make_number (w32_console_toggle_lock_key (vk_code, new_state));
13299
13300 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_TOGGLE_LOCK_KEY,
13301 (WPARAM) vk_code, (LPARAM) new_state))
13302 {
13303 MSG msg;
13304 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
13305 return make_number (msg.wParam);
13306 }
13307 return Qnil;
13308 }
13309 \f
13310 DEFUN ("file-system-info", Ffile_system_info, Sfile_system_info, 1, 1, 0,
13311 "Return storage information about the file system FILENAME is on.\n\
13312 Value is a list of floats (TOTAL FREE AVAIL), where TOTAL is the total\n\
13313 storage of the file system, FREE is the free storage, and AVAIL is the\n\
13314 storage available to a non-superuser. All 3 numbers are in bytes.\n\
13315 If the underlying system call fails, value is nil.")
13316 (filename)
13317 Lisp_Object filename;
13318 {
13319 Lisp_Object encoded, value;
13320
13321 CHECK_STRING (filename, 0);
13322 filename = Fexpand_file_name (filename, Qnil);
13323 encoded = ENCODE_FILE (filename);
13324
13325 value = Qnil;
13326
13327 /* Determining the required information on Windows turns out, sadly,
13328 to be more involved than one would hope. The original Win32 api
13329 call for this will return bogus information on some systems, but we
13330 must dynamically probe for the replacement api, since that was
13331 added rather late on. */
13332 {
13333 HMODULE hKernel = GetModuleHandle ("kernel32");
13334 BOOL (*pfn_GetDiskFreeSpaceEx)
13335 (char *, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER)
13336 = (void *) GetProcAddress (hKernel, "GetDiskFreeSpaceEx");
13337
13338 /* On Windows, we may need to specify the root directory of the
13339 volume holding FILENAME. */
13340 char rootname[MAX_PATH];
13341 char *name = XSTRING (encoded)->data;
13342
13343 /* find the root name of the volume if given */
13344 if (isalpha (name[0]) && name[1] == ':')
13345 {
13346 rootname[0] = name[0];
13347 rootname[1] = name[1];
13348 rootname[2] = '\\';
13349 rootname[3] = 0;
13350 }
13351 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
13352 {
13353 char *str = rootname;
13354 int slashes = 4;
13355 do
13356 {
13357 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
13358 break;
13359 *str++ = *name++;
13360 }
13361 while ( *name );
13362
13363 *str++ = '\\';
13364 *str = 0;
13365 }
13366
13367 if (pfn_GetDiskFreeSpaceEx)
13368 {
13369 LARGE_INTEGER availbytes;
13370 LARGE_INTEGER freebytes;
13371 LARGE_INTEGER totalbytes;
13372
13373 if (pfn_GetDiskFreeSpaceEx(rootname,
13374 &availbytes,
13375 &totalbytes,
13376 &freebytes))
13377 value = list3 (make_float ((double) totalbytes.QuadPart),
13378 make_float ((double) freebytes.QuadPart),
13379 make_float ((double) availbytes.QuadPart));
13380 }
13381 else
13382 {
13383 DWORD sectors_per_cluster;
13384 DWORD bytes_per_sector;
13385 DWORD free_clusters;
13386 DWORD total_clusters;
13387
13388 if (GetDiskFreeSpace(rootname,
13389 &sectors_per_cluster,
13390 &bytes_per_sector,
13391 &free_clusters,
13392 &total_clusters))
13393 value = list3 (make_float ((double) total_clusters
13394 * sectors_per_cluster * bytes_per_sector),
13395 make_float ((double) free_clusters
13396 * sectors_per_cluster * bytes_per_sector),
13397 make_float ((double) free_clusters
13398 * sectors_per_cluster * bytes_per_sector));
13399 }
13400 }
13401
13402 return value;
13403 }
13404 \f
13405 syms_of_w32fns ()
13406 {
13407 /* This is zero if not using MS-Windows. */
13408 w32_in_use = 0;
13409
13410 /* The section below is built by the lisp expression at the top of the file,
13411 just above where these variables are declared. */
13412 /*&&& init symbols here &&&*/
13413 Qauto_raise = intern ("auto-raise");
13414 staticpro (&Qauto_raise);
13415 Qauto_lower = intern ("auto-lower");
13416 staticpro (&Qauto_lower);
13417 Qbar = intern ("bar");
13418 staticpro (&Qbar);
13419 Qborder_color = intern ("border-color");
13420 staticpro (&Qborder_color);
13421 Qborder_width = intern ("border-width");
13422 staticpro (&Qborder_width);
13423 Qbox = intern ("box");
13424 staticpro (&Qbox);
13425 Qcursor_color = intern ("cursor-color");
13426 staticpro (&Qcursor_color);
13427 Qcursor_type = intern ("cursor-type");
13428 staticpro (&Qcursor_type);
13429 Qgeometry = intern ("geometry");
13430 staticpro (&Qgeometry);
13431 Qicon_left = intern ("icon-left");
13432 staticpro (&Qicon_left);
13433 Qicon_top = intern ("icon-top");
13434 staticpro (&Qicon_top);
13435 Qicon_type = intern ("icon-type");
13436 staticpro (&Qicon_type);
13437 Qicon_name = intern ("icon-name");
13438 staticpro (&Qicon_name);
13439 Qinternal_border_width = intern ("internal-border-width");
13440 staticpro (&Qinternal_border_width);
13441 Qleft = intern ("left");
13442 staticpro (&Qleft);
13443 Qright = intern ("right");
13444 staticpro (&Qright);
13445 Qmouse_color = intern ("mouse-color");
13446 staticpro (&Qmouse_color);
13447 Qnone = intern ("none");
13448 staticpro (&Qnone);
13449 Qparent_id = intern ("parent-id");
13450 staticpro (&Qparent_id);
13451 Qscroll_bar_width = intern ("scroll-bar-width");
13452 staticpro (&Qscroll_bar_width);
13453 Qsuppress_icon = intern ("suppress-icon");
13454 staticpro (&Qsuppress_icon);
13455 Qundefined_color = intern ("undefined-color");
13456 staticpro (&Qundefined_color);
13457 Qvertical_scroll_bars = intern ("vertical-scroll-bars");
13458 staticpro (&Qvertical_scroll_bars);
13459 Qvisibility = intern ("visibility");
13460 staticpro (&Qvisibility);
13461 Qwindow_id = intern ("window-id");
13462 staticpro (&Qwindow_id);
13463 Qx_frame_parameter = intern ("x-frame-parameter");
13464 staticpro (&Qx_frame_parameter);
13465 Qx_resource_name = intern ("x-resource-name");
13466 staticpro (&Qx_resource_name);
13467 Quser_position = intern ("user-position");
13468 staticpro (&Quser_position);
13469 Quser_size = intern ("user-size");
13470 staticpro (&Quser_size);
13471 Qscreen_gamma = intern ("screen-gamma");
13472 staticpro (&Qscreen_gamma);
13473 Qline_spacing = intern ("line-spacing");
13474 staticpro (&Qline_spacing);
13475 Qcenter = intern ("center");
13476 staticpro (&Qcenter);
13477 Qcancel_timer = intern ("cancel-timer");
13478 staticpro (&Qcancel_timer);
13479 /* This is the end of symbol initialization. */
13480
13481 Qhyper = intern ("hyper");
13482 staticpro (&Qhyper);
13483 Qsuper = intern ("super");
13484 staticpro (&Qsuper);
13485 Qmeta = intern ("meta");
13486 staticpro (&Qmeta);
13487 Qalt = intern ("alt");
13488 staticpro (&Qalt);
13489 Qctrl = intern ("ctrl");
13490 staticpro (&Qctrl);
13491 Qcontrol = intern ("control");
13492 staticpro (&Qcontrol);
13493 Qshift = intern ("shift");
13494 staticpro (&Qshift);
13495
13496 /* Text property `display' should be nonsticky by default. */
13497 Vtext_property_default_nonsticky
13498 = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky);
13499
13500
13501 Qlaplace = intern ("laplace");
13502 staticpro (&Qlaplace);
13503
13504 Qface_set_after_frame_default = intern ("face-set-after-frame-default");
13505 staticpro (&Qface_set_after_frame_default);
13506
13507 Fput (Qundefined_color, Qerror_conditions,
13508 Fcons (Qundefined_color, Fcons (Qerror, Qnil)));
13509 Fput (Qundefined_color, Qerror_message,
13510 build_string ("Undefined color"));
13511
13512 staticpro (&w32_grabbed_keys);
13513 w32_grabbed_keys = Qnil;
13514
13515 DEFVAR_LISP ("w32-color-map", &Vw32_color_map,
13516 "An array of color name mappings for windows.");
13517 Vw32_color_map = Qnil;
13518
13519 DEFVAR_LISP ("w32-pass-alt-to-system", &Vw32_pass_alt_to_system,
13520 "Non-nil if alt key presses are passed on to Windows.\n\
13521 When non-nil, for example, alt pressed and released and then space will\n\
13522 open the System menu. When nil, Emacs silently swallows alt key events.");
13523 Vw32_pass_alt_to_system = Qnil;
13524
13525 DEFVAR_LISP ("w32-alt-is-meta", &Vw32_alt_is_meta,
13526 "Non-nil if the alt key is to be considered the same as the meta key.\n\
13527 When nil, Emacs will translate the alt key to the Alt modifier, and not Meta.");
13528 Vw32_alt_is_meta = Qt;
13529
13530 DEFVAR_INT ("w32-quit-key", &Vw32_quit_key,
13531 "If non-zero, the virtual key code for an alternative quit key.");
13532 XSETINT (Vw32_quit_key, 0);
13533
13534 DEFVAR_LISP ("w32-pass-lwindow-to-system",
13535 &Vw32_pass_lwindow_to_system,
13536 "Non-nil if the left \"Windows\" key is passed on to Windows.\n\
13537 When non-nil, the Start menu is opened by tapping the key.");
13538 Vw32_pass_lwindow_to_system = Qt;
13539
13540 DEFVAR_LISP ("w32-pass-rwindow-to-system",
13541 &Vw32_pass_rwindow_to_system,
13542 "Non-nil if the right \"Windows\" key is passed on to Windows.\n\
13543 When non-nil, the Start menu is opened by tapping the key.");
13544 Vw32_pass_rwindow_to_system = Qt;
13545
13546 DEFVAR_INT ("w32-phantom-key-code",
13547 &Vw32_phantom_key_code,
13548 "Virtual key code used to generate \"phantom\" key presses.\n\
13549 Value is a number between 0 and 255.\n\
13550 \n\
13551 Phantom key presses are generated in order to stop the system from\n\
13552 acting on \"Windows\" key events when `w32-pass-lwindow-to-system' or\n\
13553 `w32-pass-rwindow-to-system' is nil.");
13554 /* Although 255 is technically not a valid key code, it works and
13555 means that this hack won't interfere with any real key code. */
13556 Vw32_phantom_key_code = 255;
13557
13558 DEFVAR_LISP ("w32-enable-num-lock",
13559 &Vw32_enable_num_lock,
13560 "Non-nil if Num Lock should act normally.\n\
13561 Set to nil to see Num Lock as the key `kp-numlock'.");
13562 Vw32_enable_num_lock = Qt;
13563
13564 DEFVAR_LISP ("w32-enable-caps-lock",
13565 &Vw32_enable_caps_lock,
13566 "Non-nil if Caps Lock should act normally.\n\
13567 Set to nil to see Caps Lock as the key `capslock'.");
13568 Vw32_enable_caps_lock = Qt;
13569
13570 DEFVAR_LISP ("w32-scroll-lock-modifier",
13571 &Vw32_scroll_lock_modifier,
13572 "Modifier to use for the Scroll Lock on state.\n\
13573 The value can be hyper, super, meta, alt, control or shift for the\n\
13574 respective modifier, or nil to see Scroll Lock as the key `scroll'.\n\
13575 Any other value will cause the key to be ignored.");
13576 Vw32_scroll_lock_modifier = Qt;
13577
13578 DEFVAR_LISP ("w32-lwindow-modifier",
13579 &Vw32_lwindow_modifier,
13580 "Modifier to use for the left \"Windows\" key.\n\
13581 The value can be hyper, super, meta, alt, control or shift for the\n\
13582 respective modifier, or nil to appear as the key `lwindow'.\n\
13583 Any other value will cause the key to be ignored.");
13584 Vw32_lwindow_modifier = Qnil;
13585
13586 DEFVAR_LISP ("w32-rwindow-modifier",
13587 &Vw32_rwindow_modifier,
13588 "Modifier to use for the right \"Windows\" key.\n\
13589 The value can be hyper, super, meta, alt, control or shift for the\n\
13590 respective modifier, or nil to appear as the key `rwindow'.\n\
13591 Any other value will cause the key to be ignored.");
13592 Vw32_rwindow_modifier = Qnil;
13593
13594 DEFVAR_LISP ("w32-apps-modifier",
13595 &Vw32_apps_modifier,
13596 "Modifier to use for the \"Apps\" key.\n\
13597 The value can be hyper, super, meta, alt, control or shift for the\n\
13598 respective modifier, or nil to appear as the key `apps'.\n\
13599 Any other value will cause the key to be ignored.");
13600 Vw32_apps_modifier = Qnil;
13601
13602 DEFVAR_LISP ("w32-enable-synthesized-fonts", &Vw32_enable_synthesized_fonts,
13603 "Non-nil enables selection of artificially italicized and bold fonts.");
13604 Vw32_enable_synthesized_fonts = Qnil;
13605
13606 DEFVAR_LISP ("w32-enable-palette", &Vw32_enable_palette,
13607 "Non-nil enables Windows palette management to map colors exactly.");
13608 Vw32_enable_palette = Qt;
13609
13610 DEFVAR_INT ("w32-mouse-button-tolerance",
13611 &Vw32_mouse_button_tolerance,
13612 "Analogue of double click interval for faking middle mouse events.\n\
13613 The value is the minimum time in milliseconds that must elapse between\n\
13614 left/right button down events before they are considered distinct events.\n\
13615 If both mouse buttons are depressed within this interval, a middle mouse\n\
13616 button down event is generated instead.");
13617 XSETINT (Vw32_mouse_button_tolerance, GetDoubleClickTime () / 2);
13618
13619 DEFVAR_INT ("w32-mouse-move-interval",
13620 &Vw32_mouse_move_interval,
13621 "Minimum interval between mouse move events.\n\
13622 The value is the minimum time in milliseconds that must elapse between\n\
13623 successive mouse move (or scroll bar drag) events before they are\n\
13624 reported as lisp events.");
13625 XSETINT (Vw32_mouse_move_interval, 0);
13626
13627 init_x_parm_symbols ();
13628
13629 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
13630 "List of directories to search for bitmap files for w32.");
13631 Vx_bitmap_file_path = decode_env_path ((char *) 0, "PATH");
13632
13633 DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
13634 "The shape of the pointer when over text.\n\
13635 Changing the value does not affect existing frames\n\
13636 unless you set the mouse color.");
13637 Vx_pointer_shape = Qnil;
13638
13639 DEFVAR_LISP ("x-resource-name", &Vx_resource_name,
13640 "The name Emacs uses to look up resources; for internal use only.\n\
13641 `x-get-resource' uses this as the first component of the instance name\n\
13642 when requesting resource values.\n\
13643 Emacs initially sets `x-resource-name' to the name under which Emacs\n\
13644 was invoked, or to the value specified with the `-name' or `-rn'\n\
13645 switches, if present.");
13646 Vx_resource_name = Qnil;
13647
13648 Vx_nontext_pointer_shape = Qnil;
13649
13650 Vx_mode_pointer_shape = Qnil;
13651
13652 DEFVAR_LISP ("x-hourglass-pointer-shape", &Vx_hourglass_pointer_shape,
13653 "The shape of the pointer when Emacs is busy.\n\
13654 This variable takes effect when you create a new frame\n\
13655 or when you set the mouse color.");
13656 Vx_hourglass_pointer_shape = Qnil;
13657
13658 DEFVAR_BOOL ("display-hourglass", &display_hourglass_p,
13659 "Non-zero means Emacs displays an hourglass pointer on window systems.");
13660 display_hourglass_p = 1;
13661
13662 DEFVAR_LISP ("hourglass-delay", &Vhourglass_delay,
13663 "*Seconds to wait before displaying an hourglass pointer.\n\
13664 Value must be an integer or float.");
13665 Vhourglass_delay = make_number (DEFAULT_HOURGLASS_DELAY);
13666
13667 DEFVAR_LISP ("x-sensitive-text-pointer-shape",
13668 &Vx_sensitive_text_pointer_shape,
13669 "The shape of the pointer when over mouse-sensitive text.\n\
13670 This variable takes effect when you create a new frame\n\
13671 or when you set the mouse color.");
13672 Vx_sensitive_text_pointer_shape = Qnil;
13673
13674 DEFVAR_LISP ("x-window-horizontal-drag-cursor",
13675 &Vx_window_horizontal_drag_shape,
13676 "Pointer shape to use for indicating a window can be dragged horizontally.\n\
13677 This variable takes effect when you create a new frame\n\
13678 or when you set the mouse color.");
13679 Vx_window_horizontal_drag_shape = Qnil;
13680
13681 DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
13682 "A string indicating the foreground color of the cursor box.");
13683 Vx_cursor_fore_pixel = Qnil;
13684
13685 DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
13686 "Non-nil if no window manager is in use.\n\
13687 Emacs doesn't try to figure this out; this is always nil\n\
13688 unless you set it to something else.");
13689 /* We don't have any way to find this out, so set it to nil
13690 and maybe the user would like to set it to t. */
13691 Vx_no_window_manager = Qnil;
13692
13693 DEFVAR_LISP ("x-pixel-size-width-font-regexp",
13694 &Vx_pixel_size_width_font_regexp,
13695 "Regexp matching a font name whose width is the same as `PIXEL_SIZE'.\n\
13696 \n\
13697 Since Emacs gets width of a font matching with this regexp from\n\
13698 PIXEL_SIZE field of the name, font finding mechanism gets faster for\n\
13699 such a font. This is especially effective for such large fonts as\n\
13700 Chinese, Japanese, and Korean.");
13701 Vx_pixel_size_width_font_regexp = Qnil;
13702
13703 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
13704 "Time after which cached images are removed from the cache.\n\
13705 When an image has not been displayed this many seconds, remove it\n\
13706 from the image cache. Value must be an integer or nil with nil\n\
13707 meaning don't clear the cache.");
13708 Vimage_cache_eviction_delay = make_number (30 * 60);
13709
13710 DEFVAR_LISP ("w32-bdf-filename-alist",
13711 &Vw32_bdf_filename_alist,
13712 "List of bdf fonts and their corresponding filenames.");
13713 Vw32_bdf_filename_alist = Qnil;
13714
13715 DEFVAR_BOOL ("w32-strict-fontnames",
13716 &w32_strict_fontnames,
13717 "Non-nil means only use fonts that are exact matches for those requested.\n\
13718 Default is nil, which allows old fontnames that are not XLFD compliant,\n\
13719 and allows third-party CJK display to work by specifying false charset\n\
13720 fields to trick Emacs into translating to Big5, SJIS etc.\n\
13721 Setting this to t will prevent wrong fonts being selected when\n\
13722 fontsets are automatically created.");
13723 w32_strict_fontnames = 0;
13724
13725 DEFVAR_BOOL ("w32-strict-painting",
13726 &w32_strict_painting,
13727 "Non-nil means use strict rules for repainting frames.\n\
13728 Set this to nil to get the old behaviour for repainting; this should\n\
13729 only be necessary if the default setting causes problems.");
13730 w32_strict_painting = 1;
13731
13732 DEFVAR_LISP ("w32-system-coding-system",
13733 &Vw32_system_coding_system,
13734 "Coding system used by Windows system functions, such as for font names.");
13735 Vw32_system_coding_system = Qnil;
13736
13737 DEFVAR_LISP ("w32-charset-info-alist",
13738 &Vw32_charset_info_alist,
13739 "Alist linking Emacs character sets to Windows fonts\n\
13740 and codepages. Each entry should be of the form:\n\
13741 \n\
13742 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE))\n\
13743 \n\
13744 where CHARSET_NAME is a string used in font names to identify the charset,\n\
13745 WINDOWS_CHARSET is a symbol that can be one of:\n\
13746 w32-charset-ansi, w32-charset-default, w32-charset-symbol,\n\
13747 w32-charset-shiftjis, w32-charset-hangeul, w32-charset-gb2312,\n\
13748 w32-charset-chinesebig5, "
13749 #ifdef JOHAB_CHARSET
13750 "w32-charset-johab, w32-charset-hebrew,\n\
13751 w32-charset-arabic, w32-charset-greek, w32-charset-turkish,\n\
13752 w32-charset-vietnamese, w32-charset-thai, w32-charset-easteurope,\n\
13753 w32-charset-russian, w32-charset-mac, w32-charset-baltic,\n"
13754 #endif
13755 #ifdef UNICODE_CHARSET
13756 "w32-charset-unicode, "
13757 #endif
13758 "or w32-charset-oem.\n\
13759 CODEPAGE should be an integer specifying the codepage that should be used\n\
13760 to display the character set, t to do no translation and output as Unicode,\n\
13761 or nil to do no translation and output as 8 bit (or multibyte on far-east\n\
13762 versions of Windows) characters.");
13763 Vw32_charset_info_alist = Qnil;
13764
13765 staticpro (&Qw32_charset_ansi);
13766 Qw32_charset_ansi = intern ("w32-charset-ansi");
13767 staticpro (&Qw32_charset_symbol);
13768 Qw32_charset_symbol = intern ("w32-charset-symbol");
13769 staticpro (&Qw32_charset_shiftjis);
13770 Qw32_charset_shiftjis = intern ("w32-charset-shiftjis");
13771 staticpro (&Qw32_charset_hangeul);
13772 Qw32_charset_hangeul = intern ("w32-charset-hangeul");
13773 staticpro (&Qw32_charset_chinesebig5);
13774 Qw32_charset_chinesebig5 = intern ("w32-charset-chinesebig5");
13775 staticpro (&Qw32_charset_gb2312);
13776 Qw32_charset_gb2312 = intern ("w32-charset-gb2312");
13777 staticpro (&Qw32_charset_oem);
13778 Qw32_charset_oem = intern ("w32-charset-oem");
13779
13780 #ifdef JOHAB_CHARSET
13781 {
13782 static int w32_extra_charsets_defined = 1;
13783 DEFVAR_BOOL ("w32-extra-charsets-defined", &w32_extra_charsets_defined, "");
13784
13785 staticpro (&Qw32_charset_johab);
13786 Qw32_charset_johab = intern ("w32-charset-johab");
13787 staticpro (&Qw32_charset_easteurope);
13788 Qw32_charset_easteurope = intern ("w32-charset-easteurope");
13789 staticpro (&Qw32_charset_turkish);
13790 Qw32_charset_turkish = intern ("w32-charset-turkish");
13791 staticpro (&Qw32_charset_baltic);
13792 Qw32_charset_baltic = intern ("w32-charset-baltic");
13793 staticpro (&Qw32_charset_russian);
13794 Qw32_charset_russian = intern ("w32-charset-russian");
13795 staticpro (&Qw32_charset_arabic);
13796 Qw32_charset_arabic = intern ("w32-charset-arabic");
13797 staticpro (&Qw32_charset_greek);
13798 Qw32_charset_greek = intern ("w32-charset-greek");
13799 staticpro (&Qw32_charset_hebrew);
13800 Qw32_charset_hebrew = intern ("w32-charset-hebrew");
13801 staticpro (&Qw32_charset_vietnamese);
13802 Qw32_charset_vietnamese = intern ("w32-charset-vietnamese");
13803 staticpro (&Qw32_charset_thai);
13804 Qw32_charset_thai = intern ("w32-charset-thai");
13805 staticpro (&Qw32_charset_mac);
13806 Qw32_charset_mac = intern ("w32-charset-mac");
13807 }
13808 #endif
13809
13810 #ifdef UNICODE_CHARSET
13811 {
13812 static int w32_unicode_charset_defined = 1;
13813 DEFVAR_BOOL ("w32-unicode-charset-defined",
13814 &w32_unicode_charset_defined, "");
13815
13816 staticpro (&Qw32_charset_unicode);
13817 Qw32_charset_unicode = intern ("w32-charset-unicode");
13818 #endif
13819
13820 defsubr (&Sx_get_resource);
13821 #if 0 /* TODO: Port to W32 */
13822 defsubr (&Sx_change_window_property);
13823 defsubr (&Sx_delete_window_property);
13824 defsubr (&Sx_window_property);
13825 #endif
13826 defsubr (&Sxw_display_color_p);
13827 defsubr (&Sx_display_grayscale_p);
13828 defsubr (&Sxw_color_defined_p);
13829 defsubr (&Sxw_color_values);
13830 defsubr (&Sx_server_max_request_size);
13831 defsubr (&Sx_server_vendor);
13832 defsubr (&Sx_server_version);
13833 defsubr (&Sx_display_pixel_width);
13834 defsubr (&Sx_display_pixel_height);
13835 defsubr (&Sx_display_mm_width);
13836 defsubr (&Sx_display_mm_height);
13837 defsubr (&Sx_display_screens);
13838 defsubr (&Sx_display_planes);
13839 defsubr (&Sx_display_color_cells);
13840 defsubr (&Sx_display_visual_class);
13841 defsubr (&Sx_display_backing_store);
13842 defsubr (&Sx_display_save_under);
13843 defsubr (&Sx_parse_geometry);
13844 defsubr (&Sx_create_frame);
13845 defsubr (&Sx_open_connection);
13846 defsubr (&Sx_close_connection);
13847 defsubr (&Sx_display_list);
13848 defsubr (&Sx_synchronize);
13849
13850 /* W32 specific functions */
13851
13852 defsubr (&Sw32_focus_frame);
13853 defsubr (&Sw32_select_font);
13854 defsubr (&Sw32_define_rgb_color);
13855 defsubr (&Sw32_default_color_map);
13856 defsubr (&Sw32_load_color_file);
13857 defsubr (&Sw32_send_sys_command);
13858 defsubr (&Sw32_shell_execute);
13859 defsubr (&Sw32_register_hot_key);
13860 defsubr (&Sw32_unregister_hot_key);
13861 defsubr (&Sw32_registered_hot_keys);
13862 defsubr (&Sw32_reconstruct_hot_key);
13863 defsubr (&Sw32_toggle_lock_key);
13864 defsubr (&Sw32_find_bdf_fonts);
13865
13866 defsubr (&Sfile_system_info);
13867
13868 /* Setting callback functions for fontset handler. */
13869 get_font_info_func = w32_get_font_info;
13870
13871 #if 0 /* This function pointer doesn't seem to be used anywhere.
13872 And the pointer assigned has the wrong type, anyway. */
13873 list_fonts_func = w32_list_fonts;
13874 #endif
13875
13876 load_font_func = w32_load_font;
13877 find_ccl_program_func = w32_find_ccl_program;
13878 query_font_func = w32_query_font;
13879 set_frame_fontset_func = x_set_font;
13880 check_window_system_func = check_w32;
13881
13882 #if 0 /* TODO Image support for W32 */
13883 /* Images. */
13884 Qxbm = intern ("xbm");
13885 staticpro (&Qxbm);
13886 QCtype = intern (":type");
13887 staticpro (&QCtype);
13888 QCconversion = intern (":conversion");
13889 staticpro (&QCconversion);
13890 QCheuristic_mask = intern (":heuristic-mask");
13891 staticpro (&QCheuristic_mask);
13892 QCcolor_symbols = intern (":color-symbols");
13893 staticpro (&QCcolor_symbols);
13894 QCascent = intern (":ascent");
13895 staticpro (&QCascent);
13896 QCmargin = intern (":margin");
13897 staticpro (&QCmargin);
13898 QCrelief = intern (":relief");
13899 staticpro (&QCrelief);
13900 Qpostscript = intern ("postscript");
13901 staticpro (&Qpostscript);
13902 QCloader = intern (":loader");
13903 staticpro (&QCloader);
13904 QCbounding_box = intern (":bounding-box");
13905 staticpro (&QCbounding_box);
13906 QCpt_width = intern (":pt-width");
13907 staticpro (&QCpt_width);
13908 QCpt_height = intern (":pt-height");
13909 staticpro (&QCpt_height);
13910 QCindex = intern (":index");
13911 staticpro (&QCindex);
13912 Qpbm = intern ("pbm");
13913 staticpro (&Qpbm);
13914
13915 #if HAVE_XPM
13916 Qxpm = intern ("xpm");
13917 staticpro (&Qxpm);
13918 #endif
13919
13920 #if HAVE_JPEG
13921 Qjpeg = intern ("jpeg");
13922 staticpro (&Qjpeg);
13923 #endif
13924
13925 #if HAVE_TIFF
13926 Qtiff = intern ("tiff");
13927 staticpro (&Qtiff);
13928 #endif
13929
13930 #if HAVE_GIF
13931 Qgif = intern ("gif");
13932 staticpro (&Qgif);
13933 #endif
13934
13935 #if HAVE_PNG
13936 Qpng = intern ("png");
13937 staticpro (&Qpng);
13938 #endif
13939
13940 defsubr (&Sclear_image_cache);
13941
13942 #if GLYPH_DEBUG
13943 defsubr (&Simagep);
13944 defsubr (&Slookup_image);
13945 #endif
13946 #endif /* TODO */
13947
13948 hourglass_atimer = NULL;
13949 hourglass_shown_p = 0;
13950 #ifdef TODO /* Tooltip support not complete. */
13951 defsubr (&Sx_show_tip);
13952 defsubr (&Sx_hide_tip);
13953 #endif
13954 tip_timer = Qnil;
13955 staticpro (&tip_timer);
13956 tip_frame = Qnil;
13957 staticpro (&tip_frame);
13958
13959 defsubr (&Sx_file_dialog);
13960 }
13961
13962
13963 void
13964 init_xfns ()
13965 {
13966 image_types = NULL;
13967 Vimage_types = Qnil;
13968
13969 #if 0 /* TODO : Image support for W32 */
13970 define_image_type (&xbm_type);
13971 define_image_type (&gs_type);
13972 define_image_type (&pbm_type);
13973
13974 #if HAVE_XPM
13975 define_image_type (&xpm_type);
13976 #endif
13977
13978 #if HAVE_JPEG
13979 define_image_type (&jpeg_type);
13980 #endif
13981
13982 #if HAVE_TIFF
13983 define_image_type (&tiff_type);
13984 #endif
13985
13986 #if HAVE_GIF
13987 define_image_type (&gif_type);
13988 #endif
13989
13990 #if HAVE_PNG
13991 define_image_type (&png_type);
13992 #endif
13993 #endif /* TODO */
13994 }
13995
13996 #undef abort
13997
13998 void
13999 w32_abort()
14000 {
14001 int button;
14002 button = MessageBox (NULL,
14003 "A fatal error has occurred!\n\n"
14004 "Select Abort to exit, Retry to debug, Ignore to continue",
14005 "Emacs Abort Dialog",
14006 MB_ICONEXCLAMATION | MB_TASKMODAL
14007 | MB_SETFOREGROUND | MB_ABORTRETRYIGNORE);
14008 switch (button)
14009 {
14010 case IDRETRY:
14011 DebugBreak ();
14012 break;
14013 case IDIGNORE:
14014 break;
14015 case IDABORT:
14016 default:
14017 abort ();
14018 break;
14019 }
14020 }
14021
14022 /* For convenience when debugging. */
14023 int
14024 w32_last_error()
14025 {
14026 return GetLastError ();
14027 }