]> code.delx.au - gnu-emacs/blob - src/w32term.c
(w32_enable_unicode_output): Rename from
[gnu-emacs] / src / w32term.c
1 /* Implementation of GUI terminal on the Microsoft W32 API.
2 Copyright (C) 1989, 93, 94, 95, 96, 97, 98 Free Software Foundation, Inc.
3
4 This file is part of GNU Emacs.
5
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
20
21 #include <signal.h>
22 #include <config.h>
23 #include <stdio.h>
24 #include "lisp.h"
25 #include "charset.h"
26 #include "fontset.h"
27 #include "blockinput.h"
28
29 #include "w32term.h"
30 #include <shellapi.h>
31
32 #include "systty.h"
33 #include "systime.h"
34
35 #include <ctype.h>
36 #include <errno.h>
37 #include <setjmp.h>
38 #include <sys/stat.h>
39
40 #include "frame.h"
41 #include "dispextern.h"
42 #include "termhooks.h"
43 #include "termopts.h"
44 #include "termchar.h"
45 #include "gnu.h"
46 #include "disptab.h"
47 #include "buffer.h"
48 #include "window.h"
49 #include "keyboard.h"
50 #include "intervals.h"
51 #include "coding.h"
52
53 #undef min
54 #undef max
55 #define min(x, y) (((x) < (y)) ? (x) : (y))
56 #define max(x, y) (((x) > (y)) ? (x) : (y))
57
58 /* Windows libraries do not define codepages other than ANSI and
59 Unicode. We need all the ones for the languages that Emacs supports
60 if languages other than that of the current locale are to be
61 displayed under NT. */
62 #define CP_DEFAULT 1004
63 #define CP_SJIS 932
64 #define CP_GB2312 936
65 #define CP_BIG5 950
66 #define CP_KOREAN 949
67 #define CP_THAI 874
68 #define CP_LATIN1 1252
69 #define CP_LATIN2 1250
70 #define CP_LATIN3 1254
71 #define CP_LATIN4 1257
72 #define CP_CYRILLIC5 1251
73 #define CP_ARABIC6 1256
74 #define CP_GREEK7 1253
75 #define CP_HEBREW8 1255
76 #define CP_LATIN9 /*1258?*/
77 #define CP_VIETNAM /*???*/
78
79 /* ENCODE_SJIS is defined in coding.h, but ENCODE_BIG5 is only in
80 coding.c, so need our own copy here */
81 #define BIG5_SAME_ROW (0xFF - 0xA1 + 0x7F - 0x40)
82 #define ENCODE_BIG5(charset, c1, c2, b1, b2) \
83 do { \
84 unsigned int temp = (c1 - 0x21) * (0xFF - 0xA1) + (c2 - 0x21); \
85 if (charset == charset_big5_2) \
86 temp += BIG5_SAME_ROW * (0xC9 - 0xA1); \
87 b1 = temp / BIG5_SAME_ROW + 0xA1; \
88 b2 = temp % BIG5_SAME_ROW; \
89 b2 += b2 < 0x3F ? 0x40 : 0x62; \
90 } while (0)
91
92 extern unsigned int msh_mousewheel;
93
94 extern void free_frame_menubar ();
95
96 extern Lisp_Object Vwindow_system;
97
98 #define x_any_window_to_frame x_window_to_frame
99 #define x_top_window_to_frame x_window_to_frame
100
101 \f
102 /* This is display since w32 does not support multiple ones. */
103 struct w32_display_info one_w32_display_info;
104
105 /* This is a list of cons cells, each of the form (NAME . FONT-LIST-CACHE),
106 one for each element of w32_display_list and in the same order.
107 NAME is the name of the frame.
108 FONT-LIST-CACHE records previous values returned by x-list-fonts. */
109 Lisp_Object w32_display_name_list;
110
111 /* Frame being updated by update_frame. This is declared in term.c.
112 This is set by update_begin and looked at by all the
113 w32 functions. It is zero while not inside an update.
114 In that case, the w32 functions assume that `selected_frame'
115 is the frame to apply to. */
116 extern struct frame *updating_frame;
117
118 /* This is a frame waiting to be autoraised, within w32_read_socket. */
119 struct frame *pending_autoraise_frame;
120
121 /* During an update, maximum vpos for ins/del line operations to affect. */
122
123 static int flexlines;
124
125 /* During an update, nonzero if chars output now should be highlighted. */
126
127 static int highlight;
128
129 /* Nominal cursor position -- where to draw output.
130 During an update, these are different from the cursor-box position. */
131
132 static int curs_x;
133 static int curs_y;
134
135 /* Flag to enable Unicode output in case users wish to use programs
136 like Twinbridge on '95 rather than installed system level support
137 for Far East languages. */
138 int w32_enable_unicode_output;
139
140 DWORD dwWindowsThreadId = 0;
141 HANDLE hWindowsThread = NULL;
142 DWORD dwMainThreadId = 0;
143 HANDLE hMainThread = NULL;
144
145 #ifndef SIF_ALL
146 /* These definitions are new with Windows 95. */
147 #define SIF_RANGE 0x0001
148 #define SIF_PAGE 0x0002
149 #define SIF_POS 0x0004
150 #define SIF_DISABLENOSCROLL 0x0008
151 #define SIF_TRACKPOS 0x0010
152 #define SIF_ALL (SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS)
153
154 typedef struct tagSCROLLINFO
155 {
156 UINT cbSize;
157 UINT fMask;
158 int nMin;
159 int nMax;
160 UINT nPage;
161 int nPos;
162 int nTrackPos;
163 } SCROLLINFO, FAR *LPSCROLLINFO;
164 typedef SCROLLINFO CONST FAR *LPCSCROLLINFO;
165 #endif /* SIF_ALL */
166
167 /* Dynamic linking to new proportional scroll bar functions. */
168 int (PASCAL *pfnSetScrollInfo) (HWND hwnd, int fnBar, LPSCROLLINFO lpsi, BOOL fRedraw);
169 BOOL (PASCAL *pfnGetScrollInfo) (HWND hwnd, int fnBar, LPSCROLLINFO lpsi);
170
171 int vertical_scroll_bar_min_handle;
172 int vertical_scroll_bar_top_border;
173 int vertical_scroll_bar_bottom_border;
174
175 int last_scroll_bar_drag_pos;
176
177 /* Mouse movement. */
178
179 /* Where the mouse was last time we reported a mouse event. */
180 static FRAME_PTR last_mouse_frame;
181 static RECT last_mouse_glyph;
182
183 Lisp_Object Vw32_num_mouse_buttons;
184
185 Lisp_Object Vw32_swap_mouse_buttons;
186
187 /* Control whether x_raise_frame also sets input focus. */
188 Lisp_Object Vw32_grab_focus_on_raise;
189
190 /* Control whether Caps Lock affects non-ascii characters. */
191 Lisp_Object Vw32_capslock_is_shiftlock;
192
193 /* Control whether right-alt and left-ctrl should be recognized as AltGr. */
194 Lisp_Object Vw32_recognize_altgr;
195
196 /* The scroll bar in which the last motion event occurred.
197
198 If the last motion event occurred in a scroll bar, we set this
199 so w32_mouse_position can know whether to report a scroll bar motion or
200 an ordinary motion.
201
202 If the last motion event didn't occur in a scroll bar, we set this
203 to Qnil, to tell w32_mouse_position to return an ordinary motion event. */
204 Lisp_Object last_mouse_scroll_bar;
205 int last_mouse_scroll_bar_pos;
206
207 /* This is a hack. We would really prefer that w32_mouse_position would
208 return the time associated with the position it returns, but there
209 doesn't seem to be any way to wrest the timestamp from the server
210 along with the position query. So, we just keep track of the time
211 of the last movement we received, and return that in hopes that
212 it's somewhat accurate. */
213 Time last_mouse_movement_time;
214
215 /* Incremented by w32_read_socket whenever it really tries to read events. */
216 #ifdef __STDC__
217 static int volatile input_signal_count;
218 #else
219 static int input_signal_count;
220 #endif
221
222 extern Lisp_Object Vcommand_line_args, Vsystem_name;
223
224 extern Lisp_Object Qface, Qmouse_face;
225
226 extern int errno;
227
228 /* A mask of extra modifier bits to put into every keyboard char. */
229 extern int extra_keyboard_modifiers;
230
231 static Lisp_Object Qvendor_specific_keysyms;
232
233 void w32_delete_display ();
234
235 static void redraw_previous_char ();
236 static void redraw_following_char ();
237 static unsigned int w32_get_modifiers ();
238
239 static int fast_find_position ();
240 static void note_mouse_highlight ();
241 static void clear_mouse_face ();
242 static void show_mouse_face ();
243 static void do_line_dance ();
244
245 /* Forward declarations for term hooks. Consistency with the rest of Emacs
246 requires the use of K&R functions prototypes. However, MSVC does not
247 pick up the function prototypes correctly with K&R function definitions,
248 and so we declare them first to give a little help to MSVC. */
249 static void w32_clear_frame ();
250 static void w32_clear_end_of_line (int);
251 static void w32_ins_del_lines (int, int);
252 static void w32_change_line_highlight (int, int, int);
253 static void w32_insert_glyphs (GLYPH *, int);
254 static void w32_write_glyphs (GLYPH *, int);
255 static void w32_delete_glyphs (int);
256 static void w32_ring_bell ();
257 static void w32_reset_terminal_modes ();
258 static void w32_set_terminal_modes ();
259 static void w32_update_begin (FRAME_PTR);
260 static void w32_update_end (FRAME_PTR);
261 static void w32_set_terminal_window (int);
262 extern int w32_read_socket (int, struct input_event *, int, int);
263 static void w32_frame_up_to_date (FRAME_PTR);
264 static void w32_cursor_to (int, int);
265 static void w32_reassert_line_highlight (int, int);
266 static void w32_mouse_position (FRAME_PTR *, int, Lisp_Object *,
267 enum scroll_bar_part *, Lisp_Object *,
268 Lisp_Object *, unsigned long *);
269 static void w32_frame_rehighlight (FRAME_PTR);
270 static void w32_frame_raise_lower (FRAME_PTR, int);
271 static void w32_set_vertical_scroll_bar (struct window *, int, int, int);
272 static void w32_condemn_scroll_bars (FRAME_PTR);
273 static void w32_redeem_scroll_bar (struct window *);
274 static void w32_judge_scroll_bars (FRAME_PTR);
275 \f
276 #if 0
277 /* This is a function useful for recording debugging information
278 about the sequence of occurrences in this file. */
279
280 struct record
281 {
282 char *locus;
283 int type;
284 };
285
286 struct record event_record[100];
287
288 int event_record_index;
289
290 record_event (locus, type)
291 char *locus;
292 int type;
293 {
294 if (event_record_index == sizeof (event_record) / sizeof (struct record))
295 event_record_index = 0;
296
297 event_record[event_record_index].locus = locus;
298 event_record[event_record_index].type = type;
299 event_record_index++;
300 }
301
302 #endif /* 0 */
303 \f
304 /* Return the struct w32_display_info. */
305
306 struct w32_display_info *
307 w32_display_info_for_display ()
308 {
309 return (&one_w32_display_info);
310 }
311
312 void
313 w32_fill_rect (f, _hdc, pix, lprect)
314 FRAME_PTR f;
315 HDC _hdc;
316 COLORREF pix;
317 RECT * lprect;
318 {
319 HDC hdc;
320 HBRUSH hb;
321 RECT rect;
322
323 if (_hdc)
324 hdc = _hdc;
325 else
326 {
327 if (!f) return;
328 hdc = get_frame_dc (f);
329 }
330
331 hb = CreateSolidBrush (pix);
332 FillRect (hdc, lprect, hb);
333 DeleteObject (hb);
334
335 if (!_hdc)
336 release_frame_dc (f, hdc);
337 }
338
339 void
340 w32_clear_window (f)
341 FRAME_PTR f;
342 {
343 RECT rect;
344
345 GetClientRect (FRAME_W32_WINDOW (f), &rect);
346 w32_clear_rect (f, NULL, &rect);
347 }
348
349 \f
350 /* Starting and ending updates.
351
352 These hooks are called by update_frame at the beginning and end
353 of a frame update. We record in `updating_frame' the identity
354 of the frame being updated, so that the w32_... functions do not
355 need to take a frame as argument. Most of the w32_... functions
356 should never be called except during an update, the only exceptions
357 being w32_cursor_to, w32_write_glyphs and w32_reassert_line_highlight. */
358
359 static void
360 w32_update_begin (f)
361 struct frame *f;
362 {
363 if (f == 0)
364 abort ();
365
366 flexlines = f->height;
367 highlight = 0;
368
369 BLOCK_INPUT;
370
371 /* Regenerate display palette before drawing if list of requested
372 colors has changed. */
373 if (FRAME_W32_DISPLAY_INFO (f)->regen_palette)
374 {
375 w32_regenerate_palette (f);
376 FRAME_W32_DISPLAY_INFO (f)->regen_palette = FALSE;
377 }
378
379 if (f == FRAME_W32_DISPLAY_INFO (f)->mouse_face_mouse_frame)
380 {
381 /* Don't do highlighting for mouse motion during the update. */
382 FRAME_W32_DISPLAY_INFO (f)->mouse_face_defer = 1;
383
384 /* If the frame needs to be redrawn,
385 simply forget about any prior mouse highlighting. */
386 if (FRAME_GARBAGED_P (f))
387 FRAME_W32_DISPLAY_INFO (f)->mouse_face_window = Qnil;
388
389 if (!NILP (FRAME_W32_DISPLAY_INFO (f)->mouse_face_window))
390 {
391 int firstline, lastline, i;
392 struct window *w = XWINDOW (FRAME_W32_DISPLAY_INFO (f)->mouse_face_window);
393
394 /* Find the first, and the last+1, lines affected by redisplay. */
395 for (firstline = 0; firstline < f->height; firstline++)
396 if (FRAME_DESIRED_GLYPHS (f)->enable[firstline])
397 break;
398
399 lastline = f->height;
400 for (i = f->height - 1; i >= 0; i--)
401 {
402 if (FRAME_DESIRED_GLYPHS (f)->enable[i])
403 break;
404 else
405 lastline = i;
406 }
407
408 /* Can we tell that this update does not affect the window
409 where the mouse highlight is? If so, no need to turn off.
410 Likewise, don't do anything if the frame is garbaged;
411 in that case, the FRAME_CURRENT_GLYPHS that we would use
412 are all wrong, and we will redisplay that line anyway. */
413 if (! (firstline > (XFASTINT (w->top) + window_internal_height (w))
414 || lastline < XFASTINT (w->top)))
415 clear_mouse_face (FRAME_W32_DISPLAY_INFO (f));
416 }
417 }
418
419 UNBLOCK_INPUT;
420 }
421
422 static void
423 w32_update_end (f)
424 struct frame *f;
425 {
426 BLOCK_INPUT;
427
428 do_line_dance ();
429 x_display_cursor (f, 1);
430
431 if (f == FRAME_W32_DISPLAY_INFO (f)->mouse_face_mouse_frame)
432 FRAME_W32_DISPLAY_INFO (f)->mouse_face_defer = 0;
433
434 UNBLOCK_INPUT;
435 }
436
437 /* This is called after a redisplay on frame F. */
438
439 static void
440 w32_frame_up_to_date (f)
441 FRAME_PTR f;
442 {
443 BLOCK_INPUT;
444 if (FRAME_W32_DISPLAY_INFO (f)->mouse_face_deferred_gc
445 || f == FRAME_W32_DISPLAY_INFO (f)->mouse_face_mouse_frame)
446 {
447 note_mouse_highlight (FRAME_W32_DISPLAY_INFO (f)->mouse_face_mouse_frame,
448 FRAME_W32_DISPLAY_INFO (f)->mouse_face_mouse_x,
449 FRAME_W32_DISPLAY_INFO (f)->mouse_face_mouse_y);
450 FRAME_W32_DISPLAY_INFO (f)->mouse_face_deferred_gc = 0;
451 }
452 UNBLOCK_INPUT;
453 }
454 \f
455 /* External interface to control of standout mode.
456 Call this when about to modify line at position VPOS
457 and not change whether it is highlighted. */
458
459 static void
460 w32_reassert_line_highlight (new, vpos)
461 int new, vpos;
462 {
463 highlight = new;
464 }
465
466 /* Call this when about to modify line at position VPOS
467 and change whether it is highlighted. */
468
469 static void
470 w32_change_line_highlight (new_highlight, vpos, first_unused_hpos)
471 int new_highlight, vpos, first_unused_hpos;
472 {
473 highlight = new_highlight;
474 w32_cursor_to (vpos, 0);
475 w32_clear_end_of_line (updating_frame->width);
476 }
477
478 /* This is used when starting Emacs and when restarting after suspend.
479 When starting Emacs, no window is mapped. And nothing must be done
480 to Emacs's own window if it is suspended (though that rarely happens). */
481
482 static void
483 w32_set_terminal_modes (void)
484 {
485 }
486
487 /* This is called when exiting or suspending Emacs.
488 Exiting will make the W32 windows go away, and suspending
489 requires no action. */
490
491 static void
492 w32_reset_terminal_modes (void)
493 {
494 }
495 \f
496 /* Set the nominal cursor position of the frame.
497 This is where display update commands will take effect.
498 This does not affect the place where the cursor-box is displayed. */
499
500 static void
501 w32_cursor_to (row, col)
502 register int row, col;
503 {
504 int orow = row;
505
506 curs_x = col;
507 curs_y = row;
508
509 if (updating_frame == 0)
510 {
511 BLOCK_INPUT;
512 x_display_cursor (selected_frame, 1);
513 UNBLOCK_INPUT;
514 }
515 }
516 \f
517 int
518 w32_codepage_for_charset (int charset)
519 {
520 /* The codepage is only used to convert to unicode, so we only need
521 to cover the languages that we may print via unicode. */
522 if (charset == charset_latin_iso8859_1)
523 return CP_LATIN1;
524 else if (charset == charset_big5_1 ||
525 charset == charset_big5_2)
526 return CP_BIG5;
527 else if (charset == charset_jisx0208
528 || charset == charset_jisx0208_1978
529 || charset == charset_katakana_jisx0201
530 || charset == charset_latin_jisx0201
531 || charset == charset_id_internal ("japanese-jisx0212"))
532 return CP_SJIS;
533 else if (charset == charset_id_internal ("chinese-gb2312"))
534 return CP_GB2312;
535 else if (charset == charset_id_internal ("korean-ksc5601"))
536 return CP_KOREAN;
537 else if (charset == charset_id_internal ("latin-iso8859-2"))
538 return CP_LATIN2;
539 else if (charset == charset_id_internal ("latin-iso8859-3"))
540 return CP_LATIN3;
541 else if (charset == charset_id_internal ("latin-iso8859-4"))
542 return CP_LATIN4;
543 else if (charset == charset_id_internal ("cyrillic-iso8859-5"))
544 return CP_CYRILLIC5;
545 else if (charset == charset_id_internal ("arabic-iso8859-6"))
546 return CP_ARABIC6;
547 else if (charset == charset_id_internal ("greek-iso8859-7"))
548 return CP_GREEK7;
549 else if (charset == charset_id_internal ("hebrew-iso8859-8"))
550 return CP_HEBREW8;
551 else if (charset == charset_id_internal ("thai-tis620"))
552 return CP_THAI;
553 else /* Don't care - return system default. */
554 return CP_DEFAULT;
555 }
556
557 BOOL
558 w32_use_unicode_for_codepage (codepage)
559 {
560 /* If the current codepage is supported, use Unicode for output. */
561 return (w32_enable_unicode_output
562 && codepage != CP_DEFAULT && IsValidCodePage (codepage));
563 }
564
565 /* Dealing with bits of wchar_t as if they were an XChar2B. */
566 #define BUILD_WCHAR_T(byte1, byte2) \
567 ((wchar_t)(((byte1 & 0x00ff) << 8) | (byte2 & 0x00ff)))
568
569
570 #define BYTE1(ch) \
571 ((ch & 0xff00) >> 8)
572
573 #define BYTE2(ch) \
574 (ch & 0x00ff)
575
576 \f
577 /* Display a sequence of N glyphs found at GP.
578 WINDOW is the window to output to. LEFT and TOP are starting coords.
579 HL is 1 if this text is highlighted, 2 if the cursor is on it,
580 3 if should appear in its mouse-face.
581 JUST_FOREGROUND if 1 means draw only the foreground;
582 don't alter the background.
583
584 FONT is the default font to use (for glyphs whose font-code is 0).
585
586 Since the display generation code is responsible for calling
587 compute_char_face and compute_glyph_face on everything it puts in
588 the display structure, we can assume that the face code on each
589 glyph is a valid index into FRAME_COMPUTED_FACES (f), and the one
590 to which we can actually apply intern_face.
591 Call this function with input blocked. */
592
593 static int
594 dumpglyphs (f, left, top, gp, n, hl, just_foreground, cmpcharp)
595 struct frame *f;
596 int left, top;
597 register GLYPH *gp; /* Points to first GLYPH. */
598 register int n; /* Number of glyphs to display. */
599 int hl;
600 int just_foreground;
601 struct cmpchar_info *cmpcharp;
602 {
603 wchar_t *x_2byte_buffer
604 = (wchar_t *) alloca (FRAME_WINDOW_WIDTH (f) * sizeof (*x_2byte_buffer));
605 register wchar_t *cp; /* Steps through x_2byte_buffer[]. */
606
607 /* Allocate double the window width, as this buffer may contain MBCS
608 characters under w32. */
609 char *x_1byte_buffer
610 = (char *) alloca (2 * FRAME_WINDOW_WIDTH (f) * sizeof (*x_1byte_buffer));
611 register char *bp; /* Steps through x_1byte_buffer[]. */
612 register int tlen = GLYPH_TABLE_LENGTH;
613 register Lisp_Object *tbase = GLYPH_TABLE_BASE;
614 Window window = FRAME_W32_WINDOW (f);
615 HDC hdc = get_frame_dc (f);
616 int orig_left = left;
617 int gidx = 0;
618 int i;
619
620 while (n > 0)
621 {
622 /* Get the face-code of the next GLYPH. */
623 int cf, len, n_chars;
624 GLYPH g = *gp;
625 int ch, charset;
626 Lisp_Object first_ch;
627 /* HIGHEST and LOWEST are used while drawing a composite
628 character. The meanings are described later. */
629 int highest, lowest;
630
631 GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
632 cf = (cmpcharp ? cmpcharp->face_work : FAST_GLYPH_FACE (g));
633 ch = FAST_GLYPH_CHAR (g);
634 if (unibyte_display_via_language_environment
635 && SINGLE_BYTE_CHAR_P (ch)
636 && ch >= 160)
637 ch = unibyte_char_to_multibyte (ch);
638 if (gidx == 0) XSETFASTINT (first_ch, ch);
639 charset = CHAR_CHARSET (ch);
640 if (charset == CHARSET_COMPOSITION)
641 {
642 /* We must draw components of the composite character on the
643 same column. */
644 cmpcharp = cmpchar_table[COMPOSITE_CHAR_ID (ch)];
645
646 /* Set the face in the slot for work. */
647 cmpcharp->face_work = cf;
648
649 /* We don't need the return value ... */
650 dumpglyphs (f, left, top, cmpcharp->glyph, cmpcharp->glyph_len,
651 hl, just_foreground, cmpcharp);
652 /* ... because the width of just drawn text can be
653 calculated as follows. */
654 left += FONT_WIDTH (FRAME_FONT (f)) * cmpcharp->width;
655
656 ++gp, --n;
657 while (gp && (*gp & GLYPH_MASK_PADDING)) ++gp, --n;
658 cmpcharp = NULL;
659 continue;
660 }
661
662 /* Find the run of consecutive glyphs which can be drawn with
663 the same DC (i.e. the same charset and the same face-code).
664 Extract their character codes into X_2BYTE_BUFFER.
665 If CMPCHARP is not NULL, face-code is not checked because we
666 use only the face specified in `cmpcharp->face_work'. */
667 cp = x_2byte_buffer;
668 while (n > 0)
669 {
670 int this_charset, c1, c2;
671
672 g = *gp;
673 GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
674 ch = FAST_GLYPH_CHAR (g);
675 if (unibyte_display_via_language_environment
676 && SINGLE_BYTE_CHAR_P (ch)
677 && ch >= 160)
678 ch = unibyte_char_to_multibyte (ch);
679 SPLIT_CHAR (ch, this_charset, c1, c2);
680 if (this_charset != charset
681 || (cmpcharp == NULL && FAST_GLYPH_FACE (g) != cf))
682 break;
683
684 if (c2 > 0)
685 *cp = BUILD_WCHAR_T (c1, c2);
686 else
687 *cp = BUILD_WCHAR_T (0, c1);
688 ++cp;
689 ++gp, --n;
690 while (gp && (*gp & GLYPH_MASK_PADDING))
691 ++gp, --n;
692 }
693
694 /* LEN gets the length of the run. */
695 len = cp - x_2byte_buffer;
696 /* Now output this run of chars, with the font and pixel values
697 determined by the face code CF. */
698 {
699 struct face *face = FRAME_DEFAULT_FACE (f);
700 XFontStruct *font = NULL;
701 COLORREF fg;
702 COLORREF bg;
703 int stippled = 0;
704 int line_height = FRAME_LINE_HEIGHT (f);
705 /* Pixel width of each glyph in this run. */
706 int glyph_width
707 = (FONT_WIDTH (FRAME_FONT (f))
708 * (cmpcharp ? cmpcharp->width : CHARSET_WIDTH (charset)));
709 /* Overall pixel width of this run. */
710 int run_width
711 = (FONT_WIDTH (FRAME_FONT (f))
712 * (cmpcharp ? cmpcharp->width : len * CHARSET_WIDTH (charset)));
713 /* A flag to tell if we have already filled background. We
714 fill background in advance in the following cases:
715 1) A face has stipple.
716 2) A height of font is shorter than LINE_HEIGHT.
717 3) Drawing a composite character.
718 4) Font has non-zero _MULE_BASELINE_OFFSET property.
719 After filling background, we draw glyphs by XDrawString16. */
720 int background_filled;
721 /* Baseline position of a character, offset from TOP. */
722 int baseline;
723 /* The property value of `_MULE_RELATIVE_COMPOSE' and
724 `_MULE_DEFAULT_ASCENT'. */
725 int relative_compose = 0, default_ascent = 0;
726 /* 1 if we find no font or a font of inappropriate size. */
727 int require_clipping;
728 int codepage = CP_DEFAULT;
729 BOOL print_via_unicode = FALSE;
730
731 /* HL = 3 means use a mouse face previously chosen. */
732 if (hl == 3)
733 cf = FRAME_W32_DISPLAY_INFO (f)->mouse_face_face_id;
734
735 /* First look at the face of the text itself. */
736 if (cf != 0)
737 {
738 /* It's possible for the display table to specify
739 a face code that is out of range. Use 0 in that case. */
740 if (cf < 0 || cf >= FRAME_N_COMPUTED_FACES (f)
741 || FRAME_COMPUTED_FACES (f) [cf] == 0)
742 cf = 0;
743
744 if (cf == 1)
745 face = FRAME_MODE_LINE_FACE (f);
746 else
747 face = intern_face (f, FRAME_COMPUTED_FACES (f) [cf]);
748 if (FACE_STIPPLE (face))
749 stippled = 1;
750 }
751
752 /* Then comes the distinction between modeline and normal text. */
753 else if (hl == 0)
754 ;
755 else if (hl == 1)
756 {
757 face = FRAME_MODE_LINE_FACE (f);
758 if (FACE_STIPPLE (face))
759 stippled = 1;
760 }
761
762 /* Setting appropriate font and codepage for this charset. */
763 if (charset != CHARSET_ASCII)
764 {
765 int font_id;
766 int fontset = FACE_FONTSET (face);
767 struct font_info *fontp;
768
769 if ((fontset < 0 && (fontset = FRAME_FONTSET (f)) < 0)
770 || !(fontp = FS_LOAD_FONT (f, FRAME_W32_FONT_TABLE (f),
771 charset, NULL, fontset)))
772 goto font_not_found;
773
774 font = (XFontStruct *) (fontp->font);
775 codepage = w32_codepage_for_charset (charset);
776 print_via_unicode = w32_use_unicode_for_codepage (codepage);
777
778 /* tmLastChar will only exceed 255 if TEXTMETRICW is used
779 (ie on NT but not on 95). In this case there is no harm
780 in being wrong, so have a go anyway. */
781 baseline =
782 (font->tm.tmLastChar > 255
783 ? (line_height + font->tm.tmAscent - font->tm.tmDescent) / 2
784 : f->output_data.w32->font_baseline - fontp->baseline_offset);
785 if (FONT_HEIGHT (font) <= line_height
786 && (font->tm.tmAscent > baseline
787 || font->tm.tmDescent > line_height - baseline))
788 /* Adjust baseline for this font to show the whole
789 glyphs in a line. */
790 baseline = line_height - font->tm.tmDescent;
791
792 if (cmpcharp && cmpcharp->cmp_rule == NULL)
793 {
794 relative_compose = fontp->relative_compose;
795 default_ascent = fontp->default_ascent;
796 }
797
798 /* We have to change code points in the following cases. */
799 if (charset == charset_big5_1
800 || charset == charset_big5_2)
801 {
802 /* Handle Big5 encoding specially rather than
803 requiring a CCL. */
804 int big1, big2;
805 for (cp = x_2byte_buffer; cp < x_2byte_buffer + len; cp++)
806 {
807 ENCODE_BIG5 (charset, BYTE1 (*cp), BYTE2 (*cp),
808 big1, big2);
809 *cp = BUILD_WCHAR_T (big1, big2);
810 }
811 }
812 else if (fontp->font_encoder)
813 {
814 /* This font requires CCL program to calculate code
815 point of characters. */
816 struct ccl_program *ccl = fontp->font_encoder;
817
818 if (CHARSET_DIMENSION (charset) == 1)
819 for (cp = x_2byte_buffer; cp < x_2byte_buffer + len; cp++)
820 {
821 ccl->reg[0] = charset;
822 ccl->reg[1] = BYTE2 (*cp);
823 ccl_driver (ccl, NULL, NULL, 0, 0, NULL);
824 /* We assume that MSBs are appropriately
825 set/reset by CCL program. */
826 #if 0 /* this probably works under NT, but not under 95. */
827 if (font->tm.tmLastChar < 256) /* 1-byte font */
828 *cp = BUILD_WCHAR_T (0, ccl->reg[1]);
829 else
830 *cp = BUILD_WCHAR_T (ccl->reg[1], ccl->reg[2]);
831 #else /* Assume single dimensional charsets stay so. */
832 *cp = BUILD_WCHAR_T (0, ccl->reg[1]);
833 #endif
834 }
835 else
836 for (cp = x_2byte_buffer; cp < x_2byte_buffer + len; cp++)
837 {
838 ccl->reg[0] = charset;
839 ccl->reg[1] = BYTE1 (*cp) , ccl->reg[2] = BYTE2 (*cp);
840 ccl_driver (ccl, NULL, NULL, 0, 0, NULL);
841 /* We assume that MSBs are appropriately
842 set/reset by CCL program. */
843 #if 0 /* this probably works under NT, but not under 95. */
844 if (font->tm.tmLastChar < 256) /* 1-byte font */
845 *cp = BUILD_WCHAR_T (0, ccl->reg[1]);
846 else
847 *cp = BUILD_WCHAR_T (ccl->reg[1],ccl->reg[2]);
848 #else /* Assume multidimensional charsets stay so. */
849 *cp = BUILD_WCHAR_T (ccl->reg[1],ccl->reg[2]);
850 #endif
851 }
852 }
853 /* Japanese Kanji are a special case under w32, as they
854 must be printed in SJIS rather than EUC. */
855 else if ((charset == charset_jisx0208)
856 || (charset == charset_jisx0208_1978)
857 || (charset == charset_id_internal ("japanese-jisx0212")))
858 {
859 int sjis1, sjis2;
860 for (cp = x_2byte_buffer; cp < x_2byte_buffer + len; cp++)
861 {
862 ENCODE_SJIS (BYTE1 (*cp), BYTE2 (*cp), sjis1, sjis2);
863 *cp = BUILD_WCHAR_T (sjis1, sjis2);
864 }
865 }
866 else if (fontp->encoding[charset])
867 {
868 int enc = fontp->encoding[charset];
869
870 if ((enc == 1 || enc == 2) && CHARSET_DIMENSION (charset) == 2)
871 for (cp = x_2byte_buffer; cp < x_2byte_buffer + len; cp++)
872 *cp = BUILD_WCHAR_T (BYTE1 (*cp) | 0x80, BYTE2 (*cp));
873 if (enc == 1 || enc == 3)
874 for (cp = x_2byte_buffer; cp < x_2byte_buffer + len; cp++)
875 *cp = BUILD_WCHAR_T (BYTE1 (*cp), BYTE2 (*cp) | 0x80);
876 }
877 }
878 else
879 {
880 font_not_found:
881 if (charset == CHARSET_ASCII || charset == charset_latin_iso8859_1)
882 {
883 font = FACE_FONT (face);
884 if (!font || font == (XFontStruct *) FACE_DEFAULT)
885 font = FRAME_FONT (f);
886 baseline = FONT_BASE (FRAME_FONT (f));
887 if (charset == charset_latin_iso8859_1)
888 {
889 if (font->tm.tmLastChar < 0x80)
890 /* This font can't display Latin1 characters. */
891 font = NULL;
892 else
893 {
894 for (cp = x_2byte_buffer;
895 cp < x_2byte_buffer + len; cp++)
896 *cp = BUILD_WCHAR_T (BYTE1 (*cp),
897 BYTE2 (*cp) | 0x80);
898 }
899 }
900 }
901 }
902
903 /* Convert x_2byte_buffer into a buffer of single byte
904 characters - possibly containing MBCS runs. */
905 bp = x_1byte_buffer;
906 for (i = 0; i < len; i++)
907 {
908 if (BYTE1 (*(x_2byte_buffer + i)))
909 *bp++ = BYTE1 (*(x_2byte_buffer + i));
910 *bp++ = BYTE2 (*(x_2byte_buffer + i));
911 }
912 n_chars = bp - x_1byte_buffer;
913
914 fg = face->foreground;
915 bg = face->background;
916
917 /* Now override that if the cursor's on this character. */
918 if (hl == 2)
919 {
920 /* The cursor overrides stippling. */
921 stippled = 0;
922
923 if (font == FRAME_FONT (f)
924 && face->background == FRAME_BACKGROUND_PIXEL (f)
925 && face->foreground == FRAME_FOREGROUND_PIXEL (f)
926 && !cmpcharp)
927 {
928 bg = f->output_data.w32->cursor_pixel;
929 fg = face->background;
930 }
931 /* Cursor on non-default face: must merge. */
932 else
933 {
934 bg = f->output_data.w32->cursor_pixel;
935 fg = face->background;
936 /* If the glyph would be invisible,
937 try a different foreground. */
938 if (fg == bg)
939 fg = face->foreground;
940 if (fg == bg)
941 fg = f->output_data.w32->cursor_foreground_pixel;
942 if (fg == bg)
943 fg = face->foreground;
944 /* Make sure the cursor is distinct from text in this face. */
945 if (bg == face->background
946 && fg == face->foreground)
947 {
948 bg = face->foreground;
949 fg = face->background;
950 }
951 }
952 }
953
954 if (font)
955 require_clipping = (!NILP (Vclip_large_size_font)
956 && (font->tm.tmAscent > baseline
957 || font->tm.tmDescent >
958 line_height - baseline
959 || (!cmpcharp
960 && FONT_WIDTH (font) > glyph_width)));
961
962 if (font && (just_foreground || (cmpcharp && gidx > 0)))
963 background_filled = 1;
964
965 /* Stippling not supported under w32. */
966
967 else if (!font
968 || FONT_HEIGHT (font) < line_height
969 || FONT_WIDTH (font) < glyph_width
970 || cmpcharp)
971 {
972 /* Fill in the background for the current run. */
973 w32_fill_area (f, hdc, bg,
974 left,
975 top,
976 run_width,
977 line_height);
978 background_filled = 1;
979 if (cmpcharp)
980 /* To assure not to fill background while drawing
981 remaining components. */
982 just_foreground = 1;
983 }
984 else
985 background_filled = 0;
986
987 SetBkMode (hdc, background_filled ? TRANSPARENT : OPAQUE);
988 SetTextColor (hdc, fg);
989 SetBkColor (hdc, bg);
990
991 if ( print_via_unicode )
992 n_chars = MultiByteToWideChar
993 (codepage, 0, x_1byte_buffer, n_chars,
994 x_2byte_buffer, FRAME_WINDOW_WIDTH (f));
995
996 if (font)
997 {
998 SelectObject (hdc, font->hfont);
999
1000 if (!cmpcharp)
1001 {
1002 int multibyte_pos_offset = 0;
1003 if (require_clipping || FONT_WIDTH (font) != glyph_width)
1004 {
1005 RECT clip_rectangle;
1006 LPRECT clip_region = NULL;
1007 UINT fuOptions = 0;
1008
1009 for (i = 0; i < n_chars; i++)
1010 {
1011 if (require_clipping)
1012 {
1013 /* Set up a clipping rectangle for ExtTextOut */
1014 fuOptions |= ETO_CLIPPED;
1015 clip_rectangle.left = left + i * glyph_width;
1016 clip_rectangle.right
1017 = left + (i + 1) * glyph_width;
1018 clip_rectangle.top = top;
1019 clip_rectangle.bottom = top + line_height;
1020 clip_region = &clip_rectangle;
1021 }
1022
1023 /* baseline works differently on w32 than X,
1024 leave it out for now. */
1025 if (print_via_unicode)
1026 ExtTextOutW (hdc, left + glyph_width * i,
1027 top /*+ baseline*/, fuOptions,
1028 clip_region, x_2byte_buffer + i,
1029 1, NULL);
1030 else if (CHARSET_DIMENSION (charset) > 1)
1031 {
1032 /* Keep character together */
1033 int n = CHARSET_DIMENSION (charset) ;
1034 ExtTextOut (hdc, left + multibyte_pos_offset,
1035 top /*+ baseline*/, fuOptions,
1036 clip_region, x_1byte_buffer + i,
1037 n, NULL);
1038 /* fiddle i. */
1039 i += n - 1;
1040 multibyte_pos_offset += glyph_width;
1041 }
1042 else
1043 ExtTextOut (hdc, left + glyph_width * i,
1044 top /*+ baseline*/, fuOptions,
1045 clip_region, x_1byte_buffer + i,
1046 1, NULL);
1047 }
1048 }
1049 else
1050 {
1051 /* Print the whole run of characters. */
1052 if (print_via_unicode)
1053 TextOutW (hdc, left, top /*+ baseline*/,
1054 x_2byte_buffer, n_chars);
1055 else
1056 TextOut (hdc, left, top /*+ baseline*/,
1057 x_1byte_buffer, n_chars);
1058 }
1059 }
1060 else
1061 {
1062 /* Handle composite characters. */
1063 RECT clip_rectangle;
1064 LPRECT clip_region = NULL;
1065 UINT fuOptions = 0;
1066
1067 if (require_clipping)
1068 {
1069 /* Set up a clipping rectangle for ExtTextOut */
1070 fuOptions |= ETO_CLIPPED;
1071 clip_rectangle.left = left;
1072 clip_rectangle.right = left + glyph_width;
1073 clip_rectangle.top = top;
1074 clip_rectangle.bottom = top + line_height;
1075 clip_region = &clip_rectangle;
1076 }
1077 if ((cmpcharp->cmp_rule || relative_compose)
1078 && gidx == 0)
1079 {
1080 /* This is the first character. Initialize variables.
1081 HIGHEST is the highest position of glyphs ever
1082 written, LOWEST the lowest position. */
1083 int x_offset = 0;
1084
1085 if (default_ascent
1086 && CHAR_TABLE_P (Vuse_default_ascent)
1087 && !NILP (Faref (Vuse_default_ascent, first_ch)))
1088 {
1089 highest = default_ascent;
1090 lowest = 0;
1091 }
1092 else
1093 {
1094 /* Per char metrics not supported on w32 - use
1095 font's metrics. */
1096 highest = font->tm.tmAscent + 1;
1097 lowest = - font->tm.tmDescent;
1098 }
1099
1100 if (cmpcharp->cmp_rule)
1101 x_offset = (cmpcharp->col_offset[0]
1102 * FONT_WIDTH (FRAME_FONT (f)));
1103
1104 i = 1;
1105
1106 /* Draw the first character at the normal position. */
1107 if (print_via_unicode)
1108 ExtTextOutW (hdc, left + x_offset,
1109 top /*+ baseline*/,
1110 fuOptions, clip_region,
1111 x_2byte_buffer, 1, NULL);
1112 else if (CHARSET_DIMENSION (charset) > 1)
1113 {
1114 /* Keep character together */
1115 int n = CHARSET_DIMENSION (charset) ;
1116 ExtTextOut (hdc, left + x_offset,
1117 top /*+ baseline*/,
1118 fuOptions, clip_region,
1119 x_1byte_buffer, n, NULL);
1120 /* fiddle i. */
1121 i += n - 1;
1122 }
1123 else
1124 ExtTextOut (hdc, left + x_offset,
1125 top /*+ baseline*/,
1126 fuOptions, clip_region,
1127 x_1byte_buffer, 1, NULL);
1128 gidx++;
1129 }
1130 else
1131 i = 0;
1132
1133 for (; i < n_chars; i++, gidx++)
1134 {
1135 int x_offset = 0, y_offset = 0;
1136
1137 if (relative_compose)
1138 {
1139 /* No per char metrics on w32. */
1140 if (NILP (Vignore_relative_composition)
1141 || NILP (Faref (Vignore_relative_composition,
1142 make_number (cmpcharp->glyph[gidx]))))
1143 {
1144 if (- font->tm.tmDescent >= relative_compose)
1145 {
1146 /* Draw above the current glyphs. */
1147 y_offset = highest + font->tm.tmDescent;
1148 highest += font->tm.tmAscent
1149 + font->tm.tmDescent;
1150 }
1151 else if (font->tm.tmAscent <= 0)
1152 {
1153 /* Draw beneath the current glyphs. */
1154 y_offset = lowest - font->tm.tmAscent;
1155 lowest -= font->tm.tmAscent
1156 + font->tm.tmDescent;
1157 }
1158 }
1159 else
1160 {
1161 /* Draw the glyph at normal position. If
1162 it sticks out of HIGHEST or LOWEST,
1163 update them appropriately. */
1164 if (font->tm.tmAscent > highest)
1165 highest = font->tm.tmAscent;
1166 else if (- font->tm.tmDescent < lowest)
1167 lowest = - font->tm.tmDescent;
1168 }
1169 }
1170 else if (cmpcharp->cmp_rule)
1171 {
1172 int gref = (cmpcharp->cmp_rule[gidx] - 0xA0) / 9;
1173 int nref = (cmpcharp->cmp_rule[gidx] - 0xA0) % 9;
1174 int bottom, top;
1175
1176 /* Re-encode GREF and NREF so that they specify
1177 only Y-axis information:
1178 0:top, 1:base, 2:bottom, 3:center */
1179 gref = gref / 3 + (gref == 4) * 2;
1180 nref = nref / 3 + (nref == 4) * 2;
1181
1182 /* No per char metrics on w32. */
1183 bottom = ((gref == 0 ? highest : gref == 1 ? 0
1184 : gref == 2 ? lowest
1185 : (highest + lowest) / 2)
1186 - (nref == 0 ? font->tm.tmAscent
1187 + font->tm.tmDescent
1188 : nref == 1 ? font->tm.tmDescent
1189 : nref == 2 ? 0
1190 : (font->tm.tmAscent +
1191 font->tm.tmDescent) / 2));
1192 top = bottom + (font->tm.tmAscent +
1193 font->tm.tmDescent);
1194 if (top > highest)
1195 highest = top;
1196 if (bottom < lowest)
1197 lowest = bottom;
1198 y_offset = bottom + font->tm.tmDescent;
1199 x_offset = (cmpcharp->col_offset[gidx]
1200 * FONT_WIDTH (FRAME_FONT(f)));
1201 }
1202
1203 if (print_via_unicode)
1204 ExtTextOutW (hdc, left + x_offset,
1205 top /*+ baseline - y_offset*/,
1206 fuOptions, clip_region,
1207 x_2byte_buffer + i, 1, NULL);
1208 else if (CHARSET_DIMENSION (charset) > 1)
1209 {
1210 /* Keep character together */
1211 int n = CHARSET_DIMENSION (charset) ;
1212 ExtTextOut (hdc, left + x_offset,
1213 top /*+ baseline - y_offset*/,
1214 fuOptions, clip_region,
1215 x_1byte_buffer + i, n, NULL);
1216 /* fiddle i. */
1217 i += n - 1;
1218 }
1219 else
1220 ExtTextOut (hdc, left + x_offset,
1221 top /*+ baseline - y_offset*/,
1222 fuOptions, clip_region,
1223 x_1byte_buffer + i, 1, NULL);
1224 }
1225 }
1226 }
1227 if (!font)
1228 {
1229 /* Show rectangles to indicate that we found no font. */
1230 int limit = cmpcharp ? 1 : len;
1231
1232 for (i = 0; i < limit; i++)
1233 Rectangle (hdc, left + glyph_width * i, top,
1234 left + glyph_width * (i + 1) - 1,
1235 top + line_height - 1);
1236 }
1237 else if (require_clipping && !NILP (Vhighlight_wrong_size_font))
1238 {
1239 /* Indicate that we found a font of inappropriate size. */
1240 int limit = cmpcharp ? 1 : len;
1241
1242 for (i = 0; i < limit; i++)
1243 {
1244 w32_fill_area (f, hdc, fg, left + glyph_width * i,
1245 top + line_height - 1, glyph_width, 1);
1246 w32_fill_area (f, hdc, fg, left + glyph_width * i,
1247 top + line_height - 3, 1, 2);
1248 }
1249 }
1250 {
1251 /* Setting underline position based on the metric of the
1252 current font results in shaky underline if it strides
1253 over different fonts. So, we set the position based only
1254 on the default font of this frame. */
1255 int underline_position = 1;
1256
1257 if (FRAME_FONT (f)->tm.tmDescent <= underline_position)
1258 underline_position = FRAME_FONT (f)->tm.tmDescent - 1;
1259
1260 if (face->underline)
1261 w32_fill_area (f, hdc, fg, left,
1262 top + FONT_BASE (FRAME_FONT (f))
1263 + underline_position,
1264 run_width, 1);
1265 }
1266
1267 if (!cmpcharp)
1268 left += run_width;
1269 }
1270 }
1271 release_frame_dc (f, hdc);
1272
1273 return (left - orig_left);
1274 }
1275
1276 \f
1277 /* Output some text at the nominal frame cursor position.
1278 Advance the cursor over the text.
1279 Output LEN glyphs at START.
1280
1281 `highlight', set up by w32_reassert_line_highlight or w32_change_line_highlight,
1282 controls the pixel values used for foreground and background. */
1283
1284 static void
1285 w32_write_glyphs (start, len)
1286 register GLYPH *start;
1287 int len;
1288 {
1289 register int temp_length;
1290 struct frame *f;
1291
1292 BLOCK_INPUT;
1293
1294 do_line_dance ();
1295 f = updating_frame;
1296 if (f == 0)
1297 {
1298 f = selected_frame;
1299 /* If not within an update,
1300 output at the frame's visible cursor. */
1301 curs_x = f->cursor_x;
1302 curs_y = f->cursor_y;
1303 }
1304
1305 dumpglyphs (f,
1306 CHAR_TO_PIXEL_COL (f, curs_x),
1307 CHAR_TO_PIXEL_ROW (f, curs_y),
1308 start, len, highlight, 0, NULL);
1309
1310 /* If we drew on top of the cursor, note that it is turned off. */
1311 if (curs_y == f->phys_cursor_y
1312 && curs_x <= f->phys_cursor_x
1313 && curs_x + len > f->phys_cursor_x)
1314 f->phys_cursor_x = -1;
1315
1316 if (updating_frame == 0)
1317 {
1318 f->cursor_x += len;
1319 x_display_cursor (f, 1);
1320 f->cursor_x -= len;
1321 }
1322 else
1323 curs_x += len;
1324
1325 UNBLOCK_INPUT;
1326 }
1327 \f
1328 /* Clear to the end of the line.
1329 Erase the current text line from the nominal cursor position (inclusive)
1330 to column FIRST_UNUSED (exclusive). The idea is that everything
1331 from FIRST_UNUSED onward is already erased. */
1332
1333 static void
1334 w32_clear_end_of_line (first_unused)
1335 register int first_unused;
1336 {
1337 struct frame *f = updating_frame;
1338
1339 if (f == 0)
1340 abort ();
1341
1342 if (curs_y < 0 || curs_y >= f->height)
1343 return;
1344 if (first_unused <= 0)
1345 return;
1346
1347 if (first_unused >= f->width)
1348 first_unused = f->width;
1349
1350 first_unused += FRAME_LEFT_SCROLL_BAR_WIDTH (f);
1351
1352 BLOCK_INPUT;
1353
1354 do_line_dance ();
1355
1356 /* Notice if the cursor will be cleared by this operation. */
1357 if (curs_y == f->phys_cursor_y
1358 && curs_x <= f->phys_cursor_x
1359 && f->phys_cursor_x < first_unused)
1360 f->phys_cursor_x = -1;
1361
1362 w32_clear_area (f, NULL,
1363 CHAR_TO_PIXEL_COL (f, curs_x),
1364 CHAR_TO_PIXEL_ROW (f, curs_y),
1365 FONT_WIDTH (f->output_data.w32->font) * (first_unused - curs_x),
1366 f->output_data.w32->line_height);
1367
1368 UNBLOCK_INPUT;
1369 }
1370
1371 static void
1372 w32_clear_frame ()
1373 {
1374 struct frame *f = updating_frame;
1375
1376 if (f == 0)
1377 f = selected_frame;
1378
1379 f->phys_cursor_x = -1; /* Cursor not visible. */
1380 curs_x = 0; /* Nominal cursor position is top left. */
1381 curs_y = 0;
1382
1383 BLOCK_INPUT;
1384
1385 w32_clear_window (f);
1386
1387 /* We have to clear the scroll bars, too. If we have changed
1388 colors or something like that, then they should be notified. */
1389 x_scroll_bar_clear (f);
1390
1391 UNBLOCK_INPUT;
1392 }
1393 \f
1394 /* Make audible bell. */
1395
1396 static void
1397 w32_ring_bell (void)
1398 {
1399 BLOCK_INPUT;
1400
1401 if (visible_bell)
1402 {
1403 int i;
1404 HWND hwnd = FRAME_W32_WINDOW (selected_frame);
1405
1406 for (i = 0; i < 5; i++)
1407 {
1408 FlashWindow (hwnd, TRUE);
1409 Sleep (10);
1410 }
1411 FlashWindow (hwnd, FALSE);
1412 }
1413 else
1414 w32_sys_ring_bell ();
1415
1416 UNBLOCK_INPUT;
1417 }
1418 \f
1419 /* Insert and delete character.
1420 These are not supposed to be used because we are supposed to turn
1421 off the feature of using them. */
1422
1423 static void
1424 w32_insert_glyphs (start, len)
1425 register GLYPH *start;
1426 register int len;
1427 {
1428 abort ();
1429 }
1430
1431 static void
1432 w32_delete_glyphs (n)
1433 register int n;
1434 {
1435 abort ();
1436 }
1437 \f
1438 /* Specify how many text lines, from the top of the window,
1439 should be affected by insert-lines and delete-lines operations.
1440 This, and those operations, are used only within an update
1441 that is bounded by calls to w32_update_begin and w32_update_end. */
1442
1443 static void
1444 w32_set_terminal_window (n)
1445 register int n;
1446 {
1447 if (updating_frame == 0)
1448 abort ();
1449
1450 if ((n <= 0) || (n > updating_frame->height))
1451 flexlines = updating_frame->height;
1452 else
1453 flexlines = n;
1454 }
1455 \f
1456 /* These variables need not be per frame
1457 because redisplay is done on a frame-by-frame basis
1458 and the line dance for one frame is finished before
1459 anything is done for another frame. */
1460
1461 /* Array of line numbers from cached insert/delete operations.
1462 line_dance[i] is the old position of the line that we want
1463 to move to line i, or -1 if we want a blank line there. */
1464 static int *line_dance;
1465
1466 /* Allocated length of that array. */
1467 static int line_dance_len;
1468
1469 /* Flag indicating whether we've done any work. */
1470 static int line_dance_in_progress;
1471
1472 /* Perform an insert-lines or delete-lines operation,
1473 inserting N lines or deleting -N lines at vertical position VPOS. */
1474
1475 static void
1476 w32_ins_del_lines (vpos, n)
1477 int vpos, n;
1478 {
1479 register int fence, i;
1480
1481 if (vpos >= flexlines)
1482 return;
1483
1484 if (!line_dance_in_progress)
1485 {
1486 int ht = updating_frame->height;
1487 if (ht > line_dance_len)
1488 {
1489 line_dance = (int *)xrealloc (line_dance, ht * sizeof (int));
1490 line_dance_len = ht;
1491 }
1492 for (i = 0; i < ht; ++i) line_dance[i] = i;
1493 line_dance_in_progress = 1;
1494 }
1495 if (n >= 0)
1496 {
1497 if (n > flexlines - vpos)
1498 n = flexlines - vpos;
1499 fence = vpos + n;
1500 for (i = flexlines; --i >= fence;)
1501 line_dance[i] = line_dance[i-n];
1502 for (i = fence; --i >= vpos;)
1503 line_dance[i] = -1;
1504 }
1505 else
1506 {
1507 n = -n;
1508 if (n > flexlines - vpos)
1509 n = flexlines - vpos;
1510 fence = flexlines - n;
1511 for (i = vpos; i < fence; ++i)
1512 line_dance[i] = line_dance[i + n];
1513 for (i = fence; i < flexlines; ++i)
1514 line_dance[i] = -1;
1515 }
1516 }
1517
1518 /* Here's where we actually move the pixels around.
1519 Must be called with input blocked. */
1520 static void
1521 do_line_dance ()
1522 {
1523 register int i, j, distance;
1524 register struct frame *f;
1525 int ht;
1526 int intborder;
1527 HDC hdc;
1528
1529 /* Must check this flag first. If it's not set, then not only is the
1530 array uninitialized, but we might not even have a frame. */
1531 if (!line_dance_in_progress)
1532 return;
1533
1534 f = updating_frame;
1535 if (f == 0)
1536 abort ();
1537
1538 ht = f->height;
1539 intborder = f->output_data.w32->internal_border_width;
1540
1541 x_display_cursor (updating_frame, 0);
1542
1543 hdc = get_frame_dc (f);
1544
1545 for (i = 0; i < ht; ++i)
1546 if (line_dance[i] != -1 && (distance = line_dance[i]-i) > 0)
1547 {
1548 for (j = i; (j < ht && line_dance[j] != -1
1549 && line_dance[j]-j == distance); ++j);
1550 /* Copy [i,j) upward from [i+distance, j+distance) */
1551 BitBlt (hdc,
1552 intborder, CHAR_TO_PIXEL_ROW (f, i+distance),
1553 f->width * FONT_WIDTH (f->output_data.w32->font),
1554 (j-i) * f->output_data.w32->line_height,
1555 hdc,
1556 intborder, CHAR_TO_PIXEL_ROW (f, i),
1557 SRCCOPY);
1558 i = j-1;
1559 }
1560
1561 for (i = ht; --i >=0; )
1562 if (line_dance[i] != -1 && (distance = line_dance[i]-i) < 0)
1563 {
1564 for (j = i; (--j >= 0 && line_dance[j] != -1
1565 && line_dance[j]-j == distance););
1566 /* Copy (j, i] downward from (j+distance, i+distance] */
1567 BitBlt (hdc,
1568 intborder, CHAR_TO_PIXEL_ROW (f, j+1+distance),
1569 f->width * FONT_WIDTH (f->output_data.w32->font),
1570 (i-j) * f->output_data.w32->line_height,
1571 hdc,
1572 intborder, CHAR_TO_PIXEL_ROW (f, j+1),
1573 SRCCOPY);
1574 i = j+1;
1575 }
1576
1577 for (i = 0; i < ht; ++i)
1578 if (line_dance[i] == -1)
1579 {
1580 for (j = i; j < ht && line_dance[j] == -1; ++j);
1581 /* Clear [i,j) */
1582 w32_clear_area (f, hdc,
1583 intborder,
1584 CHAR_TO_PIXEL_ROW (f, i),
1585 f->width * FONT_WIDTH (f->output_data.w32->font),
1586 (j-i) * f->output_data.w32->line_height);
1587 i = j-1;
1588 }
1589 line_dance_in_progress = 0;
1590
1591 release_frame_dc (f, hdc);
1592 }
1593 \f
1594 /* Support routines for exposure events. */
1595 static void clear_cursor ();
1596
1597 /* Output into a rectangle of a window (for frame F)
1598 the characters in f->phys_lines that overlap that rectangle.
1599 TOP and LEFT are the position of the upper left corner of the rectangle.
1600 ROWS and COLS are the size of the rectangle.
1601 Call this function with input blocked. */
1602
1603 void
1604 dumprectangle (f, left, top, cols, rows)
1605 struct frame *f;
1606 register int left, top, cols, rows;
1607 {
1608 register struct frame_glyphs *active_frame = FRAME_CURRENT_GLYPHS (f);
1609 int cursor_cleared = 0;
1610 int bottom, right;
1611 register int y;
1612
1613 if (FRAME_GARBAGED_P (f))
1614 return;
1615
1616 /* Express rectangle as four edges, instead of position-and-size. */
1617 bottom = top + rows;
1618 right = left + cols;
1619
1620 /* Convert rectangle edges in pixels to edges in chars.
1621 Round down for left and top, up for right and bottom. */
1622 top = PIXEL_TO_CHAR_ROW (f, top);
1623 left = PIXEL_TO_CHAR_COL (f, left);
1624 bottom += (f->output_data.w32->line_height - 1);
1625 right += (FONT_WIDTH (f->output_data.w32->font) - 1);
1626 bottom = PIXEL_TO_CHAR_ROW (f, bottom);
1627 right = PIXEL_TO_CHAR_COL (f, right);
1628
1629 /* Clip the rectangle to what can be visible. */
1630 if (left < 0)
1631 left = 0;
1632 if (top < 0)
1633 top = 0;
1634 if (right > f->width)
1635 right = f->width;
1636 if (bottom > f->height)
1637 bottom = f->height;
1638
1639 /* Get size in chars of the rectangle. */
1640 cols = right - left;
1641 rows = bottom - top;
1642
1643 /* If rectangle has zero area, return. */
1644 if (rows <= 0) return;
1645 if (cols <= 0) return;
1646
1647 /* Turn off the cursor if it is in the rectangle.
1648 We will turn it back on afterward. */
1649 if ((f->phys_cursor_x >= left) && (f->phys_cursor_x < right)
1650 && (f->phys_cursor_y >= top) && (f->phys_cursor_y < bottom))
1651 {
1652 clear_cursor (f);
1653 cursor_cleared = 1;
1654 }
1655
1656 /* Display the text in the rectangle, one text line at a time. */
1657
1658 for (y = top; y < bottom; y++)
1659 {
1660 GLYPH *line = &active_frame->glyphs[y][left];
1661
1662 if (! active_frame->enable[y] || left > active_frame->used[y])
1663 continue;
1664
1665 dumpglyphs (f,
1666 CHAR_TO_PIXEL_COL (f, left),
1667 CHAR_TO_PIXEL_ROW (f, y),
1668 line, min (cols, active_frame->used[y] - left),
1669 active_frame->highlight[y], 0, NULL);
1670 }
1671
1672 /* Turn the cursor on if we turned it off. */
1673
1674 if (cursor_cleared)
1675 x_display_cursor (f, 1);
1676 }
1677 \f
1678 static void
1679 frame_highlight (f)
1680 struct frame *f;
1681 {
1682 x_display_cursor (f, 1);
1683 }
1684
1685 static void
1686 frame_unhighlight (f)
1687 struct frame *f;
1688 {
1689 x_display_cursor (f, 1);
1690 }
1691
1692 static void x_frame_rehighlight ();
1693
1694 /* The focus has changed. Update the frames as necessary to reflect
1695 the new situation. Note that we can't change the selected frame
1696 here, because the Lisp code we are interrupting might become confused.
1697 Each event gets marked with the frame in which it occurred, so the
1698 Lisp code can tell when the switch took place by examining the events. */
1699
1700 void
1701 x_new_focus_frame (dpyinfo, frame)
1702 struct w32_display_info *dpyinfo;
1703 struct frame *frame;
1704 {
1705 struct frame *old_focus = dpyinfo->w32_focus_frame;
1706 int events_enqueued = 0;
1707
1708 if (frame != dpyinfo->w32_focus_frame)
1709 {
1710 /* Set this before calling other routines, so that they see
1711 the correct value of w32_focus_frame. */
1712 dpyinfo->w32_focus_frame = frame;
1713
1714 if (old_focus && old_focus->auto_lower)
1715 x_lower_frame (old_focus);
1716
1717 if (dpyinfo->w32_focus_frame && dpyinfo->w32_focus_frame->auto_raise)
1718 pending_autoraise_frame = dpyinfo->w32_focus_frame;
1719 else
1720 pending_autoraise_frame = 0;
1721 }
1722
1723 x_frame_rehighlight (dpyinfo);
1724 }
1725
1726 /* Handle an event saying the mouse has moved out of an Emacs frame. */
1727
1728 void
1729 x_mouse_leave (dpyinfo)
1730 struct w32_display_info *dpyinfo;
1731 {
1732 x_new_focus_frame (dpyinfo, dpyinfo->w32_focus_event_frame);
1733 }
1734
1735 /* The focus has changed, or we have redirected a frame's focus to
1736 another frame (this happens when a frame uses a surrogate
1737 minibuffer frame). Shift the highlight as appropriate.
1738
1739 The FRAME argument doesn't necessarily have anything to do with which
1740 frame is being highlighted or unhighlighted; we only use it to find
1741 the appropriate display info. */
1742 static void
1743 w32_frame_rehighlight (frame)
1744 struct frame *frame;
1745 {
1746 x_frame_rehighlight (FRAME_W32_DISPLAY_INFO (frame));
1747 }
1748
1749 static void
1750 x_frame_rehighlight (dpyinfo)
1751 struct w32_display_info *dpyinfo;
1752 {
1753 struct frame *old_highlight = dpyinfo->w32_highlight_frame;
1754
1755 if (dpyinfo->w32_focus_frame)
1756 {
1757 dpyinfo->w32_highlight_frame
1758 = ((GC_FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->w32_focus_frame)))
1759 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->w32_focus_frame))
1760 : dpyinfo->w32_focus_frame);
1761 if (! FRAME_LIVE_P (dpyinfo->w32_highlight_frame))
1762 {
1763 FRAME_FOCUS_FRAME (dpyinfo->w32_focus_frame) = Qnil;
1764 dpyinfo->w32_highlight_frame = dpyinfo->w32_focus_frame;
1765 }
1766 }
1767 else
1768 dpyinfo->w32_highlight_frame = 0;
1769
1770 if (dpyinfo->w32_highlight_frame != old_highlight)
1771 {
1772 if (old_highlight)
1773 frame_unhighlight (old_highlight);
1774 if (dpyinfo->w32_highlight_frame)
1775 frame_highlight (dpyinfo->w32_highlight_frame);
1776 }
1777 }
1778 \f
1779 /* Keyboard processing - modifier keys, etc. */
1780
1781 /* Convert a keysym to its name. */
1782
1783 char *
1784 x_get_keysym_name (keysym)
1785 int keysym;
1786 {
1787 /* Make static so we can always return it */
1788 static char value[100];
1789
1790 BLOCK_INPUT;
1791 GetKeyNameText(keysym, value, 100);
1792 UNBLOCK_INPUT;
1793
1794 return value;
1795 }
1796 \f
1797 /* Mouse clicks and mouse movement. Rah. */
1798
1799 /* Given a pixel position (PIX_X, PIX_Y) on the frame F, return
1800 glyph co-ordinates in (*X, *Y). Set *BOUNDS to the rectangle
1801 that the glyph at X, Y occupies, if BOUNDS != 0.
1802 If NOCLIP is nonzero, do not force the value into range. */
1803
1804 void
1805 pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
1806 FRAME_PTR f;
1807 register int pix_x, pix_y;
1808 register int *x, *y;
1809 RECT *bounds;
1810 int noclip;
1811 {
1812 /* Support tty mode: if Vwindow_system is nil, behave correctly. */
1813 if (NILP (Vwindow_system))
1814 {
1815 *x = pix_x;
1816 *y = pix_y;
1817 return;
1818 }
1819
1820 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to round down
1821 even for negative values. */
1822 if (pix_x < 0)
1823 pix_x -= FONT_WIDTH ((f)->output_data.w32->font) - 1;
1824 if (pix_y < 0)
1825 pix_y -= (f)->output_data.w32->line_height - 1;
1826
1827 pix_x = PIXEL_TO_CHAR_COL (f, pix_x);
1828 pix_y = PIXEL_TO_CHAR_ROW (f, pix_y);
1829
1830 if (bounds)
1831 {
1832 bounds->left = CHAR_TO_PIXEL_COL (f, pix_x);
1833 bounds->top = CHAR_TO_PIXEL_ROW (f, pix_y);
1834 bounds->right = bounds->left + FONT_WIDTH (f->output_data.w32->font) - 1;
1835 bounds->bottom = bounds->top + f->output_data.w32->line_height - 1;
1836 }
1837
1838 if (!noclip)
1839 {
1840 if (pix_x < 0)
1841 pix_x = 0;
1842 else if (pix_x > f->width)
1843 pix_x = f->width;
1844
1845 if (pix_y < 0)
1846 pix_y = 0;
1847 else if (pix_y > f->height)
1848 pix_y = f->height;
1849 }
1850
1851 *x = pix_x;
1852 *y = pix_y;
1853 }
1854
1855 void
1856 glyph_to_pixel_coords (f, x, y, pix_x, pix_y)
1857 FRAME_PTR f;
1858 register int x, y;
1859 register int *pix_x, *pix_y;
1860 {
1861 /* Support tty mode: if Vwindow_system is nil, behave correctly. */
1862 if (NILP (Vwindow_system))
1863 {
1864 *pix_x = x;
1865 *pix_y = y;
1866 return;
1867 }
1868
1869 *pix_x = CHAR_TO_PIXEL_COL (f, x);
1870 *pix_y = CHAR_TO_PIXEL_ROW (f, y);
1871 }
1872
1873 BOOL
1874 parse_button (message, pbutton, pup)
1875 int message;
1876 int * pbutton;
1877 int * pup;
1878 {
1879 int button = 0;
1880 int up = 0;
1881
1882 switch (message)
1883 {
1884 case WM_LBUTTONDOWN:
1885 button = 0;
1886 up = 0;
1887 break;
1888 case WM_LBUTTONUP:
1889 button = 0;
1890 up = 1;
1891 break;
1892 case WM_MBUTTONDOWN:
1893 if (NILP (Vw32_swap_mouse_buttons))
1894 button = 1;
1895 else
1896 button = 2;
1897 up = 0;
1898 break;
1899 case WM_MBUTTONUP:
1900 if (NILP (Vw32_swap_mouse_buttons))
1901 button = 1;
1902 else
1903 button = 2;
1904 up = 1;
1905 break;
1906 case WM_RBUTTONDOWN:
1907 if (NILP (Vw32_swap_mouse_buttons))
1908 button = 2;
1909 else
1910 button = 1;
1911 up = 0;
1912 break;
1913 case WM_RBUTTONUP:
1914 if (NILP (Vw32_swap_mouse_buttons))
1915 button = 2;
1916 else
1917 button = 1;
1918 up = 1;
1919 break;
1920 default:
1921 return (FALSE);
1922 }
1923
1924 if (pup) *pup = up;
1925 if (pbutton) *pbutton = button;
1926
1927 return (TRUE);
1928 }
1929
1930
1931 /* Prepare a mouse-event in *RESULT for placement in the input queue.
1932
1933 If the event is a button press, then note that we have grabbed
1934 the mouse. */
1935
1936 static void
1937 construct_mouse_click (result, msg, f)
1938 struct input_event *result;
1939 W32Msg *msg;
1940 struct frame *f;
1941 {
1942 int button;
1943 int up;
1944
1945 parse_button (msg->msg.message, &button, &up);
1946
1947 /* Make the event type no_event; we'll change that when we decide
1948 otherwise. */
1949 result->kind = mouse_click;
1950 result->code = button;
1951 result->timestamp = msg->msg.time;
1952 result->modifiers = (msg->dwModifiers
1953 | (up
1954 ? up_modifier
1955 : down_modifier));
1956
1957 {
1958 int row, column;
1959
1960 XSETINT (result->x, LOWORD (msg->msg.lParam));
1961 XSETINT (result->y, HIWORD (msg->msg.lParam));
1962 XSETFRAME (result->frame_or_window, f);
1963 }
1964 }
1965
1966 static void
1967 construct_mouse_wheel (result, msg, f)
1968 struct input_event *result;
1969 W32Msg *msg;
1970 struct frame *f;
1971 {
1972 POINT p;
1973 result->kind = mouse_wheel;
1974 result->code = (short) HIWORD (msg->msg.wParam);
1975 result->timestamp = msg->msg.time;
1976 result->modifiers = msg->dwModifiers;
1977 p.x = LOWORD (msg->msg.lParam);
1978 p.y = HIWORD (msg->msg.lParam);
1979 ScreenToClient(msg->msg.hwnd, &p);
1980 XSETINT (result->x, p.x);
1981 XSETINT (result->y, p.y);
1982 XSETFRAME (result->frame_or_window, f);
1983 }
1984
1985 static void
1986 construct_drag_n_drop (result, msg, f)
1987 struct input_event *result;
1988 W32Msg *msg;
1989 struct frame *f;
1990 {
1991 Lisp_Object files;
1992 Lisp_Object frame;
1993 HDROP hdrop;
1994 POINT p;
1995 WORD num_files;
1996 char *name;
1997 int i, len;
1998
1999 result->kind = drag_n_drop;
2000 result->code = 0;
2001 result->timestamp = msg->msg.time;
2002 result->modifiers = msg->dwModifiers;
2003
2004 p.x = LOWORD (msg->msg.lParam);
2005 p.y = HIWORD (msg->msg.lParam);
2006 ScreenToClient (msg->msg.hwnd, &p);
2007 XSETINT (result->x, p.x);
2008 XSETINT (result->y, p.y);
2009
2010 hdrop = (HDROP) msg->msg.wParam;
2011 DragQueryPoint (hdrop, &p);
2012 num_files = DragQueryFile (hdrop, 0xFFFFFFFF, NULL, 0);
2013 files = Qnil;
2014
2015 for (i = 0; i < num_files; i++)
2016 {
2017 len = DragQueryFile (hdrop, i, NULL, 0);
2018 if (len <= 0)
2019 continue;
2020 name = alloca (len + 1);
2021 DragQueryFile (hdrop, i, name, len + 1);
2022 files = Fcons (build_string (name), files);
2023 }
2024
2025 DragFinish (hdrop);
2026
2027 XSETFRAME (frame, f);
2028 result->frame_or_window = Fcons (frame, files);
2029 }
2030
2031 \f
2032 /* Function to report a mouse movement to the mainstream Emacs code.
2033 The input handler calls this.
2034
2035 We have received a mouse movement event, which is given in *event.
2036 If the mouse is over a different glyph than it was last time, tell
2037 the mainstream emacs code by setting mouse_moved. If not, ask for
2038 another motion event, so we can check again the next time it moves. */
2039
2040 static void
2041 note_mouse_movement (frame, msg)
2042 FRAME_PTR frame;
2043 MSG *msg;
2044 {
2045 last_mouse_movement_time = msg->time;
2046
2047 if (msg->hwnd != FRAME_W32_WINDOW (frame))
2048 {
2049 frame->mouse_moved = 1;
2050 last_mouse_scroll_bar = Qnil;
2051
2052 note_mouse_highlight (frame, -1, -1);
2053 }
2054
2055 /* Has the mouse moved off the glyph it was on at the last sighting? */
2056 else if (LOWORD (msg->lParam) < last_mouse_glyph.left
2057 || LOWORD (msg->lParam) > last_mouse_glyph.right
2058 || HIWORD (msg->lParam) < last_mouse_glyph.top
2059 || HIWORD (msg->lParam) > last_mouse_glyph.bottom)
2060 {
2061 frame->mouse_moved = 1;
2062 last_mouse_scroll_bar = Qnil;
2063
2064 note_mouse_highlight (frame, LOWORD (msg->lParam), HIWORD (msg->lParam));
2065 }
2066 }
2067
2068 /* This is used for debugging, to turn off note_mouse_highlight. */
2069 static int disable_mouse_highlight;
2070
2071 /* Take proper action when the mouse has moved to position X, Y on frame F
2072 as regards highlighting characters that have mouse-face properties.
2073 Also dehighlighting chars where the mouse was before.
2074 X and Y can be negative or out of range. */
2075
2076 static void
2077 note_mouse_highlight (f, x, y)
2078 FRAME_PTR f;
2079 int x, y;
2080 {
2081 int row, column, portion;
2082 RECT new_glyph;
2083 Lisp_Object window;
2084 struct window *w;
2085
2086 if (disable_mouse_highlight)
2087 return;
2088
2089 FRAME_W32_DISPLAY_INFO (f)->mouse_face_mouse_x = x;
2090 FRAME_W32_DISPLAY_INFO (f)->mouse_face_mouse_y = y;
2091 FRAME_W32_DISPLAY_INFO (f)->mouse_face_mouse_frame = f;
2092
2093 if (FRAME_W32_DISPLAY_INFO (f)->mouse_face_defer)
2094 return;
2095
2096 if (gc_in_progress)
2097 {
2098 FRAME_W32_DISPLAY_INFO (f)->mouse_face_deferred_gc = 1;
2099 return;
2100 }
2101
2102 /* Find out which glyph the mouse is on. */
2103 pixel_to_glyph_coords (f, x, y, &column, &row,
2104 &new_glyph, FRAME_W32_DISPLAY_INFO (f)->grabbed);
2105
2106 /* Which window is that in? */
2107 window = window_from_coordinates (f, column, row, &portion);
2108 w = XWINDOW (window);
2109
2110 /* If we were displaying active text in another window, clear that. */
2111 if (! EQ (window, FRAME_W32_DISPLAY_INFO (f)->mouse_face_window))
2112 clear_mouse_face (FRAME_W32_DISPLAY_INFO (f));
2113
2114 /* Are we in a window whose display is up to date?
2115 And verify the buffer's text has not changed. */
2116 if (WINDOWP (window) && portion == 0 && row >= 0 && column >= 0
2117 && row < FRAME_HEIGHT (f) && column < FRAME_WIDTH (f)
2118 && EQ (w->window_end_valid, w->buffer)
2119 && w->last_modified == BUF_MODIFF (XBUFFER (w->buffer))
2120 && w->last_overlay_modified == BUF_OVERLAY_MODIFF (XBUFFER (w->buffer)))
2121 {
2122 int *ptr = FRAME_CURRENT_GLYPHS (f)->charstarts[row];
2123 int i, pos;
2124
2125 /* Find which buffer position the mouse corresponds to. */
2126 for (i = column; i >= 0; i--)
2127 if (ptr[i] > 0)
2128 break;
2129 pos = ptr[i];
2130 /* Is it outside the displayed active region (if any)? */
2131 if (pos <= 0)
2132 clear_mouse_face (FRAME_W32_DISPLAY_INFO (f));
2133 else if (! (EQ (window, FRAME_W32_DISPLAY_INFO (f)->mouse_face_window)
2134 && row >= FRAME_W32_DISPLAY_INFO (f)->mouse_face_beg_row
2135 && row <= FRAME_W32_DISPLAY_INFO (f)->mouse_face_end_row
2136 && (row > FRAME_W32_DISPLAY_INFO (f)->mouse_face_beg_row
2137 || column >= FRAME_W32_DISPLAY_INFO (f)->mouse_face_beg_col)
2138 && (row < FRAME_W32_DISPLAY_INFO (f)->mouse_face_end_row
2139 || column < FRAME_W32_DISPLAY_INFO (f)->mouse_face_end_col
2140 || FRAME_W32_DISPLAY_INFO (f)->mouse_face_past_end)))
2141 {
2142 Lisp_Object mouse_face, overlay, position;
2143 Lisp_Object *overlay_vec;
2144 int len, noverlays, ignor1;
2145 struct buffer *obuf;
2146 int obegv, ozv;
2147
2148 /* If we get an out-of-range value, return now; avoid an error. */
2149 if (pos > BUF_Z (XBUFFER (w->buffer)))
2150 return;
2151
2152 /* Make the window's buffer temporarily current for
2153 overlays_at and compute_char_face. */
2154 obuf = current_buffer;
2155 current_buffer = XBUFFER (w->buffer);
2156 obegv = BEGV;
2157 ozv = ZV;
2158 BEGV = BEG;
2159 ZV = Z;
2160
2161 /* Yes. Clear the display of the old active region, if any. */
2162 clear_mouse_face (FRAME_W32_DISPLAY_INFO (f));
2163
2164 /* Is this char mouse-active? */
2165 XSETINT (position, pos);
2166
2167 len = 10;
2168 overlay_vec = (Lisp_Object *) xmalloc (len * sizeof (Lisp_Object));
2169
2170 /* Put all the overlays we want in a vector in overlay_vec.
2171 Store the length in len. */
2172 noverlays = overlays_at (XINT (pos), 1, &overlay_vec, &len,
2173 NULL, NULL);
2174 noverlays = sort_overlays (overlay_vec, noverlays, w);
2175
2176 /* Find the highest priority overlay that has a mouse-face prop. */
2177 overlay = Qnil;
2178 for (i = 0; i < noverlays; i++)
2179 {
2180 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
2181 if (!NILP (mouse_face))
2182 {
2183 overlay = overlay_vec[i];
2184 break;
2185 }
2186 }
2187 free (overlay_vec);
2188 /* If no overlay applies, get a text property. */
2189 if (NILP (overlay))
2190 mouse_face = Fget_text_property (position, Qmouse_face, w->buffer);
2191
2192 /* Handle the overlay case. */
2193 if (! NILP (overlay))
2194 {
2195 /* Find the range of text around this char that
2196 should be active. */
2197 Lisp_Object before, after;
2198 int ignore;
2199
2200 before = Foverlay_start (overlay);
2201 after = Foverlay_end (overlay);
2202 /* Record this as the current active region. */
2203 fast_find_position (window, before,
2204 &FRAME_W32_DISPLAY_INFO (f)->mouse_face_beg_col,
2205 &FRAME_W32_DISPLAY_INFO (f)->mouse_face_beg_row);
2206 FRAME_W32_DISPLAY_INFO (f)->mouse_face_past_end
2207 = !fast_find_position (window, after,
2208 &FRAME_W32_DISPLAY_INFO (f)->mouse_face_end_col,
2209 &FRAME_W32_DISPLAY_INFO (f)->mouse_face_end_row);
2210 FRAME_W32_DISPLAY_INFO (f)->mouse_face_window = window;
2211 FRAME_W32_DISPLAY_INFO (f)->mouse_face_face_id
2212 = compute_char_face (f, w, pos, 0, 0,
2213 &ignore, pos + 1, 1);
2214
2215 /* Display it as active. */
2216 show_mouse_face (FRAME_W32_DISPLAY_INFO (f), 1);
2217 }
2218 /* Handle the text property case. */
2219 else if (! NILP (mouse_face))
2220 {
2221 /* Find the range of text around this char that
2222 should be active. */
2223 Lisp_Object before, after, beginning, end;
2224 int ignore;
2225
2226 beginning = Fmarker_position (w->start);
2227 XSETINT (end, (BUF_Z (XBUFFER (w->buffer))
2228 - XFASTINT (w->window_end_pos)));
2229 before
2230 = Fprevious_single_property_change (make_number (pos + 1),
2231 Qmouse_face,
2232 w->buffer, beginning);
2233 after
2234 = Fnext_single_property_change (position, Qmouse_face,
2235 w->buffer, end);
2236 /* Record this as the current active region. */
2237 fast_find_position (window, before,
2238 &FRAME_W32_DISPLAY_INFO (f)->mouse_face_beg_col,
2239 &FRAME_W32_DISPLAY_INFO (f)->mouse_face_beg_row);
2240 FRAME_W32_DISPLAY_INFO (f)->mouse_face_past_end
2241 = !fast_find_position (window, after,
2242 &FRAME_W32_DISPLAY_INFO (f)->mouse_face_end_col,
2243 &FRAME_W32_DISPLAY_INFO (f)->mouse_face_end_row);
2244 FRAME_W32_DISPLAY_INFO (f)->mouse_face_window = window;
2245 FRAME_W32_DISPLAY_INFO (f)->mouse_face_face_id
2246 = compute_char_face (f, w, pos, 0, 0,
2247 &ignore, pos + 1, 1);
2248
2249 /* Display it as active. */
2250 show_mouse_face (FRAME_W32_DISPLAY_INFO (f), 1);
2251 }
2252 BEGV = obegv;
2253 ZV = ozv;
2254 current_buffer = obuf;
2255 }
2256 }
2257 }
2258 \f
2259 /* Find the row and column of position POS in window WINDOW.
2260 Store them in *COLUMNP and *ROWP.
2261 This assumes display in WINDOW is up to date.
2262 If POS is above start of WINDOW, return coords
2263 of start of first screen line.
2264 If POS is after end of WINDOW, return coords of end of last screen line.
2265
2266 Value is 1 if POS is in range, 0 if it was off screen. */
2267
2268 static int
2269 fast_find_position (window, pos, columnp, rowp)
2270 Lisp_Object window;
2271 int pos;
2272 int *columnp, *rowp;
2273 {
2274 struct window *w = XWINDOW (window);
2275 FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
2276 int i;
2277 int row = 0;
2278 int left = WINDOW_LEFT_MARGIN (w);
2279 int top = w->top;
2280 int height = XFASTINT (w->height) - ! MINI_WINDOW_P (w);
2281 int width = window_internal_width (w);
2282 int *charstarts;
2283 int lastcol;
2284 int maybe_next_line = 0;
2285
2286 /* Find the right row. */
2287 for (i = 0;
2288 i < height;
2289 i++)
2290 {
2291 int linestart = FRAME_CURRENT_GLYPHS (f)->charstarts[top + i][left];
2292 if (linestart > pos)
2293 break;
2294 /* If the position sought is the end of the buffer,
2295 don't include the blank lines at the bottom of the window. */
2296 if (linestart == pos && pos == BUF_ZV (XBUFFER (w->buffer)))
2297 {
2298 maybe_next_line = 1;
2299 break;
2300 }
2301 if (linestart > 0)
2302 row = i;
2303 }
2304
2305 /* Find the right column with in it. */
2306 charstarts = FRAME_CURRENT_GLYPHS (f)->charstarts[top + row];
2307 lastcol = left;
2308 for (i = 0; i < width; i++)
2309 {
2310 if (charstarts[left + i] == pos)
2311 {
2312 *rowp = row + top;
2313 *columnp = i + left;
2314 return 1;
2315 }
2316 else if (charstarts[left + i] > pos)
2317 break;
2318 else if (charstarts[left + i] > 0)
2319 lastcol = left + i;
2320 }
2321
2322 /* If we're looking for the end of the buffer,
2323 and we didn't find it in the line we scanned,
2324 use the start of the following line. */
2325 if (maybe_next_line)
2326 {
2327 row++;
2328 i = 0;
2329 }
2330
2331 *rowp = row + top;
2332 *columnp = lastcol;
2333 return 0;
2334 }
2335
2336 /* Display the active region described by mouse_face_*
2337 in its mouse-face if HL > 0, in its normal face if HL = 0. */
2338
2339 static void
2340 show_mouse_face (dpyinfo, hl)
2341 struct w32_display_info *dpyinfo;
2342 int hl;
2343 {
2344 struct window *w = XWINDOW (dpyinfo->mouse_face_window);
2345 int width = window_internal_width (w);
2346 FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
2347 int i;
2348 int cursor_off = 0;
2349 int old_curs_x = curs_x;
2350 int old_curs_y = curs_y;
2351
2352 /* Set these variables temporarily
2353 so that if we have to turn the cursor off and on again
2354 we will put it back at the same place. */
2355 curs_x = f->phys_cursor_x;
2356 curs_y = f->phys_cursor_y;
2357
2358 for (i = FRAME_W32_DISPLAY_INFO (f)->mouse_face_beg_row;
2359 i <= FRAME_W32_DISPLAY_INFO (f)->mouse_face_end_row; i++)
2360 {
2361 int column = (i == FRAME_W32_DISPLAY_INFO (f)->mouse_face_beg_row
2362 ? FRAME_W32_DISPLAY_INFO (f)->mouse_face_beg_col
2363 : WINDOW_LEFT_MARGIN (w));
2364 int endcolumn = (i == FRAME_W32_DISPLAY_INFO (f)->mouse_face_end_row
2365 ? FRAME_W32_DISPLAY_INFO (f)->mouse_face_end_col
2366 : WINDOW_LEFT_MARGIN (w) + width);
2367 endcolumn = min (endcolumn, FRAME_CURRENT_GLYPHS (f)->used[i]);
2368
2369 /* If the cursor's in the text we are about to rewrite,
2370 turn the cursor off. */
2371 if (i == curs_y
2372 && curs_x >= column - 1
2373 && curs_x <= endcolumn)
2374 {
2375 x_display_cursor (f, 0);
2376 cursor_off = 1;
2377 }
2378
2379 dumpglyphs (f,
2380 CHAR_TO_PIXEL_COL (f, column),
2381 CHAR_TO_PIXEL_ROW (f, i),
2382 FRAME_CURRENT_GLYPHS (f)->glyphs[i] + column,
2383 endcolumn - column,
2384 /* Highlight with mouse face if hl > 0. */
2385 hl > 0 ? 3 : 0, 0, NULL);
2386 }
2387
2388 /* If we turned the cursor off, turn it back on. */
2389 if (cursor_off)
2390 x_display_cursor (f, 1);
2391
2392 curs_x = old_curs_x;
2393 curs_y = old_curs_y;
2394
2395 /* Change the mouse cursor according to the value of HL. */
2396 if (hl > 0)
2397 SetCursor (f->output_data.w32->cross_cursor);
2398 else
2399 SetCursor (f->output_data.w32->text_cursor);
2400 }
2401
2402 /* Clear out the mouse-highlighted active region.
2403 Redraw it unhighlighted first. */
2404
2405 static void
2406 clear_mouse_face (dpyinfo)
2407 struct w32_display_info *dpyinfo;
2408 {
2409 if (! NILP (dpyinfo->mouse_face_window))
2410 show_mouse_face (dpyinfo, 0);
2411
2412 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
2413 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
2414 dpyinfo->mouse_face_window = Qnil;
2415 }
2416 \f
2417 struct scroll_bar *x_window_to_scroll_bar ();
2418 static void x_scroll_bar_report_motion ();
2419
2420 /* Return the current position of the mouse.
2421 *fp should be a frame which indicates which display to ask about.
2422
2423 If the mouse movement started in a scroll bar, set *fp, *bar_window,
2424 and *part to the frame, window, and scroll bar part that the mouse
2425 is over. Set *x and *y to the portion and whole of the mouse's
2426 position on the scroll bar.
2427
2428 If the mouse movement started elsewhere, set *fp to the frame the
2429 mouse is on, *bar_window to nil, and *x and *y to the character cell
2430 the mouse is over.
2431
2432 Set *time to the server timestamp for the time at which the mouse
2433 was at this position.
2434
2435 Don't store anything if we don't have a valid set of values to report.
2436
2437 This clears the mouse_moved flag, so we can wait for the next mouse
2438 movement. This also calls XQueryPointer, which will cause the
2439 server to give us another MotionNotify when the mouse moves
2440 again. */
2441
2442 static void
2443 w32_mouse_position (fp, insist, bar_window, part, x, y, time)
2444 FRAME_PTR *fp;
2445 int insist;
2446 Lisp_Object *bar_window;
2447 enum scroll_bar_part *part;
2448 Lisp_Object *x, *y;
2449 unsigned long *time;
2450 {
2451 FRAME_PTR f1;
2452
2453 BLOCK_INPUT;
2454
2455 if (! NILP (last_mouse_scroll_bar) && insist == 0)
2456 /* This is never called at the moment. */
2457 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
2458 else
2459 {
2460 POINT pt;
2461
2462 Lisp_Object frame, tail;
2463
2464 /* Clear the mouse-moved flag for every frame on this display. */
2465 FOR_EACH_FRAME (tail, frame)
2466 XFRAME (frame)->mouse_moved = 0;
2467
2468 last_mouse_scroll_bar = Qnil;
2469
2470 GetCursorPos (&pt);
2471
2472 /* Now we have a position on the root; find the innermost window
2473 containing the pointer. */
2474 {
2475 if (FRAME_W32_DISPLAY_INFO (*fp)->grabbed && last_mouse_frame
2476 && FRAME_LIVE_P (last_mouse_frame))
2477 {
2478 f1 = last_mouse_frame;
2479 }
2480 else
2481 {
2482 /* Is win one of our frames? */
2483 f1 = x_window_to_frame (FRAME_W32_DISPLAY_INFO (*fp), WindowFromPoint(pt));
2484 }
2485
2486 /* If not, is it one of our scroll bars? */
2487 if (! f1)
2488 {
2489 struct scroll_bar *bar = x_window_to_scroll_bar (WindowFromPoint(pt));
2490
2491 if (bar)
2492 {
2493 f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2494 }
2495 }
2496
2497 if (f1 == 0 && insist > 0)
2498 f1 = selected_frame;
2499
2500 if (f1)
2501 {
2502 int ignore1, ignore2;
2503
2504 ScreenToClient (FRAME_W32_WINDOW (f1), &pt);
2505
2506 /* Ok, we found a frame. Store all the values. */
2507
2508 pixel_to_glyph_coords (f1, pt.x, pt.y, &ignore1, &ignore2,
2509 &last_mouse_glyph,
2510 FRAME_W32_DISPLAY_INFO (f1)->grabbed
2511 || insist);
2512
2513 *bar_window = Qnil;
2514 *part = 0;
2515 *fp = f1;
2516 XSETINT (*x, pt.x);
2517 XSETINT (*y, pt.y);
2518 *time = last_mouse_movement_time;
2519 }
2520 }
2521 }
2522
2523 UNBLOCK_INPUT;
2524 }
2525 \f
2526 /* Scroll bar support. */
2527
2528 /* Given an window ID, find the struct scroll_bar which manages it.
2529 This can be called in GC, so we have to make sure to strip off mark
2530 bits. */
2531 struct scroll_bar *
2532 x_window_to_scroll_bar (window_id)
2533 Window window_id;
2534 {
2535 Lisp_Object tail, frame;
2536
2537 for (tail = Vframe_list;
2538 XGCTYPE (tail) == Lisp_Cons;
2539 tail = XCONS (tail)->cdr)
2540 {
2541 Lisp_Object frame, bar, condemned;
2542
2543 frame = XCONS (tail)->car;
2544 /* All elements of Vframe_list should be frames. */
2545 if (! GC_FRAMEP (frame))
2546 abort ();
2547
2548 /* Scan this frame's scroll bar list for a scroll bar with the
2549 right window ID. */
2550 condemned = FRAME_CONDEMNED_SCROLL_BARS (XFRAME (frame));
2551 for (bar = FRAME_SCROLL_BARS (XFRAME (frame));
2552 /* This trick allows us to search both the ordinary and
2553 condemned scroll bar lists with one loop. */
2554 ! GC_NILP (bar) || (bar = condemned,
2555 condemned = Qnil,
2556 ! GC_NILP (bar));
2557 bar = XSCROLL_BAR (bar)->next)
2558 if (SCROLL_BAR_W32_WINDOW (XSCROLL_BAR (bar)) == window_id)
2559 return XSCROLL_BAR (bar);
2560 }
2561
2562 return 0;
2563 }
2564
2565 HWND
2566 my_create_scrollbar (f, bar)
2567 struct frame * f;
2568 struct scroll_bar * bar;
2569 {
2570 return (HWND) SendMessage (FRAME_W32_WINDOW (f),
2571 WM_EMACS_CREATESCROLLBAR, (WPARAM) f,
2572 (LPARAM) bar);
2573 }
2574
2575 //#define ATTACH_THREADS
2576
2577 BOOL
2578 my_show_window (FRAME_PTR f, HWND hwnd, int how)
2579 {
2580 #ifndef ATTACH_THREADS
2581 return SendMessage (FRAME_W32_WINDOW (f), WM_EMACS_SHOWWINDOW,
2582 (WPARAM) hwnd, (LPARAM) how);
2583 #else
2584 return ShowWindow (hwnd, how);
2585 #endif
2586 }
2587
2588 void
2589 my_set_window_pos (HWND hwnd, HWND hwndAfter,
2590 int x, int y, int cx, int cy, UINT flags)
2591 {
2592 #ifndef ATTACH_THREADS
2593 WINDOWPOS pos;
2594 pos.hwndInsertAfter = hwndAfter;
2595 pos.x = x;
2596 pos.y = y;
2597 pos.cx = cx;
2598 pos.cy = cy;
2599 pos.flags = flags;
2600 SendMessage (hwnd, WM_EMACS_SETWINDOWPOS, (WPARAM) &pos, 0);
2601 #else
2602 SetWindowPos (hwnd, hwndAfter, x, y, cx, cy, flags);
2603 #endif
2604 }
2605
2606 BOOL
2607 my_set_focus (f, hwnd)
2608 struct frame * f;
2609 HWND hwnd;
2610 {
2611 SendMessage (FRAME_W32_WINDOW (f), WM_EMACS_SETFOCUS,
2612 (WPARAM) hwnd, 0);
2613 }
2614
2615 BOOL
2616 my_set_foreground_window (hwnd)
2617 HWND hwnd;
2618 {
2619 SendMessage (hwnd, WM_EMACS_SETFOREGROUND, (WPARAM) hwnd, 0);
2620 }
2621
2622 void
2623 my_destroy_window (f, hwnd)
2624 struct frame * f;
2625 HWND hwnd;
2626 {
2627 SendMessage (FRAME_W32_WINDOW (f), WM_EMACS_DESTROYWINDOW,
2628 (WPARAM) hwnd, 0);
2629 }
2630
2631 /* Open a new window to serve as a scroll bar, and return the
2632 scroll bar vector for it. */
2633 static struct scroll_bar *
2634 x_scroll_bar_create (window, top, left, width, height)
2635 struct window *window;
2636 int top, left, width, height;
2637 {
2638 FRAME_PTR f = XFRAME (WINDOW_FRAME (window));
2639 struct scroll_bar *bar
2640 = XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
2641 HWND hwnd;
2642
2643 BLOCK_INPUT;
2644
2645 XSETWINDOW (bar->window, window);
2646 XSETINT (bar->top, top);
2647 XSETINT (bar->left, left);
2648 XSETINT (bar->width, width);
2649 XSETINT (bar->height, height);
2650 XSETINT (bar->start, 0);
2651 XSETINT (bar->end, 0);
2652 bar->dragging = Qnil;
2653
2654 /* Requires geometry to be set before call to create the real window */
2655
2656 hwnd = my_create_scrollbar (f, bar);
2657
2658 if (pfnSetScrollInfo)
2659 {
2660 SCROLLINFO si;
2661
2662 si.cbSize = sizeof (si);
2663 si.fMask = SIF_ALL;
2664 si.nMin = 0;
2665 si.nMax = VERTICAL_SCROLL_BAR_TOP_RANGE (height)
2666 + VERTICAL_SCROLL_BAR_MIN_HANDLE;
2667 si.nPage = si.nMax;
2668 si.nPos = 0;
2669
2670 pfnSetScrollInfo (hwnd, SB_CTL, &si, FALSE);
2671 }
2672 else
2673 {
2674 SetScrollRange (hwnd, SB_CTL, 0, VERTICAL_SCROLL_BAR_TOP_RANGE (height), FALSE);
2675 SetScrollPos (hwnd, SB_CTL, 0, FALSE);
2676 }
2677
2678 SET_SCROLL_BAR_W32_WINDOW (bar, hwnd);
2679
2680 /* Add bar to its frame's list of scroll bars. */
2681 bar->next = FRAME_SCROLL_BARS (f);
2682 bar->prev = Qnil;
2683 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
2684 if (! NILP (bar->next))
2685 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
2686
2687 UNBLOCK_INPUT;
2688
2689 return bar;
2690 }
2691
2692 /* Draw BAR's handle in the proper position.
2693 If the handle is already drawn from START to END, don't bother
2694 redrawing it, unless REBUILD is non-zero; in that case, always
2695 redraw it. (REBUILD is handy for drawing the handle after expose
2696 events.)
2697
2698 Normally, we want to constrain the start and end of the handle to
2699 fit inside its rectangle, but if the user is dragging the scroll bar
2700 handle, we want to let them drag it down all the way, so that the
2701 bar's top is as far down as it goes; otherwise, there's no way to
2702 move to the very end of the buffer. */
2703 static void
2704 x_scroll_bar_set_handle (bar, start, end, rebuild)
2705 struct scroll_bar *bar;
2706 int start, end;
2707 int rebuild;
2708 {
2709 int dragging = ! NILP (bar->dragging);
2710 Window w = SCROLL_BAR_W32_WINDOW (bar);
2711 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2712
2713 /* If the display is already accurate, do nothing. */
2714 if (! rebuild
2715 && start == XINT (bar->start)
2716 && end == XINT (bar->end))
2717 return;
2718
2719 BLOCK_INPUT;
2720
2721 {
2722 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height));
2723
2724 /* Make sure the values are reasonable, and try to preserve
2725 the distance between start and end. */
2726 {
2727 int length = end - start;
2728
2729 if (start < 0)
2730 start = 0;
2731 else if (start > top_range)
2732 start = top_range;
2733 end = start + length;
2734
2735 if (end < start)
2736 end = start;
2737 else if (end > top_range && ! dragging)
2738 end = top_range;
2739 }
2740 }
2741
2742 /* Store the adjusted setting in the scroll bar. */
2743 XSETINT (bar->start, start);
2744 XSETINT (bar->end, end);
2745
2746 /* If being dragged, let scroll bar update itself. */
2747 if (!dragging)
2748 {
2749 if (pfnSetScrollInfo)
2750 {
2751 SCROLLINFO si;
2752
2753 si.cbSize = sizeof (si);
2754 si.fMask = SIF_PAGE | SIF_POS;
2755 si.nPage = end - start + VERTICAL_SCROLL_BAR_MIN_HANDLE;
2756 si.nPos = start;
2757
2758 pfnSetScrollInfo (w, SB_CTL, &si, TRUE);
2759 }
2760 else
2761 SetScrollPos (w, SB_CTL, start, TRUE);
2762 }
2763
2764 UNBLOCK_INPUT;
2765 }
2766
2767 /* Move a scroll bar around on the screen, to accommodate changing
2768 window configurations. */
2769 static void
2770 x_scroll_bar_move (bar, top, left, width, height)
2771 struct scroll_bar *bar;
2772 int top, left, width, height;
2773 {
2774 Window w = SCROLL_BAR_W32_WINDOW (bar);
2775 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2776
2777 /* If already correctly positioned, do nothing. */
2778 if ( XINT (bar->left) == left
2779 && XINT (bar->top) == top
2780 && XINT (bar->width) == width
2781 && XINT (bar->height) == height )
2782 {
2783 /* Redraw after clear_frame. */
2784 if (!my_show_window (f, w, SW_NORMAL))
2785 InvalidateRect (w, NULL, FALSE);
2786 return;
2787 }
2788
2789 BLOCK_INPUT;
2790
2791 /* Make sure scroll bar is "visible" before moving, to ensure the
2792 area of the parent window now exposed will be refreshed. */
2793 my_show_window (f, w, SW_HIDE);
2794 MoveWindow (w, left, top, width, height, TRUE);
2795 if (pfnSetScrollInfo)
2796 {
2797 SCROLLINFO si;
2798
2799 si.cbSize = sizeof (si);
2800 si.fMask = SIF_RANGE;
2801 si.nMin = 0;
2802 si.nMax = VERTICAL_SCROLL_BAR_TOP_RANGE (height)
2803 + VERTICAL_SCROLL_BAR_MIN_HANDLE;
2804
2805 pfnSetScrollInfo (w, SB_CTL, &si, FALSE);
2806 }
2807 else
2808 SetScrollRange (w, SB_CTL, 0, VERTICAL_SCROLL_BAR_TOP_RANGE (height), FALSE);
2809 my_show_window (f, w, SW_NORMAL);
2810 // InvalidateRect (w, NULL, FALSE);
2811
2812 XSETINT (bar->left, left);
2813 XSETINT (bar->top, top);
2814 XSETINT (bar->width, width);
2815 XSETINT (bar->height, height);
2816
2817 UNBLOCK_INPUT;
2818 }
2819
2820 /* Destroy the window for BAR, and set its Emacs window's scroll bar
2821 to nil. */
2822 static void
2823 x_scroll_bar_remove (bar)
2824 struct scroll_bar *bar;
2825 {
2826 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2827
2828 BLOCK_INPUT;
2829
2830 /* Destroy the window. */
2831 my_destroy_window (f, SCROLL_BAR_W32_WINDOW (bar));
2832
2833 /* Disassociate this scroll bar from its window. */
2834 XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
2835
2836 UNBLOCK_INPUT;
2837 }
2838
2839 /* Set the handle of the vertical scroll bar for WINDOW to indicate
2840 that we are displaying PORTION characters out of a total of WHOLE
2841 characters, starting at POSITION. If WINDOW has no scroll bar,
2842 create one. */
2843 static void
2844 w32_set_vertical_scroll_bar (window, portion, whole, position)
2845 struct window *window;
2846 int portion, whole, position;
2847 {
2848 FRAME_PTR f = XFRAME (WINDOW_FRAME (window));
2849 int top = XINT (window->top);
2850 int left = WINDOW_VERTICAL_SCROLL_BAR_COLUMN (window);
2851 int height = WINDOW_VERTICAL_SCROLL_BAR_HEIGHT (window);
2852
2853 /* Where should this scroll bar be, pixelwise? */
2854 int pixel_top = CHAR_TO_PIXEL_ROW (f, top);
2855 int pixel_left = CHAR_TO_PIXEL_COL (f, left);
2856 int pixel_width
2857 = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
2858 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
2859 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.w32->font)));
2860 int pixel_height = VERTICAL_SCROLL_BAR_PIXEL_HEIGHT (f, height);
2861
2862 struct scroll_bar *bar;
2863
2864 /* Does the scroll bar exist yet? */
2865 if (NILP (window->vertical_scroll_bar))
2866 bar = x_scroll_bar_create (window,
2867 pixel_top, pixel_left,
2868 pixel_width, pixel_height);
2869 else
2870 {
2871 /* It may just need to be moved and resized. */
2872 bar = XSCROLL_BAR (window->vertical_scroll_bar);
2873 x_scroll_bar_move (bar, pixel_top, pixel_left, pixel_width, pixel_height);
2874 }
2875
2876 /* Set the scroll bar's current state. */
2877 {
2878 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (pixel_height);
2879
2880 if (whole == 0)
2881 x_scroll_bar_set_handle (bar, 0, top_range, 0);
2882 else
2883 {
2884 int start = (int) (((double) position * top_range) / whole);
2885 int end = (int) (((double) (position + portion) * top_range) / whole);
2886
2887 x_scroll_bar_set_handle (bar, start, end, 0);
2888 }
2889 }
2890
2891 XSETVECTOR (window->vertical_scroll_bar, bar);
2892 }
2893
2894
2895 /* The following three hooks are used when we're doing a thorough
2896 redisplay of the frame. We don't explicitly know which scroll bars
2897 are going to be deleted, because keeping track of when windows go
2898 away is a real pain - "Can you say set-window-configuration, boys
2899 and girls?" Instead, we just assert at the beginning of redisplay
2900 that *all* scroll bars are to be removed, and then save a scroll bar
2901 from the fiery pit when we actually redisplay its window. */
2902
2903 /* Arrange for all scroll bars on FRAME to be removed at the next call
2904 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
2905 `*redeem_scroll_bar_hook' is applied to its window before the judgement. */
2906 static void
2907 w32_condemn_scroll_bars (frame)
2908 FRAME_PTR frame;
2909 {
2910 /* Transfer all the scroll bars to FRAME_CONDEMNED_SCROLL_BARS. */
2911 while (! NILP (FRAME_SCROLL_BARS (frame)))
2912 {
2913 Lisp_Object bar;
2914 bar = FRAME_SCROLL_BARS (frame);
2915 FRAME_SCROLL_BARS (frame) = XSCROLL_BAR (bar)->next;
2916 XSCROLL_BAR (bar)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
2917 XSCROLL_BAR (bar)->prev = Qnil;
2918 if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
2919 XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = bar;
2920 FRAME_CONDEMNED_SCROLL_BARS (frame) = bar;
2921 }
2922 #ifdef PIGSFLY
2923 /* The condemned list should be empty at this point; if it's not,
2924 then the rest of Emacs isn't using the condemn/redeem/judge
2925 protocol correctly. */
2926 if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
2927 abort ();
2928
2929 /* Move them all to the "condemned" list. */
2930 FRAME_CONDEMNED_SCROLL_BARS (frame) = FRAME_SCROLL_BARS (frame);
2931 FRAME_SCROLL_BARS (frame) = Qnil;
2932 #endif
2933 }
2934
2935 /* Unmark WINDOW's scroll bar for deletion in this judgement cycle.
2936 Note that WINDOW isn't necessarily condemned at all. */
2937 static void
2938 w32_redeem_scroll_bar (window)
2939 struct window *window;
2940 {
2941 struct scroll_bar *bar;
2942
2943 /* We can't redeem this window's scroll bar if it doesn't have one. */
2944 if (NILP (window->vertical_scroll_bar))
2945 abort ();
2946
2947 bar = XSCROLL_BAR (window->vertical_scroll_bar);
2948
2949 /* Unlink it from the condemned list. */
2950 {
2951 FRAME_PTR f = XFRAME (WINDOW_FRAME (window));
2952
2953 if (NILP (bar->prev))
2954 {
2955 /* If the prev pointer is nil, it must be the first in one of
2956 the lists. */
2957 if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
2958 /* It's not condemned. Everything's fine. */
2959 return;
2960 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
2961 window->vertical_scroll_bar))
2962 FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
2963 else
2964 /* If its prev pointer is nil, it must be at the front of
2965 one or the other! */
2966 abort ();
2967 }
2968 else
2969 XSCROLL_BAR (bar->prev)->next = bar->next;
2970
2971 if (! NILP (bar->next))
2972 XSCROLL_BAR (bar->next)->prev = bar->prev;
2973
2974 bar->next = FRAME_SCROLL_BARS (f);
2975 bar->prev = Qnil;
2976 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
2977 if (! NILP (bar->next))
2978 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
2979 }
2980 #ifdef PIGSFLY
2981 struct scroll_bar *bar;
2982
2983 /* We can't redeem this window's scroll bar if it doesn't have one. */
2984 if (NILP (window->vertical_scroll_bar))
2985 abort ();
2986
2987 bar = XSCROLL_BAR (window->vertical_scroll_bar);
2988
2989 /* Unlink it from the condemned list. */
2990 {
2991 FRAME_PTR f = XFRAME (WINDOW_FRAME (window));
2992
2993 if (NILP (bar->prev))
2994 {
2995 /* If the prev pointer is nil, it must be the first in one of
2996 the lists. */
2997 if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
2998 /* It's not condemned. Everything's fine. */
2999 return;
3000 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
3001 window->vertical_scroll_bar))
3002 FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
3003 else
3004 /* If its prev pointer is nil, it must be at the front of
3005 one or the other! */
3006 abort ();
3007 }
3008 else
3009 XSCROLL_BAR (bar->prev)->next = bar->next;
3010
3011 if (! NILP (bar->next))
3012 XSCROLL_BAR (bar->next)->prev = bar->prev;
3013
3014 bar->next = FRAME_SCROLL_BARS (f);
3015 bar->prev = Qnil;
3016 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
3017 if (! NILP (bar->next))
3018 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
3019 }
3020 #endif
3021 }
3022
3023 /* Remove all scroll bars on FRAME that haven't been saved since the
3024 last call to `*condemn_scroll_bars_hook'. */
3025 static void
3026 w32_judge_scroll_bars (f)
3027 FRAME_PTR f;
3028 {
3029 Lisp_Object bar, next;
3030
3031 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
3032
3033 /* Clear out the condemned list now so we won't try to process any
3034 more events on the hapless scroll bars. */
3035 FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
3036
3037 for (; ! NILP (bar); bar = next)
3038 {
3039 struct scroll_bar *b = XSCROLL_BAR (bar);
3040
3041 x_scroll_bar_remove (b);
3042
3043 next = b->next;
3044 b->next = b->prev = Qnil;
3045 }
3046
3047 /* Now there should be no references to the condemned scroll bars,
3048 and they should get garbage-collected. */
3049 #ifdef PIGSFLY
3050 Lisp_Object bar, next;
3051
3052 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
3053
3054 /* Clear out the condemned list now so we won't try to process any
3055 more events on the hapless scroll bars. */
3056 FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
3057
3058 for (; ! NILP (bar); bar = next)
3059 {
3060 struct scroll_bar *b = XSCROLL_BAR (bar);
3061
3062 x_scroll_bar_remove (b);
3063
3064 next = b->next;
3065 b->next = b->prev = Qnil;
3066 }
3067
3068 /* Now there should be no references to the condemned scroll bars,
3069 and they should get garbage-collected. */
3070 #endif
3071 }
3072
3073 /* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
3074 is set to something other than no_event, it is enqueued.
3075
3076 This may be called from a signal handler, so we have to ignore GC
3077 mark bits. */
3078
3079 static int
3080 x_scroll_bar_handle_click (bar, msg, emacs_event)
3081 struct scroll_bar *bar;
3082 W32Msg *msg;
3083 struct input_event *emacs_event;
3084 {
3085 if (! GC_WINDOWP (bar->window))
3086 abort ();
3087
3088 emacs_event->kind = w32_scroll_bar_click;
3089 emacs_event->code = 0;
3090 /* not really meaningful to distinguish up/down */
3091 emacs_event->modifiers = msg->dwModifiers;
3092 emacs_event->frame_or_window = bar->window;
3093 emacs_event->timestamp = msg->msg.time;
3094
3095 {
3096 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height));
3097 int y;
3098 int dragging = !NILP (bar->dragging);
3099
3100 if (pfnGetScrollInfo)
3101 {
3102 SCROLLINFO si;
3103
3104 si.cbSize = sizeof (si);
3105 si.fMask = SIF_POS;
3106
3107 pfnGetScrollInfo ((HWND) msg->msg.lParam, SB_CTL, &si);
3108 y = si.nPos;
3109 }
3110 else
3111 y = GetScrollPos ((HWND) msg->msg.lParam, SB_CTL);
3112
3113 bar->dragging = Qnil;
3114
3115 switch (LOWORD (msg->msg.wParam))
3116 {
3117 case SB_LINEDOWN:
3118 emacs_event->part = scroll_bar_down_arrow;
3119 break;
3120 case SB_LINEUP:
3121 emacs_event->part = scroll_bar_up_arrow;
3122 break;
3123 case SB_PAGEUP:
3124 emacs_event->part = scroll_bar_above_handle;
3125 break;
3126 case SB_PAGEDOWN:
3127 emacs_event->part = scroll_bar_below_handle;
3128 break;
3129 case SB_TOP:
3130 emacs_event->part = scroll_bar_handle;
3131 y = 0;
3132 break;
3133 case SB_BOTTOM:
3134 emacs_event->part = scroll_bar_handle;
3135 y = top_range;
3136 break;
3137 case SB_THUMBTRACK:
3138 case SB_THUMBPOSITION:
3139 if (VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height)) <= 0xffff)
3140 y = HIWORD (msg->msg.wParam);
3141 bar->dragging = Qt;
3142 emacs_event->part = scroll_bar_handle;
3143
3144 /* "Silently" update current position. */
3145 if (pfnSetScrollInfo)
3146 {
3147 SCROLLINFO si;
3148
3149 si.cbSize = sizeof (si);
3150 si.fMask = SIF_POS;
3151
3152 #if 0
3153 /* Shrink handle if necessary to allow full range for position. */
3154 {
3155 int start = XINT (bar->start);
3156 int end = XINT (bar->end);
3157 int len = end - start;
3158
3159 /* If new end is nearly hitting bottom, we must shrink
3160 handle. How much we shrink it depends on the relative
3161 sizes of len and top_range. */
3162 if (y + len > top_range - 2)
3163 {
3164 len -= min (top_range / 10, (len / 3) + 2);
3165 if (len < 0)
3166 len = 0;
3167 }
3168 si.nPage = len + VERTICAL_SCROLL_BAR_MIN_HANDLE;
3169 si.fMask |= SIF_PAGE;
3170 }
3171 #endif
3172 si.nPos = y;
3173 /* Remember apparent position (we actually lag behind the real
3174 position, so don't set that directly. */
3175 last_scroll_bar_drag_pos = y;
3176
3177 pfnSetScrollInfo (SCROLL_BAR_W32_WINDOW (bar), SB_CTL, &si, FALSE);
3178 }
3179 else
3180 SetScrollPos (SCROLL_BAR_W32_WINDOW (bar), SB_CTL, y, FALSE);
3181 break;
3182 case SB_ENDSCROLL:
3183 /* If this is the end of a drag sequence, then reset the scroll
3184 handle size to normal and do a final redraw. Otherwise do
3185 nothing. */
3186 if (dragging)
3187 {
3188 if (pfnSetScrollInfo)
3189 {
3190 SCROLLINFO si;
3191 int start = XINT (bar->start);
3192 int end = XINT (bar->end);
3193
3194 si.cbSize = sizeof (si);
3195 si.fMask = SIF_PAGE | SIF_POS;
3196 si.nPage = end - start + VERTICAL_SCROLL_BAR_MIN_HANDLE;
3197 si.nPos = last_scroll_bar_drag_pos;
3198
3199 pfnSetScrollInfo (SCROLL_BAR_W32_WINDOW (bar), SB_CTL, &si, TRUE);
3200 }
3201 else
3202 SetScrollPos (SCROLL_BAR_W32_WINDOW (bar), SB_CTL, y, TRUE);
3203 }
3204 /* fall through */
3205 default:
3206 emacs_event->kind = no_event;
3207 return FALSE;
3208 }
3209
3210 XSETINT (emacs_event->x, y);
3211 XSETINT (emacs_event->y, top_range);
3212
3213 return TRUE;
3214 }
3215 }
3216
3217 /* Return information to the user about the current position of the mouse
3218 on the scroll bar. */
3219 static void
3220 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
3221 FRAME_PTR *fp;
3222 Lisp_Object *bar_window;
3223 enum scroll_bar_part *part;
3224 Lisp_Object *x, *y;
3225 unsigned long *time;
3226 {
3227 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
3228 Window w = SCROLL_BAR_W32_WINDOW (bar);
3229 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
3230 int pos;
3231 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height));
3232
3233 BLOCK_INPUT;
3234
3235 *fp = f;
3236 *bar_window = bar->window;
3237
3238 if (pfnGetScrollInfo)
3239 {
3240 SCROLLINFO si;
3241
3242 si.cbSize = sizeof (si);
3243 si.fMask = SIF_POS | SIF_PAGE | SIF_RANGE;
3244
3245 pfnGetScrollInfo (w, SB_CTL, &si);
3246 pos = si.nPos;
3247 top_range = si.nMax - si.nPage + 1;
3248 }
3249 else
3250 pos = GetScrollPos (w, SB_CTL);
3251
3252 switch (LOWORD (last_mouse_scroll_bar_pos))
3253 {
3254 case SB_THUMBPOSITION:
3255 case SB_THUMBTRACK:
3256 *part = scroll_bar_handle;
3257 if (VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height)) <= 0xffff)
3258 pos = HIWORD (last_mouse_scroll_bar_pos);
3259 break;
3260 case SB_LINEDOWN:
3261 *part = scroll_bar_handle;
3262 pos++;
3263 break;
3264 default:
3265 *part = scroll_bar_handle;
3266 break;
3267 }
3268
3269 XSETINT(*x, pos);
3270 XSETINT(*y, top_range);
3271
3272 f->mouse_moved = 0;
3273 last_mouse_scroll_bar = Qnil;
3274
3275 *time = last_mouse_movement_time;
3276
3277 UNBLOCK_INPUT;
3278 }
3279
3280 /* The screen has been cleared so we may have changed foreground or
3281 background colors, and the scroll bars may need to be redrawn.
3282 Clear out the scroll bars, and ask for expose events, so we can
3283 redraw them. */
3284
3285 x_scroll_bar_clear (f)
3286 FRAME_PTR f;
3287 {
3288 Lisp_Object bar;
3289
3290 for (bar = FRAME_SCROLL_BARS (f); VECTORP (bar);
3291 bar = XSCROLL_BAR (bar)->next)
3292 {
3293 HWND window = SCROLL_BAR_W32_WINDOW (XSCROLL_BAR (bar));
3294 HDC hdc = GetDC (window);
3295 RECT rect;
3296
3297 /* Hide scroll bar until ready to repaint. x_scroll_bar_move
3298 arranges to refresh the scroll bar if hidden. */
3299 my_show_window (f, window, SW_HIDE);
3300
3301 GetClientRect (window, &rect);
3302 select_palette (f, hdc);
3303 w32_clear_rect (f, hdc, &rect);
3304 deselect_palette (f, hdc);
3305
3306 ReleaseDC (window, hdc);
3307 }
3308 }
3309
3310 show_scroll_bars (f, how)
3311 FRAME_PTR f;
3312 int how;
3313 {
3314 Lisp_Object bar;
3315
3316 for (bar = FRAME_SCROLL_BARS (f); VECTORP (bar);
3317 bar = XSCROLL_BAR (bar)->next)
3318 {
3319 HWND window = SCROLL_BAR_W32_WINDOW (XSCROLL_BAR (bar));
3320 my_show_window (f, window, how);
3321 }
3322 }
3323
3324 \f
3325 /* The main W32 event-reading loop - w32_read_socket. */
3326
3327 /* Timestamp of enter window event. This is only used by w32_read_socket,
3328 but we have to put it out here, since static variables within functions
3329 sometimes don't work. */
3330 static Time enter_timestamp;
3331
3332 /* Record the last 100 characters stored
3333 to help debug the loss-of-chars-during-GC problem. */
3334 int temp_index;
3335 short temp_buffer[100];
3336
3337 extern int key_event (KEY_EVENT_RECORD *, struct input_event *, int *isdead);
3338
3339 /* Map a W32 WM_CHAR message into a KEY_EVENT_RECORD so that
3340 we can use the same routines to handle input in both console
3341 and window modes. */
3342
3343 static void
3344 convert_to_key_event (W32Msg *msgp, KEY_EVENT_RECORD *eventp)
3345 {
3346 eventp->bKeyDown = TRUE;
3347 eventp->wRepeatCount = 1;
3348 eventp->wVirtualKeyCode = msgp->msg.wParam;
3349 eventp->wVirtualScanCode = (msgp->msg.lParam & 0xFF0000) >> 16;
3350 eventp->uChar.AsciiChar = 0;
3351 eventp->dwControlKeyState = msgp->dwModifiers;
3352 }
3353
3354 /* Return nonzero if the virtual key is a dead key. */
3355
3356 static int
3357 is_dead_key (int wparam)
3358 {
3359 unsigned int code = MapVirtualKey (wparam, 2);
3360
3361 /* Windows 95 returns 0x8000, NT returns 0x80000000. */
3362 if ((code & 0x8000) || (code & 0x80000000))
3363 return 1;
3364 else
3365 return 0;
3366 }
3367
3368 /* Read events coming from the W32 shell.
3369 This routine is called by the SIGIO handler.
3370 We return as soon as there are no more events to be read.
3371
3372 Events representing keys are stored in buffer BUFP,
3373 which can hold up to NUMCHARS characters.
3374 We return the number of characters stored into the buffer,
3375 thus pretending to be `read'.
3376
3377 EXPECTED is nonzero if the caller knows input is available.
3378
3379 Some of these messages are reposted back to the message queue since the
3380 system calls the windows proc directly in a context where we cannot return
3381 the data nor can we guarantee the state we are in. So if we dispatch them
3382 we will get into an infinite loop. To prevent this from ever happening we
3383 will set a variable to indicate we are in the read_socket call and indicate
3384 which message we are processing since the windows proc gets called
3385 recursively with different messages by the system.
3386 */
3387
3388 int
3389 w32_read_socket (sd, bufp, numchars, expected)
3390 register int sd;
3391 register struct input_event *bufp;
3392 register int numchars;
3393 int expected;
3394 {
3395 int count = 0;
3396 int check_visibility = 0;
3397 W32Msg msg;
3398 struct frame *f;
3399 Lisp_Object part;
3400 struct w32_display_info *dpyinfo = &one_w32_display_info;
3401
3402 if (interrupt_input_blocked)
3403 {
3404 interrupt_input_pending = 1;
3405 return -1;
3406 }
3407
3408 interrupt_input_pending = 0;
3409 BLOCK_INPUT;
3410
3411 /* So people can tell when we have read the available input. */
3412 input_signal_count++;
3413
3414 if (numchars <= 0)
3415 abort (); /* Don't think this happens. */
3416
3417 while (get_next_msg (&msg, FALSE))
3418 {
3419 switch (msg.msg.message)
3420 {
3421 case WM_PAINT:
3422 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
3423
3424 if (f)
3425 {
3426 if (msg.rect.right == msg.rect.left ||
3427 msg.rect.bottom == msg.rect.top)
3428 {
3429 /* We may get paint messages even though the client
3430 area is clipped - these are not expose events. */
3431 DebPrint (("clipped frame %04x (%s) got WM_PAINT\n", f,
3432 XSTRING (f->name)->data));
3433 }
3434 else if (f->async_visible != 1)
3435 {
3436 /* Definitely not obscured, so mark as visible. */
3437 f->async_visible = 1;
3438 f->async_iconified = 0;
3439 SET_FRAME_GARBAGED (f);
3440 DebPrint (("frame %04x (%s) reexposed\n", f,
3441 XSTRING (f->name)->data));
3442
3443 /* WM_PAINT serves as MapNotify as well, so report
3444 visibility changes properly. */
3445 if (f->iconified)
3446 {
3447 bufp->kind = deiconify_event;
3448 XSETFRAME (bufp->frame_or_window, f);
3449 bufp++;
3450 count++;
3451 numchars--;
3452 }
3453 else if (! NILP(Vframe_list)
3454 && ! NILP (XCONS (Vframe_list)->cdr))
3455 /* Force a redisplay sooner or later to update the
3456 frame titles in case this is the second frame. */
3457 record_asynch_buffer_change ();
3458 }
3459 else
3460 {
3461 /* Erase background again for safety. */
3462 w32_clear_rect (f, NULL, &msg.rect);
3463 dumprectangle (f,
3464 msg.rect.left,
3465 msg.rect.top,
3466 msg.rect.right - msg.rect.left,
3467 msg.rect.bottom - msg.rect.top);
3468 }
3469 }
3470 break;
3471
3472 case WM_KEYDOWN:
3473 case WM_SYSKEYDOWN:
3474 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
3475
3476 if (f && !f->iconified)
3477 {
3478 if (temp_index == sizeof temp_buffer / sizeof (short))
3479 temp_index = 0;
3480 temp_buffer[temp_index++] = msg.msg.wParam;
3481 bufp->kind = non_ascii_keystroke;
3482 bufp->code = msg.msg.wParam;
3483 bufp->modifiers = w32_kbd_mods_to_emacs (msg.dwModifiers,
3484 msg.msg.wParam);
3485 XSETFRAME (bufp->frame_or_window, f);
3486 bufp->timestamp = msg.msg.time;
3487 bufp++;
3488 numchars--;
3489 count++;
3490 }
3491 break;
3492
3493 case WM_SYSCHAR:
3494 case WM_CHAR:
3495 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
3496
3497 if (f && !f->iconified)
3498 {
3499 if (numchars > 1)
3500 {
3501 int add;
3502 int isdead = 0;
3503 KEY_EVENT_RECORD key, *keyp = &key;
3504
3505 if (temp_index == sizeof temp_buffer / sizeof (short))
3506 temp_index = 0;
3507
3508 convert_to_key_event (&msg, keyp);
3509 add = key_event (keyp, bufp, &isdead);
3510 XSETFRAME (bufp->frame_or_window, f);
3511 if (add == -1)
3512 {
3513 /* The key pressed generated two characters, most likely
3514 an accent character and a key that could not be
3515 combined with it. Prepend the message on the queue
3516 again to process the second character (which is
3517 being held internally in key_event), and process
3518 the first character now. */
3519 prepend_msg (&msg);
3520 add = 1;
3521 }
3522
3523 if (isdead)
3524 break;
3525
3526 bufp += add;
3527 numchars -= add;
3528 count += add;
3529 }
3530 else
3531 {
3532 abort ();
3533 }
3534 }
3535 break;
3536
3537 case WM_MOUSEMOVE:
3538 if (dpyinfo->grabbed && last_mouse_frame
3539 && FRAME_LIVE_P (last_mouse_frame))
3540 f = last_mouse_frame;
3541 else
3542 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
3543
3544 if (f)
3545 note_mouse_movement (f, &msg.msg);
3546 else
3547 clear_mouse_face (FRAME_W32_DISPLAY_INFO (f));
3548
3549 break;
3550
3551 case WM_LBUTTONDOWN:
3552 case WM_LBUTTONUP:
3553 case WM_MBUTTONDOWN:
3554 case WM_MBUTTONUP:
3555 case WM_RBUTTONDOWN:
3556 case WM_RBUTTONUP:
3557 {
3558 int button;
3559 int up;
3560
3561 if (dpyinfo->grabbed && last_mouse_frame
3562 && FRAME_LIVE_P (last_mouse_frame))
3563 f = last_mouse_frame;
3564 else
3565 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
3566
3567 if (f)
3568 {
3569 if ((!dpyinfo->w32_focus_frame || f == dpyinfo->w32_focus_frame)
3570 && (numchars >= 1))
3571 {
3572 construct_mouse_click (bufp, &msg, f);
3573 bufp++;
3574 count++;
3575 numchars--;
3576 }
3577 }
3578
3579 parse_button (msg.msg.message, &button, &up);
3580
3581 if (up)
3582 {
3583 dpyinfo->grabbed &= ~ (1 << button);
3584 }
3585 else
3586 {
3587 dpyinfo->grabbed |= (1 << button);
3588 last_mouse_frame = f;
3589 }
3590 break;
3591 }
3592
3593 case WM_MOUSEWHEEL:
3594 if (dpyinfo->grabbed && last_mouse_frame
3595 && FRAME_LIVE_P (last_mouse_frame))
3596 f = last_mouse_frame;
3597 else
3598 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
3599
3600 if (f)
3601 {
3602 if ((!dpyinfo->w32_focus_frame
3603 || f == dpyinfo->w32_focus_frame)
3604 && (numchars >= 1))
3605 {
3606 construct_mouse_wheel (bufp, &msg, f);
3607 bufp++;
3608 count++;
3609 numchars--;
3610 }
3611 }
3612 break;
3613
3614 case WM_DROPFILES:
3615 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
3616
3617 if (f)
3618 {
3619 construct_drag_n_drop (bufp, &msg, f);
3620 bufp++;
3621 count++;
3622 numchars--;
3623 }
3624 break;
3625
3626 case WM_VSCROLL:
3627 {
3628 struct scroll_bar *bar =
3629 x_window_to_scroll_bar ((HWND)msg.msg.lParam);
3630
3631 if (bar && numchars >= 1)
3632 {
3633 if (x_scroll_bar_handle_click (bar, &msg, bufp))
3634 {
3635 bufp++;
3636 count++;
3637 numchars--;
3638 }
3639 }
3640 break;
3641 }
3642
3643 case WM_WINDOWPOSCHANGED:
3644 case WM_ACTIVATE:
3645 case WM_ACTIVATEAPP:
3646 check_visibility = 1;
3647 break;
3648
3649 case WM_MOVE:
3650 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
3651
3652 if (f && !f->async_iconified)
3653 {
3654 int x, y;
3655
3656 x_real_positions (f, &x, &y);
3657 f->output_data.w32->left_pos = x;
3658 f->output_data.w32->top_pos = y;
3659 }
3660
3661 check_visibility = 1;
3662 break;
3663
3664 case WM_SHOWWINDOW:
3665 /* If window has been obscured or exposed by another window
3666 being maximised or minimised/restored, then recheck
3667 visibility of all frames. Direct changes to our own
3668 windows get handled by WM_SIZE. */
3669 #if 0
3670 if (msg.msg.lParam != 0)
3671 check_visibility = 1;
3672 else
3673 {
3674 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
3675 f->async_visible = msg.msg.wParam;
3676 }
3677 #endif
3678
3679 check_visibility = 1;
3680 break;
3681
3682 case WM_SIZE:
3683 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
3684
3685 /* Inform lisp of whether frame has been iconified etc. */
3686 if (f)
3687 {
3688 switch (msg.msg.wParam)
3689 {
3690 case SIZE_MINIMIZED:
3691 f->async_visible = 0;
3692 f->async_iconified = 1;
3693
3694 bufp->kind = iconify_event;
3695 XSETFRAME (bufp->frame_or_window, f);
3696 bufp++;
3697 count++;
3698 numchars--;
3699 break;
3700
3701 case SIZE_MAXIMIZED:
3702 case SIZE_RESTORED:
3703 f->async_visible = 1;
3704 f->async_iconified = 0;
3705
3706 /* wait_reading_process_input will notice this and update
3707 the frame's display structures. */
3708 SET_FRAME_GARBAGED (f);
3709
3710 if (f->iconified)
3711 {
3712 bufp->kind = deiconify_event;
3713 XSETFRAME (bufp->frame_or_window, f);
3714 bufp++;
3715 count++;
3716 numchars--;
3717 }
3718 else
3719 /* Force a redisplay sooner or later
3720 to update the frame titles
3721 in case this is the second frame. */
3722 record_asynch_buffer_change ();
3723 break;
3724 }
3725 }
3726
3727 if (f && !f->async_iconified && msg.msg.wParam != SIZE_MINIMIZED)
3728 {
3729 RECT rect;
3730 int rows;
3731 int columns;
3732 int width;
3733 int height;
3734
3735 GetClientRect(msg.msg.hwnd, &rect);
3736
3737 height = rect.bottom - rect.top;
3738 width = rect.right - rect.left;
3739
3740 rows = PIXEL_TO_CHAR_HEIGHT (f, height);
3741 columns = PIXEL_TO_CHAR_WIDTH (f, width);
3742
3743 /* TODO: Clip size to the screen dimensions. */
3744
3745 /* Even if the number of character rows and columns has
3746 not changed, the font size may have changed, so we need
3747 to check the pixel dimensions as well. */
3748
3749 if (columns != f->width
3750 || rows != f->height
3751 || width != f->output_data.w32->pixel_width
3752 || height != f->output_data.w32->pixel_height)
3753 {
3754 /* I had set this to 0, 0 - I am not sure why?? */
3755
3756 change_frame_size (f, rows, columns, 0, 1);
3757 SET_FRAME_GARBAGED (f);
3758
3759 f->output_data.w32->pixel_width = width;
3760 f->output_data.w32->pixel_height = height;
3761 f->output_data.w32->win_gravity = NorthWestGravity;
3762 }
3763 }
3764
3765 check_visibility = 1;
3766 break;
3767
3768 case WM_SETFOCUS:
3769 case WM_KILLFOCUS:
3770 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
3771
3772 if (msg.msg.message == WM_SETFOCUS)
3773 {
3774 x_new_focus_frame (dpyinfo, f);
3775 }
3776 else if (f == dpyinfo->w32_focus_frame)
3777 {
3778 x_new_focus_frame (dpyinfo, 0);
3779 }
3780
3781 check_visibility = 1;
3782 break;
3783
3784 case WM_CLOSE:
3785 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
3786
3787 if (f)
3788 {
3789 if (numchars == 0)
3790 abort ();
3791
3792 bufp->kind = delete_window_event;
3793 XSETFRAME (bufp->frame_or_window, f);
3794 bufp++;
3795 count++;
3796 numchars--;
3797 }
3798 break;
3799
3800 case WM_INITMENU:
3801 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
3802
3803 if (f)
3804 {
3805 if (numchars == 0)
3806 abort ();
3807
3808 bufp->kind = menu_bar_activate_event;
3809 XSETFRAME (bufp->frame_or_window, f);
3810 bufp++;
3811 count++;
3812 numchars--;
3813 }
3814 break;
3815
3816 case WM_COMMAND:
3817 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
3818
3819 if (f)
3820 {
3821 extern void menubar_selection_callback (FRAME_PTR f, void * client_data);
3822 menubar_selection_callback (f, (void *)msg.msg.wParam);
3823 }
3824
3825 check_visibility = 1;
3826 break;
3827
3828 case WM_DISPLAYCHANGE:
3829 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
3830
3831 if (f)
3832 {
3833 dpyinfo->width = (short) LOWORD (msg.msg.lParam);
3834 dpyinfo->height = (short) HIWORD (msg.msg.lParam);
3835 dpyinfo->n_cbits = msg.msg.wParam;
3836 DebPrint (("display change: %d %d\n", dpyinfo->width,
3837 dpyinfo->height));
3838 }
3839
3840 check_visibility = 1;
3841 break;
3842
3843 default:
3844 /* Check for messages registered at runtime. */
3845 if (msg.msg.message == msh_mousewheel)
3846 {
3847 if (dpyinfo->grabbed && last_mouse_frame
3848 && FRAME_LIVE_P (last_mouse_frame))
3849 f = last_mouse_frame;
3850 else
3851 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
3852
3853 if (f)
3854 {
3855 if ((!dpyinfo->w32_focus_frame
3856 || f == dpyinfo->w32_focus_frame)
3857 && (numchars >= 1))
3858 {
3859 construct_mouse_wheel (bufp, &msg, f);
3860 bufp++;
3861 count++;
3862 numchars--;
3863 }
3864 }
3865 }
3866 break;
3867 }
3868 }
3869
3870 /* If the focus was just given to an autoraising frame,
3871 raise it now. */
3872 /* ??? This ought to be able to handle more than one such frame. */
3873 if (pending_autoraise_frame)
3874 {
3875 x_raise_frame (pending_autoraise_frame);
3876 pending_autoraise_frame = 0;
3877 }
3878
3879 /* Check which frames are still visisble, if we have enqueued any user
3880 events or been notified of events that may affect visibility. We
3881 do this here because there doesn't seem to be any direct
3882 notification from Windows that the visibility of a window has
3883 changed (at least, not in all cases). */
3884 if (count > 0 || check_visibility)
3885 {
3886 Lisp_Object tail, frame;
3887
3888 FOR_EACH_FRAME (tail, frame)
3889 {
3890 FRAME_PTR f = XFRAME (frame);
3891 /* Check "visible" frames and mark each as obscured or not.
3892 Note that async_visible is nonzero for unobscured and
3893 obscured frames, but zero for hidden and iconified frames. */
3894 if (FRAME_W32_P (f) && f->async_visible)
3895 {
3896 RECT clipbox;
3897 HDC hdc = get_frame_dc (f);
3898 GetClipBox (hdc, &clipbox);
3899 release_frame_dc (f, hdc);
3900
3901 if (clipbox.right == clipbox.left
3902 || clipbox.bottom == clipbox.top)
3903 {
3904 /* Frame has become completely obscured so mark as
3905 such (we do this by setting async_visible to 2 so
3906 that FRAME_VISIBLE_P is still true, but redisplay
3907 will skip it). */
3908 f->async_visible = 2;
3909
3910 if (!FRAME_OBSCURED_P (f))
3911 {
3912 DebPrint (("frame %04x (%s) obscured\n", f,
3913 XSTRING (f->name)->data));
3914 }
3915 }
3916 else
3917 {
3918 /* Frame is not obscured, so mark it as such. */
3919 f->async_visible = 1;
3920
3921 if (FRAME_OBSCURED_P (f))
3922 {
3923 SET_FRAME_GARBAGED (f);
3924 DebPrint (("frame %04x (%s) reexposed\n", f,
3925 XSTRING (f->name)->data));
3926
3927 /* Force a redisplay sooner or later. */
3928 record_asynch_buffer_change ();
3929 }
3930 }
3931 }
3932 }
3933 }
3934
3935 UNBLOCK_INPUT;
3936 return count;
3937 }
3938 \f
3939 /* Drawing the cursor. */
3940
3941
3942 /* Draw a hollow box cursor. Don't change the inside of the box. */
3943
3944 static void
3945 x_draw_box (f)
3946 struct frame *f;
3947 {
3948 RECT rect;
3949 HBRUSH hb;
3950 HDC hdc;
3951
3952 hdc = get_frame_dc (f);
3953
3954 hb = CreateSolidBrush (f->output_data.w32->cursor_pixel);
3955
3956 rect.left = CHAR_TO_PIXEL_COL (f, curs_x);
3957 rect.top = CHAR_TO_PIXEL_ROW (f, curs_y);
3958 rect.right = rect.left + FONT_WIDTH (f->output_data.w32->font);
3959 rect.bottom = rect.top + f->output_data.w32->line_height;
3960
3961 FrameRect (hdc, &rect, hb);
3962 DeleteObject (hb);
3963
3964 release_frame_dc (f, hdc);
3965 }
3966
3967 /* Clear the cursor of frame F to background color,
3968 and mark the cursor as not shown.
3969 This is used when the text where the cursor is
3970 is about to be rewritten. */
3971
3972 static void
3973 clear_cursor (f)
3974 struct frame *f;
3975 {
3976 if (! FRAME_VISIBLE_P (f)
3977 || f->phys_cursor_x < 0)
3978 return;
3979
3980 x_display_cursor (f, 0);
3981 f->phys_cursor_x = -1;
3982 }
3983
3984 /* Redraw the glyph at ROW, COLUMN on frame F, in the style
3985 HIGHLIGHT. HIGHLIGHT is as defined for dumpglyphs. Return the
3986 glyph drawn. */
3987
3988 static void
3989 x_draw_single_glyph (f, row, column, glyph, highlight)
3990 struct frame *f;
3991 int row, column;
3992 GLYPH glyph;
3993 int highlight;
3994 {
3995 dumpglyphs (f,
3996 CHAR_TO_PIXEL_COL (f, column),
3997 CHAR_TO_PIXEL_ROW (f, row),
3998 &glyph, 1, highlight, 0, NULL);
3999 }
4000
4001 static void
4002 x_display_bar_cursor (f, on)
4003 struct frame *f;
4004 int on;
4005 {
4006 struct frame_glyphs *current_glyphs = FRAME_CURRENT_GLYPHS (f);
4007
4008 /* This is pointless on invisible frames, and dangerous on garbaged
4009 frames; in the latter case, the frame may be in the midst of
4010 changing its size, and curs_x and curs_y may be off the frame. */
4011 if (! FRAME_VISIBLE_P (f) || FRAME_GARBAGED_P (f))
4012 return;
4013
4014 if (! on && f->phys_cursor_x < 0)
4015 return;
4016
4017 /* If there is anything wrong with the current cursor state, remove it. */
4018 if (f->phys_cursor_x >= 0
4019 && (!on
4020 || f->phys_cursor_x != curs_x
4021 || f->phys_cursor_y != curs_y
4022 || f->output_data.w32->current_cursor != bar_cursor))
4023 {
4024 /* Erase the cursor by redrawing the character underneath it. */
4025 x_draw_single_glyph (f, f->phys_cursor_y, f->phys_cursor_x,
4026 f->phys_cursor_glyph,
4027 current_glyphs->highlight[f->phys_cursor_y]);
4028 f->phys_cursor_x = -1;
4029 }
4030
4031 /* If we now need a cursor in the new place or in the new form, do it so. */
4032 if (on
4033 && (f->phys_cursor_x < 0
4034 || (f->output_data.w32->current_cursor != bar_cursor)))
4035 {
4036 f->phys_cursor_glyph
4037 = ((current_glyphs->enable[curs_y]
4038 && curs_x < current_glyphs->used[curs_y])
4039 ? current_glyphs->glyphs[curs_y][curs_x]
4040 : SPACEGLYPH);
4041 w32_fill_area (f, NULL, f->output_data.w32->cursor_pixel,
4042 CHAR_TO_PIXEL_COL (f, curs_x),
4043 CHAR_TO_PIXEL_ROW (f, curs_y),
4044 max (f->output_data.w32->cursor_width, 1),
4045 f->output_data.w32->line_height);
4046
4047 f->phys_cursor_x = curs_x;
4048 f->phys_cursor_y = curs_y;
4049
4050 f->output_data.w32->current_cursor = bar_cursor;
4051 }
4052 }
4053
4054
4055 /* Turn the displayed cursor of frame F on or off according to ON.
4056 If ON is nonzero, where to put the cursor is specified
4057 by F->cursor_x and F->cursor_y. */
4058
4059 static void
4060 x_display_box_cursor (f, on)
4061 struct frame *f;
4062 int on;
4063 {
4064 struct frame_glyphs *current_glyphs = FRAME_CURRENT_GLYPHS (f);
4065
4066 /* This is pointless on invisible frames, and dangerous on garbaged
4067 frames; in the latter case, the frame may be in the midst of
4068 changing its size, and curs_x and curs_y may be off the frame. */
4069 if (! FRAME_VISIBLE_P (f) || FRAME_GARBAGED_P (f))
4070 return;
4071
4072 /* If cursor is off and we want it off, return quickly. */
4073 if (!on && f->phys_cursor_x < 0)
4074 return;
4075
4076 /* If cursor is currently being shown and we don't want it to be
4077 or it is in the wrong place,
4078 or we want a hollow box and it's not so, (pout!)
4079 erase it. */
4080 if (f->phys_cursor_x >= 0
4081 && (!on
4082 || f->phys_cursor_x != curs_x
4083 || f->phys_cursor_y != curs_y
4084 || (f->output_data.w32->current_cursor != hollow_box_cursor
4085 && (f != FRAME_W32_DISPLAY_INFO (f)->w32_highlight_frame))))
4086 {
4087 int mouse_face_here = 0;
4088 struct frame_glyphs *active_glyphs = FRAME_CURRENT_GLYPHS (f);
4089
4090 /* If the cursor is in the mouse face area, redisplay that when
4091 we clear the cursor. */
4092 if (f == FRAME_W32_DISPLAY_INFO (f)->mouse_face_mouse_frame
4093 && (f->phys_cursor_y > FRAME_W32_DISPLAY_INFO (f)->mouse_face_beg_row
4094 || (f->phys_cursor_y == FRAME_W32_DISPLAY_INFO (f)->mouse_face_beg_row
4095 && f->phys_cursor_x >= FRAME_W32_DISPLAY_INFO (f)->mouse_face_beg_col))
4096 && (f->phys_cursor_y < FRAME_W32_DISPLAY_INFO (f)->mouse_face_end_row
4097 || (f->phys_cursor_y == FRAME_W32_DISPLAY_INFO (f)->mouse_face_end_row
4098 && f->phys_cursor_x < FRAME_W32_DISPLAY_INFO (f)->mouse_face_end_col))
4099 /* Don't redraw the cursor's spot in mouse face
4100 if it is at the end of a line (on a newline).
4101 The cursor appears there, but mouse highlighting does not. */
4102 && active_glyphs->used[f->phys_cursor_y] > f->phys_cursor_x)
4103 mouse_face_here = 1;
4104
4105 /* If the font is not as tall as a whole line,
4106 we must explicitly clear the line's whole height. */
4107 if (FONT_HEIGHT (f->output_data.w32->font) != f->output_data.w32->line_height)
4108 w32_clear_area (f, NULL,
4109 CHAR_TO_PIXEL_COL (f, f->phys_cursor_x),
4110 CHAR_TO_PIXEL_ROW (f, f->phys_cursor_y),
4111 FONT_WIDTH (f->output_data.w32->font),
4112 f->output_data.w32->line_height);
4113 /* Erase the cursor by redrawing the character underneath it. */
4114 x_draw_single_glyph (f, f->phys_cursor_y, f->phys_cursor_x,
4115 f->phys_cursor_glyph,
4116 (mouse_face_here
4117 ? 3
4118 : current_glyphs->highlight[f->phys_cursor_y]));
4119 f->phys_cursor_x = -1;
4120 }
4121
4122 /* If we want to show a cursor,
4123 or we want a box cursor and it's not so,
4124 write it in the right place. */
4125 if (on
4126 && (f->phys_cursor_x < 0
4127 || (f->output_data.w32->current_cursor != filled_box_cursor
4128 && f == FRAME_W32_DISPLAY_INFO (f)->w32_highlight_frame)))
4129 {
4130 f->phys_cursor_glyph
4131 = ((current_glyphs->enable[curs_y]
4132 && curs_x < current_glyphs->used[curs_y])
4133 ? current_glyphs->glyphs[curs_y][curs_x]
4134 : SPACEGLYPH);
4135 if (f != FRAME_W32_DISPLAY_INFO (f)->w32_highlight_frame)
4136 {
4137 x_draw_box (f);
4138 f->output_data.w32->current_cursor = hollow_box_cursor;
4139 }
4140 else
4141 {
4142 x_draw_single_glyph (f, curs_y, curs_x,
4143 f->phys_cursor_glyph, 2);
4144 f->output_data.w32->current_cursor = filled_box_cursor;
4145 }
4146
4147 f->phys_cursor_x = curs_x;
4148 f->phys_cursor_y = curs_y;
4149 }
4150 }
4151
4152 /* Display the cursor on frame F, or clear it, according to ON.
4153 Use the position specified by curs_x and curs_y
4154 if we are doing an update of frame F now.
4155 Otherwise use the position in the FRAME_CURSOR_X and FRAME_CURSOR_Y fields
4156 of F. */
4157
4158 x_display_cursor (f, on)
4159 struct frame *f;
4160 int on;
4161 {
4162 BLOCK_INPUT;
4163
4164 /* If we're not updating, then we want to use the current frame's
4165 cursor position, not our local idea of where the cursor ought to be. */
4166 if (f != updating_frame)
4167 {
4168 curs_x = FRAME_CURSOR_X (f);
4169 curs_y = FRAME_CURSOR_Y (f);
4170 }
4171
4172 if (FRAME_DESIRED_CURSOR (f) == filled_box_cursor)
4173 x_display_box_cursor (f, on);
4174 else if (FRAME_DESIRED_CURSOR (f) == bar_cursor)
4175 x_display_bar_cursor (f, on);
4176 else
4177 /* Those are the only two we have implemented! */
4178 abort ();
4179
4180 UNBLOCK_INPUT;
4181 }
4182 \f
4183 /* Changing the font of the frame. */
4184
4185 /* Give frame F the font named FONTNAME as its default font, and
4186 return the full name of that font. FONTNAME may be a wildcard
4187 pattern; in that case, we choose some font that fits the pattern.
4188 The return value shows which font we chose. */
4189
4190 Lisp_Object
4191 x_new_font (f, fontname)
4192 struct frame *f;
4193 register char *fontname;
4194 {
4195 struct font_info *fontp
4196 = fs_load_font (f, FRAME_W32_FONT_TABLE (f), CHARSET_ASCII,
4197 fontname, -1);
4198
4199 if (!fontp)
4200 return Qnil;
4201
4202 FRAME_FONT (f) = (XFontStruct *) (fontp->font);
4203 f->output_data.w32->font_baseline
4204 = FRAME_FONT(f)->tm.tmAscent + fontp->baseline_offset;
4205 FRAME_FONTSET (f) = -1;
4206
4207 /* Compute the scroll bar width in character columns. */
4208 if (f->scroll_bar_pixel_width > 0)
4209 {
4210 int wid = FONT_WIDTH (f->output_data.w32->font);
4211 f->scroll_bar_cols = (f->scroll_bar_pixel_width + wid-1) / wid;
4212 }
4213 else
4214 f->scroll_bar_cols = 2;
4215
4216 /* Now make the frame display the given font. */
4217 if (FRAME_W32_WINDOW (f) != 0)
4218 {
4219 frame_update_line_height (f);
4220 x_set_window_size (f, 0, f->width, f->height);
4221 }
4222 else
4223 /* If we are setting a new frame's font for the first time,
4224 there are no faces yet, so this font's height is the line height. */
4225 f->output_data.w32->line_height = FONT_HEIGHT (f->output_data.w32->font);
4226
4227 {
4228 Lisp_Object lispy_name;
4229
4230 lispy_name = build_string (fontname);
4231
4232 return lispy_name;
4233 }
4234 }
4235 \f
4236 /* Give frame F the fontset named FONTSETNAME as its default font, and
4237 return the full name of that fontset. FONTSETNAME may be a wildcard
4238 pattern; in that case, we choose some fontset that fits the pattern.
4239 The return value shows which fontset we chose. */
4240
4241 Lisp_Object
4242 x_new_fontset (f, fontsetname)
4243 struct frame *f;
4244 char *fontsetname;
4245 {
4246 int fontset = fs_query_fontset (f, fontsetname);
4247 struct fontset_info *fontsetp;
4248 Lisp_Object result;
4249
4250 if (fontset < 0)
4251 return Qnil;
4252
4253 if (FRAME_FONTSET (f) == fontset)
4254 /* This fontset is already set in frame F. There's nothing more
4255 to do. */
4256 return build_string (fontsetname);
4257
4258 fontsetp = FRAME_FONTSET_DATA (f)->fontset_table[fontset];
4259
4260 if (!fontsetp->fontname[CHARSET_ASCII])
4261 /* This fontset doesn't contain ASCII font. */
4262 return Qnil;
4263
4264 result = x_new_font (f, fontsetp->fontname[CHARSET_ASCII]);
4265
4266 if (!STRINGP (result))
4267 /* Can't load ASCII font. */
4268 return Qnil;
4269
4270 /* Since x_new_font doesn't update any fontset information, do it now. */
4271 FRAME_FONTSET(f) = fontset;
4272 FS_LOAD_FONT (f, FRAME_W32_FONT_TABLE (f),
4273 CHARSET_ASCII, XSTRING (result)->data, fontset);
4274
4275 return build_string (fontsetname);
4276 }
4277 \f
4278 /* Calculate the absolute position in frame F
4279 from its current recorded position values and gravity. */
4280
4281 x_calc_absolute_position (f)
4282 struct frame *f;
4283 {
4284 Window win, child;
4285 POINT pt;
4286 int flags = f->output_data.w32->size_hint_flags;
4287
4288 pt.x = pt.y = 0;
4289
4290 /* Find the position of the outside upper-left corner of
4291 the inner window, with respect to the outer window. */
4292 if (f->output_data.w32->parent_desc != FRAME_W32_DISPLAY_INFO (f)->root_window)
4293 {
4294 BLOCK_INPUT;
4295 MapWindowPoints (FRAME_W32_WINDOW (f),
4296 f->output_data.w32->parent_desc,
4297 &pt, 1);
4298 UNBLOCK_INPUT;
4299 }
4300
4301 {
4302 RECT rt;
4303 rt.left = rt.right = rt.top = rt.bottom = 0;
4304
4305 BLOCK_INPUT;
4306 AdjustWindowRect(&rt, f->output_data.w32->dwStyle,
4307 FRAME_EXTERNAL_MENU_BAR (f));
4308 UNBLOCK_INPUT;
4309
4310 pt.x += (rt.right - rt.left);
4311 pt.y += (rt.bottom - rt.top);
4312 }
4313
4314 /* Treat negative positions as relative to the leftmost bottommost
4315 position that fits on the screen. */
4316 if (flags & XNegative)
4317 f->output_data.w32->left_pos = (FRAME_W32_DISPLAY_INFO (f)->width
4318 - 2 * f->output_data.w32->border_width - pt.x
4319 - PIXEL_WIDTH (f)
4320 + f->output_data.w32->left_pos);
4321
4322 if (flags & YNegative)
4323 f->output_data.w32->top_pos = (FRAME_W32_DISPLAY_INFO (f)->height
4324 - 2 * f->output_data.w32->border_width - pt.y
4325 - PIXEL_HEIGHT (f)
4326 + f->output_data.w32->top_pos);
4327 /* The left_pos and top_pos
4328 are now relative to the top and left screen edges,
4329 so the flags should correspond. */
4330 f->output_data.w32->size_hint_flags &= ~ (XNegative | YNegative);
4331 }
4332
4333 /* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
4334 to really change the position, and 0 when calling from
4335 x_make_frame_visible (in that case, XOFF and YOFF are the current
4336 position values). It is -1 when calling from x_set_frame_parameters,
4337 which means, do adjust for borders but don't change the gravity. */
4338
4339 x_set_offset (f, xoff, yoff, change_gravity)
4340 struct frame *f;
4341 register int xoff, yoff;
4342 int change_gravity;
4343 {
4344 int modified_top, modified_left;
4345
4346 if (change_gravity > 0)
4347 {
4348 f->output_data.w32->top_pos = yoff;
4349 f->output_data.w32->left_pos = xoff;
4350 f->output_data.w32->size_hint_flags &= ~ (XNegative | YNegative);
4351 if (xoff < 0)
4352 f->output_data.w32->size_hint_flags |= XNegative;
4353 if (yoff < 0)
4354 f->output_data.w32->size_hint_flags |= YNegative;
4355 f->output_data.w32->win_gravity = NorthWestGravity;
4356 }
4357 x_calc_absolute_position (f);
4358
4359 BLOCK_INPUT;
4360 x_wm_set_size_hint (f, (long) 0, 0);
4361
4362 /* It is a mystery why we need to add the border_width here
4363 when the frame is already visible, but experiment says we do. */
4364 modified_left = f->output_data.w32->left_pos;
4365 modified_top = f->output_data.w32->top_pos;
4366 #ifndef HAVE_NTGUI
4367 /* Do not add in border widths under W32. */
4368 if (change_gravity != 0)
4369 {
4370 modified_left += f->output_data.w32->border_width;
4371 modified_top += f->output_data.w32->border_width;
4372 }
4373 #endif
4374
4375 my_set_window_pos (FRAME_W32_WINDOW (f),
4376 NULL,
4377 modified_left, modified_top,
4378 0, 0,
4379 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
4380 UNBLOCK_INPUT;
4381 }
4382
4383 /* Call this to change the size of frame F's x-window.
4384 If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
4385 for this size change and subsequent size changes.
4386 Otherwise we leave the window gravity unchanged. */
4387
4388 x_set_window_size (f, change_gravity, cols, rows)
4389 struct frame *f;
4390 int change_gravity;
4391 int cols, rows;
4392 {
4393 int pixelwidth, pixelheight;
4394 Lisp_Object window;
4395 struct w32_display_info *dpyinfo = &one_w32_display_info;
4396
4397 BLOCK_INPUT;
4398
4399 check_frame_size (f, &rows, &cols);
4400 f->output_data.w32->vertical_scroll_bar_extra
4401 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
4402 ? 0
4403 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
4404 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
4405 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.w32->font)));
4406 pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols);
4407 pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows);
4408
4409 f->output_data.w32->win_gravity = NorthWestGravity;
4410 x_wm_set_size_hint (f, (long) 0, 0);
4411
4412 {
4413 RECT rect;
4414
4415 rect.left = rect.top = 0;
4416 rect.right = pixelwidth;
4417 rect.bottom = pixelheight;
4418
4419 AdjustWindowRect(&rect, f->output_data.w32->dwStyle,
4420 FRAME_EXTERNAL_MENU_BAR (f));
4421
4422 my_set_window_pos (FRAME_W32_WINDOW (f),
4423 NULL,
4424 0, 0,
4425 rect.right - rect.left,
4426 rect.bottom - rect.top,
4427 SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
4428 }
4429
4430 /* Now, strictly speaking, we can't be sure that this is accurate,
4431 but the window manager will get around to dealing with the size
4432 change request eventually, and we'll hear how it went when the
4433 ConfigureNotify event gets here.
4434
4435 We could just not bother storing any of this information here,
4436 and let the ConfigureNotify event set everything up, but that
4437 might be kind of confusing to the lisp code, since size changes
4438 wouldn't be reported in the frame parameters until some random
4439 point in the future when the ConfigureNotify event arrives. */
4440 change_frame_size (f, rows, cols, 0, 0);
4441 PIXEL_WIDTH (f) = pixelwidth;
4442 PIXEL_HEIGHT (f) = pixelheight;
4443
4444 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
4445 receive in the ConfigureNotify event; if we get what we asked
4446 for, then the event won't cause the screen to become garbaged, so
4447 we have to make sure to do it here. */
4448 SET_FRAME_GARBAGED (f);
4449
4450 /* If cursor was outside the new size, mark it as off. */
4451 if (f->phys_cursor_y >= rows
4452 || f->phys_cursor_x >= cols)
4453 {
4454 f->phys_cursor_x = -1;
4455 f->phys_cursor_y = -1;
4456 }
4457
4458 /* Clear out any recollection of where the mouse highlighting was,
4459 since it might be in a place that's outside the new frame size.
4460 Actually checking whether it is outside is a pain in the neck,
4461 so don't try--just let the highlighting be done afresh with new size. */
4462 window = dpyinfo->mouse_face_window;
4463 if (! NILP (window) && XFRAME (window) == f)
4464 {
4465 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
4466 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
4467 dpyinfo->mouse_face_window = Qnil;
4468 }
4469
4470 UNBLOCK_INPUT;
4471 }
4472 \f
4473 /* Mouse warping. */
4474
4475 void
4476 x_set_mouse_pixel_position (f, pix_x, pix_y)
4477 struct frame *f;
4478 int pix_x, pix_y;
4479 {
4480 RECT rect;
4481 POINT pt;
4482
4483 BLOCK_INPUT;
4484
4485 GetClientRect (FRAME_W32_WINDOW (f), &rect);
4486 pt.x = rect.left + pix_x;
4487 pt.y = rect.top + pix_y;
4488 ClientToScreen (FRAME_W32_WINDOW (f), &pt);
4489
4490 SetCursorPos (pt.x, pt.y);
4491
4492 UNBLOCK_INPUT;
4493 }
4494
4495 void
4496 x_set_mouse_position (f, x, y)
4497 struct frame *f;
4498 int x, y;
4499 {
4500 int pix_x, pix_y;
4501
4502 pix_x = CHAR_TO_PIXEL_COL (f, x) + FONT_WIDTH (f->output_data.w32->font) / 2;
4503 pix_y = CHAR_TO_PIXEL_ROW (f, y) + f->output_data.w32->line_height / 2;
4504
4505 if (pix_x < 0) pix_x = 0;
4506 if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f);
4507
4508 if (pix_y < 0) pix_y = 0;
4509 if (pix_y > PIXEL_HEIGHT (f)) pix_y = PIXEL_HEIGHT (f);
4510
4511 x_set_mouse_pixel_position (f, pix_x, pix_y);
4512 }
4513 \f
4514 /* focus shifting, raising and lowering. */
4515
4516 x_focus_on_frame (f)
4517 struct frame *f;
4518 {
4519 struct w32_display_info *dpyinfo = &one_w32_display_info;
4520
4521 /* Give input focus to frame. */
4522 BLOCK_INPUT;
4523 #if 0
4524 /* Try not to change its Z-order if possible. */
4525 if (x_window_to_frame (dpyinfo, GetForegroundWindow ()))
4526 my_set_focus (f, FRAME_W32_WINDOW (f));
4527 else
4528 #endif
4529 my_set_foreground_window (FRAME_W32_WINDOW (f));
4530 UNBLOCK_INPUT;
4531 }
4532
4533 x_unfocus_frame (f)
4534 struct frame *f;
4535 {
4536 }
4537
4538 /* Raise frame F. */
4539
4540 x_raise_frame (f)
4541 struct frame *f;
4542 {
4543 BLOCK_INPUT;
4544
4545 /* Strictly speaking, raise-frame should only change the frame's Z
4546 order, leaving input focus unchanged. This is reasonable behaviour
4547 on X where the usual policy is point-to-focus. However, this
4548 behaviour would be very odd on Windows where the usual policy is
4549 click-to-focus.
4550
4551 On X, if the mouse happens to be over the raised frame, it gets
4552 input focus anyway (so the window with focus will never be
4553 completely obscured) - if not, then just moving the mouse over it
4554 is sufficient to give it focus. On Windows, the user must actually
4555 click on the frame (preferrably the title bar so as not to move
4556 point), which is more awkward. Also, no other Windows program
4557 raises a window to the top but leaves another window (possibly now
4558 completely obscured) with input focus.
4559
4560 Because there is a system setting on Windows that allows the user
4561 to choose the point to focus policy, we make the strict semantics
4562 optional, but by default we grab focus when raising. */
4563
4564 if (NILP (Vw32_grab_focus_on_raise))
4565 {
4566 /* The obvious call to my_set_window_pos doesn't work if Emacs is
4567 not already the foreground application: the frame is raised
4568 above all other frames belonging to us, but not above the
4569 current top window. To achieve that, we have to resort to this
4570 more cumbersome method. */
4571
4572 HDWP handle = BeginDeferWindowPos (2);
4573 if (handle)
4574 {
4575 DeferWindowPos (handle,
4576 FRAME_W32_WINDOW (f),
4577 HWND_TOP,
4578 0, 0, 0, 0,
4579 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
4580
4581 DeferWindowPos (handle,
4582 GetForegroundWindow (),
4583 FRAME_W32_WINDOW (f),
4584 0, 0, 0, 0,
4585 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
4586
4587 EndDeferWindowPos (handle);
4588 }
4589 }
4590 else
4591 {
4592 my_set_foreground_window (FRAME_W32_WINDOW (f));
4593 }
4594
4595 UNBLOCK_INPUT;
4596 }
4597
4598 /* Lower frame F. */
4599
4600 x_lower_frame (f)
4601 struct frame *f;
4602 {
4603 BLOCK_INPUT;
4604 my_set_window_pos (FRAME_W32_WINDOW (f),
4605 HWND_BOTTOM,
4606 0, 0, 0, 0,
4607 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
4608 UNBLOCK_INPUT;
4609 }
4610
4611 static void
4612 w32_frame_raise_lower (f, raise)
4613 FRAME_PTR f;
4614 int raise;
4615 {
4616 if (raise)
4617 x_raise_frame (f);
4618 else
4619 x_lower_frame (f);
4620 }
4621 \f
4622 /* Change of visibility. */
4623
4624 /* This tries to wait until the frame is really visible.
4625 However, if the window manager asks the user where to position
4626 the frame, this will return before the user finishes doing that.
4627 The frame will not actually be visible at that time,
4628 but it will become visible later when the window manager
4629 finishes with it. */
4630
4631 x_make_frame_visible (f)
4632 struct frame *f;
4633 {
4634 BLOCK_INPUT;
4635
4636 if (! FRAME_VISIBLE_P (f))
4637 {
4638 /* We test FRAME_GARBAGED_P here to make sure we don't
4639 call x_set_offset a second time
4640 if we get to x_make_frame_visible a second time
4641 before the window gets really visible. */
4642 if (! FRAME_ICONIFIED_P (f)
4643 && ! f->output_data.w32->asked_for_visible)
4644 x_set_offset (f, f->output_data.w32->left_pos, f->output_data.w32->top_pos, 0);
4645
4646 f->output_data.w32->asked_for_visible = 1;
4647
4648 // my_show_window (f, FRAME_W32_WINDOW (f), f->async_iconified ? SW_RESTORE : SW_SHOW);
4649 my_show_window (f, FRAME_W32_WINDOW (f), SW_SHOWNORMAL);
4650 }
4651
4652 /* Synchronize to ensure Emacs knows the frame is visible
4653 before we do anything else. We do this loop with input not blocked
4654 so that incoming events are handled. */
4655 {
4656 Lisp_Object frame;
4657 int count = input_signal_count;
4658
4659 /* This must come after we set COUNT. */
4660 UNBLOCK_INPUT;
4661
4662 XSETFRAME (frame, f);
4663
4664 while (1)
4665 {
4666 /* Once we have handled input events,
4667 we should have received the MapNotify if one is coming.
4668 So if we have not got it yet, stop looping.
4669 Some window managers make their own decisions
4670 about visibility. */
4671 if (input_signal_count != count)
4672 break;
4673 /* Machines that do polling rather than SIGIO have been observed
4674 to go into a busy-wait here. So we'll fake an alarm signal
4675 to let the handler know that there's something to be read.
4676 We used to raise a real alarm, but it seems that the handler
4677 isn't always enabled here. This is probably a bug. */
4678 if (input_polling_used ())
4679 {
4680 /* It could be confusing if a real alarm arrives while processing
4681 the fake one. Turn it off and let the handler reset it. */
4682 alarm (0);
4683 input_poll_signal (0);
4684 }
4685 /* Once we have handled input events,
4686 we should have received the MapNotify if one is coming.
4687 So if we have not got it yet, stop looping.
4688 Some window managers make their own decisions
4689 about visibility. */
4690 if (input_signal_count != count)
4691 break;
4692 }
4693 FRAME_SAMPLE_VISIBILITY (f);
4694 }
4695 }
4696
4697 /* Change from mapped state to withdrawn state. */
4698
4699 /* Make the frame visible (mapped and not iconified). */
4700
4701 x_make_frame_invisible (f)
4702 struct frame *f;
4703 {
4704 Window window;
4705
4706 /* Don't keep the highlight on an invisible frame. */
4707 if (FRAME_W32_DISPLAY_INFO (f)->w32_highlight_frame == f)
4708 FRAME_W32_DISPLAY_INFO (f)->w32_highlight_frame = 0;
4709
4710 BLOCK_INPUT;
4711
4712 my_show_window (f, FRAME_W32_WINDOW (f), SW_HIDE);
4713
4714 /* We can't distinguish this from iconification
4715 just by the event that we get from the server.
4716 So we can't win using the usual strategy of letting
4717 FRAME_SAMPLE_VISIBILITY set this. So do it by hand,
4718 and synchronize with the server to make sure we agree. */
4719 f->visible = 0;
4720 FRAME_ICONIFIED_P (f) = 0;
4721 f->async_visible = 0;
4722 f->async_iconified = 0;
4723
4724 UNBLOCK_INPUT;
4725 }
4726
4727 /* Change window state from mapped to iconified. */
4728
4729 void
4730 x_iconify_frame (f)
4731 struct frame *f;
4732 {
4733 int result;
4734
4735 /* Don't keep the highlight on an invisible frame. */
4736 if (FRAME_W32_DISPLAY_INFO (f)->w32_highlight_frame == f)
4737 FRAME_W32_DISPLAY_INFO (f)->w32_highlight_frame = 0;
4738
4739 if (f->async_iconified)
4740 return;
4741
4742 BLOCK_INPUT;
4743
4744 /* Simulate the user minimizing the frame. */
4745 PostMessage (FRAME_W32_WINDOW (f), WM_SYSCOMMAND, SC_MINIMIZE, 0);
4746
4747 f->async_iconified = 1;
4748
4749 UNBLOCK_INPUT;
4750 }
4751 \f
4752 /* Destroy the window of frame F. */
4753
4754 x_destroy_window (f)
4755 struct frame *f;
4756 {
4757 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
4758
4759 BLOCK_INPUT;
4760
4761 my_destroy_window (f, FRAME_W32_WINDOW (f));
4762 free_frame_menubar (f);
4763 free_frame_faces (f);
4764
4765 xfree (f->output_data.w32);
4766 f->output_data.w32 = 0;
4767 if (f == dpyinfo->w32_focus_frame)
4768 dpyinfo->w32_focus_frame = 0;
4769 if (f == dpyinfo->w32_focus_event_frame)
4770 dpyinfo->w32_focus_event_frame = 0;
4771 if (f == dpyinfo->w32_highlight_frame)
4772 dpyinfo->w32_highlight_frame = 0;
4773
4774 dpyinfo->reference_count--;
4775
4776 if (f == dpyinfo->mouse_face_mouse_frame)
4777 {
4778 dpyinfo->mouse_face_beg_row
4779 = dpyinfo->mouse_face_beg_col = -1;
4780 dpyinfo->mouse_face_end_row
4781 = dpyinfo->mouse_face_end_col = -1;
4782 dpyinfo->mouse_face_window = Qnil;
4783 }
4784
4785 UNBLOCK_INPUT;
4786 }
4787 \f
4788 /* Setting window manager hints. */
4789
4790 /* Set the normal size hints for the window manager, for frame F.
4791 FLAGS is the flags word to use--or 0 meaning preserve the flags
4792 that the window now has.
4793 If USER_POSITION is nonzero, we set the USPosition
4794 flag (this is useful when FLAGS is 0). */
4795
4796 x_wm_set_size_hint (f, flags, user_position)
4797 struct frame *f;
4798 long flags;
4799 int user_position;
4800 {
4801 Window window = FRAME_W32_WINDOW (f);
4802
4803 flexlines = f->height;
4804
4805 enter_crit ();
4806
4807 SetWindowLong (window, WND_FONTWIDTH_INDEX, FONT_WIDTH (f->output_data.w32->font));
4808 SetWindowLong (window, WND_LINEHEIGHT_INDEX, f->output_data.w32->line_height);
4809 SetWindowLong (window, WND_BORDER_INDEX, f->output_data.w32->internal_border_width);
4810 SetWindowLong (window, WND_SCROLLBAR_INDEX, f->output_data.w32->vertical_scroll_bar_extra);
4811
4812 leave_crit ();
4813 }
4814
4815 /* Window manager things */
4816 x_wm_set_icon_position (f, icon_x, icon_y)
4817 struct frame *f;
4818 int icon_x, icon_y;
4819 {
4820 #if 0
4821 Window window = FRAME_W32_WINDOW (f);
4822
4823 f->display.x->wm_hints.flags |= IconPositionHint;
4824 f->display.x->wm_hints.icon_x = icon_x;
4825 f->display.x->wm_hints.icon_y = icon_y;
4826
4827 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->display.x->wm_hints);
4828 #endif
4829 }
4830
4831 \f
4832 /* Initialization. */
4833
4834 #ifdef USE_X_TOOLKIT
4835 static XrmOptionDescRec emacs_options[] = {
4836 {"-geometry", ".geometry", XrmoptionSepArg, NULL},
4837 {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"},
4838
4839 {"-internal-border-width", "*EmacsScreen.internalBorderWidth",
4840 XrmoptionSepArg, NULL},
4841 {"-ib", "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL},
4842
4843 {"-T", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
4844 {"-wn", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
4845 {"-title", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
4846 {"-iconname", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
4847 {"-in", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
4848 {"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL},
4849 {"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL}
4850 };
4851 #endif /* USE_X_TOOLKIT */
4852
4853 static int w32_initialized = 0;
4854
4855 struct w32_display_info *
4856 w32_term_init (display_name, xrm_option, resource_name)
4857 Lisp_Object display_name;
4858 char *xrm_option;
4859 char *resource_name;
4860 {
4861 Lisp_Object frame;
4862 char *defaultvalue;
4863 struct w32_display_info *dpyinfo;
4864 HDC hdc;
4865
4866 BLOCK_INPUT;
4867
4868 if (!w32_initialized)
4869 {
4870 w32_initialize ();
4871 w32_initialized = 1;
4872 }
4873
4874 {
4875 int argc = 0;
4876 char *argv[3];
4877
4878 argv[0] = "";
4879 argc = 1;
4880 if (xrm_option)
4881 {
4882 argv[argc++] = "-xrm";
4883 argv[argc++] = xrm_option;
4884 }
4885 }
4886
4887 dpyinfo = &one_w32_display_info;
4888
4889 /* Put this display on the chain. */
4890 dpyinfo->next = NULL;
4891
4892 /* Put it on w32_display_name_list as well, to keep them parallel. */
4893 w32_display_name_list = Fcons (Fcons (display_name, Qnil),
4894 w32_display_name_list);
4895 dpyinfo->name_list_element = XCONS (w32_display_name_list)->car;
4896
4897 dpyinfo->w32_id_name
4898 = (char *) xmalloc (XSTRING (Vinvocation_name)->size
4899 + XSTRING (Vsystem_name)->size
4900 + 2);
4901 sprintf (dpyinfo->w32_id_name, "%s@%s",
4902 XSTRING (Vinvocation_name)->data, XSTRING (Vsystem_name)->data);
4903
4904 #if 0
4905 xrdb = x_load_resources (dpyinfo->display, xrm_option,
4906 resource_name, EMACS_CLASS);
4907
4908 /* Put the rdb where we can find it in a way that works on
4909 all versions. */
4910 dpyinfo->xrdb = xrdb;
4911 #endif
4912 hdc = GetDC (GetDesktopWindow ());
4913
4914 dpyinfo->height = GetDeviceCaps (hdc, VERTRES);
4915 dpyinfo->width = GetDeviceCaps (hdc, HORZRES);
4916 dpyinfo->root_window = GetDesktopWindow ();
4917 dpyinfo->n_planes = GetDeviceCaps (hdc, PLANES);
4918 dpyinfo->n_cbits = GetDeviceCaps (hdc, BITSPIXEL);
4919 dpyinfo->height_in = GetDeviceCaps (hdc, LOGPIXELSX);
4920 dpyinfo->width_in = GetDeviceCaps (hdc, LOGPIXELSY);
4921 dpyinfo->has_palette = GetDeviceCaps (hdc, RASTERCAPS) & RC_PALETTE;
4922 dpyinfo->grabbed = 0;
4923 dpyinfo->reference_count = 0;
4924 dpyinfo->n_fonts = 0;
4925 dpyinfo->font_table_size = 0;
4926 dpyinfo->bitmaps = 0;
4927 dpyinfo->bitmaps_size = 0;
4928 dpyinfo->bitmaps_last = 0;
4929 dpyinfo->mouse_face_mouse_frame = 0;
4930 dpyinfo->mouse_face_deferred_gc = 0;
4931 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
4932 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
4933 dpyinfo->mouse_face_face_id = 0;
4934 dpyinfo->mouse_face_window = Qnil;
4935 dpyinfo->mouse_face_mouse_x = dpyinfo->mouse_face_mouse_y = 0;
4936 dpyinfo->mouse_face_defer = 0;
4937 dpyinfo->w32_focus_frame = 0;
4938 dpyinfo->w32_focus_event_frame = 0;
4939 dpyinfo->w32_highlight_frame = 0;
4940
4941 ReleaseDC (GetDesktopWindow (), hdc);
4942
4943 /* Determine if there is a middle mouse button, to allow parse_button
4944 to decide whether right mouse events should be mouse-2 or
4945 mouse-3. */
4946 XSETINT (Vw32_num_mouse_buttons, GetSystemMetrics (SM_CMOUSEBUTTONS));
4947
4948 /* initialise palette with white and black */
4949 {
4950 COLORREF color;
4951 defined_color (0, "white", &color, 1);
4952 defined_color (0, "black", &color, 1);
4953 }
4954
4955 #ifndef F_SETOWN_BUG
4956 #ifdef F_SETOWN
4957 #ifdef F_SETOWN_SOCK_NEG
4958 /* stdin is a socket here */
4959 fcntl (connection, F_SETOWN, -getpid ());
4960 #else /* ! defined (F_SETOWN_SOCK_NEG) */
4961 fcntl (connection, F_SETOWN, getpid ());
4962 #endif /* ! defined (F_SETOWN_SOCK_NEG) */
4963 #endif /* ! defined (F_SETOWN) */
4964 #endif /* F_SETOWN_BUG */
4965
4966 #ifdef SIGIO
4967 if (interrupt_input)
4968 init_sigio (connection);
4969 #endif /* ! defined (SIGIO) */
4970
4971 UNBLOCK_INPUT;
4972
4973 return dpyinfo;
4974 }
4975 \f
4976 /* Get rid of display DPYINFO, assuming all frames are already gone. */
4977
4978 void
4979 x_delete_display (dpyinfo)
4980 struct w32_display_info *dpyinfo;
4981 {
4982 /* Discard this display from w32_display_name_list and w32_display_list.
4983 We can't use Fdelq because that can quit. */
4984 if (! NILP (w32_display_name_list)
4985 && EQ (XCONS (w32_display_name_list)->car, dpyinfo->name_list_element))
4986 w32_display_name_list = XCONS (w32_display_name_list)->cdr;
4987 else
4988 {
4989 Lisp_Object tail;
4990
4991 tail = w32_display_name_list;
4992 while (CONSP (tail) && CONSP (XCONS (tail)->cdr))
4993 {
4994 if (EQ (XCONS (XCONS (tail)->cdr)->car,
4995 dpyinfo->name_list_element))
4996 {
4997 XCONS (tail)->cdr = XCONS (XCONS (tail)->cdr)->cdr;
4998 break;
4999 }
5000 tail = XCONS (tail)->cdr;
5001 }
5002 }
5003
5004 /* free palette table */
5005 {
5006 struct w32_palette_entry * plist;
5007
5008 plist = dpyinfo->color_list;
5009 while (plist)
5010 {
5011 struct w32_palette_entry * pentry = plist;
5012 plist = plist->next;
5013 xfree(pentry);
5014 }
5015 dpyinfo->color_list = NULL;
5016 if (dpyinfo->palette)
5017 DeleteObject(dpyinfo->palette);
5018 }
5019 xfree (dpyinfo->font_table);
5020 xfree (dpyinfo->w32_id_name);
5021 }
5022 \f
5023 /* Set up use of W32. */
5024
5025 DWORD w32_msg_worker ();
5026
5027 w32_initialize ()
5028 {
5029 /* MSVC does not type K&R functions with no arguments correctly, and
5030 so we must explicitly cast them. */
5031 clear_frame_hook = (void (*)(void)) w32_clear_frame;
5032 clear_end_of_line_hook = w32_clear_end_of_line;
5033 ins_del_lines_hook = w32_ins_del_lines;
5034 change_line_highlight_hook = w32_change_line_highlight;
5035 insert_glyphs_hook = w32_insert_glyphs;
5036 write_glyphs_hook = w32_write_glyphs;
5037 delete_glyphs_hook = w32_delete_glyphs;
5038 ring_bell_hook = (void (*)(void)) w32_ring_bell;
5039 reset_terminal_modes_hook = (void (*)(void)) w32_reset_terminal_modes;
5040 set_terminal_modes_hook = (void (*)(void)) w32_set_terminal_modes;
5041 update_begin_hook = w32_update_begin;
5042 update_end_hook = w32_update_end;
5043 set_terminal_window_hook = w32_set_terminal_window;
5044 read_socket_hook = w32_read_socket;
5045 frame_up_to_date_hook = w32_frame_up_to_date;
5046 cursor_to_hook = w32_cursor_to;
5047 reassert_line_highlight_hook = w32_reassert_line_highlight;
5048 mouse_position_hook = w32_mouse_position;
5049 frame_rehighlight_hook = w32_frame_rehighlight;
5050 frame_raise_lower_hook = w32_frame_raise_lower;
5051 set_vertical_scroll_bar_hook = w32_set_vertical_scroll_bar;
5052 condemn_scroll_bars_hook = w32_condemn_scroll_bars;
5053 redeem_scroll_bar_hook = w32_redeem_scroll_bar;
5054 judge_scroll_bars_hook = w32_judge_scroll_bars;
5055
5056 scroll_region_ok = 1; /* we'll scroll partial frames */
5057 char_ins_del_ok = 0; /* just as fast to write the line */
5058 line_ins_del_ok = 1; /* we'll just blt 'em */
5059 fast_clear_end_of_line = 1; /* X does this well */
5060 memory_below_frame = 0; /* we don't remember what scrolls
5061 off the bottom */
5062 baud_rate = 19200;
5063
5064 /* Initialize input mode: interrupt_input off, no flow control, allow
5065 8 bit character input, standard quit char. */
5066 Fset_input_mode (Qnil, Qnil, make_number (2), Qnil);
5067
5068 /* Create the window thread - it will terminate itself or when the app terminates */
5069
5070 init_crit ();
5071
5072 dwMainThreadId = GetCurrentThreadId ();
5073 DuplicateHandle (GetCurrentProcess (), GetCurrentThread (),
5074 GetCurrentProcess (), &hMainThread, 0, TRUE, DUPLICATE_SAME_ACCESS);
5075
5076 /* Wait for thread to start */
5077
5078 {
5079 MSG msg;
5080
5081 PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
5082
5083 hWindowsThread = CreateThread (NULL, 0,
5084 (LPTHREAD_START_ROUTINE) w32_msg_worker,
5085 0, 0, &dwWindowsThreadId);
5086
5087 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
5088 }
5089
5090 /* It is desirable that mainThread should have the same notion of
5091 focus window and active window as windowsThread. Unfortunately, the
5092 following call to AttachThreadInput, which should do precisely what
5093 we need, causes major problems when Emacs is linked as a console
5094 program. Unfortunately, we have good reasons for doing that, so
5095 instead we need to send messages to windowsThread to make some API
5096 calls for us (ones that affect, or depend on, the active/focus
5097 window state. */
5098 #ifdef ATTACH_THREADS
5099 AttachThreadInput (dwMainThreadId, dwWindowsThreadId, TRUE);
5100 #endif
5101
5102 /* Dynamically link to optional system components. */
5103 {
5104 HANDLE user_lib = LoadLibrary ("user32.dll");
5105
5106 #define LOAD_PROC(fn) pfn##fn = (void *) GetProcAddress (user_lib, #fn)
5107
5108 /* New proportional scroll bar functions. */
5109 LOAD_PROC( SetScrollInfo );
5110 LOAD_PROC( GetScrollInfo );
5111
5112 #undef LOAD_PROC
5113
5114 FreeLibrary (user_lib);
5115
5116 /* If using proportional scroll bars, ensure handle is at least 5 pixels;
5117 otherwise use the fixed height. */
5118 vertical_scroll_bar_min_handle = (pfnSetScrollInfo != NULL) ? 5 :
5119 GetSystemMetrics (SM_CYVTHUMB);
5120
5121 /* For either kind of scroll bar, take account of the arrows; these
5122 effectively form the border of the main scroll bar range. */
5123 vertical_scroll_bar_top_border = vertical_scroll_bar_bottom_border
5124 = GetSystemMetrics (SM_CYVSCROLL);
5125 }
5126 }
5127
5128 void
5129 syms_of_w32term ()
5130 {
5131 staticpro (&w32_display_name_list);
5132 w32_display_name_list = Qnil;
5133
5134 staticpro (&last_mouse_scroll_bar);
5135 last_mouse_scroll_bar = Qnil;
5136
5137 staticpro (&Qvendor_specific_keysyms);
5138 Qvendor_specific_keysyms = intern ("vendor-specific-keysyms");
5139
5140 DEFVAR_INT ("w32-num-mouse-buttons",
5141 &Vw32_num_mouse_buttons,
5142 "Number of physical mouse buttons.");
5143 Vw32_num_mouse_buttons = Qnil;
5144
5145 DEFVAR_LISP ("w32-swap-mouse-buttons",
5146 &Vw32_swap_mouse_buttons,
5147 "Swap the mapping of middle and right mouse buttons.\n\
5148 When nil, middle button is mouse-2 and right button is mouse-3.");
5149 Vw32_swap_mouse_buttons = Qnil;
5150
5151 DEFVAR_LISP ("w32-grab-focus-on-raise",
5152 &Vw32_grab_focus_on_raise,
5153 "Raised frame grabs input focus.\n\
5154 When t, `raise-frame' grabs input focus as well. This fits well\n\
5155 with the normal Windows click-to-focus policy, but might not be\n\
5156 desirable when using a point-to-focus policy.");
5157 Vw32_grab_focus_on_raise = Qt;
5158
5159 DEFVAR_LISP ("w32-capslock-is-shiftlock",
5160 &Vw32_capslock_is_shiftlock,
5161 "Apply CapsLock state to non character input keys.\n\
5162 When nil, CapsLock only affects normal character input keys.");
5163 Vw32_capslock_is_shiftlock = Qnil;
5164
5165 DEFVAR_LISP ("w32-recognize-altgr",
5166 &Vw32_recognize_altgr,
5167 "Recognize right-alt and left-ctrl as AltGr.\n\
5168 When nil, the right-alt and left-ctrl key combination is\n\
5169 interpreted normally.");
5170 Vw32_recognize_altgr = Qt;
5171
5172 DEFVAR_BOOL ("w32-enable-unicode-output",
5173 &w32_enable_unicode_output,
5174 "Enable the use of Unicode for text output if non-nil.\n\
5175 Unicode output may prevent some third party applications for displaying\n\
5176 Far-East Languages on Windows 95/98 from working properly.\n\
5177 NT uses Unicode internally anyway, so this flag will probably have no\n\
5178 affect on NT machines.");
5179 w32_enable_unicode_output = 1;
5180 }