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