; doc/emacs/misc.texi (Network Security): Fix typo.
[emacs.git] / src / w32term.c
blobff0d2bf5ddb11f869b0e00f2df596688bc82d4f2
1 /* Implementation of GUI terminal on the Microsoft Windows API.
3 Copyright (C) 1989, 1993-2018 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or (at
10 your option) any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
20 #include <config.h>
21 #include <signal.h>
22 #include <stdio.h>
23 #include "lisp.h"
24 #include "blockinput.h"
25 #include "w32term.h"
26 #include "w32common.h" /* for OS version info */
28 #include <ctype.h>
29 #include <errno.h>
30 #include <sys/stat.h>
31 #ifdef CYGWIN
32 #include <fcntl.h> /* for O_RDWR */
33 #endif
34 #include <imm.h>
35 #include <math.h>
37 #include "coding.h"
38 #include "frame.h"
39 #include "fontset.h"
40 #include "termhooks.h"
41 #include "termopts.h"
42 #include "termchar.h"
43 #include "buffer.h"
44 #include "window.h"
45 #include "keyboard.h"
46 #include "menu.h" /* for w32_menu_show */
48 #ifdef WINDOWSNT
49 #include "w32.h" /* for filename_from_utf16, filename_from_ansi */
50 #endif
52 #ifndef WINDOWSNT
53 #include <io.h> /* for get_osfhandle */
54 #endif
56 #include <shellapi.h>
58 #include "font.h"
59 #include "w32font.h"
61 #if 0 /* TODO: stipple */
62 #include "bitmaps/gray.xbm"
63 #endif
65 /* Fringe bitmaps. */
67 static int max_fringe_bmp = 0;
68 static HBITMAP *fringe_bmp = 0;
70 /* Temporary variables for w32_read_socket. */
72 static int last_mousemove_x = 0;
73 static int last_mousemove_y = 0;
75 /* Define GET_WHEEL_DELTA_WPARAM macro if system headers don't. */
76 #ifndef GET_WHEEL_DELTA_WPARAM
77 #define GET_WHEEL_DELTA_WPARAM(wparam) ((short)HIWORD (wparam))
78 #endif
80 /* Non-zero means that a HELP_EVENT has been generated since Emacs
81 start. */
83 static int any_help_event_p;
85 extern unsigned int msh_mousewheel;
87 extern int w32_codepage_for_font (char *fontname);
88 extern Cursor w32_load_cursor (LPCTSTR name);
90 #define x_any_window_to_frame x_window_to_frame
91 #define x_top_window_to_frame x_window_to_frame
94 /* This is display since w32 does not support multiple ones. */
95 struct w32_display_info one_w32_display_info;
96 struct w32_display_info *x_display_list;
98 #if _WIN32_WINNT < 0x0500 && !defined(MINGW_W64)
99 /* Pre Windows 2000, this was not available, but define it here so
100 that Emacs compiled on such a platform will run on newer versions.
101 MinGW64 defines these unconditionally, so avoid redefining. */
103 typedef struct tagWCRANGE
105 WCHAR wcLow;
106 USHORT cGlyphs;
107 } WCRANGE;
109 typedef struct tagGLYPHSET
111 DWORD cbThis;
112 DWORD flAccel;
113 DWORD cGlyphsSupported;
114 DWORD cRanges;
115 WCRANGE ranges[1];
116 } GLYPHSET;
118 #endif /* compiling for pre-Win2k */
120 /* Dynamic linking to SetLayeredWindowAttribute (only since 2000). */
121 BOOL (WINAPI *pfnSetLayeredWindowAttributes) (HWND, COLORREF, BYTE, DWORD);
123 #ifndef LWA_ALPHA
124 #define LWA_ALPHA 0x02
125 #endif
126 /* WS_EX_LAYERED is defined unconditionally by MingW, but only for W2K and
127 later targets by MSVC headers. */
128 #ifndef WS_EX_LAYERED
129 #define WS_EX_LAYERED 0x80000
130 #endif
132 /* SM_CXVIRTUALSCREEN and SM_CYVIRTUALSCREEN are not defined on 95 and
133 NT4. */
134 #ifndef SM_CXVIRTUALSCREEN
135 #define SM_CXVIRTUALSCREEN 78
136 #endif
137 #ifndef SM_CYVIRTUALSCREEN
138 #define SM_CYVIRTUALSCREEN 79
139 #endif
141 /* The handle of the frame that currently owns the system caret. */
142 HWND w32_system_caret_hwnd;
143 int w32_system_caret_height;
144 int w32_system_caret_x;
145 int w32_system_caret_y;
146 struct window *w32_system_caret_window;
147 int w32_system_caret_hdr_height;
148 int w32_system_caret_mode_height;
149 DWORD dwWindowsThreadId = 0;
150 HANDLE hWindowsThread = NULL;
151 DWORD dwMainThreadId = 0;
152 HANDLE hMainThread = NULL;
154 int vertical_scroll_bar_min_handle;
155 int horizontal_scroll_bar_min_handle;
156 int vertical_scroll_bar_top_border;
157 int vertical_scroll_bar_bottom_border;
158 int horizontal_scroll_bar_left_border;
159 int horizontal_scroll_bar_right_border;
161 int last_scroll_bar_drag_pos;
163 /* Keyboard code page - may be changed by language-change events. */
164 int w32_keyboard_codepage;
166 #ifdef CYGWIN
167 int w32_message_fd = -1;
168 #endif /* CYGWIN */
170 static void w32_handle_tool_bar_click (struct frame *,
171 struct input_event *);
172 static void w32_define_cursor (Window, Cursor);
174 void x_lower_frame (struct frame *);
175 void x_scroll_bar_clear (struct frame *);
176 void x_raise_frame (struct frame *);
177 void x_wm_set_window_state (struct frame *, int);
178 void x_wm_set_icon_pixmap (struct frame *, int);
179 static void w32_initialize (void);
180 static void x_update_end (struct frame *);
181 static void w32_frame_up_to_date (struct frame *);
182 static void x_clear_frame (struct frame *);
183 static void frame_highlight (struct frame *);
184 static void frame_unhighlight (struct frame *);
185 static void x_new_focus_frame (struct w32_display_info *,
186 struct frame *);
187 static void x_focus_changed (int, int, struct w32_display_info *,
188 struct frame *, struct input_event *);
189 static void w32_detect_focus_change (struct w32_display_info *,
190 W32Msg *, struct input_event *);
191 static void w32_frame_rehighlight (struct frame *);
192 static void x_frame_rehighlight (struct w32_display_info *);
193 static void x_draw_hollow_cursor (struct window *, struct glyph_row *);
194 static void x_draw_bar_cursor (struct window *, struct glyph_row *, int,
195 enum text_cursor_kinds);
196 static void w32_clip_to_row (struct window *, struct glyph_row *,
197 enum glyph_row_area, HDC);
198 static BOOL my_show_window (struct frame *, HWND, int);
199 static void my_set_window_pos (HWND, HWND, int, int, int, int, UINT);
200 #if 0
201 static void my_set_focus (struct frame *, HWND);
202 #endif
203 static void my_set_foreground_window (HWND);
204 static void my_destroy_window (struct frame *, HWND);
205 static void w32fullscreen_hook (struct frame *);
207 #ifdef GLYPH_DEBUG
208 static void x_check_font (struct frame *, struct font *);
209 #endif
212 /***********************************************************************
213 Debugging
214 ***********************************************************************/
216 #if 0
218 /* This is a function useful for recording debugging information about
219 the sequence of occurrences in this file. */
221 struct record
223 char *locus;
224 int type;
227 struct record event_record[100];
229 int event_record_index;
231 record_event (char *locus, int type)
233 if (event_record_index == sizeof (event_record) / sizeof (struct record))
234 event_record_index = 0;
236 event_record[event_record_index].locus = locus;
237 event_record[event_record_index].type = type;
238 event_record_index++;
241 #endif /* 0 */
244 static void
245 XChangeGC (void *ignore, XGCValues *gc, unsigned long mask,
246 XGCValues *xgcv)
248 if (mask & GCForeground)
249 gc->foreground = xgcv->foreground;
250 if (mask & GCBackground)
251 gc->background = xgcv->background;
252 if (mask & GCFont)
253 gc->font = xgcv->font;
256 XGCValues *
257 XCreateGC (void *ignore, HWND wignore, unsigned long mask, XGCValues *xgcv)
259 XGCValues *gc = xzalloc (sizeof (XGCValues));
261 XChangeGC (ignore, gc, mask, xgcv);
263 return gc;
266 #if 0 /* unused for now, see x_draw_image_glyph_string below */
267 static void
268 XGetGCValues (void *ignore, XGCValues *gc,
269 unsigned long mask, XGCValues *xgcv)
271 XChangeGC (ignore, xgcv, mask, gc);
273 #endif
275 static void
276 w32_set_clip_rectangle (HDC hdc, RECT *rect)
278 if (rect)
280 HRGN clip_region = CreateRectRgnIndirect (rect);
281 SelectClipRgn (hdc, clip_region);
282 DeleteObject (clip_region);
284 else
285 SelectClipRgn (hdc, NULL);
288 /* Restore clipping rectangle in S */
289 static void
290 w32_restore_glyph_string_clip (struct glyph_string *s)
292 RECT *r = s->clip;
293 int n = s->num_clips;
295 if (n == 1)
296 w32_set_clip_rectangle (s->hdc, r);
297 else if (n > 1)
299 HRGN clip1 = CreateRectRgnIndirect (r);
300 HRGN clip2 = CreateRectRgnIndirect (r + 1);
301 if (CombineRgn (clip1, clip1, clip2, RGN_OR) != ERROR)
302 SelectClipRgn (s->hdc, clip1);
303 DeleteObject (clip1);
304 DeleteObject (clip2);
308 static void
309 x_get_scale_factor(struct w32_display_info *dpyinfo, int *scale_x, int *scale_y)
311 const int base_res = 96;
313 *scale_x = *scale_y = 1;
315 if (dpyinfo)
317 if (dpyinfo->resx > base_res)
318 *scale_x = floor (dpyinfo->resx / base_res);
319 if (dpyinfo->resy > base_res)
320 *scale_y = floor (dpyinfo->resy / base_res);
325 Draw a wavy line under S. The wave fills wave_height pixels from y0.
327 x0 wave_length = 2
329 y0 * * * * *
330 |* * * * * * * * *
331 wave_height = 3 | * * * *
335 static void
336 w32_draw_underwave (struct glyph_string *s, COLORREF color)
338 struct w32_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
340 int scale_x, scale_y;
341 x_get_scale_factor (dpyinfo, &scale_x, &scale_y);
343 int wave_height = 3 * scale_y, wave_length = 2 * scale_x, thickness = scale_y;
344 int dx, dy, x0, y0, width, x1, y1, x2, y2, odd, xmax;
345 XRectangle wave_clip, string_clip, final_clip;
346 RECT w32_final_clip, w32_string_clip;
347 HPEN hp, oldhp;
349 dx = wave_length;
350 dy = wave_height - 1;
351 x0 = s->x;
352 y0 = s->ybase + wave_height / 2 - scale_y;
353 width = s->width;
354 xmax = x0 + width;
356 /* Find and set clipping rectangle */
358 wave_clip.x = x0;
359 wave_clip.y = y0;
360 wave_clip.width = width;
361 wave_clip.height = wave_height;
363 get_glyph_string_clip_rect (s, &w32_string_clip);
364 CONVERT_TO_XRECT (string_clip, w32_string_clip);
366 if (!x_intersect_rectangles (&wave_clip, &string_clip, &final_clip))
367 return;
369 hp = CreatePen (PS_SOLID, thickness, color);
370 oldhp = SelectObject (s->hdc, hp);
371 CONVERT_FROM_XRECT (final_clip, w32_final_clip);
372 w32_set_clip_rectangle (s->hdc, &w32_final_clip);
374 /* Draw the waves */
376 x1 = x0 - (x0 % dx);
377 x2 = x1 + dx;
378 odd = (x1/dx) % 2;
379 y1 = y2 = y0;
381 if (odd)
382 y1 += dy;
383 else
384 y2 += dy;
386 MoveToEx (s->hdc, x1, y1, NULL);
388 while (x1 <= xmax)
390 LineTo (s->hdc, x2, y2);
391 x1 = x2, y1 = y2;
392 x2 += dx, y2 = y0 + odd*dy;
393 odd = !odd;
396 /* Restore previous pen and clipping rectangle(s) */
397 w32_restore_glyph_string_clip (s);
398 SelectObject (s->hdc, oldhp);
399 DeleteObject (hp);
402 /* Draw a hollow rectangle at the specified position. */
403 static void
404 w32_draw_rectangle (HDC hdc, XGCValues *gc, int x, int y,
405 int width, int height)
407 HBRUSH hb, oldhb;
408 HPEN hp, oldhp;
410 hb = CreateSolidBrush (gc->background);
411 hp = CreatePen (PS_SOLID, 0, gc->foreground);
412 oldhb = SelectObject (hdc, hb);
413 oldhp = SelectObject (hdc, hp);
415 /* We enlarge WIDTH and HEIGHT by 1 to be bug-compatible to the
416 brain-dead design of XDrawRectangle, which draws a rectangle that
417 is 1 pixel wider and higher than its arguments WIDTH and HEIGHT.
418 This allows us to keep the code that calls this function similar
419 to the corresponding code in xterm.c. For the details, see
420 https://lists.gnu.org/r/emacs-devel/2014-10/msg00546.html. */
421 Rectangle (hdc, x, y, x + width + 1, y + height + 1);
423 SelectObject (hdc, oldhb);
424 SelectObject (hdc, oldhp);
425 DeleteObject (hb);
426 DeleteObject (hp);
429 /* Draw a filled rectangle at the specified position. */
430 void
431 w32_fill_rect (struct frame *f, HDC hdc, COLORREF pix, RECT *lprect)
433 HBRUSH hb;
435 hb = CreateSolidBrush (pix);
436 FillRect (hdc, lprect, hb);
437 DeleteObject (hb);
440 void
441 w32_clear_window (struct frame *f)
443 RECT rect;
444 HDC hdc = get_frame_dc (f);
446 /* Under certain conditions, this can be called at startup with
447 a console frame pointer before the GUI frame is created. An HDC
448 of 0 indicates this. */
449 if (hdc)
451 GetClientRect (FRAME_W32_WINDOW (f), &rect);
452 w32_clear_rect (f, hdc, &rect);
455 release_frame_dc (f, hdc);
458 #define OPAQUE_FRAME 255
460 void
461 x_set_frame_alpha (struct frame *f)
463 struct w32_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
464 double alpha = 1.0;
465 double alpha_min = 1.0;
466 BYTE opac;
467 LONG ex_style;
468 HWND window = FRAME_W32_WINDOW (f);
470 /* Older versions of Windows do not support transparency. */
471 if (!pfnSetLayeredWindowAttributes)
472 return;
474 if (dpyinfo->w32_focus_frame == f)
475 alpha = f->alpha[0];
476 else
477 alpha = f->alpha[1];
479 if (FLOATP (Vframe_alpha_lower_limit))
480 alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
481 else if (INTEGERP (Vframe_alpha_lower_limit))
482 alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
484 if (alpha < 0.0)
485 return;
486 else if (alpha > 1.0)
487 alpha = 1.0;
488 else if (alpha < alpha_min && alpha_min <= 1.0)
489 alpha = alpha_min;
491 opac = alpha * OPAQUE_FRAME;
493 ex_style = GetWindowLong (window, GWL_EXSTYLE);
495 if (opac == OPAQUE_FRAME)
496 ex_style &= ~WS_EX_LAYERED;
497 else
498 ex_style |= WS_EX_LAYERED;
500 SetWindowLong (window, GWL_EXSTYLE, ex_style);
502 if (opac != OPAQUE_FRAME)
503 pfnSetLayeredWindowAttributes (window, 0, opac, LWA_ALPHA);
507 x_display_pixel_height (struct w32_display_info *dpyinfo)
509 int pixels = GetSystemMetrics (SM_CYVIRTUALSCREEN);
511 if (pixels == 0)
512 /* Fallback for Windows 95 or NT 4.0. */
513 pixels = GetSystemMetrics (SM_CYSCREEN);
515 return pixels;
519 x_display_pixel_width (struct w32_display_info *dpyinfo)
521 int pixels = GetSystemMetrics (SM_CXVIRTUALSCREEN);
523 if (pixels == 0)
524 /* Fallback for Windows 95 or NT 4.0. */
525 pixels = GetSystemMetrics (SM_CXSCREEN);
527 return pixels;
531 /***********************************************************************
532 Starting and ending an update
533 ***********************************************************************/
535 /* Start an update of frame F. This function is installed as a hook
536 for update_begin, i.e. it is called when update_begin is called.
537 This function is called prior to calls to x_update_window_begin for
538 each window being updated. */
540 static void
541 x_update_begin (struct frame *f)
543 struct w32_display_info *display_info = FRAME_DISPLAY_INFO (f);
545 if (! FRAME_W32_P (f))
546 return;
548 /* Regenerate display palette before drawing if list of requested
549 colors has changed. */
550 if (display_info->regen_palette)
552 w32_regenerate_palette (f);
553 display_info->regen_palette = FALSE;
558 /* Start update of window W. */
560 static void
561 x_update_window_begin (struct window *w)
563 struct frame *f = XFRAME (WINDOW_FRAME (w));
564 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
566 /* Hide the system caret during an update. */
567 if (w32_use_visible_system_caret && w32_system_caret_hwnd)
569 SendMessageTimeout (w32_system_caret_hwnd, WM_EMACS_HIDE_CARET, 0, 0,
570 0, 6000, NULL);
573 w->output_cursor = w->cursor;
575 block_input ();
577 if (f == hlinfo->mouse_face_mouse_frame)
579 /* Don't do highlighting for mouse motion during the update. */
580 hlinfo->mouse_face_defer = true;
582 /* If F needs to be redrawn, simply forget about any prior mouse
583 highlighting. */
584 if (FRAME_GARBAGED_P (f))
585 hlinfo->mouse_face_window = Qnil;
587 #if 0 /* Rows in a current matrix containing glyphs in mouse-face have
588 their mouse_face_p flag set, which means that they are always
589 unequal to rows in a desired matrix which never have that
590 flag set. So, rows containing mouse-face glyphs are never
591 scrolled, and we don't have to switch the mouse highlight off
592 here to prevent it from being scrolled. */
594 /* Can we tell that this update does not affect the window
595 where the mouse highlight is? If so, no need to turn off.
596 Likewise, don't do anything if the frame is garbaged;
597 in that case, the frame's current matrix that we would use
598 is all wrong, and we will redisplay that line anyway. */
599 if (!NILP (hlinfo->mouse_face_window)
600 && w == XWINDOW (hlinfo->mouse_face_window))
602 int i;
604 for (i = 0; i < w->desired_matrix->nrows; ++i)
605 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i))
606 break;
608 if (i < w->desired_matrix->nrows)
609 clear_mouse_face (hlinfo);
611 #endif /* 0 */
614 unblock_input ();
617 /* Draw a vertical window border from (x,y0) to (x,y1) */
619 static void
620 w32_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
622 struct frame *f = XFRAME (WINDOW_FRAME (w));
623 RECT r;
624 HDC hdc;
625 struct face *face;
627 r.left = x;
628 r.right = x + 1;
629 r.top = y0;
630 r.bottom = y1;
632 hdc = get_frame_dc (f);
633 face = FACE_FROM_ID_OR_NULL (f, VERTICAL_BORDER_FACE_ID);
634 if (face)
635 w32_fill_rect (f, hdc, face->foreground, &r);
636 else
637 w32_fill_rect (f, hdc, FRAME_FOREGROUND_PIXEL (f), &r);
639 release_frame_dc (f, hdc);
643 /* Draw a window divider from (x0, y0) to (x1, y1) */
645 static void
646 w32_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
648 struct frame *f = XFRAME (WINDOW_FRAME (w));
649 HDC hdc = get_frame_dc (f);
650 struct face *face = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FACE_ID);
651 struct face *face_first
652 = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FIRST_PIXEL_FACE_ID);
653 struct face *face_last
654 = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_LAST_PIXEL_FACE_ID);
655 unsigned long color = face ? face->foreground : FRAME_FOREGROUND_PIXEL (f);
656 unsigned long color_first = (face_first
657 ? face_first->foreground
658 : FRAME_FOREGROUND_PIXEL (f));
659 unsigned long color_last = (face_last
660 ? face_last->foreground
661 : FRAME_FOREGROUND_PIXEL (f));
663 if ((y1 - y0 > x1 - x0) && (x1 - x0 >= 3))
664 /* A vertical divider, at least three pixels wide: Draw first and
665 last pixels differently. */
667 w32_fill_area_abs (f, hdc, color_first, x0, y0, x0 + 1, y1);
668 w32_fill_area_abs (f, hdc, color, x0 + 1, y0, x1 - 1, y1);
669 w32_fill_area_abs (f, hdc, color_last, x1 - 1, y0, x1, y1);
671 else if ((x1 - x0 > y1 - y0) && (y1 - y0 >= 3))
672 /* A horizontal divider, at least three pixels high: Draw first and
673 last pixels differently. */
675 w32_fill_area_abs (f, hdc, color_first, x0, y0, x1, y0 + 1);
676 w32_fill_area_abs (f, hdc, color, x0, y0 + 1, x1, y1 - 1);
677 w32_fill_area_abs (f, hdc, color_last, x0, y1 - 1, x1, y1);
679 else
680 /* In any other case do not draw the first and last pixels
681 differently. */
682 w32_fill_area_abs (f, hdc, color, x0, y0, x1, y1);
684 release_frame_dc (f, hdc);
687 /* End update of window W.
689 Draw vertical borders between horizontally adjacent windows, and
690 display W's cursor if CURSOR_ON_P is non-zero.
692 MOUSE_FACE_OVERWRITTEN_P non-zero means that some row containing
693 glyphs in mouse-face were overwritten. In that case we have to
694 make sure that the mouse-highlight is properly redrawn.
696 W may be a menu bar pseudo-window in case we don't have X toolkit
697 support. Such windows don't have a cursor, so don't display it
698 here. */
700 static void
701 x_update_window_end (struct window *w, bool cursor_on_p,
702 bool mouse_face_overwritten_p)
704 if (!w->pseudo_window_p)
706 block_input ();
708 if (cursor_on_p)
709 display_and_set_cursor (w, true,
710 w->output_cursor.hpos, w->output_cursor.vpos,
711 w->output_cursor.x, w->output_cursor.y);
713 if (draw_window_fringes (w, true))
715 if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
716 x_draw_right_divider (w);
717 else
718 x_draw_vertical_border (w);
721 unblock_input ();
724 /* If a row with mouse-face was overwritten, arrange for
725 XTframe_up_to_date to redisplay the mouse highlight. */
726 if (mouse_face_overwritten_p)
728 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (XFRAME (w->frame));
730 hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
731 hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
732 hlinfo->mouse_face_window = Qnil;
735 /* Unhide the caret. This won't actually show the cursor, unless it
736 was visible before the corresponding call to HideCaret in
737 x_update_window_begin. */
738 if (w32_use_visible_system_caret && w32_system_caret_hwnd)
740 SendMessageTimeout (w32_system_caret_hwnd, WM_EMACS_SHOW_CARET, 0, 0,
741 0, 6000, NULL);
746 /* End update of frame F. This function is installed as a hook in
747 update_end. */
749 static void
750 x_update_end (struct frame *f)
752 if (! FRAME_W32_P (f))
753 return;
755 /* Mouse highlight may be displayed again. */
756 MOUSE_HL_INFO (f)->mouse_face_defer = false;
760 /* This function is called from various places in xdisp.c
761 whenever a complete update has been performed. */
763 static void
764 w32_frame_up_to_date (struct frame *f)
766 if (FRAME_W32_P (f))
767 FRAME_MOUSE_UPDATE (f);
771 /* Draw truncation mark bitmaps, continuation mark bitmaps, overlay
772 arrow bitmaps, or clear the fringes if no bitmaps are required
773 before DESIRED_ROW is made current. This function is called from
774 update_window_line only if it is known that there are differences
775 between bitmaps to be drawn between current row and DESIRED_ROW. */
777 static void
778 x_after_update_window_line (struct window *w, struct glyph_row *desired_row)
780 struct frame *f;
781 int width, height;
783 eassert (w);
785 if (!desired_row->mode_line_p && !w->pseudo_window_p)
786 desired_row->redraw_fringe_bitmaps_p = true;
788 /* When a window has disappeared, make sure that no rest of
789 full-width rows stays visible in the internal border. Could
790 check here if updated window is the leftmost/rightmost window,
791 but I guess it's not worth doing since vertically split windows
792 are almost never used, internal border is rarely set, and the
793 overhead is very small. */
794 if (windows_or_buffers_changed
795 && desired_row->full_width_p
796 && (f = XFRAME (w->frame),
797 width = FRAME_INTERNAL_BORDER_WIDTH (f),
798 width != 0)
799 && (height = desired_row->visible_height,
800 height > 0))
802 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
804 block_input ();
806 HDC hdc = get_frame_dc (f);
807 struct face *face = FACE_FROM_ID_OR_NULL (f, INTERNAL_BORDER_FACE_ID);
809 if (face)
811 /* Fill border with internal border face. */
812 unsigned long color = face->background;
814 w32_fill_area (f, hdc, color, 0, y, width, height);
815 w32_fill_area (f, hdc, color, FRAME_PIXEL_WIDTH (f) - width,
816 y, width, height);
818 else
820 w32_clear_area (f, hdc, 0, y, width, height);
821 w32_clear_area (f, hdc, FRAME_PIXEL_WIDTH (f) - width,
822 y, width, height);
824 release_frame_dc (f, hdc);
826 unblock_input ();
831 /* Draw the bitmap WHICH in one of the left or right fringes of
832 window W. ROW is the glyph row for which to display the bitmap; it
833 determines the vertical position at which the bitmap has to be
834 drawn. */
836 static void
837 w32_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
838 struct draw_fringe_bitmap_params *p)
840 struct frame *f = XFRAME (WINDOW_FRAME (w));
841 HDC hdc;
842 struct face *face = p->face;
844 hdc = get_frame_dc (f);
846 /* Must clip because of partially visible lines. */
847 w32_clip_to_row (w, row, ANY_AREA, hdc);
849 if (p->bx >= 0 && !p->overlay_p)
850 w32_fill_area (f, hdc, face->background,
851 p->bx, p->by, p->nx, p->ny);
853 if (p->which && p->which < max_fringe_bmp)
855 HBITMAP pixmap = fringe_bmp[p->which];
856 HDC compat_hdc;
857 HANDLE horig_obj;
859 compat_hdc = CreateCompatibleDC (hdc);
861 SaveDC (hdc);
863 horig_obj = SelectObject (compat_hdc, pixmap);
865 /* Paint overlays transparently. */
866 if (p->overlay_p)
868 HBRUSH h_brush, h_orig_brush;
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);
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);
885 SelectObject (hdc, h_orig_brush);
886 DeleteObject (h_brush);
888 else
890 SetTextColor (hdc, face->background);
891 SetBkColor (hdc, (p->cursor_p
892 ? f->output_data.w32->cursor_pixel
893 : face->foreground));
895 BitBlt (hdc, p->x, p->y, p->wd, p->h,
896 compat_hdc, 0, p->dh,
897 SRCCOPY);
900 SelectObject (compat_hdc, horig_obj);
901 DeleteDC (compat_hdc);
902 RestoreDC (hdc, -1);
905 w32_set_clip_rectangle (hdc, NULL);
907 release_frame_dc (f, hdc);
910 static void
911 w32_define_fringe_bitmap (int which, unsigned short *bits, int h, int wd)
913 if (which >= max_fringe_bmp)
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;
922 fringe_bmp[which] = CreateBitmap (wd, h, 1, 1, bits);
925 static void
926 w32_destroy_fringe_bitmap (int which)
928 if (which >= max_fringe_bmp)
929 return;
931 if (fringe_bmp[which])
932 DeleteObject (fringe_bmp[which]);
933 fringe_bmp[which] = 0;
936 /***********************************************************************
937 Display Iterator
938 ***********************************************************************/
940 /* Function prototypes of this page. */
942 static void x_set_glyph_string_clipping (struct glyph_string *);
943 static void x_set_glyph_string_gc (struct glyph_string *);
944 static void x_draw_glyph_string_background (struct glyph_string *,
945 bool);
946 static void x_draw_glyph_string_foreground (struct glyph_string *);
947 static void x_draw_composite_glyph_string_foreground (struct glyph_string *);
948 static void x_draw_glyph_string_box (struct glyph_string *);
949 static void x_draw_glyph_string (struct glyph_string *);
950 static void x_set_cursor_gc (struct glyph_string *);
951 static void x_set_mode_line_face_gc (struct glyph_string *);
952 static void x_set_mouse_face_gc (struct glyph_string *);
953 static int w32_alloc_lighter_color (struct frame *, COLORREF *, double, int);
954 static void w32_setup_relief_color (struct frame *, struct relief *,
955 double, int, COLORREF);
956 static void x_setup_relief_colors (struct glyph_string *);
957 static void x_draw_image_glyph_string (struct glyph_string *);
958 static void x_draw_image_relief (struct glyph_string *);
959 static void x_draw_image_foreground (struct glyph_string *);
960 static void w32_draw_image_foreground_1 (struct glyph_string *, HBITMAP);
961 static void x_clear_glyph_string_rect (struct glyph_string *, int,
962 int, int, int);
963 static void w32_draw_relief_rect (struct frame *, int, int, int, int,
964 int, int, int, int, int, int,
965 RECT *);
966 static void w32_draw_box_rect (struct glyph_string *, int, int, int, int,
967 int, bool, bool, RECT *);
970 /* Set S->gc to a suitable GC for drawing glyph string S in cursor
971 face. */
973 static void
974 x_set_cursor_gc (struct glyph_string *s)
976 if (s->font == FRAME_FONT (s->f)
977 && s->face->background == FRAME_BACKGROUND_PIXEL (s->f)
978 && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f)
979 /* Sometimes we are not called for each change in the default
980 face's background color (e.g., bug#26851), so the additional
981 test in the next line gives us a chance to resync. */
982 && s->f->output_data.w32->cursor_gc->foreground == s->face->background
983 && !s->cmp)
984 s->gc = s->f->output_data.w32->cursor_gc;
985 else
987 /* Cursor on non-default face: must merge. */
988 XGCValues xgcv;
989 unsigned long mask;
991 xgcv.background = s->f->output_data.w32->cursor_pixel;
992 xgcv.foreground = s->face->background;
994 /* If the glyph would be invisible, try a different foreground. */
995 if (xgcv.foreground == xgcv.background)
996 xgcv.foreground = s->face->foreground;
997 if (xgcv.foreground == xgcv.background)
998 xgcv.foreground = s->f->output_data.w32->cursor_foreground_pixel;
999 if (xgcv.foreground == xgcv.background)
1000 xgcv.foreground = s->face->foreground;
1002 /* Make sure the cursor is distinct from text in this face. */
1003 if (xgcv.background == s->face->background
1004 && xgcv.foreground == s->face->foreground)
1006 xgcv.background = s->face->foreground;
1007 xgcv.foreground = s->face->background;
1010 IF_DEBUG (x_check_font (s->f, s->font));
1011 xgcv.font = s->font;
1012 mask = GCForeground | GCBackground | GCFont;
1014 if (FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc)
1015 XChangeGC (NULL, FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc,
1016 mask, &xgcv);
1017 else
1018 FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc
1019 = XCreateGC (NULL, FRAME_W32_WINDOW (s->f), mask, &xgcv);
1021 s->gc = FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc;
1026 /* Set up S->gc of glyph string S for drawing text in mouse face. */
1028 static void
1029 x_set_mouse_face_gc (struct glyph_string *s)
1031 int face_id;
1032 struct face *face;
1034 /* What face has to be used last for the mouse face? */
1035 face_id = MOUSE_HL_INFO (s->f)->mouse_face_face_id;
1036 face = FACE_FROM_ID_OR_NULL (s->f, face_id);
1037 if (face == NULL)
1038 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
1040 if (s->first_glyph->type == CHAR_GLYPH)
1041 face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch, -1, Qnil);
1042 else
1043 face_id = FACE_FOR_CHAR (s->f, face, 0, -1, Qnil);
1044 s->face = FACE_FROM_ID (s->f, face_id);
1045 prepare_face_for_display (s->f, s->face);
1047 /* If font in this face is same as S->font, use it. */
1048 if (s->font == s->face->font)
1049 s->gc = s->face->gc;
1050 else
1052 /* Otherwise construct scratch_cursor_gc with values from FACE
1053 but font FONT. */
1054 XGCValues xgcv;
1055 unsigned long mask;
1057 xgcv.background = s->face->background;
1058 xgcv.foreground = s->face->foreground;
1059 IF_DEBUG (x_check_font (s->f, s->font));
1060 xgcv.font = s->font;
1061 mask = GCForeground | GCBackground | GCFont;
1063 if (FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc)
1064 XChangeGC (NULL, FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc,
1065 mask, &xgcv);
1066 else
1067 FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc
1068 = XCreateGC (NULL, FRAME_W32_WINDOW (s->f), mask, &xgcv);
1070 s->gc = FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc;
1073 eassert (s->gc != 0);
1077 /* Set S->gc of glyph string S to a GC suitable for drawing a mode line.
1078 Faces to use in the mode line have already been computed when the
1079 matrix was built, so there isn't much to do, here. */
1081 static inline void
1082 x_set_mode_line_face_gc (struct glyph_string *s)
1084 s->gc = s->face->gc;
1088 /* Set S->gc of glyph string S for drawing that glyph string. Set
1089 S->stippled_p to a non-zero value if the face of S has a stipple
1090 pattern. */
1092 static inline void
1093 x_set_glyph_string_gc (struct glyph_string *s)
1095 prepare_face_for_display (s->f, s->face);
1097 if (s->hl == DRAW_NORMAL_TEXT)
1099 s->gc = s->face->gc;
1100 s->stippled_p = s->face->stipple != 0;
1102 else if (s->hl == DRAW_INVERSE_VIDEO)
1104 x_set_mode_line_face_gc (s);
1105 s->stippled_p = s->face->stipple != 0;
1107 else if (s->hl == DRAW_CURSOR)
1109 x_set_cursor_gc (s);
1110 s->stippled_p = false;
1112 else if (s->hl == DRAW_MOUSE_FACE)
1114 x_set_mouse_face_gc (s);
1115 s->stippled_p = s->face->stipple != 0;
1117 else if (s->hl == DRAW_IMAGE_RAISED
1118 || s->hl == DRAW_IMAGE_SUNKEN)
1120 s->gc = s->face->gc;
1121 s->stippled_p = s->face->stipple != 0;
1123 else
1124 emacs_abort ();
1126 /* GC must have been set. */
1127 eassert (s->gc != 0);
1131 /* Set clipping for output of glyph string S. S may be part of a mode
1132 line or menu if we don't have X toolkit support. */
1134 static inline void
1135 x_set_glyph_string_clipping (struct glyph_string *s)
1137 RECT *r = s->clip;
1138 int n = get_glyph_string_clip_rects (s, r, 2);
1140 if (n == 1)
1141 w32_set_clip_rectangle (s->hdc, r);
1142 else if (n > 1)
1144 HRGN clip1 = CreateRectRgnIndirect (r);
1145 HRGN clip2 = CreateRectRgnIndirect (r + 1);
1146 if (CombineRgn (clip1, clip1, clip2, RGN_OR) != ERROR)
1147 SelectClipRgn (s->hdc, clip1);
1148 DeleteObject (clip1);
1149 DeleteObject (clip2);
1151 s->num_clips = n;
1154 /* Set SRC's clipping for output of glyph string DST. This is called
1155 when we are drawing DST's left_overhang or right_overhang only in
1156 the area of SRC. */
1158 static void
1159 x_set_glyph_string_clipping_exactly (struct glyph_string *src,
1160 struct glyph_string *dst)
1162 RECT r;
1164 r.left = src->x;
1165 r.right = r.left + src->width;
1166 r.top = src->y;
1167 r.bottom = r.top + src->height;
1168 dst->clip[0] = r;
1169 dst->num_clips = 1;
1170 w32_set_clip_rectangle (dst->hdc, &r);
1173 /* RIF:
1174 Compute left and right overhang of glyph string S. */
1176 static void
1177 w32_compute_glyph_string_overhangs (struct glyph_string *s)
1179 if (s->cmp == NULL
1180 && s->first_glyph->type == CHAR_GLYPH
1181 && !s->font_not_found_p)
1183 unsigned *code = alloca (sizeof (unsigned) * s->nchars);
1184 struct font *font = s->font;
1185 struct font_metrics metrics;
1186 int i;
1188 for (i = 0; i < s->nchars; i++)
1189 code[i] = s->char2b[i];
1190 font->driver->text_extents (font, code, s->nchars, &metrics);
1191 s->right_overhang = (metrics.rbearing > metrics.width
1192 ? metrics.rbearing - metrics.width : 0);
1193 s->left_overhang = metrics.lbearing < 0 ? -metrics.lbearing : 0;
1195 else if (s->cmp)
1197 s->right_overhang = s->cmp->rbearing - s->cmp->pixel_width;
1198 s->left_overhang = -s->cmp->lbearing;
1202 /* Fill rectangle X, Y, W, H with background color of glyph string S. */
1204 static inline void
1205 x_clear_glyph_string_rect (struct glyph_string *s,
1206 int x, int y, int w, int h)
1208 int real_x = x;
1209 int real_y = y;
1210 int real_w = w;
1211 int real_h = h;
1212 #if 0
1213 /* Take clipping into account. */
1214 if (s->gc->clip_mask == Rect)
1216 real_x = max (real_x, s->gc->clip_rectangle.left);
1217 real_y = max (real_y, s->gc->clip_rectangle.top);
1218 real_w = min (real_w, s->gc->clip_rectangle.right
1219 - s->gc->clip_rectangle.left);
1220 real_h = min (real_h, s->gc->clip_rectangle.bottom
1221 - s->gc->clip_rectangle.top);
1223 #endif
1224 w32_fill_area (s->f, s->hdc, s->gc->background, real_x, real_y,
1225 real_w, real_h);
1229 /* Draw the background of glyph_string S. If S->background_filled_p
1230 is non-zero don't draw it. FORCE_P non-zero means draw the
1231 background even if it wouldn't be drawn normally. This is used
1232 when a string preceding S draws into the background of S, or S
1233 contains the first component of a composition. */
1235 static void
1236 x_draw_glyph_string_background (struct glyph_string *s, bool force_p)
1238 /* Nothing to do if background has already been drawn or if it
1239 shouldn't be drawn in the first place. */
1240 if (!s->background_filled_p)
1242 int box_line_width = max (s->face->box_line_width, 0);
1244 #if 0 /* TODO: stipple */
1245 if (s->stippled_p)
1247 /* Fill background with a stipple pattern. */
1248 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
1249 XFillRectangle (s->display, FRAME_W32_WINDOW (s->f), s->gc, s->x,
1250 s->y + box_line_width,
1251 s->background_width,
1252 s->height - 2 * box_line_width);
1253 XSetFillStyle (s->display, s->gc, FillSolid);
1254 s->background_filled_p = true;
1256 else
1257 #endif
1258 if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
1259 /* When xdisp.c ignores FONT_HEIGHT, we cannot trust
1260 font dimensions, since the actual glyphs might be
1261 much smaller. So in that case we always clear the
1262 rectangle with background color. */
1263 || FONT_TOO_HIGH (s->font)
1264 || s->font_not_found_p
1265 || s->extends_to_end_of_line_p
1266 || force_p)
1268 x_clear_glyph_string_rect (s, s->x, s->y + box_line_width,
1269 s->background_width,
1270 s->height - 2 * box_line_width);
1271 s->background_filled_p = true;
1277 /* Draw the foreground of glyph string S. */
1279 static void
1280 x_draw_glyph_string_foreground (struct glyph_string *s)
1282 int i, x;
1284 /* If first glyph of S has a left box line, start drawing the text
1285 of S to the right of that box line. */
1286 if (s->face->box != FACE_NO_BOX
1287 && s->first_glyph->left_box_line_p)
1288 x = s->x + eabs (s->face->box_line_width);
1289 else
1290 x = s->x;
1292 SetTextColor (s->hdc, s->gc->foreground);
1293 SetBkColor (s->hdc, s->gc->background);
1294 SetTextAlign (s->hdc, TA_BASELINE | TA_LEFT);
1296 /* Draw characters of S as rectangles if S's font could not be
1297 loaded. */
1298 if (s->font_not_found_p)
1300 for (i = 0; i < s->nchars; ++i)
1302 struct glyph *g = s->first_glyph + i;
1304 w32_draw_rectangle (s->hdc, s->gc, x, s->y, g->pixel_width - 1,
1305 s->height - 1);
1306 x += g->pixel_width;
1309 else
1311 struct font *font = s->font;
1312 int boff = font->baseline_offset;
1313 int y;
1314 HFONT old_font;
1316 old_font = SelectObject (s->hdc, FONT_HANDLE (font));
1318 if (font->vertical_centering)
1319 boff = VCENTER_BASELINE_OFFSET (font, s->f) - boff;
1321 y = s->ybase - boff;
1322 if (s->for_overlaps
1323 || (s->background_filled_p && s->hl != DRAW_CURSOR))
1324 font->driver->draw (s, 0, s->nchars, x, y, false);
1325 else
1326 font->driver->draw (s, 0, s->nchars, x, y, true);
1327 if (s->face->overstrike)
1328 font->driver->draw (s, 0, s->nchars, x + 1, y, false);
1330 SelectObject (s->hdc, old_font);
1334 /* Draw the foreground of composite glyph string S. */
1336 static void
1337 x_draw_composite_glyph_string_foreground (struct glyph_string *s)
1339 int i, j, x;
1340 struct font *font = s->font;
1342 /* If first glyph of S has a left box line, start drawing the text
1343 of S to the right of that box line. */
1344 if (s->face && s->face->box != FACE_NO_BOX
1345 && s->first_glyph->left_box_line_p)
1346 x = s->x + eabs (s->face->box_line_width);
1347 else
1348 x = s->x;
1350 /* S is a glyph string for a composition. S->cmp_from is the index
1351 of the first character drawn for glyphs of this composition.
1352 S->cmp_from == 0 means we are drawing the very first character of
1353 this composition. */
1355 SetTextColor (s->hdc, s->gc->foreground);
1356 SetBkColor (s->hdc, s->gc->background);
1357 SetTextAlign (s->hdc, TA_BASELINE | TA_LEFT);
1359 /* Draw a rectangle for the composition if the font for the very
1360 first character of the composition could not be loaded. */
1361 if (s->font_not_found_p)
1363 if (s->cmp_from == 0)
1364 w32_draw_rectangle (s->hdc, s->gc, x, s->y, s->width - 1,
1365 s->height - 1);
1367 else if (! s->first_glyph->u.cmp.automatic)
1369 int y = s->ybase;
1370 HFONT old_font;
1372 old_font = SelectObject (s->hdc, FONT_HANDLE (font));
1374 for (i = 0, j = s->cmp_from; i < s->nchars; i++, j++)
1375 /* TAB in a composition means display glyphs with padding
1376 space on the left or right. */
1377 if (COMPOSITION_GLYPH (s->cmp, j) != '\t')
1379 int xx = x + s->cmp->offsets[j * 2];
1380 int yy = y - s->cmp->offsets[j * 2 + 1];
1382 font->driver->draw (s, j, j + 1, xx, yy, false);
1383 if (s->face->overstrike)
1384 font->driver->draw (s, j, j + 1, xx + 1, yy, false);
1386 SelectObject (s->hdc, old_font);
1388 else
1390 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1391 Lisp_Object glyph;
1392 int y = s->ybase;
1393 int width = 0;
1394 HFONT old_font;
1396 old_font = SelectObject (s->hdc, FONT_HANDLE (font));
1398 for (i = j = s->cmp_from; i < s->cmp_to; i++)
1400 glyph = LGSTRING_GLYPH (gstring, i);
1401 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
1402 width += LGLYPH_WIDTH (glyph);
1403 else
1405 int xoff, yoff, wadjust;
1407 if (j < i)
1409 font->driver->draw (s, j, i, x, y, false);
1410 x += width;
1412 xoff = LGLYPH_XOFF (glyph);
1413 yoff = LGLYPH_YOFF (glyph);
1414 wadjust = LGLYPH_WADJUST (glyph);
1415 font->driver->draw (s, i, i + 1, x + xoff, y + yoff, false);
1416 x += wadjust;
1417 j = i + 1;
1418 width = 0;
1421 if (j < i)
1422 font->driver->draw (s, j, i, x, y, false);
1424 SelectObject (s->hdc, old_font);
1429 /* Draw the foreground of glyph string S for glyphless characters. */
1431 static void
1432 x_draw_glyphless_glyph_string_foreground (struct glyph_string *s)
1434 struct glyph *glyph = s->first_glyph;
1435 XChar2b char2b[8];
1436 int x, i, j;
1437 bool with_background;
1439 /* If first glyph of S has a left box line, start drawing the text
1440 of S to the right of that box line. */
1441 if (s->face->box != FACE_NO_BOX
1442 && s->first_glyph->left_box_line_p)
1443 x = s->x + eabs (s->face->box_line_width);
1444 else
1445 x = s->x;
1447 SetTextColor (s->hdc, s->gc->foreground);
1448 SetBkColor (s->hdc, s->gc->background);
1449 SetTextAlign (s->hdc, TA_BASELINE | TA_LEFT);
1451 s->char2b = char2b;
1452 with_background = ((s->for_overlaps
1453 || (s->background_filled_p && s->hl != DRAW_CURSOR))) == 0;
1454 for (i = 0; i < s->nchars; i++, glyph++)
1456 char buf[7], *str = NULL;
1457 int len = glyph->u.glyphless.len;
1459 if (glyph->u.glyphless.method == GLYPHLESS_DISPLAY_ACRONYM)
1461 if (len > 0
1462 && CHAR_TABLE_P (Vglyphless_char_display)
1463 && (CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (Vglyphless_char_display))
1464 >= 1))
1466 Lisp_Object acronym
1467 = (! glyph->u.glyphless.for_no_font
1468 ? CHAR_TABLE_REF (Vglyphless_char_display,
1469 glyph->u.glyphless.ch)
1470 : XCHAR_TABLE (Vglyphless_char_display)->extras[0]);
1471 if (STRINGP (acronym))
1472 str = SSDATA (acronym);
1475 else if (glyph->u.glyphless.method == GLYPHLESS_DISPLAY_HEX_CODE)
1477 sprintf ((char *) buf, "%0*X",
1478 glyph->u.glyphless.ch < 0x10000 ? 4 : 6,
1479 (unsigned int) glyph->u.glyphless.ch);
1480 str = buf;
1483 if (glyph->u.glyphless.method != GLYPHLESS_DISPLAY_THIN_SPACE)
1484 w32_draw_rectangle (s->hdc, s->gc,
1485 x, s->ybase - glyph->ascent,
1486 glyph->pixel_width - 1,
1487 glyph->ascent + glyph->descent - 1);
1488 if (str)
1490 struct font *font = s->font;
1491 int upper_len = (len + 1) / 2;
1492 unsigned code;
1493 HFONT old_font;
1495 old_font = SelectObject (s->hdc, FONT_HANDLE (font));
1496 /* It is certain that all LEN characters in STR are ASCII. */
1497 for (j = 0; j < len; j++)
1499 code = font->driver->encode_char (font, str[j]);
1500 STORE_XCHAR2B (char2b + j, code >> 8, code & 0xFF);
1502 font->driver->draw (s, 0, upper_len,
1503 x + glyph->slice.glyphless.upper_xoff,
1504 s->ybase + glyph->slice.glyphless.upper_yoff,
1505 with_background);
1506 font->driver->draw (s, upper_len, len,
1507 x + glyph->slice.glyphless.lower_xoff,
1508 s->ybase + glyph->slice.glyphless.lower_yoff,
1509 with_background);
1510 SelectObject (s->hdc, old_font);
1512 x += glyph->pixel_width;
1517 /* Brightness beyond which a color won't have its highlight brightness
1518 boosted.
1520 Nominally, highlight colors for `3d' faces are calculated by
1521 brightening an object's color by a constant scale factor, but this
1522 doesn't yield good results for dark colors, so for colors whose
1523 brightness is less than this value (on a scale of 0-255) have to
1524 use an additional additive factor.
1526 The value here is set so that the default menu-bar/mode-line color
1527 (grey75) will not have its highlights changed at all. */
1528 #define HIGHLIGHT_COLOR_DARK_BOOST_LIMIT 187
1531 /* Allocate a color which is lighter or darker than *COLOR by FACTOR
1532 or DELTA. Try a color with RGB values multiplied by FACTOR first.
1533 If this produces the same color as COLOR, try a color where all RGB
1534 values have DELTA added. Return the allocated color in *COLOR.
1535 DISPLAY is the X display, CMAP is the colormap to operate on.
1536 Value is non-zero if successful. */
1538 static int
1539 w32_alloc_lighter_color (struct frame *f, COLORREF *color,
1540 double factor, int delta)
1542 COLORREF new;
1543 long bright;
1545 /* On Windows, RGB values are 0-255, not 0-65535, so scale delta. */
1546 delta /= 256;
1548 /* Change RGB values by specified FACTOR. Avoid overflow! */
1549 eassert (factor >= 0);
1550 new = PALETTERGB (min (0xff, factor * GetRValue (*color)),
1551 min (0xff, factor * GetGValue (*color)),
1552 min (0xff, factor * GetBValue (*color)));
1554 /* Calculate brightness of COLOR. */
1555 bright = (2 * GetRValue (*color) + 3 * GetGValue (*color)
1556 + GetBValue (*color)) / 6;
1558 /* We only boost colors that are darker than
1559 HIGHLIGHT_COLOR_DARK_BOOST_LIMIT. */
1560 if (bright < HIGHLIGHT_COLOR_DARK_BOOST_LIMIT)
1561 /* Make an additive adjustment to NEW, because it's dark enough so
1562 that scaling by FACTOR alone isn't enough. */
1564 /* How far below the limit this color is (0 - 1, 1 being darker). */
1565 double dimness = 1 - (double)bright / HIGHLIGHT_COLOR_DARK_BOOST_LIMIT;
1566 /* The additive adjustment. */
1567 int min_delta = delta * dimness * factor / 2;
1569 if (factor < 1)
1570 new = PALETTERGB (max (0, min (0xff, min_delta - GetRValue (*color))),
1571 max (0, min (0xff, min_delta - GetGValue (*color))),
1572 max (0, min (0xff, min_delta - GetBValue (*color))));
1573 else
1574 new = PALETTERGB (max (0, min (0xff, min_delta + GetRValue (*color))),
1575 max (0, min (0xff, min_delta + GetGValue (*color))),
1576 max (0, min (0xff, min_delta + GetBValue (*color))));
1579 if (new == *color)
1580 new = PALETTERGB (max (0, min (0xff, delta + GetRValue (*color))),
1581 max (0, min (0xff, delta + GetGValue (*color))),
1582 max (0, min (0xff, delta + GetBValue (*color))));
1584 /* TODO: Map to palette and retry with delta if same? */
1585 /* TODO: Free colors (if using palette)? */
1587 if (new == *color)
1588 return 0;
1590 *color = new;
1592 return 1;
1595 /* On frame F, translate pixel colors to RGB values for the NCOLORS
1596 colors in COLORS. On W32, we no longer try to map colors to
1597 a palette. */
1598 void
1599 x_query_colors (struct frame *f, XColor *colors, int ncolors)
1601 int i;
1603 for (i = 0; i < ncolors; i++)
1605 DWORD pixel = colors[i].pixel;
1606 /* Convert to a 16 bit value in range 0 - 0xffff. */
1607 colors[i].red = GetRValue (pixel) * 257;
1608 colors[i].green = GetGValue (pixel) * 257;
1609 colors[i].blue = GetBValue (pixel) * 257;
1613 void
1614 x_query_color (struct frame *f, XColor *color)
1616 x_query_colors (f, color, 1);
1620 /* Set up the foreground color for drawing relief lines of glyph
1621 string S. RELIEF is a pointer to a struct relief containing the GC
1622 with which lines will be drawn. Use a color that is FACTOR or
1623 DELTA lighter or darker than the relief's background which is found
1624 in S->f->output_data.x->relief_background. If such a color cannot
1625 be allocated, use DEFAULT_PIXEL, instead. */
1627 static void
1628 w32_setup_relief_color (struct frame *f, struct relief *relief, double factor,
1629 int delta, COLORREF default_pixel)
1631 XGCValues xgcv;
1632 struct w32_output *di = f->output_data.w32;
1633 unsigned long mask = GCForeground;
1634 COLORREF pixel;
1635 COLORREF background = di->relief_background;
1636 #if 0
1637 struct w32_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
1638 #endif
1640 /* TODO: Free colors (if using palette)? */
1642 /* Allocate new color. */
1643 xgcv.foreground = default_pixel;
1644 pixel = background;
1645 if (w32_alloc_lighter_color (f, &pixel, factor, delta))
1646 xgcv.foreground = relief->pixel = pixel;
1648 xgcv.font = NULL; /* avoid compiler warnings */
1649 if (relief->gc == 0)
1651 #if 0 /* TODO: stipple */
1652 xgcv.stipple = dpyinfo->gray;
1653 mask |= GCStipple;
1654 #endif
1655 relief->gc = XCreateGC (NULL, FRAME_W32_WINDOW (f), mask, &xgcv);
1657 else
1658 XChangeGC (NULL, relief->gc, mask, &xgcv);
1662 /* Set up colors for the relief lines around glyph string S. */
1664 static void
1665 x_setup_relief_colors (struct glyph_string *s)
1667 struct w32_output *di = s->f->output_data.w32;
1668 COLORREF color;
1670 if (s->face->use_box_color_for_shadows_p)
1671 color = s->face->box_color;
1672 else if (s->first_glyph->type == IMAGE_GLYPH
1673 && s->img->pixmap
1674 && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
1675 color = IMAGE_BACKGROUND (s->img, s->f, 0);
1676 else
1677 color = s->gc->background;
1679 if (di->white_relief.gc == 0
1680 || color != di->relief_background)
1682 di->relief_background = color;
1683 w32_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000,
1684 WHITE_PIX_DEFAULT (s->f));
1685 w32_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000,
1686 BLACK_PIX_DEFAULT (s->f));
1691 /* Draw a relief on frame F inside the rectangle given by LEFT_X,
1692 TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief
1693 to draw, it must be >= 0. RAISED_P non-zero means draw a raised
1694 relief. LEFT_P non-zero means draw a relief on the left side of
1695 the rectangle. RIGHT_P non-zero means draw a relief on the right
1696 side of the rectangle. CLIP_RECT is the clipping rectangle to use
1697 when drawing. */
1699 static void
1700 w32_draw_relief_rect (struct frame *f,
1701 int left_x, int top_y, int right_x, int bottom_y,
1702 int width, int raised_p,
1703 int top_p, int bot_p, int left_p, int right_p,
1704 RECT *clip_rect)
1706 int i;
1707 XGCValues gc;
1708 HDC hdc = get_frame_dc (f);
1710 if (raised_p)
1711 gc.foreground = f->output_data.w32->white_relief.gc->foreground;
1712 else
1713 gc.foreground = f->output_data.w32->black_relief.gc->foreground;
1715 w32_set_clip_rectangle (hdc, clip_rect);
1717 /* Top. */
1718 if (top_p)
1719 for (i = 0; i < width; ++i)
1720 w32_fill_area (f, hdc, gc.foreground,
1721 left_x + i * left_p, top_y + i,
1722 right_x - left_x - i * (left_p + right_p ) + 1, 1);
1724 /* Left. */
1725 if (left_p)
1726 for (i = 0; i < width; ++i)
1727 w32_fill_area (f, hdc, gc.foreground,
1728 left_x + i, top_y + (i + 1) * top_p, 1,
1729 bottom_y - top_y - (i + 1) * (bot_p + top_p) + 1);
1731 if (raised_p)
1732 gc.foreground = f->output_data.w32->black_relief.gc->foreground;
1733 else
1734 gc.foreground = f->output_data.w32->white_relief.gc->foreground;
1736 /* Bottom. */
1737 if (bot_p)
1738 for (i = 0; i < width; ++i)
1739 w32_fill_area (f, hdc, gc.foreground,
1740 left_x + i * left_p, bottom_y - i,
1741 right_x - left_x - i * (left_p + right_p) + 1, 1);
1743 /* Right. */
1744 if (right_p)
1745 for (i = 0; i < width; ++i)
1746 w32_fill_area (f, hdc, gc.foreground,
1747 right_x - i, top_y + (i + 1) * top_p, 1,
1748 bottom_y - top_y - (i + 1) * (bot_p + top_p) + 1);
1750 w32_set_clip_rectangle (hdc, NULL);
1752 release_frame_dc (f, hdc);
1756 /* Draw a box on frame F inside the rectangle given by LEFT_X, TOP_Y,
1757 RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the lines to
1758 draw, it must be >= 0. LEFT_P non-zero means draw a line on the
1759 left side of the rectangle. RIGHT_P non-zero means draw a line
1760 on the right side of the rectangle. CLIP_RECT is the clipping
1761 rectangle to use when drawing. */
1763 static void
1764 w32_draw_box_rect (struct glyph_string *s,
1765 int left_x, int top_y, int right_x, int bottom_y, int width,
1766 bool left_p, bool right_p, RECT *clip_rect)
1768 w32_set_clip_rectangle (s->hdc, clip_rect);
1770 /* Top. */
1771 w32_fill_area (s->f, s->hdc, s->face->box_color,
1772 left_x, top_y, right_x - left_x + 1, width);
1774 /* Left. */
1775 if (left_p)
1777 w32_fill_area (s->f, s->hdc, s->face->box_color,
1778 left_x, top_y, width, bottom_y - top_y + 1);
1781 /* Bottom. */
1782 w32_fill_area (s->f, s->hdc, s->face->box_color,
1783 left_x, bottom_y - width + 1, right_x - left_x + 1, width);
1785 /* Right. */
1786 if (right_p)
1788 w32_fill_area (s->f, s->hdc, s->face->box_color,
1789 right_x - width + 1, top_y, width, bottom_y - top_y + 1);
1792 w32_set_clip_rectangle (s->hdc, NULL);
1796 /* Draw a box around glyph string S. */
1798 static void
1799 x_draw_glyph_string_box (struct glyph_string *s)
1801 int width, left_x, right_x, top_y, bottom_y, last_x;
1802 bool left_p, right_p, raised_p;
1803 struct glyph *last_glyph;
1804 RECT clip_rect;
1806 last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
1807 ? WINDOW_RIGHT_EDGE_X (s->w)
1808 : window_box_right (s->w, s->area));
1810 /* The glyph that may have a right box line. */
1811 last_glyph = (s->cmp || s->img
1812 ? s->first_glyph
1813 : s->first_glyph + s->nchars - 1);
1815 width = eabs (s->face->box_line_width);
1816 raised_p = s->face->box == FACE_RAISED_BOX;
1817 left_x = s->x;
1818 right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
1819 ? last_x - 1
1820 : min (last_x, s->x + s->background_width) - 1));
1821 top_y = s->y;
1822 bottom_y = top_y + s->height - 1;
1824 left_p = (s->first_glyph->left_box_line_p
1825 || (s->hl == DRAW_MOUSE_FACE
1826 && (s->prev == NULL
1827 || s->prev->hl != s->hl)));
1828 right_p = (last_glyph->right_box_line_p
1829 || (s->hl == DRAW_MOUSE_FACE
1830 && (s->next == NULL
1831 || s->next->hl != s->hl)));
1833 get_glyph_string_clip_rect (s, &clip_rect);
1835 if (s->face->box == FACE_SIMPLE_BOX)
1836 w32_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
1837 left_p, right_p, &clip_rect);
1838 else
1840 x_setup_relief_colors (s);
1841 w32_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y,
1842 width, raised_p, 1, 1, left_p, right_p, &clip_rect);
1847 /* Draw foreground of image glyph string S. */
1849 static void
1850 x_draw_image_foreground (struct glyph_string *s)
1852 int x = s->x;
1853 int y = s->ybase - image_ascent (s->img, s->face, &s->slice);
1855 /* If first glyph of S has a left box line, start drawing it to the
1856 right of that line. */
1857 if (s->face->box != FACE_NO_BOX
1858 && s->first_glyph->left_box_line_p
1859 && s->slice.x == 0)
1860 x += eabs (s->face->box_line_width);
1862 /* If there is a margin around the image, adjust x- and y-position
1863 by that margin. */
1864 if (s->slice.x == 0)
1865 x += s->img->hmargin;
1866 if (s->slice.y == 0)
1867 y += s->img->vmargin;
1869 SaveDC (s->hdc);
1871 if (s->img->pixmap)
1873 HDC compat_hdc = CreateCompatibleDC (s->hdc);
1874 HBRUSH fg_brush = CreateSolidBrush (s->gc->foreground);
1875 HBRUSH orig_brush = SelectObject (s->hdc, fg_brush);
1876 HGDIOBJ orig_obj = SelectObject (compat_hdc, s->img->pixmap);
1877 SetBkColor (compat_hdc, RGB (255, 255, 255));
1878 SetTextColor (s->hdc, RGB (0, 0, 0));
1879 x_set_glyph_string_clipping (s);
1881 if (s->img->mask)
1883 HDC mask_dc = CreateCompatibleDC (s->hdc);
1884 HGDIOBJ mask_orig_obj = SelectObject (mask_dc, s->img->mask);
1886 SetTextColor (s->hdc, RGB (255, 255, 255));
1887 SetBkColor (s->hdc, RGB (0, 0, 0));
1889 BitBlt (s->hdc, x, y, s->slice.width, s->slice.height,
1890 compat_hdc, s->slice.x, s->slice.y, SRCINVERT);
1891 BitBlt (s->hdc, x, y, s->slice.width, s->slice.height,
1892 mask_dc, s->slice.x, s->slice.y, SRCAND);
1893 BitBlt (s->hdc, x, y, s->slice.width, s->slice.height,
1894 compat_hdc, s->slice.x, s->slice.y, SRCINVERT);
1896 SelectObject (mask_dc, mask_orig_obj);
1897 DeleteDC (mask_dc);
1899 else
1901 SetTextColor (s->hdc, s->gc->foreground);
1902 SetBkColor (s->hdc, s->gc->background);
1904 BitBlt (s->hdc, x, y, s->slice.width, s->slice.height,
1905 compat_hdc, s->slice.x, s->slice.y, SRCCOPY);
1907 /* When the image has a mask, we can expect that at
1908 least part of a mouse highlight or a block cursor will
1909 be visible. If the image doesn't have a mask, make
1910 a block cursor visible by drawing a rectangle around
1911 the image. I believe it's looking better if we do
1912 nothing here for mouse-face. */
1913 if (s->hl == DRAW_CURSOR)
1915 int r = s->img->relief;
1916 if (r < 0) r = -r;
1917 w32_draw_rectangle (s->hdc, s->gc, x - r, y - r ,
1918 s->slice.width + r*2 - 1,
1919 s->slice.height + r*2 - 1);
1923 w32_set_clip_rectangle (s->hdc, NULL);
1924 SelectObject (s->hdc, orig_brush);
1925 DeleteObject (fg_brush);
1926 SelectObject (compat_hdc, orig_obj);
1927 DeleteDC (compat_hdc);
1929 else
1930 w32_draw_rectangle (s->hdc, s->gc, x, y,
1931 s->slice.width - 1, s->slice.height - 1);
1933 RestoreDC (s->hdc ,-1);
1937 /* Draw a relief around the image glyph string S. */
1939 static void
1940 x_draw_image_relief (struct glyph_string *s)
1942 int x1, y1, thick, raised_p, top_p, bot_p, left_p, right_p;
1943 int extra_x, extra_y;
1944 RECT r;
1945 int x = s->x;
1946 int y = s->ybase - image_ascent (s->img, s->face, &s->slice);
1948 /* If first glyph of S has a left box line, start drawing it to the
1949 right of that line. */
1950 if (s->face->box != FACE_NO_BOX
1951 && s->first_glyph->left_box_line_p
1952 && s->slice.x == 0)
1953 x += eabs (s->face->box_line_width);
1955 /* If there is a margin around the image, adjust x- and y-position
1956 by that margin. */
1957 if (s->slice.x == 0)
1958 x += s->img->hmargin;
1959 if (s->slice.y == 0)
1960 y += s->img->vmargin;
1962 if (s->hl == DRAW_IMAGE_SUNKEN
1963 || s->hl == DRAW_IMAGE_RAISED)
1965 thick = tool_bar_button_relief >= 0 ? tool_bar_button_relief
1966 : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
1967 raised_p = s->hl == DRAW_IMAGE_RAISED;
1969 else
1971 thick = eabs (s->img->relief);
1972 raised_p = s->img->relief > 0;
1975 x1 = x + s->slice.width - 1;
1976 y1 = y + s->slice.height - 1;
1978 extra_x = extra_y = 0;
1979 if (s->face->id == TOOL_BAR_FACE_ID)
1981 if (CONSP (Vtool_bar_button_margin)
1982 && INTEGERP (XCAR (Vtool_bar_button_margin))
1983 && INTEGERP (XCDR (Vtool_bar_button_margin)))
1985 extra_x = XINT (XCAR (Vtool_bar_button_margin));
1986 extra_y = XINT (XCDR (Vtool_bar_button_margin));
1988 else if (INTEGERP (Vtool_bar_button_margin))
1989 extra_x = extra_y = XINT (Vtool_bar_button_margin);
1992 top_p = bot_p = left_p = right_p = 0;
1994 if (s->slice.x == 0)
1995 x -= thick + extra_x, left_p = 1;
1996 if (s->slice.y == 0)
1997 y -= thick + extra_y, top_p = 1;
1998 if (s->slice.x + s->slice.width == s->img->width)
1999 x1 += thick + extra_x, right_p = 1;
2000 if (s->slice.y + s->slice.height == s->img->height)
2001 y1 += thick + extra_y, bot_p = 1;
2003 x_setup_relief_colors (s);
2004 get_glyph_string_clip_rect (s, &r);
2005 w32_draw_relief_rect (s->f, x, y, x1, y1, thick, raised_p,
2006 top_p, bot_p, left_p, right_p, &r);
2010 /* Draw the foreground of image glyph string S to PIXMAP. */
2012 static void
2013 w32_draw_image_foreground_1 (struct glyph_string *s, HBITMAP pixmap)
2015 HDC hdc = CreateCompatibleDC (s->hdc);
2016 HGDIOBJ orig_hdc_obj = SelectObject (hdc, pixmap);
2017 int x = 0;
2018 int y = s->ybase - s->y - image_ascent (s->img, s->face, &s->slice);
2020 /* If first glyph of S has a left box line, start drawing it to the
2021 right of that line. */
2022 if (s->face->box != FACE_NO_BOX
2023 && s->first_glyph->left_box_line_p
2024 && s->slice.x == 0)
2025 x += eabs (s->face->box_line_width);
2027 /* If there is a margin around the image, adjust x- and y-position
2028 by that margin. */
2029 if (s->slice.x == 0)
2030 x += s->img->hmargin;
2031 if (s->slice.y == 0)
2032 y += s->img->vmargin;
2034 if (s->img->pixmap)
2036 HDC compat_hdc = CreateCompatibleDC (hdc);
2037 HBRUSH fg_brush = CreateSolidBrush (s->gc->foreground);
2038 HBRUSH orig_brush = SelectObject (hdc, fg_brush);
2039 HGDIOBJ orig_obj = SelectObject (compat_hdc, s->img->pixmap);
2041 if (s->img->mask)
2043 HDC mask_dc = CreateCompatibleDC (hdc);
2044 HGDIOBJ mask_orig_obj = SelectObject (mask_dc, s->img->mask);
2046 SetTextColor (hdc, RGB (0, 0, 0));
2047 SetBkColor (hdc, RGB (255, 255, 255));
2048 BitBlt (hdc, x, y, s->slice.width, s->slice.height,
2049 compat_hdc, s->slice.x, s->slice.y, SRCINVERT);
2050 BitBlt (hdc, x, y, s->slice.width, s->slice.height,
2051 mask_dc, s->slice.x, s->slice.y, SRCAND);
2052 BitBlt (hdc, x, y, s->slice.width, s->slice.height,
2053 compat_hdc, s->slice.x, s->slice.y, SRCINVERT);
2055 SelectObject (mask_dc, mask_orig_obj);
2056 DeleteDC (mask_dc);
2058 else
2060 SetTextColor (hdc, s->gc->foreground);
2061 SetBkColor (hdc, s->gc->background);
2063 BitBlt (hdc, x, y, s->slice.width, s->slice.height,
2064 compat_hdc, s->slice.x, s->slice.y, SRCCOPY);
2066 /* When the image has a mask, we can expect that at
2067 least part of a mouse highlight or a block cursor will
2068 be visible. If the image doesn't have a mask, make
2069 a block cursor visible by drawing a rectangle around
2070 the image. I believe it's looking better if we do
2071 nothing here for mouse-face. */
2072 if (s->hl == DRAW_CURSOR)
2074 int r = s->img->relief;
2075 if (r < 0) r = -r;
2076 w32_draw_rectangle (hdc, s->gc, x - r, y - r,
2077 s->slice.width + r*2 - 1,
2078 s->slice.height + r*2 - 1);
2082 SelectObject (hdc, orig_brush);
2083 DeleteObject (fg_brush);
2084 SelectObject (compat_hdc, orig_obj);
2085 DeleteDC (compat_hdc);
2087 else
2088 w32_draw_rectangle (hdc, s->gc, x, y,
2089 s->slice.width - 1, s->slice.height - 1);
2091 SelectObject (hdc, orig_hdc_obj);
2092 DeleteDC (hdc);
2096 /* Draw part of the background of glyph string S. X, Y, W, and H
2097 give the rectangle to draw. */
2099 static void
2100 x_draw_glyph_string_bg_rect (struct glyph_string *s, int x, int y, int w, int h)
2102 #if 0 /* TODO: stipple */
2103 if (s->stippled_p)
2105 /* Fill background with a stipple pattern. */
2106 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
2107 XFillRectangle (s->display, FRAME_W32_WINDOW (s->f), s->gc, x, y, w, h);
2108 XSetFillStyle (s->display, s->gc, FillSolid);
2110 else
2111 #endif
2112 x_clear_glyph_string_rect (s, x, y, w, h);
2116 /* Draw image glyph string S.
2118 s->y
2119 s->x +-------------------------
2120 | s->face->box
2122 | +-------------------------
2123 | | s->img->vmargin
2125 | | +-------------------
2126 | | | the image
2130 static void
2131 x_draw_image_glyph_string (struct glyph_string *s)
2133 int x, y;
2134 int box_line_hwidth = eabs (s->face->box_line_width);
2135 int box_line_vwidth = max (s->face->box_line_width, 0);
2136 int height, width;
2137 HBITMAP pixmap = 0;
2139 height = s->height;
2140 if (s->slice.y == 0)
2141 height -= box_line_vwidth;
2142 if (s->slice.y + s->slice.height >= s->img->height)
2143 height -= box_line_vwidth;
2145 /* Fill background with face under the image. Do it only if row is
2146 taller than image or if image has a clip mask to reduce
2147 flickering. */
2148 s->stippled_p = s->face->stipple != 0;
2149 if (height > s->slice.height
2150 || s->img->hmargin
2151 || s->img->vmargin
2152 || s->img->mask
2153 || s->img->pixmap == 0
2154 || s->width != s->background_width)
2156 width = s->background_width;
2157 x = s->x;
2158 if (s->first_glyph->left_box_line_p
2159 && s->slice.x == 0)
2161 x += box_line_hwidth;
2162 width -= box_line_hwidth;
2165 y = s->y;
2166 if (s->slice.y == 0)
2167 y += box_line_vwidth;
2169 #if 0 /* TODO: figure out if we need to do this on Windows. */
2170 if (s->img->mask)
2172 /* Create a pixmap as large as the glyph string. Fill it
2173 with the background color. Copy the image to it, using
2174 its mask. Copy the temporary pixmap to the display. */
2175 Screen *screen = FRAME_X_SCREEN (s->f);
2176 int depth = DefaultDepthOfScreen (screen);
2178 /* Create a pixmap as large as the glyph string. */
2179 pixmap = XCreatePixmap (s->display, FRAME_W32_WINDOW (s->f),
2180 s->background_width,
2181 s->height, depth);
2183 /* Don't clip in the following because we're working on the
2184 pixmap. */
2185 XSetClipMask (s->display, s->gc, None);
2187 /* Fill the pixmap with the background color/stipple. */
2188 if (s->stippled_p)
2190 /* Fill background with a stipple pattern. */
2191 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
2192 XFillRectangle (s->display, pixmap, s->gc,
2193 0, 0, s->background_width, s->height);
2194 XSetFillStyle (s->display, s->gc, FillSolid);
2196 else
2198 XGCValues xgcv;
2199 XGetGCValues (s->display, s->gc, GCForeground | GCBackground,
2200 &xgcv);
2201 XSetForeground (s->display, s->gc, xgcv.background);
2202 XFillRectangle (s->display, pixmap, s->gc,
2203 0, 0, s->background_width, s->height);
2204 XSetForeground (s->display, s->gc, xgcv.foreground);
2207 else
2208 #endif
2209 x_draw_glyph_string_bg_rect (s, x, y, width, height);
2211 s->background_filled_p = true;
2214 /* Draw the foreground. */
2215 if (pixmap != 0)
2217 w32_draw_image_foreground_1 (s, pixmap);
2218 x_set_glyph_string_clipping (s);
2220 HDC compat_hdc = CreateCompatibleDC (s->hdc);
2221 HBRUSH fg_brush = CreateSolidBrush (s->gc->foreground);
2222 HBRUSH orig_brush = SelectObject (s->hdc, fg_brush);
2223 HGDIOBJ orig_obj = SelectObject (compat_hdc, pixmap);
2225 SetTextColor (s->hdc, s->gc->foreground);
2226 SetBkColor (s->hdc, s->gc->background);
2227 BitBlt (s->hdc, s->x, s->y, s->background_width, s->height,
2228 compat_hdc, 0, 0, SRCCOPY);
2230 SelectObject (s->hdc, orig_brush);
2231 DeleteObject (fg_brush);
2232 SelectObject (compat_hdc, orig_obj);
2233 DeleteDC (compat_hdc);
2235 DeleteObject (pixmap);
2236 pixmap = 0;
2238 else
2239 x_draw_image_foreground (s);
2241 /* If we must draw a relief around the image, do it. */
2242 if (s->img->relief
2243 || s->hl == DRAW_IMAGE_RAISED
2244 || s->hl == DRAW_IMAGE_SUNKEN)
2245 x_draw_image_relief (s);
2249 /* Draw stretch glyph string S. */
2251 static void
2252 x_draw_stretch_glyph_string (struct glyph_string *s)
2254 eassert (s->first_glyph->type == STRETCH_GLYPH);
2256 if (s->hl == DRAW_CURSOR
2257 && !x_stretch_cursor_p)
2259 /* If `x-stretch-cursor' is nil, don't draw a block cursor as
2260 wide as the stretch glyph. */
2261 int width, background_width = s->background_width;
2262 int x = s->x;
2264 if (!s->row->reversed_p)
2266 int left_x = window_box_left_offset (s->w, TEXT_AREA);
2268 if (x < left_x)
2270 background_width -= left_x - x;
2271 x = left_x;
2274 else
2276 /* In R2L rows, draw the cursor on the right edge of the
2277 stretch glyph. */
2278 int right_x = window_box_right (s->w, TEXT_AREA);
2280 if (x + background_width > right_x)
2281 background_width -= x - right_x;
2282 x += background_width;
2284 width = min (FRAME_COLUMN_WIDTH (s->f), background_width);
2285 if (s->row->reversed_p)
2286 x -= width;
2288 /* Draw cursor. */
2289 x_draw_glyph_string_bg_rect (s, x, s->y, width, s->height);
2291 /* Clear rest using the GC of the original non-cursor face. */
2292 if (width < background_width)
2294 XGCValues *gc = s->face->gc;
2295 int y = s->y;
2296 int w = background_width - width, h = s->height;
2297 RECT r;
2298 HDC hdc = s->hdc;
2300 if (!s->row->reversed_p)
2301 x += width;
2302 else
2303 x = s->x;
2304 if (s->row->mouse_face_p
2305 && cursor_in_mouse_face_p (s->w))
2307 x_set_mouse_face_gc (s);
2308 gc = s->gc;
2310 else
2311 gc = s->face->gc;
2313 get_glyph_string_clip_rect (s, &r);
2314 w32_set_clip_rectangle (hdc, &r);
2316 #if 0 /* TODO: stipple */
2317 if (s->face->stipple)
2319 /* Fill background with a stipple pattern. */
2320 XSetFillStyle (s->display, gc, FillOpaqueStippled);
2321 XFillRectangle (s->display, FRAME_W32_WINDOW (s->f), gc, x, y, w, h);
2322 XSetFillStyle (s->display, gc, FillSolid);
2324 else
2325 #endif
2327 w32_fill_area (s->f, s->hdc, gc->background, x, y, w, h);
2331 else if (!s->background_filled_p)
2333 int background_width = s->background_width;
2334 int x = s->x, left_x = window_box_left_offset (s->w, TEXT_AREA);
2336 /* Don't draw into left margin, fringe or scrollbar area
2337 except for header line and mode line. */
2338 if (x < left_x && !s->row->mode_line_p)
2340 background_width -= left_x - x;
2341 x = left_x;
2343 if (background_width > 0)
2344 x_draw_glyph_string_bg_rect (s, x, s->y, background_width, s->height);
2347 s->background_filled_p = true;
2351 /* Draw glyph string S. */
2353 static void
2354 x_draw_glyph_string (struct glyph_string *s)
2356 bool relief_drawn_p = 0;
2358 /* If S draws into the background of its successor, draw the
2359 background of the successor first so that S can draw into it.
2360 This makes S->next use XDrawString instead of XDrawImageString. */
2361 if (s->next && s->right_overhang && !s->for_overlaps)
2363 int width;
2364 struct glyph_string *next;
2365 for (width = 0, next = s->next;
2366 next && width < s->right_overhang;
2367 width += next->width, next = next->next)
2368 if (next->first_glyph->type != IMAGE_GLYPH)
2370 x_set_glyph_string_gc (next);
2371 x_set_glyph_string_clipping (next);
2372 if (next->first_glyph->type == STRETCH_GLYPH)
2373 x_draw_stretch_glyph_string (next);
2374 else
2375 x_draw_glyph_string_background (next, true);
2376 next->num_clips = 0;
2380 /* Set up S->gc, set clipping and draw S. */
2381 x_set_glyph_string_gc (s);
2383 /* Draw relief (if any) in advance for char/composition so that the
2384 glyph string can be drawn over it. */
2385 if (!s->for_overlaps
2386 && s->face->box != FACE_NO_BOX
2387 && (s->first_glyph->type == CHAR_GLYPH
2388 || s->first_glyph->type == COMPOSITE_GLYPH))
2391 x_set_glyph_string_clipping (s);
2392 x_draw_glyph_string_background (s, true);
2393 x_draw_glyph_string_box (s);
2394 x_set_glyph_string_clipping (s);
2395 relief_drawn_p = 1;
2397 else if (!s->clip_head /* draw_glyphs didn't specify a clip mask. */
2398 && !s->clip_tail
2399 && ((s->prev && s->prev->hl != s->hl && s->left_overhang)
2400 || (s->next && s->next->hl != s->hl && s->right_overhang)))
2401 /* We must clip just this glyph. left_overhang part has already
2402 drawn when s->prev was drawn, and right_overhang part will be
2403 drawn later when s->next is drawn. */
2404 x_set_glyph_string_clipping_exactly (s, s);
2405 else
2406 x_set_glyph_string_clipping (s);
2408 switch (s->first_glyph->type)
2410 case IMAGE_GLYPH:
2411 x_draw_image_glyph_string (s);
2412 break;
2414 case STRETCH_GLYPH:
2415 x_draw_stretch_glyph_string (s);
2416 break;
2418 case CHAR_GLYPH:
2419 if (s->for_overlaps)
2420 s->background_filled_p = true;
2421 else
2422 x_draw_glyph_string_background (s, false);
2423 x_draw_glyph_string_foreground (s);
2424 break;
2426 case COMPOSITE_GLYPH:
2427 if (s->for_overlaps || (s->cmp_from > 0
2428 && ! s->first_glyph->u.cmp.automatic))
2429 s->background_filled_p = true;
2430 else
2431 x_draw_glyph_string_background (s, true);
2432 x_draw_composite_glyph_string_foreground (s);
2433 break;
2435 case GLYPHLESS_GLYPH:
2436 if (s->for_overlaps)
2437 s->background_filled_p = true;
2438 else
2439 x_draw_glyph_string_background (s, false);
2440 x_draw_glyphless_glyph_string_foreground (s);
2441 break;
2443 default:
2444 emacs_abort ();
2447 if (!s->for_overlaps)
2449 /* Draw underline. */
2450 if (s->face->underline_p)
2452 if (s->face->underline_type == FACE_UNDER_WAVE)
2454 COLORREF color;
2456 if (s->face->underline_defaulted_p)
2457 color = s->gc->foreground;
2458 else
2459 color = s->face->underline_color;
2461 w32_draw_underwave (s, color);
2463 else if (s->face->underline_type == FACE_UNDER_LINE)
2465 unsigned long thickness, position;
2466 int y;
2468 if (s->prev && s->prev->face->underline_p
2469 && s->prev->face->underline_type == FACE_UNDER_LINE)
2471 /* We use the same underline style as the previous one. */
2472 thickness = s->prev->underline_thickness;
2473 position = s->prev->underline_position;
2475 else
2477 struct font *font = font_for_underline_metrics (s);
2478 unsigned long minimum_offset;
2479 BOOL underline_at_descent_line;
2480 BOOL use_underline_position_properties;
2481 Lisp_Object val
2482 = buffer_local_value (Qunderline_minimum_offset,
2483 s->w->contents);
2484 if (INTEGERP (val))
2485 minimum_offset = XFASTINT (val);
2486 else
2487 minimum_offset = 1;
2488 val = buffer_local_value (Qx_underline_at_descent_line,
2489 s->w->contents);
2490 underline_at_descent_line
2491 = !(NILP (val) || EQ (val, Qunbound));
2493 = buffer_local_value (Qx_use_underline_position_properties,
2494 s->w->contents);
2495 use_underline_position_properties
2496 = !(NILP (val) || EQ (val, Qunbound));
2498 /* Get the underline thickness. Default is 1 pixel. */
2499 if (font && font->underline_thickness > 0)
2500 thickness = font->underline_thickness;
2501 else
2502 thickness = 1;
2503 if (underline_at_descent_line
2504 || !font)
2505 position = (s->height - thickness) - (s->ybase - s->y);
2506 else
2508 /* Get the underline position. This is the
2509 recommended vertical offset in pixels from
2510 the baseline to the top of the underline.
2511 This is a signed value according to the
2512 specs, and its default is
2514 ROUND ((maximum_descent) / 2), with
2515 ROUND (x) = floor (x + 0.5) */
2517 if (use_underline_position_properties
2518 && font->underline_position >= 0)
2519 position = font->underline_position;
2520 else
2521 position = (font->descent + 1) / 2;
2523 position = max (position, minimum_offset);
2525 /* Check the sanity of thickness and position. We should
2526 avoid drawing underline out of the current line area. */
2527 if (s->y + s->height <= s->ybase + position)
2528 position = (s->height - 1) - (s->ybase - s->y);
2529 if (s->y + s->height < s->ybase + position + thickness)
2530 thickness = (s->y + s->height) - (s->ybase + position);
2531 s->underline_thickness = thickness;
2532 s->underline_position = position;
2533 y = s->ybase + position;
2534 if (s->face->underline_defaulted_p)
2536 w32_fill_area (s->f, s->hdc, s->gc->foreground, s->x,
2537 y, s->width, 1);
2539 else
2541 w32_fill_area (s->f, s->hdc, s->face->underline_color, s->x,
2542 y, s->width, 1);
2546 /* Draw overline. */
2547 if (s->face->overline_p)
2549 unsigned long dy = 0, h = 1;
2551 if (s->face->overline_color_defaulted_p)
2553 w32_fill_area (s->f, s->hdc, s->gc->foreground, s->x,
2554 s->y + dy, s->width, h);
2556 else
2558 w32_fill_area (s->f, s->hdc, s->face->overline_color, s->x,
2559 s->y + dy, s->width, h);
2563 /* Draw strike-through. */
2564 if (s->face->strike_through_p
2565 && !FONT_TEXTMETRIC (s->font).tmStruckOut)
2567 /* Y-coordinate and height of the glyph string's first
2568 glyph. We cannot use s->y and s->height because those
2569 could be larger if there are taller display elements
2570 (e.g., characters displayed with a larger font) in the
2571 same glyph row. */
2572 int glyph_y = s->ybase - s->first_glyph->ascent;
2573 int glyph_height = s->first_glyph->ascent + s->first_glyph->descent;
2574 /* Strike-through width and offset from the glyph string's
2575 top edge. */
2576 unsigned long h = 1;
2577 unsigned long dy = (glyph_height - h) / 2;
2579 if (s->face->strike_through_color_defaulted_p)
2581 w32_fill_area (s->f, s->hdc, s->gc->foreground, s->x,
2582 glyph_y + dy, s->width, h);
2584 else
2586 w32_fill_area (s->f, s->hdc, s->face->strike_through_color, s->x,
2587 glyph_y + dy, s->width, h);
2591 /* Draw relief if not yet drawn. */
2592 if (!relief_drawn_p && s->face->box != FACE_NO_BOX)
2593 x_draw_glyph_string_box (s);
2595 if (s->prev)
2597 struct glyph_string *prev;
2599 for (prev = s->prev; prev; prev = prev->prev)
2600 if (prev->hl != s->hl
2601 && prev->x + prev->width + prev->right_overhang > s->x)
2603 /* As prev was drawn while clipped to its own area, we
2604 must draw the right_overhang part using s->hl now. */
2605 enum draw_glyphs_face save = prev->hl;
2607 prev->hl = s->hl;
2608 x_set_glyph_string_gc (prev);
2609 x_set_glyph_string_clipping_exactly (s, prev);
2610 if (prev->first_glyph->type == CHAR_GLYPH)
2611 x_draw_glyph_string_foreground (prev);
2612 else
2613 x_draw_composite_glyph_string_foreground (prev);
2614 w32_set_clip_rectangle (prev->hdc, NULL);
2615 prev->hl = save;
2616 prev->num_clips = 0;
2620 if (s->next)
2622 struct glyph_string *next;
2624 for (next = s->next; next; next = next->next)
2625 if (next->hl != s->hl
2626 && next->x - next->left_overhang < s->x + s->width)
2628 /* As next will be drawn while clipped to its own area,
2629 we must draw the left_overhang part using s->hl now. */
2630 enum draw_glyphs_face save = next->hl;
2632 next->hl = s->hl;
2633 x_set_glyph_string_gc (next);
2634 x_set_glyph_string_clipping_exactly (s, next);
2635 if (next->first_glyph->type == CHAR_GLYPH)
2636 x_draw_glyph_string_foreground (next);
2637 else
2638 x_draw_composite_glyph_string_foreground (next);
2639 w32_set_clip_rectangle (next->hdc, NULL);
2640 next->hl = save;
2641 next->num_clips = 0;
2642 next->clip_head = s->next;
2647 /* Reset clipping. */
2648 w32_set_clip_rectangle (s->hdc, NULL);
2649 s->num_clips = 0;
2653 /* Shift display to make room for inserted glyphs. */
2655 static void
2656 w32_shift_glyphs_for_insert (struct frame *f, int x, int y,
2657 int width, int height, int shift_by)
2659 HDC hdc;
2661 hdc = get_frame_dc (f);
2662 BitBlt (hdc, x + shift_by, y, width, height,
2663 hdc, x, y, SRCCOPY);
2665 release_frame_dc (f, hdc);
2669 /* Delete N glyphs at the nominal cursor position. Not implemented
2670 for X frames. */
2672 static void
2673 x_delete_glyphs (struct frame *f, register int n)
2675 if (! FRAME_W32_P (f))
2676 return;
2678 emacs_abort ();
2682 /* Clear entire frame. */
2684 static void
2685 x_clear_frame (struct frame *f)
2687 if (! FRAME_W32_P (f))
2688 return;
2690 /* Clearing the frame will erase any cursor, so mark them all as no
2691 longer visible. */
2692 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2694 block_input ();
2696 w32_clear_window (f);
2698 /* We have to clear the scroll bars, too. If we have changed
2699 colors or something like that, then they should be notified. */
2700 x_scroll_bar_clear (f);
2702 unblock_input ();
2706 /* Make audible bell. */
2708 static void
2709 w32_ring_bell (struct frame *f)
2711 block_input ();
2713 if (FRAME_W32_P (f) && visible_bell)
2715 int i;
2716 HWND hwnd = FRAME_W32_WINDOW (f);
2718 for (i = 0; i < 5; i++)
2720 FlashWindow (hwnd, TRUE);
2721 Sleep (10);
2723 FlashWindow (hwnd, FALSE);
2725 else
2726 w32_sys_ring_bell (f);
2728 unblock_input ();
2731 /***********************************************************************
2732 Line Dance
2733 ***********************************************************************/
2735 /* Perform an insert-lines or delete-lines operation, inserting N
2736 lines or deleting -N lines at vertical position VPOS. */
2738 static void
2739 x_ins_del_lines (struct frame *f, int vpos, int n)
2741 if (! FRAME_W32_P (f))
2742 return;
2744 emacs_abort ();
2748 /* Scroll part of the display as described by RUN. */
2750 static void
2751 x_scroll_run (struct window *w, struct run *run)
2753 struct frame *f = XFRAME (w->frame);
2754 int x, y, width, height, from_y, to_y, bottom_y;
2755 HWND hwnd = FRAME_W32_WINDOW (f);
2756 HRGN expect_dirty;
2758 /* Get frame-relative bounding box of the text display area of W,
2759 without mode lines. Include in this box the left and right
2760 fringes of W. */
2761 window_box (w, ANY_AREA, &x, &y, &width, &height);
2763 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2764 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2765 bottom_y = y + height;
2767 if (to_y < from_y)
2769 /* Scrolling up. Make sure we don't copy part of the mode
2770 line at the bottom. */
2771 if (from_y + run->height > bottom_y)
2772 height = bottom_y - from_y;
2773 else
2774 height = run->height;
2775 expect_dirty = CreateRectRgn (x, y + height, x + width, bottom_y);
2777 else
2779 /* Scrolling down. Make sure we don't copy over the mode line.
2780 at the bottom. */
2781 if (to_y + run->height > bottom_y)
2782 height = bottom_y - to_y;
2783 else
2784 height = run->height;
2785 expect_dirty = CreateRectRgn (x, y, x + width, to_y);
2788 block_input ();
2790 /* Cursor off. Will be switched on again in x_update_window_end. */
2791 x_clear_cursor (w);
2794 RECT from;
2795 RECT to;
2796 HRGN dirty = CreateRectRgn (0, 0, 0, 0);
2797 HRGN combined = CreateRectRgn (0, 0, 0, 0);
2799 from.left = to.left = x;
2800 from.right = to.right = x + width;
2801 from.top = from_y;
2802 from.bottom = from_y + height;
2803 to.top = y;
2804 to.bottom = bottom_y;
2806 ScrollWindowEx (hwnd, 0, to_y - from_y, &from, &to, dirty,
2807 NULL, SW_INVALIDATE);
2809 /* Combine this with what we expect to be dirty. This covers the
2810 case where not all of the region we expect is actually dirty. */
2811 CombineRgn (combined, dirty, expect_dirty, RGN_OR);
2813 /* If the dirty region is not what we expected, redraw the entire frame. */
2814 if (!EqualRgn (combined, expect_dirty))
2815 SET_FRAME_GARBAGED (f);
2817 DeleteObject (dirty);
2818 DeleteObject (combined);
2821 unblock_input ();
2822 DeleteObject (expect_dirty);
2827 /***********************************************************************
2828 Exposure Events
2829 ***********************************************************************/
2831 static void
2832 frame_highlight (struct frame *f)
2834 x_update_cursor (f, 1);
2835 x_set_frame_alpha (f);
2838 static void
2839 frame_unhighlight (struct frame *f)
2841 x_update_cursor (f, 1);
2842 x_set_frame_alpha (f);
2845 /* The focus has changed. Update the frames as necessary to reflect
2846 the new situation. Note that we can't change the selected frame
2847 here, because the Lisp code we are interrupting might become confused.
2848 Each event gets marked with the frame in which it occurred, so the
2849 Lisp code can tell when the switch took place by examining the events. */
2851 static void
2852 x_new_focus_frame (struct w32_display_info *dpyinfo, struct frame *frame)
2854 struct frame *old_focus = dpyinfo->w32_focus_frame;
2856 if (frame != dpyinfo->w32_focus_frame)
2858 /* Set this before calling other routines, so that they see
2859 the correct value of w32_focus_frame. */
2860 dpyinfo->w32_focus_frame = frame;
2862 if (old_focus && old_focus->auto_lower)
2863 x_lower_frame (old_focus);
2865 if (dpyinfo->w32_focus_frame && dpyinfo->w32_focus_frame->auto_raise)
2866 dpyinfo->w32_pending_autoraise_frame = dpyinfo->w32_focus_frame;
2867 else
2868 dpyinfo->w32_pending_autoraise_frame = NULL;
2871 x_frame_rehighlight (dpyinfo);
2875 /* Handle FocusIn and FocusOut state changes for FRAME.
2876 If FRAME has focus and there exists more than one frame, puts
2877 a FOCUS_IN_EVENT into *BUFP. */
2879 static void
2880 x_focus_changed (int type, int state, struct w32_display_info *dpyinfo,
2881 struct frame *frame, struct input_event *bufp)
2883 if (type == WM_SETFOCUS)
2885 if (dpyinfo->w32_focus_event_frame != frame)
2887 x_new_focus_frame (dpyinfo, frame);
2888 dpyinfo->w32_focus_event_frame = frame;
2889 bufp->kind = FOCUS_IN_EVENT;
2890 XSETFRAME (bufp->frame_or_window, frame);
2893 frame->output_data.x->focus_state |= state;
2895 /* TODO: IME focus? */
2897 else if (type == WM_KILLFOCUS)
2899 frame->output_data.x->focus_state &= ~state;
2901 if (dpyinfo->w32_focus_event_frame == frame)
2903 dpyinfo->w32_focus_event_frame = 0;
2904 x_new_focus_frame (dpyinfo, 0);
2906 bufp->kind = FOCUS_OUT_EVENT;
2907 XSETFRAME (bufp->frame_or_window, frame);
2910 /* TODO: IME focus? */
2915 /* The focus may have changed. Figure out if it is a real focus change,
2916 by checking both FocusIn/Out and Enter/LeaveNotify events.
2918 Returns FOCUS_IN_EVENT event in *BUFP. */
2920 static void
2921 w32_detect_focus_change (struct w32_display_info *dpyinfo, W32Msg *event,
2922 struct input_event *bufp)
2924 struct frame *frame;
2926 frame = x_any_window_to_frame (dpyinfo, event->msg.hwnd);
2927 if (! frame)
2928 return;
2930 /* On w32, this is only called from focus events, so no switch needed. */
2931 x_focus_changed (event->msg.message,
2932 (event->msg.message == WM_KILLFOCUS ?
2933 FOCUS_IMPLICIT : FOCUS_EXPLICIT),
2934 dpyinfo, frame, bufp);
2938 #if 0 /* unused */
2939 /* Handle an event saying the mouse has moved out of an Emacs frame. */
2941 static void
2942 x_mouse_leave (struct w32_display_info *dpyinfo)
2944 x_new_focus_frame (dpyinfo, dpyinfo->w32_focus_event_frame);
2946 #endif
2948 /* The focus has changed, or we have redirected a frame's focus to
2949 another frame (this happens when a frame uses a surrogate
2950 mini-buffer frame). Shift the highlight as appropriate.
2952 The FRAME argument doesn't necessarily have anything to do with which
2953 frame is being highlighted or un-highlighted; we only use it to find
2954 the appropriate X display info. */
2956 static void
2957 w32_frame_rehighlight (struct frame *frame)
2959 if (! FRAME_W32_P (frame))
2960 return;
2961 x_frame_rehighlight (FRAME_DISPLAY_INFO (frame));
2964 static void
2965 x_frame_rehighlight (struct w32_display_info *dpyinfo)
2967 struct frame *old_highlight = dpyinfo->x_highlight_frame;
2969 if (dpyinfo->w32_focus_frame)
2971 dpyinfo->x_highlight_frame
2972 = ((FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->w32_focus_frame)))
2973 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->w32_focus_frame))
2974 : dpyinfo->w32_focus_frame);
2975 if (! FRAME_LIVE_P (dpyinfo->x_highlight_frame))
2977 fset_focus_frame (dpyinfo->w32_focus_frame, Qnil);
2978 dpyinfo->x_highlight_frame = dpyinfo->w32_focus_frame;
2981 else
2982 dpyinfo->x_highlight_frame = 0;
2984 if (dpyinfo->x_highlight_frame != old_highlight)
2986 if (old_highlight)
2987 frame_unhighlight (old_highlight);
2988 if (dpyinfo->x_highlight_frame)
2989 frame_highlight (dpyinfo->x_highlight_frame);
2993 /* Keyboard processing - modifier keys, etc. */
2995 /* Convert a keysym to its name. */
2997 char *
2998 x_get_keysym_name (int keysym)
3000 /* Make static so we can always return it */
3001 static char value[100];
3003 block_input ();
3004 GetKeyNameText (keysym, value, 100);
3005 unblock_input ();
3007 return value;
3010 static int
3011 codepage_for_locale (LCID locale)
3013 char cp[20];
3015 if (GetLocaleInfo (locale, LOCALE_IDEFAULTANSICODEPAGE, cp, 20) > 0)
3016 return atoi (cp);
3017 else
3018 return CP_ACP;
3022 /* Mouse clicks and mouse movement. Rah. */
3024 /* Parse a button MESSAGE. The button index is returned in PBUTTON, and
3025 the state in PUP. XBUTTON provides extra information for extended mouse
3026 button messages. Returns FALSE if unable to parse the message. */
3027 BOOL
3028 parse_button (int message, int xbutton, int * pbutton, int * pup)
3030 int button = 0;
3031 int up = 0;
3033 switch (message)
3035 case WM_LBUTTONDOWN:
3036 button = 0;
3037 up = 0;
3038 break;
3039 case WM_LBUTTONUP:
3040 button = 0;
3041 up = 1;
3042 break;
3043 case WM_MBUTTONDOWN:
3044 if (NILP (Vw32_swap_mouse_buttons))
3045 button = 1;
3046 else
3047 button = 2;
3048 up = 0;
3049 break;
3050 case WM_MBUTTONUP:
3051 if (NILP (Vw32_swap_mouse_buttons))
3052 button = 1;
3053 else
3054 button = 2;
3055 up = 1;
3056 break;
3057 case WM_RBUTTONDOWN:
3058 if (NILP (Vw32_swap_mouse_buttons))
3059 button = 2;
3060 else
3061 button = 1;
3062 up = 0;
3063 break;
3064 case WM_RBUTTONUP:
3065 if (NILP (Vw32_swap_mouse_buttons))
3066 button = 2;
3067 else
3068 button = 1;
3069 up = 1;
3070 break;
3071 case WM_XBUTTONDOWN:
3072 button = xbutton + 2;
3073 up = 0;
3074 break;
3075 case WM_XBUTTONUP:
3076 button = xbutton + 2;
3077 up = 1;
3078 break;
3079 default:
3080 return (FALSE);
3083 if (pup) *pup = up;
3084 if (pbutton) *pbutton = button;
3086 return (TRUE);
3090 /* Prepare a mouse-event in *RESULT for placement in the input queue.
3092 If the event is a button press, then note that we have grabbed
3093 the mouse. */
3095 static Lisp_Object
3096 construct_mouse_click (struct input_event *result, W32Msg *msg, struct frame *f)
3098 int button = 0;
3099 int up = 0;
3101 parse_button (msg->msg.message, HIWORD (msg->msg.wParam),
3102 &button, &up);
3104 /* Make the event type NO_EVENT; we'll change that when we decide
3105 otherwise. */
3106 result->kind = MOUSE_CLICK_EVENT;
3107 result->code = button;
3108 result->timestamp = msg->msg.time;
3109 result->modifiers = (msg->dwModifiers
3110 | (up
3111 ? up_modifier
3112 : down_modifier));
3114 XSETINT (result->x, LOWORD (msg->msg.lParam));
3115 XSETINT (result->y, HIWORD (msg->msg.lParam));
3116 XSETFRAME (result->frame_or_window, f);
3117 result->arg = Qnil;
3118 return Qnil;
3121 static Lisp_Object
3122 construct_mouse_wheel (struct input_event *result, W32Msg *msg, struct frame *f)
3124 POINT p;
3125 int delta;
3127 result->kind = msg->msg.message == WM_MOUSEHWHEEL ? HORIZ_WHEEL_EVENT
3128 : WHEEL_EVENT;
3129 result->code = 0;
3130 result->timestamp = msg->msg.time;
3132 /* A WHEEL_DELTA positive value indicates that the wheel was rotated
3133 forward, away from the user (up); a negative value indicates that
3134 the wheel was rotated backward, toward the user (down). */
3135 delta = GET_WHEEL_DELTA_WPARAM (msg->msg.wParam);
3137 /* The up and down modifiers indicate if the wheel was rotated up or
3138 down based on WHEEL_DELTA value. */
3139 result->modifiers = (msg->dwModifiers
3140 | ((delta < 0 ) ? down_modifier : up_modifier));
3142 /* With multiple monitors, we can legitimately get negative
3143 coordinates, so cast to short to interpret them correctly. */
3144 p.x = (short) LOWORD (msg->msg.lParam);
3145 p.y = (short) HIWORD (msg->msg.lParam);
3146 /* For the case that F's w32 window is not msg->msg.hwnd. */
3147 ScreenToClient (FRAME_W32_WINDOW (f), &p);
3148 XSETINT (result->x, p.x);
3149 XSETINT (result->y, p.y);
3150 XSETFRAME (result->frame_or_window, f);
3151 result->arg = Qnil;
3152 return Qnil;
3155 static Lisp_Object
3156 construct_drag_n_drop (struct input_event *result, W32Msg *msg, struct frame *f)
3158 Lisp_Object files;
3159 Lisp_Object frame;
3160 HDROP hdrop;
3161 POINT p;
3162 WORD num_files;
3163 wchar_t name_w[MAX_PATH];
3164 #ifdef NTGUI_UNICODE
3165 const int use_unicode = 1;
3166 #else
3167 int use_unicode = w32_unicode_filenames;
3168 char name_a[MAX_PATH];
3169 char file[MAX_UTF8_PATH];
3170 #endif
3171 int i;
3173 result->kind = DRAG_N_DROP_EVENT;
3174 result->code = 0;
3175 result->timestamp = msg->msg.time;
3176 result->modifiers = msg->dwModifiers;
3178 hdrop = (HDROP) msg->msg.wParam;
3179 DragQueryPoint (hdrop, &p);
3181 #if 0
3182 p.x = LOWORD (msg->msg.lParam);
3183 p.y = HIWORD (msg->msg.lParam);
3184 ScreenToClient (msg->msg.hwnd, &p);
3185 #endif
3187 XSETINT (result->x, p.x);
3188 XSETINT (result->y, p.y);
3190 num_files = DragQueryFile (hdrop, 0xFFFFFFFF, NULL, 0);
3191 files = Qnil;
3193 for (i = 0; i < num_files; i++)
3195 if (use_unicode)
3197 eassert (DragQueryFileW (hdrop, i, NULL, 0) < MAX_PATH);
3198 /* If DragQueryFile returns zero, it failed to fetch a file
3199 name. */
3200 if (DragQueryFileW (hdrop, i, name_w, MAX_PATH) == 0)
3201 continue;
3202 #ifdef NTGUI_UNICODE
3203 files = Fcons (from_unicode_buffer (name_w), files);
3204 #else
3205 filename_from_utf16 (name_w, file);
3206 files = Fcons (DECODE_FILE (build_unibyte_string (file)), files);
3207 #endif /* NTGUI_UNICODE */
3209 #ifndef NTGUI_UNICODE
3210 else
3212 eassert (DragQueryFileA (hdrop, i, NULL, 0) < MAX_PATH);
3213 if (DragQueryFileA (hdrop, i, name_a, MAX_PATH) == 0)
3214 continue;
3215 filename_from_ansi (name_a, file);
3216 files = Fcons (DECODE_FILE (build_unibyte_string (file)), files);
3218 #endif
3221 DragFinish (hdrop);
3223 XSETFRAME (frame, f);
3224 result->frame_or_window = frame;
3225 result->arg = files;
3226 return Qnil;
3230 #if HAVE_W32NOTIFY
3232 /* File event notifications (see w32notify.c). */
3234 Lisp_Object
3235 lispy_file_action (DWORD action)
3237 static char unknown_fmt[] = "unknown-action(%d)";
3238 Lisp_Object retval;
3240 switch (action)
3242 case FILE_ACTION_ADDED:
3243 retval = Qadded;
3244 break;
3245 case FILE_ACTION_REMOVED:
3246 retval = Qremoved;
3247 break;
3248 case FILE_ACTION_MODIFIED:
3249 retval = Qmodified;
3250 break;
3251 case FILE_ACTION_RENAMED_OLD_NAME:
3252 retval = Qrenamed_from;
3253 break;
3254 case FILE_ACTION_RENAMED_NEW_NAME:
3255 retval = Qrenamed_to;
3256 break;
3257 default:
3259 char buf[sizeof(unknown_fmt) - 1 + INT_STRLEN_BOUND (DWORD)];
3261 sprintf (buf, unknown_fmt, action);
3262 retval = intern (buf);
3264 break;
3267 return retval;
3270 #ifdef WINDOWSNT
3271 /* Put file notifications into the Emacs input event queue. This
3272 function runs when the WM_EMACS_FILENOTIFY message arrives from a
3273 watcher thread. */
3274 static void
3275 queue_notifications (struct input_event *event, W32Msg *msg, struct frame *f,
3276 int *evcount)
3278 struct notifications_set *ns = NULL;
3279 Lisp_Object frame;
3280 int done = 0;
3282 /* We cannot process notification before Emacs is fully initialized,
3283 since we need the UTF-16LE coding-system to be set up. */
3284 if (!initialized)
3285 return;
3287 XSETFRAME (frame, f);
3289 while (!done)
3291 ns = NULL;
3293 /* Find out if there is a record available in the linked list of
3294 notifications sets. If so, unlink the set from the linked
3295 list. Use critical section. */
3296 enter_crit ();
3297 if (notifications_set_head->next != notifications_set_head)
3299 ns = notifications_set_head->next;
3300 ns->prev->next = ns->next;
3301 ns->next->prev = ns->prev;
3303 else
3304 done = 1;
3305 leave_crit();
3307 if (ns)
3309 BYTE *p = ns->notifications;
3310 FILE_NOTIFY_INFORMATION *fni = (PFILE_NOTIFY_INFORMATION)p;
3311 const DWORD min_size
3312 = offsetof (FILE_NOTIFY_INFORMATION, FileName) + sizeof(wchar_t);
3313 DWORD info_size = ns->size;
3314 Lisp_Object cs = Qutf_16le;
3315 Lisp_Object obj = w32_get_watch_object (ns->desc);
3317 /* notifications size could be zero when the buffer of
3318 notifications overflowed on the OS level, or when the
3319 directory being watched was itself deleted. Do nothing in
3320 that case. */
3321 if (info_size
3322 && !NILP (obj) && CONSP (obj))
3324 Lisp_Object callback = XCDR (obj);
3326 while (info_size >= min_size)
3328 Lisp_Object utf_16_fn
3329 = make_unibyte_string ((char *)fni->FileName,
3330 fni->FileNameLength);
3331 /* Note: mule-conf is preloaded, so utf-16le must
3332 already be defined at this point. */
3333 Lisp_Object fname
3334 = code_convert_string_norecord (utf_16_fn, cs, 0);
3335 Lisp_Object action = lispy_file_action (fni->Action);
3337 event->kind = FILE_NOTIFY_EVENT;
3338 event->timestamp = msg->msg.time;
3339 event->modifiers = 0;
3340 event->frame_or_window = callback;
3341 event->arg = list3 (make_pointer_integer (ns->desc),
3342 action, fname);
3343 kbd_buffer_store_event (event);
3344 (*evcount)++;
3345 if (!fni->NextEntryOffset)
3346 break;
3347 p += fni->NextEntryOffset;
3348 fni = (PFILE_NOTIFY_INFORMATION)p;
3349 info_size -= fni->NextEntryOffset;
3352 /* Free this notifications set. */
3353 xfree (ns->notifications);
3354 xfree (ns);
3357 /* We've stuffed all the events ourselves, so w32_read_socket shouldn't. */
3358 event->kind = NO_EVENT;
3360 #endif /* WINDOWSNT */
3361 #endif /* HAVE_W32NOTIFY */
3364 /* Function to report a mouse movement to the mainstream Emacs code.
3365 The input handler calls this.
3367 We have received a mouse movement event, which is given in *event.
3368 If the mouse is over a different glyph than it was last time, tell
3369 the mainstream emacs code by setting mouse_moved. If not, ask for
3370 another motion event, so we can check again the next time it moves. */
3372 static int
3373 note_mouse_movement (struct frame *frame, MSG *msg)
3375 struct w32_display_info *dpyinfo;
3376 int mouse_x = LOWORD (msg->lParam);
3377 int mouse_y = HIWORD (msg->lParam);
3378 RECT *r;
3380 if (!FRAME_X_OUTPUT (frame))
3381 return 0;
3383 dpyinfo = FRAME_DISPLAY_INFO (frame);
3384 dpyinfo->last_mouse_movement_time = msg->time;
3385 dpyinfo->last_mouse_motion_frame = frame;
3386 dpyinfo->last_mouse_motion_x = mouse_x;
3387 dpyinfo->last_mouse_motion_y = mouse_y;
3389 if (msg->hwnd != FRAME_W32_WINDOW (frame))
3391 frame->mouse_moved = true;
3392 dpyinfo->last_mouse_scroll_bar = NULL;
3393 note_mouse_highlight (frame, -1, -1);
3394 dpyinfo->last_mouse_glyph_frame = NULL;
3395 return 1;
3398 /* Has the mouse moved off the glyph it was on at the last sighting? */
3399 r = &dpyinfo->last_mouse_glyph;
3400 if (frame != dpyinfo->last_mouse_glyph_frame
3401 || mouse_x < r->left || mouse_x >= r->right
3402 || mouse_y < r->top || mouse_y >= r->bottom)
3404 frame->mouse_moved = true;
3405 dpyinfo->last_mouse_scroll_bar = NULL;
3406 note_mouse_highlight (frame, mouse_x, mouse_y);
3407 /* Remember the mouse position here, as w32_mouse_position only
3408 gets called when mouse tracking is enabled but we also need
3409 to keep track of the mouse for help_echo and highlighting at
3410 other times. */
3411 remember_mouse_glyph (frame, mouse_x, mouse_y, r);
3412 dpyinfo->last_mouse_glyph_frame = frame;
3413 return 1;
3416 return 0;
3420 /************************************************************************
3421 Mouse Face
3422 ************************************************************************/
3424 static struct scroll_bar *x_window_to_scroll_bar (Window, int);
3425 static void x_scroll_bar_report_motion (struct frame **, Lisp_Object *,
3426 enum scroll_bar_part *,
3427 Lisp_Object *, Lisp_Object *,
3428 Time *);
3429 static void x_horizontal_scroll_bar_report_motion (struct frame **, Lisp_Object *,
3430 enum scroll_bar_part *,
3431 Lisp_Object *, Lisp_Object *,
3432 Time *);
3433 static void
3434 w32_define_cursor (Window window, Cursor cursor)
3436 PostMessage (window, WM_EMACS_SETCURSOR, (WPARAM) cursor, 0);
3439 /* Return the current position of the mouse.
3440 *fp should be a frame which indicates which display to ask about.
3442 If the mouse movement started in a scroll bar, set *fp, *bar_window,
3443 and *part to the frame, window, and scroll bar part that the mouse
3444 is over. Set *x and *y to the portion and whole of the mouse's
3445 position on the scroll bar.
3447 If the mouse movement started elsewhere, set *fp to the frame the
3448 mouse is on, *bar_window to nil, and *x and *y to the character cell
3449 the mouse is over.
3451 Set *time to the server time-stamp for the time at which the mouse
3452 was at this position.
3454 Don't store anything if we don't have a valid set of values to report.
3456 This clears the mouse_moved flag, so we can wait for the next mouse
3457 movement. */
3459 static void
3460 w32_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
3461 enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
3462 Time *time)
3464 struct w32_display_info *dpyinfo = FRAME_DISPLAY_INFO (*fp);
3466 block_input ();
3468 if (dpyinfo->last_mouse_scroll_bar && insist == 0)
3470 struct scroll_bar *bar = dpyinfo->last_mouse_scroll_bar;
3472 if (bar->horizontal)
3473 x_horizontal_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
3474 else
3475 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
3477 else
3479 POINT pt;
3480 Lisp_Object frame, tail;
3481 struct frame *f1 = NULL;
3483 /* Clear the mouse-moved flag for every frame on this display. */
3484 FOR_EACH_FRAME (tail, frame)
3485 XFRAME (frame)->mouse_moved = false;
3487 dpyinfo->last_mouse_scroll_bar = NULL;
3489 GetCursorPos (&pt);
3491 /* Now we have a position on the root; find the innermost window
3492 containing the pointer. */
3494 /* If mouse was grabbed on a frame, give coords for that
3495 frame even if the mouse is now outside it. Otherwise
3496 check for window under mouse on one of our frames. */
3497 if (x_mouse_grabbed (dpyinfo))
3498 f1 = dpyinfo->last_mouse_frame;
3499 else
3501 HWND wfp = WindowFromPoint (pt);
3503 if (wfp)
3505 f1 = x_any_window_to_frame (dpyinfo, wfp);
3506 if (f1)
3508 HWND cwfp = ChildWindowFromPoint (wfp, pt);
3510 if (cwfp)
3512 struct frame *f2 = x_any_window_to_frame (dpyinfo, cwfp);
3514 /* If a child window was found, make sure that its
3515 frame is a child frame (Bug#26615, maybe). */
3516 if (f2 && FRAME_PARENT_FRAME (f2))
3517 f1 = f2;
3523 /* If not, is it one of our scroll bars? */
3524 if (! f1)
3526 struct scroll_bar *bar
3527 = x_window_to_scroll_bar (WindowFromPoint (pt), 2);
3529 if (bar)
3530 f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
3533 if (f1 == 0 && insist > 0)
3534 f1 = SELECTED_FRAME ();
3536 if (f1)
3538 /* Ok, we found a frame. Store all the values.
3539 last_mouse_glyph is a rectangle used to reduce the
3540 generation of mouse events. To not miss any motion
3541 events, we must divide the frame into rectangles of the
3542 size of the smallest character that could be displayed
3543 on it, i.e. into the same rectangles that matrices on
3544 the frame are divided into. */
3546 dpyinfo = FRAME_DISPLAY_INFO (f1);
3547 ScreenToClient (FRAME_W32_WINDOW (f1), &pt);
3548 remember_mouse_glyph (f1, pt.x, pt.y, &dpyinfo->last_mouse_glyph);
3549 dpyinfo->last_mouse_glyph_frame = f1;
3551 *bar_window = Qnil;
3552 *part = scroll_bar_above_handle;
3553 *fp = f1;
3554 XSETINT (*x, pt.x);
3555 XSETINT (*y, pt.y);
3556 *time = dpyinfo->last_mouse_movement_time;
3561 unblock_input ();
3565 /***********************************************************************
3566 Tool-bars
3567 ***********************************************************************/
3569 /* Handle mouse button event on the tool-bar of frame F, at
3570 frame-relative coordinates X/Y. EVENT_TYPE is either ButtonPress
3571 or ButtonRelease. */
3573 static void
3574 w32_handle_tool_bar_click (struct frame *f, struct input_event *button_event)
3576 int x = XFASTINT (button_event->x);
3577 int y = XFASTINT (button_event->y);
3579 if (button_event->modifiers & down_modifier)
3580 handle_tool_bar_click (f, x, y, 1, 0);
3581 else
3582 handle_tool_bar_click (f, x, y, 0,
3583 button_event->modifiers & ~up_modifier);
3588 /***********************************************************************
3589 Scroll bars
3590 ***********************************************************************/
3592 /* Scroll bar support. */
3594 /* Given a window ID, find the struct scroll_bar which manages it
3595 vertically. This can be called in GC, so we have to make sure to
3596 strip off mark bits. */
3598 static struct scroll_bar *
3599 x_window_to_scroll_bar (Window window_id, int type)
3601 Lisp_Object tail, frame;
3603 FOR_EACH_FRAME (tail, frame)
3605 Lisp_Object bar, condemned;
3607 /* Scan this frame's scroll bar list for a scroll bar with the
3608 right window ID. */
3609 condemned = FRAME_CONDEMNED_SCROLL_BARS (XFRAME (frame));
3610 for (bar = FRAME_SCROLL_BARS (XFRAME (frame));
3611 /* This trick allows us to search both the ordinary and
3612 condemned scroll bar lists with one loop. */
3613 ! NILP (bar) || (bar = condemned,
3614 condemned = Qnil,
3615 ! NILP (bar));
3616 bar = XSCROLL_BAR (bar)->next)
3617 if (SCROLL_BAR_W32_WINDOW (XSCROLL_BAR (bar)) == window_id
3618 && (type = 2
3619 || (type == 1 && XSCROLL_BAR (bar)->horizontal)
3620 || (type == 0 && !XSCROLL_BAR (bar)->horizontal)))
3621 return XSCROLL_BAR (bar);
3624 return 0;
3629 /* Set the thumb size and position of vertical scroll bar BAR. We are currently
3630 displaying PORTION out of a whole WHOLE, and our position POSITION. */
3632 static void
3633 w32_set_scroll_bar_thumb (struct scroll_bar *bar,
3634 int portion, int position, int whole)
3636 Window w = SCROLL_BAR_W32_WINDOW (bar);
3637 /* We use the whole scroll-bar height in the calculations below, to
3638 avoid strange effects like scrolling backwards when just clicking
3639 on the handle (without moving it). */
3640 double range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, bar->height)
3641 + VERTICAL_SCROLL_BAR_MIN_HANDLE;
3642 int sb_page, sb_pos;
3643 BOOL draggingp = bar->dragging ? TRUE : FALSE;
3644 SCROLLINFO si;
3646 /* We used to change the nPage setting while dragging the handle,
3647 but that had very strange effects (such as scrolling backwards
3648 while dragging downwards).
3650 Now, we don't change the nPage setting while dragging unless we
3651 get near to the end of the buffer, in which case we often have to
3652 resize the handle to "go all the way". */
3654 if (draggingp)
3656 int near_bottom_p;
3657 block_input ();
3658 si.cbSize = sizeof (si);
3659 si.fMask = SIF_POS | SIF_PAGE;
3660 GetScrollInfo (w, SB_CTL, &si);
3661 near_bottom_p = si.nPos + si.nPage >= range;
3662 unblock_input ();
3663 if (!near_bottom_p)
3664 return;
3667 if (whole)
3669 /* Position scroll bar at rock bottom if the bottom of the
3670 buffer is visible. This avoids shrinking the thumb away
3671 to nothing if it is held at the bottom of the buffer. */
3672 if (position + portion >= whole && !draggingp)
3674 sb_page = range * (whole - position) / whole;
3675 sb_pos = range;
3677 else
3679 sb_pos = position * range / whole;
3680 sb_page = (min (portion, (whole - position)) * range) / whole;
3683 else
3685 sb_page = range;
3686 sb_pos = 0;
3689 sb_page = max (sb_page, VERTICAL_SCROLL_BAR_MIN_HANDLE);
3691 block_input ();
3693 si.cbSize = sizeof (si);
3694 si.fMask = SIF_PAGE | SIF_POS;
3695 si.nPage = sb_page;
3696 si.nPos = sb_pos;
3698 SetScrollInfo (w, SB_CTL, &si, TRUE);
3700 unblock_input ();
3703 /* Set the thumb size and position of horizontal scroll bar BAR. We are currently
3704 displaying PORTION out of a whole WHOLE, and our position POSITION. */
3706 static void
3707 w32_set_horizontal_scroll_bar_thumb (struct scroll_bar *bar,
3708 int portion, int position, int whole)
3710 Window w = SCROLL_BAR_W32_WINDOW (bar);
3711 SCROLLINFO si;
3713 block_input ();
3715 si.cbSize = sizeof (si);
3716 si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
3717 si.nMin = 0;
3718 si.nMax = whole;
3719 /* Allow nPage to be one larger than nPos so we don't allow the scrolling
3720 of an already fully visible buffer. */
3721 si.nPage = min (portion, si.nMax) + 1;
3722 si.nPos = min (position, si.nMax);
3723 SetScrollInfo (w, SB_CTL, &si, TRUE);
3725 unblock_input ();
3729 /************************************************************************
3730 Scroll bars, general
3731 ************************************************************************/
3733 static HWND
3734 my_create_vscrollbar (struct frame * f, struct scroll_bar * bar)
3736 return (HWND) SendMessage (FRAME_W32_WINDOW (f),
3737 WM_EMACS_CREATEVSCROLLBAR, (WPARAM) f,
3738 (LPARAM) bar);
3741 static HWND
3742 my_create_hscrollbar (struct frame * f, struct scroll_bar * bar)
3744 return (HWND) SendMessage (FRAME_W32_WINDOW (f),
3745 WM_EMACS_CREATEHSCROLLBAR, (WPARAM) f,
3746 (LPARAM) bar);
3749 /*#define ATTACH_THREADS*/
3751 static BOOL
3752 my_show_window (struct frame *f, HWND hwnd, int how)
3754 #ifndef ATTACH_THREADS
3755 return SendMessageTimeout (FRAME_W32_WINDOW (f), WM_EMACS_SHOWWINDOW,
3756 (WPARAM) hwnd, (LPARAM) how, 0, 6000, NULL);
3757 #else
3758 return ShowWindow (hwnd, how);
3759 #endif
3762 static void
3763 my_set_window_pos (HWND hwnd, HWND hwndAfter,
3764 int x, int y, int cx, int cy, UINT flags)
3766 #ifndef ATTACH_THREADS
3767 WINDOWPOS pos;
3768 pos.hwndInsertAfter = hwndAfter;
3769 pos.x = x;
3770 pos.y = y;
3771 pos.cx = cx;
3772 pos.cy = cy;
3773 pos.flags = flags;
3774 SendMessageTimeout (hwnd, WM_EMACS_SETWINDOWPOS, (WPARAM) &pos, 0,
3775 0, 6000, NULL);
3776 #else
3777 SetWindowPos (hwnd, hwndAfter, x, y, cx, cy, flags);
3778 #endif
3781 #if 0
3782 static void
3783 my_set_focus (struct frame * f, HWND hwnd)
3785 SendMessageTimeout (FRAME_W32_WINDOW (f), WM_EMACS_SETFOCUS,
3786 (WPARAM) hwnd, 0, 0, 6000, NULL);
3788 #endif
3790 static void
3791 my_set_foreground_window (HWND hwnd)
3793 SendMessageTimeout (hwnd, WM_EMACS_SETFOREGROUND, (WPARAM) hwnd, 0,
3794 0, 6000, NULL);
3798 static void
3799 my_destroy_window (struct frame * f, HWND hwnd)
3801 SendMessageTimeout (FRAME_W32_WINDOW (f), WM_EMACS_DESTROYWINDOW,
3802 (WPARAM) hwnd, 0, 0, 6000, NULL);
3805 static void
3806 my_bring_window_to_top (HWND hwnd)
3808 SendMessageTimeout (hwnd, WM_EMACS_BRINGTOTOP, (WPARAM) hwnd, 0,
3809 0, 6000, NULL);
3812 /* Create a scroll bar and return the scroll bar vector for it. W is
3813 the Emacs window on which to create the scroll bar. TOP, LEFT,
3814 WIDTH and HEIGHT are the pixel coordinates and dimensions of the
3815 scroll bar. */
3817 static struct scroll_bar *
3818 x_scroll_bar_create (struct window *w, int left, int top, int width, int height, bool horizontal)
3820 struct frame *f = XFRAME (WINDOW_FRAME (w));
3821 HWND hwnd;
3822 SCROLLINFO si;
3823 struct scroll_bar *bar
3824 = ALLOCATE_PSEUDOVECTOR (struct scroll_bar, top, PVEC_OTHER);
3825 Lisp_Object barobj;
3827 block_input ();
3829 XSETWINDOW (bar->window, w);
3830 bar->top = top;
3831 bar->left = left;
3832 bar->width = width;
3833 bar->height = height;
3834 bar->start = 0;
3835 bar->end = 0;
3836 bar->dragging = 0;
3837 bar->horizontal = horizontal;
3839 /* Requires geometry to be set before call to create the real window */
3841 if (horizontal)
3842 hwnd = my_create_hscrollbar (f, bar);
3843 else
3844 hwnd = my_create_vscrollbar (f, bar);
3846 si.cbSize = sizeof (si);
3847 si.fMask = SIF_ALL;
3848 si.nMin = 0;
3849 if (horizontal)
3850 si.nMax = HORIZONTAL_SCROLL_BAR_LEFT_RANGE (f, width)
3851 + HORIZONTAL_SCROLL_BAR_MIN_HANDLE;
3852 else
3853 si.nMax = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height)
3854 + VERTICAL_SCROLL_BAR_MIN_HANDLE;
3855 si.nPage = si.nMax;
3856 si.nPos = 0;
3858 SetScrollInfo (hwnd, SB_CTL, &si, FALSE);
3860 SET_SCROLL_BAR_W32_WINDOW (bar, hwnd);
3862 /* Add bar to its frame's list of scroll bars. */
3863 bar->next = FRAME_SCROLL_BARS (f);
3864 bar->prev = Qnil;
3865 XSETVECTOR (barobj, bar);
3866 fset_scroll_bars (f, barobj);
3867 if (! NILP (bar->next))
3868 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
3870 unblock_input ();
3872 return bar;
3876 /* Destroy scroll bar BAR, and set its Emacs window's scroll bar to
3877 nil. */
3879 static void
3880 x_scroll_bar_remove (struct scroll_bar *bar)
3882 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
3884 block_input ();
3886 /* Destroy the window. */
3887 my_destroy_window (f, SCROLL_BAR_W32_WINDOW (bar));
3889 /* Dissociate this scroll bar from its window. */
3890 if (bar->horizontal)
3891 wset_horizontal_scroll_bar (XWINDOW (bar->window), Qnil);
3892 else
3893 wset_vertical_scroll_bar (XWINDOW (bar->window), Qnil);
3895 unblock_input ();
3898 /* Set the handle of the vertical scroll bar for WINDOW to indicate that
3899 we are displaying PORTION characters out of a total of WHOLE
3900 characters, starting at POSITION. If WINDOW has no vertical scroll
3901 bar, create one. */
3902 static void
3903 w32_set_vertical_scroll_bar (struct window *w,
3904 int portion, int whole, int position)
3906 struct frame *f = XFRAME (w->frame);
3907 Lisp_Object barobj;
3908 struct scroll_bar *bar;
3909 int top, height, left, width;
3910 int window_y, window_height;
3912 /* Get window dimensions. */
3913 window_box (w, ANY_AREA, 0, &window_y, 0, &window_height);
3914 top = window_y;
3915 height = window_height;
3917 /* Compute the left edge and the width of the scroll bar area. */
3918 left = WINDOW_SCROLL_BAR_AREA_X (w);
3919 width = WINDOW_SCROLL_BAR_AREA_WIDTH (w);
3921 /* Does the scroll bar exist yet? */
3922 if (NILP (w->vertical_scroll_bar))
3924 HDC hdc;
3925 block_input ();
3926 if (width > 0 && height > 0)
3928 hdc = get_frame_dc (f);
3929 w32_clear_area (f, hdc, left, top, width, height);
3930 release_frame_dc (f, hdc);
3932 unblock_input ();
3934 bar = x_scroll_bar_create (w, left, top, width, height, false);
3936 else
3938 /* It may just need to be moved and resized. */
3939 HWND hwnd;
3941 bar = XSCROLL_BAR (w->vertical_scroll_bar);
3942 hwnd = SCROLL_BAR_W32_WINDOW (bar);
3944 /* If already correctly positioned, do nothing. */
3945 if (bar->left == left
3946 && bar->top == top
3947 && bar->width == width
3948 && bar->height == height)
3950 /* Redraw after clear_frame. */
3951 if (!my_show_window (f, hwnd, SW_NORMAL))
3952 InvalidateRect (hwnd, NULL, FALSE);
3954 else
3956 HDC hdc;
3957 SCROLLINFO si;
3959 block_input ();
3960 if (width && height)
3962 hdc = get_frame_dc (f);
3963 /* Since Windows scroll bars are smaller than the space reserved
3964 for them on the frame, we have to clear "under" them. */
3965 w32_clear_area (f, hdc, left, top, width, height);
3966 release_frame_dc (f, hdc);
3967 x_clear_under_internal_border (f);
3969 /* Make sure scroll bar is "visible" before moving, to ensure the
3970 area of the parent window now exposed will be refreshed. */
3971 my_show_window (f, hwnd, SW_HIDE);
3972 /** MoveWindow (hwnd, left, top, width, max (height, 1), TRUE); **/
3973 /* Try to not draw over child frames. */
3974 SetWindowPos (hwnd, HWND_BOTTOM, left, top, width, max (height, 1),
3975 SWP_FRAMECHANGED);
3977 si.cbSize = sizeof (si);
3978 si.fMask = SIF_RANGE;
3979 si.nMin = 0;
3980 si.nMax = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height)
3981 + VERTICAL_SCROLL_BAR_MIN_HANDLE;
3983 SetScrollInfo (hwnd, SB_CTL, &si, FALSE);
3985 my_show_window (f, hwnd, SW_NORMAL);
3986 /* InvalidateRect (w, NULL, FALSE); */
3988 /* Remember new settings. */
3989 bar->left = left;
3990 bar->top = top;
3991 bar->width = width;
3992 bar->height = height;
3994 unblock_input ();
3997 w32_set_scroll_bar_thumb (bar, portion, position, whole);
3998 XSETVECTOR (barobj, bar);
3999 wset_vertical_scroll_bar (w, barobj);
4002 /* Set the handle of the horizontal scroll bar for WINDOW to indicate
4003 that we are displaying PORTION characters out of a total of WHOLE
4004 characters, starting at POSITION. If WINDOW has no horizontal scroll
4005 bar, create one. */
4006 static void
4007 w32_set_horizontal_scroll_bar (struct window *w,
4008 int portion, int whole, int position)
4010 struct frame *f = XFRAME (w->frame);
4011 Lisp_Object barobj;
4012 struct scroll_bar *bar;
4013 int top, height, left, width;
4014 int window_x, window_width;
4015 int clear_left = WINDOW_LEFT_EDGE_X (w);
4016 int clear_width = WINDOW_PIXEL_WIDTH (w) - WINDOW_RIGHT_DIVIDER_WIDTH (w);
4018 /* Get window dimensions. */
4019 window_box (w, ANY_AREA, &window_x, 0, &window_width, 0);
4020 left = window_x;
4021 height = WINDOW_SCROLL_BAR_AREA_HEIGHT (w);
4022 width = window_width;
4023 top = WINDOW_SCROLL_BAR_AREA_Y (w);
4025 /* Does the scroll bar exist yet? */
4026 if (NILP (w->horizontal_scroll_bar))
4028 HDC hdc;
4029 block_input ();
4030 if (width > 0 && height > 0)
4032 hdc = get_frame_dc (f);
4033 w32_clear_area (f, hdc, clear_left, top, clear_width, height);
4034 release_frame_dc (f, hdc);
4036 unblock_input ();
4038 bar = x_scroll_bar_create (w, left, top, width, height, true);
4040 else
4042 /* It may just need to be moved and resized. */
4043 HWND hwnd;
4045 bar = XSCROLL_BAR (w->horizontal_scroll_bar);
4046 hwnd = SCROLL_BAR_W32_WINDOW (bar);
4048 /* If already correctly positioned, do nothing. */
4049 if (bar->left == left && bar->top == top
4050 && bar->width == width && bar->height == height)
4052 /* Redraw after clear_frame. */
4053 if (!my_show_window (f, hwnd, SW_NORMAL))
4054 InvalidateRect (hwnd, NULL, FALSE);
4056 else
4058 HDC hdc;
4059 SCROLLINFO si;
4061 block_input ();
4062 if (width && height)
4064 hdc = get_frame_dc (f);
4065 /* Since Windows scroll bars are smaller than the space reserved
4066 for them on the frame, we have to clear "under" them. */
4067 w32_clear_area (f, hdc, clear_left, top, clear_width, height);
4068 release_frame_dc (f, hdc);
4069 x_clear_under_internal_border (f);
4071 /* Make sure scroll bar is "visible" before moving, to ensure the
4072 area of the parent window now exposed will be refreshed. */
4073 my_show_window (f, hwnd, SW_HIDE);
4074 /** MoveWindow (hwnd, left, top, width, max (height, 1), TRUE); **/
4075 /* Try to not draw over child frames. */
4076 SetWindowPos (hwnd, HWND_BOTTOM, left, top, max (width, 1), height,
4077 SWP_FRAMECHANGED);
4079 /* +++ SetScrollInfo +++ */
4080 si.cbSize = sizeof (si);
4081 si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
4082 si.nMin = 0;
4083 si.nMax = whole;
4084 si.nPage = min (portion, si.nMax) + 1;
4085 si.nPos = min (position, si.nMax);
4086 SetScrollInfo (hwnd, SB_CTL, &si, FALSE);
4088 my_show_window (f, hwnd, SW_NORMAL);
4089 /* InvalidateRect (w, NULL, FALSE); */
4091 /* Remember new settings. */
4092 bar->left = left;
4093 bar->top = top;
4094 bar->width = width;
4095 bar->height = height;
4097 unblock_input ();
4101 w32_set_horizontal_scroll_bar_thumb (bar, portion, position, whole);
4102 XSETVECTOR (barobj, bar);
4103 wset_horizontal_scroll_bar (w, barobj);
4107 /* The following three hooks are used when we're doing a thorough
4108 redisplay of the frame. We don't explicitly know which scroll bars
4109 are going to be deleted, because keeping track of when windows go
4110 away is a real pain - "Can you say set-window-configuration, boys
4111 and girls?" Instead, we just assert at the beginning of redisplay
4112 that *all* scroll bars are to be removed, and then save a scroll bar
4113 from the fiery pit when we actually redisplay its window. */
4115 /* Arrange for all scroll bars on FRAME to be removed at the next call
4116 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
4117 `*redeem_scroll_bar_hook' is applied to its window before the judgment. */
4119 static void
4120 w32_condemn_scroll_bars (struct frame *frame)
4122 if (!NILP (FRAME_SCROLL_BARS (frame)))
4124 if (!NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
4126 /* Prepend scrollbars to already condemned ones. */
4127 Lisp_Object last = FRAME_SCROLL_BARS (frame);
4129 while (!NILP (XSCROLL_BAR (last)->next))
4130 last = XSCROLL_BAR (last)->next;
4132 XSCROLL_BAR (last)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
4133 XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = last;
4136 fset_condemned_scroll_bars (frame, FRAME_SCROLL_BARS (frame));
4137 fset_scroll_bars (frame, Qnil);
4142 /* Un-mark WINDOW's scroll bar for deletion in this judgment cycle.
4143 Note that WINDOW isn't necessarily condemned at all. */
4145 static void
4146 w32_redeem_scroll_bar (struct window *w)
4148 struct scroll_bar *bar;
4149 Lisp_Object barobj;
4150 struct frame *f;
4152 /* We can't redeem this window's scroll bar if it doesn't have one. */
4153 if (NILP (w->vertical_scroll_bar) && NILP (w->horizontal_scroll_bar))
4154 emacs_abort ();
4156 if (!NILP (w->vertical_scroll_bar) && WINDOW_HAS_VERTICAL_SCROLL_BAR (w))
4158 bar = XSCROLL_BAR (w->vertical_scroll_bar);
4159 /* Unlink it from the condemned list. */
4160 f = XFRAME (WINDOW_FRAME (w));
4161 if (NILP (bar->prev))
4163 /* If the prev pointer is nil, it must be the first in one of
4164 the lists. */
4165 if (EQ (FRAME_SCROLL_BARS (f), w->vertical_scroll_bar))
4166 /* It's not condemned. Everything's fine. */
4167 goto horizontal;
4168 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
4169 w->vertical_scroll_bar))
4170 fset_condemned_scroll_bars (f, bar->next);
4171 else
4172 /* If its prev pointer is nil, it must be at the front of
4173 one or the other! */
4174 emacs_abort ();
4176 else
4177 XSCROLL_BAR (bar->prev)->next = bar->next;
4179 if (! NILP (bar->next))
4180 XSCROLL_BAR (bar->next)->prev = bar->prev;
4182 bar->next = FRAME_SCROLL_BARS (f);
4183 bar->prev = Qnil;
4184 XSETVECTOR (barobj, bar);
4185 fset_scroll_bars (f, barobj);
4186 if (! NILP (bar->next))
4187 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
4190 horizontal:
4191 if (!NILP (w->horizontal_scroll_bar) && WINDOW_HAS_HORIZONTAL_SCROLL_BAR (w))
4193 bar = XSCROLL_BAR (w->horizontal_scroll_bar);
4194 /* Unlink it from the condemned list. */
4195 f = XFRAME (WINDOW_FRAME (w));
4196 if (NILP (bar->prev))
4198 /* If the prev pointer is nil, it must be the first in one of
4199 the lists. */
4200 if (EQ (FRAME_SCROLL_BARS (f), w->horizontal_scroll_bar))
4201 /* It's not condemned. Everything's fine. */
4202 return;
4203 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
4204 w->horizontal_scroll_bar))
4205 fset_condemned_scroll_bars (f, bar->next);
4206 else
4207 /* If its prev pointer is nil, it must be at the front of
4208 one or the other! */
4209 emacs_abort ();
4211 else
4212 XSCROLL_BAR (bar->prev)->next = bar->next;
4214 if (! NILP (bar->next))
4215 XSCROLL_BAR (bar->next)->prev = bar->prev;
4217 bar->next = FRAME_SCROLL_BARS (f);
4218 bar->prev = Qnil;
4219 XSETVECTOR (barobj, bar);
4220 fset_scroll_bars (f, barobj);
4221 if (! NILP (bar->next))
4222 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
4226 /* Remove all scroll bars on FRAME that haven't been saved since the
4227 last call to `*condemn_scroll_bars_hook'. */
4229 static void
4230 w32_judge_scroll_bars (struct frame *f)
4232 Lisp_Object bar, next;
4234 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
4236 /* Clear out the condemned list now so we won't try to process any
4237 more events on the hapless scroll bars. */
4238 fset_condemned_scroll_bars (f, Qnil);
4240 for (; ! NILP (bar); bar = next)
4242 struct scroll_bar *b = XSCROLL_BAR (bar);
4244 x_scroll_bar_remove (b);
4246 next = b->next;
4247 b->next = b->prev = Qnil;
4250 /* Now there should be no references to the condemned scroll bars,
4251 and they should get garbage-collected. */
4254 /* Handle a mouse click on the vertical scroll bar BAR. If
4255 *EMACS_EVENT's kind is set to something other than NO_EVENT, it is
4256 enqueued.
4258 This may be called from a signal handler, so we have to ignore GC
4259 mark bits. */
4261 static int
4262 w32_scroll_bar_handle_click (struct scroll_bar *bar, W32Msg *msg,
4263 struct input_event *emacs_event)
4265 if (! WINDOWP (bar->window))
4266 emacs_abort ();
4268 emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
4269 emacs_event->code = 0;
4270 /* not really meaningful to distinguish up/down */
4271 emacs_event->modifiers = msg->dwModifiers;
4272 emacs_event->frame_or_window = bar->window;
4273 emacs_event->arg = Qnil;
4274 emacs_event->timestamp = msg->msg.time;
4277 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, bar->height);
4278 int y;
4279 int dragging = bar->dragging;
4280 SCROLLINFO si;
4281 int sb_event = LOWORD (msg->msg.wParam);
4283 si.cbSize = sizeof (si);
4284 if (sb_event == SB_THUMBTRACK)
4285 si.fMask = SIF_TRACKPOS;
4286 else
4287 si.fMask = SIF_POS;
4289 GetScrollInfo ((HWND) msg->msg.lParam, SB_CTL, &si);
4290 if (sb_event == SB_THUMBTRACK)
4291 y = si.nTrackPos;
4292 else
4293 y = si.nPos;
4295 bar->dragging = 0;
4296 struct frame *f; /* Value is not used. */
4297 FRAME_DISPLAY_INFO (f)->last_mouse_scroll_bar_pos = msg->msg.wParam;
4299 switch (sb_event)
4301 case SB_LINEDOWN:
4302 emacs_event->part = scroll_bar_down_arrow;
4303 break;
4304 case SB_LINEUP:
4305 emacs_event->part = scroll_bar_up_arrow;
4306 break;
4307 case SB_PAGEUP:
4308 emacs_event->part = scroll_bar_above_handle;
4309 break;
4310 case SB_PAGEDOWN:
4311 emacs_event->part = scroll_bar_below_handle;
4312 break;
4313 case SB_TOP:
4314 emacs_event->part = scroll_bar_handle;
4315 y = 0;
4316 break;
4317 case SB_BOTTOM:
4318 emacs_event->part = scroll_bar_handle;
4319 y = top_range;
4320 break;
4321 case SB_THUMBTRACK:
4322 case SB_THUMBPOSITION:
4323 bar->dragging = 1; /* ??????? */
4324 emacs_event->part = scroll_bar_handle;
4326 /* "Silently" update current position. */
4328 SCROLLINFO si;
4330 si.cbSize = sizeof (si);
4331 si.fMask = SIF_POS;
4332 si.nPos = y;
4333 /* Remember apparent position (we actually lag behind the real
4334 position, so don't set that directly). */
4335 last_scroll_bar_drag_pos = y;
4337 SetScrollInfo (SCROLL_BAR_W32_WINDOW (bar), SB_CTL, &si, FALSE);
4339 break;
4340 case SB_ENDSCROLL:
4341 /* If this is the end of a drag sequence, then reset the scroll
4342 handle size to normal and do a final redraw. Otherwise do
4343 nothing. */
4344 if (dragging)
4346 SCROLLINFO si;
4347 int start = bar->start;
4348 int end = bar->end;
4350 si.cbSize = sizeof (si);
4351 si.fMask = SIF_PAGE | SIF_POS;
4352 si.nPage = end - start + VERTICAL_SCROLL_BAR_MIN_HANDLE;
4353 si.nPos = last_scroll_bar_drag_pos;
4354 SetScrollInfo (SCROLL_BAR_W32_WINDOW (bar), SB_CTL, &si, TRUE);
4356 /* fall through */
4357 FALLTHROUGH;
4358 default:
4359 emacs_event->kind = NO_EVENT;
4360 return FALSE;
4363 XSETINT (emacs_event->x, y);
4364 XSETINT (emacs_event->y, top_range);
4366 return TRUE;
4370 /* Handle a mouse click on the horizontal scroll bar BAR. If
4371 *EMACS_EVENT's kind is set to something other than NO_EVENT, it is
4372 enqueued.
4374 This may be called from a signal handler, so we have to ignore GC
4375 mark bits. */
4377 static int
4378 w32_horizontal_scroll_bar_handle_click (struct scroll_bar *bar, W32Msg *msg,
4379 struct input_event *emacs_event)
4381 if (! WINDOWP (bar->window))
4382 emacs_abort ();
4384 emacs_event->kind = HORIZONTAL_SCROLL_BAR_CLICK_EVENT;
4385 emacs_event->code = 0;
4386 /* not really meaningful to distinguish left/right */
4387 emacs_event->modifiers = msg->dwModifiers;
4388 emacs_event->frame_or_window = bar->window;
4389 emacs_event->arg = Qnil;
4390 emacs_event->timestamp = msg->msg.time;
4393 int left_range = HORIZONTAL_SCROLL_BAR_LEFT_RANGE (f, bar->width);
4394 int x, y;
4395 int dragging = bar->dragging;
4396 SCROLLINFO si;
4397 int sb_event = LOWORD (msg->msg.wParam);
4399 si.cbSize = sizeof (si);
4400 if (sb_event == SB_THUMBTRACK)
4401 si.fMask = SIF_TRACKPOS | SIF_PAGE | SIF_RANGE;
4402 else
4403 si.fMask = SIF_POS | SIF_PAGE | SIF_RANGE;
4405 GetScrollInfo ((HWND) msg->msg.lParam, SB_CTL, &si);
4406 if (sb_event == SB_THUMBTRACK)
4407 x = si.nTrackPos;
4408 else
4409 x = si.nPos;
4410 y = si.nMax - si.nPage;
4412 bar->dragging = 0;
4413 struct frame *f; /* Value is not used. */
4414 FRAME_DISPLAY_INFO (f)->last_mouse_scroll_bar_pos = msg->msg.wParam;
4416 switch (sb_event)
4418 case SB_LINELEFT:
4419 emacs_event->part = scroll_bar_left_arrow;
4420 break;
4421 case SB_LINERIGHT:
4422 emacs_event->part = scroll_bar_right_arrow;
4423 break;
4424 case SB_PAGELEFT:
4425 emacs_event->part = scroll_bar_before_handle;
4426 break;
4427 case SB_PAGERIGHT:
4428 emacs_event->part = scroll_bar_after_handle;
4429 break;
4430 case SB_LEFT:
4431 emacs_event->part = scroll_bar_horizontal_handle;
4432 x = 0;
4433 break;
4434 case SB_RIGHT:
4435 emacs_event->part = scroll_bar_horizontal_handle;
4436 x = left_range;
4437 break;
4438 case SB_THUMBTRACK:
4439 case SB_THUMBPOSITION:
4440 bar->dragging = 1;
4441 emacs_event->part = scroll_bar_horizontal_handle;
4443 /* "Silently" update current position. */
4445 SCROLLINFO si;
4447 si.cbSize = sizeof (si);
4448 si.fMask = SIF_POS;
4449 si.nPos = min (x, XWINDOW (bar->window)->hscroll_whole - 1);
4450 /* Remember apparent position (we actually lag behind the real
4451 position, so don't set that directly). */
4452 last_scroll_bar_drag_pos = x;
4454 SetScrollInfo (SCROLL_BAR_W32_WINDOW (bar), SB_CTL, &si, FALSE);
4456 break;
4457 case SB_ENDSCROLL:
4458 /* If this is the end of a drag sequence, then reset the scroll
4459 handle size to normal and do a final redraw. Otherwise do
4460 nothing. */
4461 if (dragging)
4463 SCROLLINFO si;
4465 si.cbSize = sizeof (si);
4466 si.fMask = SIF_POS;
4467 si.nPos = min (last_scroll_bar_drag_pos,
4468 XWINDOW (bar->window)->hscroll_whole - 1);
4469 SetScrollInfo (SCROLL_BAR_W32_WINDOW (bar), SB_CTL, &si, TRUE);
4471 /* fall through */
4472 FALLTHROUGH;
4473 default:
4474 emacs_event->kind = NO_EVENT;
4475 return FALSE;
4478 XSETINT (emacs_event->x, x);
4479 XSETINT (emacs_event->y, y);
4481 return TRUE;
4485 /* Return information to the user about the current position of the mouse
4486 on the vertical scroll bar. */
4487 static void
4488 x_scroll_bar_report_motion (struct frame **fp, Lisp_Object *bar_window,
4489 enum scroll_bar_part *part,
4490 Lisp_Object *x, Lisp_Object *y,
4491 Time *time)
4493 struct w32_display_info *dpyinfo = FRAME_DISPLAY_INFO (*fp);
4494 struct scroll_bar *bar = dpyinfo->last_mouse_scroll_bar;
4495 Window w = SCROLL_BAR_W32_WINDOW (bar);
4496 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
4497 int pos;
4498 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, bar->height);
4499 SCROLLINFO si;
4500 int sb_event = LOWORD (dpyinfo->last_mouse_scroll_bar_pos);
4502 block_input ();
4504 *fp = f;
4505 *bar_window = bar->window;
4507 si.cbSize = sizeof (si);
4508 if (sb_event == SB_THUMBTRACK)
4509 si.fMask = SIF_TRACKPOS | SIF_PAGE | SIF_RANGE;
4510 else
4511 si.fMask = SIF_POS | SIF_PAGE | SIF_RANGE;
4513 GetScrollInfo (w, SB_CTL, &si);
4514 if (sb_event == SB_THUMBTRACK)
4515 pos = si.nTrackPos;
4516 else
4517 pos = si.nPos;
4518 top_range = si.nMax - si.nPage + 1;
4520 *part = scroll_bar_handle;
4521 if (sb_event == SB_LINEDOWN)
4522 pos++;
4524 XSETINT (*x, pos);
4525 XSETINT (*y, top_range);
4527 f->mouse_moved = false;
4528 dpyinfo->last_mouse_scroll_bar = NULL;
4530 *time = dpyinfo->last_mouse_movement_time;
4532 unblock_input ();
4535 /* Return information to the user about the current position of the mouse
4536 on the horizontal scroll bar. */
4537 static void
4538 x_horizontal_scroll_bar_report_motion (struct frame **fp, Lisp_Object *bar_window,
4539 enum scroll_bar_part *part,
4540 Lisp_Object *x, Lisp_Object *y,
4541 Time *time)
4543 struct w32_display_info *dpyinfo = FRAME_DISPLAY_INFO (*fp);
4544 struct scroll_bar *bar = dpyinfo->last_mouse_scroll_bar;
4545 Window w = SCROLL_BAR_W32_WINDOW (bar);
4546 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
4547 int pos;
4548 int left_range = HORIZONTAL_SCROLL_BAR_LEFT_RANGE (f, bar->width);
4549 SCROLLINFO si;
4550 int sb_event = LOWORD (dpyinfo->last_mouse_scroll_bar_pos);
4552 block_input ();
4554 *fp = f;
4555 *bar_window = bar->window;
4557 si.cbSize = sizeof (si);
4558 if (sb_event == SB_THUMBTRACK)
4559 si.fMask = SIF_TRACKPOS | SIF_PAGE | SIF_RANGE;
4560 else
4561 si.fMask = SIF_POS | SIF_PAGE | SIF_RANGE;
4563 GetScrollInfo (w, SB_CTL, &si);
4564 if (sb_event == SB_THUMBTRACK)
4565 pos = si.nTrackPos;
4566 else
4567 pos = si.nPos;
4568 left_range = si.nMax - si.nPage + 1;
4570 *part = scroll_bar_handle;
4571 if (sb_event == SB_LINERIGHT)
4572 pos++;
4575 XSETINT (*y, pos);
4576 XSETINT (*x, left_range);
4578 f->mouse_moved = false;
4579 dpyinfo->last_mouse_scroll_bar = NULL;
4581 *time = dpyinfo->last_mouse_movement_time;
4583 unblock_input ();
4587 /* The screen has been cleared so we may have changed foreground or
4588 background colors, and the scroll bars may need to be redrawn.
4589 Clear out the scroll bars, and ask for expose events, so we can
4590 redraw them. */
4592 void
4593 x_scroll_bar_clear (struct frame *f)
4595 Lisp_Object bar;
4597 /* We can have scroll bars even if this is 0,
4598 if we just turned off scroll bar mode.
4599 But in that case we should not clear them. */
4600 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
4601 || FRAME_HAS_HORIZONTAL_SCROLL_BARS (f))
4602 for (bar = FRAME_SCROLL_BARS (f); VECTORP (bar);
4603 bar = XSCROLL_BAR (bar)->next)
4605 HWND window = SCROLL_BAR_W32_WINDOW (XSCROLL_BAR (bar));
4606 HDC hdc = GetDC (window);
4607 RECT rect;
4609 /* Hide scroll bar until ready to repaint. x_scroll_bar_move
4610 arranges to refresh the scroll bar if hidden. */
4611 my_show_window (f, window, SW_HIDE);
4613 GetClientRect (window, &rect);
4614 select_palette (f, hdc);
4615 w32_clear_rect (f, hdc, &rect);
4616 x_clear_under_internal_border (f);
4617 deselect_palette (f, hdc);
4619 ReleaseDC (window, hdc);
4623 /* The main W32 event-reading loop - w32_read_socket. */
4625 /* Record the last 100 characters stored
4626 to help debug the loss-of-chars-during-GC problem. */
4628 static int temp_index;
4629 static short temp_buffer[100];
4631 /* Temporarily store lead byte of DBCS input sequences. */
4632 static char dbcs_lead = 0;
4634 /* Read events coming from the W32 shell.
4635 This routine is called by the SIGIO handler.
4636 We return as soon as there are no more events to be read.
4638 For an overview of how Emacs input works on MS-Windows, see the
4639 commentary before w32_msg_pump in w32fns.c.
4641 We return the number of characters stored into the buffer,
4642 thus pretending to be `read'.
4644 Some of these messages are reposted back to the message queue since the
4645 system calls the windows proc directly in a context where we cannot return
4646 the data nor can we guarantee the state we are in. So if we dispatch them
4647 we will get into an infinite loop. To prevent this from ever happening we
4648 will set a variable to indicate we are in the read_socket call and indicate
4649 which message we are processing since the windows proc gets called
4650 recursively with different messages by the system.
4653 extern void menubar_selection_callback (struct frame *, void *);
4655 static int
4656 w32_read_socket (struct terminal *terminal,
4657 struct input_event *hold_quit)
4659 int count = 0;
4660 int check_visibility = 0;
4661 W32Msg msg;
4662 struct frame *f;
4663 struct w32_display_info *dpyinfo = &one_w32_display_info;
4664 Mouse_HLInfo *hlinfo = &dpyinfo->mouse_highlight;
4666 block_input ();
4668 /* Process any incoming thread messages. */
4669 drain_message_queue ();
4671 /* TODO: ghostscript integration. */
4672 while (get_next_msg (&msg, FALSE))
4674 struct input_event inev;
4675 int do_help = 0;
4677 /* DebPrint (("w32_read_socket: %s time:%u\n", */
4678 /* w32_name_of_message (msg.msg.message), */
4679 /* msg.msg.time)); */
4681 EVENT_INIT (inev);
4682 inev.kind = NO_EVENT;
4683 inev.arg = Qnil;
4685 switch (msg.msg.message)
4687 case WM_EMACS_PAINT:
4688 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
4690 if (f)
4692 if (msg.rect.right == msg.rect.left ||
4693 msg.rect.bottom == msg.rect.top)
4695 /* We may get paint messages even though the client
4696 area is clipped - these are not expose events. */
4697 DebPrint (("clipped frame %p (%s) got WM_PAINT - ignored\n", f,
4698 SDATA (f->name)));
4700 else if (FRAME_VISIBLE_P (f) != 1)
4702 bool iconified = FRAME_ICONIFIED_P (f);
4704 /* Definitely not obscured, so mark as visible. */
4705 SET_FRAME_VISIBLE (f, 1);
4706 SET_FRAME_ICONIFIED (f, false);
4707 SET_FRAME_GARBAGED (f);
4708 if (!f->output_data.w32->asked_for_visible)
4709 DebPrint (("frame %p (%s) reexposed by WM_PAINT\n", f,
4710 SDATA (f->name)));
4712 /* WM_PAINT serves as MapNotify as well, so report
4713 visibility changes properly. */
4714 if (iconified)
4716 inev.kind = DEICONIFY_EVENT;
4717 XSETFRAME (inev.frame_or_window, f);
4719 else if (!NILP (Vframe_list) && !NILP (XCDR (Vframe_list)))
4720 /* Force a redisplay sooner or later to update the
4721 frame titles in case this is the second frame. */
4722 record_asynch_buffer_change ();
4724 else
4726 /* Erase background again for safety. But don't do
4727 that if the frame's 'garbaged' flag is set, since
4728 in that case expose_frame will do nothing, and if
4729 the various redisplay flags happen to be unset,
4730 we are left with a blank frame. */
4731 if (!FRAME_GARBAGED_P (f) || FRAME_PARENT_FRAME (f))
4733 HDC hdc = get_frame_dc (f);
4735 w32_clear_rect (f, hdc, &msg.rect);
4736 release_frame_dc (f, hdc);
4738 expose_frame (f,
4739 msg.rect.left,
4740 msg.rect.top,
4741 msg.rect.right - msg.rect.left,
4742 msg.rect.bottom - msg.rect.top);
4743 x_clear_under_internal_border (f);
4746 break;
4748 case WM_INPUTLANGCHANGE:
4749 /* Generate a language change event. */
4750 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
4752 /* lParam contains the input language ID in its low 16 bits.
4753 Use it to update our record of the keyboard codepage. */
4754 w32_keyboard_codepage = codepage_for_locale ((LCID)(msg.msg.lParam
4755 & 0xffff));
4757 if (f)
4759 inev.kind = LANGUAGE_CHANGE_EVENT;
4760 XSETFRAME (inev.frame_or_window, f);
4761 inev.code = w32_keyboard_codepage;
4762 inev.modifiers = msg.msg.lParam & 0xffff;
4764 break;
4766 case WM_KEYDOWN:
4767 case WM_SYSKEYDOWN:
4768 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
4770 if (f && !FRAME_ICONIFIED_P (f))
4772 if (!hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight)
4773 && !EQ (f->tool_bar_window, hlinfo->mouse_face_window))
4775 clear_mouse_face (hlinfo);
4776 hlinfo->mouse_face_hidden = true;
4779 if (temp_index == sizeof temp_buffer / sizeof (short))
4780 temp_index = 0;
4781 temp_buffer[temp_index++] = msg.msg.wParam;
4782 inev.kind = NON_ASCII_KEYSTROKE_EVENT;
4783 inev.code = msg.msg.wParam;
4784 inev.modifiers = msg.dwModifiers;
4785 XSETFRAME (inev.frame_or_window, f);
4786 inev.timestamp = msg.msg.time;
4788 break;
4790 case WM_UNICHAR:
4791 case WM_SYSCHAR:
4792 case WM_CHAR:
4793 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
4795 if (f && !FRAME_ICONIFIED_P (f))
4797 if (!hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight)
4798 && !EQ (f->tool_bar_window, hlinfo->mouse_face_window))
4800 clear_mouse_face (hlinfo);
4801 hlinfo->mouse_face_hidden = true;
4804 if (temp_index == sizeof temp_buffer / sizeof (short))
4805 temp_index = 0;
4806 temp_buffer[temp_index++] = msg.msg.wParam;
4808 inev.modifiers = msg.dwModifiers;
4809 XSETFRAME (inev.frame_or_window, f);
4810 inev.timestamp = msg.msg.time;
4812 if (msg.msg.message == WM_UNICHAR)
4814 inev.code = msg.msg.wParam;
4816 else if (msg.msg.wParam < 256)
4818 wchar_t code;
4819 char dbcs[2];
4820 dbcs[0] = 0;
4821 dbcs[1] = (char) msg.msg.wParam;
4823 if (dbcs_lead)
4825 dbcs[0] = dbcs_lead;
4826 dbcs_lead = 0;
4827 if (!MultiByteToWideChar (w32_keyboard_codepage, 0,
4828 dbcs, 2, &code, 1))
4830 /* Garbage */
4831 DebPrint (("Invalid DBCS sequence: %d %d\n",
4832 dbcs[0], dbcs[1]));
4833 inev.kind = NO_EVENT;
4834 break;
4837 else if (IsDBCSLeadByteEx (w32_keyboard_codepage,
4838 (BYTE) msg.msg.wParam))
4840 dbcs_lead = (char) msg.msg.wParam;
4841 inev.kind = NO_EVENT;
4842 break;
4844 else
4846 if (!MultiByteToWideChar (w32_keyboard_codepage, 0,
4847 &dbcs[1], 1, &code, 1))
4849 /* What to do with garbage? */
4850 DebPrint (("Invalid character: %d\n", dbcs[1]));
4851 inev.kind = NO_EVENT;
4852 break;
4855 inev.code = code;
4857 else
4859 /* Windows shouldn't generate WM_CHAR events above 0xFF
4860 in non-Unicode message handlers. */
4861 DebPrint (("Non-byte WM_CHAR: %d\n", msg.msg.wParam));
4862 inev.kind = NO_EVENT;
4863 break;
4865 inev.kind = inev.code < 128 ? ASCII_KEYSTROKE_EVENT
4866 : MULTIBYTE_CHAR_KEYSTROKE_EVENT;
4868 break;
4870 case WM_APPCOMMAND:
4871 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
4873 if (f && !FRAME_ICONIFIED_P (f))
4875 if (!hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight)
4876 && !EQ (f->tool_bar_window, hlinfo->mouse_face_window))
4878 clear_mouse_face (hlinfo);
4879 hlinfo->mouse_face_hidden = true;
4882 if (temp_index == sizeof temp_buffer / sizeof (short))
4883 temp_index = 0;
4884 temp_buffer[temp_index++] = msg.msg.wParam;
4885 inev.kind = MULTIMEDIA_KEY_EVENT;
4886 inev.code = GET_APPCOMMAND_LPARAM (msg.msg.lParam);
4887 inev.modifiers = msg.dwModifiers;
4888 XSETFRAME (inev.frame_or_window, f);
4889 inev.timestamp = msg.msg.time;
4891 break;
4893 case WM_MOUSEMOVE:
4894 /* Ignore non-movement. */
4896 int x = LOWORD (msg.msg.lParam);
4897 int y = HIWORD (msg.msg.lParam);
4898 if (x == last_mousemove_x && y == last_mousemove_y)
4899 break;
4900 last_mousemove_x = x;
4901 last_mousemove_y = y;
4904 previous_help_echo_string = help_echo_string;
4905 help_echo_string = Qnil;
4907 f = (x_mouse_grabbed (dpyinfo) ? dpyinfo->last_mouse_frame
4908 : x_window_to_frame (dpyinfo, msg.msg.hwnd));
4910 if (hlinfo->mouse_face_hidden)
4912 hlinfo->mouse_face_hidden = false;
4913 clear_mouse_face (hlinfo);
4916 if (f)
4918 /* Maybe generate SELECT_WINDOW_EVENTs for
4919 `mouse-autoselect-window'. */
4920 if (!NILP (Vmouse_autoselect_window)
4921 && (f == XFRAME (selected_frame)
4922 /* Switch to f from another frame iff
4923 focus_follows_mouse is set and f accepts
4924 focus. */
4925 || (!NILP (focus_follows_mouse)
4926 && !FRAME_NO_ACCEPT_FOCUS (f))))
4928 static Lisp_Object last_mouse_window;
4929 Lisp_Object window = window_from_coordinates
4930 (f, LOWORD (msg.msg.lParam), HIWORD (msg.msg.lParam), 0, 0);
4932 /* Window will be selected only when it is not
4933 selected now and last mouse movement event was
4934 not in it. Minibuffer window will be selected
4935 only when it is active. */
4936 if (WINDOWP (window)
4937 && !EQ (window, last_mouse_window)
4938 && !EQ (window, selected_window))
4940 inev.kind = SELECT_WINDOW_EVENT;
4941 inev.frame_or_window = window;
4944 /* Remember the last window where we saw the mouse. */
4945 last_mouse_window = window;
4948 if (!note_mouse_movement (f, &msg.msg))
4949 help_echo_string = previous_help_echo_string;
4951 else
4953 /* If we move outside the frame, then we're
4954 certainly no longer on any text in the frame. */
4955 clear_mouse_face (hlinfo);
4958 /* If the contents of the global variable help_echo_string
4959 has changed, generate a HELP_EVENT. */
4960 #if 0 /* The below is an invalid comparison when CHECK_LISP_OBJECT_TYPE.
4961 But it was originally changed to this to fix a bug, so I have
4962 not removed it completely in case the bug is still there. */
4963 if (help_echo_string != previous_help_echo_string ||
4964 (!NILP (help_echo_string) && !STRINGP (help_echo_string) && f->mouse_moved))
4965 #else /* This is what xterm.c does. */
4966 if (!NILP (help_echo_string)
4967 || !NILP (previous_help_echo_string))
4968 do_help = 1;
4969 #endif
4970 break;
4972 case WM_LBUTTONDOWN:
4973 case WM_LBUTTONUP:
4974 case WM_MBUTTONDOWN:
4975 case WM_MBUTTONUP:
4976 case WM_RBUTTONDOWN:
4977 case WM_RBUTTONUP:
4978 case WM_XBUTTONDOWN:
4979 case WM_XBUTTONUP:
4981 /* If we decide we want to generate an event to be seen
4982 by the rest of Emacs, we put it here. */
4983 bool tool_bar_p = 0;
4984 int button = 0;
4985 int up = 0;
4987 f = (x_mouse_grabbed (dpyinfo) ? dpyinfo->last_mouse_frame
4988 : x_window_to_frame (dpyinfo, msg.msg.hwnd));
4990 if (f)
4992 construct_mouse_click (&inev, &msg, f);
4994 /* Is this in the tool-bar? */
4995 if (WINDOWP (f->tool_bar_window)
4996 && WINDOW_TOTAL_LINES (XWINDOW (f->tool_bar_window)))
4998 Lisp_Object window;
4999 int x = XFASTINT (inev.x);
5000 int y = XFASTINT (inev.y);
5002 window = window_from_coordinates (f, x, y, 0, 1);
5004 if (EQ (window, f->tool_bar_window))
5006 w32_handle_tool_bar_click (f, &inev);
5007 tool_bar_p = 1;
5011 if (tool_bar_p
5012 || (dpyinfo->w32_focus_frame
5013 && f != dpyinfo->w32_focus_frame
5014 /* This does not help when the click happens in
5015 a grand-parent frame. */
5016 && !frame_ancestor_p (f, dpyinfo->w32_focus_frame)))
5017 inev.kind = NO_EVENT;
5020 parse_button (msg.msg.message, HIWORD (msg.msg.wParam),
5021 &button, &up);
5023 if (up)
5025 dpyinfo->grabbed &= ~ (1 << button);
5027 else
5029 dpyinfo->grabbed |= (1 << button);
5030 dpyinfo->last_mouse_frame = f;
5031 /* Ignore any mouse motion that happened
5032 before this event; any subsequent mouse-movement
5033 Emacs events should reflect only motion after
5034 the ButtonPress. */
5035 if (f != 0)
5037 f->mouse_moved = false;
5038 if (!tool_bar_p)
5039 f->last_tool_bar_item = -1;
5042 break;
5045 case WM_MOUSEWHEEL:
5046 case WM_MOUSEHWHEEL:
5048 f = (x_mouse_grabbed (dpyinfo) ? dpyinfo->last_mouse_frame
5049 : x_window_to_frame (dpyinfo, msg.msg.hwnd));
5051 if (f)
5053 if (!dpyinfo->w32_focus_frame
5054 || f == dpyinfo->w32_focus_frame)
5055 /* Emit an Emacs wheel-up/down event. */
5057 construct_mouse_wheel (&inev, &msg, f);
5059 /* Ignore any mouse motion that happened before this
5060 event; any subsequent mouse-movement Emacs events
5061 should reflect only motion after the ButtonPress. */
5062 f->mouse_moved = false;
5063 f->last_tool_bar_item = -1;
5064 dpyinfo->last_mouse_frame = f;
5066 else if (FRAME_NO_ACCEPT_FOCUS (f)
5067 && !x_mouse_grabbed (dpyinfo))
5069 Lisp_Object frame1 = get_frame_param (f, Qmouse_wheel_frame);
5070 struct frame *f1 = FRAMEP (frame1) ? XFRAME (frame1) : NULL;
5072 if (f1 && FRAME_LIVE_P (f1) && FRAME_W32_P (f1))
5074 construct_mouse_wheel (&inev, &msg, f1);
5075 f1->mouse_moved = false;
5076 f1->last_tool_bar_item = -1;
5077 dpyinfo->last_mouse_frame = f1;
5079 else
5080 dpyinfo->last_mouse_frame = f;
5082 else
5083 dpyinfo->last_mouse_frame = f;
5085 else
5086 dpyinfo->last_mouse_frame = f;
5088 break;
5090 case WM_DROPFILES:
5091 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
5093 if (f)
5094 construct_drag_n_drop (&inev, &msg, f);
5095 break;
5097 case WM_HSCROLL:
5099 struct scroll_bar *bar =
5100 x_window_to_scroll_bar ((HWND)msg.msg.lParam, 1);
5102 if (bar)
5103 w32_horizontal_scroll_bar_handle_click (bar, &msg, &inev);
5104 break;
5107 case WM_VSCROLL:
5109 struct scroll_bar *bar =
5110 x_window_to_scroll_bar ((HWND)msg.msg.lParam, 0);
5112 if (bar)
5113 w32_scroll_bar_handle_click (bar, &msg, &inev);
5114 break;
5117 case WM_WINDOWPOSCHANGED:
5118 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
5120 if (f)
5122 RECT rect;
5123 int /* rows, columns, */ width, height, text_width, text_height;
5125 if (GetClientRect (msg.msg.hwnd, &rect)
5126 /* GetClientRect evidently returns (0, 0, 0, 0) if
5127 called on a minimized frame. Such "dimensions"
5128 aren't useful anyway. */
5129 && !(rect.bottom == 0
5130 && rect.top == 0
5131 && rect.left == 0
5132 && rect.right == 0))
5134 height = rect.bottom - rect.top;
5135 width = rect.right - rect.left;
5136 text_width = FRAME_PIXEL_TO_TEXT_WIDTH (f, width);
5137 text_height = FRAME_PIXEL_TO_TEXT_HEIGHT (f, height);
5138 /* rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, height); */
5139 /* columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, width); */
5141 /* TODO: Clip size to the screen dimensions. */
5143 /* Even if the number of character rows and columns
5144 has not changed, the font size may have changed,
5145 so we need to check the pixel dimensions as well. */
5147 if (width != FRAME_PIXEL_WIDTH (f)
5148 || height != FRAME_PIXEL_HEIGHT (f)
5149 || text_width != FRAME_TEXT_WIDTH (f)
5150 || text_height != FRAME_TEXT_HEIGHT (f))
5152 change_frame_size (f, text_width, text_height, 0, 1, 0, 1);
5153 SET_FRAME_GARBAGED (f);
5154 cancel_mouse_face (f);
5155 f->win_gravity = NorthWestGravity;
5160 check_visibility = 1;
5161 break;
5163 case WM_ACTIVATE:
5164 case WM_ACTIVATEAPP:
5165 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
5166 if (f)
5168 /* Run the full-screen hook function also when we are
5169 being activated, to actually install the required
5170 size in effect, if the WAIT flag is set. This is
5171 because when the hook is run from x_set_fullscreen,
5172 the frame might not yet be visible, if that call is a
5173 result of make-frame, and in that case the hook just
5174 sets the WAIT flag. */
5175 if ((msg.msg.message == WM_WINDOWPOSCHANGED || msg.msg.wParam)
5176 && (f->want_fullscreen & FULLSCREEN_WAIT))
5178 /* Must set visibility right here since otherwise
5179 w32fullscreen_hook returns immediately. */
5180 SET_FRAME_VISIBLE (f, 1);
5181 w32fullscreen_hook (f);
5185 check_visibility = 1;
5186 break;
5188 case WM_MOVE:
5189 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
5191 if (f && FRAME_VISIBLE_P (f) && !FRAME_ICONIFIED_P(f))
5193 x_real_positions (f, &f->left_pos, &f->top_pos);
5194 inev.kind = MOVE_FRAME_EVENT;
5195 XSETFRAME (inev.frame_or_window, f);
5198 check_visibility = 1;
5199 break;
5201 case WM_SHOWWINDOW:
5202 /* wParam non-zero means Window is about to be shown, 0 means
5203 about to be hidden. */
5204 /* Redo the mouse-highlight after the tooltip has gone. */
5205 if (!msg.msg.wParam && msg.msg.hwnd == tip_window)
5207 tip_window = NULL;
5208 x_redo_mouse_highlight (dpyinfo);
5211 /* If window has been obscured or exposed by another window
5212 being maximized or minimized/restored, then recheck
5213 visibility of all frames. Direct changes to our own
5214 windows get handled by WM_SIZE. */
5215 #if 0
5216 if (msg.msg.lParam != 0)
5217 check_visibility = 1;
5218 else
5220 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
5221 f->async_visible = msg.msg.wParam;
5223 #endif
5225 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
5226 if (f)
5227 x_clear_under_internal_border (f);
5229 check_visibility = 1;
5230 break;
5232 case WM_SIZE:
5233 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
5235 /* Inform lisp of whether frame has been iconified etc. */
5236 if (f)
5238 switch (msg.msg.wParam)
5240 case SIZE_MINIMIZED:
5241 SET_FRAME_VISIBLE (f, 0);
5242 SET_FRAME_ICONIFIED (f, true);
5244 inev.kind = ICONIFY_EVENT;
5245 XSETFRAME (inev.frame_or_window, f);
5246 break;
5248 case SIZE_MAXIMIZED:
5250 bool iconified = FRAME_ICONIFIED_P (f);
5251 Lisp_Object fullscreen = get_frame_param (f, Qfullscreen);
5253 SET_FRAME_VISIBLE (f, 1);
5254 SET_FRAME_ICONIFIED (f, false);
5256 /* wait_reading_process_output will notice this
5257 and update the frame's display structures. */
5258 SET_FRAME_GARBAGED (f);
5260 if (iconified)
5262 int x, y;
5264 /* Reset top and left positions of the Window
5265 here since Windows sends a WM_MOVE message
5266 BEFORE telling us the Window is minimized
5267 when the Window is iconified, with 3000,3000
5268 as the co-ords. */
5269 x_real_positions (f, &x, &y);
5270 f->left_pos = x;
5271 f->top_pos = y;
5273 inev.kind = DEICONIFY_EVENT;
5274 XSETFRAME (inev.frame_or_window, f);
5276 else if (! NILP (Vframe_list)
5277 && ! NILP (XCDR (Vframe_list)))
5278 /* Force a redisplay sooner or later
5279 to update the frame titles
5280 in case this is the second frame. */
5281 record_asynch_buffer_change ();
5283 /* Windows can send us a SIZE_MAXIMIZED message even
5284 when fullscreen is fullboth. The following is a
5285 simple hack to check that based on the fact that
5286 only a maximized fullscreen frame should have both
5287 top/left outside the screen. */
5288 if (EQ (fullscreen, Qfullwidth) || EQ (fullscreen, Qfullheight)
5289 || NILP (fullscreen))
5291 int x, y;
5293 x_real_positions (f, &x, &y);
5294 if (x < 0 && y < 0)
5295 store_frame_param (f, Qfullscreen, Qmaximized);
5299 break;
5301 case SIZE_RESTORED:
5303 bool iconified = FRAME_ICONIFIED_P (f);
5305 /* The following was made unconditional in a
5306 pathetic attempt to fix bug#16967 in revision
5307 116716 but, considered counterproductive was made
5308 conditional again in revision 116727. martin */
5309 if (iconified)
5310 SET_FRAME_VISIBLE (f, 1);
5311 SET_FRAME_ICONIFIED (f, false);
5313 /* wait_reading_process_output will notice this
5314 and update the frame's display structures. */
5315 SET_FRAME_GARBAGED (f);
5317 if (iconified)
5319 /* Reset top and left positions of the Window
5320 here since Windows sends a WM_MOVE message
5321 BEFORE telling us the Window is minimized
5322 when the Window is iconified, with 3000,3000
5323 as the co-ords. */
5324 x_real_positions (f, &f->left_pos, &f->top_pos);
5326 inev.kind = DEICONIFY_EVENT;
5327 XSETFRAME (inev.frame_or_window, f);
5329 else if (! NILP (Vframe_list)
5330 && ! NILP (XCDR (Vframe_list)))
5331 /* Force a redisplay sooner or later
5332 to update the frame titles
5333 in case this is the second frame. */
5334 record_asynch_buffer_change ();
5337 if (EQ (get_frame_param (f, Qfullscreen), Qmaximized))
5338 store_frame_param (f, Qfullscreen, Qnil);
5340 break;
5344 if (f && !FRAME_ICONIFIED_P (f) && msg.msg.wParam != SIZE_MINIMIZED)
5346 RECT rect;
5347 int /* rows, columns, */ width, height, text_width, text_height;
5349 if (GetClientRect (msg.msg.hwnd, &rect)
5350 /* GetClientRect evidently returns (0, 0, 0, 0) if
5351 called on a minimized frame. Such "dimensions"
5352 aren't useful anyway. */
5353 && !(rect.bottom == 0
5354 && rect.top == 0
5355 && rect.left == 0
5356 && rect.right == 0))
5358 height = rect.bottom - rect.top;
5359 width = rect.right - rect.left;
5360 text_width = FRAME_PIXEL_TO_TEXT_WIDTH (f, width);
5361 text_height = FRAME_PIXEL_TO_TEXT_HEIGHT (f, height);
5362 /* rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, height); */
5363 /* columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, width); */
5365 /* TODO: Clip size to the screen dimensions. */
5367 /* Even if the number of character rows and columns
5368 has not changed, the font size may have changed,
5369 so we need to check the pixel dimensions as well. */
5371 if (width != FRAME_PIXEL_WIDTH (f)
5372 || height != FRAME_PIXEL_HEIGHT (f)
5373 || text_width != FRAME_TEXT_WIDTH (f)
5374 || text_height != FRAME_TEXT_HEIGHT (f))
5376 change_frame_size (f, text_width, text_height, 0, 1, 0, 1);
5377 SET_FRAME_GARBAGED (f);
5378 cancel_mouse_face (f);
5379 f->win_gravity = NorthWestGravity;
5384 check_visibility = 1;
5385 break;
5387 case WM_MOUSELEAVE:
5388 f = x_any_window_to_frame (dpyinfo, msg.msg.hwnd);
5389 if (f)
5391 if (f == hlinfo->mouse_face_mouse_frame)
5393 /* If we move outside the frame, then we're
5394 certainly no longer on any text in the frame. */
5395 clear_mouse_face (hlinfo);
5396 hlinfo->mouse_face_mouse_frame = 0;
5399 /* Generate a nil HELP_EVENT to cancel a help-echo.
5400 Do it only if there's something to cancel.
5401 Otherwise, the startup message is cleared when
5402 the mouse leaves the frame. */
5403 if (any_help_event_p)
5404 do_help = -1;
5406 break;
5408 case WM_SETFOCUS:
5409 w32_detect_focus_change (dpyinfo, &msg, &inev);
5411 dpyinfo->grabbed = 0;
5412 check_visibility = 1;
5413 break;
5415 case WM_KILLFOCUS:
5416 w32_detect_focus_change (dpyinfo, &msg, &inev);
5417 f = x_top_window_to_frame (dpyinfo, msg.msg.hwnd);
5419 if (f)
5421 if (f == hlinfo->mouse_face_mouse_frame)
5423 /* If we move outside the frame, then we're
5424 certainly no longer on any text in the frame. */
5425 clear_mouse_face (hlinfo);
5426 hlinfo->mouse_face_mouse_frame = 0;
5429 /* Generate a nil HELP_EVENT to cancel a help-echo.
5430 Do it only if there's something to cancel.
5431 Otherwise, the startup message is cleared when
5432 the mouse leaves the frame. */
5433 if (any_help_event_p)
5434 do_help = -1;
5437 dpyinfo->grabbed = 0;
5438 check_visibility = 1;
5439 break;
5441 case WM_CLOSE:
5442 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
5444 if (f)
5446 inev.kind = DELETE_WINDOW_EVENT;
5447 XSETFRAME (inev.frame_or_window, f);
5449 break;
5451 case WM_ENDSESSION:
5452 inev.kind = END_SESSION_EVENT;
5453 break;
5455 case WM_INITMENU:
5456 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
5458 if (f)
5460 inev.kind = MENU_BAR_ACTIVATE_EVENT;
5461 XSETFRAME (inev.frame_or_window, f);
5463 break;
5465 case WM_COMMAND:
5466 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
5468 if (f)
5470 menubar_selection_callback (f, (void *)msg.msg.wParam);
5473 check_visibility = 1;
5474 break;
5476 case WM_DISPLAYCHANGE:
5477 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
5479 if (f)
5481 Lisp_Object fullscreen = get_frame_param (f, Qfullscreen);
5483 dpyinfo->n_cbits = msg.msg.wParam;
5484 /* The new display could have a different resolution, in
5485 which case we must reconsider what fullscreen means.
5486 The following code is untested yet. */
5487 if (!NILP (fullscreen))
5489 x_set_fullscreen (f, fullscreen, fullscreen);
5490 w32fullscreen_hook (f);
5493 DebPrint (("display change: %d %d\n",
5494 (short) LOWORD (msg.msg.lParam),
5495 (short) HIWORD (msg.msg.lParam)));
5498 check_visibility = 1;
5499 break;
5501 #if HAVE_W32NOTIFY
5502 case WM_EMACS_FILENOTIFY:
5503 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
5504 if (f)
5505 queue_notifications (&inev, &msg, f, &count);
5506 break;
5507 #endif
5509 default:
5510 /* Check for messages registered at runtime. */
5511 if (msg.msg.message == msh_mousewheel)
5513 /* Forward MSH_MOUSEWHEEL as WM_MOUSEWHEEL. */
5514 msg.msg.message = WM_MOUSEWHEEL;
5515 prepend_msg (&msg);
5517 break;
5520 if (inev.kind != NO_EVENT)
5522 kbd_buffer_store_event_hold (&inev, hold_quit);
5523 count++;
5526 if (do_help
5527 && !(hold_quit && hold_quit->kind != NO_EVENT))
5529 Lisp_Object frame;
5531 if (f)
5532 XSETFRAME (frame, f);
5533 else
5534 frame = Qnil;
5536 if (do_help > 0)
5538 if (NILP (help_echo_string))
5540 help_echo_object = help_echo_window = Qnil;
5541 help_echo_pos = -1;
5544 any_help_event_p = 1;
5545 gen_help_event (help_echo_string, frame, help_echo_window,
5546 help_echo_object, help_echo_pos);
5548 else
5550 help_echo_string = Qnil;
5551 gen_help_event (Qnil, frame, Qnil, Qnil, 0);
5553 count++;
5557 /* If the focus was just given to an autoraising frame,
5558 raise it now. FIXME: handle more than one such frame. */
5559 if (dpyinfo->w32_pending_autoraise_frame)
5561 x_raise_frame (dpyinfo->w32_pending_autoraise_frame);
5562 dpyinfo->w32_pending_autoraise_frame = NULL;
5565 /* Check which frames are still visible, if we have enqueued any user
5566 events or been notified of events that may affect visibility. We
5567 do this here because there doesn't seem to be any direct
5568 notification from Windows that the visibility of a window has
5569 changed (at least, not in all cases). */
5570 if (count > 0 || check_visibility)
5572 Lisp_Object tail, frame;
5574 FOR_EACH_FRAME (tail, frame)
5576 struct frame *f = XFRAME (frame);
5577 /* The tooltip has been drawn already. Avoid the
5578 SET_FRAME_GARBAGED below. */
5579 if (FRAME_TOOLTIP_P (f))
5580 continue;
5582 /* Check "visible" frames and mark each as obscured or not.
5583 Note that visible is nonzero for unobscured and obscured
5584 frames, but zero for hidden and iconified frames. */
5585 if (FRAME_W32_P (f) && FRAME_VISIBLE_P (f))
5587 RECT clipbox;
5588 HDC hdc;
5589 bool obscured;
5591 enter_crit ();
5592 /* Query clipping rectangle for the entire window area
5593 (GetWindowDC), not just the client portion (GetDC).
5594 Otherwise, the scrollbars and menubar aren't counted as
5595 part of the visible area of the frame, and we may think
5596 the frame is obscured when really a scrollbar is still
5597 visible and gets WM_PAINT messages above. */
5598 hdc = GetWindowDC (FRAME_W32_WINDOW (f));
5599 GetClipBox (hdc, &clipbox);
5600 ReleaseDC (FRAME_W32_WINDOW (f), hdc);
5601 leave_crit ();
5603 obscured = FRAME_OBSCURED_P (f);
5605 if (clipbox.right == clipbox.left || clipbox.bottom == clipbox.top)
5607 /* Frame has become completely obscured so mark as such (we
5608 do this by setting visible to 2 so that FRAME_VISIBLE_P
5609 is still true, but redisplay will skip it). */
5610 SET_FRAME_VISIBLE (f, 2);
5612 if (!obscured)
5613 DebPrint (("frame %p (%s) obscured\n", f, SDATA (f->name)));
5615 else
5617 /* Frame is not obscured, so mark it as such. */
5618 SET_FRAME_VISIBLE (f, 1);
5620 if (obscured)
5622 SET_FRAME_GARBAGED (f);
5623 DebPrint (("obscured frame %p (%s) found to be visible\n",
5624 f, SDATA (f->name)));
5626 /* Force a redisplay sooner or later. */
5627 record_asynch_buffer_change ();
5634 unblock_input ();
5635 return count;
5640 /***********************************************************************
5641 Text Cursor
5642 ***********************************************************************/
5644 /* Set clipping for output in glyph row ROW. W is the window in which
5645 we operate. GC is the graphics context to set clipping in.
5647 ROW may be a text row or, e.g., a mode line. Text rows must be
5648 clipped to the interior of the window dedicated to text display,
5649 mode lines must be clipped to the whole window. */
5651 static void
5652 w32_clip_to_row (struct window *w, struct glyph_row *row,
5653 enum glyph_row_area area, HDC hdc)
5655 RECT clip_rect;
5656 int window_x, window_y, window_width;
5658 window_box (w, area, &window_x, &window_y, &window_width, 0);
5660 clip_rect.left = window_x;
5661 clip_rect.top = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
5662 clip_rect.top = max (clip_rect.top, window_y);
5663 clip_rect.right = clip_rect.left + window_width;
5664 clip_rect.bottom = clip_rect.top + row->visible_height;
5666 w32_set_clip_rectangle (hdc, &clip_rect);
5670 /* Draw a hollow box cursor on window W in glyph row ROW. */
5672 static void
5673 x_draw_hollow_cursor (struct window *w, struct glyph_row *row)
5675 struct frame *f = XFRAME (WINDOW_FRAME (w));
5676 HDC hdc;
5677 RECT rect;
5678 int left, top, h;
5679 struct glyph *cursor_glyph;
5680 HBRUSH hb = CreateSolidBrush (f->output_data.w32->cursor_pixel);
5682 /* Get the glyph the cursor is on. If we can't tell because
5683 the current matrix is invalid or such, give up. */
5684 cursor_glyph = get_phys_cursor_glyph (w);
5685 if (cursor_glyph == NULL)
5687 DeleteObject (hb);
5688 return;
5691 /* Compute frame-relative coordinates for phys cursor. */
5692 get_phys_cursor_geometry (w, row, cursor_glyph, &left, &top, &h);
5693 rect.left = left;
5694 /* When on R2L character, show cursor at the right edge of the
5695 glyph, unless the cursor box is as wide as the glyph or wider
5696 (the latter happens when x-stretch-cursor is non-nil). */
5697 if ((cursor_glyph->resolved_level & 1) != 0
5698 && cursor_glyph->pixel_width > w->phys_cursor_width)
5699 rect.left += cursor_glyph->pixel_width - w->phys_cursor_width;
5700 rect.top = top;
5701 rect.bottom = rect.top + h;
5702 rect.right = rect.left + w->phys_cursor_width;
5704 hdc = get_frame_dc (f);
5705 /* Set clipping, draw the rectangle, and reset clipping again. */
5706 w32_clip_to_row (w, row, TEXT_AREA, hdc);
5707 FrameRect (hdc, &rect, hb);
5708 DeleteObject (hb);
5709 w32_set_clip_rectangle (hdc, NULL);
5710 release_frame_dc (f, hdc);
5714 /* Draw a bar cursor on window W in glyph row ROW.
5716 Implementation note: One would like to draw a bar cursor with an
5717 angle equal to the one given by the font property XA_ITALIC_ANGLE.
5718 Unfortunately, I didn't find a font yet that has this property set.
5719 --gerd. */
5721 static void
5722 x_draw_bar_cursor (struct window *w, struct glyph_row *row,
5723 int width, enum text_cursor_kinds kind)
5725 struct frame *f = XFRAME (w->frame);
5726 struct glyph *cursor_glyph;
5728 /* If cursor is out of bounds, don't draw garbage. This can happen
5729 in mini-buffer windows when switching between echo area glyphs
5730 and mini-buffer. */
5731 cursor_glyph = get_phys_cursor_glyph (w);
5732 if (cursor_glyph == NULL)
5733 return;
5735 /* If on an image, draw like a normal cursor. That's usually better
5736 visible than drawing a bar, esp. if the image is large so that
5737 the bar might not be in the window. */
5738 if (cursor_glyph->type == IMAGE_GLYPH)
5740 struct glyph_row *row;
5741 row = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos);
5742 draw_phys_cursor_glyph (w, row, DRAW_CURSOR);
5744 else
5746 COLORREF cursor_color = f->output_data.w32->cursor_pixel;
5747 struct face *face = FACE_FROM_ID (f, cursor_glyph->face_id);
5748 int x;
5749 HDC hdc;
5751 /* If the glyph's background equals the color we normally draw
5752 the bar cursor in, the bar cursor in its normal color is
5753 invisible. Use the glyph's foreground color instead in this
5754 case, on the assumption that the glyph's colors are chosen so
5755 that the glyph is legible. */
5756 if (face->background == cursor_color)
5757 cursor_color = face->foreground;
5759 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
5761 hdc = get_frame_dc (f);
5762 w32_clip_to_row (w, row, TEXT_AREA, hdc);
5764 if (kind == BAR_CURSOR)
5766 if (width < 0)
5767 width = FRAME_CURSOR_WIDTH (f);
5768 width = min (cursor_glyph->pixel_width, width);
5770 w->phys_cursor_width = width;
5772 /* If the character under cursor is R2L, draw the bar cursor
5773 on the right of its glyph, rather than on the left. */
5774 if ((cursor_glyph->resolved_level & 1) != 0)
5775 x += cursor_glyph->pixel_width - width;
5777 w32_fill_area (f, hdc, cursor_color, x,
5778 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
5779 width, row->height);
5781 else /* HBAR_CURSOR */
5783 int dummy_x, dummy_y, dummy_h;
5785 if (width < 0)
5786 width = row->height;
5788 width = min (row->height, width);
5790 get_phys_cursor_geometry (w, row, cursor_glyph, &dummy_x,
5791 &dummy_y, &dummy_h);
5792 if ((cursor_glyph->resolved_level & 1) != 0
5793 && cursor_glyph->pixel_width > w->phys_cursor_width)
5794 x += cursor_glyph->pixel_width - w->phys_cursor_width;
5795 w32_fill_area (f, hdc, cursor_color, x,
5796 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y +
5797 row->height - width),
5798 w->phys_cursor_width, width);
5801 w32_set_clip_rectangle (hdc, NULL);
5802 release_frame_dc (f, hdc);
5807 /* RIF: Define cursor CURSOR on frame F. */
5809 static void
5810 w32_define_frame_cursor (struct frame *f, Cursor cursor)
5812 w32_define_cursor (FRAME_W32_WINDOW (f), cursor);
5816 /* RIF: Clear area on frame F. */
5818 static void
5819 w32_clear_frame_area (struct frame *f, int x, int y, int width, int height)
5821 HDC hdc;
5823 hdc = get_frame_dc (f);
5824 w32_clear_area (f, hdc, x, y, width, height);
5825 release_frame_dc (f, hdc);
5828 /* RIF: Draw or clear cursor on window W. */
5830 static void
5831 w32_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
5832 int x, int y, enum text_cursor_kinds cursor_type,
5833 int cursor_width, bool on_p, bool active_p)
5835 if (on_p)
5837 /* If the user wants to use the system caret, make sure our own
5838 cursor remains invisible. */
5839 if (w32_use_visible_system_caret)
5841 /* Call to erase_phys_cursor here seems to use the
5842 wrong values of w->phys_cursor, as they have been
5843 overwritten before this function was called. */
5844 if (w->phys_cursor_type != NO_CURSOR)
5845 erase_phys_cursor (w);
5847 cursor_type = w->phys_cursor_type = NO_CURSOR;
5848 w->phys_cursor_width = -1;
5850 else
5852 w->phys_cursor_type = cursor_type;
5855 w->phys_cursor_on_p = true;
5857 /* If this is the active cursor, we need to track it with the
5858 system caret, so third party software like screen magnifiers
5859 and speech synthesizers can follow the cursor. */
5860 if (active_p)
5862 struct frame *f = XFRAME (WINDOW_FRAME (w));
5863 HWND hwnd = FRAME_W32_WINDOW (f);
5865 w32_system_caret_x
5866 = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
5867 w32_system_caret_y
5868 = (WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y)
5869 + glyph_row->ascent - w->phys_cursor_ascent);
5870 w32_system_caret_window = w;
5871 w32_system_caret_hdr_height = WINDOW_HEADER_LINE_HEIGHT (w);
5872 w32_system_caret_mode_height = WINDOW_MODE_LINE_HEIGHT (w);
5874 PostMessage (hwnd, WM_IME_STARTCOMPOSITION, 0, 0);
5876 /* If the size of the active cursor changed, destroy the old
5877 system caret. */
5878 if (w32_system_caret_hwnd
5879 && (w32_system_caret_height != w->phys_cursor_height))
5880 PostMessage (hwnd, WM_EMACS_DESTROY_CARET, 0, 0);
5882 w32_system_caret_height = w->phys_cursor_height;
5884 /* Move the system caret. */
5885 PostMessage (hwnd, WM_EMACS_TRACK_CARET, 0, 0);
5888 if (glyph_row->exact_window_width_line_p
5889 && (glyph_row->reversed_p
5890 ? (w->phys_cursor.hpos < 0)
5891 : (w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])))
5893 glyph_row->cursor_in_fringe_p = true;
5894 draw_fringe_bitmap (w, glyph_row, glyph_row->reversed_p);
5895 return;
5898 switch (cursor_type)
5900 case HOLLOW_BOX_CURSOR:
5901 x_draw_hollow_cursor (w, glyph_row);
5902 break;
5904 case FILLED_BOX_CURSOR:
5905 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
5906 break;
5908 case BAR_CURSOR:
5909 x_draw_bar_cursor (w, glyph_row, cursor_width, BAR_CURSOR);
5910 break;
5912 case HBAR_CURSOR:
5913 x_draw_bar_cursor (w, glyph_row, cursor_width, HBAR_CURSOR);
5914 break;
5916 case NO_CURSOR:
5917 w->phys_cursor_width = 0;
5918 break;
5920 default:
5921 emacs_abort ();
5928 /* Icons. */
5930 bool
5931 x_bitmap_icon (struct frame *f, Lisp_Object icon)
5933 HANDLE main_icon;
5934 HANDLE small_icon = NULL;
5936 if (FRAME_W32_WINDOW (f) == 0)
5937 return 1;
5939 if (NILP (icon))
5940 main_icon = LoadIcon (hinst, EMACS_CLASS);
5941 else if (STRINGP (icon))
5943 /* Load the main icon from the named file. */
5944 main_icon = LoadImage (NULL, (LPCTSTR) SDATA (icon), IMAGE_ICON, 0, 0,
5945 LR_DEFAULTSIZE | LR_LOADFROMFILE);
5946 /* Try to load a small icon to go with it. */
5947 small_icon = LoadImage (NULL, (LPCSTR) SDATA (icon), IMAGE_ICON,
5948 GetSystemMetrics (SM_CXSMICON),
5949 GetSystemMetrics (SM_CYSMICON),
5950 LR_LOADFROMFILE);
5952 else if (SYMBOLP (icon))
5954 LPCTSTR name;
5956 if (EQ (icon, intern ("application")))
5957 name = (LPCTSTR) IDI_APPLICATION;
5958 else if (EQ (icon, intern ("hand")))
5959 name = (LPCTSTR) IDI_HAND;
5960 else if (EQ (icon, intern ("question")))
5961 name = (LPCTSTR) IDI_QUESTION;
5962 else if (EQ (icon, intern ("exclamation")))
5963 name = (LPCTSTR) IDI_EXCLAMATION;
5964 else if (EQ (icon, intern ("asterisk")))
5965 name = (LPCTSTR) IDI_ASTERISK;
5966 else if (EQ (icon, intern ("winlogo")))
5967 name = (LPCTSTR) IDI_WINLOGO;
5968 else
5969 return 1;
5971 main_icon = LoadIcon (NULL, name);
5973 else
5974 return 1;
5976 if (main_icon == NULL)
5977 return 1;
5979 PostMessage (FRAME_W32_WINDOW (f), WM_SETICON, (WPARAM) ICON_BIG,
5980 (LPARAM) main_icon);
5982 /* If there is a small icon that goes with it, set that too. */
5983 if (small_icon)
5984 PostMessage (FRAME_W32_WINDOW (f), WM_SETICON, (WPARAM) ICON_SMALL,
5985 (LPARAM) small_icon);
5987 return 0;
5991 /************************************************************************
5992 Handling X errors
5993 ************************************************************************/
5995 /* Display Error Handling functions not used on W32. Listing them here
5996 helps diff stay in step when comparing w32term.c with xterm.c.
5998 x_error_catcher (display, error)
5999 x_catch_errors (dpy)
6000 x_catch_errors_unwind (old_val)
6001 x_check_errors (dpy, format)
6002 x_fully_uncatch_errors ()
6003 x_had_errors_p (dpy)
6004 x_clear_errors (dpy)
6005 x_uncatch_errors (dpy, count)
6006 x_trace_wire ()
6007 x_connection_signal (signalnum)
6008 x_connection_closed (dpy, error_message)
6009 x_error_quitter (display, error)
6010 x_error_handler (display, error)
6011 x_io_error_quitter (display)
6016 /* Changing the font of the frame. */
6018 Lisp_Object
6019 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
6021 struct font *font = XFONT_OBJECT (font_object);
6022 int unit, font_ascent, font_descent;
6024 if (fontset < 0)
6025 fontset = fontset_from_font (font_object);
6026 FRAME_FONTSET (f) = fontset;
6027 if (FRAME_FONT (f) == font)
6028 /* This font is already set in frame F. There's nothing more to
6029 do. */
6030 return font_object;
6032 FRAME_FONT (f) = font;
6033 FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
6034 FRAME_COLUMN_WIDTH (f) = unit = font->average_width;
6035 get_font_ascent_descent (font, &font_ascent, &font_descent);
6036 FRAME_LINE_HEIGHT (f) = font_ascent + font_descent;
6038 /* Compute number of scrollbar columns. */
6039 unit = FRAME_COLUMN_WIDTH (f);
6040 if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
6041 FRAME_CONFIG_SCROLL_BAR_COLS (f)
6042 = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + unit - 1) / unit;
6043 else
6045 FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + unit - 1) / unit;
6046 FRAME_CONFIG_SCROLL_BAR_WIDTH (f) =
6047 FRAME_CONFIG_SCROLL_BAR_COLS (f) * unit;
6050 /* Now make the frame display the given font. */
6051 if (FRAME_X_WINDOW (f) != 0)
6053 /* Don't change the size of a tip frame; there's no point in
6054 doing it because it's done in Fx_show_tip, and it leads to
6055 problems because the tip frame has no widget. */
6056 if (!FRAME_TOOLTIP_P (f))
6057 adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
6058 FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3,
6059 false, Qfont);
6062 /* X version sets font of input methods here also. */
6064 return font_object;
6068 /***********************************************************************
6069 TODO: W32 Input Methods
6070 ***********************************************************************/
6071 /* Listing missing functions from xterm.c helps diff stay in step.
6073 xim_destroy_callback (xim, client_data, call_data)
6074 xim_open_dpy (dpyinfo, resource_name)
6075 struct xim_inst_t
6076 xim_instantiate_callback (display, client_data, call_data)
6077 xim_initialize (dpyinfo, resource_name)
6078 xim_close_dpy (dpyinfo)
6083 /* Calculate the absolute position in frame F
6084 from its current recorded position values and gravity. */
6086 static void
6087 x_calc_absolute_position (struct frame *f)
6089 int flags = f->size_hint_flags;
6091 /* The sum of the widths of the frame's left and right borders, and
6092 the sum of the heights of the frame's top and bottom borders (in
6093 pixels) drawn by Windows. */
6094 unsigned int left_right_borders_width, top_bottom_borders_height;
6096 /* Try to get the actual values of these two variables. We compute
6097 the border width (height) by subtracting the width (height) of
6098 the frame's client area from the width (height) of the frame's
6099 entire window. */
6100 WINDOWPLACEMENT wp = { 0 };
6101 RECT client_rect = { 0 };
6103 if (GetWindowPlacement (FRAME_W32_WINDOW (f), &wp)
6104 && GetClientRect (FRAME_W32_WINDOW (f), &client_rect))
6106 left_right_borders_width =
6107 (wp.rcNormalPosition.right - wp.rcNormalPosition.left) -
6108 (client_rect.right - client_rect.left);
6110 top_bottom_borders_height =
6111 (wp.rcNormalPosition.bottom - wp.rcNormalPosition.top) -
6112 (client_rect.bottom - client_rect.top);
6114 else
6116 /* Use sensible default values. */
6117 left_right_borders_width = 8;
6118 top_bottom_borders_height = 32;
6121 /* With multiple monitors, we can legitimately get negative
6122 coordinates (for monitors above or to the left of the primary
6123 monitor). Find the display origin to ensure negative positions
6124 are computed correctly (Bug#21173). */
6125 int display_left = 0;
6126 int display_top = 0;
6127 struct frame *p = FRAME_PARENT_FRAME (f);
6129 if (!p && flags & (XNegative | YNegative))
6131 Lisp_Object list;
6133 list = Fw32_display_monitor_attributes_list (Qnil);
6134 while (CONSP (list))
6136 Lisp_Object attributes = CAR(list);
6137 Lisp_Object geometry;
6138 Lisp_Object monitor_left, monitor_top;
6140 list = CDR(list);
6142 geometry = Fassoc (Qgeometry, attributes, Qnil);
6143 if (!NILP (geometry))
6145 monitor_left = Fnth (make_number (1), geometry);
6146 monitor_top = Fnth (make_number (2), geometry);
6148 display_left = min (display_left, XINT (monitor_left));
6149 display_top = min (display_top, XINT (monitor_top));
6154 /* Treat negative positions as relative to the rightmost bottommost
6155 position that fits on the screen or parent frame.
6157 I see no need for subtracting 1 from the border widths - is there
6158 any on the remaining platforms? Here these subtractions did put
6159 the last pixel line/column of a frame off-display when, for
6160 example, a (set-frame-parameter nil 'left '(- 0)) specification was
6161 used - martin 20017-05-05. */
6162 if (flags & XNegative)
6164 if (p)
6165 f->left_pos = (FRAME_PIXEL_WIDTH (p)
6166 - FRAME_PIXEL_WIDTH (f)
6167 + f->left_pos
6168 - left_right_borders_width);
6169 else
6170 f->left_pos = (x_display_pixel_width (FRAME_DISPLAY_INFO (f))
6171 + display_left
6172 - FRAME_PIXEL_WIDTH (f)
6173 + f->left_pos
6174 - left_right_borders_width);
6177 if (flags & YNegative)
6179 if (p)
6180 f->top_pos = (FRAME_PIXEL_HEIGHT (p)
6181 - FRAME_PIXEL_HEIGHT (f)
6182 + f->top_pos
6183 - top_bottom_borders_height);
6184 else
6185 f->top_pos = (x_display_pixel_height (FRAME_DISPLAY_INFO (f))
6186 + display_top
6187 - FRAME_PIXEL_HEIGHT (f)
6188 + f->top_pos
6189 - top_bottom_borders_height);
6192 /* The left_pos and top_pos are now relative to the top and left
6193 screen edges, so the flags should correspond. */
6194 f->size_hint_flags &= ~ (XNegative | YNegative);
6197 /* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
6198 to really change the position, and 0 when calling from
6199 x_make_frame_visible (in that case, XOFF and YOFF are the current
6200 position values). It is -1 when calling from x_set_frame_parameters,
6201 which means, do adjust for borders but don't change the gravity. */
6203 void
6204 x_set_offset (struct frame *f, register int xoff, register int yoff,
6205 int change_gravity)
6207 int modified_top, modified_left;
6209 if (change_gravity > 0)
6211 f->top_pos = yoff;
6212 f->left_pos = xoff;
6213 f->size_hint_flags &= ~ (XNegative | YNegative);
6214 if (xoff < 0)
6215 f->size_hint_flags |= XNegative;
6216 if (yoff < 0)
6217 f->size_hint_flags |= YNegative;
6218 f->win_gravity = NorthWestGravity;
6220 x_calc_absolute_position (f);
6222 block_input ();
6223 x_wm_set_size_hint (f, (long) 0, false);
6225 modified_left = f->left_pos;
6226 modified_top = f->top_pos;
6228 if (!FRAME_PARENT_FRAME (f))
6229 my_set_window_pos (FRAME_W32_WINDOW (f), NULL,
6230 modified_left, modified_top,
6231 0, 0,
6232 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
6233 else
6234 my_set_window_pos (FRAME_W32_WINDOW (f), HWND_TOP,
6235 modified_left, modified_top,
6236 0, 0,
6237 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
6238 unblock_input ();
6241 static void
6242 w32fullscreen_hook (struct frame *f)
6244 if (FRAME_VISIBLE_P (f))
6246 HWND hwnd = FRAME_W32_WINDOW(f);
6247 DWORD dwStyle = GetWindowLong (hwnd, GWL_STYLE);
6248 RECT rect;
6249 enum fullscreen_type prev_fsmode = FRAME_PREV_FSMODE (f);
6251 block_input();
6252 f->want_fullscreen &= ~FULLSCREEN_WAIT;
6254 if (FRAME_PREV_FSMODE (f) == FULLSCREEN_NONE)
6255 GetWindowPlacement (hwnd, &FRAME_NORMAL_PLACEMENT (f));
6257 if (FRAME_PREV_FSMODE (f) == FULLSCREEN_BOTH)
6259 if (!FRAME_UNDECORATED (f))
6260 SetWindowLong (hwnd, GWL_STYLE, dwStyle | WS_OVERLAPPEDWINDOW);
6261 SetWindowPlacement (hwnd, &FRAME_NORMAL_PLACEMENT (f));
6263 else if (FRAME_PREV_FSMODE (f) == FULLSCREEN_HEIGHT
6264 || FRAME_PREV_FSMODE (f) == FULLSCREEN_WIDTH)
6265 SetWindowPlacement (hwnd, &FRAME_NORMAL_PLACEMENT (f));
6267 FRAME_PREV_FSMODE (f) = f->want_fullscreen;
6269 if (f->want_fullscreen == FULLSCREEN_NONE)
6270 ShowWindow (hwnd, SW_SHOWNORMAL);
6271 else if (f->want_fullscreen == FULLSCREEN_MAXIMIZED)
6273 if (prev_fsmode == FULLSCREEN_BOTH || prev_fsmode == FULLSCREEN_WIDTH
6274 || prev_fsmode == FULLSCREEN_HEIGHT)
6275 /* Make window normal since otherwise the subsequent
6276 maximization might fail in some cases. */
6277 ShowWindow (hwnd, SW_SHOWNORMAL);
6278 ShowWindow (hwnd, SW_MAXIMIZE);
6280 else if (f->want_fullscreen == FULLSCREEN_BOTH)
6282 int menu_bar_height = GetSystemMetrics (SM_CYMENU);
6284 w32_fullscreen_rect (hwnd, f->want_fullscreen,
6285 FRAME_NORMAL_PLACEMENT (f).rcNormalPosition, &rect);
6286 if (!FRAME_UNDECORATED (f))
6287 SetWindowLong (hwnd, GWL_STYLE, dwStyle & ~WS_OVERLAPPEDWINDOW);
6288 SetWindowPos (hwnd, HWND_TOP, rect.left, rect.top,
6289 rect.right - rect.left, rect.bottom - rect.top,
6290 SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
6291 change_frame_size
6292 (f, FRAME_PIXEL_TO_TEXT_WIDTH (f, rect.right - rect.left),
6293 FRAME_PIXEL_TO_TEXT_HEIGHT (f, (rect.bottom - rect.top
6294 - menu_bar_height)),
6295 0, 1, 0, 1);
6297 else
6299 ShowWindow (hwnd, SW_SHOWNORMAL);
6300 w32_fullscreen_rect (hwnd, f->want_fullscreen,
6301 FRAME_NORMAL_PLACEMENT (f).rcNormalPosition, &rect);
6302 SetWindowPos (hwnd, HWND_TOP, rect.left, rect.top,
6303 rect.right - rect.left, rect.bottom - rect.top, 0);
6305 if (f->want_fullscreen == FULLSCREEN_WIDTH)
6307 int border_width = GetSystemMetrics (SM_CXFRAME);
6309 change_frame_size
6310 (f, (FRAME_PIXEL_TO_TEXT_WIDTH
6311 (f, rect.right - rect.left - 2 * border_width)),
6312 0, 0, 1, 0, 1);
6314 else
6316 int border_height = GetSystemMetrics (SM_CYFRAME);
6317 /* Won't work for wrapped menu bar. */
6318 int menu_bar_height = GetSystemMetrics (SM_CYMENU);
6319 int title_height = GetSystemMetrics (SM_CYCAPTION);
6321 change_frame_size
6322 (f, 0, (FRAME_PIXEL_TO_TEXT_HEIGHT
6323 (f, rect.bottom - rect.top - 2 * border_height
6324 - title_height - menu_bar_height)),
6325 0, 1, 0, 1);
6329 f->want_fullscreen = FULLSCREEN_NONE;
6330 unblock_input ();
6332 if (f->want_fullscreen == FULLSCREEN_BOTH
6333 || f->want_fullscreen == FULLSCREEN_WIDTH
6334 || f->want_fullscreen == FULLSCREEN_HEIGHT)
6335 do_pending_window_change (0);
6338 else
6339 f->want_fullscreen |= FULLSCREEN_WAIT;
6342 /* Call this to change the size of frame F's x-window.
6343 If CHANGE_GRAVITY, change to top-left-corner window gravity
6344 for this size change and subsequent size changes.
6345 Otherwise we leave the window gravity unchanged. */
6347 void
6348 x_set_window_size (struct frame *f, bool change_gravity,
6349 int width, int height, bool pixelwise)
6351 int pixelwidth, pixelheight;
6352 Lisp_Object fullscreen = get_frame_param (f, Qfullscreen);
6353 RECT rect;
6354 MENUBARINFO info;
6355 int menu_bar_height;
6357 block_input ();
6359 /* Get the height of the menu bar here. It's used below to detect
6360 whether the menu bar is wrapped. It's also used to specify the
6361 third argument for AdjustWindowRect. See bug#22105. */
6362 info.cbSize = sizeof (info);
6363 info.rcBar.top = info.rcBar.bottom = 0;
6364 GetMenuBarInfo (FRAME_W32_WINDOW (f), 0xFFFFFFFD, 0, &info);
6365 menu_bar_height = info.rcBar.bottom - info.rcBar.top;
6367 if (pixelwise)
6369 pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
6370 pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
6372 else
6374 pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, width);
6375 pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height);
6378 if (w32_add_wrapped_menu_bar_lines)
6380 /* When the menu bar wraps sending a SetWindowPos shrinks the
6381 height of the frame then the wrapped menu bar lines are not
6382 accounted for (Bug#15174 and Bug#18720). Here we add these
6383 extra lines to the frame height. */
6384 int default_menu_bar_height;
6386 /* Why is (apparently) SM_CYMENUSIZE needed here instead of
6387 SM_CYMENU ?? */
6388 default_menu_bar_height = GetSystemMetrics (SM_CYMENUSIZE);
6390 if ((default_menu_bar_height > 0)
6391 && (menu_bar_height > default_menu_bar_height)
6392 && ((menu_bar_height % default_menu_bar_height) == 0))
6393 pixelheight = pixelheight + menu_bar_height - default_menu_bar_height;
6396 f->win_gravity = NorthWestGravity;
6397 x_wm_set_size_hint (f, (long) 0, false);
6399 rect.left = rect.top = 0;
6400 rect.right = pixelwidth;
6401 rect.bottom = pixelheight;
6403 AdjustWindowRect (&rect, f->output_data.w32->dwStyle, menu_bar_height > 0);
6405 if (!(f->after_make_frame)
6406 && !(f->want_fullscreen & FULLSCREEN_WAIT)
6407 && FRAME_VISIBLE_P (f))
6409 RECT window_rect;
6411 GetWindowRect (FRAME_W32_WINDOW (f), &window_rect);
6413 if (EQ (fullscreen, Qmaximized)
6414 || EQ (fullscreen, Qfullboth)
6415 || EQ (fullscreen, Qfullwidth))
6417 rect.left = window_rect.left;
6418 rect.right = window_rect.right;
6419 pixelwidth = 0;
6421 if (EQ (fullscreen, Qmaximized)
6422 || EQ (fullscreen, Qfullboth)
6423 || EQ (fullscreen, Qfullheight))
6425 rect.top = window_rect.top;
6426 rect.bottom = window_rect.bottom;
6427 pixelheight = 0;
6431 if (pixelwidth > 0 || pixelheight > 0)
6433 frame_size_history_add
6434 (f, Qx_set_window_size_1, width, height,
6435 list2 (Fcons (make_number (pixelwidth),
6436 make_number (pixelheight)),
6437 Fcons (make_number (rect.right - rect.left),
6438 make_number (rect.bottom - rect.top))));
6440 if (!FRAME_PARENT_FRAME (f))
6441 my_set_window_pos (FRAME_W32_WINDOW (f), NULL,
6442 0, 0,
6443 rect.right - rect.left,
6444 rect.bottom - rect.top,
6445 SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
6446 else
6447 my_set_window_pos (FRAME_W32_WINDOW (f), HWND_TOP,
6448 0, 0,
6449 rect.right - rect.left,
6450 rect.bottom - rect.top,
6451 SWP_NOMOVE | SWP_NOACTIVATE);
6453 change_frame_size (f,
6454 ((pixelwidth == 0)
6455 ? 0 : FRAME_PIXEL_TO_TEXT_WIDTH (f, pixelwidth)),
6456 ((pixelheight == 0)
6457 ? 0 : FRAME_PIXEL_TO_TEXT_HEIGHT (f, pixelheight)),
6458 0, 1, 0, 1);
6459 SET_FRAME_GARBAGED (f);
6461 /* If cursor was outside the new size, mark it as off. */
6462 mark_window_cursors_off (XWINDOW (f->root_window));
6464 /* Clear out any recollection of where the mouse highlighting was,
6465 since it might be in a place that's outside the new frame size.
6466 Actually checking whether it is outside is a pain in the neck,
6467 so don't try--just let the highlighting be done afresh with new
6468 size. */
6469 cancel_mouse_face (f);
6472 unblock_input ();
6474 do_pending_window_change (false);
6477 /* Mouse warping. */
6479 void
6480 frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
6482 UINT trail_num = 0;
6483 BOOL ret = false;
6484 RECT rect;
6485 POINT pt;
6487 block_input ();
6489 GetClientRect (FRAME_W32_WINDOW (f), &rect);
6490 pt.x = rect.left + pix_x;
6491 pt.y = rect.top + pix_y;
6492 ClientToScreen (FRAME_W32_WINDOW (f), &pt);
6494 /* When "mouse trails" are in effect, moving the mouse cursor
6495 sometimes leaves behind an annoying "ghost" of the pointer.
6496 Avoid that by momentarily switching off mouse trails. */
6497 if (os_subtype == OS_NT
6498 && w32_major_version + w32_minor_version >= 6)
6499 ret = SystemParametersInfo (SPI_GETMOUSETRAILS, 0, &trail_num, 0);
6500 SetCursorPos (pt.x, pt.y);
6501 if (ret)
6502 SystemParametersInfo (SPI_SETMOUSETRAILS, trail_num, NULL, 0);
6504 unblock_input ();
6508 /* Focus shifting, raising and lowering. */
6510 /* The NOACTIVATE argument has no effect on Windows. According to the
6511 Windows API: An application cannot activate an inactive window
6512 without also bringing it to the top of the Z order. */
6514 void
6515 x_focus_frame (struct frame *f, bool noactivate)
6517 #if 0
6518 struct w32_display_info *dpyinfo = &one_w32_display_info;
6519 #endif
6521 /* Give input focus to frame. */
6522 block_input ();
6523 #if 0
6524 /* Try not to change its Z-order if possible. */
6525 if (x_window_to_frame (dpyinfo, GetForegroundWindow ()))
6526 my_set_focus (f, FRAME_W32_WINDOW (f));
6527 else
6528 #endif
6529 my_set_foreground_window (FRAME_W32_WINDOW (f));
6530 unblock_input ();
6533 /* Raise frame F. */
6534 void
6535 x_raise_frame (struct frame *f)
6537 block_input ();
6539 /* Strictly speaking, raise-frame should only change the frame's Z
6540 order, leaving input focus unchanged. This is reasonable behavior
6541 on X where the usual policy is point-to-focus. However, this
6542 behavior would be very odd on Windows where the usual policy is
6543 click-to-focus.
6545 On X, if the mouse happens to be over the raised frame, it gets
6546 input focus anyway (so the window with focus will never be
6547 completely obscured) - if not, then just moving the mouse over it
6548 is sufficient to give it focus. On Windows, the user must actually
6549 click on the frame (preferably the title bar so as not to move
6550 point), which is more awkward. Also, no other Windows program
6551 raises a window to the top but leaves another window (possibly now
6552 completely obscured) with input focus.
6554 Because there is a system setting on Windows that allows the user
6555 to choose the point to focus policy, we make the strict semantics
6556 optional, but by default we grab focus when raising. */
6558 if (NILP (Vw32_grab_focus_on_raise))
6560 /* The obvious call to my_set_window_pos doesn't work if Emacs is
6561 not already the foreground application: the frame is raised
6562 above all other frames belonging to us, but not above the
6563 current top window. To achieve that, we have to resort to this
6564 more cumbersome method. */
6566 HDWP handle = BeginDeferWindowPos (2);
6567 if (handle)
6569 handle = DeferWindowPos (handle,
6570 FRAME_W32_WINDOW (f),
6571 HWND_TOP,
6572 0, 0, 0, 0,
6573 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
6574 if (handle)
6576 handle = DeferWindowPos (handle,
6577 GetForegroundWindow (),
6578 FRAME_W32_WINDOW (f),
6579 0, 0, 0, 0,
6580 SWP_NOSIZE | SWP_NOMOVE |
6581 SWP_NOACTIVATE);
6582 if (handle)
6583 EndDeferWindowPos (handle);
6587 else
6589 my_bring_window_to_top (FRAME_W32_WINDOW (f));
6592 unblock_input ();
6595 /* Lower frame F. */
6596 void
6597 x_lower_frame (struct frame *f)
6599 block_input ();
6600 my_set_window_pos (FRAME_W32_WINDOW (f),
6601 HWND_BOTTOM,
6602 0, 0, 0, 0,
6603 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
6604 unblock_input ();
6607 static void
6608 w32_frame_raise_lower (struct frame *f, bool raise_flag)
6610 if (! FRAME_W32_P (f))
6611 return;
6613 if (raise_flag)
6614 x_raise_frame (f);
6615 else
6616 x_lower_frame (f);
6619 /* Change of visibility. */
6621 /* This tries to wait until the frame is really visible, depending on
6622 the value of Vx_visible_frame_timeout.
6623 However, if the window manager asks the user where to position
6624 the frame, this will return before the user finishes doing that.
6625 The frame will not actually be visible at that time,
6626 but it will become visible later when the window manager
6627 finishes with it. */
6629 void
6630 x_make_frame_visible (struct frame *f)
6632 block_input ();
6634 x_set_bitmap_icon (f);
6636 if (! FRAME_VISIBLE_P (f))
6638 /* We test FRAME_GARBAGED_P here to make sure we don't
6639 call x_set_offset a second time
6640 if we get to x_make_frame_visible a second time
6641 before the window gets really visible. */
6642 if (! FRAME_ICONIFIED_P (f)
6643 && ! f->output_data.w32->asked_for_visible)
6645 if (!FRAME_PARENT_FRAME (f))
6647 RECT workarea_rect;
6648 RECT window_rect;
6650 /* Adjust vertical window position in order to avoid being
6651 covered by a taskbar placed at the bottom of the desktop. */
6652 SystemParametersInfo (SPI_GETWORKAREA, 0, &workarea_rect, 0);
6653 GetWindowRect (FRAME_W32_WINDOW (f), &window_rect);
6654 if (window_rect.bottom > workarea_rect.bottom
6655 && window_rect.top > workarea_rect.top)
6656 f->top_pos = max (window_rect.top
6657 - window_rect.bottom + workarea_rect.bottom,
6658 workarea_rect.top);
6661 x_set_offset (f, f->left_pos, f->top_pos, 0);
6664 f->output_data.w32->asked_for_visible = 1;
6666 /* According to a report in emacs-devel 2008-06-03, SW_SHOWNORMAL
6667 causes unexpected behavior when unminimizing frames that were
6668 previously maximized. But only SW_SHOWNORMAL works properly for
6669 frames that were truely hidden (using make-frame-invisible), so
6670 we need it to avoid Bug#5482. It seems that iconified is only
6671 set for minimized windows that are still visible, so use that to
6672 determine the appropriate flag to pass ShowWindow. */
6673 my_show_window (f, FRAME_W32_WINDOW (f),
6674 FRAME_ICONIFIED_P (f)
6675 ? SW_RESTORE
6676 : FRAME_NO_FOCUS_ON_MAP (f)
6677 ? SW_SHOWNOACTIVATE
6678 : SW_SHOWNORMAL);
6681 if (!FLOATP (Vx_wait_for_event_timeout))
6682 return;
6684 /* Synchronize to ensure Emacs knows the frame is visible
6685 before we do anything else. We do this loop with input not blocked
6686 so that incoming events are handled. */
6688 Lisp_Object frame;
6689 double timeout = XFLOAT_DATA (Vx_wait_for_event_timeout);
6690 double start_time = XFLOAT_DATA (Ffloat_time (Qnil));
6692 /* This must come after we set COUNT. */
6693 unblock_input ();
6695 XSETFRAME (frame, f);
6697 /* Wait until the frame is visible. Process X events until a
6698 MapNotify event has been seen, or until we think we won't get a
6699 MapNotify at all.. */
6700 while (timeout > (XFLOAT_DATA (Ffloat_time (Qnil)) - start_time) &&
6701 !FRAME_VISIBLE_P (f))
6703 /* Force processing of queued events. */
6704 /* TODO: x_sync equivalent? */
6706 /* Machines that do polling rather than SIGIO have been observed
6707 to go into a busy-wait here. So we'll fake an alarm signal
6708 to let the handler know that there's something to be read.
6709 We used to raise a real alarm, but it seems that the handler
6710 isn't always enabled here. This is probably a bug. */
6711 if (input_polling_used ())
6713 /* It could be confusing if a real alarm arrives while processing
6714 the fake one. Turn it off and let the handler reset it. */
6715 int old_poll_suppress_count = poll_suppress_count;
6716 poll_suppress_count = 1;
6717 poll_for_input_1 ();
6718 poll_suppress_count = old_poll_suppress_count;
6724 /* Change from mapped state to withdrawn state. */
6726 /* Make the frame visible (mapped and not iconified). */
6728 void
6729 x_make_frame_invisible (struct frame *f)
6731 /* Don't keep the highlight on an invisible frame. */
6732 if (FRAME_DISPLAY_INFO (f)->x_highlight_frame == f)
6733 FRAME_DISPLAY_INFO (f)->x_highlight_frame = 0;
6735 block_input ();
6737 my_show_window (f, FRAME_W32_WINDOW (f), SW_HIDE);
6739 /* We can't distinguish this from iconification
6740 just by the event that we get from the server.
6741 So we can't win using the usual strategy of letting
6742 FRAME_SAMPLE_VISIBILITY set this. So do it by hand,
6743 and synchronize with the server to make sure we agree. */
6744 SET_FRAME_VISIBLE (f, 0);
6745 SET_FRAME_ICONIFIED (f, false);
6747 unblock_input ();
6750 /* Change window state from mapped to iconified. */
6752 void
6753 x_iconify_frame (struct frame *f)
6755 /* Don't keep the highlight on an invisible frame. */
6756 if (FRAME_DISPLAY_INFO (f)->x_highlight_frame == f)
6757 FRAME_DISPLAY_INFO (f)->x_highlight_frame = 0;
6759 if (FRAME_ICONIFIED_P (f))
6760 return;
6762 block_input ();
6764 x_set_bitmap_icon (f);
6766 /* Simulate the user minimizing the frame. */
6767 SendMessageTimeout (FRAME_W32_WINDOW (f), WM_SYSCOMMAND, SC_MINIMIZE, 0,
6768 0, 6000, NULL);
6770 SET_FRAME_VISIBLE (f, 0);
6771 SET_FRAME_ICONIFIED (f, true);
6773 unblock_input ();
6777 /* Free X resources of frame F. */
6779 void
6780 x_free_frame_resources (struct frame *f)
6782 struct w32_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
6783 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
6785 block_input ();
6787 /* We must free faces before destroying windows because some
6788 font-driver (e.g. xft) access a window while finishing a
6789 face. */
6790 free_frame_faces (f);
6792 if (FRAME_W32_WINDOW (f))
6793 my_destroy_window (f, FRAME_W32_WINDOW (f));
6795 free_frame_menubar (f);
6797 xfree (f->output_data.w32);
6798 f->output_data.w32 = NULL;
6800 if (f == dpyinfo->w32_focus_frame)
6801 dpyinfo->w32_focus_frame = 0;
6802 if (f == dpyinfo->w32_focus_event_frame)
6803 dpyinfo->w32_focus_event_frame = 0;
6804 if (f == dpyinfo->x_highlight_frame)
6805 dpyinfo->x_highlight_frame = 0;
6806 if (f == hlinfo->mouse_face_mouse_frame)
6807 reset_mouse_highlight (hlinfo);
6809 unblock_input ();
6813 /* Destroy the window of frame F. */
6814 static void
6815 x_destroy_window (struct frame *f)
6817 struct w32_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
6819 x_free_frame_resources (f);
6820 dpyinfo->reference_count--;
6824 /* Setting window manager hints. */
6826 /* Set the normal size hints for the window manager, for frame F.
6827 FLAGS is the flags word to use--or 0 meaning preserve the flags
6828 that the window now has.
6829 If USER_POSITION, set the USPosition
6830 flag (this is useful when FLAGS is 0). */
6831 void
6832 x_wm_set_size_hint (struct frame *f, long flags, bool user_position)
6834 Window window = FRAME_W32_WINDOW (f);
6836 enter_crit ();
6838 SetWindowLong (window, WND_FONTWIDTH_INDEX, FRAME_COLUMN_WIDTH (f));
6839 SetWindowLong (window, WND_LINEHEIGHT_INDEX, FRAME_LINE_HEIGHT (f));
6840 SetWindowLong (window, WND_BORDER_INDEX, FRAME_INTERNAL_BORDER_WIDTH (f));
6841 SetWindowLong (window, WND_VSCROLLBAR_INDEX, FRAME_SCROLL_BAR_AREA_WIDTH (f));
6842 SetWindowLong (window, WND_HSCROLLBAR_INDEX, FRAME_SCROLL_BAR_AREA_HEIGHT (f));
6844 leave_crit ();
6847 /***********************************************************************
6848 Fonts
6849 ***********************************************************************/
6851 #ifdef GLYPH_DEBUG
6853 /* Check that FONT is valid on frame F. It is if it can be found in F's
6854 font table. */
6856 static void
6857 x_check_font (struct frame *f, struct font *font)
6859 eassert (font != NULL && ! NILP (font->props[FONT_TYPE_INDEX]));
6860 if (font->driver->check)
6861 eassert (font->driver->check (f, font) == 0);
6864 #endif /* GLYPH_DEBUG */
6866 /* Show hourglass cursor on frame F. */
6868 static void
6869 w32_show_hourglass (struct frame *f)
6871 if (!menubar_in_use && !current_popup_menu)
6873 struct w32_output *w32 = FRAME_X_OUTPUT (f);
6875 w32->hourglass_p = 1;
6876 SetCursor (w32->hourglass_cursor);
6880 /* Hide hourglass cursor on frame F. */
6882 static void
6883 w32_hide_hourglass (struct frame *f)
6885 struct w32_output *w32 = FRAME_X_OUTPUT (f);
6887 w32->hourglass_p = 0;
6888 if (f->pointer_invisible)
6889 SetCursor (NULL);
6890 else
6891 SetCursor (w32->current_cursor);
6894 /* FIXME: old code did that, but I don't know why. Anyway,
6895 this is used for non-GUI frames (see cancel_hourglass). */
6897 void
6898 w32_arrow_cursor (void)
6900 SetCursor (w32_load_cursor (IDC_ARROW));
6903 static void
6904 w32_toggle_invisible_pointer (struct frame *f, bool invisible)
6906 block_input ();
6908 if (f->pointer_invisible != invisible)
6910 f->pointer_invisible = invisible;
6911 w32_define_cursor (FRAME_W32_WINDOW (f),
6912 f->output_data.w32->current_cursor);
6915 unblock_input ();
6918 /***********************************************************************
6919 Initialization
6920 ***********************************************************************/
6922 static int w32_initialized = 0;
6924 void
6925 w32_initialize_display_info (Lisp_Object display_name)
6927 struct w32_display_info *dpyinfo = &one_w32_display_info;
6929 memset (dpyinfo, 0, sizeof (*dpyinfo));
6931 dpyinfo->name_list_element = Fcons (display_name, Qnil);
6932 if (STRINGP (Vsystem_name))
6934 dpyinfo->w32_id_name = xmalloc (SCHARS (Vinvocation_name)
6935 + SCHARS (Vsystem_name) + 2);
6936 sprintf (dpyinfo->w32_id_name, "%s@%s",
6937 SDATA (Vinvocation_name), SDATA (Vsystem_name));
6939 else
6940 dpyinfo->w32_id_name = xlispstrdup (Vinvocation_name);
6942 /* Default Console mode values - overridden when running in GUI mode
6943 with values obtained from system metrics. */
6944 dpyinfo->resx = 1;
6945 dpyinfo->resy = 1;
6946 dpyinfo->n_planes = 1;
6947 dpyinfo->n_cbits = 4;
6948 dpyinfo->n_fonts = 0;
6949 dpyinfo->smallest_font_height = 1;
6950 dpyinfo->smallest_char_width = 1;
6951 dpyinfo->vertical_scroll_bar_cursor = w32_load_cursor (IDC_ARROW);
6952 dpyinfo->horizontal_scroll_bar_cursor = w32_load_cursor (IDC_ARROW);
6953 /* TODO: dpyinfo->gray */
6955 reset_mouse_highlight (&dpyinfo->mouse_highlight);
6958 /* Create an xrdb-style database of resources to supersede registry settings.
6959 The database is just a concatenation of C strings, finished by an additional
6960 \0. The strings are submitted to some basic normalization, so
6962 [ *]option[ *]:[ *]value...
6964 becomes
6966 option:value...
6968 but any whitespace following value is not removed. */
6970 static char *
6971 w32_make_rdb (char *xrm_option)
6973 char *buffer = xmalloc (strlen (xrm_option) + 2);
6974 char *current = buffer;
6975 char ch;
6976 int in_option = 1;
6977 int before_value = 0;
6979 do {
6980 ch = *xrm_option++;
6982 if (ch == '\n')
6984 *current++ = '\0';
6985 in_option = 1;
6986 before_value = 0;
6988 else if (ch != ' ')
6990 *current++ = ch;
6991 if (in_option && (ch == ':'))
6993 in_option = 0;
6994 before_value = 1;
6996 else if (before_value)
6998 before_value = 0;
7001 else if (!(in_option || before_value))
7003 *current++ = ch;
7005 } while (ch);
7007 *current = '\0';
7009 return buffer;
7012 extern frame_parm_handler w32_frame_parm_handlers[];
7014 static struct redisplay_interface w32_redisplay_interface =
7016 w32_frame_parm_handlers,
7017 x_produce_glyphs,
7018 x_write_glyphs,
7019 x_insert_glyphs,
7020 x_clear_end_of_line,
7021 x_scroll_run,
7022 x_after_update_window_line,
7023 x_update_window_begin,
7024 x_update_window_end,
7025 0, /* flush_display */
7026 x_clear_window_mouse_face,
7027 x_get_glyph_overhangs,
7028 x_fix_overlapping_area,
7029 w32_draw_fringe_bitmap,
7030 w32_define_fringe_bitmap,
7031 w32_destroy_fringe_bitmap,
7032 w32_compute_glyph_string_overhangs,
7033 x_draw_glyph_string,
7034 w32_define_frame_cursor,
7035 w32_clear_frame_area,
7036 w32_draw_window_cursor,
7037 w32_draw_vertical_window_border,
7038 w32_draw_window_divider,
7039 w32_shift_glyphs_for_insert,
7040 w32_show_hourglass,
7041 w32_hide_hourglass
7044 static void x_delete_terminal (struct terminal *term);
7046 static struct terminal *
7047 w32_create_terminal (struct w32_display_info *dpyinfo)
7049 struct terminal *terminal;
7051 terminal = create_terminal (output_w32, &w32_redisplay_interface);
7053 terminal->display_info.w32 = dpyinfo;
7054 dpyinfo->terminal = terminal;
7056 /* MSVC does not type K&R functions with no arguments correctly, and
7057 so we must explicitly cast them. */
7058 terminal->clear_frame_hook = x_clear_frame;
7059 terminal->ins_del_lines_hook = x_ins_del_lines;
7060 terminal->delete_glyphs_hook = x_delete_glyphs;
7061 terminal->ring_bell_hook = w32_ring_bell;
7062 terminal->toggle_invisible_pointer_hook = w32_toggle_invisible_pointer;
7063 terminal->update_begin_hook = x_update_begin;
7064 terminal->update_end_hook = x_update_end;
7065 terminal->read_socket_hook = w32_read_socket;
7066 terminal->frame_up_to_date_hook = w32_frame_up_to_date;
7067 terminal->mouse_position_hook = w32_mouse_position;
7068 terminal->frame_rehighlight_hook = w32_frame_rehighlight;
7069 terminal->frame_raise_lower_hook = w32_frame_raise_lower;
7070 terminal->fullscreen_hook = w32fullscreen_hook;
7071 terminal->menu_show_hook = w32_menu_show;
7072 terminal->popup_dialog_hook = w32_popup_dialog;
7073 terminal->set_vertical_scroll_bar_hook = w32_set_vertical_scroll_bar;
7074 terminal->set_horizontal_scroll_bar_hook = w32_set_horizontal_scroll_bar;
7075 terminal->condemn_scroll_bars_hook = w32_condemn_scroll_bars;
7076 terminal->redeem_scroll_bar_hook = w32_redeem_scroll_bar;
7077 terminal->judge_scroll_bars_hook = w32_judge_scroll_bars;
7078 terminal->delete_frame_hook = x_destroy_window;
7079 terminal->delete_terminal_hook = x_delete_terminal;
7080 /* Other hooks are NULL by default. */
7082 /* We don't yet support separate terminals on W32, so don't try to share
7083 keyboards between virtual terminals that are on the same physical
7084 terminal like X does. */
7085 terminal->kboard = allocate_kboard (Qw32);
7086 /* Don't let the initial kboard remain current longer than necessary.
7087 That would cause problems if a file loaded on startup tries to
7088 prompt in the mini-buffer. */
7089 if (current_kboard == initial_kboard)
7090 current_kboard = terminal->kboard;
7091 terminal->kboard->reference_count++;
7093 return terminal;
7096 static void
7097 x_delete_terminal (struct terminal *terminal)
7099 struct w32_display_info *dpyinfo = terminal->display_info.w32;
7101 /* Protect against recursive calls. delete_frame in
7102 delete_terminal calls us back when it deletes our last frame. */
7103 if (!terminal->name)
7104 return;
7106 block_input ();
7108 x_delete_display (dpyinfo);
7109 unblock_input ();
7112 struct w32_display_info *
7113 w32_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
7115 struct w32_display_info *dpyinfo;
7116 struct terminal *terminal;
7117 HDC hdc;
7119 block_input ();
7121 if (!w32_initialized)
7123 w32_initialize ();
7124 w32_initialized = 1;
7127 w32_initialize_display_info (display_name);
7129 dpyinfo = &one_w32_display_info;
7130 terminal = w32_create_terminal (dpyinfo);
7132 /* Set the name of the terminal. */
7133 terminal->name = xlispstrdup (display_name);
7135 dpyinfo->xrdb = xrm_option ? w32_make_rdb (xrm_option) : NULL;
7137 /* Put this display on the chain. */
7138 dpyinfo->next = x_display_list;
7139 x_display_list = dpyinfo;
7141 hdc = GetDC (NULL);
7143 dpyinfo->root_window = GetDesktopWindow ();
7144 dpyinfo->n_planes = GetDeviceCaps (hdc, PLANES);
7145 dpyinfo->n_cbits = GetDeviceCaps (hdc, BITSPIXEL);
7146 dpyinfo->resx = GetDeviceCaps (hdc, LOGPIXELSX);
7147 dpyinfo->resy = GetDeviceCaps (hdc, LOGPIXELSY);
7148 dpyinfo->has_palette = GetDeviceCaps (hdc, RASTERCAPS) & RC_PALETTE;
7149 ReleaseDC (NULL, hdc);
7151 /* initialize palette with white and black */
7153 XColor color;
7154 w32_defined_color (0, "white", &color, 1);
7155 w32_defined_color (0, "black", &color, 1);
7158 #ifdef WINDOWSNT
7159 /* Add the default keyboard. When !WINDOWSNT, we're using the
7160 standard Emacs console handling machinery and don't need an
7161 explicit FD here. */
7162 add_keyboard_wait_descriptor (0);
7163 #elif CYGWIN
7164 /* /dev/windows wakes us up when we have a thread message pending. */
7165 add_keyboard_wait_descriptor (w32_message_fd);
7166 #endif
7168 /* Create Fringe Bitmaps and store them for later use.
7170 On W32, bitmaps are all unsigned short, as Windows requires
7171 bitmap data to be Word aligned. For some reason they are
7172 horizontally reflected compared to how they appear on X, so we
7173 need to bitswap and convert to unsigned shorts before creating
7174 the bitmaps. */
7175 w32_init_fringe (terminal->rif);
7177 unblock_input ();
7179 return dpyinfo;
7182 /* Get rid of display DPYINFO, assuming all frames are already gone. */
7183 void
7184 x_delete_display (struct w32_display_info *dpyinfo)
7186 /* FIXME: the only display info apparently can't be deleted. */
7187 /* free palette table */
7189 struct w32_palette_entry * plist;
7191 plist = dpyinfo->color_list;
7192 while (plist)
7194 struct w32_palette_entry * pentry = plist;
7195 plist = plist->next;
7196 xfree (pentry);
7198 dpyinfo->color_list = NULL;
7199 if (dpyinfo->palette)
7200 DeleteObject (dpyinfo->palette);
7202 w32_reset_fringes ();
7206 /* Set up use of W32. */
7208 void
7209 w32_init_main_thread (void)
7211 dwMainThreadId = GetCurrentThreadId ();
7212 DuplicateHandle (GetCurrentProcess (), GetCurrentThread (),
7213 GetCurrentProcess (), &hMainThread, 0, TRUE,
7214 DUPLICATE_SAME_ACCESS);
7219 DWORD WINAPI w32_msg_worker (void * arg);
7221 static void
7222 w32_initialize (void)
7224 HANDLE shell;
7225 HRESULT (WINAPI * set_user_model) (const wchar_t * id);
7227 baud_rate = 19200;
7229 w32_system_caret_hwnd = NULL;
7230 w32_system_caret_height = 0;
7231 w32_system_caret_x = 0;
7232 w32_system_caret_y = 0;
7234 /* On Windows 7 and later, we need to set the user model ID
7235 to associate emacsclient launched files with Emacs frames
7236 in the UI. */
7237 shell = GetModuleHandle ("shell32.dll");
7238 if (shell)
7240 set_user_model
7241 = (void *) GetProcAddress (shell,
7242 "SetCurrentProcessExplicitAppUserModelID");
7244 /* If the function is defined, then we are running on Windows 7
7245 or newer, and the UI uses this to group related windows
7246 together. Since emacs, runemacs, emacsclient are related, we
7247 want them grouped even though the executables are different,
7248 so we need to set a consistent ID between them. */
7249 if (set_user_model)
7250 set_user_model (L"GNU.Emacs");
7253 #ifdef CYGWIN
7254 if ((w32_message_fd = emacs_open ("/dev/windows", O_RDWR, 0)) == -1)
7255 fatal ("opening /dev/windows: %s", strerror (errno));
7256 #endif /* CYGWIN */
7258 /* Initialize w32_use_visible_system_caret based on whether a screen
7259 reader is in use. */
7260 if (!SystemParametersInfo (SPI_GETSCREENREADER, 0,
7261 &w32_use_visible_system_caret, 0))
7262 w32_use_visible_system_caret = 0;
7264 any_help_event_p = 0;
7266 /* Initialize input mode: interrupt_input off, no flow control, allow
7267 8 bit character input, standard quit char. */
7268 Fset_input_mode (Qnil, Qnil, make_number (2), Qnil);
7271 LCID input_locale_id = LOWORD (GetKeyboardLayout (0));
7272 w32_keyboard_codepage = codepage_for_locale (input_locale_id);
7275 /* Create the window thread - it will terminate itself when the app
7276 terminates */
7277 init_crit ();
7279 /* Wait for thread to start */
7281 MSG msg;
7283 PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
7285 hWindowsThread = CreateThread (NULL, 0,
7286 w32_msg_worker,
7287 0, 0, &dwWindowsThreadId);
7289 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
7292 /* It is desirable that mainThread should have the same notion of
7293 focus window and active window as windowsThread. Unfortunately, the
7294 following call to AttachThreadInput, which should do precisely what
7295 we need, causes major problems when Emacs is linked as a console
7296 program. Unfortunately, we have good reasons for doing that, so
7297 instead we need to send messages to windowsThread to make some API
7298 calls for us (ones that affect, or depend on, the active/focus
7299 window state.) */
7300 #ifdef ATTACH_THREADS
7301 AttachThreadInput (dwMainThreadId, dwWindowsThreadId, TRUE);
7302 #endif
7304 /* Dynamically link to optional system components. */
7306 HMODULE user_lib = GetModuleHandle ("user32.dll");
7308 #define LOAD_PROC(lib, fn) pfn##fn = (void *) GetProcAddress (lib, #fn)
7310 LOAD_PROC (user_lib, SetLayeredWindowAttributes);
7312 #undef LOAD_PROC
7314 /* Ensure scrollbar handles are at least 5 pixels. */
7315 vertical_scroll_bar_min_handle = 5;
7316 horizontal_scroll_bar_min_handle = 5;
7318 /* For either kind of scroll bar, take account of the arrows; these
7319 effectively form the border of the main scroll bar range. */
7320 vertical_scroll_bar_top_border = vertical_scroll_bar_bottom_border
7321 = GetSystemMetrics (SM_CYVSCROLL);
7322 horizontal_scroll_bar_left_border = horizontal_scroll_bar_right_border
7323 = GetSystemMetrics (SM_CYHSCROLL);
7327 void
7328 syms_of_w32term (void)
7330 DEFSYM (Qvendor_specific_keysyms, "vendor-specific-keysyms");
7332 DEFSYM (Qadded, "added");
7333 DEFSYM (Qremoved, "removed");
7334 DEFSYM (Qmodified, "modified");
7335 DEFSYM (Qrenamed_from, "renamed-from");
7336 DEFSYM (Qrenamed_to, "renamed-to");
7338 DEFVAR_LISP ("x-wait-for-event-timeout", Vx_wait_for_event_timeout,
7339 doc: /* SKIP: real doc in xterm.c. */);
7340 Vx_wait_for_event_timeout = make_float (0.1);
7342 DEFVAR_INT ("w32-num-mouse-buttons",
7343 w32_num_mouse_buttons,
7344 doc: /* Number of physical mouse buttons. */);
7345 w32_num_mouse_buttons = 2;
7347 DEFVAR_LISP ("w32-swap-mouse-buttons",
7348 Vw32_swap_mouse_buttons,
7349 doc: /* Swap the mapping of middle and right mouse buttons.
7350 When nil, middle button is mouse-2 and right button is mouse-3. */);
7351 Vw32_swap_mouse_buttons = Qnil;
7353 DEFVAR_LISP ("w32-grab-focus-on-raise",
7354 Vw32_grab_focus_on_raise,
7355 doc: /* Raised frame grabs input focus.
7356 When t, `raise-frame' grabs input focus as well. This fits well
7357 with the normal Windows click-to-focus policy, but might not be
7358 desirable when using a point-to-focus policy. */);
7359 Vw32_grab_focus_on_raise = Qt;
7361 DEFVAR_LISP ("w32-capslock-is-shiftlock",
7362 Vw32_capslock_is_shiftlock,
7363 doc: /* Apply CapsLock state to non character input keys.
7364 When nil, CapsLock only affects normal character input keys. */);
7365 Vw32_capslock_is_shiftlock = Qnil;
7367 DEFVAR_LISP ("w32-recognize-altgr",
7368 Vw32_recognize_altgr,
7369 doc: /* Recognize right-alt and left-ctrl as AltGr.
7370 When nil, the right-alt and left-ctrl key combination is
7371 interpreted normally. */);
7372 Vw32_recognize_altgr = Qt;
7374 DEFVAR_BOOL ("w32-use-visible-system-caret",
7375 w32_use_visible_system_caret,
7376 doc: /* Flag to make the system caret visible.
7377 When this is non-nil, Emacs will indicate the position of point by
7378 using the system caret instead of drawing its own cursor. Some screen
7379 reader software does not track the system cursor properly when it is
7380 invisible, and gets confused by Emacs drawing its own cursor, so this
7381 variable is initialized to t when Emacs detects that screen reader
7382 software is running as it starts up.
7384 When this variable is set, other variables affecting the appearance of
7385 the cursor have no effect. */);
7387 w32_use_visible_system_caret = 0;
7389 /* We don't yet support this, but defining this here avoids whining
7390 from cus-start.el and other places, like "M-x set-variable". */
7391 DEFVAR_BOOL ("x-use-underline-position-properties",
7392 x_use_underline_position_properties,
7393 doc: /* SKIP: real doc in xterm.c. */);
7394 x_use_underline_position_properties = 0;
7395 DEFSYM (Qx_use_underline_position_properties,
7396 "x-use-underline-position-properties");
7398 DEFVAR_BOOL ("x-underline-at-descent-line",
7399 x_underline_at_descent_line,
7400 doc: /* SKIP: real doc in xterm.c. */);
7401 x_underline_at_descent_line = 0;
7402 DEFSYM (Qx_underline_at_descent_line, "x-underline-at-descent-line");
7404 DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
7405 doc: /* SKIP: real doc in xterm.c. */);
7406 Vx_toolkit_scroll_bars = Qt;
7408 DEFVAR_BOOL ("w32-unicode-filenames",
7409 w32_unicode_filenames,
7410 doc: /* Non-nil means use Unicode APIs when passing file names to the OS.
7411 A value of nil means file names passed to the OS APIs and returned
7412 from those APIs are encoded/decoded using the ANSI codepage
7413 specified by `file-name-coding-system'.
7415 This variable is set to non-nil by default when Emacs runs on Windows
7416 systems of the NT family, including W2K, XP, Vista, Windows 7 and
7417 Windows 8. It is set to nil on Windows 9X. */);
7418 if (os_subtype == OS_9X)
7419 w32_unicode_filenames = 0;
7420 else
7421 w32_unicode_filenames = 1;
7424 /* FIXME: The following variable will be (hopefully) removed
7425 before Emacs 25.1 gets released. */
7427 DEFVAR_BOOL ("w32-add-wrapped-menu-bar-lines",
7428 w32_add_wrapped_menu_bar_lines,
7429 doc: /* Non-nil means frame resizing accounts for wrapped menu bar lines.
7430 A value of nil means frame resizing does not add the height of wrapped
7431 menu bar lines when sending a frame resize request to the Windows API.
7432 This usually means that the resulting frame height is off by the number
7433 of wrapped menu bar lines. If this is non-nil, Emacs adds the height of
7434 wrapped menu bar lines when sending frame resize requests to the Windows
7435 API. */);
7436 w32_add_wrapped_menu_bar_lines = 1;
7438 /* Tell Emacs about this window system. */
7439 Fprovide (Qw32, Qnil);