Use XIL/XLI instead of make_number/XINT for converting descriptor to a ptr.
[bpt/emacs.git] / src / w32term.c
CommitLineData
b46a6a83 1/* Implementation of GUI terminal on the Microsoft Windows API.
e9bffc61 2
44f92739 3Copyright (C) 1989, 1993-2012 Free Software Foundation, Inc.
ee78dc32
GV
4
5This file is part of GNU Emacs.
6
9ec0b715 7GNU Emacs is free software: you can redistribute it and/or modify
ee78dc32 8it under the terms of the GNU General Public License as published by
9ec0b715
GM
9the Free Software Foundation, either version 3 of the License, or
10(at your option) any later version.
ee78dc32
GV
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
9ec0b715 18along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
ee78dc32 19
ee78dc32 20#include <config.h>
68c45bf0 21#include <signal.h>
ee78dc32
GV
22#include <stdio.h>
23#include "lisp.h"
24#include "blockinput.h"
689004fa 25#include "w32term.h"
ee78dc32
GV
26
27#include "systty.h"
28#include "systime.h"
29
30#include <ctype.h>
31#include <errno.h>
ee78dc32 32#include <sys/stat.h>
c902b920 33#include <imm.h>
ee78dc32 34
66f30e44
JR
35#include "charset.h"
36#include "character.h"
37#include "coding.h"
38#include "ccl.h"
ee78dc32
GV
39#include "frame.h"
40#include "dispextern.h"
93ff4395 41#include "fontset.h"
ee78dc32
GV
42#include "termhooks.h"
43#include "termopts.h"
44#include "termchar.h"
ee78dc32
GV
45#include "disptab.h"
46#include "buffer.h"
47#include "window.h"
66f30e44 48#include "keyboard.h"
ee78dc32 49#include "intervals.h"
66f30e44
JR
50#include "process.h"
51#include "atimer.h"
52#include "keymap.h"
53
0fda9b75 54#ifdef WINDOWSNT
66f30e44 55#include "w32heap.h"
0fda9b75
DC
56#endif
57
58#ifndef WINDOWSNT
59#include <io.h> /* for get_osfhandle */
60#endif
61
66f30e44 62#include <shellapi.h>
ee78dc32 63
027f6f90 64#include "font.h"
ef39ccbb 65#include "w32font.h"
791f420f 66\f
33c34bea 67/* Fringe bitmaps. */
791f420f 68
0e9e9a2c
KS
69static int max_fringe_bmp = 0;
70static HBITMAP *fringe_bmp = 0;
791f420f 71
706ddb8f 72/* Temporary variables for w32_read_socket. */
791f420f 73
706ddb8f
JR
74static int last_mousemove_x = 0;
75static int last_mousemove_y = 0;
791f420f 76
af3a05ed
JR
77/* Define GET_WHEEL_DELTA_WPARAM macro if system headers don't. */
78#ifndef GET_WHEEL_DELTA_WPARAM
79#define GET_WHEEL_DELTA_WPARAM(wparam) ((short)HIWORD (wparam))
80#endif
81
791f420f
JR
82/* Non-zero means that a HELP_EVENT has been generated since Emacs
83 start. */
84
85static int any_help_event_p;
86
a18bb28d
JR
87/* Last window where we saw the mouse. Used by mouse-autoselect-window. */
88static Lisp_Object last_window;
89
e7efd97e
GV
90extern unsigned int msh_mousewheel;
91
b56ceb92 92extern void free_frame_menubar (struct frame *);
ee78dc32 93
9ef2e2cf 94extern int w32_codepage_for_font (char *fontname);
2bf04b9d 95extern Cursor w32_load_cursor (LPCTSTR name);
9ef2e2cf 96
ee78dc32
GV
97#define x_any_window_to_frame x_window_to_frame
98#define x_top_window_to_frame x_window_to_frame
99
100\f
fbd6baed
GV
101/* This is display since w32 does not support multiple ones. */
102struct w32_display_info one_w32_display_info;
8c3b00cb 103struct w32_display_info *x_display_list;
ee78dc32
GV
104
105/* This is a list of cons cells, each of the form (NAME . FONT-LIST-CACHE),
fbd6baed 106 one for each element of w32_display_list and in the same order.
ee78dc32
GV
107 NAME is the name of the frame.
108 FONT-LIST-CACHE records previous values returned by x-list-fonts. */
fbd6baed 109Lisp_Object w32_display_name_list;
ee78dc32 110
41375f89 111
62aba0d4 112#if _WIN32_WINNT < 0x0500
41375f89
JR
113/* Pre Windows 2000, this was not available, but define it here so
114 that Emacs compiled on such a platform will run on newer versions. */
115
116typedef struct tagWCRANGE
117{
118 WCHAR wcLow;
119 USHORT cGlyphs;
120} WCRANGE;
121
65a6ff8f 122typedef struct tagGLYPHSET
41375f89
JR
123{
124 DWORD cbThis;
125 DWORD flAccel;
126 DWORD cGlyphsSupported;
127 DWORD cRanges;
128 WCRANGE ranges[1];
65a6ff8f 129} GLYPHSET;
41375f89 130
0fda9b75 131#endif /* compiling for pre-Win2k */
41375f89 132
8b61a891 133/* Dynamic linking to SetLayeredWindowAttribute (only since 2000). */
ff90fbde 134BOOL (WINAPI *pfnSetLayeredWindowAttributes) (HWND, COLORREF, BYTE, DWORD);
8b61a891
JR
135
136#ifndef LWA_ALPHA
137#define LWA_ALPHA 0x02
138#endif
ec7e221c
JR
139/* WS_EX_LAYERED is defined unconditionally by MingW, but only for W2K and
140 later targets by MSVC headers. */
141#ifndef WS_EX_LAYERED
142#define WS_EX_LAYERED 0x80000
143#endif
41375f89 144
ee78dc32
GV
145/* This is a frame waiting to be autoraised, within w32_read_socket. */
146struct frame *pending_autoraise_frame;
147
abb15ebd
JR
148/* The handle of the frame that currently owns the system caret. */
149HWND w32_system_caret_hwnd;
abb15ebd
JR
150int w32_system_caret_height;
151int w32_system_caret_x;
152int w32_system_caret_y;
e9e23e23
GV
153DWORD dwWindowsThreadId = 0;
154HANDLE hWindowsThread = NULL;
ee78dc32
GV
155DWORD dwMainThreadId = 0;
156HANDLE hMainThread = NULL;
157
689004fa
GV
158int vertical_scroll_bar_min_handle;
159int vertical_scroll_bar_top_border;
160int vertical_scroll_bar_bottom_border;
161
162int last_scroll_bar_drag_pos;
163
302fc036
EZ
164/* Keyboard code page - may be changed by language-change events. */
165int w32_keyboard_codepage;
166
ee78dc32
GV
167/* Mouse movement. */
168
169/* Where the mouse was last time we reported a mouse event. */
ee78dc32 170static RECT last_mouse_glyph;
d3499758 171static FRAME_PTR last_mouse_glyph_frame;
ee78dc32
GV
172
173/* The scroll bar in which the last motion event occurred.
174
175 If the last motion event occurred in a scroll bar, we set this
fbd6baed 176 so w32_mouse_position can know whether to report a scroll bar motion or
ee78dc32
GV
177 an ordinary motion.
178
179 If the last motion event didn't occur in a scroll bar, we set this
fbd6baed 180 to Qnil, to tell w32_mouse_position to return an ordinary motion event. */
9ef2e2cf
JR
181static Lisp_Object last_mouse_scroll_bar;
182static int last_mouse_scroll_bar_pos;
ee78dc32 183
fbd6baed 184/* This is a hack. We would really prefer that w32_mouse_position would
ee78dc32 185 return the time associated with the position it returns, but there
9ef2e2cf 186 doesn't seem to be any way to wrest the time-stamp from the server
ee78dc32
GV
187 along with the position query. So, we just keep track of the time
188 of the last movement we received, and return that in hopes that
189 it's somewhat accurate. */
9ef2e2cf
JR
190static Time last_mouse_movement_time;
191
192/* Incremented by w32_read_socket whenever it really tries to read
193 events. */
ee78dc32
GV
194#ifdef __STDC__
195static int volatile input_signal_count;
196#else
197static int input_signal_count;
198#endif
199
0fda9b75
DC
200#ifdef CYGWIN
201int w32_message_fd = -1;
202#endif /* CYGWIN */
203
f57e2426
J
204static void x_update_window_end (struct window *, int, int);
205static void w32_handle_tool_bar_click (struct frame *,
206 struct input_event *);
207static void w32_define_cursor (Window, Cursor);
208
209void x_lower_frame (struct frame *);
210void x_scroll_bar_clear (struct frame *);
18e27ea8 211void x_wm_set_size_hint (struct frame *, long, bool);
f57e2426
J
212void x_raise_frame (struct frame *);
213void x_set_window_size (struct frame *, int, int, int);
214void x_wm_set_window_state (struct frame *, int);
215void x_wm_set_icon_pixmap (struct frame *, int);
216static void w32_initialize (void);
217static void x_update_end (struct frame *);
218static void w32_frame_up_to_date (struct frame *);
219static void w32_set_terminal_modes (struct terminal *);
220static void w32_reset_terminal_modes (struct terminal *);
221static void x_clear_frame (struct frame *);
222static void frame_highlight (struct frame *);
223static void frame_unhighlight (struct frame *);
224static void x_new_focus_frame (struct w32_display_info *,
225 struct frame *);
226static void x_focus_changed (int, int, struct w32_display_info *,
227 struct frame *, struct input_event *);
228static void w32_detect_focus_change (struct w32_display_info *,
229 W32Msg *, struct input_event *);
230static void w32_frame_rehighlight (struct frame *);
231static void x_frame_rehighlight (struct w32_display_info *);
232static void x_draw_hollow_cursor (struct window *, struct glyph_row *);
233static void x_draw_bar_cursor (struct window *, struct glyph_row *, int,
234 enum text_cursor_kinds);
235static void w32_clip_to_row (struct window *, struct glyph_row *, int, HDC);
236static BOOL my_show_window (struct frame *, HWND, int);
237static void my_set_window_pos (HWND, HWND, int, int, int, int, UINT);
361358ea 238#if 0
f57e2426 239static void my_set_focus (struct frame *, HWND);
361358ea 240#endif
f57e2426
J
241static void my_set_foreground_window (HWND);
242static void my_destroy_window (struct frame *, HWND);
791f420f 243
e509cfa6 244#ifdef GLYPH_DEBUG
784b56e2
EZ
245static void x_check_font (struct frame *, struct font *);
246#endif
247
ee78dc32 248static Lisp_Object Qvendor_specific_keysyms;
477f1e50
EZ
249static Lisp_Object Qadded, Qremoved, Qmodified;
250static Lisp_Object Qrenamed_from, Qrenamed_to;
ee78dc32 251
ee78dc32 252\f
9ef2e2cf
JR
253/***********************************************************************
254 Debugging
255 ***********************************************************************/
256
ee78dc32 257#if 0
9ef2e2cf
JR
258
259/* This is a function useful for recording debugging information about
260 the sequence of occurrences in this file. */
ee78dc32 261
d67d1627 262struct record
ee78dc32
GV
263{
264 char *locus;
265 int type;
266};
267
268struct record event_record[100];
269
270int event_record_index;
271
b56ceb92 272record_event (char *locus, int type)
ee78dc32
GV
273{
274 if (event_record_index == sizeof (event_record) / sizeof (struct record))
275 event_record_index = 0;
276
277 event_record[event_record_index].locus = locus;
278 event_record[event_record_index].type = type;
279 event_record_index++;
280}
281
282#endif /* 0 */
283\f
791f420f 284
c65fd370 285void
b56ceb92 286XChangeGC (void *ignore, XGCValues *gc, unsigned long mask,
c65fd370 287 XGCValues *xgcv)
791f420f
JR
288{
289 if (mask & GCForeground)
290 gc->foreground = xgcv->foreground;
291 if (mask & GCBackground)
292 gc->background = xgcv->background;
293 if (mask & GCFont)
294 gc->font = xgcv->font;
295}
296
b56ceb92
JB
297XGCValues *
298XCreateGC (void *ignore, Window window, unsigned long mask, XGCValues *xgcv)
791f420f 299{
23f86fce 300 XGCValues *gc = xzalloc (sizeof (XGCValues));
791f420f
JR
301
302 XChangeGC (ignore, gc, mask, xgcv);
303
304 return gc;
305}
306
c65fd370 307void
b56ceb92
JB
308XGetGCValues (void *ignore, XGCValues *gc,
309 unsigned long mask, XGCValues *xgcv)
791f420f
JR
310{
311 XChangeGC (ignore, xgcv, mask, gc);
312}
313
791f420f
JR
314static void
315w32_set_clip_rectangle (HDC hdc, RECT *rect)
316{
317 if (rect)
318 {
319 HRGN clip_region = CreateRectRgnIndirect (rect);
320 SelectClipRgn (hdc, clip_region);
321 DeleteObject (clip_region);
322 }
323 else
324 SelectClipRgn (hdc, NULL);
325}
326
9b0e3eba
AA
327/* Restore clipping rectangle in S */
328static void
329w32_restore_glyph_string_clip (struct glyph_string *s)
330{
331 RECT *r = s->clip;
332 int n = s->num_clips;
333
334 if (n == 1)
335 w32_set_clip_rectangle (s->hdc, r);
336 else if (n > 1)
337 {
338 HRGN clip1 = CreateRectRgnIndirect (r);
339 HRGN clip2 = CreateRectRgnIndirect (r + 1);
340 if (CombineRgn (clip1, clip1, clip2, RGN_OR) != ERROR)
341 SelectClipRgn (s->hdc, clip1);
342 DeleteObject (clip1);
343 DeleteObject (clip2);
344 }
345}
346
347/*
348 Draw a wavy line under S. The wave fills wave_height pixels from y0.
349
350 x0 wave_length = 2
351 --
352 y0 * * * * *
353 |* * * * * * * * *
354 wave_height = 3 | * * * *
355
356*/
357
358void
359w32_draw_underwave (struct glyph_string *s, COLORREF color)
360{
361 int wave_height = 2, wave_length = 3;
362 int dx, dy, x0, y0, width, x1, y1, x2, y2, odd, xmax;
363 XRectangle wave_clip, string_clip, final_clip;
364 RECT w32_final_clip, w32_string_clip;
365 HPEN hp, oldhp;
366
367 dx = wave_length;
368 dy = wave_height - 1;
369 x0 = s->x;
370 y0 = s->ybase + 1;
371 width = s->width;
372 xmax = x0 + width;
373
374 /* Find and set clipping rectangle */
375
62aba0d4
FP
376 wave_clip.x = x0;
377 wave_clip.y = y0;
378 wave_clip.width = width;
379 wave_clip.height = wave_height;
380
9b0e3eba
AA
381 get_glyph_string_clip_rect (s, &w32_string_clip);
382 CONVERT_TO_XRECT (string_clip, w32_string_clip);
383
384 if (!x_intersect_rectangles (&wave_clip, &string_clip, &final_clip))
385 return;
386
387 hp = CreatePen (PS_SOLID, 0, color);
388 oldhp = SelectObject (s->hdc, hp);
389 CONVERT_FROM_XRECT (final_clip, w32_final_clip);
390 w32_set_clip_rectangle (s->hdc, &w32_final_clip);
391
392 /* Draw the waves */
393
394 x1 = x0 - (x0 % dx);
395 x2 = x1 + dx;
396 odd = (x1/dx) % 2;
397 y1 = y2 = y0;
398
399 if (odd)
400 y1 += dy;
401 else
402 y2 += dy;
403
404 MoveToEx (s->hdc, x1, y1, NULL);
405
406 while (x1 <= xmax)
407 {
408 LineTo (s->hdc, x2, y2);
409 x1 = x2, y1 = y2;
410 x2 += dx, y2 = y0 + odd*dy;
411 odd = !odd;
412 }
413
414 /* Restore previous pen and clipping rectangle(s) */
415 w32_restore_glyph_string_clip (s);
416 SelectObject (s->hdc, oldhp);
417 DeleteObject (hp);
418}
791f420f
JR
419
420/* Draw a hollow rectangle at the specified position. */
421void
422w32_draw_rectangle (HDC hdc, XGCValues *gc, int x, int y,
423 int width, int height)
424{
425 HBRUSH hb, oldhb;
426 HPEN hp, oldhp;
427
428 hb = CreateSolidBrush (gc->background);
429 hp = CreatePen (PS_SOLID, 0, gc->foreground);
430 oldhb = SelectObject (hdc, hb);
431 oldhp = SelectObject (hdc, hp);
432
433 Rectangle (hdc, x, y, x + width, y + height);
434
435 SelectObject (hdc, oldhb);
436 SelectObject (hdc, oldhp);
437 DeleteObject (hb);
438 DeleteObject (hp);
439}
440
441/* Draw a filled rectangle at the specified position. */
d67d1627 442void
b56ceb92 443w32_fill_rect (FRAME_PTR f, HDC hdc, COLORREF pix, RECT *lprect)
ee78dc32 444{
ee78dc32 445 HBRUSH hb;
791f420f 446
ee78dc32 447 hb = CreateSolidBrush (pix);
ee78dc32 448 FillRect (hdc, lprect, hb);
ee78dc32 449 DeleteObject (hb);
ee78dc32
GV
450}
451
d67d1627 452void
b56ceb92 453w32_clear_window (FRAME_PTR f)
ee78dc32
GV
454{
455 RECT rect;
00fe468b 456 HDC hdc = get_frame_dc (f);
52cf03a1 457
e4a52412
JR
458 /* Under certain conditions, this can be called at startup with
459 a console frame pointer before the GUI frame is created. An HDC
460 of 0 indicates this. */
461 if (hdc)
462 {
463 GetClientRect (FRAME_W32_WINDOW (f), &rect);
464 w32_clear_rect (f, hdc, &rect);
465 }
466
00fe468b 467 release_frame_dc (f, hdc);
ee78dc32
GV
468}
469
8b61a891
JR
470#define OPAQUE_FRAME 255
471
472void
b56ceb92 473x_set_frame_alpha (struct frame *f)
8b61a891
JR
474{
475 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
476 double alpha = 1.0;
477 double alpha_min = 1.0;
478 BYTE opac;
479 LONG ex_style;
480 HWND window = FRAME_W32_WINDOW (f);
481
482 /* Older versions of Windows do not support transparency. */
483 if (!pfnSetLayeredWindowAttributes)
484 return;
485
486 if (dpyinfo->x_highlight_frame == f)
487 alpha = f->alpha[0];
488 else
489 alpha = f->alpha[1];
490
491 if (FLOATP (Vframe_alpha_lower_limit))
492 alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
493 else if (INTEGERP (Vframe_alpha_lower_limit))
494 alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
495
2f8e69cc
CY
496 if (alpha < 0.0)
497 return;
498 else if (alpha > 1.0)
8b61a891
JR
499 alpha = 1.0;
500 else if (alpha < alpha_min && alpha_min <= 1.0)
501 alpha = alpha_min;
502
503 opac = alpha * OPAQUE_FRAME;
504
505 ex_style = GetWindowLong (window, GWL_EXSTYLE);
506
507 if (opac == OPAQUE_FRAME)
4e179b19 508 ex_style &= ~WS_EX_LAYERED;
8b61a891
JR
509 else
510 ex_style |= WS_EX_LAYERED;
511
512 SetWindowLong (window, GWL_EXSTYLE, ex_style);
513
514 if (opac != OPAQUE_FRAME)
515 pfnSetLayeredWindowAttributes (window, 0, opac, LWA_ALPHA);
516}
517
b89c78a5 518int
b56ceb92 519x_display_pixel_height (struct w32_display_info *dpyinfo)
b89c78a5 520{
cb4a3e42
JR
521 HDC dc = GetDC (NULL);
522 int pixels = GetDeviceCaps (dc, VERTRES);
523 ReleaseDC (NULL, dc);
524 return pixels;
b89c78a5
CY
525}
526
527int
b56ceb92 528x_display_pixel_width (struct w32_display_info *dpyinfo)
b89c78a5 529{
cb4a3e42
JR
530 HDC dc = GetDC (NULL);
531 int pixels = GetDeviceCaps (dc, HORZRES);
532 ReleaseDC (NULL, dc);
533 return pixels;
b89c78a5
CY
534}
535
ee78dc32 536\f
791f420f
JR
537/***********************************************************************
538 Starting and ending an update
539 ***********************************************************************/
d67d1627 540
791f420f
JR
541/* Start an update of frame F. This function is installed as a hook
542 for update_begin, i.e. it is called when update_begin is called.
543 This function is called prior to calls to x_update_window_begin for
99012074 544 each window being updated. */
ee78dc32 545
96214669 546static void
b56ceb92 547x_update_begin (struct frame *f)
ee78dc32 548{
99012074
AI
549 struct w32_display_info *display_info = FRAME_W32_DISPLAY_INFO (f);
550
7e6ac5b9
AI
551 if (! FRAME_W32_P (f))
552 return;
553
99012074
AI
554 /* Regenerate display palette before drawing if list of requested
555 colors has changed. */
556 if (display_info->regen_palette)
557 {
558 w32_regenerate_palette (f);
559 display_info->regen_palette = FALSE;
560 }
791f420f 561}
ee78dc32 562
791f420f
JR
563
564/* Start update of window W. Set the global variable updated_window
565 to the window being updated and set output_cursor to the cursor
566 position of W. */
567
568static void
b56ceb92 569x_update_window_begin (struct window *w)
791f420f
JR
570{
571 struct frame *f = XFRAME (WINDOW_FRAME (w));
bbf534ce 572 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
791f420f 573
99558ce8 574 /* Hide the system caret during an update. */
9785d95b
BK
575 if (w32_use_visible_system_caret && w32_system_caret_hwnd)
576 {
577 SendMessage (w32_system_caret_hwnd, WM_EMACS_HIDE_CARET, 0, 0);
578 }
99558ce8 579
791f420f
JR
580 updated_window = w;
581 set_output_cursor (&w->cursor);
ee78dc32 582
4d7e6e51 583 block_input ();
ee78dc32 584
bbf534ce 585 if (f == hlinfo->mouse_face_mouse_frame)
ee78dc32
GV
586 {
587 /* Don't do highlighting for mouse motion during the update. */
bbf534ce 588 hlinfo->mouse_face_defer = 1;
ee78dc32 589
9ef2e2cf
JR
590 /* If F needs to be redrawn, simply forget about any prior mouse
591 highlighting. */
ee78dc32 592 if (FRAME_GARBAGED_P (f))
bbf534ce 593 hlinfo->mouse_face_window = Qnil;
791f420f 594
ec48c3a7
JR
595#if 0 /* Rows in a current matrix containing glyphs in mouse-face have
596 their mouse_face_p flag set, which means that they are always
597 unequal to rows in a desired matrix which never have that
598 flag set. So, rows containing mouse-face glyphs are never
599 scrolled, and we don't have to switch the mouse highlight off
600 here to prevent it from being scrolled. */
d67d1627 601
791f420f
JR
602 /* Can we tell that this update does not affect the window
603 where the mouse highlight is? If so, no need to turn off.
604 Likewise, don't do anything if the frame is garbaged;
605 in that case, the frame's current matrix that we would use
606 is all wrong, and we will redisplay that line anyway. */
bbf534ce
EZ
607 if (!NILP (hlinfo->mouse_face_window)
608 && w == XWINDOW (hlinfo->mouse_face_window))
ee78dc32 609 {
791f420f 610 int i;
ee78dc32 611
791f420f
JR
612 for (i = 0; i < w->desired_matrix->nrows; ++i)
613 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i))
ee78dc32
GV
614 break;
615
791f420f 616 if (i < w->desired_matrix->nrows)
bbf534ce 617 clear_mouse_face (hlinfo);
ee78dc32 618 }
ec48c3a7 619#endif /* 0 */
ee78dc32
GV
620 }
621
4d7e6e51 622 unblock_input ();
ee78dc32
GV
623}
624
89271099 625/* Draw a vertical window border from (x,y0) to (x,y1) */
791f420f 626
96214669 627static void
b56ceb92 628w32_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
ee78dc32 629{
791f420f 630 struct frame *f = XFRAME (WINDOW_FRAME (w));
89271099
KS
631 RECT r;
632 HDC hdc;
cf2c08ca 633 struct face *face;
1c64a4a2 634
89271099
KS
635 r.left = x;
636 r.right = x + 1;
637 r.top = y0;
638 r.bottom = y1;
d67d1627 639
89271099 640 hdc = get_frame_dc (f);
cf2c08ca
EZ
641 face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
642 if (face)
643 w32_fill_rect (f, hdc, face->foreground, &r);
644 else
645 w32_fill_rect (f, hdc, FRAME_FOREGROUND_PIXEL (f), &r);
646
89271099 647 release_frame_dc (f, hdc);
791f420f 648}
ee78dc32 649
d67d1627 650
ec48c3a7
JR
651/* End update of window W (which is equal to updated_window).
652
653 Draw vertical borders between horizontally adjacent windows, and
654 display W's cursor if CURSOR_ON_P is non-zero.
655
656 MOUSE_FACE_OVERWRITTEN_P non-zero means that some row containing
657 glyphs in mouse-face were overwritten. In that case we have to
658 make sure that the mouse-highlight is properly redrawn.
659
660 W may be a menu bar pseudo-window in case we don't have X toolkit
661 support. Such windows don't have a cursor, so don't display it
662 here. */
791f420f
JR
663
664static void
b56ceb92
JB
665x_update_window_end (struct window *w, int cursor_on_p,
666 int mouse_face_overwritten_p)
791f420f 667{
d3d50620 668 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (XFRAME (w->frame));
9f5a911b 669
791f420f
JR
670 if (!w->pseudo_window_p)
671 {
4d7e6e51 672 block_input ();
ec48c3a7 673
791f420f 674 if (cursor_on_p)
89271099
KS
675 display_and_set_cursor (w, 1, output_cursor.hpos,
676 output_cursor.vpos,
677 output_cursor.x, output_cursor.y);
d67d1627 678
f94a2622
KS
679 if (draw_window_fringes (w, 1))
680 x_draw_vertical_border (w);
6b61353c 681
4d7e6e51 682 unblock_input ();
791f420f 683 }
9f5a911b
JR
684
685 /* If a row with mouse-face was overwritten, arrange for
686 XTframe_up_to_date to redisplay the mouse highlight. */
687 if (mouse_face_overwritten_p)
688 {
bbf534ce
EZ
689 hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
690 hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
691 hlinfo->mouse_face_window = Qnil;
9f5a911b
JR
692 }
693
99558ce8
JR
694 /* Unhide the caret. This won't actually show the cursor, unless it
695 was visible before the corresponding call to HideCaret in
696 x_update_window_begin. */
9785d95b
BK
697 if (w32_use_visible_system_caret && w32_system_caret_hwnd)
698 {
699 SendMessage (w32_system_caret_hwnd, WM_EMACS_SHOW_CARET, 0, 0);
700 }
99558ce8 701
791f420f
JR
702 updated_window = NULL;
703}
704
9ef2e2cf
JR
705
706/* End update of frame F. This function is installed as a hook in
707 update_end. */
708
791f420f 709static void
b56ceb92 710x_update_end (struct frame *f)
791f420f 711{
7e6ac5b9
AI
712 if (! FRAME_W32_P (f))
713 return;
714
791f420f 715 /* Mouse highlight may be displayed again. */
bbf534ce 716 MOUSE_HL_INFO (f)->mouse_face_defer = 0;
ee78dc32
GV
717}
718
9ef2e2cf 719
791f420f
JR
720/* This function is called from various places in xdisp.c whenever a
721 complete update has been performed. The global variable
722 updated_window is not available here. */
ee78dc32 723
96214669 724static void
b56ceb92 725w32_frame_up_to_date (struct frame *f)
ee78dc32 726{
791f420f 727 if (FRAME_W32_P (f))
ee78dc32 728 {
bbf534ce 729 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
89271099 730
bbf534ce
EZ
731 if (hlinfo->mouse_face_deferred_gc
732 || f == hlinfo->mouse_face_mouse_frame)
791f420f 733 {
4d7e6e51 734 block_input ();
bbf534ce
EZ
735 if (hlinfo->mouse_face_mouse_frame)
736 note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
737 hlinfo->mouse_face_mouse_x,
738 hlinfo->mouse_face_mouse_y);
739 hlinfo->mouse_face_deferred_gc = 0;
4d7e6e51 740 unblock_input ();
791f420f 741 }
ee78dc32
GV
742 }
743}
791f420f
JR
744
745
746/* Draw truncation mark bitmaps, continuation mark bitmaps, overlay
33c34bea 747 arrow bitmaps, or clear the fringes if no bitmaps are required
791f420f 748 before DESIRED_ROW is made current. The window being updated is
b71b8111 749 found in updated_window. This function is called from
791f420f
JR
750 update_window_line only if it is known that there are differences
751 between bitmaps to be drawn between current row and DESIRED_ROW. */
752
753static void
b56ceb92 754x_after_update_window_line (struct glyph_row *desired_row)
791f420f
JR
755{
756 struct window *w = updated_window;
6ff3e5e3
JR
757 struct frame *f;
758 int width, height;
759
a54e2c05 760 eassert (w);
d67d1627 761
791f420f 762 if (!desired_row->mode_line_p && !w->pseudo_window_p)
6b61353c 763 desired_row->redraw_fringe_bitmaps_p = 1;
791f420f 764
6ff3e5e3
JR
765 /* When a window has disappeared, make sure that no rest of
766 full-width rows stays visible in the internal border. Could
767 check here if updated_window is the leftmost/rightmost window,
768 but I guess it's not worth doing since vertically split windows
769 are almost never used, internal border is rarely set, and the
770 overhead is very small. */
771 if (windows_or_buffers_changed
772 && desired_row->full_width_p
d3d50620 773 && (f = XFRAME (w->frame),
6ff3e5e3
JR
774 width = FRAME_INTERNAL_BORDER_WIDTH (f),
775 width != 0)
776 && (height = desired_row->visible_height,
777 height > 0))
778 {
779 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
89271099 780
4d7e6e51 781 block_input ();
6ff3e5e3
JR
782 {
783 HDC hdc = get_frame_dc (f);
784 w32_clear_area (f, hdc, 0, y, width, height);
62e50ec6 785 w32_clear_area (f, hdc, FRAME_PIXEL_WIDTH (f) - width,
6ff3e5e3
JR
786 y, width, height);
787 release_frame_dc (f, hdc);
788 }
4d7e6e51 789 unblock_input ();
791f420f
JR
790 }
791}
792
793
33c34bea 794/* Draw the bitmap WHICH in one of the left or right fringes of
791f420f
JR
795 window W. ROW is the glyph row for which to display the bitmap; it
796 determines the vertical position at which the bitmap has to be
797 drawn. */
798
799static void
b56ceb92
JB
800w32_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
801 struct draw_fringe_bitmap_params *p)
791f420f
JR
802{
803 struct frame *f = XFRAME (WINDOW_FRAME (w));
b6ae1532
KS
804 HDC hdc;
805 struct face *face = p->face;
806
807 hdc = get_frame_dc (f);
791f420f 808
06929222
YM
809 if (!p->overlay_p)
810 {
811 int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
812
813 /* If the fringe is adjacent to the left (right) scroll bar of a
814 leftmost (rightmost, respectively) window, then extend its
815 background to the gap between the fringe and the bar. */
816 if ((WINDOW_LEFTMOST_P (w)
817 && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
818 || (WINDOW_RIGHTMOST_P (w)
819 && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w)))
820 {
821 int sb_width = WINDOW_CONFIG_SCROLL_BAR_WIDTH (w);
822
823 if (sb_width > 0)
824 {
7db47798
YM
825 int bar_area_x = WINDOW_SCROLL_BAR_AREA_X (w);
826 int bar_area_width = (WINDOW_CONFIG_SCROLL_BAR_COLS (w)
827 * FRAME_COLUMN_WIDTH (f));
06929222
YM
828
829 if (bx < 0)
830 {
831 /* Bitmap fills the fringe. */
7db47798
YM
832 if (bar_area_x + bar_area_width == p->x)
833 bx = bar_area_x + sb_width;
834 else if (p->x + p->wd == bar_area_x)
835 bx = bar_area_x;
06929222
YM
836 if (bx >= 0)
837 {
838 int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
839
7db47798 840 nx = bar_area_width - sb_width;
06929222
YM
841 by = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
842 row->y));
843 ny = row->visible_height;
844 }
845 }
846 else
847 {
7db47798 848 if (bar_area_x + bar_area_width == bx)
06929222 849 {
7db47798
YM
850 bx = bar_area_x + sb_width;
851 nx += bar_area_width - sb_width;
06929222 852 }
7db47798
YM
853 else if (bx + nx == bar_area_x)
854 nx += bar_area_width - sb_width;
06929222
YM
855 }
856 }
857 }
858
859 if (bx >= 0 && nx > 0)
860 w32_fill_area (f, hdc, face->background, bx, by, nx, ny);
861 }
862
791f420f 863 /* Must clip because of partially visible lines. */
5a874e95 864 w32_clip_to_row (w, row, -1, hdc);
791f420f 865
0e9e9a2c 866 if (p->which && p->which < max_fringe_bmp)
b6ae1532
KS
867 {
868 HBITMAP pixmap = fringe_bmp[p->which];
869 HDC compat_hdc;
870 HANDLE horig_obj;
791f420f 871
b6ae1532 872 compat_hdc = CreateCompatibleDC (hdc);
6b61353c 873
b6ae1532 874 SaveDC (hdc);
791f420f 875
b6ae1532 876 horig_obj = SelectObject (compat_hdc, pixmap);
fccb8288 877
6b61353c
KH
878 /* Paint overlays transparently. */
879 if (p->overlay_p)
880 {
881 HBRUSH h_brush, h_orig_brush;
882
883 SetTextColor (hdc, BLACK_PIX_DEFAULT (f));
884 SetBkColor (hdc, WHITE_PIX_DEFAULT (f));
885 h_brush = CreateSolidBrush (face->foreground);
886 h_orig_brush = SelectObject (hdc, h_brush);
887
888 BitBlt (hdc, p->x, p->y, p->wd, p->h,
889 compat_hdc, 0, p->dh,
890 DSTINVERT);
891 BitBlt (hdc, p->x, p->y, p->wd, p->h,
892 compat_hdc, 0, p->dh,
893 0x2E064A);
894 BitBlt (hdc, p->x, p->y, p->wd, p->h,
895 compat_hdc, 0, p->dh,
896 DSTINVERT);
897
898 SelectObject (hdc, h_orig_brush);
899 DeleteObject (h_brush);
900 }
901 else
902 {
903 SetTextColor (hdc, face->background);
904 SetBkColor (hdc, (p->cursor_p
905 ? f->output_data.w32->cursor_pixel
906 : face->foreground));
907
908 BitBlt (hdc, p->x, p->y, p->wd, p->h,
909 compat_hdc, 0, p->dh,
910 SRCCOPY);
911 }
791f420f 912
b6ae1532
KS
913 SelectObject (compat_hdc, horig_obj);
914 DeleteDC (compat_hdc);
915 RestoreDC (hdc, -1);
d33c49e8 916 }
791f420f 917
b6ae1532 918 w32_set_clip_rectangle (hdc, NULL);
791f420f 919
791f420f
JR
920 release_frame_dc (f, hdc);
921}
922
6b61353c 923static void
b56ceb92 924w32_define_fringe_bitmap (int which, unsigned short *bits, int h, int wd)
6b61353c 925{
0e9e9a2c
KS
926 if (which >= max_fringe_bmp)
927 {
928 int i = max_fringe_bmp;
929 max_fringe_bmp = which + 20;
930 fringe_bmp = (HBITMAP *) xrealloc (fringe_bmp, max_fringe_bmp * sizeof (HBITMAP));
931 while (i < max_fringe_bmp)
932 fringe_bmp[i++] = 0;
933 }
934
6b61353c
KH
935 fringe_bmp[which] = CreateBitmap (wd, h, 1, 1, bits);
936}
937
938static void
b56ceb92 939w32_destroy_fringe_bitmap (int which)
6b61353c 940{
0e9e9a2c
KS
941 if (which >= max_fringe_bmp)
942 return;
943
6b61353c
KH
944 if (fringe_bmp[which])
945 DeleteObject (fringe_bmp[which]);
946 fringe_bmp[which] = 0;
947}
948
949
ee78dc32 950\f
9ef2e2cf
JR
951/* This is called when starting Emacs and when restarting after
952 suspend. When starting Emacs, no window is mapped. And nothing
953 must be done to Emacs's own window if it is suspended (though that
954 rarely happens). */
ee78dc32 955
96214669 956static void
4a418b10 957w32_set_terminal_modes (struct terminal *term)
ee78dc32
GV
958{
959}
960
9d4f32e8 961/* This is called when exiting or suspending Emacs. Exiting will make
9ef2e2cf 962 the W32 windows go away, and suspending requires no action. */
ee78dc32 963
96214669 964static void
4a418b10 965w32_reset_terminal_modes (struct terminal *term)
ee78dc32
GV
966{
967}
791f420f 968
9ef2e2cf 969
ee78dc32 970\f
791f420f
JR
971/***********************************************************************
972 Display Iterator
973 ***********************************************************************/
974
975/* Function prototypes of this page. */
976
f57e2426
J
977static void x_set_glyph_string_clipping (struct glyph_string *);
978static void x_set_glyph_string_gc (struct glyph_string *);
979static void x_draw_glyph_string_background (struct glyph_string *,
980 int);
981static void x_draw_glyph_string_foreground (struct glyph_string *);
982static void x_draw_composite_glyph_string_foreground (struct glyph_string *);
983static void x_draw_glyph_string_box (struct glyph_string *);
984static void x_draw_glyph_string (struct glyph_string *);
985static void x_set_cursor_gc (struct glyph_string *);
986static void x_set_mode_line_face_gc (struct glyph_string *);
987static void x_set_mouse_face_gc (struct glyph_string *);
791f420f 988static int w32_alloc_lighter_color (struct frame *, COLORREF *, double, int);
f57e2426
J
989static void w32_setup_relief_color (struct frame *, struct relief *,
990 double, int, COLORREF);
991static void x_setup_relief_colors (struct glyph_string *);
992static void x_draw_image_glyph_string (struct glyph_string *);
993static void x_draw_image_relief (struct glyph_string *);
994static void x_draw_image_foreground (struct glyph_string *);
995static void w32_draw_image_foreground_1 (struct glyph_string *, HBITMAP);
996static void x_clear_glyph_string_rect (struct glyph_string *, int,
997 int, int, int);
998static void w32_draw_relief_rect (struct frame *, int, int, int, int,
999 int, int, int, int, int, int,
1000 RECT *);
1001static void w32_draw_box_rect (struct glyph_string *, int, int, int, int,
1002 int, int, int, RECT *);
c2cc16fa 1003
d67d1627 1004
791f420f
JR
1005/* Set S->gc to a suitable GC for drawing glyph string S in cursor
1006 face. */
1007
1008static void
b56ceb92 1009x_set_cursor_gc (struct glyph_string *s)
791f420f
JR
1010{
1011 if (s->font == FRAME_FONT (s->f)
1012 && s->face->background == FRAME_BACKGROUND_PIXEL (s->f)
1013 && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f)
1014 && !s->cmp)
1015 s->gc = s->f->output_data.w32->cursor_gc;
1016 else
1017 {
1018 /* Cursor on non-default face: must merge. */
1019 XGCValues xgcv;
1020 unsigned long mask;
1021
1022 xgcv.background = s->f->output_data.w32->cursor_pixel;
1023 xgcv.foreground = s->face->background;
1024
1025 /* If the glyph would be invisible, try a different foreground. */
1026 if (xgcv.foreground == xgcv.background)
1027 xgcv.foreground = s->face->foreground;
1028 if (xgcv.foreground == xgcv.background)
1029 xgcv.foreground = s->f->output_data.w32->cursor_foreground_pixel;
1030 if (xgcv.foreground == xgcv.background)
1031 xgcv.foreground = s->face->foreground;
1032
1033 /* Make sure the cursor is distinct from text in this face. */
1034 if (xgcv.background == s->face->background
1035 && xgcv.foreground == s->face->foreground)
1036 {
1037 xgcv.background = s->face->foreground;
1038 xgcv.foreground = s->face->background;
1039 }
1040
1041 IF_DEBUG (x_check_font (s->f, s->font));
1042 xgcv.font = s->font;
1043 mask = GCForeground | GCBackground | GCFont;
1044
1045 if (FRAME_W32_DISPLAY_INFO (s->f)->scratch_cursor_gc)
1046 XChangeGC (NULL, FRAME_W32_DISPLAY_INFO (s->f)->scratch_cursor_gc,
1047 mask, &xgcv);
1048 else
1049 FRAME_W32_DISPLAY_INFO (s->f)->scratch_cursor_gc
1050 = XCreateGC (NULL, s->window, mask, &xgcv);
1051
1052 s->gc = FRAME_W32_DISPLAY_INFO (s->f)->scratch_cursor_gc;
1053 }
1054}
1055
1056
1057/* Set up S->gc of glyph string S for drawing text in mouse face. */
d67d1627 1058
791f420f 1059static void
b56ceb92 1060x_set_mouse_face_gc (struct glyph_string *s)
d67d1627 1061{
791f420f 1062 int face_id;
93ff4395 1063 struct face *face;
791f420f 1064
c2cc16fa 1065 /* What face has to be used last for the mouse face? */
bbf534ce 1066 face_id = MOUSE_HL_INFO (s->f)->mouse_face_face_id;
93ff4395 1067 face = FACE_FROM_ID (s->f, face_id);
c2cc16fa
JR
1068 if (face == NULL)
1069 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
d67d1627 1070
c2cc16fa 1071 if (s->first_glyph->type == CHAR_GLYPH)
14ee5d4c 1072 face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch, -1, Qnil);
c2cc16fa 1073 else
14ee5d4c 1074 face_id = FACE_FOR_CHAR (s->f, face, 0, -1, Qnil);
791f420f
JR
1075 s->face = FACE_FROM_ID (s->f, face_id);
1076 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
1077
1078 /* If font in this face is same as S->font, use it. */
1079 if (s->font == s->face->font)
1080 s->gc = s->face->gc;
1081 else
1082 {
1083 /* Otherwise construct scratch_cursor_gc with values from FACE
1084 but font FONT. */
1085 XGCValues xgcv;
1086 unsigned long mask;
d67d1627 1087
791f420f
JR
1088 xgcv.background = s->face->background;
1089 xgcv.foreground = s->face->foreground;
1090 IF_DEBUG (x_check_font (s->f, s->font));
1091 xgcv.font = s->font;
1092 mask = GCForeground | GCBackground | GCFont;
d67d1627 1093
791f420f
JR
1094 if (FRAME_W32_DISPLAY_INFO (s->f)->scratch_cursor_gc)
1095 XChangeGC (NULL, FRAME_W32_DISPLAY_INFO (s->f)->scratch_cursor_gc,
1096 mask, &xgcv);
1097 else
1098 FRAME_W32_DISPLAY_INFO (s->f)->scratch_cursor_gc
1099 = XCreateGC (NULL, s->window, mask, &xgcv);
d67d1627 1100
791f420f
JR
1101 s->gc = FRAME_W32_DISPLAY_INFO (s->f)->scratch_cursor_gc;
1102 }
1103
a54e2c05 1104 eassert (s->gc != 0);
791f420f
JR
1105}
1106
1107
1108/* Set S->gc of glyph string S to a GC suitable for drawing a mode line.
1109 Faces to use in the mode line have already been computed when the
1110 matrix was built, so there isn't much to do, here. */
1111
55d4c1b2 1112static inline void
b56ceb92 1113x_set_mode_line_face_gc (struct glyph_string *s)
d67d1627 1114{
791f420f 1115 s->gc = s->face->gc;
791f420f
JR
1116}
1117
1118
1119/* Set S->gc of glyph string S for drawing that glyph string. Set
1120 S->stippled_p to a non-zero value if the face of S has a stipple
1121 pattern. */
1122
55d4c1b2 1123static inline void
b56ceb92 1124x_set_glyph_string_gc (struct glyph_string *s)
791f420f 1125{
ec48c3a7 1126 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
d67d1627 1127
791f420f
JR
1128 if (s->hl == DRAW_NORMAL_TEXT)
1129 {
1130 s->gc = s->face->gc;
1131 s->stippled_p = s->face->stipple != 0;
1132 }
1133 else if (s->hl == DRAW_INVERSE_VIDEO)
1134 {
1135 x_set_mode_line_face_gc (s);
1136 s->stippled_p = s->face->stipple != 0;
1137 }
1138 else if (s->hl == DRAW_CURSOR)
1139 {
1140 x_set_cursor_gc (s);
1141 s->stippled_p = 0;
1142 }
1143 else if (s->hl == DRAW_MOUSE_FACE)
1144 {
1145 x_set_mouse_face_gc (s);
1146 s->stippled_p = s->face->stipple != 0;
1147 }
1148 else if (s->hl == DRAW_IMAGE_RAISED
1149 || s->hl == DRAW_IMAGE_SUNKEN)
1150 {
1151 s->gc = s->face->gc;
1152 s->stippled_p = s->face->stipple != 0;
1153 }
1154 else
1155 {
1156 s->gc = s->face->gc;
1157 s->stippled_p = s->face->stipple != 0;
1158 }
1159
1160 /* GC must have been set. */
a54e2c05 1161 eassert (s->gc != 0);
791f420f
JR
1162}
1163
1164
791f420f
JR
1165/* Set clipping for output of glyph string S. S may be part of a mode
1166 line or menu if we don't have X toolkit support. */
1167
55d4c1b2 1168static inline void
b56ceb92 1169x_set_glyph_string_clipping (struct glyph_string *s)
791f420f 1170{
3ca3504a 1171 RECT *r = s->clip;
3ca3504a
JR
1172 int n = get_glyph_string_clip_rects (s, r, 2);
1173
1174 if (n == 1)
1175 w32_set_clip_rectangle (s->hdc, r);
1176 else if (n > 1)
1177 {
1149507c
JB
1178 HRGN clip1 = CreateRectRgnIndirect (r);
1179 HRGN clip2 = CreateRectRgnIndirect (r + 1);
1180 if (CombineRgn (clip1, clip1, clip2, RGN_OR) != ERROR)
1181 SelectClipRgn (s->hdc, clip1);
3ca3504a
JR
1182 DeleteObject (clip1);
1183 DeleteObject (clip2);
3ca3504a 1184 }
3ca3504a 1185 s->num_clips = n;
791f420f
JR
1186}
1187
027f6f90
JR
1188/* Set SRC's clipping for output of glyph string DST. This is called
1189 when we are drawing DST's left_overhang or right_overhang only in
1190 the area of SRC. */
1191
1192static void
b56ceb92
JB
1193x_set_glyph_string_clipping_exactly (struct glyph_string *src,
1194 struct glyph_string *dst)
027f6f90
JR
1195{
1196 RECT r;
1197
ef39ccbb
KH
1198 r.left = src->x;
1199 r.right = r.left + src->width;
1200 r.top = src->y;
1201 r.bottom = r.top + src->height;
1202 dst->clip[0] = r;
1203 dst->num_clips = 1;
027f6f90
JR
1204 w32_set_clip_rectangle (dst->hdc, &r);
1205}
791f420f 1206
6b6bd726 1207/* RIF:
ef39ccbb 1208 Compute left and right overhang of glyph string S. */
791f420f 1209
6b6bd726 1210static void
b56ceb92 1211w32_compute_glyph_string_overhangs (struct glyph_string *s)
791f420f 1212{
cf907d69 1213 if (s->cmp == NULL
ef39ccbb
KH
1214 && s->first_glyph->type == CHAR_GLYPH
1215 && !s->font_not_found_p)
cf907d69 1216 {
ef39ccbb
KH
1217 unsigned *code = alloca (sizeof (unsigned) * s->nchars);
1218 struct font *font = s->font;
1219 struct font_metrics metrics;
1220 int i;
cf907d69 1221
ef39ccbb
KH
1222 for (i = 0; i < s->nchars; i++)
1223 code[i] = s->char2b[i];
1224 font->driver->text_extents (font, code, s->nchars, &metrics);
1225 s->right_overhang = (metrics.rbearing > metrics.width
1226 ? metrics.rbearing - metrics.width : 0);
1227 s->left_overhang = metrics.lbearing < 0 ? -metrics.lbearing : 0;
cf907d69
JR
1228 }
1229 else if (s->cmp)
1230 {
1231 s->right_overhang = s->cmp->rbearing - s->cmp->pixel_width;
1232 s->left_overhang = -s->cmp->lbearing;
1233 }
791f420f
JR
1234}
1235
791f420f
JR
1236/* Fill rectangle X, Y, W, H with background color of glyph string S. */
1237
55d4c1b2 1238static inline void
b56ceb92
JB
1239x_clear_glyph_string_rect (struct glyph_string *s,
1240 int x, int y, int w, int h)
791f420f
JR
1241{
1242 int real_x = x;
1243 int real_y = y;
1244 int real_w = w;
1245 int real_h = h;
1246#if 0
1247 /* Take clipping into account. */
1248 if (s->gc->clip_mask == Rect)
1249 {
1250 real_x = max (real_x, s->gc->clip_rectangle.left);
1251 real_y = max (real_y, s->gc->clip_rectangle.top);
1252 real_w = min (real_w, s->gc->clip_rectangle.right
1253 - s->gc->clip_rectangle.left);
1254 real_h = min (real_h, s->gc->clip_rectangle.bottom
1255 - s->gc->clip_rectangle.top);
1256 }
1257#endif
1258 w32_fill_area (s->f, s->hdc, s->gc->background, real_x, real_y,
1259 real_w, real_h);
1260}
1261
1262
1263/* Draw the background of glyph_string S. If S->background_filled_p
1264 is non-zero don't draw it. FORCE_P non-zero means draw the
1265 background even if it wouldn't be drawn normally. This is used
1266 when a string preceding S draws into the background of S, or S
1267 contains the first component of a composition. */
1268
1269static void
b56ceb92 1270x_draw_glyph_string_background (struct glyph_string *s, int force_p)
791f420f
JR
1271{
1272 /* Nothing to do if background has already been drawn or if it
1273 shouldn't be drawn in the first place. */
1274 if (!s->background_filled_p)
1275 {
60222d69
AI
1276 int box_line_width = max (s->face->box_line_width, 0);
1277
01b220b6 1278#if 0 /* TODO: stipple */
791f420f
JR
1279 if (s->stippled_p)
1280 {
1281 /* Fill background with a stipple pattern. */
1282 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
1283 XFillRectangle (s->display, s->window, s->gc, s->x,
60222d69 1284 s->y + box_line_width,
791f420f 1285 s->background_width,
60222d69 1286 s->height - 2 * box_line_width);
791f420f
JR
1287 XSetFillStyle (s->display, s->gc, FillSolid);
1288 s->background_filled_p = 1;
1289 }
1290 else
1291#endif
60222d69 1292 if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
791f420f
JR
1293 || s->font_not_found_p
1294 || s->extends_to_end_of_line_p
1295 || force_p)
1296 {
60222d69 1297 x_clear_glyph_string_rect (s, s->x, s->y + box_line_width,
791f420f 1298 s->background_width,
60222d69 1299 s->height - 2 * box_line_width);
791f420f
JR
1300 s->background_filled_p = 1;
1301 }
1302 }
1303}
1304
1305
1306/* Draw the foreground of glyph string S. */
1307
1308static void
b56ceb92 1309x_draw_glyph_string_foreground (struct glyph_string *s)
791f420f
JR
1310{
1311 int i, x;
1312
1313 /* If first glyph of S has a left box line, start drawing the text
1314 of S to the right of that box line. */
1315 if (s->face->box != FACE_NO_BOX
1316 && s->first_glyph->left_box_line_p)
1ea40aa2 1317 x = s->x + eabs (s->face->box_line_width);
791f420f
JR
1318 else
1319 x = s->x;
1320
791f420f
JR
1321 SetTextColor (s->hdc, s->gc->foreground);
1322 SetBkColor (s->hdc, s->gc->background);
1323 SetTextAlign (s->hdc, TA_BASELINE | TA_LEFT);
1324
791f420f
JR
1325 /* Draw characters of S as rectangles if S's font could not be
1326 loaded. */
1327 if (s->font_not_found_p)
1328 {
1329 for (i = 0; i < s->nchars; ++i)
1330 {
1331 struct glyph *g = s->first_glyph + i;
1332
1333 w32_draw_rectangle (s->hdc, s->gc, x, s->y, g->pixel_width - 1,
1334 s->height - 1);
1335 x += g->pixel_width;
1336 }
1337 }
ef39ccbb 1338 else
027f6f90 1339 {
c35f9821
JR
1340 struct font *font = s->font;
1341 int boff = font->baseline_offset;
027f6f90 1342 int y;
c35f9821
JR
1343 HFONT old_font;
1344
1345 old_font = SelectObject (s->hdc, FONT_HANDLE (font));
027f6f90 1346
c35f9821
JR
1347 if (font->vertical_centering)
1348 boff = VCENTER_BASELINE_OFFSET (font, s->f) - boff;
027f6f90
JR
1349
1350 y = s->ybase - boff;
1351 if (s->for_overlaps
1352 || (s->background_filled_p && s->hl != DRAW_CURSOR))
c35f9821 1353 font->driver->draw (s, 0, s->nchars, x, y, 0);
027f6f90 1354 else
c35f9821 1355 font->driver->draw (s, 0, s->nchars, x, y, 1);
027f6f90 1356 if (s->face->overstrike)
c35f9821 1357 font->driver->draw (s, 0, s->nchars, x + 1, y, 0);
791f420f 1358
c35f9821
JR
1359 SelectObject (s->hdc, old_font);
1360 }
791f420f
JR
1361}
1362
1363/* Draw the foreground of composite glyph string S. */
1364
1365static void
b56ceb92 1366x_draw_composite_glyph_string_foreground (struct glyph_string *s)
791f420f 1367{
027f6f90 1368 int i, j, x;
2b107652 1369 struct font *font = s->font;
791f420f
JR
1370
1371 /* If first glyph of S has a left box line, start drawing the text
1372 of S to the right of that box line. */
027f6f90 1373 if (s->face && s->face->box != FACE_NO_BOX
791f420f 1374 && s->first_glyph->left_box_line_p)
1ea40aa2 1375 x = s->x + eabs (s->face->box_line_width);
791f420f
JR
1376 else
1377 x = s->x;
1378
2b107652
KH
1379 /* S is a glyph string for a composition. S->cmp_from is the index
1380 of the first character drawn for glyphs of this composition.
1381 S->cmp_from == 0 means we are drawing the very first character of
791f420f
JR
1382 this composition. */
1383
1384 SetTextColor (s->hdc, s->gc->foreground);
1385 SetBkColor (s->hdc, s->gc->background);
791f420f
JR
1386 SetTextAlign (s->hdc, TA_BASELINE | TA_LEFT);
1387
1388 /* Draw a rectangle for the composition if the font for the very
1389 first character of the composition could not be loaded. */
1390 if (s->font_not_found_p)
1391 {
2b107652 1392 if (s->cmp_from == 0)
791f420f
JR
1393 w32_draw_rectangle (s->hdc, s->gc, x, s->y, s->width - 1,
1394 s->height - 1);
1395 }
2b107652
KH
1396 else if (! s->first_glyph->u.cmp.automatic)
1397 {
1398 int y = s->ybase;
2b107652
KH
1399 HFONT old_font;
1400
1401 old_font = SelectObject (s->hdc, FONT_HANDLE (font));
1402
1403 for (i = 0, j = s->cmp_from; i < s->nchars; i++, j++)
bd01620e
EZ
1404 /* TAB in a composition means display glyphs with padding
1405 space on the left or right. */
2b107652
KH
1406 if (COMPOSITION_GLYPH (s->cmp, j) != '\t')
1407 {
1408 int xx = x + s->cmp->offsets[j * 2];
1409 int yy = y - s->cmp->offsets[j * 2 + 1];
1410
1411 font->driver->draw (s, j, j + 1, xx, yy, 0);
1412 if (s->face->overstrike)
1413 font->driver->draw (s, j, j + 1, xx + 1, yy, 0);
1414 }
1415 SelectObject (s->hdc, old_font);
1416 }
c35f9821 1417 else
791f420f 1418 {
2b107652
KH
1419 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1420 Lisp_Object glyph;
027f6f90
JR
1421 int y = s->ybase;
1422 int width = 0;
c35f9821
JR
1423 HFONT old_font;
1424
1425 old_font = SelectObject (s->hdc, FONT_HANDLE (font));
027f6f90 1426
2b107652 1427 for (i = j = s->cmp_from; i < s->cmp_to; i++)
a18bb28d 1428 {
2b107652
KH
1429 glyph = LGSTRING_GLYPH (gstring, i);
1430 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
1431 width += LGLYPH_WIDTH (glyph);
1432 else
027f6f90 1433 {
027f6f90
JR
1434 int xoff, yoff, wadjust;
1435
2b107652 1436 if (j < i)
027f6f90 1437 {
2b107652 1438 font->driver->draw (s, j, i, x, y, 0);
027f6f90
JR
1439 x += width;
1440 }
2b107652
KH
1441 xoff = LGLYPH_XOFF (glyph);
1442 yoff = LGLYPH_YOFF (glyph);
1443 wadjust = LGLYPH_WADJUST (glyph);
027f6f90 1444 font->driver->draw (s, i, i + 1, x + xoff, y + yoff, 0);
0c16681f 1445 x += wadjust;
2b107652 1446 j = i + 1;
027f6f90
JR
1447 width = 0;
1448 }
a18bb28d 1449 }
2b107652
KH
1450 if (j < i)
1451 font->driver->draw (s, j, i, x, y, 0);
1452
c35f9821 1453 SelectObject (s->hdc, old_font);
791f420f
JR
1454 }
1455}
1456
e5fa381b 1457
b2cca856
KH
1458/* Draw the foreground of glyph string S for glyphless characters. */
1459
1460static void
1461x_draw_glyphless_glyph_string_foreground (struct glyph_string *s)
1462{
1463 struct glyph *glyph = s->first_glyph;
1464 XChar2b char2b[8];
1465 int x, i, j;
65b6b59a 1466 int with_background;
b2cca856
KH
1467
1468 /* If first glyph of S has a left box line, start drawing the text
1469 of S to the right of that box line. */
1470 if (s->face->box != FACE_NO_BOX
1471 && s->first_glyph->left_box_line_p)
1472 x = s->x + eabs (s->face->box_line_width);
1473 else
1474 x = s->x;
1475
1476 SetTextColor (s->hdc, s->gc->foreground);
1477 SetBkColor (s->hdc, s->gc->background);
1478 SetTextAlign (s->hdc, TA_BASELINE | TA_LEFT);
1479
1480 s->char2b = char2b;
65b6b59a
KH
1481 with_background = ! (s->for_overlaps
1482 || (s->background_filled_p && s->hl != DRAW_CURSOR));
b2cca856
KH
1483 for (i = 0; i < s->nchars; i++, glyph++)
1484 {
1485 char buf[7], *str = NULL;
1486 int len = glyph->u.glyphless.len;
1487
1488 if (glyph->u.glyphless.method == GLYPHLESS_DISPLAY_ACRONYM)
1489 {
1490 if (len > 1
1491 && CHAR_TABLE_P (Vglyphless_char_display)
1492 && (CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (Vglyphless_char_display))
1493 >= 1))
1494 {
1495 Lisp_Object acronym
1496 = (! glyph->u.glyphless.for_no_font
1497 ? CHAR_TABLE_REF (Vglyphless_char_display,
1498 glyph->u.glyphless.ch)
1499 : XCHAR_TABLE (Vglyphless_char_display)->extras[0]);
1500 if (STRINGP (acronym))
51b59d79 1501 str = SSDATA (acronym);
b2cca856
KH
1502 }
1503 }
0eb025fb 1504 else if (glyph->u.glyphless.method == GLYPHLESS_DISPLAY_HEX_CODE)
b2cca856
KH
1505 {
1506 sprintf ((char *) buf, "%0*X",
1507 glyph->u.glyphless.ch < 0x10000 ? 4 : 6,
1508 glyph->u.glyphless.ch);
1509 str = buf;
1510 }
1511
0eb025fb
EZ
1512 if (glyph->u.glyphless.method != GLYPHLESS_DISPLAY_THIN_SPACE)
1513 w32_draw_rectangle (s->hdc, s->gc,
1514 x, s->ybase - glyph->ascent,
1515 glyph->pixel_width - 1,
1516 glyph->ascent + glyph->descent - 1);
b2cca856
KH
1517 if (str)
1518 {
1519 struct font *font = s->font;
1520 int upper_len = (len + 1) / 2;
1521 unsigned code;
1522 HFONT old_font;
1523
65b6b59a 1524 old_font = SelectObject (s->hdc, FONT_HANDLE (font));
0eb025fb 1525 /* It is certain that all LEN characters in STR are ASCII. */
b2cca856
KH
1526 for (j = 0; j < len; j++)
1527 {
1528 code = font->driver->encode_char (font, str[j]);
1529 STORE_XCHAR2B (char2b + j, code >> 8, code & 0xFF);
1530 }
1531 font->driver->draw (s, 0, upper_len,
1532 x + glyph->slice.glyphless.upper_xoff,
1533 s->ybase + glyph->slice.glyphless.upper_yoff,
65b6b59a 1534 with_background);
b2cca856
KH
1535 font->driver->draw (s, upper_len, len,
1536 x + glyph->slice.glyphless.lower_xoff,
1537 s->ybase + glyph->slice.glyphless.lower_yoff,
65b6b59a 1538 with_background);
b2cca856
KH
1539 SelectObject (s->hdc, old_font);
1540 }
b2cca856
KH
1541 x += glyph->pixel_width;
1542 }
1543}
1544
1545
e5fa381b
JR
1546/* Brightness beyond which a color won't have its highlight brightness
1547 boosted.
1548
1549 Nominally, highlight colors for `3d' faces are calculated by
1550 brightening an object's color by a constant scale factor, but this
e8500ff4 1551 doesn't yield good results for dark colors, so for colors whose
e5fa381b
JR
1552 brightness is less than this value (on a scale of 0-255) have to
1553 use an additional additive factor.
1554
1555 The value here is set so that the default menu-bar/mode-line color
1556 (grey75) will not have its highlights changed at all. */
1557#define HIGHLIGHT_COLOR_DARK_BOOST_LIMIT 187
1558
1559
791f420f
JR
1560/* Allocate a color which is lighter or darker than *COLOR by FACTOR
1561 or DELTA. Try a color with RGB values multiplied by FACTOR first.
1562 If this produces the same color as COLOR, try a color where all RGB
1563 values have DELTA added. Return the allocated color in *COLOR.
1564 DISPLAY is the X display, CMAP is the colormap to operate on.
1565 Value is non-zero if successful. */
1566
1567static int
b56ceb92
JB
1568w32_alloc_lighter_color (struct frame *f, COLORREF *color,
1569 double factor, int delta)
791f420f
JR
1570{
1571 COLORREF new;
e5fa381b
JR
1572 long bright;
1573
1574 /* On Windows, RGB values are 0-255, not 0-65535, so scale delta. */
1575 delta /= 256;
791f420f
JR
1576
1577 /* Change RGB values by specified FACTOR. Avoid overflow! */
a54e2c05 1578 eassert (factor >= 0);
791f420f
JR
1579 new = PALETTERGB (min (0xff, factor * GetRValue (*color)),
1580 min (0xff, factor * GetGValue (*color)),
1581 min (0xff, factor * GetBValue (*color)));
e5fa381b
JR
1582
1583 /* Calculate brightness of COLOR. */
1584 bright = (2 * GetRValue (*color) + 3 * GetGValue (*color)
1585 + GetBValue (*color)) / 6;
1586
1587 /* We only boost colors that are darker than
1588 HIGHLIGHT_COLOR_DARK_BOOST_LIMIT. */
1589 if (bright < HIGHLIGHT_COLOR_DARK_BOOST_LIMIT)
1590 /* Make an additive adjustment to NEW, because it's dark enough so
1591 that scaling by FACTOR alone isn't enough. */
1592 {
1593 /* How far below the limit this color is (0 - 1, 1 being darker). */
1594 double dimness = 1 - (double)bright / HIGHLIGHT_COLOR_DARK_BOOST_LIMIT;
1595 /* The additive adjustment. */
1596 int min_delta = delta * dimness * factor / 2;
d67d1627 1597
e5fa381b
JR
1598 if (factor < 1)
1599 new = PALETTERGB (max (0, min (0xff, min_delta - GetRValue (*color))),
1600 max (0, min (0xff, min_delta - GetGValue (*color))),
1601 max (0, min (0xff, min_delta - GetBValue (*color))));
1602 else
1603 new = PALETTERGB (max (0, min (0xff, min_delta + GetRValue (*color))),
1604 max (0, min (0xff, min_delta + GetGValue (*color))),
1605 max (0, min (0xff, min_delta + GetBValue (*color))));
1606 }
d67d1627 1607
791f420f
JR
1608 if (new == *color)
1609 new = PALETTERGB (max (0, min (0xff, delta + GetRValue (*color))),
1610 max (0, min (0xff, delta + GetGValue (*color))),
1611 max (0, min (0xff, delta + GetBValue (*color))));
1612
01b220b6
JR
1613 /* TODO: Map to palette and retry with delta if same? */
1614 /* TODO: Free colors (if using palette)? */
93ff4395 1615
791f420f
JR
1616 if (new == *color)
1617 return 0;
1618
1619 *color = new;
1620
1621 return 1;
1622}
1623
8b7d0a16
JR
1624/* On frame F, translate pixel colors to RGB values for the NCOLORS
1625 colors in COLORS. On W32, we no longer try to map colors to
1626 a palette. */
1627void
b56ceb92 1628x_query_colors (struct frame *f, XColor *colors, int ncolors)
8b7d0a16
JR
1629{
1630 int i;
1631
1632 for (i = 0; i < ncolors; i++)
1633 {
1634 DWORD pixel = colors[i].pixel;
1635 /* Convert to a 16 bit value in range 0 - 0xffff. */
1636 colors[i].red = GetRValue (pixel) * 257;
1637 colors[i].green = GetGValue (pixel) * 257;
1638 colors[i].blue = GetBValue (pixel) * 257;
1639 }
1640}
1641
1642void
b56ceb92 1643x_query_color (struct frame *f, XColor *color)
8b7d0a16
JR
1644{
1645 x_query_colors (f, color, 1);
1646}
1647
791f420f
JR
1648
1649/* Set up the foreground color for drawing relief lines of glyph
1650 string S. RELIEF is a pointer to a struct relief containing the GC
1651 with which lines will be drawn. Use a color that is FACTOR or
1652 DELTA lighter or darker than the relief's background which is found
1653 in S->f->output_data.x->relief_background. If such a color cannot
1654 be allocated, use DEFAULT_PIXEL, instead. */
d67d1627 1655
791f420f 1656static void
b56ceb92
JB
1657w32_setup_relief_color (struct frame *f, struct relief *relief, double factor,
1658 int delta, COLORREF default_pixel)
791f420f
JR
1659{
1660 XGCValues xgcv;
1661 struct w32_output *di = f->output_data.w32;
1662 unsigned long mask = GCForeground;
1663 COLORREF pixel;
1664 COLORREF background = di->relief_background;
1665 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
1666
01b220b6 1667 /* TODO: Free colors (if using palette)? */
93ff4395 1668
791f420f
JR
1669 /* Allocate new color. */
1670 xgcv.foreground = default_pixel;
1671 pixel = background;
1672 if (w32_alloc_lighter_color (f, &pixel, factor, delta))
1673 {
1674 relief->allocated_p = 1;
1675 xgcv.foreground = relief->pixel = pixel;
1676 }
d67d1627 1677
791f420f
JR
1678 if (relief->gc == 0)
1679 {
01b220b6 1680#if 0 /* TODO: stipple */
791f420f
JR
1681 xgcv.stipple = dpyinfo->gray;
1682 mask |= GCStipple;
1683#endif
1684 relief->gc = XCreateGC (NULL, FRAME_W32_WINDOW (f), mask, &xgcv);
1685 }
1686 else
1687 XChangeGC (NULL, relief->gc, mask, &xgcv);
1688}
1689
1690
1691/* Set up colors for the relief lines around glyph string S. */
1692
1693static void
b56ceb92 1694x_setup_relief_colors (struct glyph_string *s)
791f420f
JR
1695{
1696 struct w32_output *di = s->f->output_data.w32;
1697 COLORREF color;
1698
1699 if (s->face->use_box_color_for_shadows_p)
1700 color = s->face->box_color;
6ff3e5e3 1701 else if (s->first_glyph->type == IMAGE_GLYPH
6637c996 1702 && s->img->pixmap
6ff3e5e3
JR
1703 && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
1704 color = IMAGE_BACKGROUND (s->img, s->f, 0);
791f420f
JR
1705 else
1706 color = s->gc->background;
1707
1708 if (di->white_relief.gc == 0
1709 || color != di->relief_background)
1710 {
1711 di->relief_background = color;
1712 w32_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000,
1713 WHITE_PIX_DEFAULT (s->f));
1714 w32_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000,
1715 BLACK_PIX_DEFAULT (s->f));
1716 }
1717}
1718
1719
1720/* Draw a relief on frame F inside the rectangle given by LEFT_X,
1721 TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief
1722 to draw, it must be >= 0. RAISED_P non-zero means draw a raised
1723 relief. LEFT_P non-zero means draw a relief on the left side of
1724 the rectangle. RIGHT_P non-zero means draw a relief on the right
1725 side of the rectangle. CLIP_RECT is the clipping rectangle to use
1726 when drawing. */
1727
1728static void
b56ceb92 1729w32_draw_relief_rect (struct frame *f,
e8500ff4
JB
1730 int left_x, int top_y, int right_x, int bottom_y,
1731 int width, int raised_p,
1732 int top_p, int bot_p, int left_p, int right_p,
b56ceb92 1733 RECT *clip_rect)
791f420f
JR
1734{
1735 int i;
1736 XGCValues gc;
1737 HDC hdc = get_frame_dc (f);
1738
1739 if (raised_p)
e5fa381b 1740 gc.foreground = f->output_data.w32->white_relief.gc->foreground;
791f420f 1741 else
e5fa381b 1742 gc.foreground = f->output_data.w32->black_relief.gc->foreground;
791f420f
JR
1743
1744 w32_set_clip_rectangle (hdc, clip_rect);
1745
1746 /* Top. */
cb0b194a
KS
1747 if (top_p)
1748 for (i = 0; i < width; ++i)
1749 w32_fill_area (f, hdc, gc.foreground,
1750 left_x + i * left_p, top_y + i,
1751 right_x - left_x - i * (left_p + right_p ) + 1, 1);
791f420f
JR
1752
1753 /* Left. */
1754 if (left_p)
1755 for (i = 0; i < width; ++i)
9f5a911b
JR
1756 w32_fill_area (f, hdc, gc.foreground,
1757 left_x + i, top_y + i, 1,
df3bd29d 1758 bottom_y - top_y - 2 * i + 1);
791f420f
JR
1759
1760 if (raised_p)
e5fa381b 1761 gc.foreground = f->output_data.w32->black_relief.gc->foreground;
791f420f 1762 else
e5fa381b 1763 gc.foreground = f->output_data.w32->white_relief.gc->foreground;
d67d1627 1764
791f420f 1765 /* Bottom. */
cb0b194a
KS
1766 if (bot_p)
1767 for (i = 0; i < width; ++i)
1768 w32_fill_area (f, hdc, gc.foreground,
1769 left_x + i * left_p, bottom_y - i,
1770 right_x - left_x - i * (left_p + right_p) + 1, 1);
791f420f
JR
1771
1772 /* Right. */
1773 if (right_p)
1774 for (i = 0; i < width; ++i)
9f5a911b
JR
1775 w32_fill_area (f, hdc, gc.foreground,
1776 right_x - i, top_y + i + 1, 1,
df3bd29d 1777 bottom_y - top_y - 2 * i - 1);
791f420f
JR
1778
1779 w32_set_clip_rectangle (hdc, NULL);
d67d1627 1780
791f420f
JR
1781 release_frame_dc (f, hdc);
1782}
1783
1784
1785/* Draw a box on frame F inside the rectangle given by LEFT_X, TOP_Y,
1786 RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the lines to
1787 draw, it must be >= 0. LEFT_P non-zero means draw a line on the
1788 left side of the rectangle. RIGHT_P non-zero means draw a line
1789 on the right side of the rectangle. CLIP_RECT is the clipping
1790 rectangle to use when drawing. */
1791
1792static void
b56ceb92
JB
1793w32_draw_box_rect (struct glyph_string *s,
1794 int left_x, int top_y, int right_x, int bottom_y, int width,
1795 int left_p, int right_p, RECT *clip_rect)
791f420f 1796{
00fe468b 1797 w32_set_clip_rectangle (s->hdc, clip_rect);
d67d1627 1798
791f420f 1799 /* Top. */
00fe468b 1800 w32_fill_area (s->f, s->hdc, s->face->box_color,
2d0c0bd7 1801 left_x, top_y, right_x - left_x + 1, width);
791f420f
JR
1802
1803 /* Left. */
1804 if (left_p)
1805 {
00fe468b 1806 w32_fill_area (s->f, s->hdc, s->face->box_color,
2d0c0bd7 1807 left_x, top_y, width, bottom_y - top_y + 1);
791f420f 1808 }
d67d1627 1809
791f420f 1810 /* Bottom. */
00fe468b 1811 w32_fill_area (s->f, s->hdc, s->face->box_color,
2d0c0bd7 1812 left_x, bottom_y - width + 1, right_x - left_x + 1, width);
d67d1627 1813
791f420f
JR
1814 /* Right. */
1815 if (right_p)
1816 {
00fe468b 1817 w32_fill_area (s->f, s->hdc, s->face->box_color,
2d0c0bd7 1818 right_x - width + 1, top_y, width, bottom_y - top_y + 1);
791f420f
JR
1819 }
1820
00fe468b 1821 w32_set_clip_rectangle (s->hdc, NULL);
791f420f
JR
1822}
1823
1824
1825/* Draw a box around glyph string S. */
1826
1827static void
b56ceb92 1828x_draw_glyph_string_box (struct glyph_string *s)
791f420f
JR
1829{
1830 int width, left_x, right_x, top_y, bottom_y, last_x, raised_p;
1831 int left_p, right_p;
1832 struct glyph *last_glyph;
1833 RECT clip_rect;
1834
82ead4b1
KS
1835 last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
1836 ? WINDOW_RIGHT_EDGE_X (s->w)
1837 : window_box_right (s->w, s->area));
d67d1627 1838
791f420f
JR
1839 /* The glyph that may have a right box line. */
1840 last_glyph = (s->cmp || s->img
1841 ? s->first_glyph
1842 : s->first_glyph + s->nchars - 1);
1843
1ea40aa2 1844 width = eabs (s->face->box_line_width);
791f420f
JR
1845 raised_p = s->face->box == FACE_RAISED_BOX;
1846 left_x = s->x;
9f5a911b 1847 right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
791f420f
JR
1848 ? last_x - 1
1849 : min (last_x, s->x + s->background_width) - 1));
1850 top_y = s->y;
1851 bottom_y = top_y + s->height - 1;
1852
1853 left_p = (s->first_glyph->left_box_line_p
1854 || (s->hl == DRAW_MOUSE_FACE
1855 && (s->prev == NULL
1856 || s->prev->hl != s->hl)));
1857 right_p = (last_glyph->right_box_line_p
1858 || (s->hl == DRAW_MOUSE_FACE
1859 && (s->next == NULL
1860 || s->next->hl != s->hl)));
d67d1627 1861
89271099 1862 get_glyph_string_clip_rect (s, &clip_rect);
791f420f
JR
1863
1864 if (s->face->box == FACE_SIMPLE_BOX)
1865 w32_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
1866 left_p, right_p, &clip_rect);
1867 else
1868 {
1869 x_setup_relief_colors (s);
1870 w32_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y,
cb0b194a 1871 width, raised_p, 1, 1, left_p, right_p, &clip_rect);
791f420f
JR
1872 }
1873}
1874
1875
1876/* Draw foreground of image glyph string S. */
1877
1878static void
b56ceb92 1879x_draw_image_foreground (struct glyph_string *s)
791f420f 1880{
cb0b194a
KS
1881 int x = s->x;
1882 int y = s->ybase - image_ascent (s->img, s->face, &s->slice);
791f420f
JR
1883
1884 /* If first glyph of S has a left box line, start drawing it to the
1885 right of that line. */
1886 if (s->face->box != FACE_NO_BOX
cb0b194a
KS
1887 && s->first_glyph->left_box_line_p
1888 && s->slice.x == 0)
1ea40aa2 1889 x += eabs (s->face->box_line_width);
791f420f
JR
1890
1891 /* If there is a margin around the image, adjust x- and y-position
1892 by that margin. */
cb0b194a
KS
1893 if (s->slice.x == 0)
1894 x += s->img->hmargin;
1895 if (s->slice.y == 0)
1896 y += s->img->vmargin;
791f420f
JR
1897
1898 SaveDC (s->hdc);
1899
1900 if (s->img->pixmap)
1901 {
d30591dc
JR
1902 HDC compat_hdc = CreateCompatibleDC (s->hdc);
1903 HBRUSH fg_brush = CreateSolidBrush (s->gc->foreground);
1904 HBRUSH orig_brush = SelectObject (s->hdc, fg_brush);
1905 HGDIOBJ orig_obj = SelectObject (compat_hdc, s->img->pixmap);
1906 SetBkColor (compat_hdc, RGB (255, 255, 255));
1907 SetTextColor (s->hdc, RGB (0, 0, 0));
1908 x_set_glyph_string_clipping (s);
1909
791f420f
JR
1910 if (s->img->mask)
1911 {
d30591dc
JR
1912 HDC mask_dc = CreateCompatibleDC (s->hdc);
1913 HGDIOBJ mask_orig_obj = SelectObject (mask_dc, s->img->mask);
1914
1915 SetTextColor (s->hdc, RGB (255, 255, 255));
1916 SetBkColor (s->hdc, RGB (0, 0, 0));
1917
cb0b194a
KS
1918 BitBlt (s->hdc, x, y, s->slice.width, s->slice.height,
1919 compat_hdc, s->slice.x, s->slice.y, SRCINVERT);
1920 BitBlt (s->hdc, x, y, s->slice.width, s->slice.height,
1921 mask_dc, s->slice.x, s->slice.y, SRCAND);
1922 BitBlt (s->hdc, x, y, s->slice.width, s->slice.height,
1923 compat_hdc, s->slice.x, s->slice.y, SRCINVERT);
d30591dc
JR
1924
1925 SelectObject (mask_dc, mask_orig_obj);
1926 DeleteDC (mask_dc);
791f420f
JR
1927 }
1928 else
791f420f 1929 {
d30591dc
JR
1930 SetTextColor (s->hdc, s->gc->foreground);
1931 SetBkColor (s->hdc, s->gc->background);
1932
cb0b194a
KS
1933 BitBlt (s->hdc, x, y, s->slice.width, s->slice.height,
1934 compat_hdc, s->slice.x, s->slice.y, SRCCOPY);
791f420f
JR
1935
1936 /* When the image has a mask, we can expect that at
1937 least part of a mouse highlight or a block cursor will
1938 be visible. If the image doesn't have a mask, make
1939 a block cursor visible by drawing a rectangle around
1940 the image. I believe it's looking better if we do
1941 nothing here for mouse-face. */
1942 if (s->hl == DRAW_CURSOR)
c65eff23
KS
1943 {
1944 int r = s->img->relief;
1945 if (r < 0) r = -r;
1946 w32_draw_rectangle (s->hdc, s->gc, x - r, y - r ,
cb0b194a
KS
1947 s->slice.width + r*2 - 1,
1948 s->slice.height + r*2 - 1);
c65eff23 1949 }
791f420f 1950 }
d30591dc
JR
1951
1952 w32_set_clip_rectangle (s->hdc, NULL);
1953 SelectObject (s->hdc, orig_brush);
1954 DeleteObject (fg_brush);
1955 SelectObject (compat_hdc, orig_obj);
1956 DeleteDC (compat_hdc);
791f420f
JR
1957 }
1958 else
cb0b194a
KS
1959 w32_draw_rectangle (s->hdc, s->gc, x, y,
1960 s->slice.width - 1, s->slice.height - 1);
ee78dc32 1961
791f420f
JR
1962 RestoreDC (s->hdc ,-1);
1963}
ee78dc32 1964
791f420f 1965
791f420f
JR
1966/* Draw a relief around the image glyph string S. */
1967
1968static void
b56ceb92 1969x_draw_image_relief (struct glyph_string *s)
791f420f
JR
1970{
1971 int x0, y0, x1, y1, thick, raised_p;
1972 RECT r;
cb0b194a
KS
1973 int x = s->x;
1974 int y = s->ybase - image_ascent (s->img, s->face, &s->slice);
d67d1627 1975
791f420f
JR
1976 /* If first glyph of S has a left box line, start drawing it to the
1977 right of that line. */
1978 if (s->face->box != FACE_NO_BOX
cb0b194a
KS
1979 && s->first_glyph->left_box_line_p
1980 && s->slice.x == 0)
1ea40aa2 1981 x += eabs (s->face->box_line_width);
d67d1627 1982
791f420f
JR
1983 /* If there is a margin around the image, adjust x- and y-position
1984 by that margin. */
cb0b194a
KS
1985 if (s->slice.x == 0)
1986 x += s->img->hmargin;
1987 if (s->slice.y == 0)
1988 y += s->img->vmargin;
d67d1627 1989
791f420f
JR
1990 if (s->hl == DRAW_IMAGE_SUNKEN
1991 || s->hl == DRAW_IMAGE_RAISED)
1992 {
e8500ff4
JB
1993 thick = tool_bar_button_relief >= 0 ? tool_bar_button_relief
1994 : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
791f420f
JR
1995 raised_p = s->hl == DRAW_IMAGE_RAISED;
1996 }
1997 else
ee78dc32 1998 {
1ea40aa2 1999 thick = eabs (s->img->relief);
791f420f
JR
2000 raised_p = s->img->relief > 0;
2001 }
d67d1627 2002
791f420f
JR
2003 x0 = x - thick;
2004 y0 = y - thick;
cb0b194a
KS
2005 x1 = x + s->slice.width + thick - 1;
2006 y1 = y + s->slice.height + thick - 1;
d67d1627 2007
791f420f 2008 x_setup_relief_colors (s);
89271099 2009 get_glyph_string_clip_rect (s, &r);
cb0b194a
KS
2010 w32_draw_relief_rect (s->f, x0, y0, x1, y1, thick, raised_p,
2011 s->slice.y == 0,
2012 s->slice.y + s->slice.height == s->img->height,
2013 s->slice.x == 0,
2014 s->slice.x + s->slice.width == s->img->width,
2015 &r);
791f420f 2016}
ee78dc32 2017
791f420f
JR
2018
2019/* Draw the foreground of image glyph string S to PIXMAP. */
2020
2021static void
b56ceb92 2022w32_draw_image_foreground_1 (struct glyph_string *s, HBITMAP pixmap)
791f420f
JR
2023{
2024 HDC hdc = CreateCompatibleDC (s->hdc);
2025 HGDIOBJ orig_hdc_obj = SelectObject (hdc, pixmap);
cb0b194a
KS
2026 int x = 0;
2027 int y = s->ybase - s->y - image_ascent (s->img, s->face, &s->slice);
791f420f
JR
2028
2029 /* If first glyph of S has a left box line, start drawing it to the
2030 right of that line. */
2031 if (s->face->box != FACE_NO_BOX
cb0b194a
KS
2032 && s->first_glyph->left_box_line_p
2033 && s->slice.x == 0)
1ea40aa2 2034 x += eabs (s->face->box_line_width);
791f420f
JR
2035
2036 /* If there is a margin around the image, adjust x- and y-position
2037 by that margin. */
cb0b194a
KS
2038 if (s->slice.x == 0)
2039 x += s->img->hmargin;
2040 if (s->slice.y == 0)
2041 y += s->img->vmargin;
791f420f
JR
2042
2043 if (s->img->pixmap)
2044 {
d30591dc
JR
2045 HDC compat_hdc = CreateCompatibleDC (hdc);
2046 HBRUSH fg_brush = CreateSolidBrush (s->gc->foreground);
2047 HBRUSH orig_brush = SelectObject (hdc, fg_brush);
2048 HGDIOBJ orig_obj = SelectObject (compat_hdc, s->img->pixmap);
2049
791f420f
JR
2050 if (s->img->mask)
2051 {
d30591dc
JR
2052 HDC mask_dc = CreateCompatibleDC (hdc);
2053 HGDIOBJ mask_orig_obj = SelectObject (mask_dc, s->img->mask);
2054
2055 SetTextColor (hdc, RGB (0, 0, 0));
2056 SetBkColor (hdc, RGB (255, 255, 255));
cb0b194a
KS
2057 BitBlt (hdc, x, y, s->slice.width, s->slice.height,
2058 compat_hdc, s->slice.x, s->slice.y, SRCINVERT);
2059 BitBlt (hdc, x, y, s->slice.width, s->slice.height,
2060 mask_dc, s->slice.x, s->slice.y, SRCAND);
2061 BitBlt (hdc, x, y, s->slice.width, s->slice.height,
2062 compat_hdc, s->slice.x, s->slice.y, SRCINVERT);
d30591dc
JR
2063
2064 SelectObject (mask_dc, mask_orig_obj);
2065 DeleteDC (mask_dc);
791f420f
JR
2066 }
2067 else
ef0e360f 2068 {
d30591dc
JR
2069 SetTextColor (hdc, s->gc->foreground);
2070 SetBkColor (hdc, s->gc->background);
2071
cb0b194a
KS
2072 BitBlt (hdc, x, y, s->slice.width, s->slice.height,
2073 compat_hdc, s->slice.x, s->slice.y, SRCCOPY);
791f420f
JR
2074
2075 /* When the image has a mask, we can expect that at
2076 least part of a mouse highlight or a block cursor will
2077 be visible. If the image doesn't have a mask, make
2078 a block cursor visible by drawing a rectangle around
2079 the image. I believe it's looking better if we do
2080 nothing here for mouse-face. */
2081 if (s->hl == DRAW_CURSOR)
c65eff23
KS
2082 {
2083 int r = s->img->relief;
2084 if (r < 0) r = -r;
cb0b194a
KS
2085 w32_draw_rectangle (hdc, s->gc, x - r, y - r,
2086 s->slice.width + r*2 - 1,
2087 s->slice.height + r*2 - 1);
c65eff23 2088 }
ef0e360f 2089 }
d30591dc
JR
2090
2091 SelectObject (hdc, orig_brush);
2092 DeleteObject (fg_brush);
2093 SelectObject (compat_hdc, orig_obj);
2094 DeleteDC (compat_hdc);
791f420f
JR
2095 }
2096 else
cb0b194a
KS
2097 w32_draw_rectangle (hdc, s->gc, x, y,
2098 s->slice.width - 1, s->slice.height - 1);
791f420f
JR
2099
2100 SelectObject (hdc, orig_hdc_obj);
2101 DeleteDC (hdc);
2102}
2103
2104
2105/* Draw part of the background of glyph string S. X, Y, W, and H
2106 give the rectangle to draw. */
2107
2108static void
b56ceb92 2109x_draw_glyph_string_bg_rect (struct glyph_string *s, int x, int y, int w, int h)
791f420f 2110{
01b220b6 2111#if 0 /* TODO: stipple */
791f420f
JR
2112 if (s->stippled_p)
2113 {
2114 /* Fill background with a stipple pattern. */
2115 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
2116 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
2117 XSetFillStyle (s->display, s->gc, FillSolid);
2118 }
2119 else
2120#endif
2121 x_clear_glyph_string_rect (s, x, y, w, h);
2122}
2123
2124
d67d1627 2125/* Draw image glyph string S.
791f420f
JR
2126
2127 s->y
2128 s->x +-------------------------
2129 | s->face->box
2130 |
2131 | +-------------------------
d6ff54d5 2132 | | s->img->vmargin
791f420f
JR
2133 | |
2134 | | +-------------------
2135 | | | the image
cabb23bc 2136
791f420f
JR
2137 */
2138
2139static void
b56ceb92 2140x_draw_image_glyph_string (struct glyph_string *s)
791f420f
JR
2141{
2142 int x, y;
1ea40aa2 2143 int box_line_hwidth = eabs (s->face->box_line_width);
60222d69 2144 int box_line_vwidth = max (s->face->box_line_width, 0);
791f420f
JR
2145 int height;
2146 HBITMAP pixmap = 0;
2147
60222d69 2148 height = s->height - 2 * box_line_vwidth;
791f420f
JR
2149
2150 /* Fill background with face under the image. Do it only if row is
2151 taller than image or if image has a clip mask to reduce
2152 flickering. */
2153 s->stippled_p = s->face->stipple != 0;
cb0b194a 2154 if (height > s->slice.height
d6ff54d5 2155 || s->img->hmargin
c2cc16fa 2156 || s->img->vmargin
791f420f 2157 || s->img->mask
791f420f
JR
2158 || s->img->pixmap == 0
2159 || s->width != s->background_width)
2160 {
cb0b194a
KS
2161 x = s->x;
2162 if (s->first_glyph->left_box_line_p
2163 && s->slice.x == 0)
2164 x += box_line_hwidth;
2165
2166 y = s->y;
2167 if (s->slice.y == 0)
2168 y += box_line_vwidth;
d67d1627 2169
d30591dc 2170#if 0 /* TODO: figure out if we need to do this on Windows. */
791f420f 2171 if (s->img->mask)
ee78dc32 2172 {
c2cc16fa
JR
2173 /* Create a pixmap as large as the glyph string. Fill it
2174 with the background color. Copy the image to it, using
2175 its mask. Copy the temporary pixmap to the display. */
791f420f
JR
2176 Screen *screen = FRAME_X_SCREEN (s->f);
2177 int depth = DefaultDepthOfScreen (screen);
2178
2179 /* Create a pixmap as large as the glyph string. */
2180 pixmap = XCreatePixmap (s->display, s->window,
2181 s->background_width,
2182 s->height, depth);
d67d1627 2183
791f420f
JR
2184 /* Don't clip in the following because we're working on the
2185 pixmap. */
2186 XSetClipMask (s->display, s->gc, None);
ee78dc32 2187
791f420f
JR
2188 /* Fill the pixmap with the background color/stipple. */
2189 if (s->stippled_p)
2190 {
2191 /* Fill background with a stipple pattern. */
2192 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
2193 XFillRectangle (s->display, pixmap, s->gc,
2194 0, 0, s->background_width, s->height);
2195 XSetFillStyle (s->display, s->gc, FillSolid);
2196 }
ef0e360f 2197 else
791f420f
JR
2198 {
2199 XGCValues xgcv;
2200 XGetGCValues (s->display, s->gc, GCForeground | GCBackground,
2201 &xgcv);
2202 XSetForeground (s->display, s->gc, xgcv.background);
2203 XFillRectangle (s->display, pixmap, s->gc,
2204 0, 0, s->background_width, s->height);
2205 XSetForeground (s->display, s->gc, xgcv.foreground);
2206 }
ee78dc32 2207 }
791f420f
JR
2208 else
2209#endif
791f420f 2210 x_draw_glyph_string_bg_rect (s, x, y, s->background_width, height);
d67d1627 2211
791f420f
JR
2212 s->background_filled_p = 1;
2213 }
ee78dc32 2214
791f420f
JR
2215 /* Draw the foreground. */
2216 if (pixmap != 0)
2217 {
2218 w32_draw_image_foreground_1 (s, pixmap);
2219 x_set_glyph_string_clipping (s);
ee78dc32 2220 {
791f420f
JR
2221 HDC compat_hdc = CreateCompatibleDC (s->hdc);
2222 HBRUSH fg_brush = CreateSolidBrush (s->gc->foreground);
2223 HBRUSH orig_brush = SelectObject (s->hdc, fg_brush);
2224 HGDIOBJ orig_obj = SelectObject (compat_hdc, pixmap);
2225
2226 SetTextColor (s->hdc, s->gc->foreground);
2227 SetBkColor (s->hdc, s->gc->background);
791f420f
JR
2228 BitBlt (s->hdc, s->x, s->y, s->background_width, s->height,
2229 compat_hdc, 0, 0, SRCCOPY);
d30591dc 2230
791f420f
JR
2231 SelectObject (s->hdc, orig_brush);
2232 DeleteObject (fg_brush);
2233 SelectObject (compat_hdc, orig_obj);
2234 DeleteDC (compat_hdc);
2235 }
2236 DeleteObject (pixmap);
2237 pixmap = 0;
2238 }
2239 else
2240 x_draw_image_foreground (s);
ee78dc32 2241
791f420f
JR
2242 /* If we must draw a relief around the image, do it. */
2243 if (s->img->relief
2244 || s->hl == DRAW_IMAGE_RAISED
2245 || s->hl == DRAW_IMAGE_SUNKEN)
2246 x_draw_image_relief (s);
2247}
ee78dc32 2248
cabb23bc 2249
791f420f 2250/* Draw stretch glyph string S. */
cabb23bc 2251
791f420f 2252static void
b56ceb92 2253x_draw_stretch_glyph_string (struct glyph_string *s)
791f420f 2254{
a54e2c05 2255 eassert (s->first_glyph->type == STRETCH_GLYPH);
65c4903c 2256
791f420f
JR
2257 if (s->hl == DRAW_CURSOR
2258 && !x_stretch_cursor_p)
2259 {
b236615c
EZ
2260 /* If `x-stretch-cursor' is nil, don't draw a block cursor as
2261 wide as the stretch glyph. */
e8f6b0db 2262 int width, background_width = s->background_width;
b236615c 2263 int x = s->x;
e8f6b0db 2264
b236615c 2265 if (!s->row->reversed_p)
e8f6b0db 2266 {
b236615c
EZ
2267 int left_x = window_box_left_offset (s->w, TEXT_AREA);
2268
2269 if (x < left_x)
2270 {
2271 background_width -= left_x - x;
2272 x = left_x;
2273 }
2274 }
2275 else
2276 {
2277 /* In R2L rows, draw the cursor on the right edge of the
2278 stretch glyph. */
2279 int right_x = window_box_right_offset (s->w, TEXT_AREA);
2280
2281 if (x + background_width > right_x)
2282 background_width -= x - right_x;
2283 x += background_width;
e8f6b0db
KS
2284 }
2285 width = min (FRAME_COLUMN_WIDTH (s->f), background_width);
b236615c
EZ
2286 if (s->row->reversed_p)
2287 x -= width;
cabb23bc 2288
791f420f 2289 /* Draw cursor. */
e8f6b0db 2290 x_draw_glyph_string_bg_rect (s, x, s->y, width, s->height);
cabb23bc 2291
791f420f 2292 /* Clear rest using the GC of the original non-cursor face. */
e8f6b0db 2293 if (width < background_width)
791f420f
JR
2294 {
2295 XGCValues *gc = s->face->gc;
e8f6b0db
KS
2296 int y = s->y;
2297 int w = background_width - width, h = s->height;
791f420f
JR
2298 RECT r;
2299 HDC hdc = s->hdc;
9f5a911b 2300
b236615c
EZ
2301 if (!s->row->reversed_p)
2302 x += width;
2303 else
2304 x = s->x;
9f5a911b
JR
2305 if (s->row->mouse_face_p
2306 && cursor_in_mouse_face_p (s->w))
2307 {
2308 x_set_mouse_face_gc (s);
2309 gc = s->gc;
2310 }
2311 else
2312 gc = s->face->gc;
d67d1627 2313
89271099 2314 get_glyph_string_clip_rect (s, &r);
791f420f
JR
2315 w32_set_clip_rectangle (hdc, &r);
2316
01b220b6 2317#if 0 /* TODO: stipple */
791f420f
JR
2318 if (s->face->stipple)
2319 {
2320 /* Fill background with a stipple pattern. */
2321 XSetFillStyle (s->display, gc, FillOpaqueStippled);
2322 XFillRectangle (s->display, s->window, gc, x, y, w, h);
2323 XSetFillStyle (s->display, gc, FillSolid);
2324 }
2325 else
2326#endif
2327 {
2328 w32_fill_area (s->f, s->hdc, gc->background, x, y, w, h);
2329 }
2330 }
2331 }
9f5a911b 2332 else if (!s->background_filled_p)
e8f6b0db
KS
2333 {
2334 int background_width = s->background_width;
2335 int x = s->x, left_x = window_box_left_offset (s->w, TEXT_AREA);
2336
6c693929
KS
2337 /* Don't draw into left margin, fringe or scrollbar area
2338 except for header line and mode line. */
2339 if (x < left_x && !s->row->mode_line_p)
e8f6b0db
KS
2340 {
2341 background_width -= left_x - x;
2342 x = left_x;
2343 }
2344 if (background_width > 0)
2345 x_draw_glyph_string_bg_rect (s, x, s->y, background_width, s->height);
5e6b6dcd 2346 }
d67d1627 2347
791f420f
JR
2348 s->background_filled_p = 1;
2349}
cabb23bc 2350
cabb23bc 2351
791f420f
JR
2352/* Draw glyph string S. */
2353
2354static void
b56ceb92 2355x_draw_glyph_string (struct glyph_string *s)
791f420f 2356{
858a55c1
AI
2357 int relief_drawn_p = 0;
2358
791f420f
JR
2359 /* If S draws into the background of its successor, draw the
2360 background of the successor first so that S can draw into it.
2361 This makes S->next use XDrawString instead of XDrawImageString. */
c2ded1b7 2362 if (s->next && s->right_overhang && !s->for_overlaps)
791f420f 2363 {
027f6f90
JR
2364 int width;
2365 struct glyph_string *next;
e3f81cd5
CY
2366 for (width = 0, next = s->next;
2367 next && width < s->right_overhang;
027f6f90
JR
2368 width += next->width, next = next->next)
2369 if (next->first_glyph->type != IMAGE_GLYPH)
2370 {
2371 x_set_glyph_string_gc (next);
2372 x_set_glyph_string_clipping (next);
85bdc6d2
CY
2373 if (next->first_glyph->type == STRETCH_GLYPH)
2374 x_draw_stretch_glyph_string (next);
2375 else
2376 x_draw_glyph_string_background (next, 1);
3ca3504a 2377 next->num_clips = 0;
027f6f90 2378 }
791f420f
JR
2379 }
2380
2381 /* Set up S->gc, set clipping and draw S. */
2382 x_set_glyph_string_gc (s);
791f420f 2383
858a55c1
AI
2384 /* Draw relief (if any) in advance for char/composition so that the
2385 glyph string can be drawn over it. */
c2ded1b7 2386 if (!s->for_overlaps
858a55c1
AI
2387 && s->face->box != FACE_NO_BOX
2388 && (s->first_glyph->type == CHAR_GLYPH
2389 || s->first_glyph->type == COMPOSITE_GLYPH))
2390
2391 {
9f5a911b 2392 x_set_glyph_string_clipping (s);
858a55c1
AI
2393 x_draw_glyph_string_background (s, 1);
2394 x_draw_glyph_string_box (s);
9f5a911b 2395 x_set_glyph_string_clipping (s);
858a55c1
AI
2396 relief_drawn_p = 1;
2397 }
a6e0b7e5
JR
2398 else if (!s->clip_head /* draw_glyphs didn't specify a clip mask. */
2399 && !s->clip_tail
2400 && ((s->prev && s->prev->hl != s->hl && s->left_overhang)
2401 || (s->next && s->next->hl != s->hl && s->right_overhang)))
027f6f90
JR
2402 /* We must clip just this glyph. left_overhang part has already
2403 drawn when s->prev was drawn, and right_overhang part will be
2404 drawn later when s->next is drawn. */
2405 x_set_glyph_string_clipping_exactly (s, s);
9f5a911b
JR
2406 else
2407 x_set_glyph_string_clipping (s);
858a55c1 2408
791f420f
JR
2409 switch (s->first_glyph->type)
2410 {
2411 case IMAGE_GLYPH:
2412 x_draw_image_glyph_string (s);
2413 break;
2414
2415 case STRETCH_GLYPH:
2416 x_draw_stretch_glyph_string (s);
2417 break;
2418
2419 case CHAR_GLYPH:
c2ded1b7 2420 if (s->for_overlaps)
791f420f
JR
2421 s->background_filled_p = 1;
2422 else
2423 x_draw_glyph_string_background (s, 0);
2424 x_draw_glyph_string_foreground (s);
2425 break;
2426
2427 case COMPOSITE_GLYPH:
2b107652
KH
2428 if (s->for_overlaps || (s->cmp_from > 0
2429 && ! s->first_glyph->u.cmp.automatic))
791f420f
JR
2430 s->background_filled_p = 1;
2431 else
2432 x_draw_glyph_string_background (s, 1);
2433 x_draw_composite_glyph_string_foreground (s);
2434 break;
2435
b2cca856 2436 case GLYPHLESS_GLYPH:
65b6b59a 2437 if (s->for_overlaps)
b2cca856
KH
2438 s->background_filled_p = 1;
2439 else
65b6b59a 2440 x_draw_glyph_string_background (s, 0);
b2cca856
KH
2441 x_draw_glyphless_glyph_string_foreground (s);
2442 break;
2443
791f420f 2444 default:
1088b922 2445 emacs_abort ();
791f420f
JR
2446 }
2447
c2ded1b7 2448 if (!s->for_overlaps)
791f420f
JR
2449 {
2450 /* Draw underline. */
ef39ccbb 2451 if (s->face->underline_p)
791f420f 2452 {
9b0e3eba 2453 if (s->face->underline_type == FACE_UNDER_WAVE)
30f27523 2454 {
9b0e3eba
AA
2455 COLORREF color;
2456
2457 if (s->face->underline_defaulted_p)
2458 color = s->gc->foreground;
2459 else
2460 color = s->face->underline_color;
2461
2462 w32_draw_underwave (s, color);
ef39ccbb 2463 }
9b0e3eba 2464 else if (s->face->underline_type == FACE_UNDER_LINE)
ef39ccbb 2465 {
9b0e3eba
AA
2466 unsigned long thickness, position;
2467 int y;
2468
2469 if (s->prev && s->prev->face->underline_p)
2470 {
2471 /* We use the same underline style as the previous one. */
2472 thickness = s->prev->underline_thickness;
2473 position = s->prev->underline_position;
2474 }
ef39ccbb 2475 else
9b0e3eba
AA
2476 {
2477 /* Get the underline thickness. Default is 1 pixel. */
2478 if (s->font && s->font->underline_thickness > 0)
2479 thickness = s->font->underline_thickness;
2480 else
2481 thickness = 1;
2482 if (x_underline_at_descent_line)
2483 position = (s->height - thickness) - (s->ybase - s->y);
2484 else
2485 {
2486 /* Get the underline position. This is the recommended
2487 vertical offset in pixels from the baseline to the top of
2488 the underline. This is a signed value according to the
2489 specs, and its default is
2490
2491 ROUND ((maximum_descent) / 2), with
2492 ROUND (x) = floor (x + 0.5) */
2493
2494 if (x_use_underline_position_properties
2495 && s->font && s->font->underline_position >= 0)
2496 position = s->font->underline_position;
2497 else if (s->font)
2498 position = (s->font->descent + 1) / 2;
2499 }
2500 position = max (position, underline_minimum_offset);
2501 }
2502 /* Check the sanity of thickness and position. We should
2503 avoid drawing underline out of the current line area. */
2504 if (s->y + s->height <= s->ybase + position)
2505 position = (s->height - 1) - (s->ybase - s->y);
2506 if (s->y + s->height < s->ybase + position + thickness)
2507 thickness = (s->y + s->height) - (s->ybase + position);
2508 s->underline_thickness = thickness;
2509 s->underline_position =position;
2510 y = s->ybase + position;
2511 if (s->face->underline_defaulted_p)
2512 {
2513 w32_fill_area (s->f, s->hdc, s->gc->foreground, s->x,
2514 y, s->width, 1);
2515 }
ef39ccbb 2516 else
027f6f90 2517 {
9b0e3eba
AA
2518 w32_fill_area (s->f, s->hdc, s->face->underline_color, s->x,
2519 y, s->width, 1);
027f6f90 2520 }
791f420f
JR
2521 }
2522 }
791f420f
JR
2523 /* Draw overline. */
2524 if (s->face->overline_p)
2525 {
2526 unsigned long dy = 0, h = 1;
2527
2528 if (s->face->overline_color_defaulted_p)
027f6f90
JR
2529 {
2530 w32_fill_area (s->f, s->hdc, s->gc->foreground, s->x,
9a01ee33 2531 s->y + dy, s->width, h);
027f6f90 2532 }
791f420f
JR
2533 else
2534 {
59508699 2535 w32_fill_area (s->f, s->hdc, s->face->overline_color, s->x,
9a01ee33 2536 s->y + dy, s->width, h);
791f420f
JR
2537 }
2538 }
2539
2540 /* Draw strike-through. */
9ef2e2cf 2541 if (s->face->strike_through_p
ed3751c8 2542 && !FONT_TEXTMETRIC (s->font).tmStruckOut)
791f420f
JR
2543 {
2544 unsigned long h = 1;
2545 unsigned long dy = (s->height - h) / 2;
2546
2547 if (s->face->strike_through_color_defaulted_p)
2548 {
2549 w32_fill_area (s->f, s->hdc, s->gc->foreground, s->x, s->y + dy,
2550 s->width, h);
2551 }
2552 else
2553 {
def7fa34 2554 w32_fill_area (s->f, s->hdc, s->face->strike_through_color, s->x,
791f420f
JR
2555 s->y + dy, s->width, h);
2556 }
2557 }
2558
027f6f90 2559 /* Draw relief if not yet drawn. */
858a55c1 2560 if (!relief_drawn_p && s->face->box != FACE_NO_BOX)
791f420f 2561 x_draw_glyph_string_box (s);
027f6f90
JR
2562
2563 if (s->prev)
2564 {
2565 struct glyph_string *prev;
2566
2567 for (prev = s->prev; prev; prev = prev->prev)
2568 if (prev->hl != s->hl
2569 && prev->x + prev->width + prev->right_overhang > s->x)
2570 {
2571 /* As prev was drawn while clipped to its own area, we
2572 must draw the right_overhang part using s->hl now. */
2573 enum draw_glyphs_face save = prev->hl;
2574
2575 prev->hl = s->hl;
2576 x_set_glyph_string_gc (prev);
2577 x_set_glyph_string_clipping_exactly (s, prev);
2578 if (prev->first_glyph->type == CHAR_GLYPH)
2579 x_draw_glyph_string_foreground (prev);
2580 else
2581 x_draw_composite_glyph_string_foreground (prev);
2582 w32_set_clip_rectangle (prev->hdc, NULL);
2583 prev->hl = save;
3ca3504a 2584 prev->num_clips = 0;
027f6f90
JR
2585 }
2586 }
2587
2588 if (s->next)
2589 {
2590 struct glyph_string *next;
2591
2592 for (next = s->next; next; next = next->next)
2593 if (next->hl != s->hl
2594 && next->x - next->left_overhang < s->x + s->width)
2595 {
2596 /* As next will be drawn while clipped to its own area,
2597 we must draw the left_overhang part using s->hl now. */
2598 enum draw_glyphs_face save = next->hl;
2599
2600 next->hl = s->hl;
2601 x_set_glyph_string_gc (next);
2602 x_set_glyph_string_clipping_exactly (s, next);
2603 if (next->first_glyph->type == CHAR_GLYPH)
2604 x_draw_glyph_string_foreground (next);
2605 else
2606 x_draw_composite_glyph_string_foreground (next);
2607 w32_set_clip_rectangle (next->hdc, NULL);
2608 next->hl = save;
3ca3504a 2609 next->num_clips = 0;
3057e615 2610 next->clip_head = s->next;
027f6f90
JR
2611 }
2612 }
791f420f
JR
2613 }
2614
2615 /* Reset clipping. */
2616 w32_set_clip_rectangle (s->hdc, NULL);
3ca3504a 2617 s->num_clips = 0;
791f420f
JR
2618}
2619
2620
89271099 2621/* Shift display to make room for inserted glyphs. */
ee78dc32 2622
89271099 2623void
b56ceb92
JB
2624w32_shift_glyphs_for_insert (struct frame *f, int x, int y,
2625 int width, int height, int shift_by)
791f420f 2626{
791f420f
JR
2627 HDC hdc;
2628
791f420f 2629 hdc = get_frame_dc (f);
89271099
KS
2630 BitBlt (hdc, x + shift_by, y, width, height,
2631 hdc, x, y, SRCCOPY);
791f420f 2632
791f420f 2633 release_frame_dc (f, hdc);
ee78dc32 2634}
791f420f
JR
2635
2636
2637/* Delete N glyphs at the nominal cursor position. Not implemented
2638 for X frames. */
ee78dc32 2639
96214669 2640static void
b56ceb92 2641x_delete_glyphs (struct frame *f, register int n)
ee78dc32 2642{
7e6ac5b9
AI
2643 if (! FRAME_W32_P (f))
2644 return;
2645
1088b922 2646 emacs_abort ();
791f420f 2647}
ee78dc32 2648
ee78dc32 2649
7684e57b 2650/* Clear entire frame. */
791f420f 2651
96214669 2652static void
4a418b10 2653x_clear_frame (struct frame *f)
ee78dc32 2654{
7e6ac5b9
AI
2655 if (! FRAME_W32_P (f))
2656 return;
2657
791f420f
JR
2658 /* Clearing the frame will erase any cursor, so mark them all as no
2659 longer visible. */
2660 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2661 output_cursor.hpos = output_cursor.vpos = 0;
2662 output_cursor.x = -1;
ee78dc32 2663
791f420f
JR
2664 /* We don't set the output cursor here because there will always
2665 follow an explicit cursor_to. */
4d7e6e51 2666 block_input ();
ee78dc32 2667
fbd6baed 2668 w32_clear_window (f);
ee78dc32
GV
2669
2670 /* We have to clear the scroll bars, too. If we have changed
2671 colors or something like that, then they should be notified. */
2672 x_scroll_bar_clear (f);
2673
4d7e6e51 2674 unblock_input ();
ee78dc32 2675}
791f420f 2676
ee78dc32
GV
2677\f
2678/* Make audible bell. */
2679
96214669 2680static void
4a418b10 2681w32_ring_bell (struct frame *f)
ee78dc32 2682{
4d7e6e51 2683 block_input ();
ee78dc32 2684
0f32f023 2685 if (FRAME_W32_P (f) && visible_bell)
8331e676
GV
2686 {
2687 int i;
4a418b10 2688 HWND hwnd = FRAME_W32_WINDOW (f);
8331e676 2689
d67d1627 2690 for (i = 0; i < 5; i++)
8331e676
GV
2691 {
2692 FlashWindow (hwnd, TRUE);
2693 Sleep (10);
2694 }
2695 FlashWindow (hwnd, FALSE);
2696 }
ee78dc32 2697 else
4a418b10 2698 w32_sys_ring_bell (f);
ee78dc32 2699
4d7e6e51 2700 unblock_input ();
ee78dc32 2701}
791f420f 2702
ee78dc32 2703\f
791f420f
JR
2704/* Specify how many text lines, from the top of the window,
2705 should be affected by insert-lines and delete-lines operations.
2706 This, and those operations, are used only within an update
2707 that is bounded by calls to x_update_begin and x_update_end. */
ee78dc32 2708
96214669 2709static void
b56ceb92 2710w32_set_terminal_window (struct frame *f, int n)
ee78dc32 2711{
791f420f 2712 /* This function intentionally left blank. */
ee78dc32 2713}
791f420f
JR
2714
2715\f
2716/***********************************************************************
2717 Line Dance
2718 ***********************************************************************/
2719
2720/* Perform an insert-lines or delete-lines operation, inserting N
2721 lines or deleting -N lines at vertical position VPOS. */
ee78dc32 2722
96214669 2723static void
b56ceb92 2724x_ins_del_lines (struct frame *f, int vpos, int n)
ee78dc32 2725{
7e6ac5b9
AI
2726 if (! FRAME_W32_P (f))
2727 return;
2728
1088b922 2729 emacs_abort ();
ee78dc32 2730}
791f420f
JR
2731
2732
2733/* Scroll part of the display as described by RUN. */
2734
2735static void
b56ceb92 2736x_scroll_run (struct window *w, struct run *run)
791f420f 2737{
d3d50620 2738 struct frame *f = XFRAME (w->frame);
791f420f 2739 int x, y, width, height, from_y, to_y, bottom_y;
4d6e8199
JR
2740 HWND hwnd = FRAME_W32_WINDOW (f);
2741 HRGN expect_dirty;
791f420f
JR
2742
2743 /* Get frame-relative bounding box of the text display area of W,
33c34bea
KS
2744 without mode lines. Include in this box the left and right
2745 fringes of W. */
791f420f 2746 window_box (w, -1, &x, &y, &width, &height);
791f420f 2747
7db47798
YM
2748 /* If the fringe is adjacent to the left (right) scroll bar of a
2749 leftmost (rightmost, respectively) window, then extend its
2750 background to the gap between the fringe and the bar. */
2751 if ((WINDOW_LEFTMOST_P (w)
2752 && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
2753 || (WINDOW_RIGHTMOST_P (w)
2754 && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w)))
2755 {
2756 int sb_width = WINDOW_CONFIG_SCROLL_BAR_WIDTH (w);
2757
2758 if (sb_width > 0)
2759 {
2760 int bar_area_x = WINDOW_SCROLL_BAR_AREA_X (w);
2761 int bar_area_width = (WINDOW_CONFIG_SCROLL_BAR_COLS (w)
2762 * FRAME_COLUMN_WIDTH (f));
2763
2764 if (bar_area_x + bar_area_width == x)
2765 {
2766 x = bar_area_x + sb_width;
2767 width += bar_area_width - sb_width;
2768 }
2769 else if (x + width == bar_area_x)
2770 width += bar_area_width - sb_width;
2771 }
2772 }
2773
791f420f
JR
2774 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2775 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2776 bottom_y = y + height;
2777
2778 if (to_y < from_y)
2779 {
2780 /* Scrolling up. Make sure we don't copy part of the mode
2781 line at the bottom. */
2782 if (from_y + run->height > bottom_y)
2783 height = bottom_y - from_y;
2784 else
2785 height = run->height;
4d6e8199 2786 expect_dirty = CreateRectRgn (x, y + height, x + width, bottom_y);
791f420f
JR
2787 }
2788 else
2789 {
fa463103 2790 /* Scrolling down. Make sure we don't copy over the mode line.
791f420f
JR
2791 at the bottom. */
2792 if (to_y + run->height > bottom_y)
2793 height = bottom_y - to_y;
2794 else
2795 height = run->height;
4d6e8199 2796 expect_dirty = CreateRectRgn (x, y, x + width, to_y);
791f420f
JR
2797 }
2798
4d7e6e51 2799 block_input ();
d67d1627 2800
791f420f
JR
2801 /* Cursor off. Will be switched on again in x_update_window_end. */
2802 updated_window = w;
2803 x_clear_cursor (w);
2804
4d6e8199
JR
2805 {
2806 RECT from;
2807 RECT to;
2808 HRGN dirty = CreateRectRgn (0, 0, 0, 0);
2809 HRGN combined = CreateRectRgn (0, 0, 0, 0);
2810
2811 from.left = to.left = x;
2812 from.right = to.right = x + width;
2813 from.top = from_y;
2814 from.bottom = from_y + height;
2815 to.top = y;
2816 to.bottom = bottom_y;
2817
2818 ScrollWindowEx (hwnd, 0, to_y - from_y, &from, &to, dirty,
2819 NULL, SW_INVALIDATE);
2820
2821 /* Combine this with what we expect to be dirty. This covers the
2822 case where not all of the region we expect is actually dirty. */
2823 CombineRgn (combined, dirty, expect_dirty, RGN_OR);
2824
2825 /* If the dirty region is not what we expected, redraw the entire frame. */
2826 if (!EqualRgn (combined, expect_dirty))
2827 SET_FRAME_GARBAGED (f);
e8ac5d88
JR
2828
2829 DeleteObject (dirty);
2830 DeleteObject (combined);
4d6e8199
JR
2831 }
2832
4d7e6e51 2833 unblock_input ();
e8ac5d88 2834 DeleteObject (expect_dirty);
791f420f
JR
2835}
2836
9ef2e2cf 2837
ee78dc32 2838\f
791f420f
JR
2839/***********************************************************************
2840 Exposure Events
2841 ***********************************************************************/
d67d1627 2842
96214669 2843static void
b56ceb92 2844frame_highlight (struct frame *f)
ee78dc32 2845{
89271099 2846 x_update_cursor (f, 1);
8b61a891 2847 x_set_frame_alpha (f);
89271099 2848}
791f420f 2849
89271099 2850static void
b56ceb92 2851frame_unhighlight (struct frame *f)
89271099
KS
2852{
2853 x_update_cursor (f, 1);
8b61a891 2854 x_set_frame_alpha (f);
89271099 2855}
791f420f 2856
89271099
KS
2857/* The focus has changed. Update the frames as necessary to reflect
2858 the new situation. Note that we can't change the selected frame
2859 here, because the Lisp code we are interrupting might become confused.
2860 Each event gets marked with the frame in which it occurred, so the
2861 Lisp code can tell when the switch took place by examining the events. */
791f420f 2862
89271099 2863static void
b56ceb92 2864x_new_focus_frame (struct w32_display_info *dpyinfo, struct frame *frame)
89271099
KS
2865{
2866 struct frame *old_focus = dpyinfo->w32_focus_frame;
791f420f 2867
89271099 2868 if (frame != dpyinfo->w32_focus_frame)
791f420f 2869 {
89271099
KS
2870 /* Set this before calling other routines, so that they see
2871 the correct value of w32_focus_frame. */
2872 dpyinfo->w32_focus_frame = frame;
791f420f 2873
89271099
KS
2874 if (old_focus && old_focus->auto_lower)
2875 x_lower_frame (old_focus);
791f420f 2876
89271099
KS
2877 if (dpyinfo->w32_focus_frame && dpyinfo->w32_focus_frame->auto_raise)
2878 pending_autoraise_frame = dpyinfo->w32_focus_frame;
2df85294 2879 else
89271099 2880 pending_autoraise_frame = 0;
791f420f 2881 }
89271099
KS
2882
2883 x_frame_rehighlight (dpyinfo);
791f420f
JR
2884}
2885
55131bef
JR
2886
2887/* Handle FocusIn and FocusOut state changes for FRAME.
2888 If FRAME has focus and there exists more than one frame, puts
2889 a FOCUS_IN_EVENT into *BUFP. */
2890
2891static void
b56ceb92
JB
2892x_focus_changed (int type, int state, struct w32_display_info *dpyinfo,
2893 struct frame *frame, struct input_event *bufp)
55131bef
JR
2894{
2895 if (type == WM_SETFOCUS)
2896 {
2897 if (dpyinfo->w32_focus_event_frame != frame)
2898 {
2899 x_new_focus_frame (dpyinfo, frame);
2900 dpyinfo->w32_focus_event_frame = frame;
2901
2902 /* Don't stop displaying the initial startup message
2903 for a switch-frame event we don't need. */
8e50cc2d
SM
2904 if (NILP (Vterminal_frame)
2905 && CONSP (Vframe_list)
2906 && !NILP (XCDR (Vframe_list)))
55131bef
JR
2907 {
2908 bufp->kind = FOCUS_IN_EVENT;
2909 XSETFRAME (bufp->frame_or_window, frame);
2910 }
2911 }
2912
2913 frame->output_data.x->focus_state |= state;
2914
2915 /* TODO: IME focus? */
2916 }
2917 else if (type == WM_KILLFOCUS)
2918 {
2919 frame->output_data.x->focus_state &= ~state;
2920
2921 if (dpyinfo->w32_focus_event_frame == frame)
2922 {
2923 dpyinfo->w32_focus_event_frame = 0;
2924 x_new_focus_frame (dpyinfo, 0);
2925 }
2926
2927 /* TODO: IME focus? */
2928 }
2929}
2930
2931
2932/* The focus may have changed. Figure out if it is a real focus change,
2933 by checking both FocusIn/Out and Enter/LeaveNotify events.
2934
2935 Returns FOCUS_IN_EVENT event in *BUFP. */
2936
2937static void
b56ceb92
JB
2938w32_detect_focus_change (struct w32_display_info *dpyinfo, W32Msg *event,
2939 struct input_event *bufp)
55131bef
JR
2940{
2941 struct frame *frame;
2942
2943 frame = x_any_window_to_frame (dpyinfo, event->msg.hwnd);
2944 if (! frame)
2945 return;
2946
2947 /* On w32, this is only called from focus events, so no switch needed. */
2948 x_focus_changed (event->msg.message,
2949 (event->msg.message == WM_KILLFOCUS ?
2950 FOCUS_IMPLICIT : FOCUS_EXPLICIT),
2951 dpyinfo, frame, bufp);
2952}
2953
2954
89271099 2955/* Handle an event saying the mouse has moved out of an Emacs frame. */
ee78dc32
GV
2956
2957void
b56ceb92 2958x_mouse_leave (struct w32_display_info *dpyinfo)
ee78dc32 2959{
fbd6baed 2960 x_new_focus_frame (dpyinfo, dpyinfo->w32_focus_event_frame);
ee78dc32
GV
2961}
2962
2963/* The focus has changed, or we have redirected a frame's focus to
2964 another frame (this happens when a frame uses a surrogate
9ef2e2cf 2965 mini-buffer frame). Shift the highlight as appropriate.
ee78dc32
GV
2966
2967 The FRAME argument doesn't necessarily have anything to do with which
9ef2e2cf
JR
2968 frame is being highlighted or un-highlighted; we only use it to find
2969 the appropriate X display info. */
2970
ee78dc32 2971static void
b56ceb92 2972w32_frame_rehighlight (struct frame *frame)
ee78dc32 2973{
7e6ac5b9
AI
2974 if (! FRAME_W32_P (frame))
2975 return;
fbd6baed 2976 x_frame_rehighlight (FRAME_W32_DISPLAY_INFO (frame));
ee78dc32
GV
2977}
2978
2979static void
b56ceb92 2980x_frame_rehighlight (struct w32_display_info *dpyinfo)
ee78dc32 2981{
4baaed0f 2982 struct frame *old_highlight = dpyinfo->x_highlight_frame;
ee78dc32 2983
fbd6baed 2984 if (dpyinfo->w32_focus_frame)
ee78dc32 2985 {
4baaed0f 2986 dpyinfo->x_highlight_frame
8e50cc2d 2987 = ((FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->w32_focus_frame)))
fbd6baed
GV
2988 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->w32_focus_frame))
2989 : dpyinfo->w32_focus_frame);
4baaed0f 2990 if (! FRAME_LIVE_P (dpyinfo->x_highlight_frame))
ee78dc32 2991 {
f00af5b1 2992 fset_focus_frame (dpyinfo->w32_focus_frame, Qnil);
4baaed0f 2993 dpyinfo->x_highlight_frame = dpyinfo->w32_focus_frame;
ee78dc32
GV
2994 }
2995 }
2996 else
4baaed0f 2997 dpyinfo->x_highlight_frame = 0;
ee78dc32 2998
4baaed0f 2999 if (dpyinfo->x_highlight_frame != old_highlight)
ee78dc32
GV
3000 {
3001 if (old_highlight)
3002 frame_unhighlight (old_highlight);
4baaed0f
KS
3003 if (dpyinfo->x_highlight_frame)
3004 frame_highlight (dpyinfo->x_highlight_frame);
ee78dc32
GV
3005 }
3006}
3007\f
3008/* Keyboard processing - modifier keys, etc. */
3009
3010/* Convert a keysym to its name. */
3011
3012char *
b56ceb92 3013x_get_keysym_name (int keysym)
ee78dc32
GV
3014{
3015 /* Make static so we can always return it */
3016 static char value[100];
3017
4d7e6e51 3018 block_input ();
9127e20e 3019 GetKeyNameText (keysym, value, 100);
4d7e6e51 3020 unblock_input ();
ee78dc32
GV
3021
3022 return value;
3023}
9ef2e2cf 3024
b56ceb92
JB
3025static int
3026codepage_for_locale (LCID locale)
13087e59
JR
3027{
3028 char cp[20];
3029
3030 if (GetLocaleInfo (locale, LOCALE_IDEFAULTANSICODEPAGE, cp, 20) > 0)
3031 return atoi (cp);
3032 else
3033 return CP_ACP;
3034}
9ef2e2cf 3035
ee78dc32
GV
3036\f
3037/* Mouse clicks and mouse movement. Rah. */
3038
53823ab9
JR
3039/* Parse a button MESSAGE. The button index is returned in PBUTTON, and
3040 the state in PUP. XBUTTON provides extra information for extended mouse
3041 button messages. Returns FALSE if unable to parse the message. */
d67d1627 3042BOOL
b56ceb92 3043parse_button (int message, int xbutton, int * pbutton, int * pup)
ee78dc32
GV
3044{
3045 int button = 0;
3046 int up = 0;
d67d1627 3047
ee78dc32
GV
3048 switch (message)
3049 {
3050 case WM_LBUTTONDOWN:
3051 button = 0;
3052 up = 0;
3053 break;
3054 case WM_LBUTTONUP:
3055 button = 0;
3056 up = 1;
3057 break;
3058 case WM_MBUTTONDOWN:
fbd6baed 3059 if (NILP (Vw32_swap_mouse_buttons))
52cf03a1
GV
3060 button = 1;
3061 else
3062 button = 2;
ee78dc32
GV
3063 up = 0;
3064 break;
3065 case WM_MBUTTONUP:
fbd6baed 3066 if (NILP (Vw32_swap_mouse_buttons))
52cf03a1
GV
3067 button = 1;
3068 else
3069 button = 2;
ee78dc32
GV
3070 up = 1;
3071 break;
3072 case WM_RBUTTONDOWN:
fbd6baed 3073 if (NILP (Vw32_swap_mouse_buttons))
52cf03a1
GV
3074 button = 2;
3075 else
3076 button = 1;
ee78dc32
GV
3077 up = 0;
3078 break;
3079 case WM_RBUTTONUP:
fbd6baed 3080 if (NILP (Vw32_swap_mouse_buttons))
52cf03a1
GV
3081 button = 2;
3082 else
3083 button = 1;
ee78dc32
GV
3084 up = 1;
3085 break;
53823ab9
JR
3086 case WM_XBUTTONDOWN:
3087 button = xbutton + 2;
3088 up = 0;
3089 break;
3090 case WM_XBUTTONUP:
3091 button = xbutton + 2;
3092 up = 1;
3093 break;
ee78dc32
GV
3094 default:
3095 return (FALSE);
3096 }
d67d1627 3097
ee78dc32
GV
3098 if (pup) *pup = up;
3099 if (pbutton) *pbutton = button;
d67d1627 3100
ee78dc32
GV
3101 return (TRUE);
3102}
3103
3104
3105/* Prepare a mouse-event in *RESULT for placement in the input queue.
3106
3107 If the event is a button press, then note that we have grabbed
3108 the mouse. */
3109
ec48c3a7 3110static Lisp_Object
b56ceb92 3111construct_mouse_click (struct input_event *result, W32Msg *msg, struct frame *f)
ee78dc32
GV
3112{
3113 int button;
3114 int up;
3115
53823ab9
JR
3116 parse_button (msg->msg.message, HIWORD (msg->msg.wParam),
3117 &button, &up);
ee78dc32 3118
3b8f9651 3119 /* Make the event type NO_EVENT; we'll change that when we decide
ee78dc32 3120 otherwise. */
3b8f9651 3121 result->kind = MOUSE_CLICK_EVENT;
ee78dc32
GV
3122 result->code = button;
3123 result->timestamp = msg->msg.time;
3124 result->modifiers = (msg->dwModifiers
3125 | (up
3126 ? up_modifier
3127 : down_modifier));
3128
ec48c3a7
JR
3129 XSETINT (result->x, LOWORD (msg->msg.lParam));
3130 XSETINT (result->y, HIWORD (msg->msg.lParam));
3131 XSETFRAME (result->frame_or_window, f);
3132 result->arg = Qnil;
3133 return Qnil;
ee78dc32
GV
3134}
3135
ec48c3a7 3136static Lisp_Object
b56ceb92 3137construct_mouse_wheel (struct input_event *result, W32Msg *msg, struct frame *f)
689004fa
GV
3138{
3139 POINT p;
637ad49d
JR
3140 int delta;
3141
1526bc23
JR
3142 result->kind = msg->msg.message == WM_MOUSEHWHEEL ? HORIZ_WHEEL_EVENT
3143 : WHEEL_EVENT;
637ad49d 3144 result->code = 0;
689004fa 3145 result->timestamp = msg->msg.time;
637ad49d
JR
3146
3147 /* A WHEEL_DELTA positive value indicates that the wheel was rotated
3148 forward, away from the user (up); a negative value indicates that
3149 the wheel was rotated backward, toward the user (down). */
3150 delta = GET_WHEEL_DELTA_WPARAM (msg->msg.wParam);
3151
3152 /* The up and down modifiers indicate if the wheel was rotated up or
3153 down based on WHEEL_DELTA value. */
3154 result->modifiers = (msg->dwModifiers
3155 | ((delta < 0 ) ? down_modifier : up_modifier));
3156
8b03732e
JR
3157 /* With multiple monitors, we can legitimately get negative
3158 coordinates, so cast to short to interpret them correctly. */
3159 p.x = (short) LOWORD (msg->msg.lParam);
3160 p.y = (short) HIWORD (msg->msg.lParam);
9127e20e 3161 ScreenToClient (msg->msg.hwnd, &p);
689004fa
GV
3162 XSETINT (result->x, p.x);
3163 XSETINT (result->y, p.y);
3164 XSETFRAME (result->frame_or_window, f);
7e889510 3165 result->arg = Qnil;
ec48c3a7 3166 return Qnil;
689004fa
GV
3167}
3168
ec48c3a7 3169static Lisp_Object
b56ceb92 3170construct_drag_n_drop (struct input_event *result, W32Msg *msg, struct frame *f)
12857dfd
RS
3171{
3172 Lisp_Object files;
3173 Lisp_Object frame;
3174 HDROP hdrop;
3175 POINT p;
3176 WORD num_files;
89271099
KS
3177 char *name;
3178 int i, len;
d67d1627 3179
89271099
KS
3180 result->kind = DRAG_N_DROP_EVENT;
3181 result->code = 0;
3182 result->timestamp = msg->msg.time;
3183 result->modifiers = msg->dwModifiers;
791f420f 3184
89271099
KS
3185 hdrop = (HDROP) msg->msg.wParam;
3186 DragQueryPoint (hdrop, &p);
791f420f 3187
89271099
KS
3188#if 0
3189 p.x = LOWORD (msg->msg.lParam);
3190 p.y = HIWORD (msg->msg.lParam);
3191 ScreenToClient (msg->msg.hwnd, &p);
3192#endif
791f420f 3193
89271099
KS
3194 XSETINT (result->x, p.x);
3195 XSETINT (result->y, p.y);
791f420f 3196
89271099
KS
3197 num_files = DragQueryFile (hdrop, 0xFFFFFFFF, NULL, 0);
3198 files = Qnil;
ee78dc32 3199
89271099
KS
3200 for (i = 0; i < num_files; i++)
3201 {
3202 len = DragQueryFile (hdrop, i, NULL, 0);
3203 if (len <= 0)
3204 continue;
3205 name = alloca (len + 1);
3206 DragQueryFile (hdrop, i, name, len + 1);
3207 files = Fcons (DECODE_FILE (build_string (name)), files);
ee78dc32
GV
3208 }
3209
89271099 3210 DragFinish (hdrop);
2bf04b9d 3211
89271099 3212 XSETFRAME (frame, f);
00cff0a1
YM
3213 result->frame_or_window = frame;
3214 result->arg = files;
89271099 3215 return Qnil;
ee78dc32
GV
3216}
3217
c5c91b84
EZ
3218\f
3219/* File event notifications (see w32notify.c). */
3220
182b170f 3221Lisp_Object
477f1e50
EZ
3222lispy_file_action (DWORD action)
3223{
3224 static char unknown_fmt[] = "unknown-action(%d)";
3225 Lisp_Object retval;
3226
3227 switch (action)
3228 {
3229 case FILE_ACTION_ADDED:
3230 retval = Qadded;
3231 break;
3232 case FILE_ACTION_REMOVED:
3233 retval = Qremoved;
3234 break;
3235 case FILE_ACTION_MODIFIED:
3236 retval = Qmodified;
3237 break;
3238 case FILE_ACTION_RENAMED_OLD_NAME:
3239 retval = Qrenamed_from;
3240 break;
3241 case FILE_ACTION_RENAMED_NEW_NAME:
3242 retval = Qrenamed_to;
3243 break;
3244 default:
3245 {
3246 char buf[sizeof(unknown_fmt) - 1 + INT_STRLEN_BOUND (DWORD)];
3247
3248 sprintf (buf, unknown_fmt, action);
3249 retval = intern (buf);
3250 }
3251 break;
3252 }
3253
3254 return retval;
3255}
3256
3257/* Put file notifications into the Emacs input event queue. This
3258 function runs when the WM_EMACS_FILENOTIFY message arrives from a
3259 watcher thread. */
3260static void
3261queue_notifications (struct input_event *event, W32Msg *msg, struct frame *f,
3262 int *evcount)
3263{
3264 BYTE *p = file_notifications;
3265 FILE_NOTIFY_INFORMATION *fni = (PFILE_NOTIFY_INFORMATION)p;
3266 const DWORD min_size
3267 = offsetof (FILE_NOTIFY_INFORMATION, FileName) + sizeof(wchar_t);
3268 Lisp_Object frame;
3269
3270 /* We cannot process notification before Emacs is fully initialized,
3271 since we need the UTF-16LE coding-system to be set up. */
3272 if (!initialized)
3273 {
3274 notification_buffer_in_use = 0;
3275 return;
3276 }
3277
3278 XSETFRAME (frame, f);
3279
3280 enter_crit ();
3281 if (notification_buffer_in_use)
3282 {
3283 DWORD info_size = notifications_size;
4f0800ec 3284 Lisp_Object cs = intern ("utf-16le");
0b86d359 3285 Lisp_Object obj = w32_get_watch_object (notifications_desc);
477f1e50
EZ
3286
3287 /* notifications_size could be zero when the buffer of
3288 notifications overflowed on the OS level, or when the
3289 directory being watched was itself deleted. Do nothing in
3290 that case. */
4f0800ec
EZ
3291 if (info_size
3292 && !NILP (obj) && CONSP (obj))
477f1e50 3293 {
4f0800ec
EZ
3294 Lisp_Object callback = XCDR (obj);
3295
477f1e50
EZ
3296 while (info_size >= min_size)
3297 {
3298 Lisp_Object utf_16_fn
3299 = make_unibyte_string ((char *)fni->FileName,
3300 fni->FileNameLength);
3301 /* Note: mule-conf is preloaded, so utf-16le must
3302 already be defined at this point. */
3303 Lisp_Object fname
4f0800ec 3304 = code_convert_string_norecord (utf_16_fn, cs, 0);
477f1e50 3305 Lisp_Object action = lispy_file_action (fni->Action);
477f1e50 3306
4f0800ec
EZ
3307 event->kind = FILE_NOTIFY_EVENT;
3308 event->code = (ptrdiff_t)notifications_desc;
3309 event->timestamp = msg->msg.time;
3310 event->modifiers = 0;
3311 event->frame_or_window = callback;
3312 event->arg = Fcons (action, fname);
3313 kbd_buffer_store_event (event);
3314 (*evcount)++;
477f1e50
EZ
3315
3316 if (!fni->NextEntryOffset)
3317 break;
3318 p += fni->NextEntryOffset;
3319 fni = (PFILE_NOTIFY_INFORMATION)p;
3320 info_size -= fni->NextEntryOffset;
3321 }
3322 }
3323 notification_buffer_in_use = 0;
3324 }
3325 else
3326 DebPrint (("We were promised notifications, but in-use flag is zero!\n"));
3327 leave_crit ();
3328
3329 /* We've stuffed all the events ourselves, so w32_read_socket shouldn't. */
3330 event->kind = NO_EVENT;
3331}
3332
89271099
KS
3333\f
3334/* Function to report a mouse movement to the mainstream Emacs code.
3335 The input handler calls this.
ee78dc32 3336
89271099
KS
3337 We have received a mouse movement event, which is given in *event.
3338 If the mouse is over a different glyph than it was last time, tell
3339 the mainstream emacs code by setting mouse_moved. If not, ask for
3340 another motion event, so we can check again the next time it moves. */
31d4844a 3341
89271099
KS
3342static MSG last_mouse_motion_event;
3343static Lisp_Object last_mouse_motion_frame;
ec48c3a7 3344
fc5c7550 3345static int
b56ceb92 3346note_mouse_movement (FRAME_PTR frame, MSG *msg)
ec48c3a7 3347{
89271099
KS
3348 int mouse_x = LOWORD (msg->lParam);
3349 int mouse_y = HIWORD (msg->lParam);
ec48c3a7 3350
89271099
KS
3351 last_mouse_movement_time = msg->time;
3352 memcpy (&last_mouse_motion_event, msg, sizeof (last_mouse_motion_event));
3353 XSETFRAME (last_mouse_motion_frame, frame);
31d4844a 3354
027f6f90
JR
3355 if (!FRAME_X_OUTPUT (frame))
3356 return 0;
3357
89271099
KS
3358 if (msg->hwnd != FRAME_W32_WINDOW (frame))
3359 {
3360 frame->mouse_moved = 1;
3361 last_mouse_scroll_bar = Qnil;
3362 note_mouse_highlight (frame, -1, -1);
d3499758 3363 last_mouse_glyph_frame = 0;
fc5c7550 3364 return 1;
89271099 3365 }
31d4844a 3366
89271099 3367 /* Has the mouse moved off the glyph it was on at the last sighting? */
d3499758
JR
3368 if (frame != last_mouse_glyph_frame
3369 || mouse_x < last_mouse_glyph.left
fc5c7550
YM
3370 || mouse_x >= last_mouse_glyph.right
3371 || mouse_y < last_mouse_glyph.top
3372 || mouse_y >= last_mouse_glyph.bottom)
31d4844a 3373 {
89271099
KS
3374 frame->mouse_moved = 1;
3375 last_mouse_scroll_bar = Qnil;
3376 note_mouse_highlight (frame, mouse_x, mouse_y);
3377 /* Remember the mouse position here, as w32_mouse_position only
3378 gets called when mouse tracking is enabled but we also need
3379 to keep track of the mouse for help_echo and highlighting at
3380 other times. */
1bb92eca 3381 remember_mouse_glyph (frame, mouse_x, mouse_y, &last_mouse_glyph);
d3499758 3382 last_mouse_glyph_frame = frame;
fc5c7550 3383 return 1;
31d4844a 3384 }
fc5c7550
YM
3385
3386 return 0;
31d4844a 3387}
89271099 3388
ee78dc32 3389\f
89271099
KS
3390/************************************************************************
3391 Mouse Face
3392 ************************************************************************/
3393
b56ceb92
JB
3394static struct scroll_bar *x_window_to_scroll_bar (Window);
3395static void x_scroll_bar_report_motion (FRAME_PTR *, Lisp_Object *,
3396 enum scroll_bar_part *,
3397 Lisp_Object *, Lisp_Object *,
3398 unsigned long *);
f57e2426 3399static void x_check_fullscreen (struct frame *);
9f5a911b 3400
89271099 3401static void
b56ceb92 3402redo_mouse_highlight (void)
89271099
KS
3403{
3404 if (!NILP (last_mouse_motion_frame)
3405 && FRAME_LIVE_P (XFRAME (last_mouse_motion_frame)))
3406 note_mouse_highlight (XFRAME (last_mouse_motion_frame),
3407 LOWORD (last_mouse_motion_event.lParam),
3408 HIWORD (last_mouse_motion_event.lParam));
3409}
3410
1bb8a291 3411static void
b56ceb92 3412w32_define_cursor (Window window, Cursor cursor)
89271099
KS
3413{
3414 PostMessage (window, WM_EMACS_SETCURSOR, (WPARAM) cursor, 0);
3415}
ee78dc32
GV
3416/* Return the current position of the mouse.
3417 *fp should be a frame which indicates which display to ask about.
3418
3419 If the mouse movement started in a scroll bar, set *fp, *bar_window,
3420 and *part to the frame, window, and scroll bar part that the mouse
3421 is over. Set *x and *y to the portion and whole of the mouse's
3422 position on the scroll bar.
3423
3424 If the mouse movement started elsewhere, set *fp to the frame the
3425 mouse is on, *bar_window to nil, and *x and *y to the character cell
3426 the mouse is over.
3427
9ef2e2cf 3428 Set *time to the server time-stamp for the time at which the mouse
ee78dc32
GV
3429 was at this position.
3430
3431 Don't store anything if we don't have a valid set of values to report.
3432
3433 This clears the mouse_moved flag, so we can wait for the next mouse
9ef2e2cf 3434 movement. */
ee78dc32
GV
3435
3436static void
b56ceb92
JB
3437w32_mouse_position (FRAME_PTR *fp, int insist, Lisp_Object *bar_window,
3438 enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
3439 unsigned long *time)
ee78dc32
GV
3440{
3441 FRAME_PTR f1;
3442
4d7e6e51 3443 block_input ();
ee78dc32 3444
95fa970d 3445 if (! NILP (last_mouse_scroll_bar) && insist == 0)
ee78dc32
GV
3446 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
3447 else
3448 {
3449 POINT pt;
3450
3451 Lisp_Object frame, tail;
3452
3453 /* Clear the mouse-moved flag for every frame on this display. */
3454 FOR_EACH_FRAME (tail, frame)
3455 XFRAME (frame)->mouse_moved = 0;
3456
3457 last_mouse_scroll_bar = Qnil;
d67d1627 3458
ee78dc32
GV
3459 GetCursorPos (&pt);
3460
3461 /* Now we have a position on the root; find the innermost window
3462 containing the pointer. */
3463 {
fbd6baed 3464 if (FRAME_W32_DISPLAY_INFO (*fp)->grabbed && last_mouse_frame
ee78dc32
GV
3465 && FRAME_LIVE_P (last_mouse_frame))
3466 {
08712a41
AI
3467 /* If mouse was grabbed on a frame, give coords for that frame
3468 even if the mouse is now outside it. */
ee78dc32
GV
3469 f1 = last_mouse_frame;
3470 }
3471 else
3472 {
08712a41 3473 /* Is window under mouse one of our frames? */
9f5a911b 3474 f1 = x_any_window_to_frame (FRAME_W32_DISPLAY_INFO (*fp),
9127e20e 3475 WindowFromPoint (pt));
ee78dc32
GV
3476 }
3477
3478 /* If not, is it one of our scroll bars? */
3479 if (! f1)
3480 {
9127e20e
JR
3481 struct scroll_bar *bar
3482 = x_window_to_scroll_bar (WindowFromPoint (pt));
ee78dc32
GV
3483
3484 if (bar)
3485 {
3486 f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
3487 }
3488 }
3489
95fa970d 3490 if (f1 == 0 && insist > 0)
791f420f 3491 f1 = SELECTED_FRAME ();
ee78dc32
GV
3492
3493 if (f1)
3494 {
791f420f
JR
3495 /* Ok, we found a frame. Store all the values.
3496 last_mouse_glyph is a rectangle used to reduce the
3497 generation of mouse events. To not miss any motion
3498 events, we must divide the frame into rectangles of the
3499 size of the smallest character that could be displayed
3500 on it, i.e. into the same rectangles that matrices on
3501 the frame are divided into. */
3502
791f420f 3503 ScreenToClient (FRAME_W32_WINDOW (f1), &pt);
1bb92eca 3504 remember_mouse_glyph (f1, pt.x, pt.y, &last_mouse_glyph);
d3499758 3505 last_mouse_glyph_frame = f1;
ee78dc32
GV
3506
3507 *bar_window = Qnil;
3508 *part = 0;
3509 *fp = f1;
3510 XSETINT (*x, pt.x);
3511 XSETINT (*y, pt.y);
3512 *time = last_mouse_movement_time;
3513 }
3514 }
3515 }
3516
4d7e6e51 3517 unblock_input ();
ee78dc32 3518}
791f420f 3519
ee78dc32 3520\f
89271099
KS
3521/***********************************************************************
3522 Tool-bars
3523 ***********************************************************************/
3524
3525/* Handle mouse button event on the tool-bar of frame F, at
301b181a 3526 frame-relative coordinates X/Y. EVENT_TYPE is either ButtonPress
09e80d9f 3527 or ButtonRelease. */
89271099
KS
3528
3529static void
b56ceb92 3530w32_handle_tool_bar_click (struct frame *f, struct input_event *button_event)
89271099
KS
3531{
3532 int x = XFASTINT (button_event->x);
3533 int y = XFASTINT (button_event->y);
3534
3535 if (button_event->modifiers & down_modifier)
3536 handle_tool_bar_click (f, x, y, 1, 0);
3537 else
3538 handle_tool_bar_click (f, x, y, 0,
3539 button_event->modifiers & ~up_modifier);
3540}
3541
3542
3543\f
3544/***********************************************************************
3545 Scroll bars
3546 ***********************************************************************/
3547
ee78dc32
GV
3548/* Scroll bar support. */
3549
ec48c3a7 3550/* Given a window ID, find the struct scroll_bar which manages it.
ee78dc32
GV
3551 This can be called in GC, so we have to make sure to strip off mark
3552 bits. */
9ef2e2cf
JR
3553
3554static struct scroll_bar *
b56ceb92 3555x_window_to_scroll_bar (Window window_id)
ee78dc32 3556{
791f420f 3557 Lisp_Object tail;
ee78dc32 3558
8e50cc2d 3559 for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
ee78dc32
GV
3560 {
3561 Lisp_Object frame, bar, condemned;
3562
8e713be6 3563 frame = XCAR (tail);
ee78dc32 3564 /* All elements of Vframe_list should be frames. */
8e50cc2d 3565 if (! FRAMEP (frame))
1088b922 3566 emacs_abort ();
ee78dc32
GV
3567
3568 /* Scan this frame's scroll bar list for a scroll bar with the
3569 right window ID. */
3570 condemned = FRAME_CONDEMNED_SCROLL_BARS (XFRAME (frame));
3571 for (bar = FRAME_SCROLL_BARS (XFRAME (frame));
3572 /* This trick allows us to search both the ordinary and
3573 condemned scroll bar lists with one loop. */
8e50cc2d 3574 ! NILP (bar) || (bar = condemned,
ee78dc32 3575 condemned = Qnil,
8e50cc2d 3576 ! NILP (bar));
ee78dc32 3577 bar = XSCROLL_BAR (bar)->next)
fbd6baed 3578 if (SCROLL_BAR_W32_WINDOW (XSCROLL_BAR (bar)) == window_id)
ee78dc32
GV
3579 return XSCROLL_BAR (bar);
3580 }
3581
3582 return 0;
3583}
3584
791f420f
JR
3585
3586\f
3587/* Set the thumb size and position of scroll bar BAR. We are currently
3588 displaying PORTION out of a whole WHOLE, and our position POSITION. */
3589
3590static void
b56ceb92
JB
3591w32_set_scroll_bar_thumb (struct scroll_bar *bar,
3592 int portion, int position, int whole)
791f420f
JR
3593{
3594 Window w = SCROLL_BAR_W32_WINDOW (bar);
feade168
KS
3595 /* We use the whole scroll-bar height in the calculations below, to
3596 avoid strange effects like scrolling backwards when just clicking
3597 on the handle (without moving it). */
3598 double range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height))
3599 + VERTICAL_SCROLL_BAR_MIN_HANDLE;
791f420f
JR
3600 int sb_page, sb_pos;
3601 BOOL draggingp = !NILP (bar->dragging) ? TRUE : FALSE;
818a1a5d 3602 SCROLLINFO si;
791f420f 3603
feade168
KS
3604 /* We used to change the nPage setting while dragging the handle,
3605 but that had very strange effects (such as scrolling backwards
3606 while dragging downwards).
3607
3608 Now, we don't change the nPage setting while dragging unless we
3609 get near to the end of the buffer, in which case we often have to
3610 resize the handle to "go all the way". */
3611
3612 if (draggingp)
791f420f 3613 {
feade168 3614 int near_bottom_p;
4d7e6e51 3615 block_input ();
feade168
KS
3616 si.cbSize = sizeof (si);
3617 si.fMask = SIF_POS | SIF_PAGE;
ed3751c8 3618 GetScrollInfo (w, SB_CTL, &si);
feade168 3619 near_bottom_p = si.nPos + si.nPage >= range;
4d7e6e51 3620 unblock_input ();
feade168
KS
3621 if (!near_bottom_p)
3622 return;
3623 }
f65aa365 3624
791f420f
JR
3625 if (whole)
3626 {
3627 /* Position scroll bar at rock bottom if the bottom of the
9858f6c3 3628 buffer is visible. This avoids shrinking the thumb away
791f420f 3629 to nothing if it is held at the bottom of the buffer. */
feade168
KS
3630 if (position + portion >= whole && !draggingp)
3631 {
3632 sb_page = range * (whole - position) / whole;
3633 sb_pos = range;
3634 }
3635 else
3636 {
3637 sb_pos = position * range / whole;
3638 sb_page = (min (portion, (whole - position)) * range) / whole;
3639 }
791f420f
JR
3640 }
3641 else
3642 {
3643 sb_page = range;
3644 sb_pos = 0;
3645 }
3646
feade168
KS
3647 sb_page = max (sb_page, VERTICAL_SCROLL_BAR_MIN_HANDLE);
3648
4d7e6e51 3649 block_input ();
791f420f 3650
818a1a5d 3651 si.cbSize = sizeof (si);
feade168 3652 si.fMask = SIF_PAGE | SIF_POS;
818a1a5d
JR
3653 si.nPage = sb_page;
3654 si.nPos = sb_pos;
3655
feade168 3656 SetScrollInfo (w, SB_CTL, &si, TRUE);
791f420f 3657
4d7e6e51 3658 unblock_input ();
791f420f
JR
3659}
3660
3661\f
3662/************************************************************************
3663 Scroll bars, general
3664 ************************************************************************/
d67d1627 3665
decb374a 3666static HWND
b56ceb92 3667my_create_scrollbar (struct frame * f, struct scroll_bar * bar)
ee78dc32 3668{
689004fa 3669 return (HWND) SendMessage (FRAME_W32_WINDOW (f),
d67d1627 3670 WM_EMACS_CREATESCROLLBAR, (WPARAM) f,
689004fa 3671 (LPARAM) bar);
ee78dc32
GV
3672}
3673
ab76d376 3674/*#define ATTACH_THREADS*/
52cf03a1 3675
14d050df 3676static BOOL
689004fa 3677my_show_window (FRAME_PTR f, HWND hwnd, int how)
52cf03a1
GV
3678{
3679#ifndef ATTACH_THREADS
689004fa
GV
3680 return SendMessage (FRAME_W32_WINDOW (f), WM_EMACS_SHOWWINDOW,
3681 (WPARAM) hwnd, (LPARAM) how);
52cf03a1 3682#else
689004fa 3683 return ShowWindow (hwnd, how);
52cf03a1
GV
3684#endif
3685}
3686
14d050df 3687static void
52cf03a1 3688my_set_window_pos (HWND hwnd, HWND hwndAfter,
689004fa 3689 int x, int y, int cx, int cy, UINT flags)
52cf03a1
GV
3690{
3691#ifndef ATTACH_THREADS
689004fa
GV
3692 WINDOWPOS pos;
3693 pos.hwndInsertAfter = hwndAfter;
52cf03a1
GV
3694 pos.x = x;
3695 pos.y = y;
3696 pos.cx = cx;
3697 pos.cy = cy;
3698 pos.flags = flags;
3699 SendMessage (hwnd, WM_EMACS_SETWINDOWPOS, (WPARAM) &pos, 0);
3700#else
3701 SetWindowPos (hwnd, hwndAfter, x, y, cx, cy, flags);
3702#endif
3703}
3704
2e6c8532 3705#if 0
14d050df 3706static void
b56ceb92 3707my_set_focus (struct frame * f, HWND hwnd)
689004fa 3708{
d67d1627 3709 SendMessage (FRAME_W32_WINDOW (f), WM_EMACS_SETFOCUS,
689004fa
GV
3710 (WPARAM) hwnd, 0);
3711}
2e6c8532 3712#endif
689004fa 3713
14d050df 3714static void
b56ceb92 3715my_set_foreground_window (HWND hwnd)
ef0e360f
GV
3716{
3717 SendMessage (hwnd, WM_EMACS_SETFOREGROUND, (WPARAM) hwnd, 0);
3718}
3719
14d050df
JB
3720
3721static void
b56ceb92 3722my_destroy_window (struct frame * f, HWND hwnd)
ee78dc32 3723{
d67d1627 3724 SendMessage (FRAME_W32_WINDOW (f), WM_EMACS_DESTROYWINDOW,
ee78dc32
GV
3725 (WPARAM) hwnd, 0);
3726}
3727
85d0efd1
EZ
3728static void
3729my_bring_window_to_top (HWND hwnd)
3730{
3731 SendMessage (hwnd, WM_EMACS_BRINGTOTOP, (WPARAM) hwnd, 0);
3732}
3733
791f420f
JR
3734/* Create a scroll bar and return the scroll bar vector for it. W is
3735 the Emacs window on which to create the scroll bar. TOP, LEFT,
e8500ff4 3736 WIDTH and HEIGHT are the pixel coordinates and dimensions of the
791f420f
JR
3737 scroll bar. */
3738
ee78dc32 3739static struct scroll_bar *
b56ceb92 3740x_scroll_bar_create (struct window *w, int top, int left, int width, int height)
ee78dc32 3741{
791f420f
JR
3742 struct frame *f = XFRAME (WINDOW_FRAME (w));
3743 HWND hwnd;
818a1a5d 3744 SCROLLINFO si;
ee78dc32
GV
3745 struct scroll_bar *bar
3746 = XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
71688bd7 3747 Lisp_Object barobj;
ee78dc32 3748
4d7e6e51 3749 block_input ();
ee78dc32 3750
791f420f 3751 XSETWINDOW (bar->window, w);
ee78dc32
GV
3752 XSETINT (bar->top, top);
3753 XSETINT (bar->left, left);
3754 XSETINT (bar->width, width);
3755 XSETINT (bar->height, height);
3756 XSETINT (bar->start, 0);
3757 XSETINT (bar->end, 0);
3758 bar->dragging = Qnil;
06929222 3759 bar->fringe_extended_p = Qnil;
ee78dc32
GV
3760
3761 /* Requires geometry to be set before call to create the real window */
3762
3763 hwnd = my_create_scrollbar (f, bar);
3764
818a1a5d
JR
3765 si.cbSize = sizeof (si);
3766 si.fMask = SIF_ALL;
3767 si.nMin = 0;
3768 si.nMax = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height)
3769 + VERTICAL_SCROLL_BAR_MIN_HANDLE;
3770 si.nPage = si.nMax;
3771 si.nPos = 0;
689004fa 3772
818a1a5d 3773 SetScrollInfo (hwnd, SB_CTL, &si, FALSE);
ee78dc32 3774
fbd6baed 3775 SET_SCROLL_BAR_W32_WINDOW (bar, hwnd);
ee78dc32
GV
3776
3777 /* Add bar to its frame's list of scroll bars. */
3778 bar->next = FRAME_SCROLL_BARS (f);
3779 bar->prev = Qnil;
71688bd7 3780 XSETVECTOR (barobj, bar);
f00af5b1 3781 fset_scroll_bars (f, barobj);
ee78dc32
GV
3782 if (! NILP (bar->next))
3783 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
3784
4d7e6e51 3785 unblock_input ();
ee78dc32
GV
3786
3787 return bar;
3788}
3789
ee78dc32 3790
791f420f
JR
3791/* Destroy scroll bar BAR, and set its Emacs window's scroll bar to
3792 nil. */
ee78dc32 3793
ee78dc32 3794static void
b56ceb92 3795x_scroll_bar_remove (struct scroll_bar *bar)
ee78dc32
GV
3796{
3797 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
3798
4d7e6e51 3799 block_input ();
ee78dc32
GV
3800
3801 /* Destroy the window. */
fbd6baed 3802 my_destroy_window (f, SCROLL_BAR_W32_WINDOW (bar));
ee78dc32 3803
99d99081 3804 /* Dissociate this scroll bar from its window. */
e8c17b81 3805 wset_vertical_scroll_bar (XWINDOW (bar->window), Qnil);
ee78dc32 3806
4d7e6e51 3807 unblock_input ();
ee78dc32
GV
3808}
3809
3810/* Set the handle of the vertical scroll bar for WINDOW to indicate
3811 that we are displaying PORTION characters out of a total of WHOLE
3812 characters, starting at POSITION. If WINDOW has no scroll bar,
3813 create one. */
3814static void
b56ceb92
JB
3815w32_set_vertical_scroll_bar (struct window *w,
3816 int portion, int whole, int position)
ee78dc32 3817{
d3d50620 3818 struct frame *f = XFRAME (w->frame);
dd86bd82 3819 Lisp_Object barobj;
ee78dc32 3820 struct scroll_bar *bar;
9ef2e2cf 3821 int top, height, left, sb_left, width, sb_width;
62e50ec6 3822 int window_y, window_height;
06929222 3823 int fringe_extended_p;
791f420f
JR
3824
3825 /* Get window dimensions. */
62e50ec6 3826 window_box (w, -1, 0, &window_y, 0, &window_height);
791f420f 3827 top = window_y;
62e50ec6 3828 width = WINDOW_CONFIG_SCROLL_BAR_COLS (w) * FRAME_COLUMN_WIDTH (f);
791f420f
JR
3829 height = window_height;
3830
3831 /* Compute the left edge of the scroll bar area. */
62e50ec6 3832 left = WINDOW_SCROLL_BAR_AREA_X (w);
791f420f
JR
3833
3834 /* Compute the width of the scroll bar which might be less than
3835 the width of the area reserved for the scroll bar. */
62e50ec6
KS
3836 if (WINDOW_CONFIG_SCROLL_BAR_WIDTH (w) > 0)
3837 sb_width = WINDOW_CONFIG_SCROLL_BAR_WIDTH (w);
791f420f
JR
3838 else
3839 sb_width = width;
ee78dc32 3840
791f420f 3841 /* Compute the left edge of the scroll bar. */
62e50ec6 3842 if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w))
06929222 3843 sb_left = left + (WINDOW_RIGHTMOST_P (w) ? width - sb_width : 0);
ee78dc32 3844 else
06929222
YM
3845 sb_left = left + (WINDOW_LEFTMOST_P (w) ? 0 : width - sb_width);
3846
3847 if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
3848 fringe_extended_p = (WINDOW_LEFTMOST_P (w)
3849 && WINDOW_LEFT_FRINGE_WIDTH (w)
3850 && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
3851 || WINDOW_LEFT_MARGIN_COLS (w) == 0));
ee78dc32 3852 else
06929222
YM
3853 fringe_extended_p = (WINDOW_RIGHTMOST_P (w)
3854 && WINDOW_RIGHT_FRINGE_WIDTH (w)
3855 && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
3856 || WINDOW_RIGHT_MARGIN_COLS (w) == 0));
791f420f
JR
3857
3858 /* Does the scroll bar exist yet? */
d3d50620 3859 if (NILP (w->vertical_scroll_bar))
ee78dc32 3860 {
00fe468b 3861 HDC hdc;
4d7e6e51 3862 block_input ();
6ff3e5e3 3863 if (width > 0 && height > 0)
9f5a911b
JR
3864 {
3865 hdc = get_frame_dc (f);
06929222
YM
3866 if (fringe_extended_p)
3867 w32_clear_area (f, hdc, sb_left, top, sb_width, height);
3868 else
3869 w32_clear_area (f, hdc, left, top, width, height);
9f5a911b
JR
3870 release_frame_dc (f, hdc);
3871 }
4d7e6e51 3872 unblock_input ();
00fe468b 3873
791f420f 3874 bar = x_scroll_bar_create (w, top, sb_left, sb_width, height);
ee78dc32 3875 }
791f420f
JR
3876 else
3877 {
d67d1627 3878 /* It may just need to be moved and resized. */
791f420f
JR
3879 HWND hwnd;
3880
d3d50620 3881 bar = XSCROLL_BAR (w->vertical_scroll_bar);
791f420f
JR
3882 hwnd = SCROLL_BAR_W32_WINDOW (bar);
3883
3884 /* If already correctly positioned, do nothing. */
3885 if ( XINT (bar->left) == sb_left
3886 && XINT (bar->top) == top
3887 && XINT (bar->width) == sb_width
06929222
YM
3888 && XINT (bar->height) == height
3889 && !NILP (bar->fringe_extended_p) == fringe_extended_p )
791f420f
JR
3890 {
3891 /* Redraw after clear_frame. */
3892 if (!my_show_window (f, hwnd, SW_NORMAL))
3893 InvalidateRect (hwnd, NULL, FALSE);
3894 }
3895 else
3896 {
00fe468b 3897 HDC hdc;
818a1a5d
JR
3898 SCROLLINFO si;
3899
4d7e6e51 3900 block_input ();
9f5a911b
JR
3901 if (width && height)
3902 {
3903 hdc = get_frame_dc (f);
3904 /* Since Windows scroll bars are smaller than the space reserved
3905 for them on the frame, we have to clear "under" them. */
06929222
YM
3906 if (fringe_extended_p)
3907 w32_clear_area (f, hdc, sb_left, top, sb_width, height);
3908 else
3909 w32_clear_area (f, hdc, left, top, width, height);
9f5a911b
JR
3910 release_frame_dc (f, hdc);
3911 }
791f420f
JR
3912 /* Make sure scroll bar is "visible" before moving, to ensure the
3913 area of the parent window now exposed will be refreshed. */
3914 my_show_window (f, hwnd, SW_HIDE);
9f5a911b
JR
3915 MoveWindow (hwnd, sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
3916 top, sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
3917 max (height, 1), TRUE);
ee78dc32 3918
818a1a5d
JR
3919 si.cbSize = sizeof (si);
3920 si.fMask = SIF_RANGE;
3921 si.nMin = 0;
3922 si.nMax = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height)
3923 + VERTICAL_SCROLL_BAR_MIN_HANDLE;
3924
3925 SetScrollInfo (hwnd, SB_CTL, &si, FALSE);
ee78dc32 3926
791f420f 3927 my_show_window (f, hwnd, SW_NORMAL);
ab76d376 3928 /* InvalidateRect (w, NULL, FALSE); */
791f420f
JR
3929
3930 /* Remember new settings. */
3931 XSETINT (bar->left, sb_left);
3932 XSETINT (bar->top, top);
3933 XSETINT (bar->width, sb_width);
3934 XSETINT (bar->height, height);
3935
4d7e6e51 3936 unblock_input ();
791f420f
JR
3937 }
3938 }
06929222
YM
3939 bar->fringe_extended_p = fringe_extended_p ? Qt : Qnil;
3940
791f420f 3941 w32_set_scroll_bar_thumb (bar, portion, position, whole);
dd86bd82 3942 XSETVECTOR (barobj, bar);
e8c17b81 3943 wset_vertical_scroll_bar (w, barobj);
ee78dc32
GV
3944}
3945
3946
3947/* The following three hooks are used when we're doing a thorough
3948 redisplay of the frame. We don't explicitly know which scroll bars
3949 are going to be deleted, because keeping track of when windows go
3950 away is a real pain - "Can you say set-window-configuration, boys
3951 and girls?" Instead, we just assert at the beginning of redisplay
3952 that *all* scroll bars are to be removed, and then save a scroll bar
3953 from the fiery pit when we actually redisplay its window. */
3954
3955/* Arrange for all scroll bars on FRAME to be removed at the next call
3956 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
9ef2e2cf
JR
3957 `*redeem_scroll_bar_hook' is applied to its window before the judgment. */
3958
ee78dc32 3959static void
b56ceb92 3960w32_condemn_scroll_bars (FRAME_PTR frame)
ee78dc32 3961{
ef0e360f
GV
3962 /* Transfer all the scroll bars to FRAME_CONDEMNED_SCROLL_BARS. */
3963 while (! NILP (FRAME_SCROLL_BARS (frame)))
3964 {
3965 Lisp_Object bar;
3966 bar = FRAME_SCROLL_BARS (frame);
f00af5b1 3967 fset_scroll_bars (frame, XSCROLL_BAR (bar)->next);
ef0e360f
GV
3968 XSCROLL_BAR (bar)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
3969 XSCROLL_BAR (bar)->prev = Qnil;
3970 if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
3971 XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = bar;
f00af5b1 3972 fset_condemned_scroll_bars (frame, bar);
ef0e360f 3973 }
ee78dc32
GV
3974}
3975
c2cc16fa 3976
9ef2e2cf 3977/* Un-mark WINDOW's scroll bar for deletion in this judgment cycle.
ee78dc32 3978 Note that WINDOW isn't necessarily condemned at all. */
c2cc16fa 3979
ee78dc32 3980static void
b56ceb92 3981w32_redeem_scroll_bar (struct window *window)
ee78dc32
GV
3982{
3983 struct scroll_bar *bar;
71688bd7 3984 Lisp_Object barobj;
c2cc16fa 3985 struct frame *f;
ee78dc32
GV
3986
3987 /* We can't redeem this window's scroll bar if it doesn't have one. */
d3d50620 3988 if (NILP (window->vertical_scroll_bar))
1088b922 3989 emacs_abort ();
ee78dc32 3990
d3d50620 3991 bar = XSCROLL_BAR (window->vertical_scroll_bar);
ee78dc32 3992
ef0e360f 3993 /* Unlink it from the condemned list. */
c2cc16fa
JR
3994 f = XFRAME (WINDOW_FRAME (window));
3995 if (NILP (bar->prev))
3996 {
3997 /* If the prev pointer is nil, it must be the first in one of
3998 the lists. */
d3d50620 3999 if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
c2cc16fa
JR
4000 /* It's not condemned. Everything's fine. */
4001 return;
4002 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
d3d50620 4003 window->vertical_scroll_bar))
f00af5b1 4004 fset_condemned_scroll_bars (f, bar->next);
c2cc16fa
JR
4005 else
4006 /* If its prev pointer is nil, it must be at the front of
4007 one or the other! */
1088b922 4008 emacs_abort ();
c2cc16fa
JR
4009 }
4010 else
4011 XSCROLL_BAR (bar->prev)->next = bar->next;
ef0e360f 4012
c2cc16fa
JR
4013 if (! NILP (bar->next))
4014 XSCROLL_BAR (bar->next)->prev = bar->prev;
ef0e360f 4015
c2cc16fa
JR
4016 bar->next = FRAME_SCROLL_BARS (f);
4017 bar->prev = Qnil;
71688bd7 4018 XSETVECTOR (barobj, bar);
f00af5b1 4019 fset_scroll_bars (f, barobj);
c2cc16fa
JR
4020 if (! NILP (bar->next))
4021 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
ee78dc32
GV
4022}
4023
4024/* Remove all scroll bars on FRAME that haven't been saved since the
4025 last call to `*condemn_scroll_bars_hook'. */
9ef2e2cf 4026
ee78dc32 4027static void
b56ceb92 4028w32_judge_scroll_bars (FRAME_PTR f)
ee78dc32
GV
4029{
4030 Lisp_Object bar, next;
4031
4032 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
4033
4034 /* Clear out the condemned list now so we won't try to process any
4035 more events on the hapless scroll bars. */
f00af5b1 4036 fset_condemned_scroll_bars (f, Qnil);
ee78dc32
GV
4037
4038 for (; ! NILP (bar); bar = next)
4039 {
4040 struct scroll_bar *b = XSCROLL_BAR (bar);
4041
4042 x_scroll_bar_remove (b);
4043
4044 next = b->next;
4045 b->next = b->prev = Qnil;
4046 }
4047
4048 /* Now there should be no references to the condemned scroll bars,
4049 and they should get garbage-collected. */
4050}
4051
4052/* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
3b8f9651 4053 is set to something other than NO_EVENT, it is enqueued.
ee78dc32
GV
4054
4055 This may be called from a signal handler, so we have to ignore GC
4056 mark bits. */
2c28562d 4057
52cf03a1 4058static int
b56ceb92
JB
4059w32_scroll_bar_handle_click (struct scroll_bar *bar, W32Msg *msg,
4060 struct input_event *emacs_event)
ee78dc32 4061{
8e50cc2d 4062 if (! WINDOWP (bar->window))
1088b922 4063 emacs_abort ();
ee78dc32 4064
4b219faa 4065 emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
ee78dc32 4066 emacs_event->code = 0;
52cf03a1
GV
4067 /* not really meaningful to distinguish up/down */
4068 emacs_event->modifiers = msg->dwModifiers;
ee78dc32 4069 emacs_event->frame_or_window = bar->window;
7e889510 4070 emacs_event->arg = Qnil;
ee78dc32
GV
4071 emacs_event->timestamp = msg->msg.time;
4072
4073 {
791f420f 4074 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
689004fa
GV
4075 int y;
4076 int dragging = !NILP (bar->dragging);
818a1a5d 4077 SCROLLINFO si;
689004fa 4078
818a1a5d
JR
4079 si.cbSize = sizeof (si);
4080 si.fMask = SIF_POS;
689004fa 4081
818a1a5d
JR
4082 GetScrollInfo ((HWND) msg->msg.lParam, SB_CTL, &si);
4083 y = si.nPos;
689004fa
GV
4084
4085 bar->dragging = Qnil;
ee78dc32 4086
9ef2e2cf
JR
4087
4088 last_mouse_scroll_bar_pos = msg->msg.wParam;
d67d1627 4089
ee78dc32 4090 switch (LOWORD (msg->msg.wParam))
2c28562d 4091 {
2c28562d 4092 case SB_LINEDOWN:
52cf03a1 4093 emacs_event->part = scroll_bar_down_arrow;
ee78dc32 4094 break;
2c28562d 4095 case SB_LINEUP:
52cf03a1 4096 emacs_event->part = scroll_bar_up_arrow;
ee78dc32 4097 break;
2c28562d 4098 case SB_PAGEUP:
ee78dc32
GV
4099 emacs_event->part = scroll_bar_above_handle;
4100 break;
2c28562d 4101 case SB_PAGEDOWN:
ee78dc32
GV
4102 emacs_event->part = scroll_bar_below_handle;
4103 break;
2c28562d 4104 case SB_TOP:
ee78dc32
GV
4105 emacs_event->part = scroll_bar_handle;
4106 y = 0;
4107 break;
2c28562d 4108 case SB_BOTTOM:
ee78dc32
GV
4109 emacs_event->part = scroll_bar_handle;
4110 y = top_range;
4111 break;
689004fa 4112 case SB_THUMBTRACK:
2c28562d 4113 case SB_THUMBPOSITION:
791f420f
JR
4114 if (VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height)) <= 0xffff)
4115 y = HIWORD (msg->msg.wParam);
689004fa 4116 bar->dragging = Qt;
ee78dc32 4117 emacs_event->part = scroll_bar_handle;
689004fa
GV
4118
4119 /* "Silently" update current position. */
818a1a5d
JR
4120 {
4121 SCROLLINFO si;
689004fa 4122
818a1a5d
JR
4123 si.cbSize = sizeof (si);
4124 si.fMask = SIF_POS;
4125 si.nPos = y;
4126 /* Remember apparent position (we actually lag behind the real
e8500ff4 4127 position, so don't set that directly). */
818a1a5d 4128 last_scroll_bar_drag_pos = y;
689004fa 4129
818a1a5d
JR
4130 SetScrollInfo (SCROLL_BAR_W32_WINDOW (bar), SB_CTL, &si, FALSE);
4131 }
ee78dc32 4132 break;
2c28562d 4133 case SB_ENDSCROLL:
689004fa
GV
4134 /* If this is the end of a drag sequence, then reset the scroll
4135 handle size to normal and do a final redraw. Otherwise do
4136 nothing. */
4137 if (dragging)
4138 {
818a1a5d
JR
4139 SCROLLINFO si;
4140 int start = XINT (bar->start);
4141 int end = XINT (bar->end);
4142
4143 si.cbSize = sizeof (si);
4144 si.fMask = SIF_PAGE | SIF_POS;
4145 si.nPage = end - start + VERTICAL_SCROLL_BAR_MIN_HANDLE;
4146 si.nPos = last_scroll_bar_drag_pos;
4147 SetScrollInfo (SCROLL_BAR_W32_WINDOW (bar), SB_CTL, &si, TRUE);
689004fa
GV
4148 }
4149 /* fall through */
2c28562d 4150 default:
3b8f9651 4151 emacs_event->kind = NO_EVENT;
52cf03a1 4152 return FALSE;
2c28562d 4153 }
52cf03a1 4154
ee78dc32
GV
4155 XSETINT (emacs_event->x, y);
4156 XSETINT (emacs_event->y, top_range);
52cf03a1
GV
4157
4158 return TRUE;
ee78dc32
GV
4159 }
4160}
4161
4162/* Return information to the user about the current position of the mouse
4163 on the scroll bar. */
9ef2e2cf 4164
ee78dc32 4165static void
b56ceb92
JB
4166x_scroll_bar_report_motion (FRAME_PTR *fp, Lisp_Object *bar_window,
4167 enum scroll_bar_part *part,
4168 Lisp_Object *x, Lisp_Object *y,
4169 unsigned long *time)
ee78dc32
GV
4170{
4171 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
fbd6baed 4172 Window w = SCROLL_BAR_W32_WINDOW (bar);
ee78dc32
GV
4173 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
4174 int pos;
791f420f 4175 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
818a1a5d 4176 SCROLLINFO si;
ee78dc32 4177
4d7e6e51 4178 block_input ();
ee78dc32
GV
4179
4180 *fp = f;
4181 *bar_window = bar->window;
4182
818a1a5d
JR
4183 si.cbSize = sizeof (si);
4184 si.fMask = SIF_POS | SIF_PAGE | SIF_RANGE;
689004fa 4185
818a1a5d
JR
4186 GetScrollInfo (w, SB_CTL, &si);
4187 pos = si.nPos;
4188 top_range = si.nMax - si.nPage + 1;
ee78dc32
GV
4189
4190 switch (LOWORD (last_mouse_scroll_bar_pos))
4191 {
4192 case SB_THUMBPOSITION:
4193 case SB_THUMBTRACK:
4194 *part = scroll_bar_handle;
791f420f 4195 if (VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height)) <= 0xffff)
ee78dc32
GV
4196 pos = HIWORD (last_mouse_scroll_bar_pos);
4197 break;
4198 case SB_LINEDOWN:
4199 *part = scroll_bar_handle;
4200 pos++;
4201 break;
4202 default:
4203 *part = scroll_bar_handle;
4204 break;
4205 }
4206
9127e20e
JR
4207 XSETINT (*x, pos);
4208 XSETINT (*y, top_range);
ee78dc32
GV
4209
4210 f->mouse_moved = 0;
4211 last_mouse_scroll_bar = Qnil;
4212
4213 *time = last_mouse_movement_time;
4214
4d7e6e51 4215 unblock_input ();
ee78dc32
GV
4216}
4217
9ef2e2cf 4218
ee78dc32
GV
4219/* The screen has been cleared so we may have changed foreground or
4220 background colors, and the scroll bars may need to be redrawn.
4221 Clear out the scroll bars, and ask for expose events, so we can
4222 redraw them. */
9ef2e2cf 4223
791f420f 4224void
b56ceb92 4225x_scroll_bar_clear (FRAME_PTR f)
ee78dc32 4226{
ee78dc32
GV
4227 Lisp_Object bar;
4228
9ef2e2cf
JR
4229 /* We can have scroll bars even if this is 0,
4230 if we just turned off scroll bar mode.
4231 But in that case we should not clear them. */
4232 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
4233 for (bar = FRAME_SCROLL_BARS (f); VECTORP (bar);
4234 bar = XSCROLL_BAR (bar)->next)
4235 {
4236 HWND window = SCROLL_BAR_W32_WINDOW (XSCROLL_BAR (bar));
4237 HDC hdc = GetDC (window);
4238 RECT rect;
52cf03a1 4239
9ef2e2cf
JR
4240 /* Hide scroll bar until ready to repaint. x_scroll_bar_move
4241 arranges to refresh the scroll bar if hidden. */
4242 my_show_window (f, window, SW_HIDE);
689004fa 4243
9ef2e2cf
JR
4244 GetClientRect (window, &rect);
4245 select_palette (f, hdc);
4246 w32_clear_rect (f, hdc, &rect);
4247 deselect_palette (f, hdc);
689004fa 4248
9ef2e2cf
JR
4249 ReleaseDC (window, hdc);
4250 }
52cf03a1
GV
4251}
4252
ee78dc32 4253\f
fbd6baed 4254/* The main W32 event-reading loop - w32_read_socket. */
ee78dc32
GV
4255
4256/* Record the last 100 characters stored
4257 to help debug the loss-of-chars-during-GC problem. */
9ef2e2cf
JR
4258
4259static int temp_index;
4260static short temp_buffer[100];
ee78dc32 4261
2e3566d8
JR
4262/* Temporarily store lead byte of DBCS input sequences. */
4263static char dbcs_lead = 0;
afd153f0 4264
fbd6baed 4265/* Read events coming from the W32 shell.
ee78dc32
GV
4266 This routine is called by the SIGIO handler.
4267 We return as soon as there are no more events to be read.
4268
d263a633
EZ
4269 For an overview of how Emacs input works on MS-Windows, see the
4270 commentary before w32_msg_pump in w32fns.c.
4271
ee78dc32
GV
4272 We return the number of characters stored into the buffer,
4273 thus pretending to be `read'.
4274
ee78dc32 4275 Some of these messages are reposted back to the message queue since the
d67d1627 4276 system calls the windows proc directly in a context where we cannot return
decb374a 4277 the data nor can we guarantee the state we are in. So if we dispatch them
ee78dc32
GV
4278 we will get into an infinite loop. To prevent this from ever happening we
4279 will set a variable to indicate we are in the read_socket call and indicate
d67d1627 4280 which message we are processing since the windows proc gets called
e9e23e23 4281 recursively with different messages by the system.
ee78dc32
GV
4282*/
4283
24f981c9 4284static int
f75beb47 4285w32_read_socket (struct terminal *terminal,
b56ceb92 4286 struct input_event *hold_quit)
ee78dc32
GV
4287{
4288 int count = 0;
689004fa 4289 int check_visibility = 0;
fbd6baed 4290 W32Msg msg;
ee78dc32 4291 struct frame *f;
fbd6baed 4292 struct w32_display_info *dpyinfo = &one_w32_display_info;
bbf534ce 4293 Mouse_HLInfo *hlinfo = &dpyinfo->mouse_highlight;
0fda9b75 4294 static char buf[1];
ee78dc32 4295
4d7e6e51 4296 block_input ();
ee78dc32
GV
4297
4298 /* So people can tell when we have read the available input. */
4299 input_signal_count++;
4300
0fda9b75
DC
4301 /* Process any incoming thread messages. */
4302 drain_message_queue ();
4303
07c07cfe 4304 /* TODO: ghostscript integration. */
52cf03a1 4305 while (get_next_msg (&msg, FALSE))
ee78dc32 4306 {
6b61353c
KH
4307 struct input_event inev;
4308 int do_help = 0;
4309
0fda9b75
DC
4310 /* DebPrint (("w32_read_socket: %s time:%u\n", */
4311 /* w32_name_of_message (msg.msg.message), */
4312 /* msg.msg.time)); */
4313
6b61353c
KH
4314 EVENT_INIT (inev);
4315 inev.kind = NO_EVENT;
4316 inev.arg = Qnil;
4317
ee78dc32
GV
4318 switch (msg.msg.message)
4319 {
f7b146dc 4320 case WM_EMACS_PAINT:
9f5a911b 4321 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
ee78dc32 4322
d67d1627 4323 if (f)
9f5a911b
JR
4324 {
4325 if (msg.rect.right == msg.rect.left ||
4326 msg.rect.bottom == msg.rect.top)
4327 {
4328 /* We may get paint messages even though the client
4329 area is clipped - these are not expose events. */
4330 DebPrint (("clipped frame %p (%s) got WM_PAINT - ignored\n", f,
e69b0960 4331 SDATA (f->name)));
9f5a911b
JR
4332 }
4333 else if (f->async_visible != 1)
4334 {
4335 /* Definitely not obscured, so mark as visible. */
4336 f->async_visible = 1;
4337 f->async_iconified = 0;
4338 SET_FRAME_GARBAGED (f);
4339 DebPrint (("frame %p (%s) reexposed by WM_PAINT\n", f,
e69b0960 4340 SDATA (f->name)));
9f5a911b
JR
4341
4342 /* WM_PAINT serves as MapNotify as well, so report
4343 visibility changes properly. */
4344 if (f->iconified)
4345 {
6b61353c
KH
4346 inev.kind = DEICONIFY_EVENT;
4347 XSETFRAME (inev.frame_or_window, f);
9f5a911b
JR
4348 }
4349 else if (! NILP (Vframe_list)
4350 && ! NILP (XCDR (Vframe_list)))
4351 /* Force a redisplay sooner or later to update the
4352 frame titles in case this is the second frame. */
4353 record_asynch_buffer_change ();
4354 }
4355 else
4356 {
4357 HDC hdc = get_frame_dc (f);
4358
4359 /* Erase background again for safety. */
4360 w32_clear_rect (f, hdc, &msg.rect);
4361 release_frame_dc (f, hdc);
4362 expose_frame (f,
4363 msg.rect.left,
4364 msg.rect.top,
4365 msg.rect.right - msg.rect.left,
4366 msg.rect.bottom - msg.rect.top);
4367 }
4368 }
52cf03a1 4369 break;
689004fa 4370
f98169a0
GV
4371 case WM_INPUTLANGCHANGE:
4372 /* Generate a language change event. */
4373 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
4374
0bd8297f
EZ
4375 /* lParam contains the input language ID in its low 16 bits.
4376 Use it to update our record of the keyboard codepage. */
302fc036
EZ
4377 w32_keyboard_codepage = codepage_for_locale ((LCID)(msg.msg.lParam
4378 & 0xffff));
13087e59 4379
f98169a0
GV
4380 if (f)
4381 {
6b61353c
KH
4382 inev.kind = LANGUAGE_CHANGE_EVENT;
4383 XSETFRAME (inev.frame_or_window, f);
302fc036 4384 inev.code = w32_keyboard_codepage;
6b61353c 4385 inev.modifiers = msg.msg.lParam & 0xffff;
f98169a0
GV
4386 }
4387 break;
4388
ee78dc32
GV
4389 case WM_KEYDOWN:
4390 case WM_SYSKEYDOWN:
4391 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
d67d1627 4392
ee78dc32
GV
4393 if (f && !f->iconified)
4394 {
bbf534ce 4395 if (!hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight)
e69b0960 4396 && !EQ (f->tool_bar_window, hlinfo->mouse_face_window))
3d26a7c2 4397 {
bbf534ce
EZ
4398 clear_mouse_face (hlinfo);
4399 hlinfo->mouse_face_hidden = 1;
3d26a7c2
KS
4400 }
4401
ee78dc32
GV
4402 if (temp_index == sizeof temp_buffer / sizeof (short))
4403 temp_index = 0;
4404 temp_buffer[temp_index++] = msg.msg.wParam;
6b61353c
KH
4405 inev.kind = NON_ASCII_KEYSTROKE_EVENT;
4406 inev.code = msg.msg.wParam;
4407 inev.modifiers = msg.dwModifiers;
4408 XSETFRAME (inev.frame_or_window, f);
4409 inev.timestamp = msg.msg.time;
ee78dc32
GV
4410 }
4411 break;
689004fa 4412
a60b0333 4413 case WM_UNICHAR:
ee78dc32
GV
4414 case WM_SYSCHAR:
4415 case WM_CHAR:
4416 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
d67d1627 4417
ee78dc32
GV
4418 if (f && !f->iconified)
4419 {
bbf534ce 4420 if (!hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight)
e69b0960 4421 && !EQ (f->tool_bar_window, hlinfo->mouse_face_window))
3d26a7c2 4422 {
bbf534ce
EZ
4423 clear_mouse_face (hlinfo);
4424 hlinfo->mouse_face_hidden = 1;
3d26a7c2
KS
4425 }
4426
f98169a0
GV
4427 if (temp_index == sizeof temp_buffer / sizeof (short))
4428 temp_index = 0;
4429 temp_buffer[temp_index++] = msg.msg.wParam;
480cb5d2
JR
4430
4431 inev.modifiers = msg.dwModifiers;
4432 XSETFRAME (inev.frame_or_window, f);
4433 inev.timestamp = msg.msg.time;
4434
a60b0333
JR
4435 if (msg.msg.message == WM_UNICHAR)
4436 {
a60b0333
JR
4437 inev.code = msg.msg.wParam;
4438 }
480cb5d2
JR
4439 else if (msg.msg.wParam < 256)
4440 {
4441 wchar_t code;
4442 char dbcs[2];
4443 dbcs[0] = 0;
4444 dbcs[1] = (char) msg.msg.wParam;
4445
4446 if (dbcs_lead)
4447 {
4448 dbcs[0] = dbcs_lead;
4449 dbcs_lead = 0;
302fc036 4450 if (!MultiByteToWideChar (w32_keyboard_codepage, 0,
13087e59 4451 dbcs, 2, &code, 1))
480cb5d2
JR
4452 {
4453 /* Garbage */
4454 DebPrint (("Invalid DBCS sequence: %d %d\n",
4455 dbcs[0], dbcs[1]));
4456 inev.kind = NO_EVENT;
4457 break;
4458 }
4459 }
302fc036 4460 else if (IsDBCSLeadByteEx (w32_keyboard_codepage,
13087e59 4461 (BYTE) msg.msg.wParam))
480cb5d2
JR
4462 {
4463 dbcs_lead = (char) msg.msg.wParam;
4464 inev.kind = NO_EVENT;
4465 break;
4466 }
4467 else
4468 {
302fc036 4469 if (!MultiByteToWideChar (w32_keyboard_codepage, 0,
13087e59 4470 &dbcs[1], 1, &code, 1))
480cb5d2
JR
4471 {
4472 /* What to do with garbage? */
4473 DebPrint (("Invalid character: %d\n", dbcs[1]));
4474 inev.kind = NO_EVENT;
4475 break;
4476 }
4477 }
4478 inev.code = code;
4479 }
a60b0333
JR
4480 else
4481 {
480cb5d2
JR
4482 /* Windows shouldn't generate WM_CHAR events above 0xFF
4483 in non-Unicode message handlers. */
4484 DebPrint (("Non-byte WM_CHAR: %d\n", msg.msg.wParam));
4485 inev.kind = NO_EVENT;
4486 break;
a60b0333 4487 }
480cb5d2
JR
4488 inev.kind = inev.code < 128 ? ASCII_KEYSTROKE_EVENT
4489 : MULTIBYTE_CHAR_KEYSTROKE_EVENT;
ee78dc32
GV
4490 }
4491 break;
689004fa 4492
4b219faa
JR
4493 case WM_APPCOMMAND:
4494 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
4495
4496 if (f && !f->iconified)
4497 {
bbf534ce 4498 if (!hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight)
e69b0960 4499 && !EQ (f->tool_bar_window, hlinfo->mouse_face_window))
4b219faa 4500 {
bbf534ce
EZ
4501 clear_mouse_face (hlinfo);
4502 hlinfo->mouse_face_hidden = 1;
4b219faa
JR
4503 }
4504
4505 if (temp_index == sizeof temp_buffer / sizeof (short))
4506 temp_index = 0;
4507 temp_buffer[temp_index++] = msg.msg.wParam;
4508 inev.kind = MULTIMEDIA_KEY_EVENT;
ed3751c8 4509 inev.code = GET_APPCOMMAND_LPARAM (msg.msg.lParam);
4b219faa
JR
4510 inev.modifiers = msg.dwModifiers;
4511 XSETFRAME (inev.frame_or_window, f);
4512 inev.timestamp = msg.msg.time;
4513 }
4514 break;
65a6ff8f 4515
ee78dc32 4516 case WM_MOUSEMOVE:
706ddb8f
JR
4517 /* Ignore non-movement. */
4518 {
4519 int x = LOWORD (msg.msg.lParam);
4520 int y = HIWORD (msg.msg.lParam);
4521 if (x == last_mousemove_x && y == last_mousemove_y)
4522 break;
4523 last_mousemove_x = x;
4524 last_mousemove_y = y;
4525 }
4526
89271099 4527 previous_help_echo_string = help_echo_string;
fc5c7550 4528 help_echo_string = Qnil;
791f420f 4529
ee78dc32
GV
4530 if (dpyinfo->grabbed && last_mouse_frame
4531 && FRAME_LIVE_P (last_mouse_frame))
4532 f = last_mouse_frame;
4533 else
4534 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
d67d1627 4535
bbf534ce 4536 if (hlinfo->mouse_face_hidden)
3d26a7c2 4537 {
bbf534ce
EZ
4538 hlinfo->mouse_face_hidden = 0;
4539 clear_mouse_face (hlinfo);
3d26a7c2
KS
4540 }
4541
ee78dc32 4542 if (f)
a18bb28d
JR
4543 {
4544 /* Generate SELECT_WINDOW_EVENTs when needed. */
92b23323 4545 if (!NILP (Vmouse_autoselect_window))
a18bb28d
JR
4546 {
4547 Lisp_Object window;
a18bb28d
JR
4548 int x = LOWORD (msg.msg.lParam);
4549 int y = HIWORD (msg.msg.lParam);
4550
9173a8fb 4551 window = window_from_coordinates (f, x, y, 0, 0);
a18bb28d
JR
4552
4553 /* Window will be selected only when it is not
4554 selected now and last mouse movement event was
4555 not in it. Minibuffer window will be selected
e0f24100 4556 only when it is active. */
ed3751c8 4557 if (WINDOWP (window)
a18bb28d 4558 && !EQ (window, last_window)
74a9b36f
MR
4559 && !EQ (window, selected_window)
4560 /* For click-to-focus window managers
4561 create event iff we don't leave the
4562 selected frame. */
4563 && (focus_follows_mouse
d3d50620
DA
4564 || (EQ (XWINDOW (window)->frame,
4565 XWINDOW (selected_window)->frame))))
a18bb28d 4566 {
6b61353c
KH
4567 inev.kind = SELECT_WINDOW_EVENT;
4568 inev.frame_or_window = window;
a18bb28d
JR
4569 }
4570
9d4f32e8 4571 last_window = window;
a18bb28d 4572 }
fc5c7550
YM
4573 if (!note_mouse_movement (f, &msg.msg))
4574 help_echo_string = previous_help_echo_string;
a18bb28d 4575 }
ee78dc32 4576 else
791f420f
JR
4577 {
4578 /* If we move outside the frame, then we're
4579 certainly no longer on any text in the frame. */
bbf534ce 4580 clear_mouse_face (hlinfo);
791f420f
JR
4581 }
4582
89271099 4583 /* If the contents of the global variable help_echo_string
791f420f 4584 has changed, generate a HELP_EVENT. */
646b5f55 4585#if 0 /* The below is an invalid comparison when CHECK_LISP_OBJECT_TYPE.
e597eb7d
JR
4586 But it was originally changed to this to fix a bug, so I have
4587 not removed it completely in case the bug is still there. */
89271099
KS
4588 if (help_echo_string != previous_help_echo_string ||
4589 (!NILP (help_echo_string) && !STRINGP (help_echo_string) && f->mouse_moved))
e597eb7d
JR
4590#else /* This is what xterm.c does. */
4591 if (!NILP (help_echo_string)
4592 || !NILP (previous_help_echo_string))
6b61353c 4593 do_help = 1;
e597eb7d 4594#endif
791f420f 4595 break;
689004fa 4596
ee78dc32
GV
4597 case WM_LBUTTONDOWN:
4598 case WM_LBUTTONUP:
4599 case WM_MBUTTONDOWN:
4600 case WM_MBUTTONUP:
4601 case WM_RBUTTONDOWN:
4602 case WM_RBUTTONUP:
53823ab9
JR
4603 case WM_XBUTTONDOWN:
4604 case WM_XBUTTONUP:
ee78dc32 4605 {
791f420f
JR
4606 /* If we decide we want to generate an event to be seen
4607 by the rest of Emacs, we put it here. */
791f420f 4608 int tool_bar_p = 0;
ee78dc32
GV
4609 int button;
4610 int up;
791f420f 4611
ee78dc32
GV
4612 if (dpyinfo->grabbed && last_mouse_frame
4613 && FRAME_LIVE_P (last_mouse_frame))
4614 f = last_mouse_frame;
4615 else
4616 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
d67d1627 4617
ee78dc32
GV
4618 if (f)
4619 {
6b61353c 4620 construct_mouse_click (&inev, &msg, f);
d67d1627 4621
791f420f 4622 /* Is this in the tool-bar? */
e69b0960
DA
4623 if (WINDOWP (f->tool_bar_window)
4624 && WINDOW_TOTAL_LINES (XWINDOW (f->tool_bar_window)))
791f420f
JR
4625 {
4626 Lisp_Object window;
6b61353c
KH
4627 int x = XFASTINT (inev.x);
4628 int y = XFASTINT (inev.y);
791f420f 4629
9173a8fb 4630 window = window_from_coordinates (f, x, y, 0, 1);
b8b47c19 4631
e69b0960 4632 if (EQ (window, f->tool_bar_window))
791f420f 4633 {
6b61353c 4634 w32_handle_tool_bar_click (f, &inev);
791f420f
JR
4635 tool_bar_p = 1;
4636 }
4637 }
4638
6b61353c
KH
4639 if (tool_bar_p
4640 || (dpyinfo->w32_focus_frame
4641 && f != dpyinfo->w32_focus_frame))
4642 inev.kind = NO_EVENT;
ee78dc32 4643 }
d67d1627 4644
53823ab9
JR
4645 parse_button (msg.msg.message, HIWORD (msg.msg.wParam),
4646 &button, &up);
4647
ee78dc32
GV
4648 if (up)
4649 {
4650 dpyinfo->grabbed &= ~ (1 << button);
4651 }
4652 else
4653 {
4654 dpyinfo->grabbed |= (1 << button);
4655 last_mouse_frame = f;
791f420f
JR
4656 /* Ignore any mouse motion that happened
4657 before this event; any subsequent mouse-movement
4658 Emacs events should reflect only motion after
4659 the ButtonPress. */
4660 if (f != 0)
4661 f->mouse_moved = 0;
4662
4663 if (!tool_bar_p)
4664 last_tool_bar_item = -1;
ee78dc32 4665 }
689004fa 4666 break;
ee78dc32 4667 }
d67d1627 4668
1c64a4a2 4669 case WM_MOUSEWHEEL:
1526bc23 4670 case WM_MOUSEHWHEEL:
1c64a4a2 4671 {
1c64a4a2
JB
4672 if (dpyinfo->grabbed && last_mouse_frame
4673 && FRAME_LIVE_P (last_mouse_frame))
4674 f = last_mouse_frame;
4675 else
4676 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
4677
4678 if (f)
4679 {
1c64a4a2 4680
6b61353c
KH
4681 if (!dpyinfo->w32_focus_frame
4682 || f == dpyinfo->w32_focus_frame)
1c64a4a2 4683 {
637ad49d 4684 /* Emit an Emacs wheel-up/down event. */
6b61353c 4685 construct_mouse_wheel (&inev, &msg, f);
1c64a4a2 4686 }
637ad49d
JR
4687 /* Ignore any mouse motion that happened before this
4688 event; any subsequent mouse-movement Emacs events
4689 should reflect only motion after the
db9cd97a 4690 ButtonPress. */
637ad49d 4691 f->mouse_moved = 0;
1c64a4a2 4692 }
637ad49d
JR
4693 last_mouse_frame = f;
4694 last_tool_bar_item = -1;
1c64a4a2 4695 }
ee78dc32 4696 break;
689004fa 4697
12857dfd
RS
4698 case WM_DROPFILES:
4699 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
4700
4701 if (f)
6b61353c 4702 construct_drag_n_drop (&inev, &msg, f);
12857dfd
RS
4703 break;
4704
ee78dc32
GV
4705 case WM_VSCROLL:
4706 {
689004fa
GV
4707 struct scroll_bar *bar =
4708 x_window_to_scroll_bar ((HWND)msg.msg.lParam);
d67d1627 4709
6b61353c
KH
4710 if (bar)
4711 w32_scroll_bar_handle_click (bar, &msg, &inev);
689004fa 4712 break;
ee78dc32 4713 }
d67d1627 4714
689004fa 4715 case WM_WINDOWPOSCHANGED:
549808db
JR
4716 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
4717 if (f)
4718 {
62e50ec6
KS
4719 if (f->want_fullscreen & FULLSCREEN_WAIT)
4720 f->want_fullscreen &= ~(FULLSCREEN_WAIT|FULLSCREEN_BOTH);
549808db
JR
4721 }
4722 check_visibility = 1;
4723 break;
4724
689004fa
GV
4725 case WM_ACTIVATE:
4726 case WM_ACTIVATEAPP:
549808db
JR
4727 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
4728 if (f)
4729 x_check_fullscreen (f);
689004fa 4730 check_visibility = 1;
ee78dc32 4731 break;
689004fa 4732
ee78dc32
GV
4733 case WM_MOVE:
4734 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
d67d1627 4735
ee78dc32
GV
4736 if (f && !f->async_iconified)
4737 {
689004fa
GV
4738 int x, y;
4739
4740 x_real_positions (f, &x, &y);
62e50ec6
KS
4741 f->left_pos = x;
4742 f->top_pos = y;
ee78dc32 4743 }
689004fa
GV
4744
4745 check_visibility = 1;
4746 break;
4747
4748 case WM_SHOWWINDOW:
b71b8111
JR
4749 /* wParam non-zero means Window is about to be shown, 0 means
4750 about to be hidden. */
4751 /* Redo the mouse-highlight after the tooltip has gone. */
4752 if (!msg.msg.wParam && msg.msg.hwnd == tip_window)
4753 {
4754 tip_window = NULL;
4755 redo_mouse_highlight ();
4756 }
4757
689004fa 4758 /* If window has been obscured or exposed by another window
53964682 4759 being maximized or minimized/restored, then recheck
689004fa
GV
4760 visibility of all frames. Direct changes to our own
4761 windows get handled by WM_SIZE. */
4762#if 0
4763 if (msg.msg.lParam != 0)
4764 check_visibility = 1;
4765 else
4766 {
4767 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
4768 f->async_visible = msg.msg.wParam;
4769 }
4770#endif
4771
4772 check_visibility = 1;
ee78dc32 4773 break;
689004fa 4774
ee78dc32
GV
4775 case WM_SIZE:
4776 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
d67d1627 4777
689004fa
GV
4778 /* Inform lisp of whether frame has been iconified etc. */
4779 if (f)
ee78dc32 4780 {
689004fa 4781 switch (msg.msg.wParam)
ee78dc32 4782 {
689004fa
GV
4783 case SIZE_MINIMIZED:
4784 f->async_visible = 0;
ee78dc32 4785 f->async_iconified = 1;
d67d1627 4786
6b61353c
KH
4787 inev.kind = ICONIFY_EVENT;
4788 XSETFRAME (inev.frame_or_window, f);
689004fa
GV
4789 break;
4790
4791 case SIZE_MAXIMIZED:
4792 case SIZE_RESTORED:
ee78dc32
GV
4793 f->async_visible = 1;
4794 f->async_iconified = 0;
d67d1627 4795
d64b707c 4796 /* wait_reading_process_output will notice this and update
ee78dc32
GV
4797 the frame's display structures. */
4798 SET_FRAME_GARBAGED (f);
d67d1627 4799
ee78dc32
GV
4800 if (f->iconified)
4801 {
31d4844a
KH
4802 int x, y;
4803
4804 /* Reset top and left positions of the Window
4805 here since Windows sends a WM_MOVE message
4806 BEFORE telling us the Window is minimized
4807 when the Window is iconified, with 3000,3000
4808 as the co-ords. */
4809 x_real_positions (f, &x, &y);
62e50ec6
KS
4810 f->left_pos = x;
4811 f->top_pos = y;
31d4844a 4812
6b61353c
KH
4813 inev.kind = DEICONIFY_EVENT;
4814 XSETFRAME (inev.frame_or_window, f);
ee78dc32 4815 }
9ef2e2cf
JR
4816 else if (! NILP (Vframe_list)
4817 && ! NILP (XCDR (Vframe_list)))
ee78dc32
GV
4818 /* Force a redisplay sooner or later
4819 to update the frame titles
4820 in case this is the second frame. */
4821 record_asynch_buffer_change ();
689004fa 4822 break;
ee78dc32 4823 }
ee78dc32 4824 }
689004fa 4825
ef0e360f
GV
4826 if (f && !f->async_iconified && msg.msg.wParam != SIZE_MINIMIZED)
4827 {
4828 RECT rect;
4829 int rows;
4830 int columns;
4831 int width;
4832 int height;
d67d1627 4833
9127e20e 4834 GetClientRect (msg.msg.hwnd, &rect);
d67d1627 4835
ef0e360f
GV
4836 height = rect.bottom - rect.top;
4837 width = rect.right - rect.left;
d67d1627 4838
62e50ec6
KS
4839 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, height);
4840 columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, width);
d67d1627 4841
ef0e360f 4842 /* TODO: Clip size to the screen dimensions. */
d67d1627 4843
ef0e360f
GV
4844 /* Even if the number of character rows and columns has
4845 not changed, the font size may have changed, so we need
4846 to check the pixel dimensions as well. */
d67d1627 4847
62e50ec6
KS
4848 if (columns != FRAME_COLS (f)
4849 || rows != FRAME_LINES (f)
4850 || width != FRAME_PIXEL_WIDTH (f)
4851 || height != FRAME_PIXEL_HEIGHT (f))
ef0e360f 4852 {
791f420f 4853 change_frame_size (f, rows, columns, 0, 1, 0);
ef0e360f 4854 SET_FRAME_GARBAGED (f);
31d4844a 4855 cancel_mouse_face (f);
62e50ec6
KS
4856 FRAME_PIXEL_WIDTH (f) = width;
4857 FRAME_PIXEL_HEIGHT (f) = height;
4858 f->win_gravity = NorthWestGravity;
ef0e360f
GV
4859 }
4860 }
4861
689004fa
GV
4862 check_visibility = 1;
4863 break;
4864
1576fbfa
JR
4865 case WM_MOUSELEAVE:
4866 f = x_any_window_to_frame (dpyinfo, msg.msg.hwnd);
4867 if (f)
4868 {
bbf534ce 4869 if (f == hlinfo->mouse_face_mouse_frame)
1576fbfa
JR
4870 {
4871 /* If we move outside the frame, then we're
4872 certainly no longer on any text in the frame. */
bbf534ce
EZ
4873 clear_mouse_face (hlinfo);
4874 hlinfo->mouse_face_mouse_frame = 0;
1576fbfa
JR
4875 }
4876
4877 /* Generate a nil HELP_EVENT to cancel a help-echo.
4878 Do it only if there's something to cancel.
4879 Otherwise, the startup message is cleared when
4880 the mouse leaves the frame. */
4881 if (any_help_event_p)
6b61353c 4882 do_help = -1;
1576fbfa
JR
4883 }
4884 break;
d67d1627 4885
689004fa 4886 case WM_SETFOCUS:
55131bef 4887 w32_detect_focus_change (dpyinfo, &msg, &inev);
791f420f 4888
791f420f
JR
4889 dpyinfo->grabbed = 0;
4890 check_visibility = 1;
4891 break;
4892
689004fa 4893 case WM_KILLFOCUS:
791f420f 4894 f = x_top_window_to_frame (dpyinfo, msg.msg.hwnd);
08712a41 4895
791f420f
JR
4896 if (f)
4897 {
791f420f
JR
4898 if (f == dpyinfo->w32_focus_event_frame)
4899 dpyinfo->w32_focus_event_frame = 0;
4900
4901 if (f == dpyinfo->w32_focus_frame)
4902 x_new_focus_frame (dpyinfo, 0);
4903
bbf534ce 4904 if (f == hlinfo->mouse_face_mouse_frame)
791f420f
JR
4905 {
4906 /* If we move outside the frame, then we're
4907 certainly no longer on any text in the frame. */
bbf534ce
EZ
4908 clear_mouse_face (hlinfo);
4909 hlinfo->mouse_face_mouse_frame = 0;
791f420f 4910 }
9ef2e2cf 4911
791f420f
JR
4912 /* Generate a nil HELP_EVENT to cancel a help-echo.
4913 Do it only if there's something to cancel.
4914 Otherwise, the startup message is cleared when
4915 the mouse leaves the frame. */
4916 if (any_help_event_p)
6b61353c 4917 do_help = -1;
791f420f 4918 }
689004fa 4919
08712a41 4920 dpyinfo->grabbed = 0;
689004fa 4921 check_visibility = 1;
ee78dc32 4922 break;
689004fa 4923
ee78dc32
GV
4924 case WM_CLOSE:
4925 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
d67d1627 4926
ee78dc32
GV
4927 if (f)
4928 {
6b61353c
KH
4929 inev.kind = DELETE_WINDOW_EVENT;
4930 XSETFRAME (inev.frame_or_window, f);
ee78dc32 4931 }
689004fa
GV
4932 break;
4933
4934 case WM_INITMENU:
4935 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
d67d1627 4936
689004fa
GV
4937 if (f)
4938 {
6b61353c
KH
4939 inev.kind = MENU_BAR_ACTIVATE_EVENT;
4940 XSETFRAME (inev.frame_or_window, f);
689004fa 4941 }
ee78dc32 4942 break;
689004fa 4943
ee78dc32
GV
4944 case WM_COMMAND:
4945 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
014b6ea1 4946
ee78dc32
GV
4947 if (f)
4948 {
f98169a0
GV
4949 extern void menubar_selection_callback
4950 (FRAME_PTR f, void * client_data);
014b6ea1 4951 menubar_selection_callback (f, (void *)msg.msg.wParam);
ee78dc32 4952 }
689004fa
GV
4953
4954 check_visibility = 1;
4955 break;
4956
4957 case WM_DISPLAYCHANGE:
4958 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
4959
d67d1627 4960 if (f)
689004fa 4961 {
689004fa 4962 dpyinfo->n_cbits = msg.msg.wParam;
b89c78a5
CY
4963 DebPrint (("display change: %d %d\n",
4964 (short) LOWORD (msg.msg.lParam),
4965 (short) HIWORD (msg.msg.lParam)));
689004fa 4966 }
d67d1627 4967
689004fa 4968 check_visibility = 1;
ee78dc32 4969 break;
e7efd97e 4970
477f1e50
EZ
4971 case WM_EMACS_FILENOTIFY:
4972 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
4973 if (f)
4974 queue_notifications (&inev, &msg, f, &count);
4975 break;
4976
e7efd97e 4977 default:
e471b241 4978 /* Check for messages registered at runtime. */
e7efd97e
GV
4979 if (msg.msg.message == msh_mousewheel)
4980 {
e471b241 4981 /* Forward MSH_MOUSEWHEEL as WM_MOUSEWHEEL. */
66f30e44 4982 msg.msg.message = WM_MOUSEWHEEL;
e471b241 4983 prepend_msg (&msg);
e7efd97e
GV
4984 }
4985 break;
ee78dc32 4986 }
6b61353c
KH
4987
4988 if (inev.kind != NO_EVENT)
4989 {
4990 kbd_buffer_store_event_hold (&inev, hold_quit);
4991 count++;
4992 }
4993
4994 if (do_help
4995 && !(hold_quit && hold_quit->kind != NO_EVENT))
4996 {
4997 Lisp_Object frame;
4998
4999 if (f)
5000 XSETFRAME (frame, f);
5001 else
5002 frame = Qnil;
5003
5004 if (do_help > 0)
5005 {
e597eb7d 5006 if (NILP (help_echo_string))
6b61353c
KH
5007 {
5008 help_echo_object = help_echo_window = Qnil;
5009 help_echo_pos = -1;
5010 }
5011
5012 any_help_event_p = 1;
5013 gen_help_event (help_echo_string, frame, help_echo_window,
5014 help_echo_object, help_echo_pos);
5015 }
5016 else
5017 {
5018 help_echo_string = Qnil;
5019 gen_help_event (Qnil, frame, Qnil, Qnil, 0);
5020 }
5021 count++;
5022 }
ee78dc32
GV
5023 }
5024
5025 /* If the focus was just given to an autoraising frame,
5026 raise it now. */
5027 /* ??? This ought to be able to handle more than one such frame. */
5028 if (pending_autoraise_frame)
5029 {
5030 x_raise_frame (pending_autoraise_frame);
5031 pending_autoraise_frame = 0;
5032 }
5033
e8500ff4 5034 /* Check which frames are still visible, if we have enqueued any user
689004fa
GV
5035 events or been notified of events that may affect visibility. We
5036 do this here because there doesn't seem to be any direct
5037 notification from Windows that the visibility of a window has
5038 changed (at least, not in all cases). */
5039 if (count > 0 || check_visibility)
5040 {
5041 Lisp_Object tail, frame;
5042
5043 FOR_EACH_FRAME (tail, frame)
1c64a4a2
JB
5044 {
5045 FRAME_PTR f = XFRAME (frame);
5046 /* The tooltip has been drawn already. Avoid the
5047 SET_FRAME_GARBAGED below. */
5048 if (EQ (frame, tip_frame))
5049 continue;
5050
5051 /* Check "visible" frames and mark each as obscured or not.
5052 Note that async_visible is nonzero for unobscured and
5053 obscured frames, but zero for hidden and iconified frames. */
5054 if (FRAME_W32_P (f) && f->async_visible)
5055 {
5056 RECT clipbox;
5057 HDC hdc;
5058
5059 enter_crit ();
5060 /* Query clipping rectangle for the entire window area
5061 (GetWindowDC), not just the client portion (GetDC).
5062 Otherwise, the scrollbars and menubar aren't counted as
5063 part of the visible area of the frame, and we may think
5064 the frame is obscured when really a scrollbar is still
5065 visible and gets WM_PAINT messages above. */
5066 hdc = GetWindowDC (FRAME_W32_WINDOW (f));
5067 GetClipBox (hdc, &clipbox);
5068 ReleaseDC (FRAME_W32_WINDOW (f), hdc);
5069 leave_crit ();
5070
5071 if (clipbox.right == clipbox.left
5072 || clipbox.bottom == clipbox.top)
5073 {
5074 /* Frame has become completely obscured so mark as
5075 such (we do this by setting async_visible to 2 so
5076 that FRAME_VISIBLE_P is still true, but redisplay
5077 will skip it). */
5078 f->async_visible = 2;
689004fa 5079
1c64a4a2
JB
5080 if (!FRAME_OBSCURED_P (f))
5081 {
5082 DebPrint (("frame %p (%s) obscured\n", f,
e69b0960 5083 SDATA (f->name)));
1c64a4a2
JB
5084 }
5085 }
5086 else
5087 {
5088 /* Frame is not obscured, so mark it as such. */
5089 f->async_visible = 1;
689004fa 5090
1c64a4a2
JB
5091 if (FRAME_OBSCURED_P (f))
5092 {
5093 SET_FRAME_GARBAGED (f);
5094 DebPrint (("obscured frame %p (%s) found to be visible\n", f,
e69b0960 5095 SDATA (f->name)));
689004fa 5096
1c64a4a2
JB
5097 /* Force a redisplay sooner or later. */
5098 record_asynch_buffer_change ();
5099 }
5100 }
5101 }
5102 }
689004fa
GV
5103 }
5104
4d7e6e51 5105 unblock_input ();
ee78dc32
GV
5106 return count;
5107}
791f420f 5108
9ef2e2cf 5109
ee78dc32 5110\f
791f420f
JR
5111/***********************************************************************
5112 Text Cursor
5113 ***********************************************************************/
5114
791f420f
JR
5115/* Set clipping for output in glyph row ROW. W is the window in which
5116 we operate. GC is the graphics context to set clipping in.
ee78dc32 5117
791f420f
JR
5118 ROW may be a text row or, e.g., a mode line. Text rows must be
5119 clipped to the interior of the window dedicated to text display,
5120 mode lines must be clipped to the whole window. */
ee78dc32
GV
5121
5122static void
b56ceb92 5123w32_clip_to_row (struct window *w, struct glyph_row *row, int area, HDC hdc)
ee78dc32 5124{
791f420f 5125 RECT clip_rect;
b5a2e277 5126 int window_x, window_y, window_width;
52cf03a1 5127
b5a2e277 5128 window_box (w, area, &window_x, &window_y, &window_width, 0);
52cf03a1 5129
b5a2e277 5130 clip_rect.left = window_x;
791f420f
JR
5131 clip_rect.top = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
5132 clip_rect.top = max (clip_rect.top, window_y);
5133 clip_rect.right = clip_rect.left + window_width;
5134 clip_rect.bottom = clip_rect.top + row->visible_height;
5135
791f420f 5136 w32_set_clip_rectangle (hdc, &clip_rect);
ee78dc32
GV
5137}
5138
791f420f
JR
5139
5140/* Draw a hollow box cursor on window W in glyph row ROW. */
ee78dc32
GV
5141
5142static void
b56ceb92 5143x_draw_hollow_cursor (struct window *w, struct glyph_row *row)
ee78dc32 5144{
791f420f 5145 struct frame *f = XFRAME (WINDOW_FRAME (w));
988646fc 5146 HDC hdc;
791f420f 5147 RECT rect;
b756209d 5148 int left, top, h;
791f420f
JR
5149 struct glyph *cursor_glyph;
5150 HBRUSH hb = CreateSolidBrush (f->output_data.w32->cursor_pixel);
5151
07c07cfe
JR
5152 /* Get the glyph the cursor is on. If we can't tell because
5153 the current matrix is invalid or such, give up. */
5154 cursor_glyph = get_phys_cursor_glyph (w);
5155 if (cursor_glyph == NULL)
5156 return;
5157
4d91ce74 5158 /* Compute frame-relative coordinates for phys cursor. */
b756209d
EZ
5159 get_phys_cursor_geometry (w, row, cursor_glyph, &left, &top, &h);
5160 rect.left = left;
5161 rect.top = top;
07c07cfe 5162 rect.bottom = rect.top + h;
4d91ce74 5163 rect.right = rect.left + w->phys_cursor_width;
ee78dc32 5164
988646fc 5165 hdc = get_frame_dc (f);
a18bb28d 5166 /* Set clipping, draw the rectangle, and reset clipping again. */
b5a2e277 5167 w32_clip_to_row (w, row, TEXT_AREA, hdc);
791f420f
JR
5168 FrameRect (hdc, &rect, hb);
5169 DeleteObject (hb);
a18bb28d 5170 w32_set_clip_rectangle (hdc, NULL);
791f420f 5171 release_frame_dc (f, hdc);
ee78dc32
GV
5172}
5173
791f420f
JR
5174
5175/* Draw a bar cursor on window W in glyph row ROW.
5176
5177 Implementation note: One would like to draw a bar cursor with an
5178 angle equal to the one given by the font property XA_ITALIC_ANGLE.
5179 Unfortunately, I didn't find a font yet that has this property set.
5180 --gerd. */
ee78dc32
GV
5181
5182static void
b56ceb92
JB
5183x_draw_bar_cursor (struct window *w, struct glyph_row *row,
5184 int width, enum text_cursor_kinds kind)
ee78dc32 5185{
d3d50620 5186 struct frame *f = XFRAME (w->frame);
c2cc16fa 5187 struct glyph *cursor_glyph;
791f420f 5188
c2cc16fa
JR
5189 /* If cursor is out of bounds, don't draw garbage. This can happen
5190 in mini-buffer windows when switching between echo area glyphs
5191 and mini-buffer. */
5192 cursor_glyph = get_phys_cursor_glyph (w);
5193 if (cursor_glyph == NULL)
5194 return;
9ef2e2cf 5195
c2cc16fa
JR
5196 /* If on an image, draw like a normal cursor. That's usually better
5197 visible than drawing a bar, esp. if the image is large so that
5198 the bar might not be in the window. */
5199 if (cursor_glyph->type == IMAGE_GLYPH)
5200 {
5201 struct glyph_row *row;
5202 row = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos);
89271099 5203 draw_phys_cursor_glyph (w, row, DRAW_CURSOR);
c2cc16fa
JR
5204 }
5205 else
5206 {
6ff3e5e3
JR
5207 COLORREF cursor_color = f->output_data.w32->cursor_pixel;
5208 struct face *face = FACE_FROM_ID (f, cursor_glyph->face_id);
705af33f
JR
5209 int x;
5210 HDC hdc;
6ff3e5e3 5211
6ff3e5e3
JR
5212 /* If the glyph's background equals the color we normally draw
5213 the bar cursor in, the bar cursor in its normal color is
5214 invisible. Use the glyph's foreground color instead in this
5215 case, on the assumption that the glyph's colors are chosen so
5216 that the glyph is legible. */
5217 if (face->background == cursor_color)
5218 cursor_color = face->foreground;
5219
c2cc16fa 5220 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
a18bb28d 5221
c2cc16fa 5222 hdc = get_frame_dc (f);
b5a2e277 5223 w32_clip_to_row (w, row, TEXT_AREA, hdc);
17456df1
JR
5224
5225 if (kind == BAR_CURSOR)
5226 {
705af33f
JR
5227 if (width < 0)
5228 width = FRAME_CURSOR_WIDTH (f);
5229 width = min (cursor_glyph->pixel_width, width);
5230
5231 w->phys_cursor_width = width;
5232
93352106
EZ
5233 /* If the character under cursor is R2L, draw the bar cursor
5234 on the right of its glyph, rather than on the left. */
5235 if ((cursor_glyph->resolved_level & 1) != 0)
5236 x += cursor_glyph->pixel_width - width;
5237
17456df1
JR
5238 w32_fill_area (f, hdc, cursor_color, x,
5239 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
5240 width, row->height);
5241 }
5242 else
5243 {
705af33f
JR
5244 int dummy_x, dummy_y, dummy_h;
5245
5246 if (width < 0)
5247 width = row->height;
5248
5249 width = min (row->height, width);
5250
5251 get_phys_cursor_geometry (w, row, cursor_glyph, &dummy_x,
5252 &dummy_y, &dummy_h);
17456df1
JR
5253 w32_fill_area (f, hdc, cursor_color, x,
5254 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y +
5255 row->height - width),
705af33f 5256 w->phys_cursor_width, width);
17456df1 5257 }
a18bb28d
JR
5258
5259 w32_set_clip_rectangle (hdc, NULL);
c2cc16fa 5260 release_frame_dc (f, hdc);
791f420f 5261 }
ee78dc32
GV
5262}
5263
791f420f 5264
89271099 5265/* RIF: Define cursor CURSOR on frame F. */
791f420f 5266
ee78dc32 5267static void
b56ceb92 5268w32_define_frame_cursor (struct frame *f, Cursor cursor)
ee78dc32 5269{
89271099 5270 w32_define_cursor (FRAME_W32_WINDOW (f), cursor);
791f420f 5271}
ee78dc32 5272
ee78dc32 5273
89271099 5274/* RIF: Clear area on frame F. */
ee78dc32 5275
791f420f 5276static void
b56ceb92 5277w32_clear_frame_area (struct frame *f, int x, int y, int width, int height)
791f420f 5278{
89271099 5279 HDC hdc;
791f420f 5280
89271099
KS
5281 hdc = get_frame_dc (f);
5282 w32_clear_area (f, hdc, x, y, width, height);
5283 release_frame_dc (f, hdc);
791f420f 5284}
ee78dc32 5285
89271099 5286/* RIF: Draw or clear cursor on window W. */
791f420f
JR
5287
5288static void
b56ceb92
JB
5289w32_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
5290 int x, int y, int cursor_type, int cursor_width,
5291 int on_p, int active_p)
ee78dc32 5292{
e5a3b7d9 5293 if (on_p)
791f420f 5294 {
99558ce8
JR
5295 /* If the user wants to use the system caret, make sure our own
5296 cursor remains invisible. */
5297 if (w32_use_visible_system_caret)
5298 {
6b61353c
KH
5299 /* Call to erase_phys_cursor here seems to use the
5300 wrong values of w->phys_cursor, as they have been
5301 overwritten before this function was called. */
99558ce8 5302 if (w->phys_cursor_type != NO_CURSOR)
89271099 5303 erase_phys_cursor (w);
99558ce8 5304
e5a3b7d9 5305 cursor_type = w->phys_cursor_type = NO_CURSOR;
e1429afe 5306 w->phys_cursor_width = -1;
99558ce8
JR
5307 }
5308 else
e1429afe 5309 {
e5a3b7d9 5310 w->phys_cursor_type = cursor_type;
e1429afe 5311 }
99558ce8 5312
791f420f
JR
5313 w->phys_cursor_on_p = 1;
5314
abb15ebd
JR
5315 /* If this is the active cursor, we need to track it with the
5316 system caret, so third party software like screen magnifiers
5317 and speech synthesizers can follow the cursor. */
e5a3b7d9 5318 if (active_p)
abb15ebd 5319 {
0648dde0 5320 struct frame *f = XFRAME (WINDOW_FRAME (w));
99558ce8 5321 HWND hwnd = FRAME_W32_WINDOW (f);
abb15ebd 5322
99558ce8
JR
5323 w32_system_caret_x
5324 = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
5325 w32_system_caret_y
5326 = (WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y)
5327 + glyph_row->ascent - w->phys_cursor_ascent);
5328
c902b920
JR
5329 PostMessage (hwnd, WM_IME_STARTCOMPOSITION, 0, 0);
5330
99558ce8
JR
5331 /* If the size of the active cursor changed, destroy the old
5332 system caret. */
5333 if (w32_system_caret_hwnd
5334 && (w32_system_caret_height != w->phys_cursor_height))
5335 PostMessage (hwnd, WM_EMACS_DESTROY_CARET, 0, 0);
5336
5337 w32_system_caret_height = w->phys_cursor_height;
5338
5339 /* Move the system caret. */
5340 PostMessage (hwnd, WM_EMACS_TRACK_CARET, 0, 0);
abb15ebd
JR
5341 }
5342
6b61353c 5343 if (glyph_row->exact_window_width_line_p
f951a506
EZ
5344 && (glyph_row->reversed_p
5345 ? (w->phys_cursor.hpos < 0)
5346 : (w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])))
6b61353c
KH
5347 {
5348 glyph_row->cursor_in_fringe_p = 1;
f951a506 5349 draw_fringe_bitmap (w, glyph_row, glyph_row->reversed_p);
6b61353c
KH
5350 return;
5351 }
5352
e5a3b7d9 5353 switch (cursor_type)
ee78dc32 5354 {
791f420f
JR
5355 case HOLLOW_BOX_CURSOR:
5356 x_draw_hollow_cursor (w, glyph_row);
5357 break;
5358
5359 case FILLED_BOX_CURSOR:
89271099 5360 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
791f420f
JR
5361 break;
5362
5363 case BAR_CURSOR:
e5a3b7d9 5364 x_draw_bar_cursor (w, glyph_row, cursor_width, BAR_CURSOR);
17456df1
JR
5365 break;
5366
5367 case HBAR_CURSOR:
e5a3b7d9 5368 x_draw_bar_cursor (w, glyph_row, cursor_width, HBAR_CURSOR);
791f420f 5369 break;
ee78dc32 5370
791f420f 5371 case NO_CURSOR:
a18bb28d 5372 w->phys_cursor_width = 0;
791f420f
JR
5373 break;
5374
5375 default:
1088b922 5376 emacs_abort ();
791f420f 5377 }
ee78dc32
GV
5378 }
5379}
5380
689004fa 5381
ee78dc32 5382\f
7f5d1df8
GV
5383/* Icons. */
5384
5385int
b56ceb92 5386x_bitmap_icon (struct frame *f, Lisp_Object icon)
7f5d1df8 5387{
945a75f8
JR
5388 HANDLE main_icon;
5389 HANDLE small_icon = NULL;
7f5d1df8
GV
5390
5391 if (FRAME_W32_WINDOW (f) == 0)
5392 return 1;
5393
5394 if (NILP (icon))
945a75f8 5395 main_icon = LoadIcon (hinst, EMACS_CLASS);
7f5d1df8 5396 else if (STRINGP (icon))
945a75f8
JR
5397 {
5398 /* Load the main icon from the named file. */
5399 main_icon = LoadImage (NULL, (LPCTSTR) SDATA (icon), IMAGE_ICON, 0, 0,
5400 LR_DEFAULTSIZE | LR_LOADFROMFILE);
5401 /* Try to load a small icon to go with it. */
5402 small_icon = LoadImage (NULL, (LPCSTR) SDATA (icon), IMAGE_ICON,
5403 GetSystemMetrics (SM_CXSMICON),
5404 GetSystemMetrics (SM_CYSMICON),
5405 LR_LOADFROMFILE);
5406 }
7f5d1df8
GV
5407 else if (SYMBOLP (icon))
5408 {
5409 LPCTSTR name;
5410
5411 if (EQ (icon, intern ("application")))
5412 name = (LPCTSTR) IDI_APPLICATION;
5413 else if (EQ (icon, intern ("hand")))
5414 name = (LPCTSTR) IDI_HAND;
5415 else if (EQ (icon, intern ("question")))
5416 name = (LPCTSTR) IDI_QUESTION;
5417 else if (EQ (icon, intern ("exclamation")))
5418 name = (LPCTSTR) IDI_EXCLAMATION;
5419 else if (EQ (icon, intern ("asterisk")))
5420 name = (LPCTSTR) IDI_ASTERISK;
5421 else if (EQ (icon, intern ("winlogo")))
5422 name = (LPCTSTR) IDI_WINLOGO;
5423 else
5424 return 1;
5425
945a75f8 5426 main_icon = LoadIcon (NULL, name);
7f5d1df8
GV
5427 }
5428 else
5429 return 1;
5430
945a75f8 5431 if (main_icon == NULL)
7f5d1df8
GV
5432 return 1;
5433
791f420f 5434 PostMessage (FRAME_W32_WINDOW (f), WM_SETICON, (WPARAM) ICON_BIG,
945a75f8
JR
5435 (LPARAM) main_icon);
5436
5437 /* If there is a small icon that goes with it, set that too. */
5438 if (small_icon)
5439 PostMessage (FRAME_W32_WINDOW (f), WM_SETICON, (WPARAM) ICON_SMALL,
5440 (LPARAM) small_icon);
7f5d1df8
GV
5441
5442 return 0;
5443}
5444
5445\f
c2cc16fa
JR
5446/************************************************************************
5447 Handling X errors
5448 ************************************************************************/
5449
5450/* Display Error Handling functions not used on W32. Listing them here
5451 helps diff stay in step when comparing w32term.c with xterm.c.
5452
5453x_error_catcher (display, error)
5454x_catch_errors (dpy)
5455x_catch_errors_unwind (old_val)
5456x_check_errors (dpy, format)
16ca6226 5457x_fully_uncatch_errors ()
c2cc16fa
JR
5458x_had_errors_p (dpy)
5459x_clear_errors (dpy)
5460x_uncatch_errors (dpy, count)
5461x_trace_wire ()
5462x_connection_signal (signalnum)
5463x_connection_closed (dpy, error_message)
5464x_error_quitter (display, error)
5465x_error_handler (display, error)
5466x_io_error_quitter (display)
5467
5468 */
5469
5470\f
ee78dc32
GV
5471/* Changing the font of the frame. */
5472
027f6f90 5473Lisp_Object
b56ceb92 5474x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
027f6f90 5475{
ef39ccbb 5476 struct font *font = XFONT_OBJECT (font_object);
027f6f90 5477
ef39ccbb
KH
5478 if (fontset < 0)
5479 fontset = fontset_from_font (font_object);
5480 FRAME_FONTSET (f) = fontset;
5481 if (FRAME_FONT (f) == font)
027f6f90
JR
5482 /* This font is already set in frame F. There's nothing more to
5483 do. */
f9c34147 5484 return font_object;
027f6f90 5485
ef39ccbb
KH
5486 FRAME_FONT (f) = font;
5487 FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
5488 FRAME_COLUMN_WIDTH (f) = font->average_width;
5489 FRAME_SPACE_WIDTH (f) = font->space_width;
5490 FRAME_LINE_HEIGHT (f) = font->height;
027f6f90
JR
5491
5492 compute_fringe_widths (f, 1);
5493
5494 /* Compute the scroll bar width in character columns. */
5495 if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
5496 {
5497 int wid = FRAME_COLUMN_WIDTH (f);
5498 FRAME_CONFIG_SCROLL_BAR_COLS (f)
5499 = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
5500 }
5501 else
5502 {
5503 int wid = FRAME_COLUMN_WIDTH (f);
5504 FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
5505 }
5506
5507 /* Now make the frame display the given font. */
5508 if (FRAME_X_WINDOW (f) != 0)
5509 {
5510 /* Don't change the size of a tip frame; there's no point in
5511 doing it because it's done in Fx_show_tip, and it leads to
5512 problems because the tip frame has no widget. */
5513 if (NILP (tip_frame) || XFRAME (tip_frame) != f)
5514 x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
5515 }
5516
f9c34147 5517 /* X version sets font of input methods here also. */
027f6f90 5518
f9c34147 5519 return font_object;
027f6f90 5520}
027f6f90 5521
c2cc16fa
JR
5522\f
5523/***********************************************************************
5524 TODO: W32 Input Methods
5525 ***********************************************************************/
5526/* Listing missing functions from xterm.c helps diff stay in step.
791f420f 5527
c2cc16fa
JR
5528xim_destroy_callback (xim, client_data, call_data)
5529xim_open_dpy (dpyinfo, resource_name)
5530struct xim_inst_t
5531xim_instantiate_callback (display, client_data, call_data)
5532xim_initialize (dpyinfo, resource_name)
5533xim_close_dpy (dpyinfo)
791f420f 5534
c2cc16fa 5535 */
791f420f 5536
cabb23bc 5537\f
689004fa
GV
5538/* Calculate the absolute position in frame F
5539 from its current recorded position values and gravity. */
5540
9ef2e2cf 5541void
b56ceb92 5542x_calc_absolute_position (struct frame *f)
ee78dc32 5543{
62e50ec6 5544 int flags = f->size_hint_flags;
ee78dc32 5545
83676aa2
KS
5546 /* The sum of the widths of the frame's left and right borders, and
5547 the sum of the heights of the frame's top and bottom borders (in
5548 pixels) drawn by Windows. */
5549 unsigned int left_right_borders_width, top_bottom_borders_height;
5550
5551 /* Try to get the actual values of these two variables. We compute
5552 the border width (height) by subtracting the width (height) of
5553 the frame's client area from the width (height) of the frame's
5554 entire window. */
5555 WINDOWPLACEMENT wp = { 0 };
5556 RECT client_rect = { 0 };
5557
5558 if (GetWindowPlacement (FRAME_W32_WINDOW (f), &wp)
5559 && GetClientRect (FRAME_W32_WINDOW (f), &client_rect))
5560 {
5561 left_right_borders_width =
5562 (wp.rcNormalPosition.right - wp.rcNormalPosition.left) -
5563 (client_rect.right - client_rect.left);
5564
5565 top_bottom_borders_height =
5566 (wp.rcNormalPosition.bottom - wp.rcNormalPosition.top) -
5567 (client_rect.bottom - client_rect.top);
5568 }
5569 else
5570 {
5571 /* Use sensible default values. */
5572 left_right_borders_width = 8;
5573 top_bottom_borders_height = 32;
5574 }
5575
5576 /* Treat negative positions as relative to the rightmost bottommost
ee78dc32
GV
5577 position that fits on the screen. */
5578 if (flags & XNegative)
b89c78a5 5579 f->left_pos = (x_display_pixel_width (FRAME_W32_DISPLAY_INFO (f))
62e50ec6 5580 - FRAME_PIXEL_WIDTH (f)
83676aa2
KS
5581 + f->left_pos
5582 - (left_right_borders_width - 1));
158cba56 5583
ee78dc32 5584 if (flags & YNegative)
b89c78a5 5585 f->top_pos = (x_display_pixel_height (FRAME_W32_DISPLAY_INFO (f))
62e50ec6 5586 - FRAME_PIXEL_HEIGHT (f)
83676aa2
KS
5587 + f->top_pos
5588 - (top_bottom_borders_height - 1));
5589
5590 /* The left_pos and top_pos are now relative to the top and left
5591 screen edges, so the flags should correspond. */
62e50ec6 5592 f->size_hint_flags &= ~ (XNegative | YNegative);
ee78dc32
GV
5593}
5594
5595/* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
5596 to really change the position, and 0 when calling from
5597 x_make_frame_visible (in that case, XOFF and YOFF are the current
5598 position values). It is -1 when calling from x_set_frame_parameters,
5599 which means, do adjust for borders but don't change the gravity. */
5600
9ef2e2cf 5601void
b56ceb92
JB
5602x_set_offset (struct frame *f, register int xoff, register int yoff,
5603 int change_gravity)
ee78dc32
GV
5604{
5605 int modified_top, modified_left;
5606
5607 if (change_gravity > 0)
5608 {
62e50ec6
KS
5609 f->top_pos = yoff;
5610 f->left_pos = xoff;
5611 f->size_hint_flags &= ~ (XNegative | YNegative);
ee78dc32 5612 if (xoff < 0)
62e50ec6 5613 f->size_hint_flags |= XNegative;
ee78dc32 5614 if (yoff < 0)
62e50ec6
KS
5615 f->size_hint_flags |= YNegative;
5616 f->win_gravity = NorthWestGravity;
ee78dc32
GV
5617 }
5618 x_calc_absolute_position (f);
5619
4d7e6e51 5620 block_input ();
ee78dc32
GV
5621 x_wm_set_size_hint (f, (long) 0, 0);
5622
62e50ec6
KS
5623 modified_left = f->left_pos;
5624 modified_top = f->top_pos;
ee78dc32 5625
fbd6baed 5626 my_set_window_pos (FRAME_W32_WINDOW (f),
52cf03a1
GV
5627 NULL,
5628 modified_left, modified_top,
cabb23bc 5629 0, 0,
689004fa 5630 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
4d7e6e51 5631 unblock_input ();
ee78dc32
GV
5632}
5633
549808db
JR
5634
5635/* Check if we need to resize the frame due to a fullscreen request.
cc92c454 5636 If so needed, resize the frame. */
549808db 5637static void
b56ceb92 5638x_check_fullscreen (struct frame *f)
549808db 5639{
62e50ec6 5640 if (f->want_fullscreen & FULLSCREEN_BOTH)
549808db
JR
5641 {
5642 int width, height, ign;
d67d1627 5643
62e50ec6 5644 x_real_positions (f, &f->left_pos, &f->top_pos);
549808db
JR
5645
5646 x_fullscreen_adjust (f, &width, &height, &ign, &ign);
d67d1627 5647
549808db 5648 /* We do not need to move the window, it shall be taken care of
66f30e44 5649 when setting WM manager hints. */
62e50ec6 5650 if (FRAME_COLS (f) != width || FRAME_LINES (f) != height)
549808db
JR
5651 {
5652 change_frame_size (f, height, width, 0, 1, 0);
5653 SET_FRAME_GARBAGED (f);
5654 cancel_mouse_face (f);
5655
cc92c454 5656 /* Wait for the change of frame size to occur. */
62e50ec6 5657 f->want_fullscreen |= FULLSCREEN_WAIT;
549808db
JR
5658 }
5659 }
5660}
5661
ee78dc32
GV
5662/* Call this to change the size of frame F's x-window.
5663 If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
5664 for this size change and subsequent size changes.
5665 Otherwise we leave the window gravity unchanged. */
c2cc16fa 5666
791f420f 5667void
b56ceb92 5668x_set_window_size (struct frame *f, int change_gravity, int cols, int rows)
ee78dc32
GV
5669{
5670 int pixelwidth, pixelheight;
d67d1627 5671
4d7e6e51 5672 block_input ();
d67d1627 5673
ee78dc32 5674 check_frame_size (f, &rows, &cols);
62e50ec6
KS
5675 f->scroll_bar_actual_width
5676 = FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f);
d33c49e8 5677
b6ae1532 5678 compute_fringe_widths (f, 0);
d33c49e8 5679
62e50ec6
KS
5680 pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, cols);
5681 pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
d67d1627 5682
62e50ec6 5683 f->win_gravity = NorthWestGravity;
ee78dc32 5684 x_wm_set_size_hint (f, (long) 0, 0);
d67d1627 5685
ee78dc32
GV
5686 {
5687 RECT rect;
5688
5689 rect.left = rect.top = 0;
5690 rect.right = pixelwidth;
5691 rect.bottom = pixelheight;
d67d1627 5692
ed3751c8
JB
5693 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
5694 FRAME_EXTERNAL_MENU_BAR (f));
d67d1627 5695
fbd6baed 5696 my_set_window_pos (FRAME_W32_WINDOW (f),
d67d1627 5697 NULL,
52cf03a1 5698 0, 0,
689004fa
GV
5699 rect.right - rect.left,
5700 rect.bottom - rect.top,
5701 SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
ee78dc32 5702 }
d67d1627 5703
f8d1a163
JR
5704#if 0
5705 /* The following mirrors what is done in xterm.c. It appears to be
5706 for informing lisp of the new size immediately, while the actual
5707 resize will happen asynchronously. But on Windows, the menu bar
5708 automatically wraps when the frame is too narrow to contain it,
5709 and that causes any calculations made here to come out wrong. The
fffa137c 5710 end is some nasty buggy behavior, including the potential loss
f8d1a163
JR
5711 of the minibuffer.
5712
5713 Disabling this code is either not sufficient to fix the problems
5714 completely, or it causes fresh problems, but at least it removes
5715 the most problematic symptom of the minibuffer becoming unusable.
5716
5717 -----------------------------------------------------------------
5718
5719 Now, strictly speaking, we can't be sure that this is accurate,
ee78dc32
GV
5720 but the window manager will get around to dealing with the size
5721 change request eventually, and we'll hear how it went when the
5722 ConfigureNotify event gets here.
d67d1627 5723
ee78dc32
GV
5724 We could just not bother storing any of this information here,
5725 and let the ConfigureNotify event set everything up, but that
ec48c3a7 5726 might be kind of confusing to the Lisp code, since size changes
ee78dc32 5727 wouldn't be reported in the frame parameters until some random
791f420f
JR
5728 point in the future when the ConfigureNotify event arrives.
5729
5730 We pass 1 for DELAY since we can't run Lisp code inside of
5731 a BLOCK_INPUT. */
5732 change_frame_size (f, rows, cols, 0, 1, 0);
62e50ec6
KS
5733 FRAME_PIXEL_WIDTH (f) = pixelwidth;
5734 FRAME_PIXEL_HEIGHT (f) = pixelheight;
ee78dc32 5735
689004fa
GV
5736 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
5737 receive in the ConfigureNotify event; if we get what we asked
5738 for, then the event won't cause the screen to become garbaged, so
5739 we have to make sure to do it here. */
5740 SET_FRAME_GARBAGED (f);
5741
ee78dc32 5742 /* If cursor was outside the new size, mark it as off. */
e69b0960 5743 mark_window_cursors_off (XWINDOW (f->root_window));
ee78dc32 5744
689004fa 5745 /* Clear out any recollection of where the mouse highlighting was,
d67d1627 5746 since it might be in a place that's outside the new frame size.
689004fa
GV
5747 Actually checking whether it is outside is a pain in the neck,
5748 so don't try--just let the highlighting be done afresh with new size. */
31d4844a 5749 cancel_mouse_face (f);
f8d1a163 5750#endif
31d4844a 5751
4d7e6e51 5752 unblock_input ();
ee78dc32
GV
5753}
5754\f
5755/* Mouse warping. */
5756
ec48c3a7
JR
5757void x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y);
5758
5759void
b56ceb92 5760x_set_mouse_position (struct frame *f, int x, int y)
ec48c3a7
JR
5761{
5762 int pix_x, pix_y;
5763
62e50ec6
KS
5764 pix_x = FRAME_COL_TO_PIXEL_X (f, x) + FRAME_COLUMN_WIDTH (f) / 2;
5765 pix_y = FRAME_LINE_TO_PIXEL_Y (f, y) + FRAME_LINE_HEIGHT (f) / 2;
ec48c3a7
JR
5766
5767 if (pix_x < 0) pix_x = 0;
62e50ec6 5768 if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
ec48c3a7
JR
5769
5770 if (pix_y < 0) pix_y = 0;
62e50ec6 5771 if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
ec48c3a7
JR
5772
5773 x_set_mouse_pixel_position (f, pix_x, pix_y);
5774}
5775
1bcd16f2 5776void
b56ceb92 5777x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
1bcd16f2 5778{
689004fa
GV
5779 RECT rect;
5780 POINT pt;
5781
4d7e6e51 5782 block_input ();
1bcd16f2 5783
689004fa
GV
5784 GetClientRect (FRAME_W32_WINDOW (f), &rect);
5785 pt.x = rect.left + pix_x;
5786 pt.y = rect.top + pix_y;
5787 ClientToScreen (FRAME_W32_WINDOW (f), &pt);
1bcd16f2 5788
689004fa 5789 SetCursorPos (pt.x, pt.y);
1bcd16f2 5790
4d7e6e51 5791 unblock_input ();
1bcd16f2
MB
5792}
5793
ee78dc32
GV
5794\f
5795/* focus shifting, raising and lowering. */
5796
ec48c3a7 5797void
b56ceb92 5798x_focus_on_frame (struct frame *f)
ee78dc32 5799{
689004fa
GV
5800 struct w32_display_info *dpyinfo = &one_w32_display_info;
5801
5802 /* Give input focus to frame. */
4d7e6e51 5803 block_input ();
689004fa
GV
5804#if 0
5805 /* Try not to change its Z-order if possible. */
5806 if (x_window_to_frame (dpyinfo, GetForegroundWindow ()))
5807 my_set_focus (f, FRAME_W32_WINDOW (f));
5808 else
5809#endif
ef0e360f 5810 my_set_foreground_window (FRAME_W32_WINDOW (f));
4d7e6e51 5811 unblock_input ();
ee78dc32
GV
5812}
5813
ec48c3a7 5814void
b56ceb92 5815x_unfocus_frame (struct frame *f)
ee78dc32
GV
5816{
5817}
5818
5819/* Raise frame F. */
791f420f 5820void
b56ceb92 5821x_raise_frame (struct frame *f)
ee78dc32 5822{
4d7e6e51 5823 block_input ();
689004fa
GV
5824
5825 /* Strictly speaking, raise-frame should only change the frame's Z
fffa137c 5826 order, leaving input focus unchanged. This is reasonable behavior
689004fa 5827 on X where the usual policy is point-to-focus. However, this
fffa137c 5828 behavior would be very odd on Windows where the usual policy is
689004fa
GV
5829 click-to-focus.
5830
5831 On X, if the mouse happens to be over the raised frame, it gets
5832 input focus anyway (so the window with focus will never be
5833 completely obscured) - if not, then just moving the mouse over it
5834 is sufficient to give it focus. On Windows, the user must actually
e1dbe924 5835 click on the frame (preferably the title bar so as not to move
689004fa
GV
5836 point), which is more awkward. Also, no other Windows program
5837 raises a window to the top but leaves another window (possibly now
5838 completely obscured) with input focus.
5839
5840 Because there is a system setting on Windows that allows the user
5841 to choose the point to focus policy, we make the strict semantics
5842 optional, but by default we grab focus when raising. */
5843
5844 if (NILP (Vw32_grab_focus_on_raise))
ee78dc32 5845 {
689004fa
GV
5846 /* The obvious call to my_set_window_pos doesn't work if Emacs is
5847 not already the foreground application: the frame is raised
5848 above all other frames belonging to us, but not above the
5849 current top window. To achieve that, we have to resort to this
5850 more cumbersome method. */
5851
5852 HDWP handle = BeginDeferWindowPos (2);
5853 if (handle)
5854 {
85d0efd1
EZ
5855 handle = DeferWindowPos (handle,
5856 FRAME_W32_WINDOW (f),
5857 HWND_TOP,
5858 0, 0, 0, 0,
5859 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
5860 if (handle)
5861 {
5862 handle = DeferWindowPos (handle,
5863 GetForegroundWindow (),
5864 FRAME_W32_WINDOW (f),
5865 0, 0, 0, 0,
5866 SWP_NOSIZE | SWP_NOMOVE |
5867 SWP_NOACTIVATE);
5868 if (handle)
5869 EndDeferWindowPos (handle);
5870 }
689004fa 5871 }
ee78dc32 5872 }
689004fa
GV
5873 else
5874 {
85d0efd1 5875 my_bring_window_to_top (FRAME_W32_WINDOW (f));
689004fa
GV
5876 }
5877
4d7e6e51 5878 unblock_input ();
ee78dc32
GV
5879}
5880
5881/* Lower frame F. */
791f420f 5882void
b56ceb92 5883x_lower_frame (struct frame *f)
ee78dc32 5884{
4d7e6e51 5885 block_input ();
689004fa
GV
5886 my_set_window_pos (FRAME_W32_WINDOW (f),
5887 HWND_BOTTOM,
5888 0, 0, 0, 0,
5889 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
4d7e6e51 5890 unblock_input ();
ee78dc32
GV
5891}
5892
5893static void
b56ceb92 5894w32_frame_raise_lower (FRAME_PTR f, int raise_flag)
ee78dc32 5895{
7e6ac5b9
AI
5896 if (! FRAME_W32_P (f))
5897 return;
5898
ec48c3a7 5899 if (raise_flag)
ee78dc32
GV
5900 x_raise_frame (f);
5901 else
5902 x_lower_frame (f);
5903}
5904\f
5905/* Change of visibility. */
5906
5907/* This tries to wait until the frame is really visible.
5908 However, if the window manager asks the user where to position
5909 the frame, this will return before the user finishes doing that.
5910 The frame will not actually be visible at that time,
5911 but it will become visible later when the window manager
5912 finishes with it. */
5913
ec48c3a7 5914void
b56ceb92 5915x_make_frame_visible (struct frame *f)
ee78dc32 5916{
7f5d1df8
GV
5917 Lisp_Object type;
5918
4d7e6e51 5919 block_input ();
ee78dc32 5920
7f5d1df8
GV
5921 type = x_icon_type (f);
5922 if (!NILP (type))
5923 x_bitmap_icon (f, type);
5924
ee78dc32
GV
5925 if (! FRAME_VISIBLE_P (f))
5926 {
5927 /* We test FRAME_GARBAGED_P here to make sure we don't
5928 call x_set_offset a second time
5929 if we get to x_make_frame_visible a second time
5930 before the window gets really visible. */
5931 if (! FRAME_ICONIFIED_P (f)
fbd6baed 5932 && ! f->output_data.w32->asked_for_visible)
8958048c
EZ
5933 {
5934 RECT workarea_rect;
5935 RECT window_rect;
5936
5937 /* Adjust vertical window position in order to avoid being
5938 covered by a task bar placed at the bottom of the desktop. */
ed3751c8 5939 SystemParametersInfo (SPI_GETWORKAREA, 0, &workarea_rect, 0);
9d4f32e8 5940 GetWindowRect (FRAME_W32_WINDOW (f), &window_rect);
8958048c
EZ
5941 if (window_rect.bottom > workarea_rect.bottom
5942 && window_rect.top > workarea_rect.top)
5943 f->top_pos = max (window_rect.top
5944 - window_rect.bottom + workarea_rect.bottom,
5945 workarea_rect.top);
5946
5947 x_set_offset (f, f->left_pos, f->top_pos, 0);
5948 }
ee78dc32 5949
fbd6baed 5950 f->output_data.w32->asked_for_visible = 1;
52cf03a1 5951
22610910 5952 /* According to a report in emacs-devel 2008-06-03, SW_SHOWNORMAL
91af3942 5953 causes unexpected behavior when unminimizing frames that were
53964682 5954 previously maximized. But only SW_SHOWNORMAL works properly for
22610910
JR
5955 frames that were truely hidden (using make-frame-invisible), so
5956 we need it to avoid Bug#5482. It seems that async_iconified
53964682 5957 is only set for minimized windows that are still visible, so
22610910 5958 use that to determine the appropriate flag to pass ShowWindow. */
12f71857 5959 my_show_window (f, FRAME_W32_WINDOW (f),
22610910 5960 f->async_iconified ? SW_RESTORE : SW_SHOWNORMAL);
ee78dc32
GV
5961 }
5962
5963 /* Synchronize to ensure Emacs knows the frame is visible
5964 before we do anything else. We do this loop with input not blocked
5965 so that incoming events are handled. */
5966 {
5967 Lisp_Object frame;
791f420f 5968 int count;
ee78dc32
GV
5969
5970 /* This must come after we set COUNT. */
4d7e6e51 5971 unblock_input ();
ee78dc32
GV
5972
5973 XSETFRAME (frame, f);
5974
791f420f
JR
5975 /* Wait until the frame is visible. Process X events until a
5976 MapNotify event has been seen, or until we think we won't get a
5977 MapNotify at all.. */
5978 for (count = input_signal_count + 10;
5979 input_signal_count < count && !FRAME_VISIBLE_P (f);)
ee78dc32 5980 {
791f420f 5981 /* Force processing of queued events. */
01b220b6 5982 /* TODO: x_sync equivalent? */
791f420f 5983
ee78dc32
GV
5984 /* Machines that do polling rather than SIGIO have been observed
5985 to go into a busy-wait here. So we'll fake an alarm signal
5986 to let the handler know that there's something to be read.
5987 We used to raise a real alarm, but it seems that the handler
5988 isn't always enabled here. This is probably a bug. */
5989 if (input_polling_used ())
5990 {
5991 /* It could be confusing if a real alarm arrives while processing
5992 the fake one. Turn it off and let the handler reset it. */
a9b4e0ec
AI
5993 int old_poll_suppress_count = poll_suppress_count;
5994 poll_suppress_count = 1;
5995 poll_for_input_1 ();
5996 poll_suppress_count = old_poll_suppress_count;
ee78dc32 5997 }
ee78dc32
GV
5998 }
5999 FRAME_SAMPLE_VISIBILITY (f);
6000 }
6001}
6002
6003/* Change from mapped state to withdrawn state. */
6004
6005/* Make the frame visible (mapped and not iconified). */
6006
b56ceb92
JB
6007void
6008x_make_frame_invisible (struct frame *f)
ee78dc32 6009{
ee78dc32 6010 /* Don't keep the highlight on an invisible frame. */
4baaed0f
KS
6011 if (FRAME_W32_DISPLAY_INFO (f)->x_highlight_frame == f)
6012 FRAME_W32_DISPLAY_INFO (f)->x_highlight_frame = 0;
d67d1627 6013
4d7e6e51 6014 block_input ();
d67d1627 6015
689004fa 6016 my_show_window (f, FRAME_W32_WINDOW (f), SW_HIDE);
d67d1627 6017
ee78dc32
GV
6018 /* We can't distinguish this from iconification
6019 just by the event that we get from the server.
6020 So we can't win using the usual strategy of letting
6021 FRAME_SAMPLE_VISIBILITY set this. So do it by hand,
6022 and synchronize with the server to make sure we agree. */
6023 f->visible = 0;
6024 FRAME_ICONIFIED_P (f) = 0;
6025 f->async_visible = 0;
6026 f->async_iconified = 0;
d67d1627 6027
4d7e6e51 6028 unblock_input ();
ee78dc32
GV
6029}
6030
6031/* Change window state from mapped to iconified. */
6032
52cf03a1 6033void
b56ceb92 6034x_iconify_frame (struct frame *f)
ee78dc32 6035{
7f5d1df8 6036 Lisp_Object type;
ee78dc32
GV
6037
6038 /* Don't keep the highlight on an invisible frame. */
4baaed0f
KS
6039 if (FRAME_W32_DISPLAY_INFO (f)->x_highlight_frame == f)
6040 FRAME_W32_DISPLAY_INFO (f)->x_highlight_frame = 0;
ee78dc32
GV
6041
6042 if (f->async_iconified)
6043 return;
6044
4d7e6e51 6045 block_input ();
ee78dc32 6046
7f5d1df8
GV
6047 type = x_icon_type (f);
6048 if (!NILP (type))
6049 x_bitmap_icon (f, type);
6050
689004fa 6051 /* Simulate the user minimizing the frame. */
4934bcdd 6052 SendMessage (FRAME_W32_WINDOW (f), WM_SYSCOMMAND, SC_MINIMIZE, 0);
ee78dc32 6053
4d7e6e51 6054 unblock_input ();
ee78dc32 6055}
c2cc16fa 6056
ee78dc32 6057\f
25badd7a 6058/* Free X resources of frame F. */
ee78dc32 6059
25badd7a 6060void
7c3320d8 6061x_free_frame_resources (struct frame *f)
ee78dc32 6062{
fbd6baed 6063 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
bbf534ce 6064 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
ee78dc32 6065
4d7e6e51 6066 block_input ();
ee78dc32 6067
ef39ccbb
KH
6068 /* We must free faces before destroying windows because some
6069 font-driver (e.g. xft) access a window while finishing a
6070 face. */
6071 if (FRAME_FACE_CACHE (f))
6072 free_frame_faces (f);
027f6f90 6073
25badd7a
AI
6074 if (FRAME_W32_WINDOW (f))
6075 my_destroy_window (f, FRAME_W32_WINDOW (f));
d67d1627 6076
ee78dc32 6077 free_frame_menubar (f);
ee78dc32 6078
5bcee7ef
KL
6079 unload_color (f, FRAME_FOREGROUND_PIXEL (f));
6080 unload_color (f, FRAME_BACKGROUND_PIXEL (f));
25badd7a
AI
6081 unload_color (f, f->output_data.w32->cursor_pixel);
6082 unload_color (f, f->output_data.w32->cursor_foreground_pixel);
6083 unload_color (f, f->output_data.w32->border_pixel);
6084 unload_color (f, f->output_data.w32->mouse_pixel);
c2cc16fa
JR
6085 if (f->output_data.w32->white_relief.allocated_p)
6086 unload_color (f, f->output_data.w32->white_relief.pixel);
6087 if (f->output_data.w32->black_relief.allocated_p)
6088 unload_color (f, f->output_data.w32->black_relief.pixel);
6089
25badd7a
AI
6090 if (FRAME_FACE_CACHE (f))
6091 free_frame_faces (f);
d67d1627 6092
fbd6baed 6093 xfree (f->output_data.w32);
25badd7a 6094 f->output_data.w32 = NULL;
d67d1627 6095
fbd6baed
GV
6096 if (f == dpyinfo->w32_focus_frame)
6097 dpyinfo->w32_focus_frame = 0;
6098 if (f == dpyinfo->w32_focus_event_frame)
6099 dpyinfo->w32_focus_event_frame = 0;
4baaed0f
KS
6100 if (f == dpyinfo->x_highlight_frame)
6101 dpyinfo->x_highlight_frame = 0;
ee78dc32 6102
bbf534ce 6103 if (f == hlinfo->mouse_face_mouse_frame)
ee78dc32 6104 {
bbf534ce
EZ
6105 hlinfo->mouse_face_beg_row
6106 = hlinfo->mouse_face_beg_col = -1;
6107 hlinfo->mouse_face_end_row
6108 = hlinfo->mouse_face_end_col = -1;
6109 hlinfo->mouse_face_window = Qnil;
6110 hlinfo->mouse_face_deferred_gc = 0;
6111 hlinfo->mouse_face_mouse_frame = 0;
ee78dc32
GV
6112 }
6113
4d7e6e51 6114 unblock_input ();
ee78dc32 6115}
25badd7a
AI
6116
6117
6118/* Destroy the window of frame F. */
4a418b10 6119void
b56ceb92 6120x_destroy_window (struct frame *f)
25badd7a
AI
6121{
6122 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
6123
6124 x_free_frame_resources (f);
25badd7a
AI
6125 dpyinfo->reference_count--;
6126}
c2cc16fa 6127
ee78dc32
GV
6128\f
6129/* Setting window manager hints. */
6130
6131/* Set the normal size hints for the window manager, for frame F.
6132 FLAGS is the flags word to use--or 0 meaning preserve the flags
6133 that the window now has.
18e27ea8 6134 If USER_POSITION, set the USPosition
ee78dc32 6135 flag (this is useful when FLAGS is 0). */
791f420f 6136void
18e27ea8 6137x_wm_set_size_hint (struct frame *f, long flags, bool user_position)
ee78dc32 6138{
fbd6baed 6139 Window window = FRAME_W32_WINDOW (f);
ee78dc32 6140
97c23857 6141 enter_crit ();
ee78dc32 6142
62e50ec6
KS
6143 SetWindowLong (window, WND_FONTWIDTH_INDEX, FRAME_COLUMN_WIDTH (f));
6144 SetWindowLong (window, WND_LINEHEIGHT_INDEX, FRAME_LINE_HEIGHT (f));
6145 SetWindowLong (window, WND_BORDER_INDEX, FRAME_INTERNAL_BORDER_WIDTH (f));
6146 SetWindowLong (window, WND_SCROLLBAR_INDEX, f->scroll_bar_actual_width);
ee78dc32 6147
97c23857 6148 leave_crit ();
ee78dc32
GV
6149}
6150
6151/* Window manager things */
c65fd370 6152void
b56ceb92 6153x_wm_set_icon_position (struct frame *f, int icon_x, int icon_y)
ee78dc32
GV
6154{
6155#if 0
fbd6baed 6156 Window window = FRAME_W32_WINDOW (f);
ee78dc32
GV
6157
6158 f->display.x->wm_hints.flags |= IconPositionHint;
6159 f->display.x->wm_hints.icon_x = icon_x;
6160 f->display.x->wm_hints.icon_y = icon_y;
6161
6162 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->display.x->wm_hints);
6163#endif
6164}
6165
c2cc16fa 6166\f
784b56e2
EZ
6167/***********************************************************************
6168 Fonts
6169 ***********************************************************************/
6170
e509cfa6 6171#ifdef GLYPH_DEBUG
784b56e2
EZ
6172
6173/* Check that FONT is valid on frame F. It is if it can be found in F's
6174 font table. */
6175
6176static void
6177x_check_font (struct frame *f, struct font *font)
6178{
a54e2c05 6179 eassert (font != NULL && ! NILP (font->props[FONT_TYPE_INDEX]));
784b56e2 6180 if (font->driver->check)
a54e2c05 6181 eassert (font->driver->check (f, font) == 0);
784b56e2
EZ
6182}
6183
e509cfa6 6184#endif /* GLYPH_DEBUG */
784b56e2
EZ
6185
6186
6187\f
791f420f
JR
6188/***********************************************************************
6189 Initialization
6190 ***********************************************************************/
ee78dc32 6191
fbd6baed 6192static int w32_initialized = 0;
ee78dc32 6193
f7737f5d 6194void
b56ceb92 6195w32_initialize_display_info (Lisp_Object display_name)
f7737f5d
JR
6196{
6197 struct w32_display_info *dpyinfo = &one_w32_display_info;
bbf534ce 6198 Mouse_HLInfo *hlinfo = &dpyinfo->mouse_highlight;
f7737f5d 6199
72af86bd 6200 memset (dpyinfo, 0, sizeof (*dpyinfo));
f7737f5d
JR
6201
6202 /* Put it on w32_display_name_list. */
6203 w32_display_name_list = Fcons (Fcons (display_name, Qnil),
6204 w32_display_name_list);
6205 dpyinfo->name_list_element = XCAR (w32_display_name_list);
d67d1627 6206
23f86fce
DA
6207 dpyinfo->w32_id_name = xmalloc (SCHARS (Vinvocation_name)
6208 + SCHARS (Vsystem_name) + 2);
f7737f5d 6209 sprintf (dpyinfo->w32_id_name, "%s@%s",
d5db4077 6210 SDATA (Vinvocation_name), SDATA (Vsystem_name));
f7737f5d
JR
6211
6212 /* Default Console mode values - overridden when running in GUI mode
6213 with values obtained from system metrics. */
6214 dpyinfo->resx = 1;
6215 dpyinfo->resy = 1;
f7737f5d
JR
6216 dpyinfo->n_planes = 1;
6217 dpyinfo->n_cbits = 4;
6218 dpyinfo->n_fonts = 0;
6219 dpyinfo->smallest_font_height = 1;
6220 dpyinfo->smallest_char_width = 1;
6221
bbf534ce
EZ
6222 hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
6223 hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
6224 hlinfo->mouse_face_face_id = DEFAULT_FACE_ID;
6225 hlinfo->mouse_face_window = Qnil;
6226 hlinfo->mouse_face_overlay = Qnil;
6227 hlinfo->mouse_face_hidden = 0;
2bf04b9d
JR
6228
6229 dpyinfo->vertical_scroll_bar_cursor = w32_load_cursor (IDC_ARROW);
01b220b6 6230 /* TODO: dpyinfo->gray */
f7737f5d
JR
6231
6232}
6233
0105dc3e 6234/* Create an xrdb-style database of resources to supersede registry settings.
c13a8a91 6235 The database is just a concatenation of C strings, finished by an additional
decb374a 6236 \0. The strings are submitted to some basic normalization, so
c13a8a91
JB
6237
6238 [ *]option[ *]:[ *]value...
6239
6240 becomes
6241
6242 option:value...
6243
6244 but any whitespace following value is not removed. */
6245
6246static char *
b56ceb92 6247w32_make_rdb (char *xrm_option)
c13a8a91
JB
6248{
6249 char *buffer = xmalloc (strlen (xrm_option) + 2);
6250 char *current = buffer;
6251 char ch;
6252 int in_option = 1;
6253 int before_value = 0;
6254
6255 do {
6256 ch = *xrm_option++;
6257
6258 if (ch == '\n')
6259 {
6260 *current++ = '\0';
6261 in_option = 1;
6262 before_value = 0;
6263 }
6264 else if (ch != ' ')
6265 {
6266 *current++ = ch;
6267 if (in_option && (ch == ':'))
6268 {
6269 in_option = 0;
6270 before_value = 1;
6271 }
6272 else if (before_value)
6273 {
6274 before_value = 0;
6275 }
6276 }
6277 else if (!(in_option || before_value))
6278 {
6279 *current++ = ch;
6280 }
6281 } while (ch);
6282
6283 *current = '\0';
6284
6285 return buffer;
6286}
6287
4a418b10
JR
6288void
6289x_flush (struct frame * f)
6290{ /* Nothing to do */ }
6291
6292
6293extern frame_parm_handler w32_frame_parm_handlers[];
6294
6295static struct redisplay_interface w32_redisplay_interface =
6296{
6297 w32_frame_parm_handlers,
6298 x_produce_glyphs,
6299 x_write_glyphs,
6300 x_insert_glyphs,
6301 x_clear_end_of_line,
6302 x_scroll_run,
6303 x_after_update_window_line,
6304 x_update_window_begin,
6305 x_update_window_end,
6306 x_cursor_to,
6307 x_flush,
6308 0, /* flush_display_optional */
6309 x_clear_window_mouse_face,
e5e29349 6310 x_get_glyph_overhangs,
4a418b10
JR
6311 x_fix_overlapping_area,
6312 w32_draw_fringe_bitmap,
6313 w32_define_fringe_bitmap,
6314 w32_destroy_fringe_bitmap,
cf907d69 6315 w32_compute_glyph_string_overhangs,
4a418b10
JR
6316 x_draw_glyph_string,
6317 w32_define_frame_cursor,
6318 w32_clear_frame_area,
6319 w32_draw_window_cursor,
6320 w32_draw_vertical_window_border,
6321 w32_shift_glyphs_for_insert
6322};
6323
6324static void x_delete_terminal (struct terminal *term);
6325
6326static struct terminal *
6327w32_create_terminal (struct w32_display_info *dpyinfo)
6328{
6329 struct terminal *terminal;
def7fa34 6330
4a418b10
JR
6331 terminal = create_terminal ();
6332
6333 terminal->type = output_w32;
6334 terminal->display_info.w32 = dpyinfo;
6335 dpyinfo->terminal = terminal;
6336
6337 /* MSVC does not type K&R functions with no arguments correctly, and
6338 so we must explicitly cast them. */
6339 terminal->clear_frame_hook = x_clear_frame;
6340 terminal->ins_del_lines_hook = x_ins_del_lines;
6341 terminal->delete_glyphs_hook = x_delete_glyphs;
6342 terminal->ring_bell_hook = w32_ring_bell;
6343 terminal->reset_terminal_modes_hook = w32_reset_terminal_modes;
6344 terminal->set_terminal_modes_hook = w32_set_terminal_modes;
6345 terminal->update_begin_hook = x_update_begin;
6346 terminal->update_end_hook = x_update_end;
6347 terminal->set_terminal_window_hook = w32_set_terminal_window;
6348 terminal->read_socket_hook = w32_read_socket;
6349 terminal->frame_up_to_date_hook = w32_frame_up_to_date;
6350 terminal->mouse_position_hook = w32_mouse_position;
6351 terminal->frame_rehighlight_hook = w32_frame_rehighlight;
6352 terminal->frame_raise_lower_hook = w32_frame_raise_lower;
7684e57b 6353 /* terminal->fullscreen_hook = XTfullscreen_hook; */
4a418b10
JR
6354 terminal->set_vertical_scroll_bar_hook = w32_set_vertical_scroll_bar;
6355 terminal->condemn_scroll_bars_hook = w32_condemn_scroll_bars;
6356 terminal->redeem_scroll_bar_hook = w32_redeem_scroll_bar;
6357 terminal->judge_scroll_bars_hook = w32_judge_scroll_bars;
6358
6359 terminal->delete_frame_hook = x_destroy_window;
6360 terminal->delete_terminal_hook = x_delete_terminal;
def7fa34 6361
4a418b10
JR
6362 terminal->rif = &w32_redisplay_interface;
6363 terminal->scroll_region_ok = 1; /* We'll scroll partial frames. */
6364 terminal->char_ins_del_ok = 1;
6365 terminal->line_ins_del_ok = 1; /* We'll just blt 'em. */
6366 terminal->fast_clear_end_of_line = 1; /* X does this well. */
6367 terminal->memory_below_frame = 0; /* We don't remember what scrolls
6368 off the bottom. */
6369
1526bc23
JR
6370 /* We don't yet support separate terminals on W32, so don't try to share
6371 keyboards between virtual terminals that are on the same physical
6372 terminal like X does. */
23f86fce 6373 terminal->kboard = xmalloc (sizeof (KBOARD));
1526bc23 6374 init_kboard (terminal->kboard);
15dbb4d6 6375 kset_window_system (terminal->kboard, intern ("w32"));
1526bc23
JR
6376 terminal->kboard->next_kboard = all_kboards;
6377 all_kboards = terminal->kboard;
6378 /* Don't let the initial kboard remain current longer than necessary.
6379 That would cause problems if a file loaded on startup tries to
6380 prompt in the mini-buffer. */
6381 if (current_kboard == initial_kboard)
6382 current_kboard = terminal->kboard;
6383 terminal->kboard->reference_count++;
1526bc23 6384
4a418b10
JR
6385 return terminal;
6386}
6387
6388static void
6389x_delete_terminal (struct terminal *terminal)
6390{
6391 struct w32_display_info *dpyinfo = terminal->display_info.w32;
4a418b10 6392
e2749141 6393 /* Protect against recursive calls. delete_frame in
4a418b10 6394 delete_terminal calls us back when it deletes our last frame. */
adc54316 6395 if (!terminal->name)
4a418b10
JR
6396 return;
6397
4d7e6e51 6398 block_input ();
4a418b10
JR
6399
6400 x_delete_display (dpyinfo);
4d7e6e51 6401 unblock_input ();
4a418b10
JR
6402}
6403
fbd6baed 6404struct w32_display_info *
b56ceb92 6405w32_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
ee78dc32 6406{
fbd6baed 6407 struct w32_display_info *dpyinfo;
4a418b10 6408 struct terminal *terminal;
ee78dc32 6409 HDC hdc;
d67d1627 6410
4d7e6e51 6411 block_input ();
d67d1627 6412
fbd6baed 6413 if (!w32_initialized)
ee78dc32 6414 {
fbd6baed
GV
6415 w32_initialize ();
6416 w32_initialized = 1;
ee78dc32 6417 }
d67d1627 6418
f7737f5d 6419 w32_initialize_display_info (display_name);
ee78dc32 6420
f7737f5d 6421 dpyinfo = &one_w32_display_info;
4a418b10
JR
6422 terminal = w32_create_terminal (dpyinfo);
6423
6424 /* Set the name of the terminal. */
23f86fce 6425 terminal->name = xmalloc (SBYTES (display_name) + 1);
4a418b10
JR
6426 strncpy (terminal->name, SDATA (display_name), SBYTES (display_name));
6427 terminal->name[SBYTES (display_name)] = 0;
8c3b00cb 6428
c13a8a91
JB
6429 dpyinfo->xrdb = xrm_option ? w32_make_rdb (xrm_option) : NULL;
6430
8c3b00cb
AI
6431 /* Put this display on the chain. */
6432 dpyinfo->next = x_display_list;
6433 x_display_list = dpyinfo;
d67d1627 6434
cb4a3e42 6435 hdc = GetDC (NULL);
791f420f 6436
ee78dc32
GV
6437 dpyinfo->root_window = GetDesktopWindow ();
6438 dpyinfo->n_planes = GetDeviceCaps (hdc, PLANES);
6439 dpyinfo->n_cbits = GetDeviceCaps (hdc, BITSPIXEL);
55689ab1
JR
6440 dpyinfo->resx = GetDeviceCaps (hdc, LOGPIXELSX);
6441 dpyinfo->resy = GetDeviceCaps (hdc, LOGPIXELSY);
52cf03a1 6442 dpyinfo->has_palette = GetDeviceCaps (hdc, RASTERCAPS) & RC_PALETTE;
cb4a3e42 6443 ReleaseDC (NULL, hdc);
52cf03a1 6444
e1dbe924 6445 /* initialize palette with white and black */
52cf03a1 6446 {
316ed821 6447 XColor color;
55689ab1
JR
6448 w32_defined_color (0, "white", &color, 1);
6449 w32_defined_color (0, "black", &color, 1);
52cf03a1
GV
6450 }
6451
0fda9b75
DC
6452#ifdef WINDOWSNT
6453 /* Add the default keyboard. When !WINDOWSNT, we're using the
6454 standard Emacs console handling machinery and don't need an
6455 explicit FD here. */
543c3ccd 6456 add_keyboard_wait_descriptor (0);
0fda9b75
DC
6457#elif CYGWIN
6458 /* /dev/windows wakes us up when we have a thread message pending. */
6459 add_keyboard_wait_descriptor (w32_message_fd);
6460#endif
543c3ccd 6461
b6ae1532
KS
6462 /* Create Fringe Bitmaps and store them for later use.
6463
6464 On W32, bitmaps are all unsigned short, as Windows requires
6465 bitmap data to be Word aligned. For some reason they are
6466 horizontally reflected compared to how they appear on X, so we
6467 need to bitswap and convert to unsigned shorts before creating
6468 the bitmaps. */
09b69f01 6469 w32_init_fringe (terminal->rif);
f7737f5d 6470
4d7e6e51 6471 unblock_input ();
ee78dc32
GV
6472
6473 return dpyinfo;
6474}
6475\f
6476/* Get rid of display DPYINFO, assuming all frames are already gone. */
ee78dc32 6477void
b56ceb92 6478x_delete_display (struct w32_display_info *dpyinfo)
ee78dc32 6479{
fbd6baed 6480 /* Discard this display from w32_display_name_list and w32_display_list.
ee78dc32 6481 We can't use Fdelq because that can quit. */
fbd6baed 6482 if (! NILP (w32_display_name_list)
8e713be6
KR
6483 && EQ (XCAR (w32_display_name_list), dpyinfo->name_list_element))
6484 w32_display_name_list = XCDR (w32_display_name_list);
ee78dc32
GV
6485 else
6486 {
6487 Lisp_Object tail;
6488
fbd6baed 6489 tail = w32_display_name_list;
8e713be6 6490 while (CONSP (tail) && CONSP (XCDR (tail)))
ee78dc32 6491 {
f7737f5d 6492 if (EQ (XCAR (XCDR (tail)), dpyinfo->name_list_element))
ee78dc32 6493 {
f3fbd155 6494 XSETCDR (tail, XCDR (XCDR (tail)));
ee78dc32
GV
6495 break;
6496 }
8e713be6 6497 tail = XCDR (tail);
ee78dc32
GV
6498 }
6499 }
6500
52cf03a1
GV
6501 /* free palette table */
6502 {
fbd6baed 6503 struct w32_palette_entry * plist;
52cf03a1
GV
6504
6505 plist = dpyinfo->color_list;
6506 while (plist)
6507 {
fbd6baed 6508 struct w32_palette_entry * pentry = plist;
52cf03a1 6509 plist = plist->next;
9127e20e 6510 xfree (pentry);
52cf03a1
GV
6511 }
6512 dpyinfo->color_list = NULL;
6513 if (dpyinfo->palette)
ed3751c8 6514 DeleteObject (dpyinfo->palette);
52cf03a1 6515 }
fbd6baed 6516 xfree (dpyinfo->w32_id_name);
f7737f5d 6517
6b61353c 6518 w32_reset_fringes ();
ee78dc32 6519}
0fda9b75 6520
ee78dc32 6521\f
fbd6baed 6522/* Set up use of W32. */
ee78dc32 6523
b0d4e0c7 6524DWORD WINAPI w32_msg_worker (void * arg);
ee78dc32 6525
1bb8a291 6526static void
b56ceb92 6527w32_initialize (void)
fbd6baed 6528{
ff90fbde 6529 HANDLE shell;
0a3472c7 6530 HRESULT (WINAPI * set_user_model) (wchar_t * id);
ff90fbde 6531
ee78dc32
GV
6532 baud_rate = 19200;
6533
abb15ebd
JR
6534 w32_system_caret_hwnd = NULL;
6535 w32_system_caret_height = 0;
abb15ebd
JR
6536 w32_system_caret_x = 0;
6537 w32_system_caret_y = 0;
6538
ff90fbde
JR
6539 /* On Windows 7 and later, we need to set the user model ID
6540 to associate emacsclient launched files with Emacs frames
6541 in the UI. */
6542 shell = GetModuleHandle ("shell32.dll");
6543 if (shell)
6544 {
6545 set_user_model
6546 = (void *) GetProcAddress (shell,
6547 "SetCurrentProcessExplicitAppUserModelID");
6548
6549 /* If the function is defined, then we are running on Windows 7
6550 or newer, and the UI uses this to group related windows
6551 together. Since emacs, runemacs, emacsclient are related, we
6552 want them grouped even though the executables are different,
6553 so we need to set a consistent ID between them. */
6554 if (set_user_model)
6555 set_user_model (L"GNU.Emacs");
6556 }
6557
0fda9b75
DC
6558#ifdef CYGWIN
6559 if ((w32_message_fd = open ("/dev/windows", O_RDWR | O_CLOEXEC)) == -1)
6560 fatal ("opening /dev/windows: %s", strerror (errno));
6561#endif /* CYGWIN */
6562
c2baa2b6
JR
6563 /* Initialize w32_use_visible_system_caret based on whether a screen
6564 reader is in use. */
6565 if (!SystemParametersInfo (SPI_GETSCREENREADER, 0,
6566 &w32_use_visible_system_caret, 0))
6567 w32_use_visible_system_caret = 0;
6568
791f420f
JR
6569 last_tool_bar_item = -1;
6570 any_help_event_p = 0;
6571
689004fa
GV
6572 /* Initialize input mode: interrupt_input off, no flow control, allow
6573 8 bit character input, standard quit char. */
6574 Fset_input_mode (Qnil, Qnil, make_number (2), Qnil);
ee78dc32 6575
13087e59 6576 {
46534e1e 6577 DWORD input_locale_id = (DWORD) GetKeyboardLayout (0);
302fc036
EZ
6578 w32_keyboard_codepage =
6579 codepage_for_locale ((LCID) (input_locale_id & 0xffff));
13087e59 6580 }
ee78dc32 6581
13087e59
JR
6582 /* Create the window thread - it will terminate itself when the app
6583 terminates */
ee78dc32
GV
6584 init_crit ();
6585
6586 dwMainThreadId = GetCurrentThreadId ();
d67d1627 6587 DuplicateHandle (GetCurrentProcess (), GetCurrentThread (),
ee78dc32
GV
6588 GetCurrentProcess (), &hMainThread, 0, TRUE, DUPLICATE_SAME_ACCESS);
6589
6590 /* Wait for thread to start */
ee78dc32
GV
6591 {
6592 MSG msg;
6593
6594 PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
6595
d67d1627 6596 hWindowsThread = CreateThread (NULL, 0,
b0d4e0c7
JR
6597 w32_msg_worker,
6598 0, 0, &dwWindowsThreadId);
ee78dc32
GV
6599
6600 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
6601 }
d67d1627 6602
52cf03a1 6603 /* It is desirable that mainThread should have the same notion of
e9e23e23 6604 focus window and active window as windowsThread. Unfortunately, the
52cf03a1
GV
6605 following call to AttachThreadInput, which should do precisely what
6606 we need, causes major problems when Emacs is linked as a console
6607 program. Unfortunately, we have good reasons for doing that, so
e9e23e23 6608 instead we need to send messages to windowsThread to make some API
52cf03a1 6609 calls for us (ones that affect, or depend on, the active/focus
65a6ff8f 6610 window state.) */
52cf03a1 6611#ifdef ATTACH_THREADS
e9e23e23 6612 AttachThreadInput (dwMainThreadId, dwWindowsThreadId, TRUE);
52cf03a1 6613#endif
689004fa 6614
33e40ce7 6615 /* Dynamically link to optional system components. */
689004fa 6616 {
ff90fbde 6617 HMODULE user_lib = GetModuleHandle ("user32.dll");
689004fa 6618
41375f89 6619#define LOAD_PROC(lib, fn) pfn##fn = (void *) GetProcAddress (lib, #fn)
689004fa 6620
8b61a891 6621 LOAD_PROC (user_lib, SetLayeredWindowAttributes);
65a6ff8f 6622
689004fa
GV
6623#undef LOAD_PROC
6624
33e40ce7
JR
6625 /* Ensure scrollbar handle is at least 5 pixels. */
6626 vertical_scroll_bar_min_handle = 5;
689004fa
GV
6627
6628 /* For either kind of scroll bar, take account of the arrows; these
6629 effectively form the border of the main scroll bar range. */
6630 vertical_scroll_bar_top_border = vertical_scroll_bar_bottom_border
6631 = GetSystemMetrics (SM_CYVSCROLL);
6632 }
ee78dc32
GV
6633}
6634
6635void
b56ceb92 6636syms_of_w32term (void)
ee78dc32 6637{
fbd6baed
GV
6638 staticpro (&w32_display_name_list);
6639 w32_display_name_list = Qnil;
ee78dc32
GV
6640
6641 staticpro (&last_mouse_scroll_bar);
6642 last_mouse_scroll_bar = Qnil;
6643
5f33dbf7 6644 DEFSYM (Qvendor_specific_keysyms, "vendor-specific-keysyms");
52cf03a1 6645
477f1e50
EZ
6646 DEFSYM (Qadded, "added");
6647 DEFSYM (Qremoved, "removed");
6648 DEFSYM (Qmodified, "modified");
6649 DEFSYM (Qrenamed_from, "renamed-from");
6650 DEFSYM (Qrenamed_to, "renamed-to");
6651
fbd6baed 6652 DEFVAR_INT ("w32-num-mouse-buttons",
29208e82 6653 w32_num_mouse_buttons,
33f09670 6654 doc: /* Number of physical mouse buttons. */);
e597eb7d 6655 w32_num_mouse_buttons = 2;
52cf03a1 6656
fbd6baed 6657 DEFVAR_LISP ("w32-swap-mouse-buttons",
29208e82 6658 Vw32_swap_mouse_buttons,
33f09670
JR
6659 doc: /* Swap the mapping of middle and right mouse buttons.
6660When nil, middle button is mouse-2 and right button is mouse-3. */);
fbd6baed 6661 Vw32_swap_mouse_buttons = Qnil;
689004fa
GV
6662
6663 DEFVAR_LISP ("w32-grab-focus-on-raise",
29208e82 6664 Vw32_grab_focus_on_raise,
33f09670
JR
6665 doc: /* Raised frame grabs input focus.
6666When t, `raise-frame' grabs input focus as well. This fits well
6667with the normal Windows click-to-focus policy, but might not be
6668desirable when using a point-to-focus policy. */);
689004fa
GV
6669 Vw32_grab_focus_on_raise = Qt;
6670
6671 DEFVAR_LISP ("w32-capslock-is-shiftlock",
29208e82 6672 Vw32_capslock_is_shiftlock,
33f09670
JR
6673 doc: /* Apply CapsLock state to non character input keys.
6674When nil, CapsLock only affects normal character input keys. */);
689004fa 6675 Vw32_capslock_is_shiftlock = Qnil;
ef0e360f
GV
6676
6677 DEFVAR_LISP ("w32-recognize-altgr",
29208e82 6678 Vw32_recognize_altgr,
33f09670
JR
6679 doc: /* Recognize right-alt and left-ctrl as AltGr.
6680When nil, the right-alt and left-ctrl key combination is
d67d1627 6681interpreted normally. */);
ef0e360f 6682 Vw32_recognize_altgr = Qt;
bc6af935 6683
99558ce8 6684 DEFVAR_BOOL ("w32-use-visible-system-caret",
29208e82 6685 w32_use_visible_system_caret,
99558ce8
JR
6686 doc: /* Flag to make the system caret visible.
6687When this is non-nil, Emacs will indicate the position of point by
6688using the system caret instead of drawing its own cursor. Some screen
6689reader software does not track the system cursor properly when it is
6690invisible, and gets confused by Emacs drawing its own cursor, so this
d67d1627 6691variable is initialized to t when Emacs detects that screen reader
99558ce8
JR
6692software is running as it starts up.
6693
6694When this variable is set, other variables affecting the appearance of
6695the cursor have no effect. */);
6696
c2baa2b6 6697 w32_use_visible_system_caret = 0;
99558ce8 6698
099b6577
EZ
6699 /* We don't yet support this, but defining this here avoids whining
6700 from cus-start.el and other places, like "M-x set-variable". */
6701 DEFVAR_BOOL ("x-use-underline-position-properties",
29208e82 6702 x_use_underline_position_properties,
fb7ada5f 6703 doc: /* Non-nil means make use of UNDERLINE_POSITION font properties.
e1e4b63b 6704A value of nil means ignore them. If you encounter fonts with bogus
099b6577 6705UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
ea883883
GM
6706to 4.1, set this to nil. You can also use `underline-minimum-offset'
6707to override the font's UNDERLINE_POSITION for small font display
6708sizes. */);
099b6577
EZ
6709 x_use_underline_position_properties = 0;
6710
30f27523 6711 DEFVAR_BOOL ("x-underline-at-descent-line",
29208e82 6712 x_underline_at_descent_line,
fb7ada5f 6713 doc: /* Non-nil means to draw the underline at the same place as the descent line.
e1e4b63b
JB
6714A value of nil means to draw the underline according to the value of the
6715variable `x-use-underline-position-properties', which is usually at the
6716baseline level. The default value is nil. */);
30f27523
KS
6717 x_underline_at_descent_line = 0;
6718
29208e82 6719 DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
65807d73
GM
6720 doc: /* Which toolkit scroll bars Emacs uses, if any.
6721A value of nil means Emacs doesn't use toolkit scroll bars.
6722With the X Window system, the value is a symbol describing the
6723X toolkit. Possible values are: gtk, motif, xaw, or xaw3d.
44f92739 6724With MS Windows or Nextstep, the value is t. */);
5bf04520 6725 Vx_toolkit_scroll_bars = Qt;
791f420f
JR
6726
6727 staticpro (&last_mouse_motion_frame);
6728 last_mouse_motion_frame = Qnil;
0fda9b75
DC
6729
6730 Fprovide (intern_c_string ("w32"), Qnil);
ee78dc32 6731}