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