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