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