X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/c1f34a993c4ae0f13d5dfc3f1da885e510e931e6..4786c02b83a521bb35f8928dac33a884b6ca7cfa:/src/w32fns.c diff --git a/src/w32fns.c b/src/w32fns.c index 2cb99c9005..a5018ae9d3 100644 --- a/src/w32fns.c +++ b/src/w32fns.c @@ -1,6 +1,6 @@ /* Graphical user interface functions for the Microsoft Windows API. -Copyright (C) 1989, 1992-2015 Free Software Foundation, Inc. +Copyright (C) 1989, 1992-2016 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -35,24 +35,14 @@ along with GNU Emacs. If not, see . */ #include "w32term.h" #include "frame.h" #include "window.h" -#include "character.h" #include "buffer.h" -#include "intervals.h" -#include "dispextern.h" #include "keyboard.h" #include "blockinput.h" -#include "epaths.h" -#include "charset.h" #include "coding.h" -#include "ccl.h" -#include "fontset.h" -#include "systime.h" -#include "termhooks.h" #include "w32common.h" #ifdef WINDOWSNT -#include "w32heap.h" #include #endif /* WINDOWSNT */ @@ -62,11 +52,10 @@ along with GNU Emacs. If not, see . */ #include "w32.h" #endif -#include "bitmaps/gray.xbm" - #include #include #include +#include #include #include #include @@ -75,9 +64,6 @@ along with GNU Emacs. If not, see . */ #include #include -#include "font.h" -#include "w32font.h" - #ifndef FOF_NO_CONNECTED_ELEMENTS #define FOF_NO_CONNECTED_ELEMENTS 0x2000 #endif @@ -138,6 +124,19 @@ struct MONITOR_INFO DWORD dwFlags; }; +#if _WIN32_WINDOWS >= 0x0410 +#define C_CHILDREN_TITLEBAR CCHILDREN_TITLEBAR +typedef TITLEBARINFO TITLEBAR_INFO; +#else +#define C_CHILDREN_TITLEBAR 5 +typedef struct +{ + DWORD cbSize; + RECT rcTitleBar; + DWORD rgstate[C_CHILDREN_TITLEBAR+1]; +} TITLEBAR_INFO, *PTITLEBAR_INFO; +#endif + #ifndef CCHDEVICENAME #define CCHDEVICENAME 32 #endif @@ -172,6 +171,8 @@ typedef BOOL CALLBACK (* MonitorEnum_Proc) (IN HMONITOR monitor, IN HDC hdc, IN RECT *rcMonitor, IN LPARAM dwData); typedef BOOL (WINAPI * EnumDisplayMonitors_Proc) (IN HDC hdc, IN RECT *rcClip, IN MonitorEnum_Proc fnEnum, IN LPARAM dwData); +typedef BOOL (WINAPI * GetTitleBarInfo_Proc) + (IN HWND hwnd, OUT TITLEBAR_INFO* info); TrackMouseEvent_Proc track_mouse_event_fn = NULL; ImmGetCompositionString_Proc get_composition_string_fn = NULL; @@ -182,6 +183,7 @@ MonitorFromPoint_Proc monitor_from_point_fn = NULL; GetMonitorInfo_Proc get_monitor_info_fn = NULL; MonitorFromWindow_Proc monitor_from_window_fn = NULL; EnumDisplayMonitors_Proc enum_display_monitors_fn = NULL; +GetTitleBarInfo_Proc get_title_bar_info_fn = NULL; #ifdef NTGUI_UNICODE #define unicode_append_menu AppendMenuW @@ -743,7 +745,7 @@ w32_color_map_lookup (const char *colorname) tem = XCAR (elt); - if (lstrcmpi (SDATA (tem), colorname) == 0) + if (lstrcmpi (SSDATA (tem), colorname) == 0) { ret = Fcdr (elt); break; @@ -786,7 +788,7 @@ add_system_logical_colors_to_map (Lisp_Object *system_colors) strcpy (full_name_buffer, SYSTEM_COLOR_PREFIX); while (RegEnumValueA (colors_key, index, name_buffer, &name_size, - NULL, NULL, color_buffer, &color_size) + NULL, NULL, (LPBYTE)color_buffer, &color_size) == ERROR_SUCCESS) { int r, g, b; @@ -1211,9 +1213,9 @@ x_decode_color (struct frame *f, Lisp_Object arg, int def) CHECK_STRING (arg); - if (strcmp (SDATA (arg), "black") == 0) + if (strcmp (SSDATA (arg), "black") == 0) return BLACK_PIX_DEFAULT (f); - else if (strcmp (SDATA (arg), "white") == 0) + else if (strcmp (SSDATA (arg), "white") == 0) return WHITE_PIX_DEFAULT (f); if ((FRAME_DISPLAY_INFO (f)->n_planes * FRAME_DISPLAY_INFO (f)->n_cbits) == 1) @@ -1221,7 +1223,7 @@ x_decode_color (struct frame *f, Lisp_Object arg, int def) /* w32_defined_color is responsible for coping with failures by looking for a near-miss. */ - if (w32_defined_color (f, SDATA (arg), &cdef, true)) + if (w32_defined_color (f, SSDATA (arg), &cdef, true)) return cdef.pixel; /* defined_color failed; return an ultimate default. */ @@ -1283,8 +1285,10 @@ x_set_background_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval) void x_set_mouse_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval) { +#if 0 Cursor cursor, nontext_cursor, mode_cursor, hand_cursor; int count; +#endif int mask_color; if (!EQ (Qnil, arg)) @@ -1662,10 +1666,7 @@ x_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) FRAME_MENU_BAR_LINES (f) = 0; FRAME_MENU_BAR_HEIGHT (f) = 0; if (nlines) - { - FRAME_EXTERNAL_MENU_BAR (f) = 1; - windows_or_buffers_changed = 23; - } + FRAME_EXTERNAL_MENU_BAR (f) = 1; else { if (FRAME_EXTERNAL_MENU_BAR (f) == 1) @@ -1717,11 +1718,9 @@ x_set_tool_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) void x_change_tool_bar_height (struct frame *f, int height) { - Lisp_Object frame; int unit = FRAME_LINE_HEIGHT (f); int old_height = FRAME_TOOL_BAR_HEIGHT (f); int lines = (height + unit - 1) / unit; - int old_text_height = FRAME_TEXT_HEIGHT (f); Lisp_Object fullscreen; /* Make sure we redisplay all windows in this frame. */ @@ -1745,9 +1744,15 @@ x_change_tool_bar_height (struct frame *f, int height) /* Recalculate toolbar height. */ f->n_tool_bar_rows = 0; + if (old_height == 0 + && (!f->after_make_frame + || NILP (frame_inhibit_implied_resize) + || (CONSP (frame_inhibit_implied_resize) + && NILP (Fmemq (Qtool_bar_lines, frame_inhibit_implied_resize))))) + f->tool_bar_redisplayed = f->tool_bar_resized = false; adjust_frame_size (f, -1, -1, - ((!f->tool_bar_redisplayed_once + ((!f->tool_bar_resized && (NILP (fullscreen = get_frame_param (f, Qfullscreen)) || EQ (fullscreen, Qfullwidth))) ? 1 @@ -1755,6 +1760,8 @@ x_change_tool_bar_height (struct frame *f, int height) : 4), false, Qtool_bar_lines); + f->tool_bar_resized = f->tool_bar_redisplayed; + /* adjust_frame_size might not have done anything, garbage frame here. */ adjust_frame_glyphs (f); @@ -1842,7 +1849,7 @@ x_set_name (struct frame *f, Lisp_Object name, bool explicit) /* Check for no change needed in this very common case before we do any consing. */ if (!strcmp (FRAME_DISPLAY_INFO (f)->w32_id_name, - SDATA (f->name))) + SSDATA (f->name))) return; name = build_string (FRAME_DISPLAY_INFO (f)->w32_id_name); } @@ -2903,7 +2910,7 @@ get_wm_chars (HWND aWnd, int *buf, int buflen, int ignore_ctrl, int ctrl, /* Non-character payload in a WM_CHAR (Ctrl-something pressed, see above). Ignore, and report. */ if (ctrl_cnt) - *ctrl_cnt++; + (*ctrl_cnt)++; continue; } /* Traditionally, Emacs would ignore the character payload of VK_NUMPAD* @@ -2931,7 +2938,7 @@ get_wm_chars (HWND aWnd, int *buf, int buflen, int ignore_ctrl, int ctrl, #ifdef DBG_WM_CHARS # define FPRINTF_WM_CHARS(ARG) fprintf ARG #else -# define FPRINTF_WM_CHARS(ARG) 0 +# define FPRINTF_WM_CHARS(ARG) (void)0 #endif /* This is a heuristic only. This is supposed to track the state of the @@ -2990,7 +2997,7 @@ deliver_wm_chars (int do_translate, HWND hwnd, UINT msg, UINT wParam, { W32Msg wmsg; DWORD console_modifiers = construct_console_modifiers (); - int *b = buf, strip_Alt = 1, strip_ExtraMods = 1, hairy = 0; + int *b = buf, strip_ExtraMods = 1, hairy = 0; char *type_CtrlAlt = NULL; /* XXXX In fact, there may be another case when we need to do the same: @@ -3118,25 +3125,25 @@ deliver_wm_chars (int do_translate, HWND hwnd, UINT msg, UINT wParam, && console_modifiers & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED)) { type_CtrlAlt = "bB"; /* generic bindable Ctrl-Alt- modifiers */ - if (console_modifiers & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) + if ((console_modifiers & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) == (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) /* double-Ctrl: e.g. AltGr-rCtrl on some layouts (in this order!) */ type_CtrlAlt = "dD"; - else if (console_modifiers - & (LEFT_CTRL_PRESSED | LEFT_ALT_PRESSED) + else if ((console_modifiers + & (LEFT_CTRL_PRESSED | LEFT_ALT_PRESSED)) == (LEFT_CTRL_PRESSED | LEFT_ALT_PRESSED)) type_CtrlAlt = "lL"; /* Ctrl-Alt- modifiers on the left */ else if (!NILP (Vw32_recognize_altgr) - && (console_modifiers - & (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED)) + && ((console_modifiers + & (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED))) == (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED)) type_CtrlAlt = "gG"; /* modifiers as in AltGr */ } else if (wmsg.dwModifiers & (alt_modifier | meta_modifier) - || (console_modifiers - & (LEFT_WIN_PRESSED | RIGHT_WIN_PRESSED - | APPS_PRESSED | SCROLLLOCK_ON))) + || ((console_modifiers + & (LEFT_WIN_PRESSED | RIGHT_WIN_PRESSED + | APPS_PRESSED | SCROLLLOCK_ON)))) { /* Pure Alt (or combination of Alt, Win, APPS, scrolllock. */ type_CtrlAlt = "aA"; @@ -4353,97 +4360,7 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) case WM_WINDOWPOSCHANGING: /* Don't restrict the sizing of any kind of frames. If the window manager doesn't, there's no reason to do it ourselves. */ -#if 0 - if (frame_resize_pixelwise || hwnd == tip_window) -#endif - return 0; - -#if 0 - /* Don't restrict the sizing of fullscreened frames, allowing them to be - flush with the sides of the screen. */ - f = x_window_to_frame (dpyinfo, hwnd); - if (f && FRAME_PREV_FSMODE (f) != FULLSCREEN_NONE) - return 0; - - { - WINDOWPLACEMENT wp; - LPWINDOWPOS lppos = (WINDOWPOS *) lParam; - - wp.length = sizeof (WINDOWPLACEMENT); - GetWindowPlacement (hwnd, &wp); - - if (wp.showCmd != SW_SHOWMAXIMIZED && wp.showCmd != SW_SHOWMINIMIZED - && (lppos->flags & SWP_NOSIZE) == 0) - { - RECT rect; - int wdiff; - int hdiff; - DWORD font_width; - DWORD line_height; - DWORD internal_border; - DWORD vscrollbar_extra; - DWORD hscrollbar_extra; - RECT wr; - - wp.length = sizeof (wp); - GetWindowRect (hwnd, &wr); - - enter_crit (); - - font_width = GetWindowLong (hwnd, WND_FONTWIDTH_INDEX); - line_height = GetWindowLong (hwnd, WND_LINEHEIGHT_INDEX); - internal_border = GetWindowLong (hwnd, WND_BORDER_INDEX); - vscrollbar_extra = GetWindowLong (hwnd, WND_VSCROLLBAR_INDEX); - hscrollbar_extra = GetWindowLong (hwnd, WND_HSCROLLBAR_INDEX); - - leave_crit (); - - memset (&rect, 0, sizeof (rect)); - AdjustWindowRect (&rect, GetWindowLong (hwnd, GWL_STYLE), - GetMenu (hwnd) != NULL); - - /* Force width and height of client area to be exact - multiples of the character cell dimensions. */ - wdiff = (lppos->cx - (rect.right - rect.left) - - 2 * internal_border - vscrollbar_extra) - % font_width; - hdiff = (lppos->cy - (rect.bottom - rect.top) - - 2 * internal_border - hscrollbar_extra) - % line_height; - - if (wdiff || hdiff) - { - /* For right/bottom sizing we can just fix the sizes. - However for top/left sizing we will need to fix the X - and Y positions as well. */ - - int cx_mintrack = GetSystemMetrics (SM_CXMINTRACK); - int cy_mintrack = GetSystemMetrics (SM_CYMINTRACK); - - lppos->cx = max (lppos->cx - wdiff, cx_mintrack); - lppos->cy = max (lppos->cy - hdiff, cy_mintrack); - - if (wp.showCmd != SW_SHOWMAXIMIZED - && (lppos->flags & SWP_NOMOVE) == 0) - { - if (lppos->x != wr.left || lppos->y != wr.top) - { - lppos->x += wdiff; - lppos->y += hdiff; - } - else - { - lppos->flags |= SWP_NOMOVE; - } - } - - return 0; - } - } - } - - goto dflt; -#endif + return 0; case WM_GETMINMAXINFO: /* Hack to allow resizing the Emacs frame above the screen size. @@ -4700,8 +4617,7 @@ my_create_tip_window (struct frame *f) rect.right = FRAME_PIXEL_WIDTH (f); rect.bottom = FRAME_PIXEL_HEIGHT (f); - AdjustWindowRect (&rect, f->output_data.w32->dwStyle, - FRAME_EXTERNAL_MENU_BAR (f)); + AdjustWindowRect (&rect, f->output_data.w32->dwStyle, false); tip_window = FRAME_W32_WINDOW (f) = CreateWindow (EMACS_CLASS, @@ -4893,12 +4809,6 @@ do_unwind_create_frame (Lisp_Object frame) unwind_create_frame (frame); } -static void -unwind_create_frame_1 (Lisp_Object val) -{ - inhibit_lisp_code = val; -} - static void x_default_font_parameter (struct frame *f, Lisp_Object parms) { @@ -4958,11 +4868,11 @@ This function is an internal primitive--use `make-frame' instead. */) bool minibuffer_only = false; long window_prompting = 0; ptrdiff_t count = SPECPDL_INDEX (); - struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; Lisp_Object display; struct w32_display_info *dpyinfo = NULL; Lisp_Object parent; struct kboard *kb; + int x_width = 0, x_height = 0; if (!FRAME_W32_P (SELECTED_FRAME ()) && !FRAME_INITIAL_P (SELECTED_FRAME ())) @@ -5007,7 +4917,6 @@ This function is an internal primitive--use `make-frame' instead. */) /* No need to protect DISPLAY because that's not used after passing it to make_frame_without_minibuffer. */ frame = Qnil; - GCPRO4 (parameters, parent, name, frame); tem = x_get_arg (dpyinfo, parameters, Qminibuffer, "minibuffer", "Minibuffer", RES_TYPE_SYMBOL); if (EQ (tem, Qnone) || NILP (tem)) @@ -5186,7 +5095,7 @@ This function is an internal primitive--use `make-frame' instead. */) f->output_data.w32->current_cursor = f->output_data.w32->nontext_cursor; - window_prompting = x_figure_window_size (f, parameters, true); + window_prompting = x_figure_window_size (f, parameters, true, &x_width, &x_height); tem = x_get_arg (dpyinfo, parameters, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN); f->no_split = minibuffer_only || EQ (tem, Qt); @@ -5220,8 +5129,10 @@ This function is an internal primitive--use `make-frame' instead. */) /* Allow x_set_window_size, now. */ f->can_x_set_window_size = true; - adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f), 0, true, - Qx_create_frame_2); + if (x_width > 0) + SET_FRAME_WIDTH (f, x_width); + if (x_height > 0) + SET_FRAME_HEIGHT (f, x_height); /* Tell the server what size and position, etc, we want, and how badly we want them. This should be done after we have the menu @@ -5230,6 +5141,9 @@ This function is an internal primitive--use `make-frame' instead. */) x_wm_set_size_hint (f, window_prompting, false); unblock_input (); + adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f), 0, true, + Qx_create_frame_2); + /* Process fullscreen parameter here in the hope that normalizing a fullheight/fullwidth frame will produce the size set by the last adjust_frame_size call. */ @@ -5269,8 +5183,6 @@ This function is an internal primitive--use `make-frame' instead. */) if (CONSP (XCAR (tem)) && !NILP (XCAR (XCAR (tem)))) fset_param_alist (f, Fcons (XCAR (tem), f->param_alist)); - UNGCPRO; - /* Make sure windows on this frame appear in calls to next-window and similar functions. */ Vwindow_list = Qnil; @@ -5295,7 +5207,7 @@ x_get_focus_frame (struct frame *frame) DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0, doc: /* Internal function called by `color-defined-p', which see. -\(Note that the Nextstep version of this function ignores FRAME.) */) +(Note that the Nextstep version of this function ignores FRAME.) */) (Lisp_Object color, Lisp_Object frame) { XColor foo; @@ -5303,7 +5215,7 @@ DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0, CHECK_STRING (color); - if (w32_defined_color (f, SDATA (color), &foo, false)) + if (w32_defined_color (f, SSDATA (color), &foo, false)) return Qt; else return Qnil; @@ -5318,7 +5230,7 @@ DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0, CHECK_STRING (color); - if (w32_defined_color (f, SDATA (color), &foo, false)) + if (w32_defined_color (f, SSDATA (color), &foo, false)) return list3i ((GetRValue (foo.pixel) << 8) | GetRValue (foo.pixel), (GetGValue (foo.pixel) << 8) | GetGValue (foo.pixel), (GetBValue (foo.pixel) << 8) | GetBValue (foo.pixel)); @@ -5437,7 +5349,7 @@ If omitted or nil, that stands for the selected frame's display. */) DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0, doc: /* Return the "vendor ID" string of the GUI software on TERMINAL. -\(Labeling every distributor as a "vendor" embodies the false assumption +(Labeling every distributor as a "vendor" embodies the false assumption that operating systems cannot be developed and distributed noncommercially.) For GNU and Unix systems, this queries the X server software; for @@ -5594,7 +5506,6 @@ w32_display_monitor_attributes_list (void) Lisp_Object monitor_list = Qnil, monitor_frames, rest, frame; int i, n_monitors; HMONITOR *monitors; - struct gcpro gcpro1, gcpro2, gcpro3; if (!(enum_display_monitors_fn && get_monitor_info_fn && monitor_from_window_fn)) @@ -5636,8 +5547,6 @@ w32_display_monitor_attributes_list (void) } } - GCPRO3 (attributes_list, primary_monitor_attributes, monitor_frames); - for (i = 0; i < n_monitors; i++) { Lisp_Object geometry, workarea, name, attributes = Qnil; @@ -5685,8 +5594,6 @@ w32_display_monitor_attributes_list (void) if (!NILP (primary_monitor_attributes)) attributes_list = Fcons (primary_monitor_attributes, attributes_list); - UNGCPRO; - xfree (monitors); return attributes_list; @@ -5775,8 +5682,8 @@ Internal use only, use `display-monitor-attributes-list' instead. */) DEFUN ("set-message-beep", Fset_message_beep, Sset_message_beep, 1, 1, 0, doc: /* Set the sound generated when the bell is rung. -SOUND is 'asterisk, 'exclamation, 'hand, 'question, 'ok, or 'silent -to use the corresponding system sound for the bell. The 'silent sound +SOUND is `asterisk', `exclamation', `hand', `question', `ok', or `silent' +to use the corresponding system sound for the bell. The `silent' sound prevents Emacs from making any sound at all. SOUND is nil to use the normal beep. */) (Lisp_Object sound) @@ -5828,8 +5735,7 @@ x_display_info_for_name (Lisp_Object name) validate_x_resource_name (); - dpyinfo = w32_term_init (name, (unsigned char *)0, - SSDATA (Vx_resource_name)); + dpyinfo = w32_term_init (name, NULL, SSDATA (Vx_resource_name)); if (dpyinfo == 0) error ("Cannot connect to server %s", SDATA (name)); @@ -5845,10 +5751,10 @@ DISPLAY is the name of the display to connect to. Optional second arg XRM-STRING is a string of resources in xrdb format. If the optional third arg MUST-SUCCEED is non-nil, terminate Emacs if we can't open the connection. -\(In the Nextstep version, the last two arguments are currently ignored.) */) +(In the Nextstep version, the last two arguments are currently ignored.) */) (Lisp_Object display, Lisp_Object xrm_string, Lisp_Object must_succeed) { - unsigned char *xrm_option; + char *xrm_option; struct w32_display_info *dpyinfo; CHECK_STRING (display); @@ -5873,20 +5779,15 @@ terminate Emacs if we can't open the connection. HOME directory, then in Emacs etc dir for a file called rgb.txt. */ { Lisp_Object color_file; - struct gcpro gcpro1; color_file = build_string ("~/rgb.txt"); - GCPRO1 (color_file); - if (NILP (Ffile_readable_p (color_file))) color_file = Fexpand_file_name (build_string ("rgb.txt"), Fsymbol_value (intern ("data-directory"))); Vw32_color_map = Fx_load_color_file (color_file); - - UNGCPRO; } if (NILP (Vw32_color_map)) Vw32_color_map = w32_default_color_map (); @@ -5895,9 +5796,9 @@ terminate Emacs if we can't open the connection. add_system_logical_colors_to_map (&Vw32_color_map); if (! NILP (xrm_string)) - xrm_option = SDATA (xrm_string); + xrm_option = SSDATA (xrm_string); else - xrm_option = (unsigned char *) 0; + xrm_option = NULL; /* Use this general default value to start with. */ /* First remove .exe suffix from invocation-name - it looks ugly. */ @@ -5915,8 +5816,7 @@ terminate Emacs if we can't open the connection. /* This is what opens the connection and sets x_current_display. This also initializes many symbols, such as those used for input. */ - dpyinfo = w32_term_init (display, xrm_option, - SSDATA (Vx_resource_name)); + dpyinfo = w32_term_init (display, xrm_option, SSDATA (Vx_resource_name)); if (dpyinfo == 0) { @@ -6171,14 +6071,13 @@ x_create_tip_frame (struct w32_display_info *dpyinfo, struct frame *f; Lisp_Object frame; Lisp_Object name; - long window_prompting = 0; int width, height; ptrdiff_t count = SPECPDL_INDEX (); - struct gcpro gcpro1, gcpro2, gcpro3; struct kboard *kb; bool face_change_before = face_change; Lisp_Object buffer; struct buffer *old_buffer; + int x_width = 0, x_height = 0; /* Use this general default value to start with until we know if this frame has a specified name. */ @@ -6199,7 +6098,6 @@ x_create_tip_frame (struct w32_display_info *dpyinfo, Vx_resource_name = name; frame = Qnil; - GCPRO3 (parms, name, frame); /* Make a frame without minibuffer nor mode-line. */ f = make_frame (false); f->wants_modeline = 0; @@ -6310,7 +6208,7 @@ x_create_tip_frame (struct w32_display_info *dpyinfo, f->output_data.w32->dwStyle = WS_BORDER | WS_POPUP | WS_DISABLED; f->output_data.w32->parent_desc = FRAME_DISPLAY_INFO (f)->root_window; - window_prompting = x_figure_window_size (f, parms, false); + x_figure_window_size (f, parms, true, &x_width, &x_height); /* No fringes on tip frame. */ f->fringe_cols = 0; @@ -6375,8 +6273,6 @@ x_create_tip_frame (struct w32_display_info *dpyinfo, f->no_split = true; - UNGCPRO; - /* Now that the frame is official, it counts as a reference to its display. */ FRAME_DISPLAY_INFO (f)->reference_count++; @@ -6481,7 +6377,7 @@ compute_tip_xy (struct frame *f, if (INTEGERP (left)) *root_x = XINT (left); else if (INTEGERP (right)) - *root_y = XINT (right) - width; + *root_x = XINT (right) - width; else if (*root_x + XINT (dx) <= min_x) *root_x = 0; /* Can happen for negative dx */ else if (*root_x + XINT (dx) + width <= max_x) @@ -6535,14 +6431,11 @@ Text larger than the specified size is clipped. */) struct text_pos pos; int i, width, height; bool seen_reversed_p; - struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; int old_windows_or_buffers_changed = windows_or_buffers_changed; ptrdiff_t count = SPECPDL_INDEX (); specbind (Qinhibit_redisplay, Qt); - GCPRO4 (string, parms, frame, timeout); - CHECK_STRING (string); f = decode_window_system_frame (frame); if (NILP (timeout)) @@ -6784,8 +6677,7 @@ Text larger than the specified size is clipped. */) rect.left = rect.top = 0; rect.right = width; rect.bottom = height; - AdjustWindowRect (&rect, f->output_data.w32->dwStyle, - FRAME_EXTERNAL_MENU_BAR (f)); + AdjustWindowRect (&rect, f->output_data.w32->dwStyle, false); /* Position and size tooltip, and put it in the topmost group. The add-on of FRAME_COLUMN_WIDTH to the 5th argument is a @@ -6824,7 +6716,6 @@ Text larger than the specified size is clipped. */) tip_timer = call3 (intern ("run-at-time"), timeout, Qnil, intern ("x-hide-tip")); - UNGCPRO; return unbind_to (count, Qnil); } @@ -6836,7 +6727,6 @@ Value is t if tooltip was open, nil otherwise. */) { ptrdiff_t count; Lisp_Object deleted, frame, timer; - struct gcpro gcpro1, gcpro2; /* Return quickly if nothing to do. */ if (NILP (tip_timer) && NILP (tip_frame)) @@ -6844,7 +6734,6 @@ Value is t if tooltip was open, nil otherwise. */) frame = tip_frame; timer = tip_timer; - GCPRO2 (frame, timer); tip_frame = tip_timer = deleted = Qnil; count = SPECPDL_INDEX (); @@ -6860,7 +6749,6 @@ Value is t if tooltip was open, nil otherwise. */) deleted = Qt; } - UNGCPRO; return unbind_to (count, deleted); } @@ -7033,13 +6921,7 @@ value of DIR as in previous invocations; this is standard Windows behavior. */) char fname_ret[MAX_UTF8_PATH]; #endif /* NTGUI_UNICODE */ - struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5, gcpro6; - GCPRO6 (prompt, dir, default_filename, mustmatch, only_dir_p, filename); - { - struct gcpro gcpro1, gcpro2; - GCPRO2 (orig_dir, orig_prompt); /* There is no GCPRON, N>6. */ - /* Note: under NTGUI_UNICODE, we do _NOT_ use ENCODE_FILE: the system file encoding expected by the platform APIs (e.g. Cygwin's POSIX implementation) may not be the same as the encoding expected @@ -7087,9 +6969,9 @@ value of DIR as in previous invocations; this is standard Windows behavior. */) /* We modify these in-place, so make copies for safety. */ dir = Fcopy_sequence (dir); - unixtodos_filename (SDATA (dir)); + unixtodos_filename (SSDATA (dir)); filename = Fcopy_sequence (filename); - unixtodos_filename (SDATA (filename)); + unixtodos_filename (SSDATA (filename)); if (SBYTES (filename) >= MAX_UTF8_PATH) report_file_error ("filename too long", default_filename); if (w32_unicode_filenames) @@ -7102,12 +6984,12 @@ value of DIR as in previous invocations; this is standard Windows behavior. */) if (errno == ENOENT && filename_buf_w[MAX_PATH - 1] != 0) report_file_error ("filename too long", default_filename); } - len = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, + len = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags, SSDATA (prompt), -1, NULL, 0); if (len > 32768) len = 32768; prompt_w = alloca (len * sizeof (wchar_t)); - pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, + pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags, SSDATA (prompt), -1, prompt_w, len); } else @@ -7120,12 +7002,12 @@ value of DIR as in previous invocations; this is standard Windows behavior. */) if (errno == ENOENT && filename_buf_a[MAX_PATH - 1] != 0) report_file_error ("filename too long", default_filename); } - len = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, + len = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags, SSDATA (prompt), -1, NULL, 0); if (len > 32768) len = 32768; prompt_w = alloca (len * sizeof (wchar_t)); - pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, + pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags, SSDATA (prompt), -1, prompt_w, len); len = pWideCharToMultiByte (CP_ACP, 0, prompt_w, -1, NULL, 0, NULL, NULL); if (len > 32768) @@ -7268,15 +7150,13 @@ value of DIR as in previous invocations; this is standard Windows behavior. */) Qfile_name_history, default_filename, Qnil); - - UNGCPRO; } /* Make "Cancel" equivalent to C-g. */ if (NILP (filename)) Fsignal (Qquit, Qnil); - RETURN_UNGCPRO (filename); + return filename; } @@ -7314,7 +7194,7 @@ DEFUN ("system-move-file-to-trash", Fsystem_move_file_to_trash, encoded_file = ENCODE_FILE (filename); - path = map_w32_filename (SDATA (encoded_file), NULL); + path = map_w32_filename (SSDATA (encoded_file), NULL); /* The Unicode version of SHFileOperation is not supported on Windows 9X. */ @@ -7353,7 +7233,8 @@ DEFUN ("system-move-file-to-trash", Fsystem_move_file_to_trash, /* If a file cannot be represented in ANSI codepage, don't let them inadvertently delete other files because some characters are interpreted as a wildcards. */ - if (_mbspbrk (tmp_path_a, "?*")) + if (_mbspbrk ((unsigned char *)tmp_path_a, + (const unsigned char *)"?*")) result = ERROR_FILE_NOT_FOUND; else { @@ -7482,7 +7363,6 @@ a ShowWindow flag: char *doc_a = NULL, *params_a = NULL, *ops_a = NULL; Lisp_Object absdoc, handler; BOOL success; - struct gcpro gcpro1; #endif CHECK_STRING (document); @@ -7582,7 +7462,6 @@ a ShowWindow flag: absolute. But DOCUMENT does not have to be a file, it can be a URL, for example. So we make it absolute only if it is an existing file; if it is a file that does not exist, tough. */ - GCPRO1 (absdoc); absdoc = Fexpand_file_name (document, Qnil); /* Don't call file handlers for file-exists-p, since they might attempt to access the file, which could fail or produce undesired @@ -7606,15 +7485,14 @@ a ShowWindow flag: } else document = ENCODE_FILE (document); - UNGCPRO; current_dir = ENCODE_FILE (current_dir); /* Cannot use filename_to_utf16/ansi with DOCUMENT, since it could be a URL that is not limited to MAX_PATH chararcters. */ - doclen = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, + doclen = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags, SSDATA (document), -1, NULL, 0); doc_w = xmalloc (doclen * sizeof (wchar_t)); - pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, + pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags, SSDATA (document), -1, doc_w, doclen); if (use_unicode) { @@ -7629,12 +7507,12 @@ a ShowWindow flag: int len; parameters = ENCODE_SYSTEM (parameters); - len = pMultiByteToWideChar (CP_ACP, MB_ERR_INVALID_CHARS, + len = pMultiByteToWideChar (CP_ACP, multiByteToWideCharFlags, SSDATA (parameters), -1, NULL, 0); if (len > 32768) len = 32768; params_w = alloca (len * sizeof (wchar_t)); - pMultiByteToWideChar (CP_ACP, MB_ERR_INVALID_CHARS, + pMultiByteToWideChar (CP_ACP, multiByteToWideCharFlags, SSDATA (parameters), -1, params_w, len); params_w[len - 1] = 0; } @@ -7673,7 +7551,7 @@ a ShowWindow flag: } else { - char document_a[MAX_PATH], current_dir_a[MAX_PATH]; + char current_dir_a[MAX_PATH]; SHELLEXECUTEINFOA shexinfo_a; int codepage = codepage_for_filenames (NULL); int ldoc_a = pWideCharToMultiByte (codepage, 0, doc_w, -1, NULL, 0, @@ -7752,22 +7630,17 @@ w32_parse_hot_key (Lisp_Object key) int vk_code; int lisp_modifiers; int w32_modifiers; - struct gcpro gcpro1; CHECK_VECTOR (key); if (ASIZE (key) != 1) return Qnil; - GCPRO1 (key); - c = AREF (key, 0); if (CONSP (c) && lucid_event_type_list_p (c)) c = Fevent_convert_list (c); - UNGCPRO; - if (! INTEGERP (c) && ! SYMBOLP (c)) error ("Key definition is invalid"); @@ -7779,7 +7652,7 @@ w32_parse_hot_key (Lisp_Object key) c = Fcar (c); if (!SYMBOLP (c)) emacs_abort (); - vk_code = lookup_vk_code (SDATA (SYMBOL_NAME (c))); + vk_code = lookup_vk_code (SSDATA (SYMBOL_NAME (c))); } else if (INTEGERP (c)) { @@ -7986,183 +7859,259 @@ This is a direct interface to the Windows API FindWindow function. */) return Qt; } -DEFUN ("w32-frame-menu-bar-size", Fw32_frame_menu_bar_size, Sw32_frame_menu_bar_size, 0, 1, 0, - doc: /* Return sizes of menu bar on frame FRAME. -The return value is a list of four elements: The current width and -height of FRAME's menu bar in pixels, the height of one menu bar line in -a wrapped menu bar in pixels, and the height of a single line menu bar -in pixels. - -If FRAME is omitted or nil, the selected frame is used. */) - (Lisp_Object frame) -{ - struct frame *f = decode_any_frame (frame); - MENUBARINFO menu_bar; - int width, height, single_height, wrapped_height; - - if (FRAME_INITIAL_P (f) || !FRAME_W32_P (f)) - return Qnil; - - block_input (); - - single_height = GetSystemMetrics (SM_CYMENU); - wrapped_height = GetSystemMetrics (SM_CYMENUSIZE); - menu_bar.cbSize = sizeof (menu_bar); - menu_bar.rcBar.right = menu_bar.rcBar.left = 0; - menu_bar.rcBar.top = menu_bar.rcBar.bottom = 0; - GetMenuBarInfo (FRAME_W32_WINDOW (f), 0xFFFFFFFD, 0, &menu_bar); - width = menu_bar.rcBar.right - menu_bar.rcBar.left; - height = menu_bar.rcBar.bottom - menu_bar.rcBar.top; - - unblock_input (); - - return list4 (make_number (width), make_number (height), - make_number (wrapped_height), make_number (single_height)); -} - -DEFUN ("w32-frame-rect", Fw32_frame_rect, Sw32_frame_rect, 0, 2, 0, - doc: /* Return boundary rectangle of FRAME in screen coordinates. -FRAME must be a live frame and defaults to the selected one. +DEFUN ("w32-frame-geometry", Fw32_frame_geometry, Sw32_frame_geometry, 0, 1, 0, + doc: /* Return geometric attributes of FRAME. +FRAME must be a live frame and defaults to the selected one. The return +value is an association list of the attributes listed below. All height +and width values are in pixels. -The boundary rectangle is a list of four elements, specifying the left, -top, right and bottom screen coordinates of FRAME including menu and -title bar and decorations. Optional argument CLIENT non-nil means to -return the boundaries of the client rectangle which excludes menu and -title bar and decorations. */) - (Lisp_Object frame, Lisp_Object client) -{ - struct frame *f = decode_live_frame (frame); - RECT rect; - - if (FRAME_INITIAL_P (f) || !FRAME_W32_P (f)) - return Qnil; - - block_input (); - - if (!NILP (client)) - GetClientRect (FRAME_W32_WINDOW (f), &rect); - else - GetWindowRect (FRAME_W32_WINDOW (f), &rect); - - unblock_input (); - - return list4 (make_number (rect.left), make_number (rect.top), - make_number (rect.right), make_number (rect.bottom)); -} - -DEFUN ("x-frame-geometry", Fx_frame_geometry, Sx_frame_geometry, 0, 1, 0, - doc: /* Return geometric attributes of frame FRAME. -FRAME must be a live frame and defaults to the selected one. - -The return value is an association list containing the following -elements (all size values are in pixels). +`outer-position' is a cons of the outer left and top edges of FRAME + relative to the origin - the position (0, 0) - of FRAME's display. -- `frame-outer-size' is a cons of the outer width and height of FRAME. - The outer size includes the title bar and the external borders as well - as any menu and/or tool bar of frame. +`outer-size' is a cons of the outer width and height of FRAME. The + outer size includes the title bar and the external borders as well as + any menu and/or tool bar of frame. -- `border' is a cons of the horizontal and vertical width of FRAME's - external borders. +`external-border-size' is a cons of the horizontal and vertical width of + FRAME's external borders as supplied by the window manager. -- `title-bar-height' is the height of the title bar of FRAME. +`title-bar-size' is a cons of the width and height of the title bar of + FRAME as supplied by the window manager. If both of them are zero, + FRAME has no title bar. If only the width is zero, Emacs was not + able to retrieve the width information. -- `menu-bar-external' if t means the menu bar is by default external - (not included in the inner size of FRAME). +`menu-bar-external', if non-nil, means the menu bar is external (never + included in the inner edges of FRAME). -- `menu-bar-size' is a cons of the width and height of the menu bar of +`menu-bar-size' is a cons of the width and height of the menu bar of FRAME. -- `tool-bar-external' if t means the tool bar is by default external - (not included in the inner size of FRAME). +`tool-bar-external', if non-nil, means the tool bar is external (never + included in the inner edges of FRAME). -- `tool-bar-side' tells tells on which side the tool bar on FRAME is by - default and can be one of `left', `top', `right' or `bottom'. +`tool-bar-position' tells on which side the tool bar on FRAME is and can + be one of `left', `top', `right' or `bottom'. If this is nil, FRAME + has no tool bar. -- `tool-bar-size' is a cons of the width and height of the tool bar of +`tool-bar-size' is a cons of the width and height of the tool bar of FRAME. -- `frame-inner-size' is a cons of the inner width and height of FRAME. - This excludes FRAME's title bar and external border as well as any - external menu and/or tool bar. */) +`internal-border-width' is the width of the internal border of + FRAME. */) (Lisp_Object frame) { struct frame *f = decode_live_frame (frame); - Lisp_Object geometry = Qnil; - RECT frame_outer_edges, frame_inner_edges; + MENUBARINFO menu_bar; - int border_width, border_height, title_height; - int single_bar_height, wrapped_bar_height, menu_bar_height; - Lisp_Object fullscreen = Fframe_parameter (frame, Qfullscreen); + WINDOWINFO window; + int left, top, right, bottom; + unsigned int external_border_width, external_border_height; + int title_bar_width = 0, title_bar_height = 0; + int single_menu_bar_height, wrapped_menu_bar_height, menu_bar_height; + int tool_bar_height = FRAME_TOOL_BAR_HEIGHT (f); + int internal_border_width = FRAME_INTERNAL_BORDER_WIDTH (f); if (FRAME_INITIAL_P (f) || !FRAME_W32_P (f)) return Qnil; block_input (); - - /* Outer frame rectangle, including outer borders and title bar. */ - GetWindowRect (FRAME_W32_WINDOW (f), &frame_outer_edges); - /* Inner frame rectangle, excluding borders and title bar. */ - GetClientRect (FRAME_W32_WINDOW (f), &frame_inner_edges); - /* Outer border. */ - border_width = GetSystemMetrics (SM_CXFRAME); - border_height = GetSystemMetrics (SM_CYFRAME); + /* Outer rectangle and borders. */ + window.cbSize = sizeof (window); + GetWindowInfo (FRAME_W32_WINDOW (f), &window); + external_border_width = window.cxWindowBorders; + external_border_height = window.cyWindowBorders; /* Title bar. */ - title_height = GetSystemMetrics (SM_CYCAPTION); + if (get_title_bar_info_fn) + { + TITLEBAR_INFO title_bar; + + title_bar.cbSize = sizeof (title_bar); + title_bar.rcTitleBar.left = title_bar.rcTitleBar.right = 0; + title_bar.rcTitleBar.top = title_bar.rcTitleBar.bottom = 0; + for (int i = 0; i < 6; i++) + title_bar.rgstate[i] = 0; + if (get_title_bar_info_fn (FRAME_W32_WINDOW (f), &title_bar) + && !(title_bar.rgstate[0] & 0x00008001)) + { + title_bar_width + = title_bar.rcTitleBar.right - title_bar.rcTitleBar.left; + title_bar_height + = title_bar.rcTitleBar.bottom - title_bar.rcTitleBar.top; + } + } + else if ((window.dwStyle & WS_CAPTION) == WS_CAPTION) + title_bar_height = GetSystemMetrics (SM_CYCAPTION); /* Menu bar. */ menu_bar.cbSize = sizeof (menu_bar); menu_bar.rcBar.right = menu_bar.rcBar.left = 0; menu_bar.rcBar.top = menu_bar.rcBar.bottom = 0; GetMenuBarInfo (FRAME_W32_WINDOW (f), 0xFFFFFFFD, 0, &menu_bar); - single_bar_height = GetSystemMetrics (SM_CYMENU); - wrapped_bar_height = GetSystemMetrics (SM_CYMENUSIZE); + single_menu_bar_height = GetSystemMetrics (SM_CYMENU); + wrapped_menu_bar_height = GetSystemMetrics (SM_CYMENUSIZE); unblock_input (); + left = window.rcWindow.left; + top = window.rcWindow.top; + right = window.rcWindow.right; + bottom = window.rcWindow.bottom; + + /* Menu bar. */ menu_bar_height = menu_bar.rcBar.bottom - menu_bar.rcBar.top; /* Fix menu bar height reported by GetMenuBarInfo. */ - if (menu_bar_height > single_bar_height) + if (menu_bar_height > single_menu_bar_height) /* A wrapped menu bar. */ - menu_bar_height += single_bar_height - wrapped_bar_height; + menu_bar_height += single_menu_bar_height - wrapped_menu_bar_height; else if (menu_bar_height > 0) /* A single line menu bar. */ - menu_bar_height = single_bar_height; - - return - listn (CONSTYPE_HEAP, 10, - Fcons (Qframe_position, - Fcons (make_number (frame_outer_edges.left), - make_number (frame_outer_edges.top))), - Fcons (Qframe_outer_size, - Fcons (make_number - (frame_outer_edges.right - frame_outer_edges.left), - make_number - (frame_outer_edges.bottom - frame_outer_edges.top))), + menu_bar_height = single_menu_bar_height; + + return listn (CONSTYPE_HEAP, 10, + Fcons (Qouter_position, + Fcons (make_number (left), make_number (top))), + Fcons (Qouter_size, + Fcons (make_number (right - left), + make_number (bottom - top))), Fcons (Qexternal_border_size, - ((EQ (fullscreen, Qfullboth) || EQ (fullscreen, Qfullscreen)) - ? Fcons (make_number (0), make_number (0)) - : Fcons (make_number (border_width), - make_number (border_height)))), - Fcons (Qtitle_height, - ((EQ (fullscreen, Qfullboth) || EQ (fullscreen, Qfullscreen)) - ? make_number (0) - : make_number (title_height))), + Fcons (make_number (external_border_width), + make_number (external_border_height))), + Fcons (Qtitle_bar_size, + Fcons (make_number (title_bar_width), + make_number (title_bar_height))), Fcons (Qmenu_bar_external, Qt), Fcons (Qmenu_bar_size, Fcons (make_number (menu_bar.rcBar.right - menu_bar.rcBar.left), make_number (menu_bar_height))), Fcons (Qtool_bar_external, Qnil), - Fcons (Qtool_bar_position, Qtop), + Fcons (Qtool_bar_position, tool_bar_height ? Qtop : Qnil), Fcons (Qtool_bar_size, - Fcons (make_number (FRAME_TOOL_BAR_LINES (f) - ? (FRAME_PIXEL_WIDTH (f) - - 2 * FRAME_INTERNAL_BORDER_WIDTH (f)) + Fcons (make_number + (tool_bar_height + ? right - left - 2 * internal_border_width : 0), - make_number (FRAME_TOOL_BAR_HEIGHT (f)))), - Fcons (Qframe_inner_size, - Fcons (make_number - (frame_inner_edges.right - frame_inner_edges.left), - make_number - (frame_inner_edges.bottom - frame_inner_edges.top)))); + make_number (tool_bar_height))), + Fcons (Qinternal_border_width, + make_number (internal_border_width))); +} + +DEFUN ("w32-frame-edges", Fw32_frame_edges, Sw32_frame_edges, 0, 2, 0, + doc: /* Return edge coordinates of FRAME. +FRAME must be a live frame and defaults to the selected one. The return +value is a list of the form (LEFT, TOP, RIGHT, BOTTOM). All values are +in pixels relative to the origin - the position (0, 0) - of FRAME's +display. + +If optional argument TYPE is the symbol `outer-edges', return the outer +edges of FRAME. The outer edges comprise the decorations of the window +manager (like the title bar or external borders) as well as any external +menu or tool bar of FRAME. If optional argument TYPE is the symbol +`native-edges' or nil, return the native edges of FRAME. The native +edges exclude the decorations of the window manager and any external +menu or tool bar of FRAME. If TYPE is the symbol `inner-edges', return +the inner edges of FRAME. These edges exclude title bar, any borders, +menu bar or tool bar of FRAME. */) + (Lisp_Object frame, Lisp_Object type) +{ + struct frame *f = decode_live_frame (frame); + + if (FRAME_INITIAL_P (f) || !FRAME_W32_P (f)) + return Qnil; + + if (EQ (type, Qouter_edges)) + { + RECT rectangle; + + block_input (); + /* Outer frame rectangle, including outer borders and title bar. */ + GetWindowRect (FRAME_W32_WINDOW (f), &rectangle); + unblock_input (); + + return list4 (make_number (rectangle.left), + make_number (rectangle.top), + make_number (rectangle.right), + make_number (rectangle.bottom)); + } + else + { + RECT rectangle; + POINT pt; + int left, top, right, bottom; + + block_input (); + /* Inner frame rectangle, excluding borders and title bar. */ + GetClientRect (FRAME_W32_WINDOW (f), &rectangle); + /* Get top-left corner of native rectangle in screen + coordinates. */ + pt.x = 0; + pt.y = 0; + ClientToScreen (FRAME_W32_WINDOW (f), &pt); + unblock_input (); + + left = pt.x; + top = pt.y; + right = left + rectangle.right; + bottom = top + rectangle.bottom; + + if (EQ (type, Qinner_edges)) + { + int internal_border_width = FRAME_INTERNAL_BORDER_WIDTH (f); + + return list4 (make_number (left + internal_border_width), + make_number (top + + FRAME_TOOL_BAR_HEIGHT (f) + + internal_border_width), + make_number (right - internal_border_width), + make_number (bottom - internal_border_width)); + } + else + return list4 (make_number (left), make_number (top), + make_number (right), make_number (bottom)); + } +} + +DEFUN ("w32-mouse-absolute-pixel-position", Fw32_mouse_absolute_pixel_position, + Sw32_mouse_absolute_pixel_position, 0, 0, 0, + doc: /* Return absolute position of mouse cursor in pixels. +The position is returned as a cons cell (X . Y) of the coordinates of +the mouse cursor position in pixels relative to a position (0, 0) of the +selected frame's display. */) + (void) +{ + POINT pt; + + block_input (); + GetCursorPos (&pt); + unblock_input (); + + return Fcons (make_number (pt.x), make_number (pt.y)); +} + +DEFUN ("w32-set-mouse-absolute-pixel-position", Fw32_set_mouse_absolute_pixel_position, + Sw32_set_mouse_absolute_pixel_position, 2, 2, 0, + doc: /* Move mouse pointer to absolute pixel position (X, Y). +The coordinates X and Y are interpreted in pixels relative to a position +(0, 0) of the selected frame's display. */) + (Lisp_Object x, Lisp_Object y) +{ + UINT trail_num = 0; + BOOL ret = false; + + CHECK_TYPE_RANGED_INTEGER (int, x); + CHECK_TYPE_RANGED_INTEGER (int, y); + + block_input (); + /* When "mouse trails" are in effect, moving the mouse cursor + sometimes leaves behind an annoying "ghost" of the pointer. + Avoid that by momentarily switching off mouse trails. */ + if (os_subtype == OS_NT + && w32_major_version + w32_minor_version >= 6) + ret = SystemParametersInfo (SPI_GETMOUSETRAILS, 0, &trail_num, 0); + SetCursorPos (XINT (x), XINT (y)); + if (ret) + SystemParametersInfo (SPI_SETMOUSETRAILS, trail_num, NULL, 0); + unblock_input (); + + return Qnil; } DEFUN ("w32-battery-status", Fw32_battery_status, Sw32_battery_status, 0, 0, 0, @@ -8317,7 +8266,7 @@ If the underlying system call fails, value is nil. */) char rootname[MAX_UTF8_PATH]; wchar_t rootname_w[MAX_PATH]; char rootname_a[MAX_PATH]; - char *name = SDATA (encoded); + char *name = SSDATA (encoded); BOOL result; /* find the root name of the volume if given */ @@ -8771,7 +8720,7 @@ w32_kbd_patch_key (KEY_EVENT_RECORD *event, int cpId) event->uChar.UnicodeChar = buf[isdead - 1]; isdead = WideCharToMultiByte (cpId, 0, buf, isdead, - ansi_code, 4, NULL, NULL); + (LPSTR)ansi_code, 4, NULL, NULL); } else isdead = 0; @@ -8813,6 +8762,457 @@ Internal use only. */) return menubar_in_use ? Qt : Qnil; } +#if defined WINDOWSNT && !defined HAVE_DBUS + +/*********************************************************************** + Tray notifications + ***********************************************************************/ +/* A private struct declaration to avoid compile-time limits. */ +typedef struct MY_NOTIFYICONDATAW { + DWORD cbSize; + HWND hWnd; + UINT uID; + UINT uFlags; + UINT uCallbackMessage; + HICON hIcon; + WCHAR szTip[128]; + DWORD dwState; + DWORD dwStateMask; + WCHAR szInfo[256]; + _ANONYMOUS_UNION union { + UINT uTimeout; + UINT uVersion; + } DUMMYUNIONNAME; + WCHAR szInfoTitle[64]; + DWORD dwInfoFlags; + GUID guidItem; + HICON hBalloonIcon; +} MY_NOTIFYICONDATAW; + +#define MYNOTIFYICONDATAW_V1_SIZE offsetof (MY_NOTIFYICONDATAW, szTip[64]) +#define MYNOTIFYICONDATAW_V2_SIZE offsetof (MY_NOTIFYICONDATAW, guidItem) +#define MYNOTIFYICONDATAW_V3_SIZE offsetof (MY_NOTIFYICONDATAW, hBalloonIcon) +#ifndef NIF_INFO +# define NIF_INFO 0x00000010 +#endif +#ifndef NIIF_NONE +# define NIIF_NONE 0x00000000 +#endif +#ifndef NIIF_INFO +# define NIIF_INFO 0x00000001 +#endif +#ifndef NIIF_WARNING +# define NIIF_WARNING 0x00000002 +#endif +#ifndef NIIF_ERROR +# define NIIF_ERROR 0x00000003 +#endif + + +#define EMACS_TRAY_NOTIFICATION_ID 42 /* arbitrary */ +#define EMACS_NOTIFICATION_MSG (WM_APP + 1) + +enum NI_Severity { + Ni_None, + Ni_Info, + Ni_Warn, + Ni_Err +}; + +/* Report the version of a DLL given by its name. The return value is + constructed using MAKEDLLVERULL. */ +static ULONGLONG +get_dll_version (const char *dll_name) +{ + ULONGLONG version = 0; + HINSTANCE hdll = LoadLibrary (dll_name); + + if (hdll) + { + DLLGETVERSIONPROC pDllGetVersion + = (DLLGETVERSIONPROC) GetProcAddress (hdll, "DllGetVersion"); + + if (pDllGetVersion) + { + DLLVERSIONINFO dvi; + HRESULT result; + + memset (&dvi, 0, sizeof(dvi)); + dvi.cbSize = sizeof(dvi); + result = pDllGetVersion (&dvi); + if (SUCCEEDED (result)) + version = MAKEDLLVERULL (dvi.dwMajorVersion, dvi.dwMinorVersion, + 0, 0); + } + FreeLibrary (hdll); + } + + return version; +} + +/* Return the number of bytes in UTF-8 encoded string STR that + corresponds to at most LIM characters. If STR ends before LIM + characters, return the number of bytes in STR including the + terminating null byte. */ +static int +utf8_mbslen_lim (const char *str, int lim) +{ + const char *p = str; + int mblen = 0, nchars = 0; + + while (*p && nchars < lim) + { + int nbytes = CHAR_BYTES (*p); + + mblen += nbytes; + nchars++; + p += nbytes; + } + + if (!*p && nchars < lim) + mblen++; + + return mblen; +} + +/* Low-level subroutine to show tray notifications. All strings are + supposed to be unibyte UTF-8 encoded by the caller. */ +static EMACS_INT +add_tray_notification (struct frame *f, const char *icon, const char *tip, + enum NI_Severity severity, unsigned timeout, + const char *title, const char *msg) +{ + EMACS_INT retval = EMACS_TRAY_NOTIFICATION_ID; + + if (FRAME_W32_P (f)) + { + MY_NOTIFYICONDATAW nidw; + ULONGLONG shell_dll_version = get_dll_version ("Shell32.dll"); + wchar_t tipw[128], msgw[256], titlew[64]; + int tiplen; + + memset (&nidw, 0, sizeof(nidw)); + + /* MSDN says the full struct is supported since Vista, whose + Shell32.dll version is said to be 6.0.6. But DllGetVersion + cannot report the 3rd field value, it reports "build number" + instead, which is something else. So we use the Windows 7's + version 6.1 as cutoff, and Vista loses. (Actually, the loss + is not a real one, since we don't expose the hBalloonIcon + member of the struct to Lisp.) */ + if (shell_dll_version >= MAKEDLLVERULL (6, 1, 0, 0)) /* >= Windows 7 */ + nidw.cbSize = sizeof (nidw); + else if (shell_dll_version >= MAKEDLLVERULL (6, 0, 0, 0)) /* XP */ + nidw.cbSize = MYNOTIFYICONDATAW_V3_SIZE; + else if (shell_dll_version >= MAKEDLLVERULL (5, 0, 0, 0)) /* W2K */ + nidw.cbSize = MYNOTIFYICONDATAW_V2_SIZE; + else + nidw.cbSize = MYNOTIFYICONDATAW_V1_SIZE; /* < W2K */ + nidw.hWnd = FRAME_W32_WINDOW (f); + nidw.uID = EMACS_TRAY_NOTIFICATION_ID; + nidw.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP | NIF_INFO; + nidw.uCallbackMessage = EMACS_NOTIFICATION_MSG; + if (!*icon) + nidw.hIcon = LoadIcon (hinst, EMACS_CLASS); + else + { + if (w32_unicode_filenames) + { + wchar_t icon_w[MAX_PATH]; + + if (filename_to_utf16 (icon, icon_w) != 0) + { + errno = ENOENT; + return -1; + } + nidw.hIcon = LoadImageW (NULL, icon_w, IMAGE_ICON, 0, 0, + LR_DEFAULTSIZE | LR_LOADFROMFILE); + } + else + { + char icon_a[MAX_PATH]; + + if (filename_to_ansi (icon, icon_a) != 0) + { + errno = ENOENT; + return -1; + } + nidw.hIcon = LoadImageA (NULL, icon_a, IMAGE_ICON, 0, 0, + LR_DEFAULTSIZE | LR_LOADFROMFILE); + } + } + if (!nidw.hIcon) + { + switch (GetLastError ()) + { + case ERROR_FILE_NOT_FOUND: + errno = ENOENT; + break; + default: + errno = ENOMEM; + break; + } + return -1; + } + + /* Windows 9X and NT4 support only 64 characters in the Tip, + later versions support up to 128. */ + if (nidw.cbSize == MYNOTIFYICONDATAW_V1_SIZE) + { + tiplen = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags, + tip, utf8_mbslen_lim (tip, 63), + tipw, 64); + if (tiplen >= 63) + tipw[63] = 0; + } + else + { + tiplen = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags, + tip, utf8_mbslen_lim (tip, 127), + tipw, 128); + if (tiplen >= 127) + tipw[127] = 0; + } + if (tiplen == 0) + { + errno = EINVAL; + retval = -1; + goto done; + } + wcscpy (nidw.szTip, tipw); + + /* The rest of the structure is only supported since Windows 2000. */ + if (nidw.cbSize > MYNOTIFYICONDATAW_V1_SIZE) + { + int slen; + + slen = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags, + msg, utf8_mbslen_lim (msg, 255), + msgw, 256); + if (slen >= 255) + msgw[255] = 0; + else if (slen == 0) + { + errno = EINVAL; + retval = -1; + goto done; + } + wcscpy (nidw.szInfo, msgw); + nidw.uTimeout = timeout; + slen = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags, + title, utf8_mbslen_lim (title, 63), + titlew, 64); + if (slen >= 63) + titlew[63] = 0; + else if (slen == 0) + { + errno = EINVAL; + retval = -1; + goto done; + } + wcscpy (nidw.szInfoTitle, titlew); + + switch (severity) + { + case Ni_None: + nidw.dwInfoFlags = NIIF_NONE; + break; + case Ni_Info: + default: + nidw.dwInfoFlags = NIIF_INFO; + break; + case Ni_Warn: + nidw.dwInfoFlags = NIIF_WARNING; + break; + case Ni_Err: + nidw.dwInfoFlags = NIIF_ERROR; + break; + } + } + + if (!Shell_NotifyIconW (NIM_ADD, (PNOTIFYICONDATAW)&nidw)) + { + /* GetLastError returns meaningless results when + Shell_NotifyIcon fails. */ + DebPrint (("Shell_NotifyIcon ADD failed (err=%d)\n", + GetLastError ())); + errno = EINVAL; + retval = -1; + } + done: + if (*icon && !DestroyIcon (nidw.hIcon)) + DebPrint (("DestroyIcon failed (err=%d)\n", GetLastError ())); + } + return retval; +} + +/* Low-level subroutine to remove a tray notification. Note: we only + pass the minimum data about the notification: its ID and the handle + of the window to which it sends messages. MSDN doesn't say this is + enough, but it works in practice. This allows us to avoid keeping + the notification data around after we show the notification. */ +static void +delete_tray_notification (struct frame *f, int id) +{ + if (FRAME_W32_P (f)) + { + MY_NOTIFYICONDATAW nidw; + + memset (&nidw, 0, sizeof(nidw)); + nidw.hWnd = FRAME_W32_WINDOW (f); + nidw.uID = id; + + if (!Shell_NotifyIconW (NIM_DELETE, (PNOTIFYICONDATAW)&nidw)) + { + /* GetLastError returns meaningless results when + Shell_NotifyIcon fails. */ + DebPrint (("Shell_NotifyIcon DELETE failed\n")); + errno = EINVAL; + return; + } + } + return; +} + +DEFUN ("w32-notification-notify", + Fw32_notification_notify, Sw32_notification_notify, + 0, MANY, 0, + doc: /* Display an MS-Windows tray notification as specified by PARAMS. + +Value is the integer unique ID of the notification that can be used +to remove the notification using `w32-notification-close', which see. +If the function fails, the return value is nil. + +Tray notifications, a.k.a. \"taskbar messages\", are messages that +inform the user about events unrelated to the current user activity, +such as a significant system event, by briefly displaying informative +text in a balloon from an icon in the notification area of the taskbar. + +Parameters in PARAMS are specified as keyword/value pairs. All the +parameters are optional, but if no parameters are specified, the +function will do nothing and return nil. + +The following parameters are supported: + +:icon ICON -- Display ICON in the system tray. If ICON is a string, + it should specify a file name from which to load the + icon; the specified file should be a .ico Windows icon + file. If ICON is not a string, or if this parameter + is not specified, the standard Emacs icon will be used. + +:tip TIP -- Use TIP as the tooltip for the notification. If TIP + is a string, this is the text of a tooltip that will + be shown when the mouse pointer hovers over the tray + icon added by the notification. If TIP is not a + string, or if this parameter is not specified, the + default tooltip text is \"Emacs notification\". The + tooltip text can be up to 127 characters long (63 + on Windows versions before W2K). Longer strings + will be truncated. + +:level LEVEL -- Notification severity level, one of `info', + `warning', or `error'. If given, the value + determines the icon displayed to the left of the + notification title, but only if the `:title' + parameter (see below) is also specified and is a + string. + +:title TITLE -- The title of the notification. If TITLE is a string, + it is displayed in a larger font immediately above + the body text. The title text can be up to 63 + characters long; longer text will be truncated. + +:body BODY -- The body of the notification. If BODY is a string, + it specifies the text of the notification message. + Use embedded newlines to control how the text is + broken into lines. The body text can be up to 255 + characters long, and will be truncated if it's longer. + +Note that versions of Windows before W2K support only `:icon' and `:tip'. +You can pass the other parameters, but they will be ignored on those +old systems. + +There can be at most one active notification at any given time. An +active notification must be removed by calling `w32-notification-close' +before a new one can be shown. + +usage: (w32-notification-notify &rest PARAMS) */) + (ptrdiff_t nargs, Lisp_Object *args) +{ + struct frame *f = SELECTED_FRAME (); + Lisp_Object arg_plist, lres; + EMACS_INT retval; + char *icon, *tip, *title, *msg; + enum NI_Severity severity; + unsigned timeout; + + if (nargs == 0) + return Qnil; + + arg_plist = Flist (nargs, args); + + /* Icon. */ + lres = Fplist_get (arg_plist, QCicon); + if (STRINGP (lres)) + icon = SSDATA (ENCODE_FILE (Fexpand_file_name (lres, Qnil))); + else + icon = ""; + + /* Tip. */ + lres = Fplist_get (arg_plist, QCtip); + if (STRINGP (lres)) + tip = SSDATA (code_convert_string_norecord (lres, Qutf_8, 1)); + else + tip = "Emacs notification"; + + /* Severity. */ + lres = Fplist_get (arg_plist, QClevel); + if (NILP (lres)) + severity = Ni_None; + else if (EQ (lres, Qinfo)) + severity = Ni_Info; + else if (EQ (lres, Qwarning)) + severity = Ni_Warn; + else if (EQ (lres, Qerror)) + severity = Ni_Err; + else + severity = Ni_Info; + + /* Title. */ + lres = Fplist_get (arg_plist, QCtitle); + if (STRINGP (lres)) + title = SSDATA (code_convert_string_norecord (lres, Qutf_8, 1)); + else + title = ""; + + /* Notification body text. */ + lres = Fplist_get (arg_plist, QCbody); + if (STRINGP (lres)) + msg = SSDATA (code_convert_string_norecord (lres, Qutf_8, 1)); + else + msg = ""; + + /* Do it! */ + retval = add_tray_notification (f, icon, tip, severity, timeout, title, msg); + return (retval < 0 ? Qnil : make_number (retval)); +} + +DEFUN ("w32-notification-close", + Fw32_notification_close, Sw32_notification_close, + 1, 1, 0, + doc: /* Remove the MS-Windows tray notification specified by its ID. */) + (Lisp_Object id) +{ + struct frame *f = SELECTED_FRAME (); + + if (INTEGERP (id)) + delete_tray_notification (f, XINT (id)); + + return Qnil; +} + +#endif /* WINDOWSNT && !HAVE_DBUS */ + /*********************************************************************** Initialization @@ -8886,6 +9286,15 @@ syms_of_w32fns (void) DEFSYM (Qframes, "frames"); DEFSYM (Qtip_frame, "tip-frame"); DEFSYM (Qunicode_sip, "unicode-sip"); +#if defined WINDOWSNT && !defined HAVE_DBUS + DEFSYM (QCicon, ":icon"); + DEFSYM (QCtip, ":tip"); + DEFSYM (QClevel, ":level"); + DEFSYM (Qinfo, "info"); + DEFSYM (Qwarning, "warning"); + DEFSYM (QCtitle, ":title"); + DEFSYM (QCbody, ":body"); +#endif /* Symbols used elsewhere, but only in MS-Windows-specific code. */ DEFSYM (Qgnutls_dll, "gnutls"); @@ -9162,6 +9571,16 @@ Default is nil. This variable has effect only on NT family of systems, not on Windows 9X. */); w32_use_fallback_wm_chars_method = 0; + DEFVAR_BOOL ("w32-disable-new-uniscribe-apis", + w32_disable_new_uniscribe_apis, + doc: /* Non-nil means don't use new Uniscribe APIs. +The new APIs are used to access OTF features supported by fonts. +This is intended only for debugging of the new Uniscribe-related code. +Default is nil. + +This variable has effect only on Windows Vista and later. */); + w32_disable_new_uniscribe_apis = 0; + #if 0 /* TODO: Port to W32 */ defsubr (&Sx_change_window_property); defsubr (&Sx_delete_window_property); @@ -9188,7 +9607,10 @@ This variable has effect only on NT family of systems, not on Windows 9X. */); defsubr (&Sx_open_connection); defsubr (&Sx_close_connection); defsubr (&Sx_display_list); - defsubr (&Sx_frame_geometry); + defsubr (&Sw32_frame_geometry); + defsubr (&Sw32_frame_edges); + defsubr (&Sw32_mouse_absolute_pixel_position); + defsubr (&Sw32_set_mouse_absolute_pixel_position); defsubr (&Sx_synchronize); /* W32 specific functions */ @@ -9204,10 +9626,12 @@ This variable has effect only on NT family of systems, not on Windows 9X. */); defsubr (&Sw32_reconstruct_hot_key); defsubr (&Sw32_toggle_lock_key); defsubr (&Sw32_window_exists_p); - defsubr (&Sw32_frame_rect); - defsubr (&Sw32_frame_menu_bar_size); defsubr (&Sw32_battery_status); defsubr (&Sw32__menu_bar_in_use); +#if defined WINDOWSNT && !defined HAVE_DBUS + defsubr (&Sw32_notification_notify); + defsubr (&Sw32_notification_close); +#endif #ifdef WINDOWSNT defsubr (&Sfile_system_info); @@ -9246,6 +9670,12 @@ static PVOID except_addr; /* Stack overflow recovery. */ +/* MinGW headers don't declare this (should be in malloc.h). Also, + the function is not present pre-W2K, so make the call through + a function pointer. */ +typedef int (__cdecl *_resetstkoflw_proc) (void); +static _resetstkoflw_proc resetstkoflw; + /* Re-establish the guard page at stack limit. This is needed because when a stack overflow is detected, Windows removes the guard bit from the guard page, so if we don't re-establish that protection, @@ -9253,12 +9683,14 @@ static PVOID except_addr; void w32_reset_stack_overflow_guard (void) { - /* MinGW headers don't declare this (should be in malloc.h). */ - _CRTIMP int __cdecl _resetstkoflw (void); - + if (resetstkoflw == NULL) + resetstkoflw = + (_resetstkoflw_proc)GetProcAddress (GetModuleHandle ("msvcrt.dll"), + "_resetstkoflw"); /* We ignore the return value. If _resetstkoflw fails, the next stack overflow will crash the program. */ - (void)_resetstkoflw (); + if (resetstkoflw != NULL) + (void)resetstkoflw (); } static void @@ -9470,6 +9902,8 @@ globals_of_w32fns (void) GetProcAddress (user32_lib, "MonitorFromWindow"); enum_display_monitors_fn = (EnumDisplayMonitors_Proc) GetProcAddress (user32_lib, "EnumDisplayMonitors"); + get_title_bar_info_fn = (GetTitleBarInfo_Proc) + GetProcAddress (user32_lib, "GetTitleBarInfo"); { HMODULE imm32_lib = GetModuleHandle ("imm32.dll"); @@ -9487,6 +9921,7 @@ globals_of_w32fns (void) except_addr = 0; #ifndef CYGWIN prev_exception_handler = SetUnhandledExceptionFilter (my_exception_handler); + resetstkoflw = NULL; #endif DEFVAR_INT ("w32-ansi-code-page", @@ -9505,10 +9940,6 @@ globals_of_w32fns (void) InitCommonControls (); syms_of_w32uniscribe (); - - /* Needed for recovery from C stack overflows in batch mode. */ - if (noninteractive) - dwMainThreadId = GetCurrentThreadId (); } #ifdef NTGUI_UNICODE