diff options
Diffstat (limited to 'src/xfns.c')
-rw-r--r-- | src/xfns.c | 605 |
1 files changed, 559 insertions, 46 deletions
diff --git a/src/xfns.c b/src/xfns.c index d3e0839d8ac..3d667446e67 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -90,6 +90,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ #include <Xm/FileSB.h> #include <Xm/List.h> #include <Xm/TextF.h> +#include <Xm/MwmUtil.h> #endif #ifdef USE_LUCID @@ -117,6 +118,35 @@ static ptrdiff_t image_cache_refcount; static int dpyinfo_refcount; #endif +#ifndef USE_MOTIF +#ifndef USE_GTK +/** #define MWM_HINTS_FUNCTIONS (1L << 0) **/ +#define MWM_HINTS_DECORATIONS (1L << 1) +/** #define MWM_HINTS_INPUT_MODE (1L << 2) **/ +/** #define MWM_HINTS_STATUS (1L << 3) **/ + +#define MWM_DECOR_ALL (1L << 0) +/** #define MWM_DECOR_BORDER (1L << 1) **/ +/** #define MWM_DECOR_RESIZEH (1L << 2) **/ +/** #define MWM_DECOR_TITLE (1L << 3) **/ +/** #define MWM_DECOR_MENU (1L << 4) **/ +/** #define MWM_DECOR_MINIMIZE (1L << 5) **/ +/** #define MWM_DECOR_MAXIMIZE (1L << 6) **/ + +/** #define _XA_MOTIF_WM_HINTS "_MOTIF_WM_HINTS" **/ + +typedef struct { + unsigned long flags; + unsigned long functions; + unsigned long decorations; + long input_mode; + unsigned long status; +} PropMotifWmHints; + +#define PROP_MOTIF_WM_HINTS_ELEMENTS 5 +#endif /* NOT USE_GTK */ +#endif /* NOT USE_MOTIF */ + static struct x_display_info *x_display_info_for_name (Lisp_Object); static void set_up_x_back_buffer (struct frame *f); @@ -185,7 +215,9 @@ x_real_pos_and_offsets (struct frame *f, int win_x = 0, win_y = 0, outer_x = 0, outer_y = 0; int real_x = 0, real_y = 0; bool had_errors = false; - Window win = f->output_data.x->parent_desc; + Window win = (FRAME_PARENT_FRAME (f) + ? FRAME_X_WINDOW (FRAME_PARENT_FRAME (f)) + : f->output_data.x->parent_desc); struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f); long max_len = 400; Atom target_type = XA_CARDINAL; @@ -323,7 +355,8 @@ x_real_pos_and_offsets (struct frame *f, outer_geom_cookie = xcb_get_geometry (xcb_conn, FRAME_OUTER_WINDOW (f)); - if (dpyinfo->root_window == f->output_data.x->parent_desc) + if ((dpyinfo->root_window == f->output_data.x->parent_desc) + && !FRAME_PARENT_FRAME (f)) /* Try _NET_FRAME_EXTENTS if our parent is the root window. */ prop_cookie = xcb_get_property (xcb_conn, 0, win, dpyinfo->Xatom_net_frame_extents, @@ -437,7 +470,8 @@ x_real_pos_and_offsets (struct frame *f, #endif } - if (dpyinfo->root_window == f->output_data.x->parent_desc) + if ((dpyinfo->root_window == f->output_data.x->parent_desc) + && !FRAME_PARENT_FRAME (f)) { /* Try _NET_FRAME_EXTENTS if our parent is the root window. */ #ifdef USE_XCB @@ -735,6 +769,204 @@ x_set_inhibit_double_buffering (struct frame *f, unblock_input (); } +/** + * 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) +{ + if (!EQ (new_value, old_value)) + { + FRAME_UNDECORATED (f) = NILP (new_value) ? false : true; +#ifdef USE_GTK + xg_set_undecorated (f, new_value); +#else + Display *dpy = FRAME_X_DISPLAY (f); + PropMotifWmHints hints; + Atom prop = XInternAtom (dpy, "_MOTIF_WM_HINTS", False); + + memset (&hints, 0, sizeof(hints)); + hints.flags = MWM_HINTS_DECORATIONS; + hints.decorations = NILP (new_value) ? MWM_DECOR_ALL : 0; + + block_input (); + /* For some reason the third and fourth argument in the following + call must be identic: In the corresponding XGetWindowProperty + call in getMotifHints, xfwm has the third and seventh arg both + display_info->atoms[MOTIF_WM_HINTS]. Obviously, YMMV. */ + XChangeProperty (dpy, FRAME_OUTER_WINDOW (f), prop, prop, 32, + PropModeReplace, (unsigned char *) &hints, + PROP_MOTIF_WM_HINTS_ELEMENTS); + unblock_input (); + +#endif /* USE_GTK */ + } +} + +/** + * 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_X_P (p))) + { + store_frame_param (f, Qparent_frame, old_value); + error ("Invalid specification of `parent-frame'"); + } + + if (p != FRAME_PARENT_FRAME (f)) + { + block_input (); + XReparentWindow + (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f), + p ? FRAME_X_WINDOW (p) : DefaultRootWindow (FRAME_X_DISPLAY (f)), + f->left_pos, f->top_pos); + unblock_input (); + + fset_parent_frame (f, 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)) + { +#ifdef USE_GTK + xg_set_no_focus_on_map (f, new_value); +#else /* not USE_GTK */ + Display *dpy = FRAME_X_DISPLAY (f); + Atom prop = XInternAtom (dpy, "_NET_WM_USER_TIME", False); + Time timestamp = NILP (new_value) ? CurrentTime : 0; + + XChangeProperty (dpy, FRAME_OUTER_WINDOW (f), prop, + XA_CARDINAL, 32, PropModeReplace, + (unsigned char *) ×tamp, 1); +#endif /* USE_GTK */ + 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)) + { +#ifdef USE_GTK + xg_set_no_accept_focus (f, new_value); +#else /* not USE_GTK */ +#ifdef USE_X_TOOLKIT + Arg al[1]; + + XtSetArg (al[0], XtNinput, NILP (new_value) ? True : False); + XtSetValues (f->output_data.x->widget, al, 1); +#else /* not USE_X_TOOLKIT */ + Window window = FRAME_X_WINDOW (f); + + f->output_data.x->wm_hints.input = NILP (new_value) ? True : False; + XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints); +#endif /* USE_X_TOOLKIT */ +#endif /* USE_GTK */ + FRAME_NO_ACCEPT_FOCUS (f) = !NILP (new_value); + } +} + +/** + * x_set_override_redirect: + * + * Set frame F's `override_redirect' parameter which, if non-nil, hints + * that the window manager doesn't want to deal with F. Usually, such + * frames have no decorations and always appear on top of all frames. + * + * Some window managers may not honor this parameter. + */ +static void +x_set_override_redirect (struct frame *f, Lisp_Object new_value, Lisp_Object old_value) +{ + if (!EQ (new_value, old_value)) + { + /* Here (xfwm) override_redirect can be changed for invisible + frames only. */ + x_make_frame_invisible (f); + +#ifdef USE_GTK + xg_set_override_redirect (f, new_value); +#else /* not USE_GTK */ + XSetWindowAttributes attributes; + + attributes.override_redirect = NILP (new_value) ? False : True; + XChangeWindowAttributes (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f), + CWOverrideRedirect, &attributes); +#endif + x_make_frame_visible (f); + FRAME_OVERRIDE_REDIRECT (f) = !NILP (new_value); + } +} + + #ifdef USE_GTK /* Set icon from FILE for frame F. By using GTK functions the icon @@ -1272,7 +1504,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 (TYPE_RANGED_INTEGERP (int, value)) @@ -2693,7 +2925,7 @@ x_window (struct frame *f, long window_prompting) and specify it. Note that we do not specify here whether the position is a user-specified or program-specified one. - We pass that information later, in x_wm_set_size_hints. */ + We pass that information later, in x_wm_set_size_hint. */ { int left = f->left_pos; bool xneg = (window_prompting & XNegative) != 0; @@ -2783,7 +3015,8 @@ x_window (struct frame *f, long window_prompting) } #endif /* HAVE_X_I18N */ - attribute_mask = CWEventMask; + attributes.override_redirect = FRAME_OVERRIDE_REDIRECT (f); + attribute_mask = CWEventMask | CWOverrideRedirect; XChangeWindowAttributes (XtDisplay (shell_widget), XtWindow (shell_widget), attribute_mask, &attributes); @@ -2803,6 +3036,25 @@ x_window (struct frame *f, long window_prompting) x_set_name (f, name, explicit); } + if (FRAME_UNDECORATED (f)) + { + Display *dpy = FRAME_X_DISPLAY (f); + PropMotifWmHints hints; + Atom prop = XInternAtom (dpy, "_MOTIF_WM_HINTS", False); + + memset (&hints, 0, sizeof(hints)); + hints.flags = MWM_HINTS_DECORATIONS; + hints.decorations = 0; + + /* For some reason the third and fourth argument in the following + call must be identic: In the corresponding XGetWindowProperty + call in getMotifHints, xfwm has the third and seventh arg both + display_info->atoms[MOTIF_WM_HINTS]. Obviously, YMMV. */ + XChangeProperty (dpy, FRAME_OUTER_WINDOW (f), prop, prop, 32, + PropModeReplace, (unsigned char *) &hints, + PROP_MOTIF_WM_HINTS_ELEMENTS); + } + XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), f->output_data.x->current_cursor = f->output_data.x->text_cursor); @@ -2870,8 +3122,9 @@ x_window (struct frame *f) attributes.save_under = True; attributes.event_mask = STANDARD_EVENT_SET; attributes.colormap = FRAME_X_COLORMAP (f); + attributes.override_redirect = FRAME_OVERRIDE_REDIRECT (f); attribute_mask = (CWBackPixel | CWBorderPixel | CWBitGravity | CWEventMask - | CWColormap); + | CWOverrideRedirect | CWColormap); block_input (); FRAME_X_WINDOW (f) @@ -2943,6 +3196,26 @@ x_window (struct frame *f) x_set_name (f, name, explicit); } + if (FRAME_UNDECORATED (f)) + { + Display *dpy = FRAME_X_DISPLAY (f); + PropMotifWmHints hints; + Atom prop = XInternAtom (dpy, "_MOTIF_WM_HINTS", False); + + memset (&hints, 0, sizeof(hints)); + hints.flags = MWM_HINTS_DECORATIONS; + hints.decorations = 0; + + /* For some reason the third and fourth argument in the following + call must be identic: In the corresponding XGetWindowProperty + call in getMotifHints, xfwm has the third and seventh arg both + display_info->atoms[MOTIF_WM_HINTS]. Obviously, YMMV. */ + XChangeProperty (dpy, FRAME_OUTER_WINDOW (f), prop, prop, 32, + PropModeReplace, (unsigned char *) &hints, + PROP_MOTIF_WM_HINTS_ELEMENTS); + } + + XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), f->output_data.x->current_cursor = f->output_data.x->text_cursor); @@ -3285,11 +3558,12 @@ This function is an internal primitive--use `make-frame' instead. */) Lisp_Object frame, tem; Lisp_Object name; bool minibuffer_only = false; + bool undecorated = false, override_redirect = false; long window_prompting = 0; ptrdiff_t count = SPECPDL_INDEX (); Lisp_Object display; struct x_display_info *dpyinfo = NULL; - Lisp_Object parent; + Lisp_Object parent, parent_frame; struct kboard *kb; int x_width = 0, x_height = 0; @@ -3341,6 +3615,36 @@ This function is an internal primitive--use `make-frame' instead. */) else f = make_frame (true); + parent_frame = x_get_arg (dpyinfo, parms, Qparent_frame, NULL, NULL, + RES_TYPE_SYMBOL); + /* Accept parent-frame iff parent-id was not specified. */ + if (!NILP (parent) + || EQ (parent_frame, Qunbound) + || NILP (parent_frame) + || !FRAMEP (parent_frame) + || !FRAME_LIVE_P (XFRAME (parent_frame)) + || !FRAME_X_P (XFRAME (parent_frame))) + parent_frame = Qnil; + + fset_parent_frame (f, parent_frame); + store_frame_param (f, Qparent_frame, parent_frame); + + if (!NILP (tem = (x_get_arg (dpyinfo, parms, Qundecorated, NULL, NULL, + RES_TYPE_BOOLEAN))) + && !(EQ (tem, Qunbound))) + undecorated = true; + + FRAME_UNDECORATED (f) = undecorated; + store_frame_param (f, Qundecorated, undecorated ? Qt : Qnil); + + if (!NILP (tem = (x_get_arg (dpyinfo, parms, Qoverride_redirect, NULL, NULL, + RES_TYPE_BOOLEAN))) + && !(EQ (tem, Qunbound))) + override_redirect = true; + + FRAME_OVERRIDE_REDIRECT (f) = override_redirect; + store_frame_param (f, Qoverride_redirect, override_redirect ? Qt : Qnil); + XSETFRAME (frame, f); f->terminal = dpyinfo->terminal; @@ -3528,15 +3832,24 @@ This function is an internal primitive--use `make-frame' instead. */) init_iterator with a null face cache, which should not happen. */ 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, parms, Qmin_width, NULL, NULL, RES_TYPE_NUMBER); + if (NUMBERP (tem)) + store_frame_param (f, Qmin_width, tem); + tem = x_get_arg (dpyinfo, parms, 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); @@ -3611,6 +3924,21 @@ This function is an internal primitive--use `make-frame' instead. */) x_default_parameter (f, parms, Qalpha, Qnil, "alpha", "Alpha", RES_TYPE_NUMBER); + if (!NILP (parent_frame)) + { + struct frame *p = XFRAME (parent_frame); + + block_input (); + XReparentWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f), + FRAME_X_WINDOW (p), f->left_pos, f->top_pos); + unblock_input (); + } + + x_default_parameter (f, parms, Qno_focus_on_map, Qnil, + NULL, NULL, RES_TYPE_BOOLEAN); + x_default_parameter (f, parms, Qno_accept_focus, Qnil, + NULL, NULL, RES_TYPE_BOOLEAN); + #if defined (USE_X_TOOLKIT) || defined (USE_GTK) /* Create the menu bar. */ if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f)) @@ -3656,23 +3984,23 @@ This function is an internal primitive--use `make-frame' instead. */) /* 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.x->explicit_parent) + if (!f->output_data.x->explicit_parent) { - Lisp_Object visibility; - - visibility = x_get_arg (dpyinfo, parms, Qvisibility, 0, 0, - RES_TYPE_SYMBOL); - if (EQ (visibility, Qunbound)) - visibility = Qt; + Lisp_Object visibility + = x_get_arg (dpyinfo, parms, 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); } block_input (); @@ -3685,14 +4013,21 @@ This function is an internal primitive--use `make-frame' instead. */) if (dpyinfo->client_leader_window != 0) { XChangeProperty (FRAME_X_DISPLAY (f), - FRAME_OUTER_WINDOW (f), - dpyinfo->Xatom_wm_client_leader, - XA_WINDOW, 32, PropModeReplace, - (unsigned char *) &dpyinfo->client_leader_window, 1); + FRAME_OUTER_WINDOW (f), + dpyinfo->Xatom_wm_client_leader, + XA_WINDOW, 32, PropModeReplace, + (unsigned char *) &dpyinfo->client_leader_window, 1); } unblock_input (); + /* Works iff frame has been already mapped. */ + x_default_parameter (f, parms, Qskip_taskbar, Qnil, + NULL, NULL, RES_TYPE_BOOLEAN); + /* The `z-group' parameter works only for visible frames. */ + x_default_parameter (f, parms, Qz_group, Qnil, + NULL, NULL, RES_TYPE_SYMBOL); + /* Initialize `default-minibuffer-frame' in case this is the first frame on this terminal. */ if (FRAME_HAS_MINIBUF_P (f) @@ -3710,7 +4045,7 @@ This function is an internal primitive--use `make-frame' instead. */) and similar functions. */ Vwindow_list = Qnil; - return unbind_to (count, frame); + return unbind_to (count, frame); } @@ -4644,9 +4979,9 @@ frame_geometry (Lisp_Object frame, Lisp_Object attribute) struct frame *f = decode_live_frame (frame); /** XWindowAttributes atts; **/ Window rootw; - unsigned int ign, native_width, native_height; - int xy_ign, xptr, yptr; - int left_off, right_off, top_off, bottom_off; + unsigned int ign, native_width, native_height, x_border_width = 0; + int x_native = 0, y_native = 0, xptr = 0, yptr = 0; + int left_off = 0, right_off = 0, top_off = 0, bottom_off = 0; int outer_left, outer_top, outer_right, outer_bottom; int native_left, native_top, native_right, native_bottom; int inner_left, inner_top, inner_right, inner_bottom; @@ -4660,25 +4995,51 @@ frame_geometry (Lisp_Object frame, Lisp_Object attribute) block_input (); XGetGeometry (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f), - &rootw, &xy_ign, &xy_ign, &native_width, &native_height, - &ign, &ign); + &rootw, &x_native, &y_native, &native_width, &native_height, + &x_border_width, &ign); /** XGetWindowAttributes (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f), &atts); **/ - x_real_pos_and_offsets (f, &left_off, &right_off, &top_off, &bottom_off, - NULL, NULL, &xptr, &yptr, NULL); + if (!FRAME_PARENT_FRAME (f)) + x_real_pos_and_offsets (f, &left_off, &right_off, &top_off, &bottom_off, + NULL, NULL, &xptr, &yptr, NULL); unblock_input (); /** native_width = atts.width; **/ /** native_height = atts.height; **/ - outer_left = xptr; - outer_top = yptr; - outer_right = outer_left + left_off + native_width + right_off; - outer_bottom = outer_top + top_off + native_height + bottom_off; + if (FRAME_PARENT_FRAME (f)) + { + Lisp_Object parent, edges; + + XSETFRAME (parent, FRAME_PARENT_FRAME (f)); + edges = Fx_frame_edges (parent, Qnative_edges); + if (!NILP (edges)) + { + x_native += XINT (Fnth (make_number (0), edges)); + y_native += XINT (Fnth (make_number (1), edges)); + } + + outer_left = x_native; + outer_top = y_native; + outer_right = outer_left + native_width + 2 * x_border_width; + outer_bottom = outer_top + native_height + 2 * x_border_width; + + native_left = x_native + x_border_width; + native_top = y_native + x_border_width; + native_right = native_left + native_width; + native_bottom = native_top + native_height; + } + else + { + outer_left = xptr; + outer_top = yptr; + outer_right = outer_left + left_off + native_width + right_off; + outer_bottom = outer_top + top_off + native_height + bottom_off; - native_left = outer_left + left_off; - native_top = outer_top + top_off; - native_right = native_left + native_width; - native_bottom = native_top + native_height; + native_left = outer_left + left_off; + native_top = outer_top + top_off; + native_right = native_left + native_width; + native_bottom = native_top + native_height; + } internal_border_width = FRAME_INTERNAL_BORDER_WIDTH (f); inner_left = native_left + internal_border_width; @@ -4749,7 +5110,7 @@ frame_geometry (Lisp_Object frame, Lisp_Object attribute) make_number (inner_right), make_number (inner_bottom)); else return - listn (CONSTYPE_HEAP, 10, + listn (CONSTYPE_HEAP, 11, Fcons (Qouter_position, Fcons (make_number (outer_left), make_number (outer_top))), @@ -4760,6 +5121,7 @@ frame_geometry (Lisp_Object frame, Lisp_Object attribute) Fcons (Qexternal_border_size, Fcons (make_number (right_off), make_number (bottom_off))), + Fcons (Qouter_border_width, make_number (x_border_width)), /* Approximate. */ Fcons (Qtitle_bar_size, Fcons (make_number (0), @@ -4788,7 +5150,8 @@ and width values are in pixels. `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. + any menu and/or tool bar of frame. For a child frame the value + includes FRAME's X borders, if any. `external-border-size' is a cons of the horizontal and vertical width of FRAME's external borders as supplied by the window manager. @@ -4815,7 +5178,11 @@ and width values are in pixels. FRAME. `internal-border-width' is the width of the internal border of - FRAME. */) + FRAME. + +`outer-border-width' is the width of the X border of FRAME. The X + border is usually only shown for frames without window manager + decorations like child and tooltip frames. */) (Lisp_Object frame) { return frame_geometry (frame, Qnil); @@ -4845,6 +5212,139 @@ menu bar or tool bar of FRAME. */) : Qnative_edges)); } +/** + * x_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 +x_frame_list_z_order (Display* dpy, Window window) +{ + Window root, parent, *children; + unsigned int nchildren; + int i; + Lisp_Object frames = Qnil; + + block_input (); + if (XQueryTree (dpy, window, &root, &parent, &children, &nchildren)) + { + unblock_input (); + for (i = 0; i < nchildren; i++) + { + Lisp_Object frame, tail; + + FOR_EACH_FRAME (tail, frame) + /* With a reparenting window manager the parent_desc field + usually specifies the topmost windows of our frames. + Otherwise FRAME_OUTER_WINDOW should do. */ + if (XFRAME (frame)->output_data.x->parent_desc == children[i] + || FRAME_OUTER_WINDOW (XFRAME (frame)) == children[i]) + frames = Fcons (frame, frames); + } + + if (children) XFree ((char *)children); + } + else + unblock_input (); + + return frames; +} + + +DEFUN ("x-frame-list-z-order", Fx_frame_list_z_order, + Sx_frame_list_z_order, 0, 1, 0, + doc: /* Return list of Emacs' frames, in Z (stacking) order. +The optional argument TERMINAL specifies which display to ask about. +TERMINAL should be either a frame or a display name (a string). If +omitted or nil, that stands for the selected frame's display. Return +nil if TERMINAL contains no Emacs frame. + +As a special case, if TERMINAL 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 terminal) +{ + struct x_display_info *dpyinfo = check_x_display_info (terminal); + Display *dpy = dpyinfo->display; + Window window; + + if (FRAMEP (terminal) && FRAME_LIVE_P (XFRAME (terminal))) + window = FRAME_X_WINDOW (XFRAME (terminal)); + else + window = dpyinfo->root_window; + + return x_frame_list_z_order (dpy, window); +} + +/** + * x_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 +x_frame_restack (struct frame *f1, struct frame *f2, bool above_flag) +{ +#ifdef USE_GTK + block_input (); + xg_frame_restack (f1, f2, above_flag); + unblock_input (); +#else + Display *dpy = FRAME_X_DISPLAY (f1); + Window window1 = FRAME_OUTER_WINDOW (f1); + XWindowChanges wc; + unsigned long mask = (CWSibling | CWStackMode); + + wc.sibling = FRAME_OUTER_WINDOW (f2); + wc.stack_mode = above_flag ? Above : Below; + block_input (); + /* Configure the window manager window (a normal XConfigureWindow + won't cut it). This should also work for child frames. */ + XReconfigureWMWindow (dpy, window1, FRAME_X_SCREEN_NUMBER (f1), mask, &wc); + unblock_input (); +#endif /* USE_GTK */ +} + + +DEFUN ("x-frame-restack", Fx_frame_restack, Sx_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-step 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_OUTER_WINDOW (f1) && FRAME_OUTER_WINDOW (f2)) + { + x_frame_restack (f1, f2, !NILP (above)); + return Qt; + } + else + { + error ("Cannot restack frames"); + return Qnil; + } +} + + DEFUN ("x-mouse-absolute-pixel-position", Fx_mouse_absolute_pixel_position, Sx_mouse_absolute_pixel_position, 0, 0, 0, doc: /* Return absolute position of mouse cursor in pixels. @@ -6585,6 +7085,8 @@ value of DIR as in previous invocations; this is standard Windows behavior. */) if (popup_activated ()) error ("Trying to use a menu from within a menu-entry"); + else + x_menu_set_in_use (true); CHECK_STRING (prompt); CHECK_STRING (dir); @@ -6641,6 +7143,8 @@ nil, it defaults to the selected frame. */) if (popup_activated ()) error ("Trying to use a menu from within a menu-entry"); + else + x_menu_set_in_use (true); /* Prevent redisplay. */ specbind (Qinhibit_redisplay, Qt); @@ -6979,6 +7483,13 @@ frame_parm_handler x_frame_parm_handlers[] = x_set_sticky, x_set_tool_bar_position, 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, + x_set_override_redirect, }; void @@ -7183,6 +7694,8 @@ When using Gtk+ tooltips, the tooltip face is not used. */); defsubr (&Sx_display_monitor_attributes_list); defsubr (&Sx_frame_geometry); defsubr (&Sx_frame_edges); + defsubr (&Sx_frame_list_z_order); + defsubr (&Sx_frame_restack); defsubr (&Sx_mouse_absolute_pixel_position); defsubr (&Sx_set_mouse_absolute_pixel_position); defsubr (&Sx_wm_set_size_hint); |