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