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