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