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