(Fformat_time_string): Doc fix.
[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:
52cf03a1 2195 return FALSE;
2c28562d 2196 }
52cf03a1 2197
ee78dc32
GV
2198 XSETINT (emacs_event->x, y);
2199 XSETINT (emacs_event->y, top_range);
52cf03a1
GV
2200
2201 return TRUE;
ee78dc32
GV
2202 }
2203}
2204
2205/* Return information to the user about the current position of the mouse
2206 on the scroll bar. */
2207static void
2208x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
2209 FRAME_PTR *fp;
2210 Lisp_Object *bar_window;
2211 enum scroll_bar_part *part;
2212 Lisp_Object *x, *y;
2213 unsigned long *time;
2214{
2215 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
2216 Window w = SCROLL_BAR_WIN32_WINDOW (bar);
2217 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2218 int pos;
2219
2220 BLOCK_INPUT;
2221
2222 *fp = f;
2223 *bar_window = bar->window;
2224
2225 pos = GetScrollPos (w, SB_CTL);
2226
2227 switch (LOWORD (last_mouse_scroll_bar_pos))
2228 {
2229 case SB_THUMBPOSITION:
2230 case SB_THUMBTRACK:
2231 *part = scroll_bar_handle;
2232 if (VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height)) <= 0xffff)
2233 pos = HIWORD (last_mouse_scroll_bar_pos);
2234 break;
2235 case SB_LINEDOWN:
2236 *part = scroll_bar_handle;
2237 pos++;
2238 break;
2239 default:
2240 *part = scroll_bar_handle;
2241 break;
2242 }
2243
2244 XSETINT(*x, pos);
2245 XSETINT(*y, VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height)));
2246
2247 f->mouse_moved = 0;
2248 last_mouse_scroll_bar = Qnil;
2249
2250 *time = last_mouse_movement_time;
2251
2252 UNBLOCK_INPUT;
2253}
2254
2255/* The screen has been cleared so we may have changed foreground or
2256 background colors, and the scroll bars may need to be redrawn.
2257 Clear out the scroll bars, and ask for expose events, so we can
2258 redraw them. */
2259
2260x_scroll_bar_clear (f)
2261 FRAME_PTR f;
2262{
ee78dc32
GV
2263 Lisp_Object bar;
2264
2265 for (bar = FRAME_SCROLL_BARS (f); VECTORP (bar);
2266 bar = XSCROLL_BAR (bar)->next)
52cf03a1
GV
2267 {
2268 HWND window = SCROLL_BAR_WIN32_WINDOW (XSCROLL_BAR (bar));
2269 HDC hdc = GetDC (window);
2270 RECT rect;
2271
0b287713 2272 my_show_window (window, SW_HIDE);
52cf03a1
GV
2273 GetClientRect (window, &rect);
2274 select_palette (f, hdc);
2275 win32_clear_rect (f, hdc, &rect);
2276 deselect_palette (f, hdc);
2277 }
2278}
2279
2280show_scroll_bars (f, how)
2281 FRAME_PTR f;
2282 int how;
2283{
2284 Lisp_Object bar;
2285
2286 for (bar = FRAME_SCROLL_BARS (f); VECTORP (bar);
2287 bar = XSCROLL_BAR (bar)->next)
2288 {
2289 HWND window = SCROLL_BAR_WIN32_WINDOW (XSCROLL_BAR (bar));
2290 my_show_window (window, how);
2291 }
ee78dc32
GV
2292}
2293
2294\f
2295/* The main Win32 event-reading loop - w32_read_socket. */
2296
2297/* Timestamp of enter window event. This is only used by w32_read_socket,
2298 but we have to put it out here, since static variables within functions
2299 sometimes don't work. */
2300static Time enter_timestamp;
2301
2302/* Record the last 100 characters stored
2303 to help debug the loss-of-chars-during-GC problem. */
2304int temp_index;
2305short temp_buffer[100];
2306
afd153f0
GV
2307extern int key_event (KEY_EVENT_RECORD *, struct input_event *);
2308
2309/* Map a Win32 WM_CHAR message into a KEY_EVENT_RECORD so that
2310 we can use the same routines to handle input in both console
2311 and window modes. */
2312
2313static void
2314convert_to_key_event (Win32Msg *msgp, KEY_EVENT_RECORD *eventp)
2315{
2316 eventp->bKeyDown = TRUE;
2317 eventp->wRepeatCount = 1;
2318 eventp->wVirtualKeyCode = msgp->msg.wParam;
2319 eventp->wVirtualScanCode = (msgp->msg.lParam & 0xFF0000) >> 16;
2320 eventp->uChar.AsciiChar = 0;
2321 eventp->dwControlKeyState = msgp->dwModifiers;
2322}
2323
2324/* Return nonzero if the virtual key is a dead key. */
2325
2326static int
2327is_dead_key (int wparam)
2328{
2329 unsigned int code = MapVirtualKey (wparam, 2);
2330
2331 /* Win95 returns 0x8000, NT returns 0x80000000. */
2332 if ((code & 0x8000) || (code & 0x80000000))
2333 return 1;
2334 else
2335 return 0;
2336}
2337
ee78dc32
GV
2338/* Read events coming from the Win32 shell.
2339 This routine is called by the SIGIO handler.
2340 We return as soon as there are no more events to be read.
2341
2342 Events representing keys are stored in buffer BUFP,
2343 which can hold up to NUMCHARS characters.
2344 We return the number of characters stored into the buffer,
2345 thus pretending to be `read'.
2346
2347 WAITP is nonzero if we should block until input arrives.
2348 EXPECTED is nonzero if the caller knows input is available.
2349
2350 Some of these messages are reposted back to the message queue since the
2351 system calls the winproc directly in a context where we cannot return the
2352 data nor can we guarantee the state we are in. So if we dispatch them
2353 we will get into an infinite loop. To prevent this from ever happening we
2354 will set a variable to indicate we are in the read_socket call and indicate
2355 which message we are processing since the winproc gets called recursively with different
2356 messages by the system.
2357*/
2358
2359int
2360w32_read_socket (sd, bufp, numchars, waitp, expected)
2361 register int sd;
2362 register struct input_event *bufp;
2363 register int numchars;
2364 int waitp;
2365 int expected;
2366{
2367 int count = 0;
2368 int nbytes = 0;
2369 int items_pending; /* How many items are in the X queue. */
2370 Win32Msg msg;
2371 struct frame *f;
2372 int event_found = 0;
2373 int prefix;
2374 Lisp_Object part;
2375 struct win32_display_info *dpyinfo = &one_win32_display_info;
2376
2377 if (interrupt_input_blocked)
2378 {
2379 interrupt_input_pending = 1;
2380 return -1;
2381 }
2382
2383 interrupt_input_pending = 0;
2384 BLOCK_INPUT;
2385
2386 /* So people can tell when we have read the available input. */
2387 input_signal_count++;
2388
2389 if (numchars <= 0)
2390 abort (); /* Don't think this happens. */
2391
52cf03a1 2392 while (get_next_msg (&msg, FALSE))
ee78dc32
GV
2393 {
2394 switch (msg.msg.message)
2395 {
2396 case WM_ERASEBKGND:
2397 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
2398 if (f)
2399 {
2400 win32_clear_rect (f, NULL, &msg.rect);
2401 }
2402 break;
2403 case WM_PAINT:
2404 {
2405 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
2406
2407 if (f)
2408 {
2409 if (f->async_visible == 0)
2410 {
2411 f->async_visible = 1;
2412 f->async_iconified = 0;
2413 SET_FRAME_GARBAGED (f);
2414 }
2415 else
2416 {
2417 dumprectangle (f,
2418 msg.rect.left,
2419 msg.rect.top,
2420 msg.rect.right-msg.rect.left+1,
2421 msg.rect.bottom-msg.rect.top+1);
2422
2423 }
2424 }
2425 }
2426
2427 break;
52cf03a1
GV
2428 case WM_PALETTECHANGED:
2429 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
2430 if (f)
2431 /* Realize palette - will force update if needed. */
2432 release_frame_dc (f, get_frame_dc (f));
2433 break;
ee78dc32
GV
2434 case WM_KEYDOWN:
2435 case WM_SYSKEYDOWN:
2436 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
2437
2438 if (f && !f->iconified)
2439 {
2440 if (temp_index == sizeof temp_buffer / sizeof (short))
2441 temp_index = 0;
2442 temp_buffer[temp_index++] = msg.msg.wParam;
2443 bufp->kind = non_ascii_keystroke;
2444 bufp->code = msg.msg.wParam;
52cf03a1 2445 bufp->modifiers = win32_kbd_mods_to_emacs (msg.dwModifiers);
ee78dc32
GV
2446 XSETFRAME (bufp->frame_or_window, f);
2447 bufp->timestamp = msg.msg.time;
2448 bufp++;
2449 numchars--;
2450 count++;
2451 }
2452 break;
2453 case WM_SYSCHAR:
2454 case WM_CHAR:
2455 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
2456
2457 if (f && !f->iconified)
2458 {
2459 if (numchars > 1)
2460 {
afd153f0
GV
2461 int add;
2462 KEY_EVENT_RECORD key, *keyp = &key;
2463
ee78dc32
GV
2464 if (temp_index == sizeof temp_buffer / sizeof (short))
2465 temp_index = 0;
afd153f0
GV
2466
2467 convert_to_key_event (&msg, keyp);
2468 add = key_event (keyp, bufp);
a92989c3 2469 XSETFRAME (bufp->frame_or_window, f);
afd153f0
GV
2470 if (add == -1)
2471 {
2472 /* The key pressed generated two characters, most likely
2473 an accent character and a key that could not be
2474 combined with it. Prepend the message on the queue
2475 again to process the second character (which is
2476 being held internally in key_event), and process
2477 the first character now. */
2478 prepend_msg (&msg);
2479 add = 1;
2480 }
2481
2482 /* Throw dead keys away. */
2483 if (is_dead_key (msg.msg.wParam))
2484 break;
2485
2486 bufp += add;
2487 numchars -= add;
2488 count += add;
ee78dc32
GV
2489 }
2490 else
2491 {
2492 abort ();
2493 }
2494 }
2495 break;
2496 case WM_MOUSEMOVE:
2497 if (dpyinfo->grabbed && last_mouse_frame
2498 && FRAME_LIVE_P (last_mouse_frame))
2499 f = last_mouse_frame;
2500 else
2501 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
2502
2503 if (f)
2504 note_mouse_movement (f, &msg.msg);
2505 else
2506 clear_mouse_face (FRAME_WIN32_DISPLAY_INFO (f));
2507
2508 break;
2509 case WM_LBUTTONDOWN:
2510 case WM_LBUTTONUP:
2511 case WM_MBUTTONDOWN:
2512 case WM_MBUTTONUP:
2513 case WM_RBUTTONDOWN:
2514 case WM_RBUTTONUP:
2515 {
2516 int button;
2517 int up;
2518
2519 if (dpyinfo->grabbed && last_mouse_frame
2520 && FRAME_LIVE_P (last_mouse_frame))
2521 f = last_mouse_frame;
2522 else
2523 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
2524
2525 if (f)
2526 {
2527 if ((!dpyinfo->win32_focus_frame || f == dpyinfo->win32_focus_frame)
2528 && (numchars >= 1))
2529 {
2530 construct_mouse_click (bufp, &msg, f);
2531 bufp++;
2532 count++;
2533 numchars--;
2534 }
2535 }
2536
2537 parse_button (msg.msg.message, &button, &up);
2538
2539 if (up)
2540 {
2541 dpyinfo->grabbed &= ~ (1 << button);
2542 }
2543 else
2544 {
2545 dpyinfo->grabbed |= (1 << button);
2546 last_mouse_frame = f;
2547 }
2548 }
2549
2550 break;
2551 case WM_VSCROLL:
2552 {
2553 struct scroll_bar *bar = x_window_to_scroll_bar ((HWND)msg.msg.lParam);
2554
2555 if (bar && numchars >= 1)
2556 {
52cf03a1
GV
2557 if (x_scroll_bar_handle_click (bar, &msg, bufp))
2558 {
2559 bufp++;
2560 count++;
2561 numchars--;
2562 }
ee78dc32
GV
2563 }
2564 }
2565
2566 break;
2567 case WM_MOVE:
2568 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
2569
2570 if (f && !f->async_iconified)
2571 {
2572 f->output_data.win32->left_pos = LOWORD (msg.msg.lParam);
2573 f->output_data.win32->top_pos = HIWORD (msg.msg.lParam);
2574 }
2575
2576 break;
2577 case WM_SIZE:
2578 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
2579
2580 if (f && !f->async_iconified && msg.msg.wParam != SIZE_MINIMIZED)
2581 {
2582 RECT rect;
2583 int rows;
2584 int columns;
2585 int width;
2586 int height;
2587
97c23857 2588 GetClientRect(msg.msg.hwnd, &rect);
ee78dc32
GV
2589
2590 height = rect.bottom - rect.top + 1;
2591 width = rect.right - rect.left + 1;
2592
2593 rows = PIXEL_TO_CHAR_HEIGHT (f, height);
2594 columns = PIXEL_TO_CHAR_WIDTH (f, width);
2595
2596 /* Even if the number of character rows and columns has
2597 not changed, the font size may have changed, so we need
2598 to check the pixel dimensions as well. */
2599
2600 if (columns != f->width
2601 || rows != f->height
2602 || width != f->output_data.win32->pixel_width
2603 || height != f->output_data.win32->pixel_height)
2604 {
2605 /* I had set this to 0, 0 - I am not sure why?? */
2606
2607 change_frame_size (f, rows, columns, 0, 1);
2608 SET_FRAME_GARBAGED (f);
2609
2610 f->output_data.win32->pixel_width = width;
2611 f->output_data.win32->pixel_height = height;
2612 f->output_data.win32->win_gravity = NorthWestGravity;
2613 }
2614 }
2615
2616 break;
2617 case WM_SETFOCUS:
2618 case WM_KILLFOCUS:
2619 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
2620
2621 if (msg.msg.message == WM_SETFOCUS)
2622 {
2623 x_new_focus_frame (dpyinfo, f);
2624 }
2625 else if (f == dpyinfo->win32_focus_frame)
2626 x_new_focus_frame (dpyinfo, 0);
2627
2628 break;
2629 case WM_SYSCOMMAND:
2630 switch (msg.msg.wParam)
2631 {
2632 case SC_CLOSE:
2633 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
2634
2635 if (f)
2636 {
2637 if (numchars == 0)
2638 abort ();
2639
2640 bufp->kind = delete_window_event;
2641 XSETFRAME (bufp->frame_or_window, f);
2642 bufp++;
2643 count++;
2644 numchars--;
2645 }
2646
2647 break;
2648 case SC_MINIMIZE:
2649 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
2650
2651 if (f)
2652 {
2653 f->async_visible = 1;
2654 f->async_iconified = 1;
2655
2656 bufp->kind = iconify_event;
2657 XSETFRAME (bufp->frame_or_window, f);
2658 bufp++;
2659 count++;
2660 numchars--;
2661 }
2662
2663 break;
2664 case SC_MAXIMIZE:
2665 case SC_RESTORE:
2666 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
2667
2668 if (f)
2669 {
2670 f->async_visible = 1;
2671 f->async_iconified = 0;
2672
2673 /* wait_reading_process_input will notice this and update
2674 the frame's display structures. */
2675 SET_FRAME_GARBAGED (f);
2676
2677 if (f->iconified)
2678 {
2679 bufp->kind = deiconify_event;
2680 XSETFRAME (bufp->frame_or_window, f);
2681 bufp++;
2682 count++;
2683 numchars--;
2684 }
2685 else
2686 /* Force a redisplay sooner or later
2687 to update the frame titles
2688 in case this is the second frame. */
2689 record_asynch_buffer_change ();
2690 }
2691
2692 break;
2693 }
2694
2695 break;
2696 case WM_CLOSE:
2697 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
2698
2699 if (f)
2700 {
2701 if (numchars == 0)
2702 abort ();
2703
2704 bufp->kind = delete_window_event;
2705 XSETFRAME (bufp->frame_or_window, f);
2706 bufp++;
2707 count++;
2708 numchars--;
2709 }
2710
2711 break;
2712 case WM_COMMAND:
2713 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
2714
2715 if (f)
2716 {
2717 if (msg.msg.lParam == 0)
2718 {
2719 /* Came from window menu */
2720
2721 extern Lisp_Object get_frame_menubar_event ();
2722 Lisp_Object event = get_frame_menubar_event (f, msg.msg.wParam);
2723 struct input_event buf;
2724 Lisp_Object frame;
2725
2726 XSETFRAME (frame, f);
2727 buf.kind = menu_bar_event;
2728
2729 /* Store initial menu bar event */
2730
2731 if (!NILP (event))
2732 {
2733 buf.frame_or_window = Fcons (frame, Fcons (Qmenu_bar, Qnil));
2734 kbd_buffer_store_event (&buf);
2735 }
2736
2737 /* Enqueue the events */
2738
2739 while (!NILP (event))
2740 {
2741 buf.frame_or_window = Fcons (frame, XCONS (event)->car);
2742 kbd_buffer_store_event (&buf);
2743 event = XCONS (event)->cdr;
2744 }
2745 }
2746 else
2747 {
2748 /* Came from popup menu */
2749 }
2750 }
2751 break;
2752 }
2753 }
2754
2755 /* If the focus was just given to an autoraising frame,
2756 raise it now. */
2757 /* ??? This ought to be able to handle more than one such frame. */
2758 if (pending_autoraise_frame)
2759 {
2760 x_raise_frame (pending_autoraise_frame);
2761 pending_autoraise_frame = 0;
2762 }
2763
2764 UNBLOCK_INPUT;
2765 return count;
2766}
2767\f
2768/* Drawing the cursor. */
2769
2770
2771/* Draw a hollow box cursor. Don't change the inside of the box. */
2772
2773static void
2774x_draw_box (f)
2775 struct frame *f;
2776{
2777 RECT rect;
2778 HBRUSH hb;
2779 HDC hdc;
2780
52cf03a1 2781 hdc = get_frame_dc (f);
ee78dc32
GV
2782
2783 hb = CreateSolidBrush (f->output_data.win32->cursor_pixel);
2784
2785 rect.left = CHAR_TO_PIXEL_COL (f, curs_x);
2786 rect.top = CHAR_TO_PIXEL_ROW (f, curs_y);
52cf03a1
GV
2787 rect.right = rect.left + FONT_WIDTH (f->output_data.win32->font);
2788 rect.bottom = rect.top + f->output_data.win32->line_height;
2789
ee78dc32 2790 FrameRect (hdc, &rect, hb);
ee78dc32 2791 DeleteObject (hb);
52cf03a1
GV
2792
2793 release_frame_dc (f, hdc);
ee78dc32
GV
2794}
2795
2796/* Clear the cursor of frame F to background color,
2797 and mark the cursor as not shown.
2798 This is used when the text where the cursor is
2799 is about to be rewritten. */
2800
2801static void
2802clear_cursor (f)
2803 struct frame *f;
2804{
2805 if (! FRAME_VISIBLE_P (f)
2806 || f->phys_cursor_x < 0)
2807 return;
2808
2809 x_display_cursor (f, 0);
2810 f->phys_cursor_x = -1;
2811}
2812
2813/* Redraw the glyph at ROW, COLUMN on frame F, in the style
2814 HIGHLIGHT. HIGHLIGHT is as defined for dumpglyphs. Return the
2815 glyph drawn. */
2816
2817static void
2818x_draw_single_glyph (f, row, column, glyph, highlight)
2819 struct frame *f;
2820 int row, column;
2821 GLYPH glyph;
2822 int highlight;
2823{
2824 dumpglyphs (f,
2825 CHAR_TO_PIXEL_COL (f, column),
2826 CHAR_TO_PIXEL_ROW (f, row),
2827 &glyph, 1, highlight, 0);
2828}
2829
2830static void
2831x_display_bar_cursor (f, on)
2832 struct frame *f;
2833 int on;
2834{
2835 struct frame_glyphs *current_glyphs = FRAME_CURRENT_GLYPHS (f);
2836
2837 /* This is pointless on invisible frames, and dangerous on garbaged
2838 frames; in the latter case, the frame may be in the midst of
2839 changing its size, and curs_x and curs_y may be off the frame. */
2840 if (! FRAME_VISIBLE_P (f) || FRAME_GARBAGED_P (f))
2841 return;
2842
2843 if (! on && f->phys_cursor_x < 0)
2844 return;
2845
2846 /* If we're not updating, then we want to use the current frame's
2847 cursor position, not our local idea of where the cursor ought to be. */
2848 if (f != updating_frame)
2849 {
2850 curs_x = FRAME_CURSOR_X (f);
2851 curs_y = FRAME_CURSOR_Y (f);
2852 }
2853
2854 /* If there is anything wrong with the current cursor state, remove it. */
2855 if (f->phys_cursor_x >= 0
2856 && (!on
2857 || f->phys_cursor_x != curs_x
2858 || f->phys_cursor_y != curs_y
2859 || f->output_data.win32->current_cursor != bar_cursor))
2860 {
2861 /* Erase the cursor by redrawing the character underneath it. */
2862 x_draw_single_glyph (f, f->phys_cursor_y, f->phys_cursor_x,
2863 f->phys_cursor_glyph,
2864 current_glyphs->highlight[f->phys_cursor_y]);
2865 f->phys_cursor_x = -1;
2866 }
2867
2868 /* If we now need a cursor in the new place or in the new form, do it so. */
2869 if (on
2870 && (f->phys_cursor_x < 0
2871 || (f->output_data.win32->current_cursor != bar_cursor)))
2872 {
2873 f->phys_cursor_glyph
2874 = ((current_glyphs->enable[curs_y]
2875 && curs_x < current_glyphs->used[curs_y])
2876 ? current_glyphs->glyphs[curs_y][curs_x]
2877 : SPACEGLYPH);
2878 win32_fill_area (f, NULL, f->output_data.win32->cursor_pixel,
2879 CHAR_TO_PIXEL_COL (f, curs_x),
2880 CHAR_TO_PIXEL_ROW (f, curs_y),
2881 max (f->output_data.win32->cursor_width, 1),
2882 f->output_data.win32->line_height);
2883
2884 f->phys_cursor_x = curs_x;
2885 f->phys_cursor_y = curs_y;
2886
2887 f->output_data.win32->current_cursor = bar_cursor;
2888 }
2889}
2890
2891
2892/* Turn the displayed cursor of frame F on or off according to ON.
2893 If ON is nonzero, where to put the cursor is specified
2894 by F->cursor_x and F->cursor_y. */
2895
2896static void
2897x_display_box_cursor (f, on)
2898 struct frame *f;
2899 int on;
2900{
2901 struct frame_glyphs *current_glyphs = FRAME_CURRENT_GLYPHS (f);
2902
2903 /* This is pointless on invisible frames, and dangerous on garbaged
2904 frames; in the latter case, the frame may be in the midst of
2905 changing its size, and curs_x and curs_y may be off the frame. */
2906 if (! FRAME_VISIBLE_P (f) || FRAME_GARBAGED_P (f))
2907 return;
2908
2909 /* If cursor is off and we want it off, return quickly. */
2910 if (!on && f->phys_cursor_x < 0)
2911 return;
2912
2913 /* If we're not updating, then we want to use the current frame's
2914 cursor position, not our local idea of where the cursor ought to be. */
2915 if (f != updating_frame)
2916 {
2917 curs_x = FRAME_CURSOR_X (f);
2918 curs_y = FRAME_CURSOR_Y (f);
2919 }
2920
2921 /* If cursor is currently being shown and we don't want it to be
2922 or it is in the wrong place,
2923 or we want a hollow box and it's not so, (pout!)
2924 erase it. */
2925 if (f->phys_cursor_x >= 0
2926 && (!on
2927 || f->phys_cursor_x != curs_x
2928 || f->phys_cursor_y != curs_y
2929 || (f->output_data.win32->current_cursor != hollow_box_cursor
2930 && (f != FRAME_WIN32_DISPLAY_INFO (f)->win32_highlight_frame))))
2931 {
2932 int mouse_face_here = 0;
2933 struct frame_glyphs *active_glyphs = FRAME_CURRENT_GLYPHS (f);
2934
2935 /* If the cursor is in the mouse face area, redisplay that when
2936 we clear the cursor. */
2937 if (f == FRAME_WIN32_DISPLAY_INFO (f)->mouse_face_mouse_frame
2938 &&
2939 (f->phys_cursor_y > FRAME_WIN32_DISPLAY_INFO (f)->mouse_face_beg_row
2940 || (f->phys_cursor_y == FRAME_WIN32_DISPLAY_INFO (f)->mouse_face_beg_row
2941 && f->phys_cursor_x >= FRAME_WIN32_DISPLAY_INFO (f)->mouse_face_beg_col))
2942 &&
2943 (f->phys_cursor_y < FRAME_WIN32_DISPLAY_INFO (f)->mouse_face_end_row
2944 || (f->phys_cursor_y == FRAME_WIN32_DISPLAY_INFO (f)->mouse_face_end_row
2945 && f->phys_cursor_x < FRAME_WIN32_DISPLAY_INFO (f)->mouse_face_end_col))
2946 /* Don't redraw the cursor's spot in mouse face
2947 if it is at the end of a line (on a newline).
2948 The cursor appears there, but mouse highlighting does not. */
2949 && active_glyphs->used[f->phys_cursor_y] > f->phys_cursor_x)
2950 mouse_face_here = 1;
2951
2952 /* If the font is not as tall as a whole line,
2953 we must explicitly clear the line's whole height. */
2954 if (FONT_HEIGHT (f->output_data.win32->font) != f->output_data.win32->line_height)
2955 win32_clear_area (f, NULL,
2956 CHAR_TO_PIXEL_COL (f, f->phys_cursor_x),
2957 CHAR_TO_PIXEL_ROW (f, f->phys_cursor_y),
2958 FONT_WIDTH (f->output_data.win32->font),
2959 f->output_data.win32->line_height);
2960 /* Erase the cursor by redrawing the character underneath it. */
2961 x_draw_single_glyph (f, f->phys_cursor_y, f->phys_cursor_x,
2962 f->phys_cursor_glyph,
2963 (mouse_face_here
2964 ? 3
2965 : current_glyphs->highlight[f->phys_cursor_y]));
2966 f->phys_cursor_x = -1;
2967 }
2968
2969 /* If we want to show a cursor,
2970 or we want a box cursor and it's not so,
2971 write it in the right place. */
2972 if (on
2973 && (f->phys_cursor_x < 0
2974 || (f->output_data.win32->current_cursor != filled_box_cursor
2975 && f == FRAME_WIN32_DISPLAY_INFO (f)->win32_highlight_frame)))
2976 {
2977 f->phys_cursor_glyph
2978 = ((current_glyphs->enable[curs_y]
2979 && curs_x < current_glyphs->used[curs_y])
2980 ? current_glyphs->glyphs[curs_y][curs_x]
2981 : SPACEGLYPH);
2982 if (f != FRAME_WIN32_DISPLAY_INFO (f)->win32_highlight_frame)
2983 {
2984 x_draw_box (f);
2985 f->output_data.win32->current_cursor = hollow_box_cursor;
2986 }
2987 else
2988 {
2989 x_draw_single_glyph (f, curs_y, curs_x,
2990 f->phys_cursor_glyph, 2);
2991 f->output_data.win32->current_cursor = filled_box_cursor;
2992 }
2993
2994 f->phys_cursor_x = curs_x;
2995 f->phys_cursor_y = curs_y;
2996 }
2997}
2998
2999x_display_cursor (f, on)
3000 struct frame *f;
3001 int on;
3002{
3003 BLOCK_INPUT;
3004
3005 if (FRAME_DESIRED_CURSOR (f) == filled_box_cursor)
3006 x_display_box_cursor (f, on);
3007 else if (FRAME_DESIRED_CURSOR (f) == bar_cursor)
3008 x_display_bar_cursor (f, on);
3009 else
3010 /* Those are the only two we have implemented! */
3011 abort ();
3012
3013 UNBLOCK_INPUT;
3014}
3015\f
3016/* Changing the font of the frame. */
3017
3018/* Give frame F the font named FONTNAME as its default font, and
3019 return the full name of that font. FONTNAME may be a wildcard
3020 pattern; in that case, we choose some font that fits the pattern.
3021 The return value shows which font we chose. */
3022
3023Lisp_Object
3024x_new_font (f, fontname)
3025 struct frame *f;
3026 register char *fontname;
3027{
3028 int already_loaded;
3029 int n_matching_fonts;
3030 XFontStruct *font_info;
3031 char new_font_name[101];
3032
3033 /* Get a font which matches this name */
3034 {
3035 LOGFONT lf;
3036
3037 if (!x_to_win32_font(fontname, &lf)
3038 || !win32_to_x_font(&lf, new_font_name, 100))
3039 {
3040 return Qnil;
3041 }
3042 }
3043
3044 /* See if we've already loaded a matching font. */
3045 already_loaded = -1;
3046
3047 {
3048 int i;
3049
3050 for (i = 0; i < FRAME_WIN32_DISPLAY_INFO (f)->n_fonts; i++)
3051 if (!strcmp (FRAME_WIN32_DISPLAY_INFO (f)->font_table[i].name, new_font_name))
3052 {
3053 already_loaded = i;
3054 fontname = FRAME_WIN32_DISPLAY_INFO (f)->font_table[i].name;
3055 break;
3056 }
3057 }
3058
3059 /* If we have, just return it from the table. */
3060 if (already_loaded >= 0)
3061 f->output_data.win32->font = FRAME_WIN32_DISPLAY_INFO (f)->font_table[already_loaded].font;
3062 /* Otherwise, load the font and add it to the table. */
3063 else
3064 {
3065 XFontStruct *font;
3066 int n_fonts;
3067
3068 font = win32_load_font(FRAME_WIN32_DISPLAY_INFO (f), fontname);
3069
3070 if (! font)
3071 {
3072 return Qnil;
3073 }
3074
3075 /* Do we need to create the table? */
3076 if (FRAME_WIN32_DISPLAY_INFO (f)->font_table_size == 0)
3077 {
3078 FRAME_WIN32_DISPLAY_INFO (f)->font_table_size = 16;
3079 FRAME_WIN32_DISPLAY_INFO (f)->font_table
3080 = (struct font_info *) xmalloc (FRAME_WIN32_DISPLAY_INFO (f)->font_table_size
3081 * sizeof (struct font_info));
3082 }
3083 /* Do we need to grow the table? */
3084 else if (FRAME_WIN32_DISPLAY_INFO (f)->n_fonts
3085 >= FRAME_WIN32_DISPLAY_INFO (f)->font_table_size)
3086 {
3087 FRAME_WIN32_DISPLAY_INFO (f)->font_table_size *= 2;
3088 FRAME_WIN32_DISPLAY_INFO (f)->font_table
3089 = (struct font_info *) xrealloc (FRAME_WIN32_DISPLAY_INFO (f)->font_table,
3090 (FRAME_WIN32_DISPLAY_INFO (f)->font_table_size
3091 * sizeof (struct font_info)));
3092 }
3093
3094 n_fonts = FRAME_WIN32_DISPLAY_INFO (f)->n_fonts;
3095 FRAME_WIN32_DISPLAY_INFO (f)->font_table[n_fonts].name = (char *) xmalloc (strlen (fontname) + 1);
3096 bcopy (fontname, FRAME_WIN32_DISPLAY_INFO (f)->font_table[n_fonts].name, strlen (fontname) + 1);
3097 f->output_data.win32->font = FRAME_WIN32_DISPLAY_INFO (f)->font_table[n_fonts].font = font;
3098 FRAME_WIN32_DISPLAY_INFO (f)->n_fonts++;
3099 }
3100
3101 /* Compute the scroll bar width in character columns. */
3102 if (f->scroll_bar_pixel_width > 0)
3103 {
3104 int wid = FONT_WIDTH (f->output_data.win32->font);
3105 f->scroll_bar_cols = (f->scroll_bar_pixel_width + wid-1) / wid;
3106 }
3107 else
3108 f->scroll_bar_cols = 2;
3109
3110 /* Now make the frame display the given font. */
3111 if (FRAME_WIN32_WINDOW (f) != 0)
3112 {
3113 frame_update_line_height (f);
3114 x_set_window_size (f, 0, f->width, f->height);
3115 }
3116 else
3117 /* If we are setting a new frame's font for the first time,
3118 there are no faces yet, so this font's height is the line height. */
3119 f->output_data.win32->line_height = FONT_HEIGHT (f->output_data.win32->font);
3120
3121 {
3122 Lisp_Object lispy_name;
3123
3124 lispy_name = build_string (fontname);
3125
3126 return lispy_name;
3127 }
3128}
3129\f
3130x_calc_absolute_position (f)
3131 struct frame *f;
3132{
3133 Window win, child;
3134 POINT pt;
3135 int flags = f->output_data.win32->size_hint_flags;
3136
3137 pt.x = pt.y = 0;
3138
3139 /* Find the position of the outside upper-left corner of
3140 the inner window, with respect to the outer window. */
3141 if (f->output_data.win32->parent_desc != FRAME_WIN32_DISPLAY_INFO (f)->root_window)
3142 {
3143 BLOCK_INPUT;
3144 MapWindowPoints (FRAME_WIN32_WINDOW (f),
3145 f->output_data.win32->parent_desc,
3146 &pt, 1);
3147 UNBLOCK_INPUT;
3148 }
3149
3150 {
3151 RECT rt;
3152 rt.left = rt.right = rt.top = rt.bottom = 0;
3153
3154 BLOCK_INPUT;
97c23857
GV
3155 AdjustWindowRect(&rt, f->output_data.win32->dwStyle,
3156 FRAME_EXTERNAL_MENU_BAR (f));
ee78dc32
GV
3157 UNBLOCK_INPUT;
3158
3159 pt.x += (rt.right - rt.left);
3160 pt.y += (rt.bottom - rt.top);
3161 }
3162
3163 /* Treat negative positions as relative to the leftmost bottommost
3164 position that fits on the screen. */
3165 if (flags & XNegative)
3166 f->output_data.win32->left_pos = (FRAME_WIN32_DISPLAY_INFO (f)->width
3167 - 2 * f->output_data.win32->border_width - pt.x
3168 - PIXEL_WIDTH (f)
3169 + f->output_data.win32->left_pos);
3170
3171 if (flags & YNegative)
3172 f->output_data.win32->top_pos = (FRAME_WIN32_DISPLAY_INFO (f)->height
3173 - 2 * f->output_data.win32->border_width - pt.y
3174 - PIXEL_HEIGHT (f)
3175 + f->output_data.win32->top_pos);
3176 /* The left_pos and top_pos
3177 are now relative to the top and left screen edges,
3178 so the flags should correspond. */
3179 f->output_data.win32->size_hint_flags &= ~ (XNegative | YNegative);
3180}
3181
3182/* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
3183 to really change the position, and 0 when calling from
3184 x_make_frame_visible (in that case, XOFF and YOFF are the current
3185 position values). It is -1 when calling from x_set_frame_parameters,
3186 which means, do adjust for borders but don't change the gravity. */
3187
3188x_set_offset (f, xoff, yoff, change_gravity)
3189 struct frame *f;
3190 register int xoff, yoff;
3191 int change_gravity;
3192{
3193 int modified_top, modified_left;
3194
3195 if (change_gravity > 0)
3196 {
3197 f->output_data.win32->top_pos = yoff;
3198 f->output_data.win32->left_pos = xoff;
3199 f->output_data.win32->size_hint_flags &= ~ (XNegative | YNegative);
3200 if (xoff < 0)
3201 f->output_data.win32->size_hint_flags |= XNegative;
3202 if (yoff < 0)
3203 f->output_data.win32->size_hint_flags |= YNegative;
3204 f->output_data.win32->win_gravity = NorthWestGravity;
3205 }
3206 x_calc_absolute_position (f);
3207
3208 BLOCK_INPUT;
3209 x_wm_set_size_hint (f, (long) 0, 0);
3210
3211 /* It is a mystery why we need to add the border_width here
3212 when the frame is already visible, but experiment says we do. */
3213 modified_left = f->output_data.win32->left_pos;
3214 modified_top = f->output_data.win32->top_pos;
3215 if (change_gravity != 0)
3216 {
3217 modified_left += f->output_data.win32->border_width;
3218 modified_top += f->output_data.win32->border_width;
3219 }
3220
52cf03a1
GV
3221 my_set_window_pos (FRAME_WIN32_WINDOW (f),
3222 NULL,
3223 modified_left, modified_top,
3224 0,0,
3225 SWP_NOZORDER | SWP_NOSIZE);
ee78dc32
GV
3226 UNBLOCK_INPUT;
3227}
3228
3229/* Call this to change the size of frame F's x-window.
3230 If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
3231 for this size change and subsequent size changes.
3232 Otherwise we leave the window gravity unchanged. */
3233
3234x_set_window_size (f, change_gravity, cols, rows)
3235 struct frame *f;
3236 int change_gravity;
3237 int cols, rows;
3238{
3239 int pixelwidth, pixelheight;
3240
3241 BLOCK_INPUT;
3242
3243 check_frame_size (f, &rows, &cols);
3244 f->output_data.win32->vertical_scroll_bar_extra
3245 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
3246 ? 0
3247 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
3248 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
3249 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.win32->font)));
3250 pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols);
3251 pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows);
3252
3253 f->output_data.win32->win_gravity = NorthWestGravity;
3254 x_wm_set_size_hint (f, (long) 0, 0);
3255
3256 {
3257 RECT rect;
3258
3259 rect.left = rect.top = 0;
3260 rect.right = pixelwidth;
3261 rect.bottom = pixelheight;
3262
97c23857
GV
3263 AdjustWindowRect(&rect, f->output_data.win32->dwStyle,
3264 FRAME_EXTERNAL_MENU_BAR (f));
ee78dc32
GV
3265
3266 /* All windows have an extra pixel */
3267
52cf03a1
GV
3268 my_set_window_pos (FRAME_WIN32_WINDOW (f),
3269 NULL,
3270 0, 0,
3271 rect.right - rect.left + 1,
3272 rect.bottom - rect.top + 1,
3273 SWP_NOZORDER | SWP_NOMOVE);
ee78dc32
GV
3274 }
3275
3276 /* Now, strictly speaking, we can't be sure that this is accurate,
3277 but the window manager will get around to dealing with the size
3278 change request eventually, and we'll hear how it went when the
3279 ConfigureNotify event gets here.
3280
3281 We could just not bother storing any of this information here,
3282 and let the ConfigureNotify event set everything up, but that
3283 might be kind of confusing to the lisp code, since size changes
3284 wouldn't be reported in the frame parameters until some random
3285 point in the future when the ConfigureNotify event arrives. */
3286 change_frame_size (f, rows, cols, 0, 0);
3287 PIXEL_WIDTH (f) = pixelwidth;
3288 PIXEL_HEIGHT (f) = pixelheight;
3289
3290 /* If cursor was outside the new size, mark it as off. */
3291 if (f->phys_cursor_y >= rows
3292 || f->phys_cursor_x >= cols)
3293 {
3294 f->phys_cursor_x = -1;
3295 f->phys_cursor_y = -1;
3296 }
3297
3298 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
3299 receive in the ConfigureNotify event; if we get what we asked
3300 for, then the event won't cause the screen to become garbaged, so
3301 we have to make sure to do it here. */
3302 SET_FRAME_GARBAGED (f);
3303
3304 UNBLOCK_INPUT;
3305}
3306\f
3307/* Mouse warping. */
3308
3309void
3310x_set_mouse_position (f, x, y)
3311 struct frame *f;
3312 int x, y;
3313{
3314 int pix_x, pix_y;
3315
3316 pix_x = CHAR_TO_PIXEL_COL (f, x) + FONT_WIDTH (f->output_data.win32->font) / 2;
3317 pix_y = CHAR_TO_PIXEL_ROW (f, y) + f->output_data.win32->line_height / 2;
3318
3319 if (pix_x < 0) pix_x = 0;
3320 if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f);
3321
3322 if (pix_y < 0) pix_y = 0;
3323 if (pix_y > PIXEL_HEIGHT (f)) pix_y = PIXEL_HEIGHT (f);
3324
3325 BLOCK_INPUT;
3326
3327 SetCursorPos (pix_x, pix_y);
3328
3329 UNBLOCK_INPUT;
3330}
3331
3332/* Move the mouse to position pixel PIX_X, PIX_Y relative to frame F. */
3333
3334void
3335x_set_mouse_pixel_position (f, pix_x, pix_y)
3336 struct frame *f;
3337 int pix_x, pix_y;
3338{
3339 BLOCK_INPUT;
3340
3341 SetCursorPos (pix_x, pix_y);
3342
3343 UNBLOCK_INPUT;
3344}
3345\f
3346/* focus shifting, raising and lowering. */
3347
3348x_focus_on_frame (f)
3349 struct frame *f;
3350{
3351}
3352
3353x_unfocus_frame (f)
3354 struct frame *f;
3355{
3356}
3357
3358/* Raise frame F. */
3359
3360x_raise_frame (f)
3361 struct frame *f;
3362{
52cf03a1 3363// if (f->async_visible)
ee78dc32
GV
3364 {
3365 BLOCK_INPUT;
52cf03a1
GV
3366 my_set_window_pos (FRAME_WIN32_WINDOW (f),
3367 HWND_TOP,
3368 0, 0, 0, 0,
3369 SWP_NOSIZE | SWP_NOMOVE);
ee78dc32
GV
3370 UNBLOCK_INPUT;
3371 }
3372}
3373
3374/* Lower frame F. */
3375
3376x_lower_frame (f)
3377 struct frame *f;
3378{
52cf03a1 3379// if (f->async_visible)
ee78dc32
GV
3380 {
3381 BLOCK_INPUT;
52cf03a1
GV
3382 my_set_window_pos (FRAME_WIN32_WINDOW (f),
3383 HWND_BOTTOM,
3384 0, 0, 0, 0,
3385 SWP_NOSIZE | SWP_NOMOVE);
ee78dc32
GV
3386 UNBLOCK_INPUT;
3387 }
3388}
3389
3390static void
3391win32_frame_raise_lower (f, raise)
3392 FRAME_PTR f;
3393 int raise;
3394{
3395 if (raise)
3396 x_raise_frame (f);
3397 else
3398 x_lower_frame (f);
3399}
3400\f
3401/* Change of visibility. */
3402
3403/* This tries to wait until the frame is really visible.
3404 However, if the window manager asks the user where to position
3405 the frame, this will return before the user finishes doing that.
3406 The frame will not actually be visible at that time,
3407 but it will become visible later when the window manager
3408 finishes with it. */
3409
3410x_make_frame_visible (f)
3411 struct frame *f;
3412{
3413 BLOCK_INPUT;
3414
3415 if (! FRAME_VISIBLE_P (f))
3416 {
3417 /* We test FRAME_GARBAGED_P here to make sure we don't
3418 call x_set_offset a second time
3419 if we get to x_make_frame_visible a second time
3420 before the window gets really visible. */
3421 if (! FRAME_ICONIFIED_P (f)
52cf03a1
GV
3422 && ! f->output_data.win32->asked_for_visible)
3423 {
3424 x_set_offset (f, f->output_data.win32->left_pos, f->output_data.win32->top_pos, 0);
3425// SetForegroundWindow (FRAME_WIN32_WINDOW (f));
3426 }
ee78dc32
GV
3427
3428 f->output_data.win32->asked_for_visible = 1;
52cf03a1
GV
3429
3430 my_show_window (FRAME_WIN32_WINDOW (f), SW_SHOWNORMAL);
ee78dc32
GV
3431 }
3432
3433 /* Synchronize to ensure Emacs knows the frame is visible
3434 before we do anything else. We do this loop with input not blocked
3435 so that incoming events are handled. */
3436 {
3437 Lisp_Object frame;
3438 int count = input_signal_count;
3439
3440 /* This must come after we set COUNT. */
3441 UNBLOCK_INPUT;
3442
3443 XSETFRAME (frame, f);
3444
3445 while (1)
3446 {
3447 /* Once we have handled input events,
3448 we should have received the MapNotify if one is coming.
3449 So if we have not got it yet, stop looping.
3450 Some window managers make their own decisions
3451 about visibility. */
3452 if (input_signal_count != count)
3453 break;
3454 /* Machines that do polling rather than SIGIO have been observed
3455 to go into a busy-wait here. So we'll fake an alarm signal
3456 to let the handler know that there's something to be read.
3457 We used to raise a real alarm, but it seems that the handler
3458 isn't always enabled here. This is probably a bug. */
3459 if (input_polling_used ())
3460 {
3461 /* It could be confusing if a real alarm arrives while processing
3462 the fake one. Turn it off and let the handler reset it. */
3463 alarm (0);
3464 input_poll_signal ();
3465 }
3466 /* Once we have handled input events,
3467 we should have received the MapNotify if one is coming.
3468 So if we have not got it yet, stop looping.
3469 Some window managers make their own decisions
3470 about visibility. */
3471 if (input_signal_count != count)
3472 break;
3473 }
3474 FRAME_SAMPLE_VISIBILITY (f);
3475 }
3476}
3477
3478/* Change from mapped state to withdrawn state. */
3479
3480/* Make the frame visible (mapped and not iconified). */
3481
3482x_make_frame_invisible (f)
3483 struct frame *f;
3484{
3485 Window window;
3486
3487 /* Don't keep the highlight on an invisible frame. */
3488 if (FRAME_WIN32_DISPLAY_INFO (f)->win32_highlight_frame == f)
3489 FRAME_WIN32_DISPLAY_INFO (f)->win32_highlight_frame = 0;
3490
3491 BLOCK_INPUT;
3492
52cf03a1 3493 my_show_window (FRAME_WIN32_WINDOW (f), SW_HIDE);
ee78dc32
GV
3494
3495 /* We can't distinguish this from iconification
3496 just by the event that we get from the server.
3497 So we can't win using the usual strategy of letting
3498 FRAME_SAMPLE_VISIBILITY set this. So do it by hand,
3499 and synchronize with the server to make sure we agree. */
3500 f->visible = 0;
3501 FRAME_ICONIFIED_P (f) = 0;
3502 f->async_visible = 0;
3503 f->async_iconified = 0;
3504
3505 UNBLOCK_INPUT;
3506}
3507
3508/* Change window state from mapped to iconified. */
3509
52cf03a1
GV
3510void
3511x_iconify_frame (f)
ee78dc32
GV
3512 struct frame *f;
3513{
3514 int result;
3515
3516 /* Don't keep the highlight on an invisible frame. */
3517 if (FRAME_WIN32_DISPLAY_INFO (f)->win32_highlight_frame == f)
3518 FRAME_WIN32_DISPLAY_INFO (f)->win32_highlight_frame = 0;
3519
3520 if (f->async_iconified)
3521 return;
3522
3523 BLOCK_INPUT;
3524
52cf03a1
GV
3525 my_show_window (FRAME_WIN32_WINDOW (f), SW_SHOWMINIMIZED);
3526 /* The frame doesn't seem to be lowered automatically. */
3527 x_lower_frame (f);
ee78dc32
GV
3528
3529 f->async_iconified = 1;
3530
3531 UNBLOCK_INPUT;
3532}
3533\f
3534/* Destroy the window of frame F. */
3535
3536x_destroy_window (f)
3537 struct frame *f;
3538{
3539 struct win32_display_info *dpyinfo = FRAME_WIN32_DISPLAY_INFO (f);
3540
3541 BLOCK_INPUT;
3542
3543 my_destroy_window (f, FRAME_WIN32_WINDOW (f));
3544 free_frame_menubar (f);
3545 free_frame_faces (f);
3546
3547 xfree (f->output_data.win32);
3548 f->output_data.win32 = 0;
3549 if (f == dpyinfo->win32_focus_frame)
3550 dpyinfo->win32_focus_frame = 0;
3551 if (f == dpyinfo->win32_focus_event_frame)
3552 dpyinfo->win32_focus_event_frame = 0;
3553 if (f == dpyinfo->win32_highlight_frame)
3554 dpyinfo->win32_highlight_frame = 0;
3555
3556 dpyinfo->reference_count--;
3557
3558 if (f == dpyinfo->mouse_face_mouse_frame)
3559 {
3560 dpyinfo->mouse_face_beg_row
3561 = dpyinfo->mouse_face_beg_col = -1;
3562 dpyinfo->mouse_face_end_row
3563 = dpyinfo->mouse_face_end_col = -1;
3564 dpyinfo->mouse_face_window = Qnil;
3565 }
3566
3567 UNBLOCK_INPUT;
3568}
3569\f
3570/* Setting window manager hints. */
3571
3572/* Set the normal size hints for the window manager, for frame F.
3573 FLAGS is the flags word to use--or 0 meaning preserve the flags
3574 that the window now has.
3575 If USER_POSITION is nonzero, we set the USPosition
3576 flag (this is useful when FLAGS is 0). */
3577
3578x_wm_set_size_hint (f, flags, user_position)
3579 struct frame *f;
3580 long flags;
3581 int user_position;
3582{
3583 Window window = FRAME_WIN32_WINDOW (f);
3584
3585 flexlines = f->height;
3586
97c23857 3587 enter_crit ();
ee78dc32
GV
3588
3589 SetWindowLong (window, WND_X_UNITS_INDEX, FONT_WIDTH (f->output_data.win32->font));
3590 SetWindowLong (window, WND_Y_UNITS_INDEX, f->output_data.win32->line_height);
3591
97c23857 3592 leave_crit ();
ee78dc32
GV
3593}
3594
3595/* Window manager things */
3596x_wm_set_icon_position (f, icon_x, icon_y)
3597 struct frame *f;
3598 int icon_x, icon_y;
3599{
3600#if 0
3601 Window window = FRAME_WIN32_WINDOW (f);
3602
3603 f->display.x->wm_hints.flags |= IconPositionHint;
3604 f->display.x->wm_hints.icon_x = icon_x;
3605 f->display.x->wm_hints.icon_y = icon_y;
3606
3607 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->display.x->wm_hints);
3608#endif
3609}
3610
3611\f
3612/* Initialization. */
3613
3614#ifdef USE_X_TOOLKIT
3615static XrmOptionDescRec emacs_options[] = {
3616 {"-geometry", ".geometry", XrmoptionSepArg, NULL},
3617 {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"},
3618
3619 {"-internal-border-width", "*EmacsScreen.internalBorderWidth",
3620 XrmoptionSepArg, NULL},
3621 {"-ib", "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL},
3622
3623 {"-T", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
3624 {"-wn", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
3625 {"-title", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
3626 {"-iconname", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
3627 {"-in", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
3628 {"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL},
3629 {"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL}
3630};
3631#endif /* USE_X_TOOLKIT */
3632
3633static int win32_initialized = 0;
3634
3635struct win32_display_info *
3636win32_term_init (display_name, xrm_option, resource_name)
3637 Lisp_Object display_name;
3638 char *xrm_option;
3639 char *resource_name;
3640{
3641 Lisp_Object frame;
3642 char *defaultvalue;
3643 struct win32_display_info *dpyinfo;
3644 HDC hdc;
97c23857 3645
ee78dc32
GV
3646 BLOCK_INPUT;
3647
3648 if (!win32_initialized)
3649 {
3650 win32_initialize ();
3651 win32_initialized = 1;
3652 }
3653
3654 {
3655 int argc = 0;
3656 char *argv[3];
3657
3658 argv[0] = "";
3659 argc = 1;
3660 if (xrm_option)
3661 {
3662 argv[argc++] = "-xrm";
3663 argv[argc++] = xrm_option;
3664 }
3665 }
3666
3667 dpyinfo = &one_win32_display_info;
3668
3669 /* Put this display on the chain. */
3670 dpyinfo->next = NULL;
3671
3672 /* Put it on win32_display_name_list as well, to keep them parallel. */
3673 win32_display_name_list = Fcons (Fcons (display_name, Qnil),
3674 win32_display_name_list);
3675 dpyinfo->name_list_element = XCONS (win32_display_name_list)->car;
97c23857 3676
ee78dc32
GV
3677 dpyinfo->win32_id_name
3678 = (char *) xmalloc (XSTRING (Vinvocation_name)->size
3679 + XSTRING (Vsystem_name)->size
3680 + 2);
3681 sprintf (dpyinfo->win32_id_name, "%s@%s",
3682 XSTRING (Vinvocation_name)->data, XSTRING (Vsystem_name)->data);
3683
3684#if 0
3685 xrdb = x_load_resources (dpyinfo->display, xrm_option,
3686 resource_name, EMACS_CLASS);
3687
3688 /* Put the rdb where we can find it in a way that works on
3689 all versions. */
3690 dpyinfo->xrdb = xrdb;
3691#endif
52cf03a1 3692 hdc = GetDC (GetDesktopWindow ());
ee78dc32
GV
3693
3694 dpyinfo->height = GetDeviceCaps (hdc, VERTRES);
3695 dpyinfo->width = GetDeviceCaps (hdc, HORZRES);
3696 dpyinfo->root_window = GetDesktopWindow ();
3697 dpyinfo->n_planes = GetDeviceCaps (hdc, PLANES);
3698 dpyinfo->n_cbits = GetDeviceCaps (hdc, BITSPIXEL);
3699 dpyinfo->height_in = GetDeviceCaps (hdc, LOGPIXELSX);
3700 dpyinfo->width_in = GetDeviceCaps (hdc, LOGPIXELSY);
52cf03a1 3701 dpyinfo->has_palette = GetDeviceCaps (hdc, RASTERCAPS) & RC_PALETTE;
ee78dc32
GV
3702 dpyinfo->grabbed = 0;
3703 dpyinfo->reference_count = 0;
3704 dpyinfo->n_fonts = 0;
3705 dpyinfo->font_table_size = 0;
3706 dpyinfo->bitmaps = 0;
3707 dpyinfo->bitmaps_size = 0;
3708 dpyinfo->bitmaps_last = 0;
3709 dpyinfo->mouse_face_mouse_frame = 0;
3710 dpyinfo->mouse_face_deferred_gc = 0;
3711 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
3712 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
3713 dpyinfo->mouse_face_face_id = 0;
3714 dpyinfo->mouse_face_window = Qnil;
3715 dpyinfo->mouse_face_mouse_x = dpyinfo->mouse_face_mouse_y = 0;
3716 dpyinfo->mouse_face_defer = 0;
3717 dpyinfo->win32_focus_frame = 0;
3718 dpyinfo->win32_focus_event_frame = 0;
3719 dpyinfo->win32_highlight_frame = 0;
3720
3721 ReleaseDC (GetDesktopWindow (), hdc);
3722
52cf03a1
GV
3723 /* Determine if there is a middle mouse button, to allow parse_button
3724 to decide whether right mouse events should be mouse-2 or
3725 mouse-3. */
3726 XSETINT (Vwin32_num_mouse_buttons, GetSystemMetrics (SM_CMOUSEBUTTONS));
3727
3728 /* initialise palette with white and black */
3729 {
3730 COLORREF color;
3731 defined_color (0, "white", &color, 1);
3732 defined_color (0, "black", &color, 1);
3733 }
3734
ee78dc32
GV
3735#ifndef F_SETOWN_BUG
3736#ifdef F_SETOWN
3737#ifdef F_SETOWN_SOCK_NEG
3738 /* stdin is a socket here */
3739 fcntl (connection, F_SETOWN, -getpid ());
3740#else /* ! defined (F_SETOWN_SOCK_NEG) */
3741 fcntl (connection, F_SETOWN, getpid ());
3742#endif /* ! defined (F_SETOWN_SOCK_NEG) */
3743#endif /* ! defined (F_SETOWN) */
3744#endif /* F_SETOWN_BUG */
3745
3746#ifdef SIGIO
3747 if (interrupt_input)
3748 init_sigio (connection);
3749#endif /* ! defined (SIGIO) */
3750
3751 UNBLOCK_INPUT;
3752
3753 return dpyinfo;
3754}
3755\f
3756/* Get rid of display DPYINFO, assuming all frames are already gone. */
3757
3758void
3759x_delete_display (dpyinfo)
3760 struct win32_display_info *dpyinfo;
3761{
3762 /* Discard this display from win32_display_name_list and win32_display_list.
3763 We can't use Fdelq because that can quit. */
3764 if (! NILP (win32_display_name_list)
3765 && EQ (XCONS (win32_display_name_list)->car, dpyinfo->name_list_element))
3766 win32_display_name_list = XCONS (win32_display_name_list)->cdr;
3767 else
3768 {
3769 Lisp_Object tail;
3770
3771 tail = win32_display_name_list;
3772 while (CONSP (tail) && CONSP (XCONS (tail)->cdr))
3773 {
3774 if (EQ (XCONS (XCONS (tail)->cdr)->car,
3775 dpyinfo->name_list_element))
3776 {
3777 XCONS (tail)->cdr = XCONS (XCONS (tail)->cdr)->cdr;
3778 break;
3779 }
3780 tail = XCONS (tail)->cdr;
3781 }
3782 }
3783
52cf03a1
GV
3784 /* free palette table */
3785 {
3786 struct win32_palette_entry * plist;
3787
3788 plist = dpyinfo->color_list;
3789 while (plist)
3790 {
3791 struct win32_palette_entry * pentry = plist;
3792 plist = plist->next;
3793 xfree(pentry);
3794 }
3795 dpyinfo->color_list = NULL;
3796 if (dpyinfo->palette)
3797 DeleteObject(dpyinfo->palette);
3798 }
ee78dc32
GV
3799 xfree (dpyinfo->font_table);
3800 xfree (dpyinfo->win32_id_name);
3801}
3802\f
3803/* Set up use of Win32. */
3804
3805DWORD win_msg_worker ();
3806
3807win32_initialize ()
3808{
3809 clear_frame_hook = win32_clear_frame;
3810 clear_end_of_line_hook = win32_clear_end_of_line;
3811 ins_del_lines_hook = win32_ins_del_lines;
3812 change_line_highlight_hook = win32_change_line_highlight;
3813 insert_glyphs_hook = win32_insert_glyphs;
3814 write_glyphs_hook = win32_write_glyphs;
3815 delete_glyphs_hook = win32_delete_glyphs;
3816 ring_bell_hook = win32_ring_bell;
3817 reset_terminal_modes_hook = win32_reset_terminal_modes;
3818 set_terminal_modes_hook = win32_set_terminal_modes;
3819 update_begin_hook = win32_update_begin;
3820 update_end_hook = win32_update_end;
3821 set_terminal_window_hook = win32_set_terminal_window;
3822 read_socket_hook = w32_read_socket;
3823 frame_up_to_date_hook = win32_frame_up_to_date;
3824 cursor_to_hook = win32_cursor_to;
3825 reassert_line_highlight_hook = win32_reassert_line_highlight;
3826 mouse_position_hook = win32_mouse_position;
3827 frame_rehighlight_hook = win32_frame_rehighlight;
3828 frame_raise_lower_hook = win32_frame_raise_lower;
3829 set_vertical_scroll_bar_hook = win32_set_vertical_scroll_bar;
3830 condemn_scroll_bars_hook = win32_condemn_scroll_bars;
3831 redeem_scroll_bar_hook = win32_redeem_scroll_bar;
3832 judge_scroll_bars_hook = win32_judge_scroll_bars;
3833
3834 scroll_region_ok = 1; /* we'll scroll partial frames */
3835 char_ins_del_ok = 0; /* just as fast to write the line */
3836 line_ins_del_ok = 1; /* we'll just blt 'em */
3837 fast_clear_end_of_line = 1; /* X does this well */
3838 memory_below_frame = 0; /* we don't remember what scrolls
3839 off the bottom */
3840 baud_rate = 19200;
3841
3842 /* Try to use interrupt input; if we can't, then start polling. */
3843 Fset_input_mode (Qt, Qnil, Qt, Qnil);
3844
3845 /* Create the window thread - it will terminate itself or when the app terminates */
3846
3847 init_crit ();
3848
3849 dwMainThreadId = GetCurrentThreadId ();
3850 DuplicateHandle (GetCurrentProcess (), GetCurrentThread (),
3851 GetCurrentProcess (), &hMainThread, 0, TRUE, DUPLICATE_SAME_ACCESS);
3852
3853 /* Wait for thread to start */
3854
3855 {
3856 MSG msg;
3857
3858 PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
3859
3860 hWinThread = CreateThread (NULL, 0,
3861 (LPTHREAD_START_ROUTINE) win_msg_worker,
3862 0, 0, &dwWinThreadId);
3863
3864 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
3865 }
3866
52cf03a1
GV
3867 /* It is desirable that mainThread should have the same notion of
3868 focus window and active window as winThread. Unfortunately, the
3869 following call to AttachThreadInput, which should do precisely what
3870 we need, causes major problems when Emacs is linked as a console
3871 program. Unfortunately, we have good reasons for doing that, so
3872 instead we need to send messages to winThread to make some API
3873 calls for us (ones that affect, or depend on, the active/focus
3874 window state. */
3875#ifdef ATTACH_THREADS
a92989c3 3876 AttachThreadInput (dwMainThreadId, dwWinThreadId, TRUE);
52cf03a1 3877#endif
ee78dc32
GV
3878}
3879
3880void
3881syms_of_win32term ()
3882{
3883 staticpro (&win32_display_name_list);
3884 win32_display_name_list = Qnil;
3885
3886 staticpro (&last_mouse_scroll_bar);
3887 last_mouse_scroll_bar = Qnil;
3888
3889 staticpro (&Qvendor_specific_keysyms);
3890 Qvendor_specific_keysyms = intern ("vendor-specific-keysyms");
52cf03a1
GV
3891
3892 DEFVAR_INT ("win32-num-mouse-buttons",
3893 &Vwin32_num_mouse_buttons,
3894 "Number of physical mouse buttons.");
3895 Vwin32_num_mouse_buttons = Qnil;
3896
3897 DEFVAR_LISP ("win32-swap-mouse-buttons",
3898 &Vwin32_swap_mouse_buttons,
3899 "Swap the mapping of middle and right mouse buttons.\n\
3900When nil, middle button is mouse-2 and right button is mouse-3.");
3901 Vwin32_swap_mouse_buttons = Qnil;
ee78dc32 3902}