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