X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/fd4fc004ab4d4fd5a75f1663e7067e58cf389912..0a2aedfe6d650e825a50f25f972bac20d669f5cb:/src/w32fns.c diff --git a/src/w32fns.c b/src/w32fns.c index 10c8af7107..20e09d8a46 100644 --- a/src/w32fns.c +++ b/src/w32fns.c @@ -6,8 +6,8 @@ This file is part of GNU Emacs. GNU Emacs is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. +the Free Software Foundation, either version 3 of the License, or (at +your option) any later version. GNU Emacs is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -74,15 +74,10 @@ along with GNU Emacs. If not, see . */ #define FOF_NO_CONNECTED_ELEMENTS 0x2000 #endif -void syms_of_w32fns (void); -void globals_of_w32fns (void); - -extern void free_frame_menubar (struct frame *); extern int w32_console_toggle_lock_key (int, Lisp_Object); extern void w32_menu_display_help (HWND, HMENU, UINT, UINT); extern void w32_free_menu_strings (HWND); extern const char *map_w32_filename (const char *, const char **); -extern char * w32_strerror (int error_no); #ifndef IDC_HAND #define IDC_HAND MAKEINTRESOURCE(32649) @@ -191,11 +186,7 @@ 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 -#else /* !NTGUI_UNICODE */ extern AppendMenuW_Proc unicode_append_menu; -#endif /* NTGUI_UNICODE */ /* Flag to selectively ignore WM_IME_CHAR messages. */ static int ignore_ime_char = 0; @@ -222,7 +213,6 @@ static HWND w32_visible_system_caret_hwnd; static int w32_unicode_gui; /* From w32menu.c */ -extern HMENU current_popup_menu; int menubar_in_use = 0; /* From w32uniscribe.c */ @@ -365,10 +355,7 @@ void x_set_cursor_type (struct frame *, Lisp_Object, Lisp_Object); void x_set_icon_type (struct frame *, Lisp_Object, Lisp_Object); void x_set_icon_name (struct frame *, Lisp_Object, Lisp_Object); void x_explicitly_set_name (struct frame *, Lisp_Object, Lisp_Object); -void x_set_menu_bar_lines (struct frame *, Lisp_Object, Lisp_Object); void x_set_title (struct frame *, Lisp_Object, Lisp_Object); -void x_set_tool_bar_lines (struct frame *, Lisp_Object, Lisp_Object); -void x_set_internal_border_width (struct frame *f, Lisp_Object, Lisp_Object); /* Store the screen positions of frame F into XPTR and YPTR. @@ -491,7 +478,7 @@ if the entry is new. */) /* The default colors for the w32 color map */ typedef struct colormap_t { - char *name; + const char *name; COLORREF colorref; } colormap_t; @@ -829,7 +816,7 @@ add_system_logical_colors_to_map (Lisp_Object *system_colors) NULL, NULL, (LPBYTE)color_buffer, &color_size) == ERROR_SUCCESS) { - int r, g, b; + unsigned r, g, b; if (sscanf (color_buffer, " %u %u %u", &r, &g, &b) == 3) *system_colors = Fcons (Fcons (build_string (full_name_buffer), make_number (RGB (r, g, b))), @@ -1244,7 +1231,7 @@ w32_defined_color (struct frame *f, const char *color, XColor *color_def, If F is not a color screen, return DEF (default) regardless of what ARG says. */ -int +static int x_decode_color (struct frame *f, Lisp_Object arg, int def) { XColor cdef; @@ -1527,7 +1514,7 @@ x_set_cursor_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval) Note that this does not fully take effect if done before F has a window. */ -void +static void x_set_border_pixel (struct frame *f, int pix) { @@ -1638,7 +1625,7 @@ x_set_icon_name (struct frame *f, Lisp_Object arg, Lisp_Object oldval) #endif } -void +static void x_clear_under_internal_border (struct frame *f) { int border = FRAME_INTERNAL_BORDER_WIDTH (f); @@ -1671,7 +1658,7 @@ x_set_internal_border_width (struct frame *f, Lisp_Object arg, Lisp_Object oldva if (border != FRAME_INTERNAL_BORDER_WIDTH (f)) { - FRAME_INTERNAL_BORDER_WIDTH (f) = border; + f->internal_border_width = border; if (FRAME_X_WINDOW (f) != 0) { @@ -1864,7 +1851,7 @@ w32_set_title_bar_text (struct frame *f, Lisp_Object name) suggesting a new name, which lisp code should override; if F->explicit_name is set, ignore the new name; otherwise, set it. */ -void +static void x_set_name (struct frame *f, Lisp_Object name, bool explicit) { /* Make sure that requests from lisp code override requests from @@ -1969,6 +1956,8 @@ x_set_scroll_bar_default_height (struct frame *f) /* Subroutines for creating a frame. */ +Cursor w32_load_cursor (LPCTSTR); + Cursor w32_load_cursor (LPCTSTR name) { @@ -2112,6 +2101,7 @@ my_post_msg (W32Msg * wmsg, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) post_msg (wmsg); } +#ifdef WINDOWSNT /* The Windows keyboard hook callback. */ static LRESULT CALLBACK funhook (int code, WPARAM w, LPARAM l) @@ -2188,8 +2178,8 @@ funhook (int code, WPARAM w, LPARAM l) can prevent this by setting the w32-pass-[lr]window-to-system variable to NIL. */ - if (hs->vkCode == VK_LWIN && !NILP (Vw32_pass_lwindow_to_system) || - hs->vkCode == VK_RWIN && !NILP (Vw32_pass_rwindow_to_system)) + if ((hs->vkCode == VK_LWIN && !NILP (Vw32_pass_lwindow_to_system)) || + (hs->vkCode == VK_RWIN && !NILP (Vw32_pass_rwindow_to_system))) { /* Not prevented - Simulate the keypress to the system. */ memset (inputs, 0, sizeof (inputs)); @@ -2235,8 +2225,8 @@ funhook (int code, WPARAM w, LPARAM l) /* Some other key was pressed while a captured Win key is down. This is either an Emacs registered hotkey combination, or a system hotkey. */ - if (kbdhook.lwindown && kbdhook.lwin_hooked[hs->vkCode] || - kbdhook.rwindown && kbdhook.rwin_hooked[hs->vkCode]) + if ((kbdhook.lwindown && kbdhook.lwin_hooked[hs->vkCode]) || + (kbdhook.rwindown && kbdhook.rwin_hooked[hs->vkCode])) { /* Hooked Win-x combination, do not pass the keypress to Windows. */ kbdhook.suppress_lone = 1; @@ -2370,10 +2360,11 @@ remove_w32_kbdhook (void) kbdhook.hook = NULL; } } +#endif /* WINDOWSNT */ /* Mark a specific key combination as hooked, preventing it to be handled by the system. */ -void +static void hook_w32_key (int hook, int modifier, int vkey) { char *tbl = NULL; @@ -2411,6 +2402,7 @@ hook_w32_key (int hook, int modifier, int vkey) } } +#ifdef WINDOWSNT /* Check the current Win key pressed state. */ int check_w32_winkey_state (int vkey) @@ -2438,12 +2430,13 @@ check_w32_winkey_state (int vkey) } return 0; } +#endif /* WINDOWSNT */ /* Reset the keyboard hook state. Locking the workstation with Win-L leaves the Win key(s) "down" from the hook's point of view - the keyup event is never seen. Thus, this function must be called when the system is locked. */ -void +static void reset_w32_kbdhook_state (void) { kbdhook.lwindown = 0; @@ -2628,8 +2621,10 @@ modifier_set (int vkey) else return (GetKeyState (vkey) & 0x1); } +#ifdef WINDOWSNT if (w32_kbdhook_active && (vkey == VK_LWIN || vkey == VK_RWIN)) return check_w32_winkey_state (vkey); +#endif if (!modifiers_recorded) return (GetKeyState (vkey) & 0x8000); @@ -2650,6 +2645,7 @@ modifier_set (int vkey) /* Convert between the modifier bits W32 uses and the modifier bits Emacs uses. */ +unsigned int w32_key_to_modifier (int); unsigned int w32_key_to_modifier (int key) @@ -2748,6 +2744,8 @@ w32_get_key_modifiers (unsigned int wparam, unsigned int lparam) return mods; } +unsigned int map_keypad_keys (unsigned int, unsigned int); + unsigned int map_keypad_keys (unsigned int virt_key, unsigned int extended) { @@ -3120,6 +3118,8 @@ cancel_all_deferred_msgs (void) PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0); } +DWORD WINAPI w32_msg_worker (void *); + DWORD WINAPI w32_msg_worker (void *arg) { @@ -3338,7 +3338,7 @@ get_wm_chars (HWND aWnd, int *buf, int buflen, int ignore_ctrl, int ctrl, Be ready to treat the case when this delivers WM_(SYS)DEADCHAR. */ static int after_deadkey = -1; -int +static int deliver_wm_chars (int do_translate, HWND hwnd, UINT msg, UINT wParam, UINT lParam, int legacy_alt_meta) { @@ -3382,7 +3382,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_ExtraMods = 1, hairy = 0; - char *type_CtrlAlt = NULL; + const char *type_CtrlAlt = NULL; /* XXXX In fact, there may be another case when we need to do the same: What happens if the string defined in the LIGATURES has length @@ -3538,9 +3538,45 @@ deliver_wm_chars (int do_translate, HWND hwnd, UINT msg, UINT wParam, SHORT r = VkKeyScanW (*b), bitmap = 0x1FF; FPRINTF_WM_CHARS((stderr, "VkKeyScanW %#06x %#04x\n", (int)r, - wParam)); + wParam)); if ((r & 0xFF) == wParam) bitmap = r>>8; /* *b is reachable via simple interface */ + else + { + /* VkKeyScanW() (essentially) returns the FIRST key with + the specified character; so here the pressed key is the + SECONDARY key producing the character. + + Essentially, we have no information about the "role" of + modifiers on this key: which contribute into the + produced character (so "are consumed"), and which are + "extra" (must attache to bindable events). + + The default above would consume ALL modifiers, so the + character is reported "as is". However, on many layouts + the ordering of the keys (in the layout table) is not + thought out well, so the "secondary" keys are often those + which the users would prefer to use with Alt-CHAR. + (Moreover - with e.g. Czech-QWERTY - the ASCII + punctuation is accessible from two equally [nu]preferable + AltGr-keys.) + + SO: Heuristic: if the reported char is ASCII, AND Meta + modifier is a candidate, behave as if Meta is present + (fallback to the legacy branch; bug#23251). + + (This would break layouts + - delivering ASCII characters + - on SECONDARY keys + - with not Shift/AltGr-like modifier combinations. + All 3 conditions together must be pretty exotic + cases - and a workaround exists: use "primary" keys!) */ + if (*b < 0x80 + && (wmsg.dwModifiers + & (alt_modifier | meta_modifier + | super_modifier | hyper_modifier))) + return 0; + } if (*type_CtrlAlt == 'a') /* Simple Alt seen */ { if ((bitmap & ~1) == 0) /* 1: KBDSHIFT */ @@ -4734,12 +4770,16 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) my_post_msg (&wmsg, hwnd, msg, wParam, lParam); goto dflt; +#ifdef WINDOWSNT case WM_CREATE: setup_w32_kbdhook (); goto dflt; +#endif case WM_DESTROY: +#ifdef WINDOWSNT remove_w32_kbdhook (); +#endif CoUninitialize (); return 0; @@ -4753,6 +4793,11 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) my_post_msg (&wmsg, hwnd, msg, wParam, lParam); return 0; + case WM_ENDSESSION: + my_post_msg (&wmsg, hwnd, msg, wParam, lParam); + /* If we return, the process will be terminated immediately. */ + sleep (1000); + 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. */ @@ -5220,7 +5265,7 @@ x_default_font_parameter (struct frame *f, Lisp_Object parms) if (!STRINGP (font)) { int i; - static char *names[] + static const char *names[] = { "Courier New-10", "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1", "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1", @@ -5240,7 +5285,8 @@ x_default_font_parameter (struct frame *f, Lisp_Object parms) { /* Remember the explicit font parameter, so we can re-apply it after we've applied the `default' face settings. */ - x_set_frame_parameters (f, Fcons (Fcons (Qfont_param, font_param), Qnil)); + x_set_frame_parameters (f, Fcons (Fcons (Qfont_parameter, font_param), + Qnil)); } x_default_parameter (f, parms, Qfont, font, "font", "Font", RES_TYPE_STRING); } @@ -5562,8 +5608,10 @@ This function is an internal primitive--use `make-frame' instead. */) else if (! NILP (visibility)) x_make_frame_visible (f); else - /* Must have been Qnil. */ - ; + { + /* Must have been Qnil. */ + ; + } } /* Initialize `default-minibuffer-frame' in case this is the first @@ -5603,7 +5651,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; @@ -5745,7 +5793,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 @@ -6106,11 +6154,13 @@ SOUND is nil to use the normal beep. */) return sound; } +#if 0 /* unused */ int x_screen_planes (register struct frame *f) { return FRAME_DISPLAY_INFO (f)->n_planes; } +#endif /* Return the display structure for the display named NAME. Open a new connection if necessary. */ @@ -6147,7 +6197,7 @@ 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) { char *xrm_option; @@ -6416,8 +6466,6 @@ no value of TYPE (always string in the MS Windows case). */) Tool tips ***********************************************************************/ -static Lisp_Object x_create_tip_frame (struct w32_display_info *, - Lisp_Object, Lisp_Object); static void compute_tip_xy (struct frame *, Lisp_Object, Lisp_Object, Lisp_Object, int, int, int *, int *); @@ -6452,8 +6500,7 @@ unwind_create_tip_frame (Lisp_Object frame) /* Create a frame for a tooltip on the display described by DPYINFO. - PARMS is a list of frame parameters. TEXT is the string to - display in the tip frame. Value is the frame. + PARMS is a list of frame parameters. Value is the frame. Note that functions called here, esp. x_default_parameter can signal errors, for instance when a specified color name is @@ -6461,8 +6508,7 @@ unwind_create_tip_frame (Lisp_Object frame) when this happens. */ static Lisp_Object -x_create_tip_frame (struct w32_display_info *dpyinfo, - Lisp_Object parms, Lisp_Object text) +x_create_tip_frame (struct w32_display_info *dpyinfo, Lisp_Object parms) { struct frame *f; Lisp_Object frame; @@ -6471,8 +6517,6 @@ x_create_tip_frame (struct w32_display_info *dpyinfo, ptrdiff_t count = SPECPDL_INDEX (); 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 @@ -6496,23 +6540,9 @@ x_create_tip_frame (struct w32_display_info *dpyinfo, frame = Qnil; /* Make a frame without minibuffer nor mode-line. */ f = make_frame (false); - f->wants_modeline = 0; + f->wants_modeline = false; XSETFRAME (frame, f); - AUTO_STRING (tip, " *tip*"); - buffer = Fget_buffer_create (tip); - /* Use set_window_buffer instead of Fset_window_buffer (see - discussion of bug#11984, bug#12025, bug#12026). */ - set_window_buffer (FRAME_ROOT_WINDOW (f), buffer, false, false); - old_buffer = current_buffer; - set_buffer_internal_1 (XBUFFER (buffer)); - bset_truncate_lines (current_buffer, Qnil); - specbind (Qinhibit_read_only, Qt); - specbind (Qinhibit_modification_hooks, Qt); - Ferase_buffer (); - Finsert (1, &text); - set_buffer_internal_1 (old_buffer); - record_unwind_protect (unwind_create_tip_frame, frame); /* By setting the output method, we're essentially saying that @@ -6546,7 +6576,7 @@ x_create_tip_frame (struct w32_display_info *dpyinfo, { fset_name (f, name); f->explicit_name = true; - /* use the frame's title when getting resources for this frame. */ + /* Use the frame's title when getting resources for this frame. */ specbind (Qx_resource_name, name); } @@ -6576,14 +6606,10 @@ x_create_tip_frame (struct w32_display_info *dpyinfo, parms = Fcons (Fcons (Qinternal_border_width, value), parms); } + x_default_parameter (f, parms, Qinternal_border_width, make_number (1), "internalBorderWidth", "internalBorderWidth", RES_TYPE_NUMBER); - x_default_parameter (f, parms, Qright_divider_width, make_number (0), - NULL, NULL, RES_TYPE_NUMBER); - x_default_parameter (f, parms, Qbottom_divider_width, make_number (0), - NULL, NULL, RES_TYPE_NUMBER); - /* Also do the stuff which must be set before the window exists. */ x_default_parameter (f, parms, Qforeground_color, build_string ("black"), "foreground", "Foreground", RES_TYPE_STRING); @@ -6610,6 +6636,9 @@ x_create_tip_frame (struct w32_display_info *dpyinfo, f->fringe_cols = 0; f->left_fringe_width = 0; f->right_fringe_width = 0; + /* No dividers on tip frame. */ + f->right_divider_width = 0; + f->bottom_divider_width = 0; block_input (); my_create_tip_window (f); @@ -6636,7 +6665,6 @@ x_create_tip_frame (struct w32_display_info *dpyinfo, SET_FRAME_LINES (f, 0); adjust_frame_size (f, width * FRAME_COLUMN_WIDTH (f), height * FRAME_LINE_HEIGHT (f), 0, true, Qtip_frame); - /* Add `tooltip' frame parameter's default value. */ if (NILP (Fframe_parameter (frame, Qtooltip))) Fmodify_frame_parameters (frame, Fcons (Fcons (Qtooltip, Qt), Qnil)); @@ -6654,8 +6682,6 @@ x_create_tip_frame (struct w32_display_info *dpyinfo, Lisp_Object fg = Fframe_parameter (frame, Qforeground_color); Lisp_Object colors = Qnil; - /* Set tip_frame here, so that */ - tip_frame = frame; call2 (Qface_set_after_frame_default, frame, Qnil); if (!EQ (bg, Fframe_parameter (frame, Qbackground_color))) @@ -6787,6 +6813,48 @@ compute_tip_xy (struct frame *f, *root_x = min_x; } +/* Hide tooltip. Delete its frame if DELETE is true. */ +static Lisp_Object +x_hide_tip (bool delete) +{ + if (!NILP (tip_timer)) + { + call1 (Qcancel_timer, tip_timer); + tip_timer = Qnil; + } + + if (NILP (tip_frame) + || (!delete && FRAMEP (tip_frame) + && !FRAME_VISIBLE_P (XFRAME (tip_frame)))) + return Qnil; + else + { + ptrdiff_t count; + Lisp_Object was_open = Qnil; + + count = SPECPDL_INDEX (); + specbind (Qinhibit_redisplay, Qt); + specbind (Qinhibit_quit, Qt); + + if (FRAMEP (tip_frame)) + { + if (delete) + { + delete_frame (tip_frame, Qnil); + tip_frame = Qnil; + } + else + x_make_frame_invisible (XFRAME (tip_frame)); + + was_open = Qt; + } + else + tip_frame = Qnil; + + return unbind_to (count, was_open); + } +} + DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0, doc: /* Show STRING in a \"tooltip\" window on frame FRAME. @@ -6820,20 +6888,22 @@ A tooltip's maximum size is specified by `x-max-tooltip-size'. Text larger than the specified size is clipped. */) (Lisp_Object string, Lisp_Object frame, Lisp_Object parms, Lisp_Object timeout, Lisp_Object dx, Lisp_Object dy) { - struct frame *f; + struct frame *tip_f; struct window *w; int root_x, root_y; struct buffer *old_buffer; struct text_pos pos; - int i, width, height; - bool seen_reversed_p; + int width, height; int old_windows_or_buffers_changed = windows_or_buffers_changed; ptrdiff_t count = SPECPDL_INDEX (); + ptrdiff_t count_1; + Lisp_Object window, size; + AUTO_STRING (tip, " *tip*"); specbind (Qinhibit_redisplay, Qt); CHECK_STRING (string); - f = decode_window_system_frame (frame); + decode_window_system_frame (frame); if (NILP (timeout)) timeout = make_number (5); else @@ -6852,91 +6922,155 @@ Text larger than the specified size is clipped. */) if (NILP (last_show_tip_args)) last_show_tip_args = Fmake_vector (make_number (3), Qnil); - if (!NILP (tip_frame)) + if (FRAMEP (tip_frame) && FRAME_LIVE_P (XFRAME (tip_frame))) { Lisp_Object last_string = AREF (last_show_tip_args, 0); Lisp_Object last_frame = AREF (last_show_tip_args, 1); Lisp_Object last_parms = AREF (last_show_tip_args, 2); - if (EQ (frame, last_frame) - && !NILP (Fequal (last_string, string)) + if (FRAME_VISIBLE_P (XFRAME (tip_frame)) + && EQ (frame, last_frame) + && !NILP (Fequal_including_properties (last_string, string)) && !NILP (Fequal (last_parms, parms))) { - struct frame *f = XFRAME (tip_frame); - /* Only DX and DY have changed. */ + tip_f = XFRAME (tip_frame); if (!NILP (tip_timer)) { Lisp_Object timer = tip_timer; + tip_timer = Qnil; call1 (Qcancel_timer, timer); } block_input (); - compute_tip_xy (f, parms, dx, dy, FRAME_PIXEL_WIDTH (f), - FRAME_PIXEL_HEIGHT (f), &root_x, &root_y); + compute_tip_xy (tip_f, parms, dx, dy, FRAME_PIXEL_WIDTH (tip_f), + FRAME_PIXEL_HEIGHT (tip_f), &root_x, &root_y); /* Put tooltip in topmost group and in position. */ - SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST, + SetWindowPos (FRAME_W32_WINDOW (tip_f), HWND_TOPMOST, root_x, root_y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOOWNERZORDER); /* Ensure tooltip is on top of other topmost windows (eg menus). */ - SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOP, + SetWindowPos (FRAME_W32_WINDOW (tip_f), HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOOWNERZORDER); + /* Let redisplay know that we have made the frame visible already. */ + SET_FRAME_VISIBLE (tip_f, 1); + ShowWindow (FRAME_W32_WINDOW (tip_f), SW_SHOWNOACTIVATE); unblock_input (); + goto start_timer; } - } + else if (tooltip_reuse_hidden_frame && EQ (frame, last_frame)) + { + bool delete = false; + Lisp_Object tail, elt, parm, last; + + /* Check if every parameter in PARMS has the same value in + last_parms. This may destruct last_parms which, however, + will be recreated below. */ + for (tail = parms; CONSP (tail); tail = XCDR (tail)) + { + elt = XCAR (tail); + parm = Fcar (elt); + /* The left, top, right and bottom parameters are handled + by compute_tip_xy so they can be ignored here. */ + if (!EQ (parm, Qleft) && !EQ (parm, Qtop) + && !EQ (parm, Qright) && !EQ (parm, Qbottom)) + { + last = Fassq (parm, last_parms); + if (NILP (Fequal (Fcdr (elt), Fcdr (last)))) + { + /* We lost, delete the old tooltip. */ + delete = true; + break; + } + else + last_parms = call2 (Qassq_delete_all, parm, last_parms); + } + else + last_parms = call2 (Qassq_delete_all, parm, last_parms); + } + + /* Now check if there's a parameter left in last_parms with a + non-nil value. */ + for (tail = last_parms; CONSP (tail); tail = XCDR (tail)) + { + elt = XCAR (tail); + parm = Fcar (elt); + if (!EQ (parm, Qleft) && !EQ (parm, Qtop) && !EQ (parm, Qright) + && !EQ (parm, Qbottom) && !NILP (Fcdr (elt))) + { + /* We lost, delete the old tooltip. */ + delete = true; + break; + } + } - /* Hide a previous tip, if any. */ - Fx_hide_tip (); + x_hide_tip (delete); + } + else + x_hide_tip (true); + } + else + x_hide_tip (true); ASET (last_show_tip_args, 0, string); ASET (last_show_tip_args, 1, frame); ASET (last_show_tip_args, 2, parms); - /* Add default values to frame parameters. */ - if (NILP (Fassq (Qname, parms))) - parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms); - if (NILP (Fassq (Qinternal_border_width, parms))) - parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms); - if (NILP (Fassq (Qright_divider_width, parms))) - parms = Fcons (Fcons (Qright_divider_width, make_number (0)), parms); - if (NILP (Fassq (Qbottom_divider_width, parms))) - parms = Fcons (Fcons (Qbottom_divider_width, make_number (0)), parms); - if (NILP (Fassq (Qborder_width, parms))) - parms = Fcons (Fcons (Qborder_width, make_number (1)), parms); - if (NILP (Fassq (Qborder_color, parms))) - parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms); - if (NILP (Fassq (Qbackground_color, parms))) - parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")), - parms); - /* Block input until the tip has been fully drawn, to avoid crashes when drawing tips in menus. */ block_input (); - /* Create a frame for the tooltip, and record it in the global - variable tip_frame. */ - frame = x_create_tip_frame (FRAME_DISPLAY_INFO (f), parms, string); - f = XFRAME (frame); + if (!FRAMEP (tip_frame) || !FRAME_LIVE_P (XFRAME (tip_frame))) + { + /* Add default values to frame parameters. */ + if (NILP (Fassq (Qname, parms))) + parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms); + if (NILP (Fassq (Qinternal_border_width, parms))) + parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms); + if (NILP (Fassq (Qborder_width, parms))) + parms = Fcons (Fcons (Qborder_width, make_number (1)), parms); + if (NILP (Fassq (Qborder_color, parms))) + parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms); + if (NILP (Fassq (Qbackground_color, parms))) + parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")), + parms); - /* Set up the frame's root window. */ - w = XWINDOW (FRAME_ROOT_WINDOW (f)); + /* Create a frame for the tooltip, and record it in the global + variable tip_frame. */ + struct frame *f; /* The value is unused. */ + if (NILP (tip_frame = x_create_tip_frame (FRAME_DISPLAY_INFO (f), parms))) + { + /* Creating the tip frame failed. */ + unblock_input (); + return unbind_to (count, Qnil); + } + } + + tip_f = XFRAME (tip_frame); + window = FRAME_ROOT_WINDOW (tip_f); + set_window_buffer (window, Fget_buffer_create (tip), false, false); + w = XWINDOW (window); + w->pseudo_window_p = true; + + /* Set up the frame's root window. Note: The following code does not + try to size the window or its frame correctly. Its only purpose is + to make the subsequent text size calculations work. The right + sizes should get installed when the toolkit gets back to us. */ w->left_col = 0; w->top_line = 0; w->pixel_left = 0; w->pixel_top = 0; if (CONSP (Vx_max_tooltip_size) - && INTEGERP (XCAR (Vx_max_tooltip_size)) - && XINT (XCAR (Vx_max_tooltip_size)) > 0 - && INTEGERP (XCDR (Vx_max_tooltip_size)) - && XINT (XCDR (Vx_max_tooltip_size)) > 0) + && RANGED_INTEGERP (1, XCAR (Vx_max_tooltip_size), INT_MAX) + && RANGED_INTEGERP (1, XCDR (Vx_max_tooltip_size), INT_MAX)) { w->total_cols = XFASTINT (XCAR (Vx_max_tooltip_size)); w->total_lines = XFASTINT (XCDR (Vx_max_tooltip_size)); @@ -6947,164 +7081,71 @@ Text larger than the specified size is clipped. */) w->total_lines = 40; } - w->pixel_width = w->total_cols * FRAME_COLUMN_WIDTH (f); - w->pixel_height = w->total_lines * FRAME_LINE_HEIGHT (f); + w->pixel_width = w->total_cols * FRAME_COLUMN_WIDTH (tip_f); + w->pixel_height = w->total_lines * FRAME_LINE_HEIGHT (tip_f); + FRAME_TOTAL_COLS (tip_f) = WINDOW_TOTAL_COLS (w); + adjust_frame_glyphs (tip_f); - FRAME_TOTAL_COLS (f) = WINDOW_TOTAL_COLS (w); - adjust_frame_glyphs (f); - w->pseudo_window_p = true; - - /* Display the tooltip text in a temporary buffer. */ + /* Insert STRING into the root window's buffer and fit the frame to + the buffer. */ + count_1 = SPECPDL_INDEX (); old_buffer = current_buffer; - set_buffer_internal_1 (XBUFFER (XWINDOW (FRAME_ROOT_WINDOW (f))->contents)); + set_buffer_internal_1 (XBUFFER (w->contents)); bset_truncate_lines (current_buffer, Qnil); + specbind (Qinhibit_read_only, Qt); + specbind (Qinhibit_modification_hooks, Qt); + specbind (Qinhibit_point_motion_hooks, Qt); + Ferase_buffer (); + Finsert (1, &string); clear_glyph_matrix (w->desired_matrix); clear_glyph_matrix (w->current_matrix); SET_TEXT_POS (pos, BEGV, BEGV_BYTE); - try_window (FRAME_ROOT_WINDOW (f), pos, TRY_WINDOW_IGNORE_FONTS_CHANGE); - - /* Compute width and height of the tooltip. */ - width = height = 0; - seen_reversed_p = false; - for (i = 0; i < w->desired_matrix->nrows; ++i) - { - struct glyph_row *row = &w->desired_matrix->rows[i]; - struct glyph *last; - int row_width; - - /* Stop at the first empty row at the end. */ - if (!row->enabled_p || !MATRIX_ROW_DISPLAYS_TEXT_P (row)) - break; - - /* Let the row go over the full width of the frame. */ - row->full_width_p = true; - - row_width = row->pixel_width; - if (row->used[TEXT_AREA]) - { - if (!row->reversed_p) - { - /* There's a glyph at the end of rows that is used to - place the cursor there. Don't include the width of - this glyph. */ - last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1]; - if (NILP (last->object)) - row_width -= last->pixel_width; - } - else - { - /* There could be a stretch glyph at the beginning of R2L - rows that is produced by extend_face_to_end_of_line. - Don't count that glyph. */ - struct glyph *g = row->glyphs[TEXT_AREA]; - - if (g->type == STRETCH_GLYPH && NILP (g->object)) - { - row_width -= g->pixel_width; - seen_reversed_p = true; - } - } - } - - height += row->height; - width = max (width, row_width); - } - - /* If we've seen partial-length R2L rows, we need to re-adjust the - tool-tip frame width and redisplay it again, to avoid over-wide - tips due to the stretch glyph that extends R2L lines to full - width of the frame. */ - if (seen_reversed_p) - { - /* PXW: Why do we do the pixel-to-cols conversion only if - seen_reversed_p holds? Don't we have to set other fields of - the window/frame structure? - - w->total_cols and FRAME_TOTAL_COLS want the width in columns, - not in pixels. */ - w->pixel_width = width; - width /= WINDOW_FRAME_COLUMN_WIDTH (w); - w->total_cols = width; - FRAME_TOTAL_COLS (f) = width; - SET_FRAME_WIDTH (f, width); - adjust_frame_glyphs (f); - w->pseudo_window_p = 1; - clear_glyph_matrix (w->desired_matrix); - clear_glyph_matrix (w->current_matrix); - try_window (FRAME_ROOT_WINDOW (f), pos, TRY_WINDOW_IGNORE_FONTS_CHANGE); - width = height = 0; - /* Recompute width and height of the tooltip. */ - for (i = 0; i < w->desired_matrix->nrows; ++i) - { - struct glyph_row *row = &w->desired_matrix->rows[i]; - struct glyph *last; - int row_width; - - if (!row->enabled_p || !MATRIX_ROW_DISPLAYS_TEXT_P (row)) - break; - row->full_width_p = true; - row_width = row->pixel_width; - if (row->used[TEXT_AREA] && !row->reversed_p) - { - last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1]; - if (NILP (last->object)) - row_width -= last->pixel_width; - } - - height += row->height; - width = max (width, row_width); - } - } - - /* Add the frame's internal border to the width and height the w32 - window should have. */ - height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f); - width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f); - - /* Move the tooltip window where the mouse pointer is. Resize and - show it. - - PXW: This should use the frame's pixel coordinates. */ - compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y); - + try_window (window, pos, TRY_WINDOW_IGNORE_FONTS_CHANGE); + /* Calculate size of tooltip window. */ + size = Fwindow_text_pixel_size (window, Qnil, Qnil, Qnil, + make_number (w->pixel_height), Qnil); + /* Add the frame's internal border to calculated size. */ + width = XINT (Fcar (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f); + height = XINT (Fcdr (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f); + /* Calculate position of tooltip frame. */ + compute_tip_xy (tip_f, parms, dx, dy, width, height, &root_x, &root_y); + + /* Show tooltip frame. */ { - /* Adjust Window size to take border into account. */ RECT rect; + int pad = (NUMBERP (Vw32_tooltip_extra_pixels) + ? max (0, XINT (Vw32_tooltip_extra_pixels)) + : FRAME_COLUMN_WIDTH (tip_f)); + rect.left = rect.top = 0; rect.right = width; rect.bottom = height; - 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 - peculiarity of w32 display: without it, some fonts cause the - last character of the tip to be truncated or wrapped around to - the next line. */ - SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST, + AdjustWindowRect (&rect, tip_f->output_data.w32->dwStyle, + FRAME_EXTERNAL_MENU_BAR (tip_f)); + + /* Position and size tooltip and put it in the topmost group. */ + SetWindowPos (FRAME_W32_WINDOW (tip_f), HWND_TOPMOST, root_x, root_y, - rect.right - rect.left + FRAME_COLUMN_WIDTH (f), + rect.right - rect.left + pad, rect.bottom - rect.top, SWP_NOACTIVATE | SWP_NOOWNERZORDER); /* Ensure tooltip is on top of other topmost windows (eg menus). */ - SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOP, + SetWindowPos (FRAME_W32_WINDOW (tip_f), HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOOWNERZORDER); /* Let redisplay know that we have made the frame visible already. */ - SET_FRAME_VISIBLE (f, 1); + SET_FRAME_VISIBLE (tip_f, 1); - ShowWindow (FRAME_W32_WINDOW (f), SW_SHOWNOACTIVATE); + ShowWindow (FRAME_W32_WINDOW (tip_f), SW_SHOWNOACTIVATE); } - /* Draw into the window. */ w->must_be_updated_p = true; update_single_window (w); - - unblock_input (); - - /* Restore original current buffer. */ set_buffer_internal_1 (old_buffer); + unbind_to (count_1, Qnil); + unblock_input (); windows_or_buffers_changed = old_windows_or_buffers_changed; start_timer: @@ -7121,31 +7162,7 @@ DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0, Value is t if tooltip was open, nil otherwise. */) (void) { - ptrdiff_t count; - Lisp_Object deleted, frame, timer; - - /* Return quickly if nothing to do. */ - if (NILP (tip_timer) && NILP (tip_frame)) - return Qnil; - - frame = tip_frame; - timer = tip_timer; - tip_frame = tip_timer = deleted = Qnil; - - count = SPECPDL_INDEX (); - specbind (Qinhibit_redisplay, Qt); - specbind (Qinhibit_quit, Qt); - - if (!NILP (timer)) - call1 (Qcancel_timer, timer); - - if (FRAMEP (frame)) - { - delete_frame (frame, Qnil); - deleted = Qt; - } - - return unbind_to (count, deleted); + return x_hide_tip (!tooltip_reuse_hidden_frame); } /*********************************************************************** @@ -7272,7 +7289,9 @@ value of DIR as in previous invocations; this is standard Windows behavior. */) { /* Filter index: 1: All Files, 2: Directories only */ static const wchar_t filter_w[] = L"All Files (*.*)\0*.*\0Directories\0*|*\0"; +#ifndef NTGUI_UNICODE static const char filter_a[] = "All Files (*.*)\0*.*\0Directories\0*|*\0"; +#endif Lisp_Object filename = default_filename; struct frame *f = SELECTED_FRAME (); @@ -8018,8 +8037,8 @@ lookup_vk_code (char *key) /* Alphanumerics map to themselves. */ if (key[1] == 0) { - if (key[0] >= 'A' && key[0] <= 'Z' || - key[0] >= '0' && key[0] <= '9') + if ((key[0] >= 'A' && key[0] <= 'Z') + || (key[0] >= '0' && key[0] <= '9')) return key[0]; if (key[0] >= 'a' && key[0] <= 'z') return toupper(key[0]); @@ -8550,7 +8569,7 @@ DEFUN ("w32-set-mouse-absolute-pixel-position", Fw32_set_mouse_absolute_pixel_po 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. */) +\(0, 0) of the selected frame's display. */) (Lisp_Object x, Lisp_Object y) { UINT trail_num = 0; @@ -8653,7 +8672,7 @@ The following %-sequences are provided: else { long m; - float h; + double h; char buffer[16]; snprintf (buffer, 16, "%ld", seconds_left); seconds = build_string (buffer); @@ -8946,7 +8965,7 @@ w32_strerror (int error_no) --ret; buf[ret] = '\0'; if (!ret) - sprintf (buf, "w32 error %u", error_no); + sprintf (buf, "w32 error %d", error_no); return buf; } @@ -8954,6 +8973,8 @@ w32_strerror (int error_no) /* For convenience when debugging. (You cannot call GetLastError directly from GDB: it will crash, because it uses the __stdcall calling convention, not the _cdecl convention assumed by GDB.) */ +DWORD w32_last_error (void); + DWORD w32_last_error (void) { @@ -9604,7 +9625,7 @@ usage: (w32-notification-notify &rest PARAMS) */) EMACS_INT retval; char *icon, *tip, *title, *msg; enum NI_Severity severity; - unsigned timeout; + unsigned timeout = 0; if (nargs == 0) return Qnil; @@ -9616,14 +9637,14 @@ usage: (w32-notification-notify &rest PARAMS) */) if (STRINGP (lres)) icon = SSDATA (ENCODE_FILE (Fexpand_file_name (lres, Qnil))); else - icon = ""; + icon = (char *)""; /* Tip. */ lres = Fplist_get (arg_plist, QCtip); if (STRINGP (lres)) tip = SSDATA (code_convert_string_norecord (lres, Qutf_8, 1)); else - tip = "Emacs notification"; + tip = (char *)"Emacs notification"; /* Severity. */ lres = Fplist_get (arg_plist, QClevel); @@ -9643,14 +9664,14 @@ usage: (w32-notification-notify &rest PARAMS) */) if (STRINGP (lres)) title = SSDATA (code_convert_string_norecord (lres, Qutf_8, 1)); else - title = ""; + title = (char *)""; /* Notification body text. */ lres = Fplist_get (arg_plist, QCbody); if (STRINGP (lres)) msg = SSDATA (code_convert_string_norecord (lres, Qutf_8, 1)); else - msg = ""; + msg = (char *)""; /* Do it! */ retval = add_tray_notification (f, icon, tip, severity, timeout, title, msg); @@ -9739,12 +9760,13 @@ syms_of_w32fns (void) DEFSYM (Qctrl, "ctrl"); DEFSYM (Qcontrol, "control"); DEFSYM (Qshift, "shift"); - DEFSYM (Qfont_param, "font-parameter"); + DEFSYM (Qfont_parameter, "font-parameter"); DEFSYM (Qgeometry, "geometry"); DEFSYM (Qworkarea, "workarea"); DEFSYM (Qmm_size, "mm-size"); DEFSYM (Qframes, "frames"); DEFSYM (Qtip_frame, "tip-frame"); + DEFSYM (Qassq_delete_all, "assq-delete-all"); DEFSYM (Qunicode_sip, "unicode-sip"); #if defined WINDOWSNT && !defined HAVE_DBUS DEFSYM (QCicon, ":icon"); @@ -9757,10 +9779,10 @@ syms_of_w32fns (void) #endif /* Symbols used elsewhere, but only in MS-Windows-specific code. */ - DEFSYM (Qgnutls_dll, "gnutls"); - DEFSYM (Qlibxml2_dll, "libxml2"); + DEFSYM (Qgnutls, "gnutls"); + DEFSYM (Qlibxml2, "libxml2"); DEFSYM (Qserif, "serif"); - DEFSYM (Qzlib_dll, "zlib"); + DEFSYM (Qzlib, "zlib"); Fput (Qundefined_color, Qerror_conditions, listn (CONSTYPE_PURE, 2, Qundefined_color, Qerror)); @@ -10057,6 +10079,18 @@ Default is nil. This variable has effect only on Windows Vista and later. */); w32_disable_new_uniscribe_apis = 0; + DEFVAR_LISP ("w32-tooltip-extra-pixels", + Vw32_tooltip_extra_pixels, + doc: /* Number of pixels added after tooltip text. +On Windows some fonts may cause the last character of a tooltip be +truncated or wrapped around to the next line. Adding some extra space +at the end of the toooltip works around this problem. + +This variable specifies the number of pixels that shall be added. The +default value t means to add the width of one canonical character of the +tip frame. */); + Vw32_tooltip_extra_pixels = Qt; + #if 0 /* TODO: Port to W32 */ defsubr (&Sx_change_window_property); defsubr (&Sx_delete_window_property); @@ -10227,7 +10261,7 @@ typedef USHORT (WINAPI * CaptureStackBackTrace_proc) (ULONG, ULONG, PVOID *, #define BACKTRACE_LIMIT_MAX 62 -int +static int w32_backtrace (void **buffer, int limit) { static CaptureStackBackTrace_proc s_pfn_CaptureStackBackTrace = NULL; @@ -10300,8 +10334,8 @@ emacs_abort (void) but not on Windows 7. addr2line doesn't mind a missing "0x", but will be confused by an extra one. */ if (except_addr) - sprintf (buf, "\r\nException 0x%lx at this address:\r\n%p\r\n", - except_code, except_addr); + sprintf (buf, "\r\nException 0x%x at this address:\r\n%p\r\n", + (unsigned int) except_code, except_addr); if (stderr_fd >= 0) { if (except_addr)