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