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