/* 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.
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
#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 <mbstring.h>
#endif /* WINDOWSNT */
#include "w32.h"
#endif
-#include "bitmaps/gray.xbm"
-
#include <commctrl.h>
#include <commdlg.h>
#include <shellapi.h>
+#include <shlwapi.h>
#include <ctype.h>
#include <winspool.h>
#include <objbase.h>
#include <imm.h>
#include <windowsx.h>
-#include "font.h"
-#include "w32font.h"
-
#ifndef FOF_NO_CONNECTED_ELEMENTS
#define FOF_NO_CONNECTED_ELEMENTS 0x2000
#endif
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
(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;
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
tem = XCAR (elt);
- if (lstrcmpi (SDATA (tem), colorname) == 0)
+ if (lstrcmpi (SSDATA (tem), colorname) == 0)
{
ret = Fcdr (elt);
break;
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;
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)
/* 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. */
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))
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)
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. */
/* 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
: 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);
/* 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);
}
/* 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*
#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
environments!) should have different values. Moreover, switching to a
non-Emacs window with the same language environment, and using (dead)keys
there would change the value stored in the kernel, but not this value. */
-static int after_deadkey = 0;
+/* A layout may emit deadkey=0. It looks like this would reset the state
+ of the kernel's finite automaton (equivalent to emiting 0-length string,
+ which is otherwise impossible in the dead-key map of a layout).
+ Be ready to treat the case when this delivers WM_(SYS)DEADCHAR. */
+static int after_deadkey = -1;
int
deliver_wm_chars (int do_translate, HWND hwnd, UINT msg, UINT wParam,
points to a keypress.
(However, the "old style" TranslateMessage() would deliver at most 16 of
them.) Be on a safe side, and prepare to treat many more. */
- int ctrl_cnt, buf[1024], count, is_dead, after_dead = (after_deadkey != -1);
+ int ctrl_cnt, buf[1024], count, is_dead, after_dead = (after_deadkey > 0);
/* Since the keypress processing logic of Windows has a lot of state, it
is important to call TranslateMessage() for every keyup/keydown, AND
{
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:
&& 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
- & (RIGHT_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";
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 */
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.
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,
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)
{
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 ()))
/* 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))
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);
/* 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
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. */
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;
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;
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));
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))
}
}
- GCPRO3 (attributes_list, primary_monitor_attributes, monitor_frames);
-
for (i = 0; i < n_monitors; i++)
{
Lisp_Object geometry, workarea, name, attributes = Qnil;
if (!NILP (primary_monitor_attributes))
attributes_list = Fcons (primary_monitor_attributes, attributes_list);
- UNGCPRO;
-
xfree (monitors);
return attributes_list;
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)
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));
\(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);
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 ();
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. */
/* 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)
{
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. */
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;
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;
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++;
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)
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))
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
tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
intern ("x-hide-tip"));
- UNGCPRO;
return unbind_to (count, Qnil);
}
{
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))
frame = tip_frame;
timer = tip_timer;
- GCPRO2 (frame, timer);
tip_frame = tip_timer = deleted = Qnil;
count = SPECPDL_INDEX ();
deleted = Qt;
}
- UNGCPRO;
return unbind_to (count, deleted);
}
\f
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
/* 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)
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
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)
Qfile_name_history,
default_filename,
Qnil);
-
- UNGCPRO;
}
/* Make "Cancel" equivalent to C-g. */
if (NILP (filename))
Fsignal (Qquit, Qnil);
- RETURN_UNGCPRO (filename);
+ return filename;
}
\f
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. */
/* 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
{
char *doc_a = NULL, *params_a = NULL, *ops_a = NULL;
Lisp_Object absdoc, handler;
BOOL success;
- struct gcpro gcpro1;
#endif
CHECK_STRING (document);
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
}
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)
{
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;
}
}
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,
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");
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))
{
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.
+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.
-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;
+`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.
- if (FRAME_INITIAL_P (f) || !FRAME_W32_P (f))
- return Qnil;
+`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.
- block_input ();
+`external-border-size' is a cons of the horizontal and vertical width of
+ FRAME's external borders as supplied by the window manager.
- 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;
+`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.
- unblock_input ();
-
- return list4 (make_number (width), make_number (height),
- make_number (wrapped_height), make_number (single_height));
-}
+`menu-bar-external', if non-nil, means the menu bar is external (never
+ included in the inner edges of FRAME).
-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.
-
-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).
-
-- `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.
-
-- `title-bar-height' is the height of the title bar of FRAME.
-
-- `menu-bar-external' if t means the menu bar is by default external
- (not included in the inner size 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,
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 */
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;
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 */
+
\f
/***********************************************************************
Initialization
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");
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);
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 */
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);
/* 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,
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
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");
except_addr = 0;
#ifndef CYGWIN
prev_exception_handler = SetUnhandledExceptionFilter (my_exception_handler);
+ resetstkoflw = NULL;
#endif
DEFVAR_INT ("w32-ansi-code-page",
InitCommonControls ();
syms_of_w32uniscribe ();
-
- /* Needed for recovery from C stack overflows in batch mode. */
- if (noninteractive)
- dwMainThreadId = GetCurrentThreadId ();
}
#ifdef NTGUI_UNICODE