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