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