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