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