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