X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/5613a6f6d52bca0018c5777aba67a99f51016a35..7e09ef09a479731d01b1ca46e94ddadd73ac98e3:/src/w32fns.c diff --git a/src/w32fns.c b/src/w32fns.c index def9d8acb7..26eeb5f76f 100644 --- a/src/w32fns.c +++ b/src/w32fns.c @@ -1,6 +1,6 @@ /* Graphical user interface functions for the Microsoft Windows API. -Copyright (C) 1989, 1992-2014 Free Software Foundation, Inc. +Copyright (C) 1989, 1992-2015 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -224,7 +224,7 @@ static int w32_unicode_gui; /* From w32menu.c */ extern HMENU current_popup_menu; -static int menubar_in_use = 0; +int menubar_in_use = 0; /* From w32uniscribe.c */ extern void syms_of_w32uniscribe (void); @@ -263,9 +263,9 @@ static unsigned int sound_type = 0xFFFFFFFF; the first display on the list. */ struct w32_display_info * -check_x_display_info (Lisp_Object frame) +check_x_display_info (Lisp_Object object) { - if (NILP (frame)) + if (NILP (object)) { struct frame *sf = XFRAME (selected_frame); @@ -274,14 +274,23 @@ check_x_display_info (Lisp_Object frame) else return &one_w32_display_info; } - else if (STRINGP (frame)) - return x_display_info_for_name (frame); + else if (TERMINALP (object)) + { + struct terminal *t = decode_live_terminal (object); + + if (t->type != output_w32) + error ("Terminal %d is not a W32 display", t->id); + + return t->display_info.w32; + } + else if (STRINGP (object)) + return x_display_info_for_name (object); else { struct frame *f; - CHECK_LIVE_FRAME (frame); - f = XFRAME (frame); + CHECK_LIVE_FRAME (object); + f = XFRAME (object); if (! FRAME_W32_P (f)) error ("Non-W32 frame used"); return FRAME_DISPLAY_INFO (f); @@ -328,8 +337,7 @@ 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. @@ -1361,23 +1369,23 @@ x_set_mouse_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval) { CHECK_NUMBER (Vx_window_horizontal_drag_shape); horizontal_drag_cursor - = XCreateFontCursor (FRAME_X_DISPLAY (f), + = XCreateFontCursor (FRAME_W32_DISPLAY (f), XINT (Vx_window_horizontal_drag_shape)); } else horizontal_drag_cursor - = XCreateFontCursor (FRAME_X_DISPLAY (f), XC_sb_h_double_arrow); + = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_sb_h_double_arrow); if (!NILP (Vx_window_vertical_drag_shape)) { CHECK_NUMBER (Vx_window_vertical_drag_shape); vertical_drag_cursor - = XCreateFontCursor (FRAME_X_DISPLAY (f), + = XCreateFontCursor (FRAME_W32_DISPLAY (f), XINT (Vx_window_vertical_drag_shape)); } else vertical_drag_cursor - = XCreateFontCursor (FRAME_X_DISPLAY (f), XC_sb_v_double_arrow); + = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_sb_v_double_arrow); /* Check and report errors with the above calls. */ x_check_errors (FRAME_W32_DISPLAY (f), "can't set cursor shape: %s"); @@ -1599,8 +1607,53 @@ x_set_icon_name (struct frame *f, Lisp_Object arg, Lisp_Object oldval) unblock_input (); #endif } - +void +x_clear_under_internal_border (struct frame *f) +{ + int border = FRAME_INTERNAL_BORDER_WIDTH (f); + + /* Clear border if it's larger than before. */ + if (border != 0) + { + HDC hdc = get_frame_dc (f); + int width = FRAME_PIXEL_WIDTH (f); + int height = FRAME_PIXEL_HEIGHT (f); + + block_input (); + w32_clear_area (f, hdc, 0, FRAME_TOP_MARGIN_HEIGHT (f), width, border); + w32_clear_area (f, hdc, 0, 0, border, height); + w32_clear_area (f, hdc, width - border, 0, border, height); + w32_clear_area (f, hdc, 0, height - border, width, border); + release_frame_dc (f, hdc); + unblock_input (); + } +} + + +void +x_set_internal_border_width (struct frame *f, Lisp_Object arg, Lisp_Object oldval) +{ + int border; + + CHECK_TYPE_RANGED_INTEGER (int, arg); + border = max (XINT (arg), 0); + + if (border != FRAME_INTERNAL_BORDER_WIDTH (f)) + { + FRAME_INTERNAL_BORDER_WIDTH (f) = border; + + if (FRAME_X_WINDOW (f) != 0) + { + adjust_frame_size (f, -1, -1, 3, 0, Qinternal_border_width); + + if (FRAME_VISIBLE_P (f)) + x_clear_under_internal_border (f); + } + } +} + + void x_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) { @@ -1621,7 +1674,10 @@ x_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) FRAME_MENU_BAR_LINES (f) = 0; FRAME_MENU_BAR_HEIGHT (f) = 0; if (nlines) - FRAME_EXTERNAL_MENU_BAR (f) = 1; + { + FRAME_EXTERNAL_MENU_BAR (f) = 1; + windows_or_buffers_changed = 23; + } else { if (FRAME_EXTERNAL_MENU_BAR (f) == 1) @@ -1630,11 +1686,16 @@ x_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) /* Adjust the frame size so that the client (text) dimensions remain the same. This depends on FRAME_EXTERNAL_MENU_BAR being - set correctly. */ - x_set_window_size (f, 0, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f), 1); - do_pending_window_change (0); + set correctly. Note that we resize twice: The first time upon + a request from the window manager who wants to keep the height + of the outer rectangle (including decorations) unchanged, and a + second time because we want to keep the height of the inner + rectangle (without the decorations unchanged). */ + adjust_frame_size (f, -1, -1, 2, 1, Qmenu_bar_lines); + + /* Not sure whether this is needed. */ + x_clear_under_internal_border (f); } - adjust_frame_glyphs (f); } @@ -1648,8 +1709,7 @@ x_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) void x_set_tool_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) { - int delta, nlines, root_height; - int unit = FRAME_LINE_HEIGHT (f); + int nlines; /* Treat tool bars like menu bars. */ if (FRAME_MINIBUF_ONLY_P (f)) @@ -1661,66 +1721,51 @@ x_set_tool_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) else nlines = 0; - /* Make sure we redisplay all windows in this frame. */ - windows_or_buffers_changed = 23; + x_change_tool_bar_height (f, nlines * FRAME_LINE_HEIGHT (f)); +} - /* DELTA is in pixels now. */ - delta = (nlines - FRAME_TOOL_BAR_LINES (f)) * unit; - /* Don't resize the tool-bar to more than we have room for. Note: The - calculations below and the subsequent call to resize_frame_windows - are inherently flawed because they can make the toolbar higher than - the containing frame. */ - if (delta > 0) - { - root_height = WINDOW_PIXEL_HEIGHT (XWINDOW (FRAME_ROOT_WINDOW (f))); - if (root_height - delta < unit) - { - delta = root_height - unit; - /* When creating a new frame and toolbar mode is enabled, we - need at least one toolbar line. */ - nlines = max (FRAME_TOOL_BAR_LINES (f) + delta / unit, 1); - } - } +/* Set the pixel height of the tool bar of frame F to HEIGHT. */ +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); - FRAME_TOOL_BAR_LINES (f) = nlines; - FRAME_TOOL_BAR_HEIGHT (f) = nlines * FRAME_LINE_HEIGHT (f); - ++windows_or_buffers_changed; - resize_frame_windows (f, FRAME_TEXT_HEIGHT (f), 0, 1); - adjust_frame_glyphs (f); + /* Make sure we redisplay all windows in this frame. */ + windows_or_buffers_changed = 23; + + /* Recalculate tool bar and frame text sizes. */ + FRAME_TOOL_BAR_HEIGHT (f) = height; + FRAME_TOOL_BAR_LINES (f) = lines; + /* Store `tool-bar-lines' and `height' frame parameters. */ + store_frame_param (f, Qtool_bar_lines, make_number (lines)); + store_frame_param (f, Qheight, make_number (FRAME_LINES (f))); - /* We also have to make sure that the internal border at the top of - the frame, below the menu bar or tool bar, is redrawn when the - tool bar disappears. This is so because the internal border is - below the tool bar if one is displayed, but is below the menu bar - if there isn't a tool bar. The tool bar draws into the area - below the menu bar. */ if (FRAME_W32_WINDOW (f) && FRAME_TOOL_BAR_HEIGHT (f) == 0) { clear_frame (f); clear_current_matrices (f); } - /* If the tool bar gets smaller, the internal border below it - has to be cleared. It was formerly part of the display - of the larger tool bar, and updating windows won't clear it. */ - if (FRAME_INTERNAL_BORDER_WIDTH (f) != 0 && FRAME_VISIBLE_P (f)) - { - int height = FRAME_INTERNAL_BORDER_WIDTH (f); - int width = FRAME_PIXEL_WIDTH (f); - int y = nlines * unit; - HDC hdc = get_frame_dc (f); + if ((height < old_height) && WINDOWP (f->tool_bar_window)) + clear_glyph_matrix (XWINDOW (f->tool_bar_window)->current_matrix); - block_input (); - w32_clear_area (f, hdc, 0, y, width, height); - release_frame_dc (f, hdc); - unblock_input (); - } + /* Recalculate toolbar height. */ + f->n_tool_bar_rows = 0; - if (delta < 0 && WINDOWP (f->tool_bar_window)) - clear_glyph_matrix (XWINDOW (f->tool_bar_window)->current_matrix); + adjust_frame_size (f, -1, -1, (old_height == 0 || height == 0) ? 2 : 4, 0, + Qtool_bar_lines); - run_window_configuration_change_hook (f); + /* adjust_frame_size might not have done anything, garbage frame + here. */ + adjust_frame_glyphs (f); + SET_FRAME_GARBAGED (f); + if (FRAME_X_WINDOW (f)) + x_clear_under_internal_border (f); } @@ -1839,6 +1884,16 @@ x_set_scroll_bar_default_width (struct frame *f) = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + unit - 1) / unit; } + +void +x_set_scroll_bar_default_height (struct frame *f) +{ + int unit = FRAME_LINE_HEIGHT (f); + + FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) = GetSystemMetrics (SM_CXHSCROLL); + FRAME_CONFIG_SCROLL_BAR_LINES (f) + = (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + unit - 1) / unit; +} /* Subroutines for creating a frame. */ @@ -1893,7 +1948,7 @@ w32_init_class (HINSTANCE hinst) } static HWND -w32_createscrollbar (struct frame *f, struct scroll_bar * bar) +w32_createvscrollbar (struct frame *f, struct scroll_bar * bar) { return CreateWindow ("SCROLLBAR", "", SBS_VERT | WS_CHILD | WS_VISIBLE, /* Position and size of scroll bar. */ @@ -1901,14 +1956,22 @@ w32_createscrollbar (struct frame *f, struct scroll_bar * bar) FRAME_W32_WINDOW (f), NULL, hinst, NULL); } +static HWND +w32_createhscrollbar (struct frame *f, struct scroll_bar * bar) +{ + return CreateWindow ("SCROLLBAR", "", SBS_HORZ | WS_CHILD | WS_VISIBLE, + /* Position and size of scroll bar. */ + bar->left, bar->top, bar->width, bar->height, + FRAME_W32_WINDOW (f), NULL, hinst, NULL); +} + static void -w32_createwindow (struct frame *f) +w32_createwindow (struct frame *f, int *coords) { HWND hwnd; RECT rect; - Lisp_Object top = Qunbound; - Lisp_Object left = Qunbound; - struct w32_display_info *dpyinfo = &one_w32_display_info; + int top; + int left; rect.left = rect.top = 0; rect.right = FRAME_PIXEL_WIDTH (f); @@ -1923,25 +1986,21 @@ w32_createwindow (struct frame *f) if (f->size_hint_flags & USPosition || f->size_hint_flags & PPosition) { - XSETINT (left, f->left_pos); - XSETINT (top, f->top_pos); + left = f->left_pos; + top = f->top_pos; } - else if (EQ (left, Qunbound) && EQ (top, Qunbound)) + else { - /* When called with RES_TYPE_NUMBER, w32_get_arg will return zero - for anything that is not a number and is not Qunbound. */ - left = x_get_arg (dpyinfo, Qnil, Qleft, "left", "Left", RES_TYPE_NUMBER); - top = x_get_arg (dpyinfo, Qnil, Qtop, "top", "Top", RES_TYPE_NUMBER); + left = coords[0]; + top = coords[1]; } FRAME_W32_WINDOW (f) = hwnd = CreateWindow (EMACS_CLASS, f->namebuf, f->output_data.w32->dwStyle | WS_CLIPCHILDREN, - EQ (left, Qunbound) ? CW_USEDEFAULT : XINT (left), - EQ (top, Qunbound) ? CW_USEDEFAULT : XINT (top), - rect.right - rect.left, - rect.bottom - rect.top, + left, top, + rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, hinst, @@ -1952,7 +2011,8 @@ w32_createwindow (struct frame *f) SetWindowLong (hwnd, WND_FONTWIDTH_INDEX, FRAME_COLUMN_WIDTH (f)); SetWindowLong (hwnd, WND_LINEHEIGHT_INDEX, FRAME_LINE_HEIGHT (f)); SetWindowLong (hwnd, WND_BORDER_INDEX, FRAME_INTERNAL_BORDER_WIDTH (f)); - SetWindowLong (hwnd, WND_SCROLLBAR_INDEX, FRAME_SCROLL_BAR_AREA_WIDTH (f)); + SetWindowLong (hwnd, WND_VSCROLLBAR_INDEX, FRAME_SCROLL_BAR_AREA_WIDTH (f)); + SetWindowLong (hwnd, WND_HSCROLLBAR_INDEX, FRAME_SCROLL_BAR_AREA_HEIGHT (f)); SetWindowLong (hwnd, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f)); /* Enable drag-n-drop. */ @@ -2367,7 +2427,8 @@ w32_name_of_message (UINT msg) M (WM_EMACS_KILL), M (WM_EMACS_CREATEWINDOW), M (WM_EMACS_DONE), - M (WM_EMACS_CREATESCROLLBAR), + M (WM_EMACS_CREATEVSCROLLBAR), + M (WM_EMACS_CREATEHSCROLLBAR), M (WM_EMACS_SHOWWINDOW), M (WM_EMACS_SETWINDOWPOS), M (WM_EMACS_DESTROYWINDOW), @@ -2384,6 +2445,7 @@ w32_name_of_message (UINT msg) M (WM_EMACS_SHOW_CARET), M (WM_EMACS_HIDE_CARET), M (WM_EMACS_SETCURSOR), + M (WM_EMACS_SHOWCURSOR), M (WM_EMACS_PAINT), M (WM_CHAR), #undef M @@ -2459,7 +2521,8 @@ w32_msg_pump (deferred_msg * msg_buf) the patch for XP is not publicly available until XP SP3, and older versions will never be patched. */ CoInitialize (NULL); - w32_createwindow ((struct frame *) msg.wParam); + w32_createwindow ((struct frame *) msg.wParam, + (int *) msg.lParam); if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0)) emacs_abort (); break; @@ -3441,6 +3504,7 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) track_mouse_event_fn (&tme); track_mouse_window = hwnd; } + case WM_HSCROLL: case WM_VSCROLL: if (w32_mouse_move_interval <= 0 || (msg == WM_MOUSEMOVE && button_state == 0)) @@ -3779,10 +3843,14 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) return 0; case WM_WINDOWPOSCHANGING: - /* Don't restrict the sizing of tip frames. */ - if (frame_resize_pixelwise || hwnd == tip_window) - return 0; + /* 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); @@ -3805,7 +3873,8 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) DWORD font_width; DWORD line_height; DWORD internal_border; - DWORD scrollbar_extra; + DWORD vscrollbar_extra; + DWORD hscrollbar_extra; RECT wr; wp.length = sizeof (wp); @@ -3816,7 +3885,8 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) font_width = GetWindowLong (hwnd, WND_FONTWIDTH_INDEX); line_height = GetWindowLong (hwnd, WND_LINEHEIGHT_INDEX); internal_border = GetWindowLong (hwnd, WND_BORDER_INDEX); - scrollbar_extra = GetWindowLong (hwnd, WND_SCROLLBAR_INDEX); + vscrollbar_extra = GetWindowLong (hwnd, WND_VSCROLLBAR_INDEX); + hscrollbar_extra = GetWindowLong (hwnd, WND_HSCROLLBAR_INDEX); leave_crit (); @@ -3827,10 +3897,10 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) /* 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 - scrollbar_extra) + - 2 * internal_border - vscrollbar_extra) % font_width; hdiff = (lppos->cy - (rect.bottom - rect.top) - - 2 * internal_border) + - 2 * internal_border - hscrollbar_extra) % line_height; if (wdiff || hdiff) @@ -3865,6 +3935,7 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) } goto dflt; +#endif case WM_GETMINMAXINFO: /* Hack to allow resizing the Emacs frame above the screen size. @@ -3899,9 +3970,20 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) return 0; } - case WM_EMACS_CREATESCROLLBAR: - return (LRESULT) w32_createscrollbar ((struct frame *) wParam, - (struct scroll_bar *) lParam); + case WM_EMACS_SHOWCURSOR: + { + ShowCursor ((BOOL) wParam); + + return 0; + } + + case WM_EMACS_CREATEVSCROLLBAR: + return (LRESULT) w32_createvscrollbar ((struct frame *) wParam, + (struct scroll_bar *) lParam); + + case WM_EMACS_CREATEHSCROLLBAR: + return (LRESULT) w32_createhscrollbar ((struct frame *) wParam, + (struct scroll_bar *) lParam); case WM_EMACS_SHOWWINDOW: return ShowWindow ((HWND) wParam, (WPARAM) lParam); @@ -4060,8 +4142,25 @@ static void my_create_window (struct frame * f) { MSG msg; + static int coords[2]; + Lisp_Object left, top; + struct w32_display_info *dpyinfo = &one_w32_display_info; + + /* When called with RES_TYPE_NUMBER, x_get_arg will return zero for + anything that is not a number and is not Qunbound. */ + left = x_get_arg (dpyinfo, Qnil, Qleft, "left", "Left", RES_TYPE_NUMBER); + top = x_get_arg (dpyinfo, Qnil, Qtop, "top", "Top", RES_TYPE_NUMBER); + if (EQ (left, Qunbound)) + coords[0] = CW_USEDEFAULT; + else + coords[0] = XINT (left); + if (EQ (top, Qunbound)) + coords[1] = CW_USEDEFAULT; + else + coords[1] = XINT (top); - if (!PostThreadMessage (dwWindowsThreadId, WM_EMACS_CREATEWINDOW, (WPARAM)f, 0)) + if (!PostThreadMessage (dwWindowsThreadId, WM_EMACS_CREATEWINDOW, + (WPARAM)f, (LPARAM)coords)) emacs_abort (); GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE); } @@ -4104,7 +4203,8 @@ my_create_tip_window (struct frame *f) SetWindowLong (tip_window, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f)); /* Tip frames have no scrollbars. */ - SetWindowLong (tip_window, WND_SCROLLBAR_INDEX, 0); + SetWindowLong (tip_window, WND_VSCROLLBAR_INDEX, 0); + SetWindowLong (tip_window, WND_HSCROLLBAR_INDEX, 0); /* Do this to discard the default setting specified by our parent. */ ShowWindow (tip_window, SW_HIDE); @@ -4336,7 +4436,6 @@ This function is an internal primitive--use `make-frame' instead. */) Lisp_Object name; int minibuffer_only = 0; long window_prompting = 0; - int width, height; ptrdiff_t count = SPECPDL_INDEX (); struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; Lisp_Object display; @@ -4404,8 +4503,9 @@ This function is an internal primitive--use `make-frame' instead. */) XSETFRAME (frame, f); - /* By default, make scrollbars the system standard width. */ - x_set_scroll_bar_default_width (f); + /* By default, make scrollbars the system standard width and height. */ + FRAME_CONFIG_SCROLL_BAR_WIDTH (f) = GetSystemMetrics (SM_CXVSCROLL); + FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) = GetSystemMetrics (SM_CXHSCROLL); f->terminal = dpyinfo->terminal; @@ -4431,7 +4531,6 @@ This function is an internal primitive--use `make-frame' instead. */) #endif /* GLYPH_DEBUG */ /* Specify the parent under which to make this window. */ - if (!NILP (parent)) { f->output_data.w32->parent_desc = (Window) XFASTINT (parent); @@ -4454,7 +4553,7 @@ This function is an internal primitive--use `make-frame' instead. */) { fset_name (f, name); f->explicit_name = 1; - /* 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); } @@ -4464,9 +4563,11 @@ This function is an internal primitive--use `make-frame' instead. */) x_default_parameter (f, parameters, Qfont_backend, Qnil, "fontBackend", "FontBackend", RES_TYPE_STRING); + /* Extract the window parameters from the supplied values that are needed to determine window geometry. */ x_default_font_parameter (f, parameters); + x_default_parameter (f, parameters, Qborder_width, make_number (2), "borderWidth", "BorderWidth", RES_TYPE_NUMBER); @@ -4480,7 +4581,7 @@ This function is an internal primitive--use `make-frame' instead. */) "internalBorder", "InternalBorder", RES_TYPE_NUMBER); if (! EQ (value, Qunbound)) parameters = Fcons (Fcons (Qinternal_border_width, value), - parameters); + parameters); } /* Default internalBorderWidth to 0 on Windows to match other programs. */ x_default_parameter (f, parameters, Qinternal_border_width, make_number (0), @@ -4491,6 +4592,8 @@ This function is an internal primitive--use `make-frame' instead. */) NULL, NULL, RES_TYPE_NUMBER); x_default_parameter (f, parameters, Qvertical_scroll_bars, Qright, "verticalScrollBars", "ScrollBars", RES_TYPE_SYMBOL); + x_default_parameter (f, parameters, Qhorizontal_scroll_bars, Qnil, + "horizontalScrollBars", "ScrollBars", RES_TYPE_SYMBOL); /* Also do the stuff which must be set before the window exists. */ x_default_parameter (f, parameters, Qforeground_color, build_string ("black"), @@ -4511,57 +4614,42 @@ This function is an internal primitive--use `make-frame' instead. */) "rightFringe", "RightFringe", RES_TYPE_NUMBER); /* Process alpha here (Bug#16619). */ x_default_parameter (f, parameters, Qalpha, Qnil, - "alpha", "Alpha", RES_TYPE_NUMBER); + "alpha", "Alpha", RES_TYPE_NUMBER); - /* Init faces before x_default_parameter is called for scroll-bar - parameters because that function calls x_set_scroll_bar_width, - which calls change_frame_size, which calls Fset_window_buffer, - which runs hooks, which call Fvertical_motion. At the end, we - end up in init_iterator with a null face cache, which should not - happen. */ + /* Init faces first since we need the frame's column width/line + height in various occasions. */ init_frame_faces (f); - /* Avoid calling window-configuration-change-hook; otherwise we - could get an infloop in next_frame since the frame is not yet in - Vframe_list. */ - { - ptrdiff_t count2 = SPECPDL_INDEX (); - - record_unwind_protect (unwind_create_frame_1, inhibit_lisp_code); - inhibit_lisp_code = Qt; - - /* PXW: This is a duplicate from below. We have to do it here since - otherwise x_set_tool_bar_lines will work with the character sizes - installed by init_frame_faces while the frame's pixel size is still - calculated from a character size of 1 and we subsequently hit the - eassert (height >= 0) assertion in window_box_height. The - non-pixelwise code apparently worked around this because it had one - frame line vs one toolbar line which left us with a zero root - window height which was obviously wrong as well ... */ - change_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f), - FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 1, 0, 0, 1); - - /* The X resources controlling the menu-bar and tool-bar are - processed specially at startup, and reflected in the mode - variables; ignore them here. */ - x_default_parameter (f, parameters, Qmenu_bar_lines, - NILP (Vmenu_bar_mode) - ? make_number (0) : make_number (1), - NULL, NULL, RES_TYPE_NUMBER); - x_default_parameter (f, parameters, Qtool_bar_lines, - NILP (Vtool_bar_mode) - ? make_number (0) : make_number (1), - NULL, NULL, RES_TYPE_NUMBER); - - unbind_to (count2, Qnil); - } + /* The following call of change_frame_size is needed since otherwise + x_set_tool_bar_lines will already work with the character sizes + installed by init_frame_faces while the frame's pixel size is + still calculated from a character size of 1 and we subsequently + hit the (height >= 0) assertion in window_box_height. + + The non-pixelwise code apparently worked around this because it + had one frame line vs one toolbar line which left us with a zero + root window height which was obviously wrong as well ... */ + adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f), + FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 5, 1, Qnil); + + /* The X resources controlling the menu-bar and tool-bar are + processed specially at startup, and reflected in the mode + variables; ignore them here. */ + x_default_parameter (f, parameters, Qmenu_bar_lines, + NILP (Vmenu_bar_mode) + ? make_number (0) : make_number (1), + NULL, NULL, RES_TYPE_NUMBER); + x_default_parameter (f, parameters, Qtool_bar_lines, + NILP (Vtool_bar_mode) + ? make_number (0) : make_number (1), + NULL, NULL, RES_TYPE_NUMBER); x_default_parameter (f, parameters, Qbuffer_predicate, Qnil, "bufferPredicate", "BufferPredicate", RES_TYPE_SYMBOL); x_default_parameter (f, parameters, Qtitle, Qnil, "title", "Title", RES_TYPE_STRING); x_default_parameter (f, parameters, Qfullscreen, Qnil, - "fullscreen", "Fullscreen", RES_TYPE_SYMBOL); + "fullscreen", "Fullscreen", RES_TYPE_SYMBOL); f->output_data.w32->dwStyle = WS_OVERLAPPEDWINDOW; f->output_data.w32->parent_desc = FRAME_DISPLAY_INFO (f)->root_window; @@ -4604,15 +4692,13 @@ This function is an internal primitive--use `make-frame' instead. */) "cursorType", "CursorType", RES_TYPE_SYMBOL); x_default_parameter (f, parameters, Qscroll_bar_width, Qnil, "scrollBarWidth", "ScrollBarWidth", RES_TYPE_NUMBER); + x_default_parameter (f, parameters, Qscroll_bar_height, Qnil, + "scrollBarHeight", "ScrollBarHeight", RES_TYPE_NUMBER); + + /* Allow x_set_window_size, now. */ + f->can_x_set_window_size = true; - /* Dimensions, especially FRAME_LINES (f), must be done via change_frame_size. - Change will not be effected unless different from the current - FRAME_LINES (f). */ - width = FRAME_TEXT_WIDTH (f); - height = FRAME_TEXT_HEIGHT (f); - FRAME_TEXT_HEIGHT (f) = 0; - SET_FRAME_WIDTH (f, 0); - change_frame_size (f, width, height, 1, 0, 0, 1); + adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f), 0, 1, Qnil); /* 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 @@ -4949,7 +5035,7 @@ If omitted or nil, that stands for the selected frame's display. */) return Qnil; } -static BOOL CALLBACK +static BOOL CALLBACK ALIGN_STACK w32_monitor_enum (HMONITOR monitor, HDC hdc, RECT *rcMonitor, LPARAM dwData) { Lisp_Object *monitor_list = (Lisp_Object *) dwData; @@ -5276,7 +5362,7 @@ terminate Emacs if we can't open the connection. { char basename[ MAX_PATH ], *str; - strcpy (basename, SDATA (Vinvocation_name)); + lispstpcpy (basename, Vinvocation_name); str = strrchr (basename, '.'); if (str) *str = 0; Vinvocation_name = build_string (basename); @@ -5488,67 +5574,6 @@ no value of TYPE (always string in the MS Windows case). */) #endif /* TODO */ - -/*********************************************************************** - Busy cursor - ***********************************************************************/ - -/* Display an hourglass cursor. Set the hourglass_p flag in display info - to indicate that an hourglass cursor is shown. */ - -void -show_hourglass (struct atimer *timer) -{ - hourglass_atimer = NULL; - - if (!hourglass_shown_p) - { - Lisp_Object tail, frame; - - block_input (); - FOR_EACH_FRAME (tail, frame) - { - struct frame *f = XFRAME (frame); - - if (FRAME_W32_P (f) && !menubar_in_use && !current_popup_menu) - { - f->output_data.w32->hourglass_p = 1; - SetCursor (f->output_data.w32->hourglass_cursor); - } - } - unblock_input (); - hourglass_shown_p = 1; - } -} - -/* Hide the hourglass cursor on all frames, if it is currently shown. */ - -void -hide_hourglass (void) -{ - if (hourglass_shown_p) - { - Lisp_Object tail, frame; - - block_input (); - FOR_EACH_FRAME (tail, frame) - { - struct frame *f = XFRAME (frame); - - if (FRAME_W32_P (f)) - { - f->output_data.w32->hourglass_p = 0; - SetCursor (f->output_data.w32->current_cursor); - } - else - /* No cursors on non GUI frames - restore to stock arrow cursor. */ - SetCursor (w32_load_cursor (IDC_ARROW)); - } - unblock_input (); - hourglass_shown_p = 0; - } -} - /*********************************************************************** Tool tips ***********************************************************************/ @@ -5638,7 +5663,8 @@ x_create_tip_frame (struct w32_display_info *dpyinfo, f->wants_modeline = 0; XSETFRAME (frame, f); - buffer = Fget_buffer_create (build_string (" *tip*")); + 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, 0, 0); @@ -5733,13 +5759,12 @@ x_create_tip_frame (struct w32_display_info *dpyinfo, "cursorColor", "Foreground", RES_TYPE_STRING); x_default_parameter (f, parms, Qborder_color, build_string ("black"), "borderColor", "BorderColor", RES_TYPE_STRING); + x_default_parameter (f, parms, Qalpha, Qnil, + "alpha", "Alpha", RES_TYPE_NUMBER); - /* Init faces before x_default_parameter is called for scroll-bar - parameters because that function calls x_set_scroll_bar_width, - which calls change_frame_size, which calls Fset_window_buffer, - which runs hooks, which call Fvertical_motion. At the end, we - end up in init_iterator with a null face cache, which should not - happen. */ + /* Init faces before x_default_parameter is called for the + scroll-bar-width parameter because otherwise we end up in + init_iterator with a null face cache, which should not happen. */ init_frame_faces (f); f->output_data.w32->dwStyle = WS_BORDER | WS_POPUP | WS_DISABLED; @@ -5770,9 +5795,10 @@ x_create_tip_frame (struct w32_display_info *dpyinfo, from the current FRAME_LINES (f). */ width = FRAME_COLS (f); height = FRAME_LINES (f); - FRAME_LINES (f) = 0; SET_FRAME_COLS (f, 0); - change_frame_size (f, width, height, 1, 0, 0, 0); + SET_FRAME_LINES (f, 0); + adjust_frame_size (f, width * FRAME_COLUMN_WIDTH (f), + height * FRAME_LINE_HEIGHT (f), 0, 1, Qnil); /* Add `tooltip' frame parameter's default value. */ if (NILP (Fframe_parameter (frame, Qtooltip))) @@ -5817,6 +5843,7 @@ x_create_tip_frame (struct w32_display_info *dpyinfo, below. And the frame needs to be on Vframe_list or making it visible won't work. */ Vframe_list = Fcons (frame, Vframe_list); + f->can_x_set_window_size = true; /* Setting attributes of faces of the tooltip frame from resources and similar will increment face_change_count, which leads to the @@ -6225,8 +6252,8 @@ Text larger than the specified size is clipped. */) } /* Draw into the window. */ - w->must_be_updated_p = 1; - update_single_window (w, 1); + w->must_be_updated_p = true; + update_single_window (w); unblock_input (); @@ -6394,7 +6421,11 @@ or directory must exist. This function is only defined on NS, MS Windows, and X Windows with the Motif or Gtk toolkits. With the Motif toolkit, ONLY-DIR-P is ignored. -Otherwise, if ONLY-DIR-P is non-nil, the user can only select directories. */) +Otherwise, if ONLY-DIR-P is non-nil, the user can only select directories. +On Windows 7 and later, the file selection dialog "remembers" the last +directory where the user selected a file, and will open that directory +instead of DIR on subsequent invocations of this function with the same +value of DIR as in previous invocations; this is standard Windows behavior. */) (Lisp_Object prompt, Lisp_Object dir, Lisp_Object default_filename, Lisp_Object mustmatch, Lisp_Object only_dir_p) { /* Filter index: 1: All Files, 2: Directories only */ @@ -6980,7 +7011,14 @@ a ShowWindow flag: Lisp_Object absdoc_encoded = ENCODE_FILE (absdoc); if (faccessat (AT_FDCWD, SSDATA (absdoc_encoded), F_OK, AT_EACCESS) == 0) - document = absdoc_encoded; + { + /* ShellExecute fails if DOCUMENT is a UNC with forward + slashes (expand-file-name above converts all backslashes + to forward slashes). Now that we know DOCUMENT is a + file, we can mirror all forward slashes into backslashes. */ + unixtodos_filename (SSDATA (absdoc_encoded)); + document = absdoc_encoded; + } else document = ENCODE_FILE (document); } @@ -7336,6 +7374,37 @@ This is a direct interface to the Windows API FindWindow function. */) return Qt; } +DEFUN ("w32-frame-menu-bar-size", Fw32_frame_menu_bar_size, Sw32_frame_menu_bar_size, 0, 1, 0, + doc: /* Return sizes of menu bar on frame FRAME. +The return value is a list of four elements: The current width and +height of FRAME's menu bar in pixels, the height of one menu bar line in +a wrapped menu bar in pixels, and the height of a single line menu bar +in pixels. + +If FRAME is omitted or nil, the selected frame is used. */) + (Lisp_Object frame) +{ + struct frame *f = decode_any_frame (frame); + MENUBARINFO menu_bar; + int width, height, single_height, wrapped_height; + + block_input (); + + single_height = GetSystemMetrics (SM_CYMENU); + wrapped_height = GetSystemMetrics (SM_CYMENUSIZE); + menu_bar.cbSize = sizeof (menu_bar); + menu_bar.rcBar.right = menu_bar.rcBar.left = 0; + menu_bar.rcBar.top = menu_bar.rcBar.bottom = 0; + GetMenuBarInfo (FRAME_W32_WINDOW (f), 0xFFFFFFFD, 0, &menu_bar); + width = menu_bar.rcBar.right - menu_bar.rcBar.left; + height = menu_bar.rcBar.bottom - menu_bar.rcBar.top; + + unblock_input (); + + return list4 (make_number (width), make_number (height), + make_number (wrapped_height), make_number (single_height)); +} + DEFUN ("w32-frame-rect", Fw32_frame_rect, Sw32_frame_rect, 0, 2, 0, doc: /* Return boundary rectangle of FRAME in screen coordinates. FRAME must be a live frame and defaults to the selected one. @@ -7350,15 +7419,131 @@ title bar and decorations. */) struct frame *f = decode_live_frame (frame); RECT rect; + 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 + FRAME. + +- `tool-bar-external' if `t' means the tool bar is by default external + (not included in the inner size 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-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. */) + (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); + + 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); + /* Title bar. */ + title_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); + unblock_input (); + + 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) + /* A wrapped menu bar. */ + menu_bar_height += single_bar_height - wrapped_bar_height; + else if (menu_bar_height > 0) + /* A single line menu bar. */ + menu_bar_height = single_bar_height; + + return + listn (CONSTYPE_PURE, 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))), + 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 (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_size, + Fcons (make_number (FRAME_TOOL_BAR_LINES (f) + ? (FRAME_PIXEL_WIDTH (f) + - 2 * FRAME_INTERNAL_BORDER_WIDTH (f)) + : 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)))); +} + DEFUN ("w32-battery-status", Fw32_battery_status, Sw32_battery_status, 0, 0, 0, doc: /* Get power status information from Windows system. @@ -8023,17 +8208,19 @@ frame_parm_handler w32_frame_parm_handlers[] = x_set_mouse_color, x_explicitly_set_name, x_set_scroll_bar_width, + x_set_scroll_bar_height, x_set_title, x_set_unsplittable, x_set_vertical_scroll_bars, + x_set_horizontal_scroll_bars, x_set_visibility, x_set_tool_bar_lines, 0, /* x_set_scroll_bar_foreground, */ 0, /* x_set_scroll_bar_background, */ x_set_screen_gamma, x_set_line_spacing, - x_set_fringe_width, - x_set_fringe_width, + x_set_left_fringe, + x_set_right_fringe, 0, /* x_set_wait_for_wm, */ x_set_fullscreen, x_set_font_backend, @@ -8351,6 +8538,7 @@ only be necessary if the default setting causes problems. */); defsubr (&Sx_open_connection); defsubr (&Sx_close_connection); defsubr (&Sx_display_list); + defsubr (&Sx_frame_geometry); defsubr (&Sx_synchronize); /* W32 specific functions */ @@ -8367,6 +8555,7 @@ only be necessary if the default setting causes problems. */); defsubr (&Sw32_toggle_lock_key); defsubr (&Sw32_window_exists_p); defsubr (&Sw32_frame_rect); + defsubr (&Sw32_frame_menu_bar_size); defsubr (&Sw32_battery_status); #ifdef WINDOWSNT