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