diff options
Diffstat (limited to 'src/w32fns.c')
-rw-r--r-- | src/w32fns.c | 659 |
1 files changed, 600 insertions, 59 deletions
diff --git a/src/w32fns.c b/src/w32fns.c index dd16d74439f..f7d3b722abf 100644 --- a/src/w32fns.c +++ b/src/w32fns.c @@ -256,6 +256,10 @@ static unsigned int sound_type = 0xFFFFFFFF; # define WTS_SESSION_LOCK 0x7 #endif +#ifndef WS_EX_NOACTIVATE +#define WS_EX_NOACTIVATE 0x08000000L +#endif + /* Keyboard hook state data. */ static struct { @@ -367,17 +371,20 @@ void x_set_title (struct frame *, Lisp_Object, Lisp_Object); void x_real_positions (struct frame *f, int *xptr, int *yptr) { - POINT pt; RECT rect; /* Get the bounds of the WM window. */ GetWindowRect (FRAME_W32_WINDOW (f), &rect); - pt.x = 0; - pt.y = 0; + if (FRAME_PARENT_FRAME (f)) + { + /* For a child window we have to get its coordinates wrt its + parent. */ + HWND parent_hwnd = FRAME_W32_WINDOW (FRAME_PARENT_FRAME (f)); - /* Convert (0, 0) in the client area to screen co-ordinates. */ - ClientToScreen (FRAME_W32_WINDOW (f), &pt); + if (parent_hwnd) + MapWindowPoints (HWND_DESKTOP, parent_hwnd, (LPPOINT) &rect, 2); + } *xptr = rect.left; *yptr = rect.top; @@ -1682,7 +1689,7 @@ x_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) most of the commands try to apply themselves to the minibuffer frame itself, and get an error because you can't switch buffers in or split the minibuffer window. */ - if (FRAME_MINIBUF_ONLY_P (f)) + if (FRAME_MINIBUF_ONLY_P (f) || FRAME_PARENT_FRAME (f)) return; if (INTEGERP (value)) @@ -1955,6 +1962,233 @@ x_set_scroll_bar_default_height (struct frame *f) FRAME_CONFIG_SCROLL_BAR_LINES (f) = (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + unit - 1) / unit; } + +/** + * x_set_undecorated: + * + * Set frame F's `undecorated' parameter. If non-nil, F's window-system + * window is drawn without decorations, title, minimize/maximize boxes + * and external borders. This usually means that the window cannot be + * dragged, resized, iconified, maximized or deleted with the mouse. If + * nil, draw the frame with all the elements listed above unless these + * have been suspended via window manager settings. + * + * Some window managers may not honor this parameter. + */ +static void +x_set_undecorated (struct frame *f, Lisp_Object new_value, Lisp_Object old_value) +{ + HWND hwnd = FRAME_W32_WINDOW (f); + DWORD dwStyle = GetWindowLong (hwnd, GWL_STYLE); + Lisp_Object border_width = Fcdr (Fassq (Qborder_width, f->param_alist)); + + block_input (); + if (!NILP (new_value) && !FRAME_UNDECORATED (f)) + { + dwStyle = ((dwStyle & ~WS_THICKFRAME & ~WS_CAPTION) + | ((NUMBERP (border_width) && (XINT (border_width) > 0)) + ? WS_BORDER : false)); + SetWindowLong (hwnd, GWL_STYLE, dwStyle); + SetWindowPos (hwnd, HWND_TOP, 0, 0, 0, 0, + SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE + | SWP_FRAMECHANGED); + FRAME_UNDECORATED (f) = true; + } + else if (NILP (new_value) && FRAME_UNDECORATED (f)) + { + SetWindowLong (hwnd, GWL_STYLE, dwStyle | WS_THICKFRAME | WS_CAPTION + | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_SYSMENU); + SetWindowPos (hwnd, HWND_TOP, 0, 0, 0, 0, + SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE + | SWP_FRAMECHANGED); + FRAME_UNDECORATED (f) = false; + } + unblock_input (); +} + +/** + * x_set_parent_frame: + * + * Set frame F's `parent-frame' parameter. If non-nil, make F a child + * frame of the frame specified by that parameter. Technically, this + * makes F's window-system window a child window of the parent frame's + * window-system window. If nil, make F's window-system window a + * top-level window--a child of its display's root window. + * + * A child frame is clipped at the native edges of its parent frame. + * Its `left' and `top' parameters specify positions relative to the + * top-left corner of its parent frame's native rectangle. Usually, + * moving a parent frame moves all its child frames too, keeping their + * position relative to the parent unaltered. When a parent frame is + * iconified or made invisible, its child frames are made invisible. + * When a parent frame is deleted, its child frames are deleted too. + * + * A visible child frame always appears on top of its parent frame thus + * obscuring parts of it. When a frame has more than one child frame, + * their stacking order is specified just as that of non-child frames + * relative to their display. + * + * Whether a child frame has a menu or tool bar may be window-system or + * window manager dependent. It's advisable to disable both via the + * frame parameter settings. + * + * Some window managers may not honor this parameter. + */ +static void +x_set_parent_frame (struct frame *f, Lisp_Object new_value, Lisp_Object old_value) +{ + struct frame *p = NULL; + + if (!NILP (new_value) + && (!FRAMEP (new_value) + || !FRAME_LIVE_P (p = XFRAME (new_value)) + || !FRAME_W32_P (p))) + { + store_frame_param (f, Qparent_frame, old_value); + error ("Invalid specification of `parent-frame'"); + } + + if (p != FRAME_PARENT_FRAME (f)) + { + HWND hwnd = FRAME_W32_WINDOW (f); + HWND hwnd_parent = p ? FRAME_W32_WINDOW (p) : NULL; + HWND hwnd_value; + + block_input (); + hwnd_value = SetParent (hwnd, hwnd_parent); + unblock_input (); + + if (hwnd_value) + fset_parent_frame (f, new_value); + else + { + store_frame_param (f, Qparent_frame, old_value); + error ("Reparenting frame failed"); + } + } +} + +/** + * x_set_skip_taskbar: + * + * Set frame F's `skip-taskbar' parameter. If non-nil, this should + * remove F's icon from the taskbar associated with the display of F's + * window-system window and inhibit switching to F's window via + * <Alt>-<TAB>. On Windows iconifying F will "roll in" its window at + * the bottom of the desktop. If nil, lift these restrictions. + * + * Some window managers may not honor this parameter. + */ +static void +x_set_skip_taskbar (struct frame *f, Lisp_Object new_value, Lisp_Object old_value) +{ + if (!EQ (new_value, old_value)) + { + HWND hwnd = FRAME_W32_WINDOW (f); + DWORD exStyle = GetWindowLong (hwnd, GWL_EXSTYLE); + + block_input (); + /* Temporarily hide the window while changing its WS_EX_NOACTIVATE + setting. */ + ShowWindow (hwnd, SW_HIDE); + if (!NILP (new_value)) + SetWindowLong (hwnd, GWL_EXSTYLE, exStyle | WS_EX_NOACTIVATE); + else + SetWindowLong (hwnd, GWL_EXSTYLE, exStyle & ~WS_EX_NOACTIVATE); + ShowWindow (hwnd, SW_SHOWNOACTIVATE); + unblock_input (); + + FRAME_SKIP_TASKBAR (f) = !NILP (new_value); + } +} + +/** + * x_set_no_focus_on_map: + * + * Set frame F's `no-focus-on-map' parameter which, if non-nil, means + * that F's window-system window does not want to receive input focus + * when it is mapped. (A frame's window is mapped when the frame is + * displayed for the first time and when the frame changes its state + * from `iconified' or `invisible' to `visible'.) + * + * Some window managers may not honor this parameter. + */ +static void +x_set_no_focus_on_map (struct frame *f, Lisp_Object new_value, Lisp_Object old_value) +{ + if (!EQ (new_value, old_value)) + FRAME_NO_FOCUS_ON_MAP (f) = !NILP (new_value); +} + +/** + * x_set_no_accept_focus: + * + * Set frame F's `no-accept-focus' parameter which, if non-nil, hints + * that F's window-system window does not want to receive input focus + * via mouse clicks or by moving the mouse into it. + * + * If non-nil, this may have the unwanted side-effect that a user cannot + * scroll a non-selected frame with the mouse. + * + * Some window managers may not honor this parameter. + */ +static void +x_set_no_accept_focus (struct frame *f, Lisp_Object new_value, Lisp_Object old_value) +{ + if (!EQ (new_value, old_value)) + FRAME_NO_ACCEPT_FOCUS (f) = !NILP (new_value); +} + +/** + * x_set_z_group: + * + * Set frame F's `z-group' parameter. If `above', F's window-system + * window is displayed above all windows that do not have the `above' + * property set. If nil, F's window is shown below all windows that + * have the `above' property set and above all windows that have the + * `below' property set. If `below', F's window is displayed below all + * windows that do not have the `below' property set. + * + * Some window managers may not honor this parameter. The value `below' + * is not supported on Windows. + */ +static void +x_set_z_group (struct frame *f, Lisp_Object new_value, Lisp_Object old_value) +{ + HWND hwnd = FRAME_W32_WINDOW (f); + + if (NILP (new_value)) + { + block_input (); + SetWindowPos (hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE + | SWP_NOOWNERZORDER); + unblock_input (); + FRAME_Z_GROUP (f) = z_group_none; + } + else if (EQ (new_value, Qabove)) + { + block_input (); + SetWindowPos (hwnd, HWND_TOPMOST, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE + | SWP_NOOWNERZORDER); + unblock_input (); + FRAME_Z_GROUP (f) = z_group_above; + } + else if (EQ (new_value, Qabove_suspended)) + { + block_input (); + SetWindowPos (hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE + | SWP_NOOWNERZORDER); + unblock_input (); + FRAME_Z_GROUP (f) = z_group_above_suspended; + } + else if (EQ (new_value, Qbelow)) + error ("Value `below' for z-group is not supported on Windows"); + else + error ("Invalid z-group specification"); +} /* Subroutines for creating a frame. */ @@ -2013,7 +2247,12 @@ w32_init_class (HINSTANCE hinst) static HWND w32_createvscrollbar (struct frame *f, struct scroll_bar * bar) { - return CreateWindow ("SCROLLBAR", "", SBS_VERT | WS_CHILD | WS_VISIBLE, + return CreateWindow ("SCROLLBAR", "", + /* Clip siblings so we don't draw over child + frames. Apparently this is not always + sufficient so we also try to make bar windows + bottommost. */ + SBS_VERT | WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS, /* Position and size of scroll bar. */ bar->left, bar->top, bar->width, bar->height, FRAME_W32_WINDOW (f), NULL, hinst, NULL); @@ -2022,7 +2261,12 @@ w32_createvscrollbar (struct frame *f, struct scroll_bar * bar) static HWND w32_createhscrollbar (struct frame *f, struct scroll_bar * bar) { - return CreateWindow ("SCROLLBAR", "", SBS_HORZ | WS_CHILD | WS_VISIBLE, + return CreateWindow ("SCROLLBAR", "", + /* Clip siblings so we don't draw over child + frames. Apparently this is not always + sufficient so we also try to make bar windows + bottommost. */ + SBS_HORZ | WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS, /* Position and size of scroll bar. */ bar->left, bar->top, bar->width, bar->height, FRAME_W32_WINDOW (f), NULL, hinst, NULL); @@ -2031,20 +2275,55 @@ w32_createhscrollbar (struct frame *f, struct scroll_bar * bar) static void w32_createwindow (struct frame *f, int *coords) { - HWND hwnd; + HWND hwnd = NULL, parent_hwnd = NULL; RECT rect; - int top; - int left; + DWORD dwStyle; + int top, left; + Lisp_Object border_width = Fcdr (Fassq (Qborder_width, f->param_alist)); + + if (FRAME_PARENT_FRAME (f) && FRAME_W32_P (FRAME_PARENT_FRAME (f))) + { + parent_hwnd = FRAME_W32_WINDOW (FRAME_PARENT_FRAME (f)); + f->output_data.w32->dwStyle = WS_CHILD | WS_CLIPSIBLINGS; + + if (FRAME_UNDECORATED (f)) + { + /* If we want a thin border, specify it here. */ + if (NUMBERP (border_width) && (XINT (border_width) > 0)) + f->output_data.w32->dwStyle = + f->output_data.w32->dwStyle | WS_BORDER; + } + else + /* To decorate a child frame, list all needed elements. */ + f->output_data.w32->dwStyle = + f->output_data.w32->dwStyle | WS_THICKFRAME | WS_CAPTION + | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_SYSMENU; + } + else if (FRAME_UNDECORATED (f)) + { + /* All attempts to start with ~WS_OVERLAPPEDWINDOW or overlapped + with all other style elements negated failed here. */ + f->output_data.w32->dwStyle = WS_POPUP; + + /* If we want a thin border, specify it here. */ + if (NUMBERP (border_width) && (XINT (border_width) > 0)) + f->output_data.w32->dwStyle = + f->output_data.w32->dwStyle | WS_BORDER; + } + else + f->output_data.w32->dwStyle = WS_OVERLAPPEDWINDOW; + + /* Always clip children. */ + f->output_data.w32->dwStyle = f->output_data.w32->dwStyle | WS_CLIPCHILDREN; rect.left = rect.top = 0; rect.right = FRAME_PIXEL_WIDTH (f); rect.bottom = FRAME_PIXEL_HEIGHT (f); AdjustWindowRect (&rect, f->output_data.w32->dwStyle, - FRAME_EXTERNAL_MENU_BAR (f)); + FRAME_EXTERNAL_MENU_BAR (f) && !parent_hwnd); /* Do first time app init */ - w32_init_class (hinst); if (f->size_hint_flags & USPosition || f->size_hint_flags & PPosition) @@ -2059,18 +2338,16 @@ w32_createwindow (struct frame *f, int *coords) } FRAME_W32_WINDOW (f) = hwnd - = CreateWindow (EMACS_CLASS, - f->namebuf, - f->output_data.w32->dwStyle | WS_CLIPCHILDREN, - left, top, - rect.right - rect.left, rect.bottom - rect.top, - NULL, - NULL, - hinst, - NULL); + = CreateWindow (EMACS_CLASS, f->namebuf, f->output_data.w32->dwStyle, + left, top, rect.right - rect.left, rect.bottom - rect.top, + parent_hwnd, NULL, hinst, NULL); if (hwnd) { + if (FRAME_SKIP_TASKBAR (f)) + SetWindowLong (hwnd, GWL_EXSTYLE, + GetWindowLong (hwnd, GWL_EXSTYLE) | WS_EX_NOACTIVATE); + 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)); @@ -2086,6 +2363,12 @@ w32_createwindow (struct frame *f, int *coords) /* Update frame positions. */ GetWindowRect (hwnd, &rect); + + if (parent_hwnd) + /* For a child window we have to get its coordinates wrt its + parent. */ + MapWindowPoints (HWND_DESKTOP, parent_hwnd, (LPPOINT) &rect, 2); + f->left_pos = rect.left; f->top_pos = rect.top; } @@ -4381,6 +4664,22 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) } } + if (f && (msg == WM_LBUTTONDOWN || msg == WM_RBUTTONDOWN + || msg == WM_MBUTTONDOWN ||msg == WM_XBUTTONDOWN) + && !FRAME_NO_ACCEPT_FOCUS (f)) + /* When clicking into a child frame or when clicking into a + parent frame with the child frame selected and + `no-accept-focus' is not set, select the clicked frame. */ + { + struct frame *p = FRAME_PARENT_FRAME (XFRAME (selected_frame)); + + if (FRAME_PARENT_FRAME (f) || f == p) + { + SetFocus (hwnd); + SetWindowPos (hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); + } + } + wmsg.dwModifiers = w32_get_modifiers (); my_post_msg (&wmsg, hwnd, msg, wParam, lParam); signal_user_input (); @@ -4486,6 +4785,10 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) if (w32_pass_multimedia_buttons_to_system) goto dflt; /* Otherwise, pass to lisp, the same way we do with mousehwheel. */ + + /* FIXME!!! This is never reached so what's the purpose? If the + non-zero return remark below is right we're doing it wrong all + the time. */ case WM_MOUSEHWHEEL: wmsg.dwModifiers = w32_get_modifiers (); my_post_msg (&wmsg, hwnd, msg, wParam, lParam); @@ -4712,19 +5015,34 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) } return 0; -#if 0 + case WM_MOUSEACTIVATE: + /* WM_MOUSEACTIVATE is the only way on Windows to implement the + `no-accept-focus' frame parameter. This means that one can't + use the mouse to scroll a window on a non-selected frame. */ + /* Still not right - can't distinguish between clicks in the client area of the frame from clicks forwarded from the scroll bars - may have to hook WM_NCHITTEST to remember the mouse - position and then check if it is in the client area ourselves. */ - case WM_MOUSEACTIVATE: + position and then check if it is in the client area + ourselves. */ + /* Discard the mouse click that activates a frame, allowing the user to click anywhere without changing point (or worse!). Don't eat mouse clicks on scrollbars though!! */ - if (LOWORD (lParam) == HTCLIENT ) - return MA_ACTIVATEANDEAT; + + if ((f = x_window_to_frame (dpyinfo, hwnd)) + && FRAME_NO_ACCEPT_FOCUS (f) + /* Ignore child frames, they don't accept focus anyway. */ + && !FRAME_PARENT_FRAME (f)) + { + Lisp_Object frame; + + XSETFRAME (frame, f); + if (!EQ (selected_frame, frame)) + /* Don't discard the message, GTK doesn't either. */ + return MA_NOACTIVATE; /* ANDEAT; */ + } goto dflt; -#endif case WM_MOUSELEAVE: /* No longer tracking mouse. */ @@ -4903,6 +5221,10 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) AttachThreadInput (GetCurrentThreadId (), foreground_thread, FALSE); + /* SetFocus to give/remove focus to/from a child window. */ + if (msg == WM_EMACS_SETFOREGROUND) + SetFocus ((HWND) wParam); + return retval; } @@ -5134,7 +5456,8 @@ w32_window (struct frame *f, long window_prompting, bool minibuffer_only) unblock_input (); - if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f)) + if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f) + && !FRAME_PARENT_FRAME (f)) initialize_frame_menubar (f); if (FRAME_W32_WINDOW (f) == 0) @@ -5322,7 +5645,7 @@ This function is an internal primitive--use `make-frame' instead. */) ptrdiff_t count = SPECPDL_INDEX (); Lisp_Object display; struct w32_display_info *dpyinfo = NULL; - Lisp_Object parent; + Lisp_Object parent, parent_frame; struct kboard *kb; int x_width = 0, x_height = 0; @@ -5359,10 +5682,11 @@ This function is an internal primitive--use `make-frame' instead. */) Vx_resource_name = name; /* See if parent window is specified. */ - parent = x_get_arg (dpyinfo, parameters, Qparent_id, NULL, NULL, RES_TYPE_NUMBER); + parent = x_get_arg (dpyinfo, parameters, Qparent_id, NULL, NULL, + RES_TYPE_NUMBER); if (EQ (parent, Qunbound)) parent = Qnil; - if (! NILP (parent)) + else if (!NILP (parent)) CHECK_NUMBER (parent); /* make_frame_without_minibuffer can run Lisp code and garbage collect. */ @@ -5385,6 +5709,31 @@ This function is an internal primitive--use `make-frame' instead. */) XSETFRAME (frame, f); + parent_frame = x_get_arg (dpyinfo, parameters, Qparent_frame, NULL, NULL, + RES_TYPE_SYMBOL); + /* Apply `parent-frame' parameter only when no `parent-id' was + specified. */ + if (!NILP (parent_frame) + && (!NILP (parent) + || !FRAMEP (parent_frame) + || !FRAME_LIVE_P (XFRAME (parent_frame)) + || !FRAME_W32_P (XFRAME (parent_frame)))) + parent_frame = Qnil; + + fset_parent_frame (f, parent_frame); + store_frame_param (f, Qparent_frame, parent_frame); + + tem = x_get_arg (dpyinfo, parameters, Qundecorated, NULL, NULL, + RES_TYPE_BOOLEAN); + FRAME_UNDECORATED (f) = !NILP (tem) && !EQ (tem, Qunbound); + store_frame_param (f, Qundecorated, FRAME_UNDECORATED (f) ? Qt : Qnil); + + tem = x_get_arg (dpyinfo, parameters, Qskip_taskbar, NULL, NULL, + RES_TYPE_BOOLEAN); + FRAME_SKIP_TASKBAR (f) = !NILP (tem) && !EQ (tem, Qunbound); + store_frame_param (f, Qskip_taskbar, + (NILP (tem) || EQ (tem, Qunbound)) ? Qnil : Qt); + /* 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); @@ -5412,7 +5761,9 @@ This function is an internal primitive--use `make-frame' instead. */) dpyinfo_refcount = dpyinfo->reference_count; #endif /* GLYPH_DEBUG */ - /* Specify the parent under which to make this window. */ + /* Specify the parent under which to make this window - this seems to + have no effect on Windows because parent_desc is explicitly reset + below. */ if (!NILP (parent)) { /* Cast to UINT_PTR shuts up compiler warnings about cast to @@ -5496,23 +5847,42 @@ This function is an internal primitive--use `make-frame' instead. */) "leftFringe", "LeftFringe", RES_TYPE_NUMBER); x_default_parameter (f, parameters, Qright_fringe, Qnil, "rightFringe", "RightFringe", RES_TYPE_NUMBER); - /* Process alpha here (Bug#16619). */ - x_default_parameter (f, parameters, Qalpha, Qnil, - "alpha", "Alpha", RES_TYPE_NUMBER); + x_default_parameter (f, parameters, Qno_focus_on_map, Qnil, + NULL, NULL, RES_TYPE_BOOLEAN); + x_default_parameter (f, parameters, Qno_accept_focus, Qnil, + NULL, NULL, RES_TYPE_BOOLEAN); + + /* Process alpha here (Bug#16619). On XP this fails with child + frames. For `no-focus-on-map' frames delay processing of alpha + until the frame becomes visible. */ + if (!FRAME_NO_FOCUS_ON_MAP (f)) + x_default_parameter (f, parameters, Qalpha, Qnil, + "alpha", "Alpha", RES_TYPE_NUMBER); /* Init faces first since we need the frame's column width/line height in various occasions. */ init_frame_faces (f); - /* The following call of change_frame_size is needed since otherwise + /* We have to call adjust_frame_size here 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. + 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 ... */ + root window height which was obviously wrong as well ... + + Also process `min-width' and `min-height' parameters right here + because `frame-windows-min-size' needs them. */ + tem = x_get_arg (dpyinfo, parameters, Qmin_width, NULL, NULL, + RES_TYPE_NUMBER); + if (NUMBERP (tem)) + store_frame_param (f, Qmin_width, tem); + tem = x_get_arg (dpyinfo, parameters, Qmin_height, NULL, NULL, + RES_TYPE_NUMBER); + if (NUMBERP (tem)) + store_frame_param (f, Qmin_height, tem); adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f), FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 5, true, Qx_create_frame_1); @@ -5520,10 +5890,17 @@ This function is an internal primitive--use `make-frame' instead. */) /* 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); + if (NILP (parent_frame)) + { + x_default_parameter (f, parameters, Qmenu_bar_lines, + NILP (Vmenu_bar_mode) + ? make_number (0) : make_number (1), + NULL, NULL, RES_TYPE_NUMBER); + } + else + /* No menu bar for child frames. */ + store_frame_param (f, Qmenu_bar_lines, make_number (0)); + x_default_parameter (f, parameters, Qtool_bar_lines, NILP (Vtool_bar_mode) ? make_number (0) : make_number (1), @@ -5534,9 +5911,7 @@ This function is an internal primitive--use `make-frame' instead. */) x_default_parameter (f, parameters, Qtitle, Qnil, "title", "Title", RES_TYPE_STRING); - f->output_data.w32->dwStyle = WS_OVERLAPPEDWINDOW; f->output_data.w32->parent_desc = FRAME_DISPLAY_INFO (f)->root_window; - f->output_data.w32->text_cursor = w32_load_cursor (IDC_IBEAM); f->output_data.w32->nontext_cursor = w32_load_cursor (IDC_ARROW); f->output_data.w32->modeline_cursor = w32_load_cursor (IDC_ARROW); @@ -5601,29 +5976,36 @@ This function is an internal primitive--use `make-frame' instead. */) adjust_frame_size call. */ x_default_parameter (f, parameters, Qfullscreen, Qnil, "fullscreen", "Fullscreen", RES_TYPE_SYMBOL); + x_default_parameter (f, parameters, Qz_group, Qnil, + NULL, NULL, RES_TYPE_SYMBOL); /* Make the window appear on the frame and enable display, unless the caller says not to. However, with explicit parent, Emacs cannot control visibility, so don't try. */ - if (! f->output_data.w32->explicit_parent) + if (!f->output_data.w32->explicit_parent) { - Lisp_Object visibility; - - visibility = x_get_arg (dpyinfo, parameters, Qvisibility, 0, 0, RES_TYPE_SYMBOL); - if (EQ (visibility, Qunbound)) - visibility = Qt; + Lisp_Object visibility + = x_get_arg (dpyinfo, parameters, Qvisibility, 0, 0, RES_TYPE_SYMBOL); if (EQ (visibility, Qicon)) x_iconify_frame (f); - else if (! NILP (visibility)) - x_make_frame_visible (f); else { - /* Must have been Qnil. */ - ; + if (EQ (visibility, Qunbound)) + visibility = Qt; + + if (!NILP (visibility)) + x_make_frame_visible (f); } + + store_frame_param (f, Qvisibility, visibility); } + /* For `no-focus-on-map' frames set alpha here. */ + if (FRAME_NO_FOCUS_ON_MAP (f)) + x_default_parameter (f, parameters, Qalpha, Qnil, + "alpha", "Alpha", RES_TYPE_NUMBER); + /* Initialize `default-minibuffer-frame' in case this is the first frame on this terminal. */ if (FRAME_HAS_MINIBUF_P (f) @@ -6572,8 +6954,6 @@ x_create_tip_frame (struct w32_display_info *dpyinfo, Lisp_Object parms) dpyinfo_refcount = dpyinfo->reference_count; #endif /* GLYPH_DEBUG */ FRAME_KBOARD (f) = kb; - f->output_data.w32->parent_desc = FRAME_DISPLAY_INFO (f)->root_window; - f->output_data.w32->explicit_parent = false; /* Set the name; the functions to which we pass f expect the name to be set. */ @@ -6639,6 +7019,7 @@ x_create_tip_frame (struct w32_display_info *dpyinfo, Lisp_Object parms) f->output_data.w32->dwStyle = WS_BORDER | WS_POPUP | WS_DISABLED; f->output_data.w32->parent_desc = FRAME_DISPLAY_INFO (f)->root_window; + f->output_data.w32->explicit_parent = false; x_figure_window_size (f, parms, true, &x_width, &x_height); @@ -7282,6 +7663,23 @@ file_dialog_callback (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) return 0; } +void +w32_dialog_in_progress (Lisp_Object in_progress) +{ + Lisp_Object frames, frame; + + /* Don't let frames in `above' z-group obscure popups. */ + FOR_EACH_FRAME (frames, frame) + { + struct frame *f = XFRAME (frame); + + if (!NILP (in_progress) && FRAME_Z_GROUP_ABOVE (f)) + x_set_z_group (f, Qabove_suspended, Qabove); + else if (NILP (in_progress) && FRAME_Z_GROUP_ABOVE_SUSPENDED (f)) + x_set_z_group (f, Qabove, Qabove_suspended); + } +} + DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 5, 0, doc: /* Read file name, prompting with PROMPT in directory DIR. Use a file selection dialog. Select DEFAULT-FILENAME in the dialog's file @@ -7513,8 +7911,12 @@ value of DIR as in previous invocations; this is standard Windows behavior. */) { int count = SPECPDL_INDEX (); + + w32_dialog_in_progress (Qt); + /* Prevent redisplay. */ specbind (Qinhibit_redisplay, Qt); + record_unwind_protect (w32_dialog_in_progress, Qnil); block_input (); if (use_unicode) { @@ -8559,6 +8961,136 @@ menu bar or tool bar of FRAME. */) } } +/** + * w32_frame_list_z_order: + * + * Recursively add list of all frames on the display specified via + * DPYINFO and whose window-system window's parent is specified by + * WINDOW to FRAMES and return FRAMES. + */ +static Lisp_Object +w32_frame_list_z_order (struct w32_display_info *dpyinfo, HWND window) +{ + Lisp_Object frame, frames = Qnil; + + while (window) + { + struct frame *f = x_window_to_frame (dpyinfo, window); + + if (f) + { + XSETFRAME (frame, f); + frames = Fcons (frame, frames); + } + + block_input (); + window = GetNextWindow (window, GW_HWNDNEXT); + unblock_input (); + } + + return Fnreverse (frames); +} + +DEFUN ("w32-frame-list-z-order", Fw32_frame_list_z_order, + Sw32_frame_list_z_order, 0, 1, 0, + doc: /* Return list of Emacs' frames, in Z (stacking) order. +The optional argument DISPLAY specifies which display to ask about. +DISPLAY should be either a frame or a display name (a string). If +omitted or nil, that stands for the selected frame's display. + +As a special case, if DISPLAY is non-nil and specifies a live frame, +return the child frames of that frame in Z (stacking) order. + +Frames are listed from topmost (first) to bottommost (last). */) + (Lisp_Object display) +{ + struct w32_display_info *dpyinfo = check_x_display_info (display); + HWND window; + + block_input (); + if (FRAMEP (display) && FRAME_LIVE_P (XFRAME (display))) + window = GetWindow (FRAME_W32_WINDOW (XFRAME (display)), GW_CHILD); + else + window = GetTopWindow (NULL); + unblock_input (); + + return w32_frame_list_z_order (dpyinfo, window); +} + +/** + * w32_frame_restack: + * + * Restack frame F1 below frame F2, above if ABOVE_FLAG is non-nil. In + * practice this is a two-step action: The first step removes F1's + * window-system window from the display. The second step reinserts + * F1's window below (above if ABOVE_FLAG is true) that of F2. + */ +static void +w32_frame_restack (struct frame *f1, struct frame *f2, bool above_flag) +{ + HWND hwnd1 = FRAME_W32_WINDOW (f1); + HWND hwnd2 = FRAME_W32_WINDOW (f2); + + block_input (); + if (above_flag) + /* Put F1 above F2 in the z-order. */ + { + if (GetNextWindow (hwnd1, GW_HWNDNEXT) != hwnd2) + { + /* Make sure F1 is below F2 first because we must not + change the relative position of F2 wrt any other + window but F1. */ + if (GetNextWindow (hwnd2, GW_HWNDNEXT) != hwnd1) + SetWindowPos (hwnd1, hwnd2, 0, 0, 0, 0, + SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE + | SWP_FRAMECHANGED); + /* Now put F1 above F2. */ + SetWindowPos (hwnd2, hwnd1, 0, 0, 0, 0, + SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE + | SWP_FRAMECHANGED); + } + } + else if (GetNextWindow (hwnd2, GW_HWNDNEXT) != hwnd1) + /* Put F1 below F2 in the z-order. */ + SetWindowPos (hwnd1, hwnd2, 0, 0, 0, 0, + SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE + | SWP_FRAMECHANGED); + unblock_input (); +} + +DEFUN ("w32-frame-restack", Fw32_frame_restack, Sw32_frame_restack, 2, 3, 0, + doc: /* Restack FRAME1 below FRAME2. +This means that if both frames are visible and the display areas of +these frames overlap, FRAME2 (partially) obscures FRAME1. If optional +third argument ABOVE is non-nil, restack FRAME1 above FRAME2. This +means that if both frames are visible and the display areas of these +frames overlap, FRAME1 (partially) obscures FRAME2. + +This may be thought of as an atomic action performed in two steps: The +first step removes FRAME1's window-system window from the display. The +second step reinserts FRAME1's window below (above if ABOVE is true) +that of FRAME2. Hence the position of FRAME2 in its display's Z +\(stacking) order relative to all other frames excluding FRAME1 remains +unaltered. + +Some window managers may refuse to restack windows. */) + (Lisp_Object frame1, Lisp_Object frame2, Lisp_Object above) +{ + struct frame *f1 = decode_live_frame (frame1); + struct frame *f2 = decode_live_frame (frame2); + + if (FRAME_W32_P (f1) && FRAME_W32_P (f2)) + { + w32_frame_restack (f1, f2, !NILP (above)); + return Qt; + } + else + { + error ("Cannot restack frames"); + return Qnil; + } +} + 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. @@ -9753,6 +10285,13 @@ frame_parm_handler w32_frame_parm_handlers[] = 0, /* x_set_sticky */ 0, /* x_set_tool_bar_position */ 0, /* x_set_inhibit_double_buffering */ + x_set_undecorated, + x_set_parent_frame, + x_set_skip_taskbar, + x_set_no_focus_on_map, + x_set_no_accept_focus, + x_set_z_group, + 0, /* x_set_override_redirect */ }; void @@ -10132,6 +10671,8 @@ tip frame. */); defsubr (&Sx_display_list); defsubr (&Sw32_frame_geometry); defsubr (&Sw32_frame_edges); + defsubr (&Sw32_frame_list_z_order); + defsubr (&Sw32_frame_restack); defsubr (&Sw32_mouse_absolute_pixel_position); defsubr (&Sw32_set_mouse_absolute_pixel_position); defsubr (&Sx_synchronize); |