]> code.delx.au - gnu-emacs/blob - src/w32term.c
(Qouter_window_id): New variable.
[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
3338 /* Read events coming from the W32 shell.
3339 This routine is called by the SIGIO handler.
3340 We return as soon as there are no more events to be read.
3341
3342 Events representing keys are stored in buffer BUFP,
3343 which can hold up to NUMCHARS characters.
3344 We return the number of characters stored into the buffer,
3345 thus pretending to be `read'.
3346
3347 EXPECTED is nonzero if the caller knows input is available.
3348
3349 Some of these messages are reposted back to the message queue since the
3350 system calls the windows proc directly in a context where we cannot return
3351 the data nor can we guarantee the state we are in. So if we dispatch them
3352 we will get into an infinite loop. To prevent this from ever happening we
3353 will set a variable to indicate we are in the read_socket call and indicate
3354 which message we are processing since the windows proc gets called
3355 recursively with different messages by the system.
3356 */
3357
3358 int
3359 w32_read_socket (sd, bufp, numchars, expected)
3360 register int sd;
3361 register struct input_event *bufp;
3362 register int numchars;
3363 int expected;
3364 {
3365 int count = 0;
3366 int check_visibility = 0;
3367 W32Msg msg;
3368 struct frame *f;
3369 Lisp_Object part;
3370 struct w32_display_info *dpyinfo = &one_w32_display_info;
3371
3372 if (interrupt_input_blocked)
3373 {
3374 interrupt_input_pending = 1;
3375 return -1;
3376 }
3377
3378 interrupt_input_pending = 0;
3379 BLOCK_INPUT;
3380
3381 /* So people can tell when we have read the available input. */
3382 input_signal_count++;
3383
3384 if (numchars <= 0)
3385 abort (); /* Don't think this happens. */
3386
3387 while (get_next_msg (&msg, FALSE))
3388 {
3389 switch (msg.msg.message)
3390 {
3391 case WM_PAINT:
3392 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
3393
3394 if (f)
3395 {
3396 if (msg.rect.right == msg.rect.left ||
3397 msg.rect.bottom == msg.rect.top)
3398 {
3399 /* We may get paint messages even though the client
3400 area is clipped - these are not expose events. */
3401 DebPrint (("clipped frame %04x (%s) got WM_PAINT\n", f,
3402 XSTRING (f->name)->data));
3403 }
3404 else if (f->async_visible != 1)
3405 {
3406 /* Definitely not obscured, so mark as visible. */
3407 f->async_visible = 1;
3408 f->async_iconified = 0;
3409 SET_FRAME_GARBAGED (f);
3410 DebPrint (("frame %04x (%s) reexposed\n", f,
3411 XSTRING (f->name)->data));
3412
3413 /* WM_PAINT serves as MapNotify as well, so report
3414 visibility changes properly. */
3415 if (f->iconified)
3416 {
3417 bufp->kind = deiconify_event;
3418 XSETFRAME (bufp->frame_or_window, f);
3419 bufp++;
3420 count++;
3421 numchars--;
3422 }
3423 else if (! NILP(Vframe_list)
3424 && ! NILP (XCONS (Vframe_list)->cdr))
3425 /* Force a redisplay sooner or later to update the
3426 frame titles in case this is the second frame. */
3427 record_asynch_buffer_change ();
3428 }
3429 else
3430 {
3431 /* Erase background again for safety. */
3432 w32_clear_rect (f, NULL, &msg.rect);
3433 dumprectangle (f,
3434 msg.rect.left,
3435 msg.rect.top,
3436 msg.rect.right - msg.rect.left,
3437 msg.rect.bottom - msg.rect.top);
3438 }
3439 }
3440 break;
3441
3442 case WM_INPUTLANGCHANGE:
3443 /* Generate a language change event. */
3444 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
3445
3446 if (f)
3447 {
3448 if (numchars == 0)
3449 abort ();
3450
3451 bufp->kind = language_change_event;
3452 XSETFRAME (bufp->frame_or_window, f);
3453 bufp->code = msg.msg.wParam;
3454 bufp->modifiers = msg.msg.lParam & 0xffff;
3455 bufp++;
3456 count++;
3457 numchars--;
3458 }
3459 break;
3460
3461 case WM_KEYDOWN:
3462 case WM_SYSKEYDOWN:
3463 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
3464
3465 if (f && !f->iconified)
3466 {
3467 if (temp_index == sizeof temp_buffer / sizeof (short))
3468 temp_index = 0;
3469 temp_buffer[temp_index++] = msg.msg.wParam;
3470 bufp->kind = non_ascii_keystroke;
3471 bufp->code = msg.msg.wParam;
3472 bufp->modifiers = msg.dwModifiers;
3473 XSETFRAME (bufp->frame_or_window, f);
3474 bufp->timestamp = msg.msg.time;
3475 bufp++;
3476 numchars--;
3477 count++;
3478 }
3479 break;
3480
3481 case WM_SYSCHAR:
3482 case WM_CHAR:
3483 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
3484
3485 if (f && !f->iconified)
3486 {
3487 if (temp_index == sizeof temp_buffer / sizeof (short))
3488 temp_index = 0;
3489 temp_buffer[temp_index++] = msg.msg.wParam;
3490 bufp->kind = ascii_keystroke;
3491 bufp->code = msg.msg.wParam;
3492 bufp->modifiers = msg.dwModifiers;
3493 XSETFRAME (bufp->frame_or_window, f);
3494 bufp->timestamp = msg.msg.time;
3495 bufp++;
3496 numchars--;
3497 count++;
3498 }
3499 break;
3500
3501 case WM_MOUSEMOVE:
3502 if (dpyinfo->grabbed && last_mouse_frame
3503 && FRAME_LIVE_P (last_mouse_frame))
3504 f = last_mouse_frame;
3505 else
3506 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
3507
3508 if (f)
3509 note_mouse_movement (f, &msg.msg);
3510 else
3511 clear_mouse_face (FRAME_W32_DISPLAY_INFO (f));
3512
3513 break;
3514
3515 case WM_LBUTTONDOWN:
3516 case WM_LBUTTONUP:
3517 case WM_MBUTTONDOWN:
3518 case WM_MBUTTONUP:
3519 case WM_RBUTTONDOWN:
3520 case WM_RBUTTONUP:
3521 {
3522 int button;
3523 int up;
3524
3525 if (dpyinfo->grabbed && last_mouse_frame
3526 && FRAME_LIVE_P (last_mouse_frame))
3527 f = last_mouse_frame;
3528 else
3529 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
3530
3531 if (f)
3532 {
3533 if ((!dpyinfo->w32_focus_frame || f == dpyinfo->w32_focus_frame)
3534 && (numchars >= 1))
3535 {
3536 construct_mouse_click (bufp, &msg, f);
3537 bufp++;
3538 count++;
3539 numchars--;
3540 }
3541 }
3542
3543 parse_button (msg.msg.message, &button, &up);
3544
3545 if (up)
3546 {
3547 dpyinfo->grabbed &= ~ (1 << button);
3548 }
3549 else
3550 {
3551 dpyinfo->grabbed |= (1 << button);
3552 last_mouse_frame = f;
3553 }
3554 break;
3555 }
3556
3557 case WM_MOUSEWHEEL:
3558 if (dpyinfo->grabbed && last_mouse_frame
3559 && FRAME_LIVE_P (last_mouse_frame))
3560 f = last_mouse_frame;
3561 else
3562 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
3563
3564 if (f)
3565 {
3566 if ((!dpyinfo->w32_focus_frame
3567 || f == dpyinfo->w32_focus_frame)
3568 && (numchars >= 1))
3569 {
3570 construct_mouse_wheel (bufp, &msg, f);
3571 bufp++;
3572 count++;
3573 numchars--;
3574 }
3575 }
3576 break;
3577
3578 case WM_DROPFILES:
3579 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
3580
3581 if (f)
3582 {
3583 construct_drag_n_drop (bufp, &msg, f);
3584 bufp++;
3585 count++;
3586 numchars--;
3587 }
3588 break;
3589
3590 case WM_VSCROLL:
3591 {
3592 struct scroll_bar *bar =
3593 x_window_to_scroll_bar ((HWND)msg.msg.lParam);
3594
3595 if (bar && numchars >= 1)
3596 {
3597 if (x_scroll_bar_handle_click (bar, &msg, bufp))
3598 {
3599 bufp++;
3600 count++;
3601 numchars--;
3602 }
3603 }
3604 break;
3605 }
3606
3607 case WM_WINDOWPOSCHANGED:
3608 case WM_ACTIVATE:
3609 case WM_ACTIVATEAPP:
3610 check_visibility = 1;
3611 break;
3612
3613 case WM_MOVE:
3614 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
3615
3616 if (f && !f->async_iconified)
3617 {
3618 int x, y;
3619
3620 x_real_positions (f, &x, &y);
3621 f->output_data.w32->left_pos = x;
3622 f->output_data.w32->top_pos = y;
3623 }
3624
3625 check_visibility = 1;
3626 break;
3627
3628 case WM_SHOWWINDOW:
3629 /* If window has been obscured or exposed by another window
3630 being maximised or minimised/restored, then recheck
3631 visibility of all frames. Direct changes to our own
3632 windows get handled by WM_SIZE. */
3633 #if 0
3634 if (msg.msg.lParam != 0)
3635 check_visibility = 1;
3636 else
3637 {
3638 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
3639 f->async_visible = msg.msg.wParam;
3640 }
3641 #endif
3642
3643 check_visibility = 1;
3644 break;
3645
3646 case WM_SIZE:
3647 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
3648
3649 /* Inform lisp of whether frame has been iconified etc. */
3650 if (f)
3651 {
3652 switch (msg.msg.wParam)
3653 {
3654 case SIZE_MINIMIZED:
3655 f->async_visible = 0;
3656 f->async_iconified = 1;
3657
3658 bufp->kind = iconify_event;
3659 XSETFRAME (bufp->frame_or_window, f);
3660 bufp++;
3661 count++;
3662 numchars--;
3663 break;
3664
3665 case SIZE_MAXIMIZED:
3666 case SIZE_RESTORED:
3667 f->async_visible = 1;
3668 f->async_iconified = 0;
3669
3670 /* wait_reading_process_input will notice this and update
3671 the frame's display structures. */
3672 SET_FRAME_GARBAGED (f);
3673
3674 if (f->iconified)
3675 {
3676 bufp->kind = deiconify_event;
3677 XSETFRAME (bufp->frame_or_window, f);
3678 bufp++;
3679 count++;
3680 numchars--;
3681 }
3682 else
3683 /* Force a redisplay sooner or later
3684 to update the frame titles
3685 in case this is the second frame. */
3686 record_asynch_buffer_change ();
3687 break;
3688 }
3689 }
3690
3691 if (f && !f->async_iconified && msg.msg.wParam != SIZE_MINIMIZED)
3692 {
3693 RECT rect;
3694 int rows;
3695 int columns;
3696 int width;
3697 int height;
3698
3699 GetClientRect(msg.msg.hwnd, &rect);
3700
3701 height = rect.bottom - rect.top;
3702 width = rect.right - rect.left;
3703
3704 rows = PIXEL_TO_CHAR_HEIGHT (f, height);
3705 columns = PIXEL_TO_CHAR_WIDTH (f, width);
3706
3707 /* TODO: Clip size to the screen dimensions. */
3708
3709 /* Even if the number of character rows and columns has
3710 not changed, the font size may have changed, so we need
3711 to check the pixel dimensions as well. */
3712
3713 if (columns != f->width
3714 || rows != f->height
3715 || width != f->output_data.w32->pixel_width
3716 || height != f->output_data.w32->pixel_height)
3717 {
3718 /* I had set this to 0, 0 - I am not sure why?? */
3719
3720 change_frame_size (f, rows, columns, 0, 1);
3721 SET_FRAME_GARBAGED (f);
3722
3723 f->output_data.w32->pixel_width = width;
3724 f->output_data.w32->pixel_height = height;
3725 f->output_data.w32->win_gravity = NorthWestGravity;
3726 }
3727 }
3728
3729 check_visibility = 1;
3730 break;
3731
3732 case WM_SETFOCUS:
3733 case WM_KILLFOCUS:
3734 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
3735
3736 if (msg.msg.message == WM_SETFOCUS)
3737 {
3738 x_new_focus_frame (dpyinfo, f);
3739 }
3740 else if (f == dpyinfo->w32_focus_frame)
3741 {
3742 x_new_focus_frame (dpyinfo, 0);
3743 }
3744
3745 check_visibility = 1;
3746 break;
3747
3748 case WM_CLOSE:
3749 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
3750
3751 if (f)
3752 {
3753 if (numchars == 0)
3754 abort ();
3755
3756 bufp->kind = delete_window_event;
3757 XSETFRAME (bufp->frame_or_window, f);
3758 bufp++;
3759 count++;
3760 numchars--;
3761 }
3762 break;
3763
3764 case WM_INITMENU:
3765 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
3766
3767 if (f)
3768 {
3769 if (numchars == 0)
3770 abort ();
3771
3772 bufp->kind = menu_bar_activate_event;
3773 XSETFRAME (bufp->frame_or_window, f);
3774 bufp++;
3775 count++;
3776 numchars--;
3777 }
3778 break;
3779
3780 case WM_COMMAND:
3781 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
3782
3783 if (f)
3784 {
3785 extern void menubar_selection_callback
3786 (FRAME_PTR f, void * client_data);
3787 menubar_selection_callback (f, (void *)msg.msg.wParam);
3788 }
3789
3790 check_visibility = 1;
3791 break;
3792
3793 case WM_DISPLAYCHANGE:
3794 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
3795
3796 if (f)
3797 {
3798 dpyinfo->width = (short) LOWORD (msg.msg.lParam);
3799 dpyinfo->height = (short) HIWORD (msg.msg.lParam);
3800 dpyinfo->n_cbits = msg.msg.wParam;
3801 DebPrint (("display change: %d %d\n", dpyinfo->width,
3802 dpyinfo->height));
3803 }
3804
3805 check_visibility = 1;
3806 break;
3807
3808 default:
3809 /* Check for messages registered at runtime. */
3810 if (msg.msg.message == msh_mousewheel)
3811 {
3812 if (dpyinfo->grabbed && last_mouse_frame
3813 && FRAME_LIVE_P (last_mouse_frame))
3814 f = last_mouse_frame;
3815 else
3816 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
3817
3818 if (f)
3819 {
3820 if ((!dpyinfo->w32_focus_frame
3821 || f == dpyinfo->w32_focus_frame)
3822 && (numchars >= 1))
3823 {
3824 construct_mouse_wheel (bufp, &msg, f);
3825 bufp++;
3826 count++;
3827 numchars--;
3828 }
3829 }
3830 }
3831 break;
3832 }
3833 }
3834
3835 /* If the focus was just given to an autoraising frame,
3836 raise it now. */
3837 /* ??? This ought to be able to handle more than one such frame. */
3838 if (pending_autoraise_frame)
3839 {
3840 x_raise_frame (pending_autoraise_frame);
3841 pending_autoraise_frame = 0;
3842 }
3843
3844 /* Check which frames are still visisble, if we have enqueued any user
3845 events or been notified of events that may affect visibility. We
3846 do this here because there doesn't seem to be any direct
3847 notification from Windows that the visibility of a window has
3848 changed (at least, not in all cases). */
3849 if (count > 0 || check_visibility)
3850 {
3851 Lisp_Object tail, frame;
3852
3853 FOR_EACH_FRAME (tail, frame)
3854 {
3855 FRAME_PTR f = XFRAME (frame);
3856 /* Check "visible" frames and mark each as obscured or not.
3857 Note that async_visible is nonzero for unobscured and
3858 obscured frames, but zero for hidden and iconified frames. */
3859 if (FRAME_W32_P (f) && f->async_visible)
3860 {
3861 RECT clipbox;
3862 HDC hdc = get_frame_dc (f);
3863 GetClipBox (hdc, &clipbox);
3864 release_frame_dc (f, hdc);
3865
3866 if (clipbox.right == clipbox.left
3867 || clipbox.bottom == clipbox.top)
3868 {
3869 /* Frame has become completely obscured so mark as
3870 such (we do this by setting async_visible to 2 so
3871 that FRAME_VISIBLE_P is still true, but redisplay
3872 will skip it). */
3873 f->async_visible = 2;
3874
3875 if (!FRAME_OBSCURED_P (f))
3876 {
3877 DebPrint (("frame %04x (%s) obscured\n", f,
3878 XSTRING (f->name)->data));
3879 }
3880 }
3881 else
3882 {
3883 /* Frame is not obscured, so mark it as such. */
3884 f->async_visible = 1;
3885
3886 if (FRAME_OBSCURED_P (f))
3887 {
3888 SET_FRAME_GARBAGED (f);
3889 DebPrint (("frame %04x (%s) reexposed\n", f,
3890 XSTRING (f->name)->data));
3891
3892 /* Force a redisplay sooner or later. */
3893 record_asynch_buffer_change ();
3894 }
3895 }
3896 }
3897 }
3898 }
3899
3900 UNBLOCK_INPUT;
3901 return count;
3902 }
3903 \f
3904 /* Drawing the cursor. */
3905
3906
3907 /* Draw a hollow box cursor. Don't change the inside of the box. */
3908
3909 static void
3910 x_draw_box (f)
3911 struct frame *f;
3912 {
3913 RECT rect;
3914 HBRUSH hb;
3915 HDC hdc;
3916
3917 hdc = get_frame_dc (f);
3918
3919 hb = CreateSolidBrush (f->output_data.w32->cursor_pixel);
3920
3921 rect.left = CHAR_TO_PIXEL_COL (f, curs_x);
3922 rect.top = CHAR_TO_PIXEL_ROW (f, curs_y);
3923 rect.right = rect.left + FONT_WIDTH (f->output_data.w32->font);
3924 rect.bottom = rect.top + f->output_data.w32->line_height;
3925
3926 FrameRect (hdc, &rect, hb);
3927 DeleteObject (hb);
3928
3929 release_frame_dc (f, hdc);
3930 }
3931
3932 /* Clear the cursor of frame F to background color,
3933 and mark the cursor as not shown.
3934 This is used when the text where the cursor is
3935 is about to be rewritten. */
3936
3937 static void
3938 clear_cursor (f)
3939 struct frame *f;
3940 {
3941 if (! FRAME_VISIBLE_P (f)
3942 || f->phys_cursor_x < 0)
3943 return;
3944
3945 x_display_cursor (f, 0);
3946 f->phys_cursor_x = -1;
3947 }
3948
3949 /* Redraw the glyph at ROW, COLUMN on frame F, in the style
3950 HIGHLIGHT. HIGHLIGHT is as defined for dumpglyphs. Return the
3951 glyph drawn. */
3952
3953 static void
3954 x_draw_single_glyph (f, row, column, glyph, highlight)
3955 struct frame *f;
3956 int row, column;
3957 GLYPH glyph;
3958 int highlight;
3959 {
3960 dumpglyphs (f,
3961 CHAR_TO_PIXEL_COL (f, column),
3962 CHAR_TO_PIXEL_ROW (f, row),
3963 &glyph, 1, highlight, 0, NULL);
3964 }
3965
3966 static void
3967 x_display_bar_cursor (f, on)
3968 struct frame *f;
3969 int on;
3970 {
3971 struct frame_glyphs *current_glyphs = FRAME_CURRENT_GLYPHS (f);
3972
3973 /* This is pointless on invisible frames, and dangerous on garbaged
3974 frames; in the latter case, the frame may be in the midst of
3975 changing its size, and curs_x and curs_y may be off the frame. */
3976 if (! FRAME_VISIBLE_P (f) || FRAME_GARBAGED_P (f))
3977 return;
3978
3979 if (! on && f->phys_cursor_x < 0)
3980 return;
3981
3982 /* If there is anything wrong with the current cursor state, remove it. */
3983 if (f->phys_cursor_x >= 0
3984 && (!on
3985 || f->phys_cursor_x != curs_x
3986 || f->phys_cursor_y != curs_y
3987 || f->output_data.w32->current_cursor != bar_cursor))
3988 {
3989 /* Erase the cursor by redrawing the character underneath it. */
3990 x_draw_single_glyph (f, f->phys_cursor_y, f->phys_cursor_x,
3991 f->phys_cursor_glyph,
3992 current_glyphs->highlight[f->phys_cursor_y]);
3993 f->phys_cursor_x = -1;
3994 }
3995
3996 /* If we now need a cursor in the new place or in the new form, do it so. */
3997 if (on
3998 && (f->phys_cursor_x < 0
3999 || (f->output_data.w32->current_cursor != bar_cursor)))
4000 {
4001 f->phys_cursor_glyph
4002 = ((current_glyphs->enable[curs_y]
4003 && curs_x < current_glyphs->used[curs_y])
4004 ? current_glyphs->glyphs[curs_y][curs_x]
4005 : SPACEGLYPH);
4006 w32_fill_area (f, NULL, f->output_data.w32->cursor_pixel,
4007 CHAR_TO_PIXEL_COL (f, curs_x),
4008 CHAR_TO_PIXEL_ROW (f, curs_y),
4009 max (f->output_data.w32->cursor_width, 1),
4010 f->output_data.w32->line_height);
4011
4012 f->phys_cursor_x = curs_x;
4013 f->phys_cursor_y = curs_y;
4014
4015 f->output_data.w32->current_cursor = bar_cursor;
4016 }
4017 }
4018
4019
4020 /* Turn the displayed cursor of frame F on or off according to ON.
4021 If ON is nonzero, where to put the cursor is specified
4022 by F->cursor_x and F->cursor_y. */
4023
4024 static void
4025 x_display_box_cursor (f, on)
4026 struct frame *f;
4027 int on;
4028 {
4029 struct frame_glyphs *current_glyphs = FRAME_CURRENT_GLYPHS (f);
4030
4031 /* This is pointless on invisible frames, and dangerous on garbaged
4032 frames; in the latter case, the frame may be in the midst of
4033 changing its size, and curs_x and curs_y may be off the frame. */
4034 if (! FRAME_VISIBLE_P (f) || FRAME_GARBAGED_P (f))
4035 return;
4036
4037 /* If cursor is off and we want it off, return quickly. */
4038 if (!on && f->phys_cursor_x < 0)
4039 return;
4040
4041 /* If cursor is currently being shown and we don't want it to be
4042 or it is in the wrong place,
4043 or we want a hollow box and it's not so, (pout!)
4044 erase it. */
4045 if (f->phys_cursor_x >= 0
4046 && (!on
4047 || f->phys_cursor_x != curs_x
4048 || f->phys_cursor_y != curs_y
4049 || (f->output_data.w32->current_cursor != hollow_box_cursor
4050 && (f != FRAME_W32_DISPLAY_INFO (f)->w32_highlight_frame))))
4051 {
4052 int mouse_face_here = 0;
4053 struct frame_glyphs *active_glyphs = FRAME_CURRENT_GLYPHS (f);
4054
4055 /* If the cursor is in the mouse face area, redisplay that when
4056 we clear the cursor. */
4057 if (f == FRAME_W32_DISPLAY_INFO (f)->mouse_face_mouse_frame
4058 && (f->phys_cursor_y > FRAME_W32_DISPLAY_INFO (f)->mouse_face_beg_row
4059 || (f->phys_cursor_y == FRAME_W32_DISPLAY_INFO (f)->mouse_face_beg_row
4060 && f->phys_cursor_x >= FRAME_W32_DISPLAY_INFO (f)->mouse_face_beg_col))
4061 && (f->phys_cursor_y < FRAME_W32_DISPLAY_INFO (f)->mouse_face_end_row
4062 || (f->phys_cursor_y == FRAME_W32_DISPLAY_INFO (f)->mouse_face_end_row
4063 && f->phys_cursor_x < FRAME_W32_DISPLAY_INFO (f)->mouse_face_end_col))
4064 /* Don't redraw the cursor's spot in mouse face
4065 if it is at the end of a line (on a newline).
4066 The cursor appears there, but mouse highlighting does not. */
4067 && active_glyphs->used[f->phys_cursor_y] > f->phys_cursor_x)
4068 mouse_face_here = 1;
4069
4070 /* If the font is not as tall as a whole line,
4071 we must explicitly clear the line's whole height. */
4072 if (FONT_HEIGHT (f->output_data.w32->font) != f->output_data.w32->line_height)
4073 w32_clear_area (f, NULL,
4074 CHAR_TO_PIXEL_COL (f, f->phys_cursor_x),
4075 CHAR_TO_PIXEL_ROW (f, f->phys_cursor_y),
4076 FONT_WIDTH (f->output_data.w32->font),
4077 f->output_data.w32->line_height);
4078 /* Erase the cursor by redrawing the character underneath it. */
4079 x_draw_single_glyph (f, f->phys_cursor_y, f->phys_cursor_x,
4080 f->phys_cursor_glyph,
4081 (mouse_face_here
4082 ? 3
4083 : current_glyphs->highlight[f->phys_cursor_y]));
4084 f->phys_cursor_x = -1;
4085 }
4086
4087 /* If we want to show a cursor,
4088 or we want a box cursor and it's not so,
4089 write it in the right place. */
4090 if (on
4091 && (f->phys_cursor_x < 0
4092 || (f->output_data.w32->current_cursor != filled_box_cursor
4093 && f == FRAME_W32_DISPLAY_INFO (f)->w32_highlight_frame)))
4094 {
4095 f->phys_cursor_glyph
4096 = ((current_glyphs->enable[curs_y]
4097 && curs_x < current_glyphs->used[curs_y])
4098 ? current_glyphs->glyphs[curs_y][curs_x]
4099 : SPACEGLYPH);
4100 if (f != FRAME_W32_DISPLAY_INFO (f)->w32_highlight_frame)
4101 {
4102 x_draw_box (f);
4103 f->output_data.w32->current_cursor = hollow_box_cursor;
4104 }
4105 else
4106 {
4107 x_draw_single_glyph (f, curs_y, curs_x,
4108 f->phys_cursor_glyph, 2);
4109 f->output_data.w32->current_cursor = filled_box_cursor;
4110 }
4111
4112 f->phys_cursor_x = curs_x;
4113 f->phys_cursor_y = curs_y;
4114 }
4115 }
4116
4117 /* Display the cursor on frame F, or clear it, according to ON.
4118 Use the position specified by curs_x and curs_y
4119 if we are doing an update of frame F now.
4120 Otherwise use the position in the FRAME_CURSOR_X and FRAME_CURSOR_Y fields
4121 of F. */
4122
4123 x_display_cursor (f, on)
4124 struct frame *f;
4125 int on;
4126 {
4127 BLOCK_INPUT;
4128
4129 /* If we're not updating, then we want to use the current frame's
4130 cursor position, not our local idea of where the cursor ought to be. */
4131 if (f != updating_frame)
4132 {
4133 curs_x = FRAME_CURSOR_X (f);
4134 curs_y = FRAME_CURSOR_Y (f);
4135 }
4136
4137 if (FRAME_DESIRED_CURSOR (f) == filled_box_cursor)
4138 x_display_box_cursor (f, on);
4139 else if (FRAME_DESIRED_CURSOR (f) == bar_cursor)
4140 x_display_bar_cursor (f, on);
4141 else
4142 /* Those are the only two we have implemented! */
4143 abort ();
4144
4145 UNBLOCK_INPUT;
4146 }
4147 \f
4148 /* Changing the font of the frame. */
4149
4150 /* Give frame F the font named FONTNAME as its default font, and
4151 return the full name of that font. FONTNAME may be a wildcard
4152 pattern; in that case, we choose some font that fits the pattern.
4153 The return value shows which font we chose. */
4154
4155 Lisp_Object
4156 x_new_font (f, fontname)
4157 struct frame *f;
4158 register char *fontname;
4159 {
4160 struct font_info *fontp
4161 = fs_load_font (f, FRAME_W32_FONT_TABLE (f), CHARSET_ASCII,
4162 fontname, -1);
4163
4164 if (!fontp)
4165 return Qnil;
4166
4167 FRAME_FONT (f) = (XFontStruct *) (fontp->font);
4168 f->output_data.w32->font_baseline
4169 = FRAME_FONT(f)->tm.tmAscent + fontp->baseline_offset;
4170 FRAME_FONTSET (f) = -1;
4171
4172 /* Compute the scroll bar width in character columns. */
4173 if (f->scroll_bar_pixel_width > 0)
4174 {
4175 int wid = FONT_WIDTH (f->output_data.w32->font);
4176 f->scroll_bar_cols = (f->scroll_bar_pixel_width + wid-1) / wid;
4177 }
4178 else
4179 f->scroll_bar_cols = 2;
4180
4181 /* Now make the frame display the given font. */
4182 if (FRAME_W32_WINDOW (f) != 0)
4183 {
4184 frame_update_line_height (f);
4185 x_set_window_size (f, 0, f->width, f->height);
4186 }
4187 else
4188 /* If we are setting a new frame's font for the first time,
4189 there are no faces yet, so this font's height is the line height. */
4190 f->output_data.w32->line_height = FONT_HEIGHT (f->output_data.w32->font);
4191
4192 {
4193 Lisp_Object lispy_name;
4194
4195 lispy_name = build_string (fontname);
4196
4197 return lispy_name;
4198 }
4199 }
4200 \f
4201 /* Give frame F the fontset named FONTSETNAME as its default font, and
4202 return the full name of that fontset. FONTSETNAME may be a wildcard
4203 pattern; in that case, we choose some fontset that fits the pattern.
4204 The return value shows which fontset we chose. */
4205
4206 Lisp_Object
4207 x_new_fontset (f, fontsetname)
4208 struct frame *f;
4209 char *fontsetname;
4210 {
4211 int fontset = fs_query_fontset (f, fontsetname);
4212 struct fontset_info *fontsetp;
4213 Lisp_Object result;
4214
4215 if (fontset < 0)
4216 return Qnil;
4217
4218 if (FRAME_FONTSET (f) == fontset)
4219 /* This fontset is already set in frame F. There's nothing more
4220 to do. */
4221 return build_string (fontsetname);
4222
4223 fontsetp = FRAME_FONTSET_DATA (f)->fontset_table[fontset];
4224
4225 if (!fontsetp->fontname[CHARSET_ASCII])
4226 /* This fontset doesn't contain ASCII font. */
4227 return Qnil;
4228
4229 result = x_new_font (f, fontsetp->fontname[CHARSET_ASCII]);
4230
4231 if (!STRINGP (result))
4232 /* Can't load ASCII font. */
4233 return Qnil;
4234
4235 /* Since x_new_font doesn't update any fontset information, do it now. */
4236 FRAME_FONTSET(f) = fontset;
4237 FS_LOAD_FONT (f, FRAME_W32_FONT_TABLE (f),
4238 CHARSET_ASCII, XSTRING (result)->data, fontset);
4239
4240 return build_string (fontsetname);
4241 }
4242 \f
4243 /* Calculate the absolute position in frame F
4244 from its current recorded position values and gravity. */
4245
4246 x_calc_absolute_position (f)
4247 struct frame *f;
4248 {
4249 Window win, child;
4250 POINT pt;
4251 int flags = f->output_data.w32->size_hint_flags;
4252
4253 pt.x = pt.y = 0;
4254
4255 /* Find the position of the outside upper-left corner of
4256 the inner window, with respect to the outer window. */
4257 if (f->output_data.w32->parent_desc != FRAME_W32_DISPLAY_INFO (f)->root_window)
4258 {
4259 BLOCK_INPUT;
4260 MapWindowPoints (FRAME_W32_WINDOW (f),
4261 f->output_data.w32->parent_desc,
4262 &pt, 1);
4263 UNBLOCK_INPUT;
4264 }
4265
4266 {
4267 RECT rt;
4268 rt.left = rt.right = rt.top = rt.bottom = 0;
4269
4270 BLOCK_INPUT;
4271 AdjustWindowRect(&rt, f->output_data.w32->dwStyle,
4272 FRAME_EXTERNAL_MENU_BAR (f));
4273 UNBLOCK_INPUT;
4274
4275 pt.x += (rt.right - rt.left);
4276 pt.y += (rt.bottom - rt.top);
4277 }
4278
4279 /* Treat negative positions as relative to the leftmost bottommost
4280 position that fits on the screen. */
4281 if (flags & XNegative)
4282 f->output_data.w32->left_pos = (FRAME_W32_DISPLAY_INFO (f)->width
4283 - 2 * f->output_data.w32->border_width - pt.x
4284 - PIXEL_WIDTH (f)
4285 + f->output_data.w32->left_pos);
4286
4287 if (flags & YNegative)
4288 f->output_data.w32->top_pos = (FRAME_W32_DISPLAY_INFO (f)->height
4289 - 2 * f->output_data.w32->border_width - pt.y
4290 - PIXEL_HEIGHT (f)
4291 + f->output_data.w32->top_pos);
4292 /* The left_pos and top_pos
4293 are now relative to the top and left screen edges,
4294 so the flags should correspond. */
4295 f->output_data.w32->size_hint_flags &= ~ (XNegative | YNegative);
4296 }
4297
4298 /* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
4299 to really change the position, and 0 when calling from
4300 x_make_frame_visible (in that case, XOFF and YOFF are the current
4301 position values). It is -1 when calling from x_set_frame_parameters,
4302 which means, do adjust for borders but don't change the gravity. */
4303
4304 x_set_offset (f, xoff, yoff, change_gravity)
4305 struct frame *f;
4306 register int xoff, yoff;
4307 int change_gravity;
4308 {
4309 int modified_top, modified_left;
4310
4311 if (change_gravity > 0)
4312 {
4313 f->output_data.w32->top_pos = yoff;
4314 f->output_data.w32->left_pos = xoff;
4315 f->output_data.w32->size_hint_flags &= ~ (XNegative | YNegative);
4316 if (xoff < 0)
4317 f->output_data.w32->size_hint_flags |= XNegative;
4318 if (yoff < 0)
4319 f->output_data.w32->size_hint_flags |= YNegative;
4320 f->output_data.w32->win_gravity = NorthWestGravity;
4321 }
4322 x_calc_absolute_position (f);
4323
4324 BLOCK_INPUT;
4325 x_wm_set_size_hint (f, (long) 0, 0);
4326
4327 /* It is a mystery why we need to add the border_width here
4328 when the frame is already visible, but experiment says we do. */
4329 modified_left = f->output_data.w32->left_pos;
4330 modified_top = f->output_data.w32->top_pos;
4331 #ifndef HAVE_NTGUI
4332 /* Do not add in border widths under W32. */
4333 if (change_gravity != 0)
4334 {
4335 modified_left += f->output_data.w32->border_width;
4336 modified_top += f->output_data.w32->border_width;
4337 }
4338 #endif
4339
4340 my_set_window_pos (FRAME_W32_WINDOW (f),
4341 NULL,
4342 modified_left, modified_top,
4343 0, 0,
4344 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
4345 UNBLOCK_INPUT;
4346 }
4347
4348 /* Call this to change the size of frame F's x-window.
4349 If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
4350 for this size change and subsequent size changes.
4351 Otherwise we leave the window gravity unchanged. */
4352
4353 x_set_window_size (f, change_gravity, cols, rows)
4354 struct frame *f;
4355 int change_gravity;
4356 int cols, rows;
4357 {
4358 int pixelwidth, pixelheight;
4359 Lisp_Object window;
4360 struct w32_display_info *dpyinfo = &one_w32_display_info;
4361
4362 BLOCK_INPUT;
4363
4364 check_frame_size (f, &rows, &cols);
4365 f->output_data.w32->vertical_scroll_bar_extra
4366 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
4367 ? 0
4368 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
4369 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
4370 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.w32->font)));
4371 pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols);
4372 pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows);
4373
4374 f->output_data.w32->win_gravity = NorthWestGravity;
4375 x_wm_set_size_hint (f, (long) 0, 0);
4376
4377 {
4378 RECT rect;
4379
4380 rect.left = rect.top = 0;
4381 rect.right = pixelwidth;
4382 rect.bottom = pixelheight;
4383
4384 AdjustWindowRect(&rect, f->output_data.w32->dwStyle,
4385 FRAME_EXTERNAL_MENU_BAR (f));
4386
4387 my_set_window_pos (FRAME_W32_WINDOW (f),
4388 NULL,
4389 0, 0,
4390 rect.right - rect.left,
4391 rect.bottom - rect.top,
4392 SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
4393 }
4394
4395 /* Now, strictly speaking, we can't be sure that this is accurate,
4396 but the window manager will get around to dealing with the size
4397 change request eventually, and we'll hear how it went when the
4398 ConfigureNotify event gets here.
4399
4400 We could just not bother storing any of this information here,
4401 and let the ConfigureNotify event set everything up, but that
4402 might be kind of confusing to the lisp code, since size changes
4403 wouldn't be reported in the frame parameters until some random
4404 point in the future when the ConfigureNotify event arrives. */
4405 change_frame_size (f, rows, cols, 0, 0);
4406 PIXEL_WIDTH (f) = pixelwidth;
4407 PIXEL_HEIGHT (f) = pixelheight;
4408
4409 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
4410 receive in the ConfigureNotify event; if we get what we asked
4411 for, then the event won't cause the screen to become garbaged, so
4412 we have to make sure to do it here. */
4413 SET_FRAME_GARBAGED (f);
4414
4415 /* If cursor was outside the new size, mark it as off. */
4416 if (f->phys_cursor_y >= rows
4417 || f->phys_cursor_x >= cols)
4418 {
4419 f->phys_cursor_x = -1;
4420 f->phys_cursor_y = -1;
4421 }
4422
4423 /* Clear out any recollection of where the mouse highlighting was,
4424 since it might be in a place that's outside the new frame size.
4425 Actually checking whether it is outside is a pain in the neck,
4426 so don't try--just let the highlighting be done afresh with new size. */
4427 window = dpyinfo->mouse_face_window;
4428 if (! NILP (window) && XFRAME (window) == f)
4429 {
4430 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
4431 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
4432 dpyinfo->mouse_face_window = Qnil;
4433 }
4434
4435 UNBLOCK_INPUT;
4436 }
4437 \f
4438 /* Mouse warping. */
4439
4440 void
4441 x_set_mouse_pixel_position (f, pix_x, pix_y)
4442 struct frame *f;
4443 int pix_x, pix_y;
4444 {
4445 RECT rect;
4446 POINT pt;
4447
4448 BLOCK_INPUT;
4449
4450 GetClientRect (FRAME_W32_WINDOW (f), &rect);
4451 pt.x = rect.left + pix_x;
4452 pt.y = rect.top + pix_y;
4453 ClientToScreen (FRAME_W32_WINDOW (f), &pt);
4454
4455 SetCursorPos (pt.x, pt.y);
4456
4457 UNBLOCK_INPUT;
4458 }
4459
4460 void
4461 x_set_mouse_position (f, x, y)
4462 struct frame *f;
4463 int x, y;
4464 {
4465 int pix_x, pix_y;
4466
4467 pix_x = CHAR_TO_PIXEL_COL (f, x) + FONT_WIDTH (f->output_data.w32->font) / 2;
4468 pix_y = CHAR_TO_PIXEL_ROW (f, y) + f->output_data.w32->line_height / 2;
4469
4470 if (pix_x < 0) pix_x = 0;
4471 if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f);
4472
4473 if (pix_y < 0) pix_y = 0;
4474 if (pix_y > PIXEL_HEIGHT (f)) pix_y = PIXEL_HEIGHT (f);
4475
4476 x_set_mouse_pixel_position (f, pix_x, pix_y);
4477 }
4478 \f
4479 /* focus shifting, raising and lowering. */
4480
4481 x_focus_on_frame (f)
4482 struct frame *f;
4483 {
4484 struct w32_display_info *dpyinfo = &one_w32_display_info;
4485
4486 /* Give input focus to frame. */
4487 BLOCK_INPUT;
4488 #if 0
4489 /* Try not to change its Z-order if possible. */
4490 if (x_window_to_frame (dpyinfo, GetForegroundWindow ()))
4491 my_set_focus (f, FRAME_W32_WINDOW (f));
4492 else
4493 #endif
4494 my_set_foreground_window (FRAME_W32_WINDOW (f));
4495 UNBLOCK_INPUT;
4496 }
4497
4498 x_unfocus_frame (f)
4499 struct frame *f;
4500 {
4501 }
4502
4503 /* Raise frame F. */
4504
4505 x_raise_frame (f)
4506 struct frame *f;
4507 {
4508 BLOCK_INPUT;
4509
4510 /* Strictly speaking, raise-frame should only change the frame's Z
4511 order, leaving input focus unchanged. This is reasonable behaviour
4512 on X where the usual policy is point-to-focus. However, this
4513 behaviour would be very odd on Windows where the usual policy is
4514 click-to-focus.
4515
4516 On X, if the mouse happens to be over the raised frame, it gets
4517 input focus anyway (so the window with focus will never be
4518 completely obscured) - if not, then just moving the mouse over it
4519 is sufficient to give it focus. On Windows, the user must actually
4520 click on the frame (preferrably the title bar so as not to move
4521 point), which is more awkward. Also, no other Windows program
4522 raises a window to the top but leaves another window (possibly now
4523 completely obscured) with input focus.
4524
4525 Because there is a system setting on Windows that allows the user
4526 to choose the point to focus policy, we make the strict semantics
4527 optional, but by default we grab focus when raising. */
4528
4529 if (NILP (Vw32_grab_focus_on_raise))
4530 {
4531 /* The obvious call to my_set_window_pos doesn't work if Emacs is
4532 not already the foreground application: the frame is raised
4533 above all other frames belonging to us, but not above the
4534 current top window. To achieve that, we have to resort to this
4535 more cumbersome method. */
4536
4537 HDWP handle = BeginDeferWindowPos (2);
4538 if (handle)
4539 {
4540 DeferWindowPos (handle,
4541 FRAME_W32_WINDOW (f),
4542 HWND_TOP,
4543 0, 0, 0, 0,
4544 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
4545
4546 DeferWindowPos (handle,
4547 GetForegroundWindow (),
4548 FRAME_W32_WINDOW (f),
4549 0, 0, 0, 0,
4550 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
4551
4552 EndDeferWindowPos (handle);
4553 }
4554 }
4555 else
4556 {
4557 my_set_foreground_window (FRAME_W32_WINDOW (f));
4558 }
4559
4560 UNBLOCK_INPUT;
4561 }
4562
4563 /* Lower frame F. */
4564
4565 x_lower_frame (f)
4566 struct frame *f;
4567 {
4568 BLOCK_INPUT;
4569 my_set_window_pos (FRAME_W32_WINDOW (f),
4570 HWND_BOTTOM,
4571 0, 0, 0, 0,
4572 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
4573 UNBLOCK_INPUT;
4574 }
4575
4576 static void
4577 w32_frame_raise_lower (f, raise)
4578 FRAME_PTR f;
4579 int raise;
4580 {
4581 if (raise)
4582 x_raise_frame (f);
4583 else
4584 x_lower_frame (f);
4585 }
4586 \f
4587 /* Change of visibility. */
4588
4589 /* This tries to wait until the frame is really visible.
4590 However, if the window manager asks the user where to position
4591 the frame, this will return before the user finishes doing that.
4592 The frame will not actually be visible at that time,
4593 but it will become visible later when the window manager
4594 finishes with it. */
4595
4596 x_make_frame_visible (f)
4597 struct frame *f;
4598 {
4599 BLOCK_INPUT;
4600
4601 if (! FRAME_VISIBLE_P (f))
4602 {
4603 /* We test FRAME_GARBAGED_P here to make sure we don't
4604 call x_set_offset a second time
4605 if we get to x_make_frame_visible a second time
4606 before the window gets really visible. */
4607 if (! FRAME_ICONIFIED_P (f)
4608 && ! f->output_data.w32->asked_for_visible)
4609 x_set_offset (f, f->output_data.w32->left_pos, f->output_data.w32->top_pos, 0);
4610
4611 f->output_data.w32->asked_for_visible = 1;
4612
4613 // my_show_window (f, FRAME_W32_WINDOW (f), f->async_iconified ? SW_RESTORE : SW_SHOW);
4614 my_show_window (f, FRAME_W32_WINDOW (f), SW_SHOWNORMAL);
4615 }
4616
4617 /* Synchronize to ensure Emacs knows the frame is visible
4618 before we do anything else. We do this loop with input not blocked
4619 so that incoming events are handled. */
4620 {
4621 Lisp_Object frame;
4622 int count = input_signal_count;
4623
4624 /* This must come after we set COUNT. */
4625 UNBLOCK_INPUT;
4626
4627 XSETFRAME (frame, f);
4628
4629 while (1)
4630 {
4631 /* Once we have handled input events,
4632 we should have received the MapNotify if one is coming.
4633 So if we have not got it yet, stop looping.
4634 Some window managers make their own decisions
4635 about visibility. */
4636 if (input_signal_count != count)
4637 break;
4638 /* Machines that do polling rather than SIGIO have been observed
4639 to go into a busy-wait here. So we'll fake an alarm signal
4640 to let the handler know that there's something to be read.
4641 We used to raise a real alarm, but it seems that the handler
4642 isn't always enabled here. This is probably a bug. */
4643 if (input_polling_used ())
4644 {
4645 /* It could be confusing if a real alarm arrives while processing
4646 the fake one. Turn it off and let the handler reset it. */
4647 alarm (0);
4648 input_poll_signal (0);
4649 }
4650 /* Once we have handled input events,
4651 we should have received the MapNotify if one is coming.
4652 So if we have not got it yet, stop looping.
4653 Some window managers make their own decisions
4654 about visibility. */
4655 if (input_signal_count != count)
4656 break;
4657 }
4658 FRAME_SAMPLE_VISIBILITY (f);
4659 }
4660 }
4661
4662 /* Change from mapped state to withdrawn state. */
4663
4664 /* Make the frame visible (mapped and not iconified). */
4665
4666 x_make_frame_invisible (f)
4667 struct frame *f;
4668 {
4669 Window window;
4670
4671 /* Don't keep the highlight on an invisible frame. */
4672 if (FRAME_W32_DISPLAY_INFO (f)->w32_highlight_frame == f)
4673 FRAME_W32_DISPLAY_INFO (f)->w32_highlight_frame = 0;
4674
4675 BLOCK_INPUT;
4676
4677 my_show_window (f, FRAME_W32_WINDOW (f), SW_HIDE);
4678
4679 /* We can't distinguish this from iconification
4680 just by the event that we get from the server.
4681 So we can't win using the usual strategy of letting
4682 FRAME_SAMPLE_VISIBILITY set this. So do it by hand,
4683 and synchronize with the server to make sure we agree. */
4684 f->visible = 0;
4685 FRAME_ICONIFIED_P (f) = 0;
4686 f->async_visible = 0;
4687 f->async_iconified = 0;
4688
4689 UNBLOCK_INPUT;
4690 }
4691
4692 /* Change window state from mapped to iconified. */
4693
4694 void
4695 x_iconify_frame (f)
4696 struct frame *f;
4697 {
4698 int result;
4699
4700 /* Don't keep the highlight on an invisible frame. */
4701 if (FRAME_W32_DISPLAY_INFO (f)->w32_highlight_frame == f)
4702 FRAME_W32_DISPLAY_INFO (f)->w32_highlight_frame = 0;
4703
4704 if (f->async_iconified)
4705 return;
4706
4707 BLOCK_INPUT;
4708
4709 /* Simulate the user minimizing the frame. */
4710 PostMessage (FRAME_W32_WINDOW (f), WM_SYSCOMMAND, SC_MINIMIZE, 0);
4711
4712 f->async_iconified = 1;
4713
4714 UNBLOCK_INPUT;
4715 }
4716 \f
4717 /* Destroy the window of frame F. */
4718
4719 x_destroy_window (f)
4720 struct frame *f;
4721 {
4722 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
4723
4724 BLOCK_INPUT;
4725
4726 my_destroy_window (f, FRAME_W32_WINDOW (f));
4727 free_frame_menubar (f);
4728 free_frame_faces (f);
4729
4730 xfree (f->output_data.w32);
4731 f->output_data.w32 = 0;
4732 if (f == dpyinfo->w32_focus_frame)
4733 dpyinfo->w32_focus_frame = 0;
4734 if (f == dpyinfo->w32_focus_event_frame)
4735 dpyinfo->w32_focus_event_frame = 0;
4736 if (f == dpyinfo->w32_highlight_frame)
4737 dpyinfo->w32_highlight_frame = 0;
4738
4739 dpyinfo->reference_count--;
4740
4741 if (f == dpyinfo->mouse_face_mouse_frame)
4742 {
4743 dpyinfo->mouse_face_beg_row
4744 = dpyinfo->mouse_face_beg_col = -1;
4745 dpyinfo->mouse_face_end_row
4746 = dpyinfo->mouse_face_end_col = -1;
4747 dpyinfo->mouse_face_window = Qnil;
4748 }
4749
4750 UNBLOCK_INPUT;
4751 }
4752 \f
4753 /* Setting window manager hints. */
4754
4755 /* Set the normal size hints for the window manager, for frame F.
4756 FLAGS is the flags word to use--or 0 meaning preserve the flags
4757 that the window now has.
4758 If USER_POSITION is nonzero, we set the USPosition
4759 flag (this is useful when FLAGS is 0). */
4760
4761 x_wm_set_size_hint (f, flags, user_position)
4762 struct frame *f;
4763 long flags;
4764 int user_position;
4765 {
4766 Window window = FRAME_W32_WINDOW (f);
4767
4768 flexlines = f->height;
4769
4770 enter_crit ();
4771
4772 SetWindowLong (window, WND_FONTWIDTH_INDEX, FONT_WIDTH (f->output_data.w32->font));
4773 SetWindowLong (window, WND_LINEHEIGHT_INDEX, f->output_data.w32->line_height);
4774 SetWindowLong (window, WND_BORDER_INDEX, f->output_data.w32->internal_border_width);
4775 SetWindowLong (window, WND_SCROLLBAR_INDEX, f->output_data.w32->vertical_scroll_bar_extra);
4776
4777 leave_crit ();
4778 }
4779
4780 /* Window manager things */
4781 x_wm_set_icon_position (f, icon_x, icon_y)
4782 struct frame *f;
4783 int icon_x, icon_y;
4784 {
4785 #if 0
4786 Window window = FRAME_W32_WINDOW (f);
4787
4788 f->display.x->wm_hints.flags |= IconPositionHint;
4789 f->display.x->wm_hints.icon_x = icon_x;
4790 f->display.x->wm_hints.icon_y = icon_y;
4791
4792 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->display.x->wm_hints);
4793 #endif
4794 }
4795
4796 \f
4797 /* Initialization. */
4798
4799 #ifdef USE_X_TOOLKIT
4800 static XrmOptionDescRec emacs_options[] = {
4801 {"-geometry", ".geometry", XrmoptionSepArg, NULL},
4802 {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"},
4803
4804 {"-internal-border-width", "*EmacsScreen.internalBorderWidth",
4805 XrmoptionSepArg, NULL},
4806 {"-ib", "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL},
4807
4808 {"-T", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
4809 {"-wn", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
4810 {"-title", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
4811 {"-iconname", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
4812 {"-in", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
4813 {"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL},
4814 {"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL}
4815 };
4816 #endif /* USE_X_TOOLKIT */
4817
4818 static int w32_initialized = 0;
4819
4820 struct w32_display_info *
4821 w32_term_init (display_name, xrm_option, resource_name)
4822 Lisp_Object display_name;
4823 char *xrm_option;
4824 char *resource_name;
4825 {
4826 Lisp_Object frame;
4827 char *defaultvalue;
4828 struct w32_display_info *dpyinfo;
4829 HDC hdc;
4830
4831 BLOCK_INPUT;
4832
4833 if (!w32_initialized)
4834 {
4835 w32_initialize ();
4836 w32_initialized = 1;
4837 }
4838
4839 {
4840 int argc = 0;
4841 char *argv[3];
4842
4843 argv[0] = "";
4844 argc = 1;
4845 if (xrm_option)
4846 {
4847 argv[argc++] = "-xrm";
4848 argv[argc++] = xrm_option;
4849 }
4850 }
4851
4852 dpyinfo = &one_w32_display_info;
4853
4854 /* Put this display on the chain. */
4855 dpyinfo->next = NULL;
4856
4857 /* Put it on w32_display_name_list as well, to keep them parallel. */
4858 w32_display_name_list = Fcons (Fcons (display_name, Qnil),
4859 w32_display_name_list);
4860 dpyinfo->name_list_element = XCONS (w32_display_name_list)->car;
4861
4862 dpyinfo->w32_id_name
4863 = (char *) xmalloc (XSTRING (Vinvocation_name)->size
4864 + XSTRING (Vsystem_name)->size
4865 + 2);
4866 sprintf (dpyinfo->w32_id_name, "%s@%s",
4867 XSTRING (Vinvocation_name)->data, XSTRING (Vsystem_name)->data);
4868
4869 #if 0
4870 xrdb = x_load_resources (dpyinfo->display, xrm_option,
4871 resource_name, EMACS_CLASS);
4872
4873 /* Put the rdb where we can find it in a way that works on
4874 all versions. */
4875 dpyinfo->xrdb = xrdb;
4876 #endif
4877 hdc = GetDC (GetDesktopWindow ());
4878
4879 dpyinfo->height = GetDeviceCaps (hdc, VERTRES);
4880 dpyinfo->width = GetDeviceCaps (hdc, HORZRES);
4881 dpyinfo->root_window = GetDesktopWindow ();
4882 dpyinfo->n_planes = GetDeviceCaps (hdc, PLANES);
4883 dpyinfo->n_cbits = GetDeviceCaps (hdc, BITSPIXEL);
4884 dpyinfo->height_in = GetDeviceCaps (hdc, LOGPIXELSX);
4885 dpyinfo->width_in = GetDeviceCaps (hdc, LOGPIXELSY);
4886 dpyinfo->has_palette = GetDeviceCaps (hdc, RASTERCAPS) & RC_PALETTE;
4887 dpyinfo->grabbed = 0;
4888 dpyinfo->reference_count = 0;
4889 dpyinfo->n_fonts = 0;
4890 dpyinfo->font_table_size = 0;
4891 dpyinfo->bitmaps = 0;
4892 dpyinfo->bitmaps_size = 0;
4893 dpyinfo->bitmaps_last = 0;
4894 dpyinfo->mouse_face_mouse_frame = 0;
4895 dpyinfo->mouse_face_deferred_gc = 0;
4896 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
4897 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
4898 dpyinfo->mouse_face_face_id = 0;
4899 dpyinfo->mouse_face_window = Qnil;
4900 dpyinfo->mouse_face_mouse_x = dpyinfo->mouse_face_mouse_y = 0;
4901 dpyinfo->mouse_face_defer = 0;
4902 dpyinfo->w32_focus_frame = 0;
4903 dpyinfo->w32_focus_event_frame = 0;
4904 dpyinfo->w32_highlight_frame = 0;
4905
4906 ReleaseDC (GetDesktopWindow (), hdc);
4907
4908 /* Determine if there is a middle mouse button, to allow parse_button
4909 to decide whether right mouse events should be mouse-2 or
4910 mouse-3. */
4911 XSETINT (Vw32_num_mouse_buttons, GetSystemMetrics (SM_CMOUSEBUTTONS));
4912
4913 /* initialise palette with white and black */
4914 {
4915 COLORREF color;
4916 defined_color (0, "white", &color, 1);
4917 defined_color (0, "black", &color, 1);
4918 }
4919
4920 #ifndef F_SETOWN_BUG
4921 #ifdef F_SETOWN
4922 #ifdef F_SETOWN_SOCK_NEG
4923 /* stdin is a socket here */
4924 fcntl (connection, F_SETOWN, -getpid ());
4925 #else /* ! defined (F_SETOWN_SOCK_NEG) */
4926 fcntl (connection, F_SETOWN, getpid ());
4927 #endif /* ! defined (F_SETOWN_SOCK_NEG) */
4928 #endif /* ! defined (F_SETOWN) */
4929 #endif /* F_SETOWN_BUG */
4930
4931 #ifdef SIGIO
4932 if (interrupt_input)
4933 init_sigio (connection);
4934 #endif /* ! defined (SIGIO) */
4935
4936 UNBLOCK_INPUT;
4937
4938 return dpyinfo;
4939 }
4940 \f
4941 /* Get rid of display DPYINFO, assuming all frames are already gone. */
4942
4943 void
4944 x_delete_display (dpyinfo)
4945 struct w32_display_info *dpyinfo;
4946 {
4947 /* Discard this display from w32_display_name_list and w32_display_list.
4948 We can't use Fdelq because that can quit. */
4949 if (! NILP (w32_display_name_list)
4950 && EQ (XCONS (w32_display_name_list)->car, dpyinfo->name_list_element))
4951 w32_display_name_list = XCONS (w32_display_name_list)->cdr;
4952 else
4953 {
4954 Lisp_Object tail;
4955
4956 tail = w32_display_name_list;
4957 while (CONSP (tail) && CONSP (XCONS (tail)->cdr))
4958 {
4959 if (EQ (XCONS (XCONS (tail)->cdr)->car,
4960 dpyinfo->name_list_element))
4961 {
4962 XCONS (tail)->cdr = XCONS (XCONS (tail)->cdr)->cdr;
4963 break;
4964 }
4965 tail = XCONS (tail)->cdr;
4966 }
4967 }
4968
4969 /* free palette table */
4970 {
4971 struct w32_palette_entry * plist;
4972
4973 plist = dpyinfo->color_list;
4974 while (plist)
4975 {
4976 struct w32_palette_entry * pentry = plist;
4977 plist = plist->next;
4978 xfree(pentry);
4979 }
4980 dpyinfo->color_list = NULL;
4981 if (dpyinfo->palette)
4982 DeleteObject(dpyinfo->palette);
4983 }
4984 xfree (dpyinfo->font_table);
4985 xfree (dpyinfo->w32_id_name);
4986 }
4987 \f
4988 /* Set up use of W32. */
4989
4990 DWORD w32_msg_worker ();
4991
4992 w32_initialize ()
4993 {
4994 /* MSVC does not type K&R functions with no arguments correctly, and
4995 so we must explicitly cast them. */
4996 clear_frame_hook = (void (*)(void)) w32_clear_frame;
4997 clear_end_of_line_hook = w32_clear_end_of_line;
4998 ins_del_lines_hook = w32_ins_del_lines;
4999 change_line_highlight_hook = w32_change_line_highlight;
5000 insert_glyphs_hook = w32_insert_glyphs;
5001 write_glyphs_hook = w32_write_glyphs;
5002 delete_glyphs_hook = w32_delete_glyphs;
5003 ring_bell_hook = (void (*)(void)) w32_ring_bell;
5004 reset_terminal_modes_hook = (void (*)(void)) w32_reset_terminal_modes;
5005 set_terminal_modes_hook = (void (*)(void)) w32_set_terminal_modes;
5006 update_begin_hook = w32_update_begin;
5007 update_end_hook = w32_update_end;
5008 set_terminal_window_hook = w32_set_terminal_window;
5009 read_socket_hook = w32_read_socket;
5010 frame_up_to_date_hook = w32_frame_up_to_date;
5011 cursor_to_hook = w32_cursor_to;
5012 reassert_line_highlight_hook = w32_reassert_line_highlight;
5013 mouse_position_hook = w32_mouse_position;
5014 frame_rehighlight_hook = w32_frame_rehighlight;
5015 frame_raise_lower_hook = w32_frame_raise_lower;
5016 set_vertical_scroll_bar_hook = w32_set_vertical_scroll_bar;
5017 condemn_scroll_bars_hook = w32_condemn_scroll_bars;
5018 redeem_scroll_bar_hook = w32_redeem_scroll_bar;
5019 judge_scroll_bars_hook = w32_judge_scroll_bars;
5020
5021 scroll_region_ok = 1; /* we'll scroll partial frames */
5022 char_ins_del_ok = 0; /* just as fast to write the line */
5023 line_ins_del_ok = 1; /* we'll just blt 'em */
5024 fast_clear_end_of_line = 1; /* X does this well */
5025 memory_below_frame = 0; /* we don't remember what scrolls
5026 off the bottom */
5027 baud_rate = 19200;
5028
5029 /* Initialize input mode: interrupt_input off, no flow control, allow
5030 8 bit character input, standard quit char. */
5031 Fset_input_mode (Qnil, Qnil, make_number (2), Qnil);
5032
5033 /* Create the window thread - it will terminate itself or when the app terminates */
5034
5035 init_crit ();
5036
5037 dwMainThreadId = GetCurrentThreadId ();
5038 DuplicateHandle (GetCurrentProcess (), GetCurrentThread (),
5039 GetCurrentProcess (), &hMainThread, 0, TRUE, DUPLICATE_SAME_ACCESS);
5040
5041 /* Wait for thread to start */
5042
5043 {
5044 MSG msg;
5045
5046 PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
5047
5048 hWindowsThread = CreateThread (NULL, 0,
5049 (LPTHREAD_START_ROUTINE) w32_msg_worker,
5050 0, 0, &dwWindowsThreadId);
5051
5052 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
5053 }
5054
5055 /* It is desirable that mainThread should have the same notion of
5056 focus window and active window as windowsThread. Unfortunately, the
5057 following call to AttachThreadInput, which should do precisely what
5058 we need, causes major problems when Emacs is linked as a console
5059 program. Unfortunately, we have good reasons for doing that, so
5060 instead we need to send messages to windowsThread to make some API
5061 calls for us (ones that affect, or depend on, the active/focus
5062 window state. */
5063 #ifdef ATTACH_THREADS
5064 AttachThreadInput (dwMainThreadId, dwWindowsThreadId, TRUE);
5065 #endif
5066
5067 /* Dynamically link to optional system components. */
5068 {
5069 HANDLE user_lib = LoadLibrary ("user32.dll");
5070
5071 #define LOAD_PROC(fn) pfn##fn = (void *) GetProcAddress (user_lib, #fn)
5072
5073 /* New proportional scroll bar functions. */
5074 LOAD_PROC( SetScrollInfo );
5075 LOAD_PROC( GetScrollInfo );
5076
5077 #undef LOAD_PROC
5078
5079 FreeLibrary (user_lib);
5080
5081 /* If using proportional scroll bars, ensure handle is at least 5 pixels;
5082 otherwise use the fixed height. */
5083 vertical_scroll_bar_min_handle = (pfnSetScrollInfo != NULL) ? 5 :
5084 GetSystemMetrics (SM_CYVTHUMB);
5085
5086 /* For either kind of scroll bar, take account of the arrows; these
5087 effectively form the border of the main scroll bar range. */
5088 vertical_scroll_bar_top_border = vertical_scroll_bar_bottom_border
5089 = GetSystemMetrics (SM_CYVSCROLL);
5090 }
5091 }
5092
5093 void
5094 syms_of_w32term ()
5095 {
5096 staticpro (&w32_display_name_list);
5097 w32_display_name_list = Qnil;
5098
5099 staticpro (&last_mouse_scroll_bar);
5100 last_mouse_scroll_bar = Qnil;
5101
5102 staticpro (&Qvendor_specific_keysyms);
5103 Qvendor_specific_keysyms = intern ("vendor-specific-keysyms");
5104
5105 DEFVAR_INT ("w32-num-mouse-buttons",
5106 &Vw32_num_mouse_buttons,
5107 "Number of physical mouse buttons.");
5108 Vw32_num_mouse_buttons = Qnil;
5109
5110 DEFVAR_LISP ("w32-swap-mouse-buttons",
5111 &Vw32_swap_mouse_buttons,
5112 "Swap the mapping of middle and right mouse buttons.\n\
5113 When nil, middle button is mouse-2 and right button is mouse-3.");
5114 Vw32_swap_mouse_buttons = Qnil;
5115
5116 DEFVAR_LISP ("w32-grab-focus-on-raise",
5117 &Vw32_grab_focus_on_raise,
5118 "Raised frame grabs input focus.\n\
5119 When t, `raise-frame' grabs input focus as well. This fits well\n\
5120 with the normal Windows click-to-focus policy, but might not be\n\
5121 desirable when using a point-to-focus policy.");
5122 Vw32_grab_focus_on_raise = Qt;
5123
5124 DEFVAR_LISP ("w32-capslock-is-shiftlock",
5125 &Vw32_capslock_is_shiftlock,
5126 "Apply CapsLock state to non character input keys.\n\
5127 When nil, CapsLock only affects normal character input keys.");
5128 Vw32_capslock_is_shiftlock = Qnil;
5129
5130 DEFVAR_LISP ("w32-recognize-altgr",
5131 &Vw32_recognize_altgr,
5132 "Recognize right-alt and left-ctrl as AltGr.\n\
5133 When nil, the right-alt and left-ctrl key combination is\n\
5134 interpreted normally.");
5135 Vw32_recognize_altgr = Qt;
5136
5137 DEFVAR_BOOL ("w32-enable-unicode-output",
5138 &w32_enable_unicode_output,
5139 "Enable the use of Unicode for text output if non-nil.\n\
5140 Unicode output may prevent some third party applications for displaying\n\
5141 Far-East Languages on Windows 95/98 from working properly.\n\
5142 NT uses Unicode internally anyway, so this flag will probably have no\n\
5143 affect on NT machines.");
5144 w32_enable_unicode_output = 1;
5145 }