emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] master 3fdd3bb: Add new frame parameters and associated fu


From: Martin Rudalics
Subject: [Emacs-diffs] master 3fdd3bb: Add new frame parameters and associated functions
Date: Wed, 12 Apr 2017 04:40:28 -0400 (EDT)

branch: master
commit 3fdd3bb56c006a2a24761b8fcea0cbd9b0cba422
Author: Martin Rudalics <address@hidden>
Commit: Martin Rudalics <address@hidden>

    Add new frame parameters and associated functions
    
    Add new frame parameters `undecorated', `override-redirect',
    `parent-frame', `skip-taskbar', `no-focus-on-map',
    `no-accept-focus', `z-group', `delete-before', `no-other-frame',
    `mouse-wheel-frame', `min-width', `min-height'.  Add new
    functions `frame-restack' and `frame-list-z-order'.
    
    * lisp/cus-start.el (focus-follows-mouse): Adapt customization
    type.
    * lisp/frame.el (handle-delete-frame): Handle child and
    `delete-before' frames.
    (other-frame): Stop looking for other frame after one round.
    (frame-list-z-order, frame-restack): New functions.
    (delete-other-frames): Handle child frames.
    * lisp/frameset.el (frameset-persistent-filter-alist)
    (frameset--record-relationships): Handle `delete-before',
    `parent-frame' and `mouse-wheel-frame' parameters.  Rename
    latter from `frameset--record-minibuffer-relationships'.
    (frameset--restore-frame): Handle ‘parent-frame’ parameter
    specially.
    (frameset-restore): Handle `delete-before', `parent-frame' and
    `mouse-wheel-frame' parameters.
    * lisp/mwheel.el (mwheel-scroll): Handle `mouse-wheel-frame'
    parameter.
    * lisp/window.el (window--min-size-ignore-p): Fix doc-string.
    (mouse-autoselect-window-select, handle-select-window): Major
    rewrite.  Try to not ignore errors.  Handle auto-selection of
    child frames and different values of `focus-follows-mouse'.
    * src/frame.c (frame_windows_min_size): Handle new `min-width'
    and `min-height' frame parameters.
    (make_frame): Initialize new frame structure members.
    (do_switch_frame): Don't reset internal_last_event_frame for
    descendant frames.
    (Fframe_parent, frame_ancestor_p, Fframe_ancestor_p): New
    functions.
    (candidate_frame): Don't return `no-other-frame' frame.
    (other_frames): New function replacing other_visible_frames.
    (delete_frame): Rewrite.  Handle child and `delete-before' frames.
    (Fmake_frame_invisible): Call other_frames.
    (store_frame_param): Check `delete-before' and `parent-frame'
    parameters for circular dependencies.
    (frame_parms, syms_of_frame): Add entries for and define new
    frame parameters.
    (focus_follows_mouse): New meaningful value `auto-raise'.
    * src/frame.h (z_group): New enumeration type.
    (frame): New slots parent_frame, undecorated, override_redirect,
    skip_taskbar, no_focus_on_map, no_accept_focus, z_group.
    (fset_parent_frame): New inlined function.
    (FRAME_UNDECORATED, FRAME_OVERRIDE_REDIRECT)
    (FRAME_PARENT_FRAME, FRAME_SKIP_TASKBAR, FRAME_NO_FOCUS_ON_MAP)
    (FRAME_NO_ACCEPT_FOCUS, FRAME_Z_GROUP, FRAME_Z_GROUP_NONE)
    (FRAME_Z_GROUP_ABOVE, FRAME_Z_GROUP_ABOVE_SUSPENDED)
    (FRAME_Z_GROUP_BELOW): New macros.
    (frame_ancestor_p): Add declaration.
    * src/gtkutil.c (xg_create_frame_widgets): Handle
    `undecorated' and `override-redirect' frame parameters.
    (x_wm_set_size_hint): None for child frames.
    (xg_set_undecorated, xg_frame_restack, xg_set_skip_taskbar)
    (xg_set_no_focus_on_map, xg_set_no_accept_focus)
    (xg_set_override_redirect): New functions.
    (xg_update_scrollbar_pos, xg_update_horizontal_scrollbar_pos):
    Don't let scrollbars obscure child frames.
    * src/gtkutil.h: (xg_set_undecorated, xg_frame_restack)
    (xg_set_skip_taskbar, xg_set_no_focus_on_map)
    (xg_set_no_accept_focus, xg_set_override_redirect): Add extern
    declarations.
    * src/nsfns.m (ns_frame_parm_handlers): Add entries for new
    frame parameters.
    (Fx_create_frame): Install `min-width' and `min-height' frame
    parameters.
    * src/nsterm.m (mouseMoved:): Handle focus_follows_mouse change.
    * src/w32fns.c (WS_EX_NOACTIVATE): Define if necessary.
    (x_real_positions): Handle child frames.
    (x_set_menu_bar_lines): Don't for child frames.
    (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): New functions.
    (w32_createvscrollbar, w32_createhscrollbar): Don't draw
    scroll bars over child frames.
    (w32_createwindow): Handle new frame parameters and child frames.
    (w32_wnd_proc): Let mouse clicks into a child frame activate
    the frame.  Try to handle the `no-accept-focus' parameter.  Do
    SetFocus when our window is brought to top or becomes the
    foreground window.
    (w32_window): Don't initialize menu bar for child frames.
    (Fx_create_frame): Handle new frame parameters.
    (x_create_tip_frame): Set explicit_parent slot.
    (w32_dialog_in_progress): New function.
    (Fx_file_dialog): Handle `z-group-above' frames.
    (w32_frame_list_z_order, Fw32_frame_list_z_order)
    (w32_frame_restack, Fw32_frame_restack): New functions.
    (w32_frame_parm_handlers): Add entries for new frame
    parameters.
    * src/w32font.c (Fx_select_font): Handle `z-group-above'
    frames during font selection dialogue.
    * src/w32term.c (construct_mouse_wheel): Construct mouse wheel
    event from F's w32 window.
    (w32_mouse_position): Handle child frames.
    (w32_set_vertical_scroll_bar, w32_set_horizontal_scroll_bar):
    Don't draw scroll bars over child frames.
    (w32_read_socket): Always erase background of child frames.
    When generating SELECT_WINDOW_EVENTs handle new value of
    `focus-follows-mouse' and handle `no-accept-focus' parameter.
    Handle `mouse-wheel-frame' parameter.
    (x_calc_absolute_position, x_set_offset, x_set_window_size):
    Handle child frames.
    (x_make_frame_visible): Handle child frames specially.  Handle
    `no-focus-on-map' parameter.
    * src/w32term.h (w32_dialog_in_progress): Add external
    declaration.
    * src/xdisp.c (x_consider_frame_title, prepare_menu_bars): Not
    for child frames.
    * src/xfns.c (Xm/MwmUtil.h): Include for WM hints.
    (PropMotifWmHints, PROP_MOTIF_WM_HINTS_ELEMENTS): Define for
    non-Motif, non-GTK case.
    (x_real_pos_and_offsets): Handle child frames.
    (x_set_undecorated, x_set_parent_frame)
    (x_set_no_focus_on_map, x_set_no_accept_focus)
    (x_set_override_redirect): New functions.
    (x_set_menu_bar_lines): Not for child frames.
    (x_window): Handle `undecorated' and `override_redirect' cases.
    (Fx_create_frame): Handle new frame parameters.
    (frame_geometry): Handle child frames and outer border.
    (x_frame_list_z_order, Fx_frame_list_z_order)
    (x_frame_restack, Fx_frame_restack): New functions.
    (Fx_file_dialog, Fx_select_font): Set x_menu_set_in_use.
    (x_frame_parm_handlers): Add entries for new frame parameters.
    * src/xmenu.c (x_menu_set_in_use): Handle `z-group-above'
    frames.
    * src/xterm.c (x_set_frame_alpha): Don't set alpha of parent
    for child frames.
    (XTmouse_position): Handle child frames.
    (x_scroll_bar_create, x_scroll_bar_expose): Don't let scroll
    bars obscure child frames.
    (handle_one_xevent): Handle child frame positions.  If necessary
    set `skip-taskbar' and reassign proper `z-group' when we are
    mapped.  When generating SELECT_WINDOW_EVENTs handle new value
    of `focus-follows-mouse'.  Handle `mouse-wheel-frame' parameter.
    Let mouse clicks into a child frame activate the frame.
    (x_calc_absolute_position, x_set_offset): Handle child frames
    specially.
    (x_set_skip_taskbar, x_set_z_group): New functions.
    (x_make_frame_visible): Handle child frames.
    (ATOM_REFS_INIT): Add entries for
    Xatom_net_wm_state_skip_taskbar, Xatom_net_wm_state_above,
    Xatom_net_wm_state_below.
    * src/xterm.h (top-level): Declare Xatom_net_wm_state_above,
    Xatom_net_wm_state_below and Xatom_net_wm_state_skip_taskbar.
    (x_set_skip_taskbar, x_set_z_group): Add extern declarations.
---
 lisp/cus-start.el |   6 +-
 lisp/frame.el     | 117 ++++++++--
 lisp/frameset.el  | 100 +++++++--
 lisp/mwheel.el    |  59 +++--
 lisp/window.el    | 169 +++++++-------
 src/frame.c       | 402 +++++++++++++++++++++++++++------
 src/frame.h       |  86 ++++++-
 src/gtkutil.c     | 135 ++++++++++-
 src/gtkutil.h     |   7 +
 src/nsfns.m       |  13 ++
 src/nsterm.m      |   2 +-
 src/w32fns.c      | 659 +++++++++++++++++++++++++++++++++++++++++++++++++-----
 src/w32font.c     |  19 +-
 src/w32term.c     | 200 ++++++++++++-----
 src/w32term.h     |   1 +
 src/xdisp.c       |   6 +
 src/xfns.c        | 605 +++++++++++++++++++++++++++++++++++++++++++++----
 src/xmenu.c       |  14 +-
 src/xterm.c       | 389 ++++++++++++++++++++++++++------
 src/xterm.h       |   8 +-
 20 files changed, 2543 insertions(+), 454 deletions(-)

diff --git a/lisp/cus-start.el b/lisp/cus-start.el
index 51c43c7..a507e30 100644
--- a/lisp/cus-start.el
+++ b/lisp/cus-start.el
@@ -286,7 +286,11 @@ Leaving \"Default\" unchecked is equivalent with 
specifying a default of
             ;; fns.c
             (use-dialog-box menu boolean "21.1")
             (use-file-dialog menu boolean "22.1")
-            (focus-follows-mouse frames boolean "20.3")
+            (focus-follows-mouse
+              frames (choice
+                      (const :tag "Off (nil)" :value nil)
+                      (const :tag "On (t)" :value t)
+                      (const :tag "Auto-raise" :value auto-raise)) "26.1")
             ;; fontset.c
             ;; FIXME nil is the initial value, fontset.el setqs it.
             (vertical-centering-font-regexp display
diff --git a/lisp/frame.el b/lisp/frame.el
index 4768b5b..86a0e26 100644
--- a/lisp/frame.el
+++ b/lisp/frame.el
@@ -115,15 +115,19 @@ appended when the minibuffer frame is created."
 (defun handle-delete-frame (event)
   "Handle delete-frame events from the X server."
   (interactive "e")
-  (let ((frame (posn-window (event-start event)))
-       (i 0)
-       (tail (frame-list)))
-    (while tail
-      (and (frame-visible-p (car tail))
-          (not (eq (car tail) frame))
-         (setq i (1+ i)))
-      (setq tail (cdr tail)))
-    (if (> i 0)
+  (let* ((frame (posn-window (event-start event))))
+    (if (catch 'other-frame
+          (dolist (frame-1 (frame-list))
+            ;; A valid "other" frame is visible, owns its minibuffer
+            ;; window, has its `delete-before' parameter unset and is
+            ;; not a child frame.
+            (when (and (not (eq frame-1 frame))
+                       (frame-visible-p frame-1)
+                       (window-live-p (minibuffer-window frame-1))
+                       (eq (window-frame (minibuffer-window frame-1)) frame-1)
+                       (not (frame-parent frame-1))
+                       (not (frame-parameter frame-1 'delete-before)))
+              (throw 'other-frame t))))
        (delete-frame frame t)
       ;; address@hidden says it is ok to ask questions before terminating.
       (save-buffers-kill-emacs))))
@@ -834,21 +838,24 @@ All frames are arranged in a cyclic order.
 This command selects the frame ARG steps away in that order.
 A negative ARG moves in the opposite order.
 
-To make this command work properly, you must tell Emacs
-how the system (or the window manager) generally handles
-focus-switching between windows.  If moving the mouse onto a window
-selects it (gives it focus), set `focus-follows-mouse' to t.
-Otherwise, that variable should be nil."
+To make this command work properly, you must tell Emacs how the
+system (or the window manager) generally handles focus-switching
+between windows.  If moving the mouse onto a window selects
+it (gives it focus), set `focus-follows-mouse' to t.  Otherwise,
+that variable should be nil."
   (interactive "p")
-  (let ((frame (selected-frame)))
+  (let ((sframe (selected-frame))
+        (frame (selected-frame)))
     (while (> arg 0)
       (setq frame (next-frame frame))
-      (while (not (eq (frame-visible-p frame) t))
+      (while (and (not (eq frame sframe))
+                  (not (eq (frame-visible-p frame) t)))
        (setq frame (next-frame frame)))
       (setq arg (1- arg)))
     (while (< arg 0)
       (setq frame (previous-frame frame))
-      (while (not (eq (frame-visible-p frame) t))
+      (while (and (not (eq frame sframe))
+                  (not (eq (frame-visible-p frame) t)))
        (setq frame (previous-frame frame)))
       (setq arg (1+ arg)))
     (select-frame-set-input-focus frame)))
@@ -1380,6 +1387,7 @@ and width values are in pixels.
        '(outer-position 0 . 0)
        (cons 'outer-size (cons (frame-width frame) (frame-height frame)))
        '(external-border-size 0 . 0)
+       '(outer-border-width . 0)
        '(title-bar-size 0 . 0)
        '(menu-bar-external . nil)
        (let ((menu-bar-lines (frame-parameter frame 'menu-bar-lines)))
@@ -1490,6 +1498,59 @@ keys and their meanings."
           for frames = (cdr (assq 'frames attributes))
           if (memq frame frames) return attributes))
 
+(declare-function x-frame-list-z-order "xfns.c" (&optional display))
+(declare-function w32-frame-list-z-order "w32fns.c" (&optional display))
+
+(defun frame-list-z-order (&optional display)
+  "Return list of Emacs' frames, in Z (stacking) order.
+The optional argument DISPLAY specifies which display to poll.
+DISPLAY should be either a frame or a display name (a string).
+If omitted or nil, that stands for the selected frame's display.
+
+Frames are listed from topmost (first) to bottommost (last).  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.
+
+Return nil if DISPLAY contains no Emacs frame."
+  (let ((frame-type (framep-on-display display)))
+    (cond
+     ((eq frame-type 'x)
+      (x-frame-list-z-order display))
+     ((eq frame-type 'w32)
+      (w32-frame-list-z-order display)))))
+
+(declare-function x-frame-restack "xfns.c" (frame1 frame2 &optional above))
+(declare-function w32-frame-restack "w32fns.c" (frame1 frame2 &optional above))
+
+(defun frame-restack (frame1 frame2 &optional above)
+  "Restack FRAME1 below FRAME2.
+This implies that if both frames are visible and the display
+areas of these frames overlap, FRAME2 will (partially) obscure
+FRAME1.  If the 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 will
+\(partially) obscure 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. "
+  (if (and (frame-live-p frame1)
+           (frame-live-p frame2)
+           (equal (frame-parameter frame1 'display)
+                  (frame-parameter frame2 'display)))
+      (let ((frame-type (framep-on-display frame1)))
+        (cond
+         ((eq frame-type 'x)
+          (x-frame-restack frame1 frame2 above))
+         ((eq frame-type 'w32)
+          (w32-frame-restack frame1 frame2 above))))
+    (error "Cannot restack frames")))
+
 (defun frame-size-changed-p (&optional frame)
   "Return non-nil when the size of FRAME has changed.
 More precisely, return non-nil when the inner width or height of
@@ -1886,7 +1947,7 @@ A geometry specification equivalent to SPEC for FRAME is 
returned,
 where the value is a cons with car `+', not numeric.
 SPEC is a frame geometry spec: (left . VALUE) or (top . VALUE).
 If VALUE is a number, then it is converted to a cons value, perhaps
-   relative to the opposite frame edge from that in the original spec.
+relative to the opposite frame edge from that in the original spec.
 FRAME defaults to the selected frame.
 
 Examples (measures in pixels) -
@@ -1907,24 +1968,36 @@ the opposite frame edge from the edge indicated in the 
input spec."
 (defun delete-other-frames (&optional frame)
   "Delete all frames on FRAME's terminal, except FRAME.
 If FRAME uses another frame's minibuffer, the minibuffer frame is
-left untouched.  FRAME must be a live frame and defaults to the
-selected one."
+left untouched.  Do not delete any of FRAME's child frames.  If
+FRAME is a child frame, delete its siblings only.  FRAME must be
+a live frame and defaults to the selected one."
   (interactive)
   (setq frame (window-normalize-frame frame))
   (let ((minibuffer-frame (window-frame (minibuffer-window frame)))
         (this (next-frame frame t))
+        (parent (frame-parent frame))
         next)
     ;; In a first round consider minibuffer-less frames only.
     (while (not (eq this frame))
       (setq next (next-frame this t))
-      (unless (eq (window-frame (minibuffer-window this)) this)
+      (unless (or (eq (window-frame (minibuffer-window this)) this)
+                  ;; When FRAME is a child frame, delete its siblings
+                  ;; only.
+                  (and parent (not (eq (frame-parent this) parent)))
+                  ;; Do not delete a child frame of FRAME.
+                  (eq (frame-parent this) frame))
         (delete-frame this))
       (setq this next))
     ;; In a second round consider all remaining frames.
     (setq this (next-frame frame t))
     (while (not (eq this frame))
       (setq next (next-frame this t))
-      (unless (eq this minibuffer-frame)
+      (unless (or (eq this minibuffer-frame)
+                  ;; When FRAME is a child frame, delete its siblings
+                  ;; only.
+                  (and parent (not (eq (frame-parent this) parent)))
+                  ;; Do not delete a child frame of FRAME.
+                  (eq (frame-parent this) frame))
         (delete-frame this))
       (setq this next))))
 
diff --git a/lisp/frameset.el b/lisp/frameset.el
index 2dd3050..ebf09d3 100644
--- a/lisp/frameset.el
+++ b/lisp/frameset.el
@@ -446,6 +446,7 @@ DO NOT MODIFY.  See `frameset-filter-alist' for a full 
description.")
      (buffer-list        . :never)
      (buffer-predicate   . :never)
      (buried-buffer-list . :never)
+     (delete-before      . :never)
      (font               . frameset-filter-shelve-param)
      (foreground-color   . frameset-filter-sanitize-color)
      (fullscreen         . frameset-filter-shelve-param)
@@ -455,7 +456,9 @@ DO NOT MODIFY.  See `frameset-filter-alist' for a full 
description.")
      (GUI:width          . frameset-filter-unshelve-param)
      (height             . frameset-filter-shelve-param)
      (outer-window-id    . :never)
+     (parent-frame       . :never)
      (parent-id          . :never)
+     (mouse-wheel-frame  . :never)
      (tty                . frameset-filter-tty-to-GUI)
      (tty-type           . frameset-filter-tty-to-GUI)
      (width              . frameset-filter-shelve-param)
@@ -717,9 +720,18 @@ If nil, check all live frames."
 
 ;; Saving framesets
 
-(defun frameset--record-minibuffer-relationships (frame-list)
-  "Process FRAME-LIST and record minibuffer relationships.
-FRAME-LIST is a list of frames.  Internal use only."
+(defun frameset--record-relationships (frame-list)
+  "Process FRAME-LIST and record relationships.
+FRAME-LIST is a list of frames.
+
+The relationships recorded for each frame are
+
+- `minibuffer' via `frameset--mini'
+- `delete-before' via `frameset--delete-before'
+- `parent-frame' via `frameset--parent-frame'
+- `mouse-wheel-frame' via `frameset--mouse-wheel-frame'
+
+Internal use only."
   ;; Record frames with their own minibuffer
   (dolist (frame (minibuffer-frame-list))
     (when (memq frame frame-list)
@@ -730,22 +742,41 @@ FRAME-LIST is a list of frames.  Internal use only."
       (set-frame-parameter frame
                           'frameset--mini
                           (cons t (eq frame default-minibuffer-frame)))))
-  ;; Now link minibufferless frames with their minibuffer frames
+  ;; Now link minibufferless frames with their minibuffer frames and
+  ;; store `parent-frame', `delete-before' and `mouse-wheel-frame'
+  ;; relationships in a similar way.
   (dolist (frame frame-list)
-    (unless (frame-parameter frame 'frameset--mini)
-      (frameset--set-id frame)
-      (let ((mb-frame (window-frame (minibuffer-window frame))))
-       ;; For minibufferless frames, frameset--mini is a cons
-       ;; (nil . FRAME-ID), where FRAME-ID is the frameset--id of
-       ;; the frame containing its minibuffer window.
-       ;; FRAME-ID can be set to nil, if FRAME-LIST doesn't contain
-       ;; the minibuffer frame of a minibufferless frame; we allow
-       ;; it without trying to second-guess the user.
-       (set-frame-parameter frame
-                            'frameset--mini
-                            (cons nil
-                                  (and mb-frame
-                                       (frameset-frame-id mb-frame))))))))
+    (let ((parent-frame (frame-parent frame))
+          (delete-before (frame-parameter frame 'delete-before))
+          (mouse-wheel-frame (frame-parameter frame 'mouse-wheel-frame))
+          (nomini (not (frame-parameter frame 'frameset--mini))))
+      (when (or nomini parent-frame delete-before mouse-wheel-frame)
+        (when nomini
+          (frameset--set-id frame))
+        (when parent-frame
+          (set-frame-parameter
+           frame 'frameset--parent-frame (frameset-frame-id parent-frame)))
+        (when delete-before
+          (set-frame-parameter
+           frame 'frameset--delete-before (frameset-frame-id delete-before)))
+        (when mouse-wheel-frame
+          (set-frame-parameter
+           frame 'frameset--mouse-wheel-frame
+           (frameset-frame-id mouse-wheel-frame)))
+        (when nomini
+          (let ((mb-frame (window-frame (minibuffer-window frame))))
+            ;; For minibufferless frames, frameset--mini is a cons
+            ;; (nil . FRAME-ID), where FRAME-ID is the frameset--id of
+            ;; the frame containing its minibuffer window.
+            ;; FRAME-ID can be set to nil, if FRAME-LIST doesn't contain
+            ;; the minibuffer frame of a minibufferless frame; we allow
+            ;; it without trying to second-guess the user.
+            (set-frame-parameter
+             frame
+             'frameset--mini
+             (cons nil
+                   (and mb-frame
+                        (frameset-frame-id mb-frame))))))))))
 
 ;;;###autoload
 (cl-defun frameset-save (frame-list
@@ -768,7 +799,7 @@ PROPERTIES is a user-defined property list to add to the 
frameset."
                                       (cl-delete-if-not predicate list)
                                     list)))
         fs)
-    (frameset--record-minibuffer-relationships frames)
+    (frameset--record-relationships frames)
     (setq fs (frameset--make
              :app app
              :name name
@@ -993,6 +1024,14 @@ Internal use only."
                                               (frameset--initial-params 
filtered-cfg))))
       (puthash frame :created frameset--action-map))
 
+    ;; Try to assign parent-frame right here - it will improve things
+    ;; for minibuffer-less child frames.
+    (let* ((frame-id (frame-parameter frame 'frameset--parent-frame))
+           (parent-frame
+            (and frame-id (frameset-frame-with-id frame-id))))
+      (when (frame-live-p parent-frame)
+        (set-frame-parameter frame 'parent-frame parent-frame)))
+
     (modify-frame-parameters frame
                             (if (eq (frame-parameter frame 'fullscreen) 
fullscreen)
                                 ;; Workaround for bug#14949
@@ -1205,6 +1244,29 @@ All keyword parameters default to nil."
            (error
             (delay-warning 'frameset (error-message-string err) :error))))))
 
+    ;; Setting the parent frame after the frame has been created is a
+    ;; pain because one can see the frame move on the screen.  Ideally,
+    ;; we would restore minibuffer equipped child frames after their
+    ;; respective parents have been made but this might interfere with
+    ;; the reordering of minibuffer frames.  Left to the experts ...
+    (dolist (frame (frame-list))
+      (let* ((frame-id (frame-parameter frame 'frameset--parent-frame))
+             (parent-frame
+              (and frame-id (frameset-frame-with-id frame-id))))
+        (when (and (not (eq (frame-parameter frame 'parent-frame) 
parent-frame))
+                   (frame-live-p parent-frame))
+          (set-frame-parameter frame 'parent-frame parent-frame)))
+      (let* ((frame-id (frame-parameter frame 'frameset--delete-before))
+             (delete-before
+              (and frame-id (frameset-frame-with-id frame-id))))
+        (when (frame-live-p delete-before)
+          (set-frame-parameter frame 'delete-before delete-before)))
+      (let* ((frame-id (frame-parameter frame 'frameset--mouse-wheel-frame))
+             (mouse-wheel-frame
+              (and frame-id (frameset-frame-with-id frame-id))))
+        (when (frame-live-p mouse-wheel-frame)
+          (set-frame-parameter frame 'mouse-wheel-frame mouse-wheel-frame))))
+
     ;; In case we try to delete the initial frame, we want to make sure that
     ;; other frames are already visible (discussed in thread for bug#14841).
     (sit-for 0 t)
diff --git a/lisp/mwheel.el b/lisp/mwheel.el
index eaeb831..958c6e8 100644
--- a/lisp/mwheel.el
+++ b/lisp/mwheel.el
@@ -190,14 +190,33 @@ This can be slightly disconcerting, but some people 
prefer it."
 This should be bound only to mouse buttons 4 and 5 on non-Windows
 systems."
   (interactive (list last-input-event))
-  (let* ((curwin (if mouse-wheel-follow-mouse
-                     (prog1
-                         (selected-window)
-                       (select-window (mwheel-event-window event)))))
-        (buffer (window-buffer curwin))
-        (opoint (with-current-buffer buffer
-                  (when (eq (car-safe transient-mark-mode) 'only)
-                    (point))))
+  (let* ((selected-window (selected-window))
+         (scroll-window
+          (or (catch 'found
+                (let* ((window (if mouse-wheel-follow-mouse
+                                   (mwheel-event-window event)
+                                 (selected-window)))
+                       (frame (when (window-live-p window)
+                                (frame-parameter
+                                 (window-frame window) 'mouse-wheel-frame))))
+                  (when (frame-live-p frame)
+                    (let* ((pos (mouse-absolute-pixel-position))
+                           (pos-x (car pos))
+                           (pos-y (cdr pos)))
+                      (walk-window-tree
+                       (lambda (window-1)
+                         (let ((edges (window-edges window-1 nil t t)))
+                           (when (and (<= (nth 0 edges) pos-x)
+                                      (<= pos-x (nth 2 edges))
+                                      (<= (nth 1 edges) pos-y)
+                                      (<= pos-y (nth 3 edges)))
+                             (throw 'found window-1))))
+                       frame nil t)))))
+              (mwheel-event-window event)))
+        (old-point
+          (and (eq scroll-window selected-window)
+              (eq (car-safe transient-mark-mode) 'only)
+              (window-point)))
          (mods
          (delq 'click (delq 'double (delq 'triple (event-modifiers event)))))
          (amt (assoc mods mouse-wheel-scroll-amount)))
@@ -232,18 +251,18 @@ systems."
                    ;; Make sure we do indeed scroll to the end of the buffer.
                    (end-of-buffer (while t (funcall 
mwheel-scroll-up-function)))))
                (t (error "Bad binding in mwheel-scroll"))))
-      (if curwin (select-window curwin)))
-    ;; If there is a temporarily active region, deactivate it if
-    ;; scrolling moves point.
-    (when opoint
-      (with-current-buffer buffer
-       (when (/= opoint (point))
-         ;; Call `deactivate-mark' at the original position, so that
-         ;; the original region is saved to the X selection.
-         (let ((newpoint (point)))
-           (goto-char opoint)
-           (deactivate-mark)
-           (goto-char newpoint))))))
+      (if (eq scroll-window selected-window)
+         ;; If there is a temporarily active region, deactivate it if
+         ;; scrolling moved point.
+         (when (and old-point (/= old-point (window-point)))
+           ;; Call `deactivate-mark' at the original position, so that
+           ;; the original region is saved to the X selection.
+           (let ((new-point (window-point)))
+             (goto-char old-point)
+             (deactivate-mark)
+             (goto-char new-point)))
+       (select-window selected-window t))))
+
   (when (and mouse-wheel-click-event mouse-wheel-inhibit-click-time)
     (if mwheel-inhibit-click-event-timer
        (cancel-timer mwheel-inhibit-click-event-timer)
diff --git a/lisp/window.el b/lisp/window.el
index 5050243..bea8383 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -1533,7 +1533,7 @@ return the minimum pixel-size of WINDOW."
    (window-normalize-window window) horizontal ignore pixelwise))
 
 (defun window--min-size-ignore-p (window ignore)
-  "Return non-nil if IGNORE says to ignore height restrictions for WINDOW."
+  "Return non-nil if IGNORE says to ignore size restrictions for WINDOW."
   (if (window-valid-p ignore)
       (eq window ignore)
     (not (memq ignore '(nil preserved)))))
@@ -8735,13 +8735,14 @@ means suspend autoselection."
 If the mouse position has stabilized in a non-selected window, select
 that window.  The minibuffer window is selected only if the minibuffer
 is active.  This function is run by `mouse-autoselect-window-timer'."
-  (ignore-errors
-   (let* ((mouse-position (mouse-position))
-         (window
-          (ignore-errors
-           (window-at (cadr mouse-position) (cddr mouse-position)
-                      (car mouse-position)))))
-     (cond
+  (let* ((mouse-position (mouse-position))
+         (mouse-x (and (numberp (cadr mouse-position))
+                       (cadr mouse-position)))
+         (mouse-y (and (numberp (cddr mouse-position))
+                       (cddr mouse-position)))
+         (frame (and mouse-x mouse-y (car mouse-position)))
+         (window (and frame (window-at mouse-x mouse-y frame))))
+    (cond
       ((or (and (fboundp 'menu-or-popup-active-p) (menu-or-popup-active-p))
           (and window
                (let ((coords (coordinates-in-window-p
@@ -8752,72 +8753,63 @@ is active.  This function is run by 
`mouse-autoselect-window-timer'."
        ;; text region of WINDOW: Suspend autoselection temporarily.
        (mouse-autoselect-window-start mouse-position nil t))
       ((or (eq mouse-autoselect-window-state 'suspend)
-          ;; When the mouse is at its first recorded position, restart
-          ;; delayed autoselection.  This works around a scenario with
-          ;; two two-window frames with identical dimensions: select the
-          ;; first window of the first frame, switch to the second
-          ;; frame, move the mouse to its second window, minimize the
-          ;; second frame.  Now the second window of the first frame
-          ;; gets selected although the mouse never really "moved" into
-          ;; that window.
-          (and (numberp mouse-autoselect-window)
-               (equal (mouse-position) mouse-autoselect-window-position-1)))
-       ;; Delayed autoselection was temporarily suspended, reenable it.
-       (mouse-autoselect-window-start mouse-position))
-      ((and window (not (eq window (selected-window)))
-           (or (not (numberp mouse-autoselect-window))
-               (and (>= mouse-autoselect-window 0)
-                    ;; If `mouse-autoselect-window' is non-negative,
-                    ;; select window if it's the same as before.
-                    (eq window mouse-autoselect-window-window))
-               ;; Otherwise select window iff the mouse is at the same
-               ;; position as before.  Observe that the first test
-               ;; after starting autoselection usually fails since the
-               ;; value of `mouse-autoselect-window-position' recorded
-               ;; there is the position where the mouse has entered the
-               ;; new window and not necessarily where the mouse has
-               ;; stopped moving.
-               (equal mouse-position mouse-autoselect-window-position))
-           ;; The minibuffer is a candidate window if it's active.
-           (or (not (window-minibuffer-p window))
-               (eq window (active-minibuffer-window))))
-       ;; Mouse position has stabilized in non-selected window: Cancel
-       ;; delayed autoselection and try to select that window.
-       (mouse-autoselect-window-cancel t)
-       ;; Select window where mouse appears unless the selected window is the
-       ;; minibuffer.  Use `unread-command-events' in order to execute pre-
-       ;; and post-command hooks and trigger idle timers.  To avoid delaying
-       ;; autoselection again, set `mouse-autoselect-window-state'."
-       (unless (window-minibuffer-p)
-        (setq mouse-autoselect-window-state 'select)
-        (setq unread-command-events
-              (cons (list 'select-window (list window))
-                    unread-command-events))))
-      ((or (and window (eq window (selected-window)))
-          (not (numberp mouse-autoselect-window))
-          (equal mouse-position mouse-autoselect-window-position))
-       ;; Mouse position has either stabilized in the selected window or at
-       ;; `mouse-autoselect-window-position': Cancel delayed autoselection.
-       (mouse-autoselect-window-cancel t))
-      (t
-       ;; Mouse position has not stabilized yet, resume delayed
-       ;; autoselection.
-       (mouse-autoselect-window-start mouse-position window))))))
+          ;; When the mouse is at its first recorded position, restart
+          ;; delayed autoselection.  This works around a scenario with
+          ;; two two-window frames with identical dimensions: select the
+          ;; first window of the first frame, switch to the second
+          ;; frame, move the mouse to its second window, minimize the
+          ;; second frame.  Now the second window of the first frame
+          ;; gets selected although the mouse never really "moved" into
+          ;; that window.
+          (and (numberp mouse-autoselect-window)
+               (equal (mouse-position) mouse-autoselect-window-position-1)))
+      ;; Delayed autoselection was temporarily suspended, reenable it.
+      (mouse-autoselect-window-start mouse-position))
+     ((and window
+           (or (not (numberp mouse-autoselect-window))
+               (and (>= mouse-autoselect-window 0)
+                    ;; If `mouse-autoselect-window' is non-negative,
+                    ;; select window if it's the same as before.
+                    (eq window mouse-autoselect-window-window))
+               ;; Otherwise select window iff the mouse is at the same
+               ;; position as before.  Observe that the first test
+               ;; after starting autoselection usually fails since the
+               ;; value of `mouse-autoselect-window-position' recorded
+               ;; there is the position where the mouse has entered the
+               ;; new window and not necessarily where the mouse has
+               ;; stopped moving.
+               (equal mouse-position mouse-autoselect-window-position))
+           ;; The minibuffer is a candidate window if it's active.
+           (or (not (window-minibuffer-p window))
+               (eq window (active-minibuffer-window))))
+      ;; Mouse position has stabilized in non-selected window: Cancel
+      ;; delayed autoselection and try to select that window.
+      (mouse-autoselect-window-cancel t)
+      ;; Use `unread-command-events' in order to execute pre- and
+      ;; post-command hooks and trigger idle timers.  To avoid delaying
+      ;; autoselection again, set `mouse-autoselect-window-state'."
+      (setq mouse-autoselect-window-state 'select)
+      (setq unread-command-events
+            (cons (list 'select-window (list window))
+                  unread-command-events)))
+     ((or (not (numberp mouse-autoselect-window))
+          (equal mouse-position mouse-autoselect-window-position))
+      ;; Mouse position has stabilized at
+      ;; `mouse-autoselect-window-position': Cancel delayed
+      ;; autoselection.
+     (mouse-autoselect-window-cancel t))
+    (window
+     ;; Mouse position has not stabilized yet, resume delayed
+     ;; autoselection.
+     (mouse-autoselect-window-start mouse-position window)))))
 
 (defun handle-select-window (event)
   "Handle select-window events."
   (interactive "^e")
-  (let ((window (posn-window (event-start event))))
+  (let* ((window (posn-window (event-start event)))
+         (frame (and (window-live-p window) (window-frame window)))
+         (old-frame (selected-frame)))
     (unless (or (not (window-live-p window))
-               ;; Don't switch if we're currently in the minibuffer.
-               ;; This tries to work around problems where the
-               ;; minibuffer gets unselected unexpectedly, and where
-               ;; you then have to move your mouse all the way down to
-               ;; the minibuffer to select it.
-               (window-minibuffer-p)
-               ;; Don't switch to minibuffer window unless it's active.
-               (and (window-minibuffer-p window)
-                    (not (minibuffer-window-active-p window)))
                ;; Don't switch when autoselection shall be delayed.
                (and (numberp mouse-autoselect-window)
                     (not (eq mouse-autoselect-window-state 'select))
@@ -8830,15 +8822,40 @@ is active.  This function is run by 
`mouse-autoselect-window-timer'."
                       (mouse-autoselect-window-start position window)
                       ;; Executing a command cancels delayed autoselection.
                       (add-hook
-                       'pre-command-hook 'mouse-autoselect-window-cancel))))
-      (when mouse-autoselect-window
-       ;; Reset state of delayed autoselection.
-       (setq mouse-autoselect-window-state nil)
-       ;; Run `mouse-leave-buffer-hook' when autoselecting window.
-       (run-hooks 'mouse-leave-buffer-hook))
+                       'pre-command-hook 'mouse-autoselect-window-cancel)))
+                ;; Don't switch to a `no-accept-focus' frame unless it's
+                ;; already selected.
+                (and (not (eq frame (selected-frame)))
+                     (frame-parameter frame 'no-accept-focus))
+                ;; Don't switch to minibuffer window unless it's active.
+                (and (window-minibuffer-p window)
+                     (not (minibuffer-window-active-p window))))
+      ;; Reset state of delayed autoselection.
+      (setq mouse-autoselect-window-state nil)
+      ;; Run `mouse-leave-buffer-hook' when autoselecting window.
+      (run-hooks 'mouse-leave-buffer-hook)
       ;; Clear echo area.
       (message nil)
-      (select-window window))))
+      ;; Select the window before giving the frame focus since otherwise
+      ;; we might get two windows with an active cursor.
+      (select-window window)
+      (cond
+       ((or (not (memq (window-system frame) '(x w32 ns)))
+            (not focus-follows-mouse)
+            ;; Focus FRAME if it's either a child frame or an ancestor
+            ;; of the frame switched from.
+            (and (not (frame-parameter frame 'parent-frame))
+                 (not (frame-ancestor-p frame old-frame)))))
+       ((eq focus-follows-mouse 'auto-raise)
+        ;; Focus and auto-raise frame.
+        (x-focus-frame frame)
+        ;; This doesn't seem to work when we move from a normal frame
+        ;; right into the child frame of another frame - we should raise
+        ;; that child frame's ancestor frame first ...
+        (raise-frame frame))
+       (t
+        ;; Just focus frame.
+        (x-focus-frame frame))))))
 
 (defun truncated-partial-width-window-p (&optional window)
   "Return non-nil if lines in WINDOW are specifically truncated due to its 
width.
diff --git a/src/frame.c b/src/frame.c
index 5f57d4a..ed6c527 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -324,11 +324,51 @@ DEFUN ("frame-windows-min-size", Fframe_windows_min_size,
   return make_number (0);
 }
 
+/**
+ * frame_windows_min_size:
+ *
+ * Return the minimum number of lines (columns if HORIZONTAL is non-nil)
+ * of FRAME.  If PIXELWISE is non-nil, return the minimum height (width)
+ * in pixels.
+ *
+ * This value is calculated by the function `frame-windows-min-size' in
+ * window.el unless the `min-height' (`min-width' if HORIZONTAL is
+ * non-nil) parameter of FRAME is non-nil thus explicitly specifying the
+ * value to be returned.  In that latter case IGNORE is ignored.
+ *
+ * If `frame-windows-min-size' is called, it will make sure that the
+ * return value accomodates all windows of FRAME respecting the values
+ * of `window-min-height' (`window-min-width' if HORIZONTAL is non-nil).
+ * With IGNORE non-nil the values of these variables are ignored.
+ *
+ * In either case never return a value less than 1.
+ */
 static int
 frame_windows_min_size (Lisp_Object frame, Lisp_Object horizontal,
                        Lisp_Object ignore, Lisp_Object pixelwise)
 {
-  return XINT (call4 (Qframe_windows_min_size, frame, horizontal,
+  struct frame *f = XFRAME (frame);
+  Lisp_Object par_size;
+
+  if ((!NILP (horizontal)
+       && NUMBERP (par_size = get_frame_param (f, Qmin_width)))
+      || (NILP (horizontal)
+         && NUMBERP (par_size = get_frame_param (f, Qmin_height))))
+    {
+      int min_size = XINT (par_size);
+
+      /* Don't allow phantom frames.  */
+      if (min_size < 1)
+       min_size = 1;
+
+      return (NILP (pixelwise)
+             ? min_size
+             : min_size * (NILP (horizontal)
+                           ? FRAME_LINE_HEIGHT (f)
+                           : FRAME_COLUMN_WIDTH (f)));
+    }
+  else
+    return XINT (call4 (Qframe_windows_min_size, frame, horizontal,
                      ignore, pixelwise));
 }
 
@@ -643,6 +683,16 @@ make_frame (bool mini_p)
   f->vertical_scroll_bar_type = vertical_scroll_bar_none;
   f->horizontal_scroll_bars = false;
   f->want_fullscreen = FULLSCREEN_NONE;
+#if ! defined (HAVE_NS)
+  f->undecorated = false;
+#ifndef HAVE_NTGUI
+  f->override_redirect = false;
+#endif
+  f->skip_taskbar = false;
+  f->no_focus_on_map = false;
+  f->no_accept_focus = false;
+  f->z_group = z_group_none;
+#endif
 #if ! defined (USE_GTK) && ! defined (HAVE_NS)
   f->last_tool_bar_item = -1;
 #endif
@@ -1215,7 +1265,10 @@ do_switch_frame (Lisp_Object frame, int track, int 
for_deletion, Lisp_Object nor
      (select-window (frame-root-window (new-frame))) doesn't end up
      with your typing being interpreted in the new frame instead of
      the one you're actually typing in.  */
-  internal_last_event_frame = Qnil;
+#ifdef HAVE_WINDOW_SYSTEM
+  if (!frame_ancestor_p (f, sf))
+#endif
+    internal_last_event_frame = Qnil;
 
   return frame;
 }
@@ -1283,6 +1336,72 @@ DEFUN ("frame-list", Fframe_list, Sframe_list,
   return frames;
 }
 
+DEFUN ("frame-parent", Fframe_parent, Sframe_parent,
+       0, 1, 0,
+       doc: /* Return the parent frame of FRAME.
+The parent frame of FRAME is the Emacs frame whose window-system window
+is the parent window of FRAME's window-system window.  When such a frame
+exists, FRAME is considered a child frame of that frame.
+
+Return nil if FRAME has no parent frame.  This means that FRAME's
+window-system window is either a "top-level" window (a window whose
+parent window is the window-system's root window) or an embedded window
+\(a window whose parent window is owned by some other application).  */)
+     (Lisp_Object frame)
+{
+  struct frame *f = decode_live_frame (frame);
+  struct frame *p = FRAME_PARENT_FRAME (f);
+  Lisp_Object parent;
+
+  /* Can't return f->parent_frame directly since it might not be defined
+     for this platform.  */
+  if (p)
+    {
+      XSETFRAME (parent, p);
+
+      return parent;
+    }
+  else
+    return Qnil;
+}
+
+#ifdef HAVE_WINDOW_SYSTEM
+bool
+frame_ancestor_p (struct frame *af, struct frame *df)
+{
+  struct frame *pf = FRAME_PARENT_FRAME (df);
+
+  while (pf)
+    {
+      if (pf == af)
+       return true;
+      else
+       pf = FRAME_PARENT_FRAME (pf);
+    }
+
+  return false;
+}
+#endif
+
+DEFUN ("frame-ancestor-p", Fframe_ancestor_p, Sframe_ancestor_p,
+       2, 2, 0,
+       doc: /* Return non-nil if ANCESTOR is an ancestor of DESCENDANT.
+ANCESTOR is an ancestor of DESCENDANT when it is either DESCENDANT's
+parent frame or it is an ancestor of DESCENDANT's parent frame.  Both,
+ANCESTOR and DESCENDANT must be live frames and default to the selected
+frame.  */)
+     (Lisp_Object ancestor, Lisp_Object descendant)
+{
+#ifdef HAVE_WINDOW_SYSTEM
+  struct frame *af = decode_live_frame (ancestor);
+  struct frame *df = decode_live_frame (descendant);
+
+  return frame_ancestor_p (af, df) ? Qt : Qnil;
+#else
+  return Qnil;
+#endif
+  }
+
 /* Return CANDIDATE if it can be used as 'other-than-FRAME' frame on the
    same tty (for tty frames) or among frames which uses FRAME's keyboard.
    If MINIBUF is nil, do not consider minibuffer-only candidate.
@@ -1303,7 +1422,9 @@ candidate_frame (Lisp_Object candidate, Lisp_Object 
frame, Lisp_Object minibuf)
       || (FRAME_TERMCAP_P (c) && FRAME_TERMCAP_P (f)
          && FRAME_TTY (c) == FRAME_TTY (f)))
     {
-      if (NILP (minibuf))
+      if (!NILP (get_frame_param (c, Qno_other_frame)))
+       return Qnil;
+      else if (NILP (minibuf))
        {
          if (!FRAME_MINIBUF_ONLY_P (c))
            return candidate;
@@ -1441,35 +1562,65 @@ DEFUN ("last-nonminibuffer-frame", 
Flast_nonminibuf_frame,
   return frame;
 }
 
-/* Return 1 if it is ok to delete frame F;
-   0 if all frames aside from F are invisible.
-   (Exception: if F is the terminal frame, and we are using X, return 1.)  */
+/**
+ * other_frames:
+ *
+ * Return true if there exists at least one visible or iconified frame
+ * but F.  Return false otherwise.
+ *
+ * Always return false when all remaining frames are either tooltip or
+ * child frames or frames with a non-nil `delete-before' parameter.  If
+ * INVISIBLE is false, also return false when the minibuffer window of
+ * all remaining frames is on F.
+
+ * If F is the terminal frame and we are using X, return true if at
+ * least one X frame exists.  */
+static bool
+other_frames (struct frame *f, bool invisible)
+{
+  Lisp_Object frames, frame, frame1;
+  struct frame *f1;
+  Lisp_Object minibuffer_window = FRAME_MINIBUF_WINDOW (f);
 
-static int
-other_visible_frames (struct frame *f)
-{
-  Lisp_Object frames, this;
+  XSETFRAME (frame, f);
+  if (WINDOWP (minibuffer_window)
+      && !EQ (frame, WINDOW_FRAME (XWINDOW (minibuffer_window))))
+    minibuffer_window = Qnil;
 
-  FOR_EACH_FRAME (frames, this)
+  FOR_EACH_FRAME (frames, frame1)
     {
-      if (f == XFRAME (this))
-       continue;
-
-      /* Verify that we can still talk to the frame's X window,
-        and note any recent change in visibility.  */
+      f1 = XFRAME (frame1);
+      if (f != f1)
+       {
+         /* Verify that we can still talk to the frame's X window, and
+            note any recent change in visibility.  */
 #ifdef HAVE_X_WINDOWS
-      if (FRAME_WINDOW_P (XFRAME (this)))
-       x_sync (XFRAME (this));
+         if (FRAME_WINDOW_P (f1))
+           x_sync (f1);
 #endif
-
-      if (FRAME_VISIBLE_P (XFRAME (this))
-         || FRAME_ICONIFIED_P (XFRAME (this))
-         /* Allow deleting the terminal frame when at least one X
-            frame exists.  */
-         || (FRAME_WINDOW_P (XFRAME (this)) && !FRAME_WINDOW_P (f)))
-       return 1;
+         if (NILP (Fframe_parameter (frame1, Qtooltip))
+             /* Tooltips and child frames don't count.  */
+             && !FRAME_PARENT_FRAME (f1)
+             /* Frames with a non-nil `delete-before' parameter don't
+                count - either they depend on us or they depend on a
+                frame that we will have to find right here.  */
+             && NILP (get_frame_param (f1, Qdelete_before))
+             /* Frames whose minibuffer window is on F don't count
+                unless INVISIBLE is set - in that case F is either made
+                invisible and may be autoraised from such a frame or
+                the FORCE argument of delete_frame was non-nil.  */
+             && (invisible || NILP (minibuffer_window)
+                 || !EQ (FRAME_MINIBUF_WINDOW (f1), minibuffer_window))
+             /* At least one visible/iconified frame must remain.  */
+             && (FRAME_VISIBLE_P (f1) || FRAME_ICONIFIED_P (f1)
+                 /* Allow deleting the terminal frame when at least one
+                    X frame exists.  */
+                 || (FRAME_WINDOW_P (f1) && !FRAME_WINDOW_P (f))))
+           return true;
+       }
     }
-  return 0;
+
+  return false;
 }
 
 /* Make sure that minibuf_window doesn't refer to FRAME's minibuffer
@@ -1518,53 +1669,65 @@ check_minibuf_window (Lisp_Object frame, int select)
 }
 
 
-/* Delete FRAME.  When FORCE equals Qnoelisp, delete FRAME
-  unconditionally.  x_connection_closed and delete_terminal use
-  this.  Any other value of FORCE implements the semantics
-  described for Fdelete_frame.  */
+/**
+ * delete_frame:
+ *
+ * Delete FRAME.  When FORCE equals Qnoelisp, delete FRAME
+ * unconditionally.  x_connection_closed and delete_terminal use this.
+ * Any other value of FORCE implements the semantics described for
+ * Fdelete_frame.  */
 Lisp_Object
 delete_frame (Lisp_Object frame, Lisp_Object force)
 {
   struct frame *f = decode_any_frame (frame);
   struct frame *sf;
   struct kboard *kb;
-
+  Lisp_Object frames, frame1;
   int minibuffer_selected, is_tooltip_frame;
+  bool nochild = !FRAME_PARENT_FRAME (f);
 
-  if (! FRAME_LIVE_P (f))
+  if (!FRAME_LIVE_P (f))
     return Qnil;
-
-  if (NILP (force) && !other_visible_frames (f))
-    error ("Attempt to delete the sole visible or iconified frame");
-
-  /* x_connection_closed must have set FORCE to `noelisp' in order
-     to delete the last frame, if it is gone.  */
-  if (NILP (XCDR (Vframe_list)) && !EQ (force, Qnoelisp))
-    error ("Attempt to delete the only frame");
+  else if (!EQ (force, Qnoelisp) && !other_frames (f, !NILP (force)))
+    {
+      if (NILP (force))
+       error ("Attempt to delete the sole visible or iconified frame");
+      else
+       error ("Attempt to delete the only frame");
+    }
 
   XSETFRAME (frame, f);
 
+  /* Softly delete all frames with this frame as their parent frame or
+     as their `delete-before' frame parameter value.  */
+  FOR_EACH_FRAME (frames, frame1)
+    if (FRAME_PARENT_FRAME (XFRAME (frame1)) == f
+       /* Process `delete-before' parameter iff FRAME is not a child
+          frame.  This avoids that we enter an infinite chain of mixed
+          dependencies.  */
+       || (nochild
+           && EQ (get_frame_param (XFRAME (frame1), Qdelete_before), frame)))
+      delete_frame (frame1, Qnil);
+
   /* Does this frame have a minibuffer, and is it the surrogate
      minibuffer for any other frame?  */
   if (FRAME_HAS_MINIBUF_P (f))
     {
-      Lisp_Object frames, this;
-
-      FOR_EACH_FRAME (frames, this)
+      FOR_EACH_FRAME (frames, frame1)
        {
          Lisp_Object fminiw;
 
-         if (EQ (this, frame))
+         if (EQ (frame1, frame))
            continue;
 
-         fminiw = FRAME_MINIBUF_WINDOW (XFRAME (this));
+         fminiw = FRAME_MINIBUF_WINDOW (XFRAME (frame1));
 
          if (WINDOWP (fminiw) && EQ (frame, WINDOW_FRAME (XWINDOW (fminiw))))
            {
              /* If we MUST delete this frame, delete the other first.
                 But do this only if FORCE equals `noelisp'.  */
              if (EQ (force, Qnoelisp))
-               delete_frame (this, Qnoelisp);
+               delete_frame (frame1, Qnoelisp);
              else
                error ("Attempt to delete a surrogate minibuffer frame");
            }
@@ -1593,20 +1756,26 @@ delete_frame (Lisp_Object frame, Lisp_Object force)
       safe_call2 (Qrun_hook_with_args, Qdelete_frame_functions, frame);
     }
 
-  /* The hook may sometimes (indirectly) cause the frame to be deleted.  */
-  if (! FRAME_LIVE_P (f))
+  /* delete_frame_functions may have deleted any frame, including this
+     one.  */
+  if (!FRAME_LIVE_P (f))
     return Qnil;
+  else if (!EQ (force, Qnoelisp) && !other_frames (f, !NILP (force)))
+    {
+      if (NILP (force))
+       error ("Attempt to delete the sole visible or iconified frame");
+      else
+       error ("Attempt to delete the only frame");
+    }
 
   /* At this point, we are committed to deleting the frame.
      There is no more chance for errors to prevent it.  */
-
   minibuffer_selected = EQ (minibuf_window, selected_window);
   sf = SELECTED_FRAME ();
   /* Don't let the frame remain selected.  */
   if (f == sf)
     {
       Lisp_Object tail;
-      Lisp_Object frame1 = Qnil;
 
       /* Look for another visible frame on the same terminal.
         Do not call next_frame here because it may loop forever.
@@ -1746,16 +1915,15 @@ delete_frame (Lisp_Object frame, Lisp_Object force)
      another one.  */
   if (f == last_nonminibuf_frame)
     {
-      Lisp_Object frames, this;
-
       last_nonminibuf_frame = 0;
 
-      FOR_EACH_FRAME (frames, this)
+      FOR_EACH_FRAME (frames, frame1)
        {
-         f = XFRAME (this);
-         if (!FRAME_MINIBUF_ONLY_P (f))
+         struct frame *f1 = XFRAME (frame1);
+
+         if (!FRAME_MINIBUF_ONLY_P (f1))
            {
-             last_nonminibuf_frame = f;
+             last_nonminibuf_frame = f1;
              break;
            }
        }
@@ -1765,13 +1933,12 @@ delete_frame (Lisp_Object frame, Lisp_Object force)
      single-kboard state if we're in it for this kboard.  */
   if (kb != NULL)
     {
-      Lisp_Object frames, this;
       /* Some frame we found on the same kboard, or nil if there are none.  */
       Lisp_Object frame_on_same_kboard = Qnil;
 
-      FOR_EACH_FRAME (frames, this)
-       if (kb == FRAME_KBOARD (XFRAME (this)))
-         frame_on_same_kboard = this;
+      FOR_EACH_FRAME (frames, frame1)
+       if (kb == FRAME_KBOARD (XFRAME (frame1)))
+         frame_on_same_kboard = frame1;
 
       if (NILP (frame_on_same_kboard))
        not_single_kboard_state (kb);
@@ -1783,29 +1950,27 @@ delete_frame (Lisp_Object frame, Lisp_Object force)
      frames with other windows.  */
   if (kb != NULL && EQ (frame, KVAR (kb, Vdefault_minibuffer_frame)))
     {
-      Lisp_Object frames, this;
-
       /* The last frame we saw with a minibuffer, minibuffer-only or not.  */
       Lisp_Object frame_with_minibuf = Qnil;
       /* Some frame we found on the same kboard, or nil if there are none.  */
       Lisp_Object frame_on_same_kboard = Qnil;
 
-      FOR_EACH_FRAME (frames, this)
+      FOR_EACH_FRAME (frames, frame1)
        {
-         struct frame *f1 = XFRAME (this);
+         struct frame *f1 = XFRAME (frame1);
 
          /* Consider only frames on the same kboard
             and only those with minibuffers.  */
          if (kb == FRAME_KBOARD (f1)
              && FRAME_HAS_MINIBUF_P (f1))
            {
-             frame_with_minibuf = this;
+             frame_with_minibuf = frame1;
              if (FRAME_MINIBUF_ONLY_P (f1))
                break;
            }
 
          if (kb == FRAME_KBOARD (f1))
-           frame_on_same_kboard = this;
+           frame_on_same_kboard = frame1;
        }
 
       if (!NILP (frame_on_same_kboard))
@@ -2118,7 +2283,7 @@ displayed in the terminal.  */)
 {
   struct frame *f = decode_live_frame (frame);
 
-  if (NILP (force) && !other_visible_frames (f))
+  if (NILP (force) && !other_frames (f, true))
     error ("Attempt to make invisible the sole visible or iconified frame");
 
   /* Don't allow minibuf_window to remain on an invisible frame.  */
@@ -2453,9 +2618,39 @@ store_frame_param (struct frame *f, Lisp_Object prop, 
Lisp_Object val)
        }
     }
 
+  /* Check these parameters for circular dependeny.  This does not check
+     for interdependencies between these properties.  Hence you can
+     still create circular dependencies with different properties, for
+     example a chain of frames F1->F2->...Fn such that F1 is an ancestor
+     frame of Fn and thus cannot be deleted before Fn and a second chain
+     Fn->Fn-1->...F1 such that Fn cannot be deleted before F1.  */
+  else if (EQ (prop, Qparent_frame) || EQ (prop, Qdelete_before))
+    {
+      Lisp_Object oldval = Fcdr (Fassq (prop, f->param_alist));
+
+      if (!EQ (oldval, val) && !NILP (val))
+       {
+         Lisp_Object frame;
+         Lisp_Object frame1 = val;
+
+         if (!FRAMEP (frame1) || !FRAME_LIVE_P (XFRAME (frame1)))
+           error ("Invalid `%s' frame parameter",
+                  SSDATA (SYMBOL_NAME (prop)));
+
+         XSETFRAME (frame, f);
+
+         while (FRAMEP (frame1) && FRAME_LIVE_P (XFRAME (frame1)))
+           if (EQ (frame1, frame))
+             error ("Circular specification of `%s' frame parameter",
+                    SSDATA (SYMBOL_NAME (prop)));
+           else
+             frame1 = get_frame_param (XFRAME (frame1), prop);
+       }
+    }
+
   /* The buffer-list parameters are stored in a special place and not
      in the alist.  All buffers must be live.  */
-  if (EQ (prop, Qbuffer_list))
+  else if (EQ (prop, Qbuffer_list))
     {
       Lisp_Object list = Qnil;
       for (; CONSP (val); val = XCDR (val))
@@ -2464,7 +2659,7 @@ store_frame_param (struct frame *f, Lisp_Object prop, 
Lisp_Object val)
       fset_buffer_list (f, Fnreverse (list));
       return;
     }
-  if (EQ (prop, Qburied_buffer_list))
+  else if (EQ (prop, Qburied_buffer_list))
     {
       Lisp_Object list = Qnil;
       for (; CONSP (val); val = XCDR (val))
@@ -3095,6 +3290,13 @@ static const struct frame_parm_table frame_parms[] =
   {"sticky",                   SYMBOL_INDEX (Qsticky)},
   {"tool-bar-position",                SYMBOL_INDEX (Qtool_bar_position)},
   {"inhibit-double-buffering",  SYMBOL_INDEX (Qinhibit_double_buffering)},
+  {"undecorated",              SYMBOL_INDEX (Qundecorated)},
+  {"parent-frame",             SYMBOL_INDEX (Qparent_frame)},
+  {"skip-taskbar",             SYMBOL_INDEX (Qskip_taskbar)},
+  {"no-focus-on-map",          SYMBOL_INDEX (Qno_focus_on_map)},
+  {"no-accept-focus",          SYMBOL_INDEX (Qno_accept_focus)},
+  {"z-group",                  SYMBOL_INDEX (Qz_group)},
+  {"override-redirect",                SYMBOL_INDEX (Qoverride_redirect)},
 };
 
 #ifdef HAVE_WINDOW_SYSTEM
@@ -4882,6 +5084,14 @@ syms_of_frame (void)
   DEFSYM (Qheight, "height");
   DEFSYM (Qicon, "icon");
   DEFSYM (Qminibuffer, "minibuffer");
+  DEFSYM (Qundecorated, "undecorated");
+  DEFSYM (Qparent_frame, "parent-frame");
+  DEFSYM (Qskip_taskbar, "skip-taskbar");
+  DEFSYM (Qno_focus_on_map, "no-focus-on-map");
+  DEFSYM (Qno_accept_focus, "no-accept-focus");
+  DEFSYM (Qz_group, "z-group");
+  DEFSYM (Qoverride_redirect, "override-redirect");
+  DEFSYM (Qdelete_before, "delete-before");
   DEFSYM (Qmodeline, "modeline");
   DEFSYM (Qonly, "only");
   DEFSYM (Qnone, "none");
@@ -4978,6 +5188,7 @@ syms_of_frame (void)
   DEFSYM (Qauto_raise, "auto-raise");
   DEFSYM (Qborder_color, "border-color");
   DEFSYM (Qborder_width, "border-width");
+  DEFSYM (Qouter_border_width, "outer-border-width");
   DEFSYM (Qbottom_divider_width, "bottom-divider-width");
   DEFSYM (Qcursor_color, "cursor-color");
   DEFSYM (Qcursor_type, "cursor-type");
@@ -5011,6 +5222,12 @@ syms_of_frame (void)
   DEFSYM (Qvisibility, "visibility");
   DEFSYM (Qwait_for_wm, "wait-for-wm");
   DEFSYM (Qinhibit_double_buffering, "inhibit-double-buffering");
+  DEFSYM (Qno_other_frame, "no-other-frame");
+  DEFSYM (Qbelow, "below");
+  DEFSYM (Qabove_suspended, "above-suspended");
+  DEFSYM (Qmin_width, "min-width");
+  DEFSYM (Qmin_height, "min-height");
+  DEFSYM (Qmouse_wheel_frame, "mouse-wheel-frame");
 
   {
     int i;
@@ -5179,12 +5396,51 @@ displayed.
 
 This variable is local to the current terminal and cannot be buffer-local.  
*/);
 
-  DEFVAR_BOOL ("focus-follows-mouse", focus_follows_mouse,
+  DEFVAR_LISP ("focus-follows-mouse", focus_follows_mouse,
               doc: /* Non-nil if window system changes focus when you move the 
mouse.
 You should set this variable to tell Emacs how your window manager
 handles focus, since there is no way in general for Emacs to find out
-automatically.  See also `mouse-autoselect-window'.  */);
-  focus_follows_mouse = 0;
+automatically.
+
+There are three meaningful values:
+
+- The default nil should be used when your window manager follows a
+  "click-to-focus" policy where you have to click the mouse inside of a
+  frame in order for that frame to get focus.
+
+- The value t should be used when your window manager has the focus
+  automatically follow the position of the mouse pointer but a window
+  that gains focus is not raised automatically.
+
+- The value `auto-raise' should be used when your window manager has the
+  focus automatically follow the position of the mouse pointer and a
+  window that gains focus is raised automatically.
+
+If this option is non-nil, Emacs moves the mouse pointer to the frame
+selected by `select-frame-set-input-focus'.  This function is used by a
+number of commands like, for example, `other-frame' and `pop-to-buffer'.
+If this option is nil and your focus follows mouse window manager does
+not autonomously move the mouse pointer to the newly selected frame, the
+previously selected window manager window might get reselected instead
+immediately.
+
+The distinction between the values t and `auto-raise' is not needed for
+"normal" frames because the window manager takes care of raising them.
+Setting this to `auto-raise' will, however, override the standard
+behavior of a window manager that does not automatically raise the frame
+that gets focus.  Setting this to `auto-raise' is also necessary to
+automatically raise child frames which are usually left alone by the
+window manager.
+
+Note that this option does not distinguish "sloppy" focus (where the
+frame that previously had focus retains focus as long as the mouse
+pointer does not move into another window manager window) from "strict"
+focus (where a frame immediately loses focus when it's left by the mouse
+pointer).
+
+In order to extend a "focus follows mouse" policy to individual Emacs
+windows, customize the variable `mouse-autoselect-window'.  */);
+  focus_follows_mouse = Qnil;
 
   DEFVAR_BOOL ("frame-resize-pixelwise", frame_resize_pixelwise,
               doc: /* Non-nil means resize frames pixelwise.
@@ -5286,6 +5542,8 @@ Gtk+ tooltips are not used) and on Windows.  */);
   defsubr (&Sselect_frame);
   defsubr (&Sselected_frame);
   defsubr (&Sframe_list);
+  defsubr (&Sframe_parent);
+  defsubr (&Sframe_ancestor_p);
   defsubr (&Snext_frame);
   defsubr (&Sprevious_frame);
   defsubr (&Slast_nonminibuf_frame);
diff --git a/src/frame.h b/src/frame.h
index 5f18901..376df52 100644
--- a/src/frame.h
+++ b/src/frame.h
@@ -45,6 +45,13 @@ enum fullscreen_type
 #endif
 };
 
+enum z_group
+{
+  z_group_none,
+  z_group_above,
+  z_group_below,
+  z_group_above_suspended,
+};
 #endif /* HAVE_WINDOW_SYSTEM */
 
 /* The structure representing a frame.  */
@@ -68,6 +75,11 @@ struct frame
      Usually it is nil.  */
   Lisp_Object title;
 
+#if defined (HAVE_WINDOW_SYSTEM) && !defined (HAVE_NS)
+  /* This frame's parent frame, if it has one.  */
+  Lisp_Object parent_frame;
+#endif /* HAVE_WINDOW_SYSTEM and not HAVE_NS */
+
   /* The frame which should receive keystrokes that occur in this
      frame, or nil if they should go to the frame itself.  This is
      usually nil, but if the frame is minibufferless, we can use this
@@ -320,6 +332,30 @@ struct frame
   bool_bf horizontal_scroll_bars : 1;
 #endif /* HAVE_WINDOW_SYSTEM */
 
+#if defined (HAVE_WINDOW_SYSTEM) && !defined (HAVE_NS)
+  /* True if this is an undecorated frame.  */
+  bool_bf undecorated : 1;
+
+#ifndef HAVE_NTGUI
+  /* True if this is an override_redirect frame.  */
+  bool_bf override_redirect : 1;
+#endif
+
+  /* Nonzero if this frame's icon should not appear on its display's taskbar.  
*/
+  bool_bf skip_taskbar : 1;
+
+  /* Nonzero if this frame's window F's X window does not want to
+     receive input focus when it is mapped.  */
+  bool_bf no_focus_on_map : 1;
+
+  /* Nonzero if this frame's window does not want to receive input focus
+     via mouse clicks or by moving the mouse into it.  */
+  bool_bf no_accept_focus : 1;
+
+  /* The z-group this frame's window belongs to. */
+  ENUM_BF (z_group) z_group : 2;
+#endif /* HAVE_WINDOW_SYSTEM and not HAVE_NS */
+
   /* Whether new_height and new_width shall be interpreted
      in pixels.  */
   bool_bf new_pixelwise : 1;
@@ -534,6 +570,13 @@ fset_face_alist (struct frame *f, Lisp_Object val)
 {
   f->face_alist = val;
 }
+#if defined (HAVE_WINDOW_SYSTEM) && !defined (HAVE_NS)
+INLINE void
+fset_parent_frame (struct frame *f, Lisp_Object val)
+{
+  f->parent_frame = val;
+}
+#endif
 INLINE void
 fset_focus_frame (struct frame *f, Lisp_Object val)
 {
@@ -854,7 +897,6 @@ default_pixels_per_inch_y (void)
 #define FRAME_FOCUS_FRAME(f) f->focus_frame
 
 #ifdef HAVE_WINDOW_SYSTEM
-
 /* This frame slot says whether scroll bars are currently enabled for frame F,
    and which side they are on.  */
 #define FRAME_VERTICAL_SCROLL_BAR_TYPE(f) ((f)->vertical_scroll_bar_type)
@@ -864,17 +906,47 @@ default_pixels_per_inch_y (void)
   ((f)->vertical_scroll_bar_type == vertical_scroll_bar_left)
 #define FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT(f) \
   ((f)->vertical_scroll_bar_type == vertical_scroll_bar_right)
-
 #else /* not HAVE_WINDOW_SYSTEM */
-
 /* If there is no window system, there are no scroll bars.  */
 #define FRAME_VERTICAL_SCROLL_BAR_TYPE(f) ((void) f, vertical_scroll_bar_none)
 #define FRAME_HAS_VERTICAL_SCROLL_BARS(f) ((void) f, 0)
 #define FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT(f) ((void) f, 0)
 #define FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT(f) ((void) f, 0)
-
 #endif /* HAVE_WINDOW_SYSTEM */
 
+#if defined (HAVE_WINDOW_SYSTEM) && !defined (HAVE_NS)
+#define FRAME_UNDECORATED(f) ((f)->undecorated)
+#ifdef HAVE_NTGUI
+#define FRAME_OVERRIDE_REDIRECT(f) ((void) f, 0)
+#else
+#define FRAME_OVERRIDE_REDIRECT(f) ((f)->override_redirect)
+#endif
+#define FRAME_PARENT_FRAME(f)                  \
+  (NILP ((f)->parent_frame)                    \
+   ? NULL                                      \
+   : XFRAME ((f)->parent_frame))
+#define FRAME_SKIP_TASKBAR(f) ((f)->skip_taskbar)
+#define FRAME_NO_FOCUS_ON_MAP(f) ((f)->no_focus_on_map)
+#define FRAME_NO_ACCEPT_FOCUS(f) ((f)->no_accept_focus)
+#define FRAME_Z_GROUP(f) ((f)->z_group)
+#define FRAME_Z_GROUP_NONE(f) ((f)->z_group == z_group_none)
+#define FRAME_Z_GROUP_ABOVE(f) ((f)->z_group == z_group_above)
+#define FRAME_Z_GROUP_ABOVE_SUSPENDED(f)       \
+  ((f)->z_group == z_group_above_suspended)
+#define FRAME_Z_GROUP_BELOW(f) ((f)->z_group == z_group_below)
+#else /* not HAVE_WINDOW_SYSTEM or HAVE_NS */
+#define FRAME_UNDECORATED(f) ((void) f, 0)
+#define FRAME_OVERRIDE_REDIRECT(f) ((void) f, 0)
+#define FRAME_PARENT_FRAME(f) ((void) f, NULL)
+#define FRAME_SKIP_TASKBAR(f) ((void) f, 0)
+#define FRAME_NO_FOCUS_ON_MAP(f) ((void) f, 0)
+#define FRAME_NO_ACCEPT_FOCUS(f) ((void) f, 0)
+#define FRAME_Z_GROUP(f) ((void) f, z_group_none)
+#define FRAME_Z_GROUP_NONE(f) ((void) f, true)
+#define FRAME_Z_GROUP_ABOVE(f) ((void) f, false)
+#define FRAME_Z_GROUP_BELOW(f) ((void) f, false)
+#endif /* HAVE_WINDOW_SYSTEM and not HAVE_NS */
+
 /* Whether horizontal scroll bars are currently enabled for frame F.  */
 #if USE_HORIZONTAL_SCROLL_BARS
 #define FRAME_HAS_HORIZONTAL_SCROLL_BARS(f) \
@@ -1041,7 +1113,8 @@ default_pixels_per_inch_y (void)
    loop will set FRAME_VAR, a Lisp_Object, to each frame in
    Vframe_list in succession and execute the statement.  LIST_VAR
    should be a Lisp_Object too; it is used to iterate through the
-   Vframe_list.
+   Vframe_list.  Note that this macro walks over child frames and
+   the tooltip frame as well.
 
    This macro is a holdover from a time when multiple frames weren't always
    supported.  An alternate definition of the macro would expand to
@@ -1221,7 +1294,7 @@ FRAME_INTERNAL_BORDER_WIDTH (struct frame *f)
   return frame_dimension (f->internal_border_width);
 }
 
-/* Pixel-size of window border lines */
+/* Pixel-size of window divider lines */
 INLINE int
 FRAME_RIGHT_DIVIDER_WIDTH (struct frame *f)
 {
@@ -1446,6 +1519,7 @@ extern void x_activate_menubar (struct frame *);
 extern void x_real_positions (struct frame *, int *, int *);
 extern void free_frame_menubar (struct frame *);
 extern void x_free_frame_resources (struct frame *);
+extern bool frame_ancestor_p (struct frame *af, struct frame *df);
 
 #if defined HAVE_X_WINDOWS
 extern void x_wm_set_icon_position (struct frame *, int, int);
diff --git a/src/gtkutil.c b/src/gtkutil.c
index 63f0143..227a062 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -1200,7 +1200,14 @@ xg_create_frame_widgets (struct frame *f)
   else if (! NILP (f->name))
     title = SSDATA (ENCODE_UTF_8 (f->name));
 
-  if (title) gtk_window_set_title (GTK_WINDOW (wtop), title);
+  if (title)
+    gtk_window_set_title (GTK_WINDOW (wtop), title);
+
+  if (FRAME_UNDECORATED (f))
+    {
+      gtk_window_set_decorated (GTK_WINDOW (wtop), FALSE);
+      store_frame_param (f, Qundecorated, Qt);
+    }
 
   FRAME_GTK_OUTER_WIDGET (f) = wtop;
   FRAME_GTK_WIDGET (f) = wfixed;
@@ -1275,6 +1282,14 @@ xg_create_frame_widgets (struct frame *f)
   gtk_window_set_resizable (GTK_WINDOW (wtop), TRUE);
 #endif
 
+  if (FRAME_OVERRIDE_REDIRECT (f))
+    {
+      GdkWindow *gwin = gtk_widget_get_window (wtop);
+
+      if (gwin)
+       gdk_window_set_override_redirect (gwin, TRUE);
+    }
+
 #ifdef USE_GTK_TOOLTIP
   /* Steal a tool tip window we can move ourselves.  */
   f->output_data.x->ttip_widget = 0;
@@ -1356,7 +1371,9 @@ x_wm_set_size_hint (struct frame *f, long int flags, bool 
user_position)
   /* Don't set size hints during initialization; that apparently leads
      to a race condition.  See the thread at
      http://lists.gnu.org/archive/html/emacs-devel/2008-10/msg00033.html  */
-  if (NILP (Vafter_init_time) || !FRAME_GTK_OUTER_WIDGET (f))
+  if (NILP (Vafter_init_time)
+      || !FRAME_GTK_OUTER_WIDGET (f)
+      || FRAME_PARENT_FRAME (f))
     return;
 
   XSETFRAME (frame, f);
@@ -1489,6 +1506,100 @@ xg_set_background_color (struct frame *f, unsigned long 
bg)
     }
 }
 
+/* Change the frame's decoration (title bar + resize borders).  This
+   might not work with all window managers.  */
+void
+xg_set_undecorated (struct frame *f, Lisp_Object undecorated)
+{
+  if (FRAME_GTK_WIDGET (f))
+    {
+      block_input ();
+      gtk_window_set_decorated (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
+                               NILP (undecorated) ? TRUE : FALSE);
+      unblock_input ();
+    }
+}
+
+
+/* Restack F1 below F2, above if ABOVE_FLAG is true.  This might not
+   work with all window managers.  */
+void
+xg_frame_restack (struct frame *f1, struct frame *f2, bool above_flag)
+{
+  block_input ();
+  if (FRAME_GTK_OUTER_WIDGET (f1) && FRAME_GTK_OUTER_WIDGET (f2))
+    {
+      GdkWindow *gwin1 = gtk_widget_get_window (FRAME_GTK_OUTER_WIDGET (f1));
+      GdkWindow *gwin2 = gtk_widget_get_window (FRAME_GTK_OUTER_WIDGET (f2));
+      Lisp_Object frame1, frame2;
+
+      XSETFRAME (frame1, f1);
+      XSETFRAME (frame2, f2);
+
+      gdk_window_restack (gwin1, gwin2, above_flag);
+      x_sync (f1);
+    }
+  unblock_input ();
+}
+
+
+/* Don't show frame in taskbar, don't ALT-TAB to it.  */
+void
+xg_set_skip_taskbar (struct frame *f, Lisp_Object skip_taskbar)
+{
+  block_input ();
+  if (FRAME_GTK_WIDGET (f))
+    gdk_window_set_skip_taskbar_hint
+      (gtk_widget_get_window (FRAME_GTK_OUTER_WIDGET (f)),
+       NILP (skip_taskbar) ? FALSE : TRUE);
+  unblock_input ();
+}
+
+
+/* Don't give frame focus.  */
+void
+xg_set_no_focus_on_map (struct frame *f, Lisp_Object no_focus_on_map)
+{
+  block_input ();
+  if (FRAME_GTK_WIDGET (f))
+    {
+      GtkWindow *gwin = GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f));
+      gboolean gno_focus_on_map = NILP (no_focus_on_map) ? TRUE : FALSE;
+
+      gtk_window_set_focus_on_map (gwin, gno_focus_on_map);
+    }
+  unblock_input ();
+}
+
+
+void
+xg_set_no_accept_focus (struct frame *f, Lisp_Object no_accept_focus)
+{
+  block_input ();
+  if (FRAME_GTK_WIDGET (f))
+    {
+      GtkWindow *gwin = GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f));
+      gboolean gno_accept_focus = NILP (no_accept_focus) ? TRUE : FALSE;
+
+      gtk_window_set_accept_focus (gwin, gno_accept_focus);
+    }
+  unblock_input ();
+}
+
+void
+xg_set_override_redirect (struct frame *f, Lisp_Object override_redirect)
+{
+  block_input ();
+
+  if (FRAME_GTK_OUTER_WIDGET (f))
+    {
+      GdkWindow *gwin = gtk_widget_get_window (FRAME_GTK_OUTER_WIDGET (f));
+
+      gdk_window_set_override_redirect (gwin, NILP (override_redirect) ? FALSE 
: TRUE);
+    }
+
+  unblock_input ();
+}
 
 /* Set the frame icon to ICON_PIXMAP/MASK.  This must be done with GTK
    functions so GTK does not overwrite the icon.  */
@@ -3769,6 +3880,7 @@ xg_update_scrollbar_pos (struct frame *f,
       GtkWidget *wparent = gtk_widget_get_parent (wscroll);
       gint msl;
       int scale = xg_get_gdk_scale ();
+      bool hidden;
 
       top /= scale;
       left /= scale;
@@ -3793,6 +3905,7 @@ xg_update_scrollbar_pos (struct frame *f,
              the height is less than the min size.  */
           gtk_widget_hide (wparent);
           gtk_widget_hide (wscroll);
+         hidden = true;
         }
       else
         {
@@ -3807,6 +3920,15 @@ xg_update_scrollbar_pos (struct frame *f,
           x_clear_area (f, oldx, oldy, oldw, oldh);
         }
 
+      if (!hidden)
+       {
+         GtkWidget *scrollbar = xg_get_widget_from_map (scrollbar_id);
+         GtkWidget *webox = gtk_widget_get_parent (scrollbar);
+
+         /* Don't obscure any child frames.  */
+         XLowerWindow (FRAME_X_DISPLAY (f), GTK_WIDGET_TO_X_WIN (webox));
+       }
+
       /* GTK does not redraw until the main loop is entered again, but
          if there are no X events pending we will not enter it.  So we sync
          here to get some events.  */
@@ -3872,6 +3994,15 @@ xg_update_horizontal_scrollbar_pos (struct frame *f,
          if there are no X events pending we will not enter it.  So we sync
          here to get some events.  */
 
+      {
+       GtkWidget *scrollbar =
+         xg_get_widget_from_map (scrollbar_id);
+       GtkWidget *webox = gtk_widget_get_parent (scrollbar);
+
+       /* Don't obscure any child frames.  */
+       XLowerWindow (FRAME_X_DISPLAY (f), GTK_WIDGET_TO_X_WIN (webox));
+      }
+
       x_sync (f);
       SET_FRAME_GARBAGED (f);
       cancel_mouse_face (f);
diff --git a/src/gtkutil.h b/src/gtkutil.h
index d67a7bc..244549f 100644
--- a/src/gtkutil.h
+++ b/src/gtkutil.h
@@ -172,6 +172,13 @@ extern void xg_set_frame_icon (struct frame *f,
                                Pixmap icon_pixmap,
                                Pixmap icon_mask);
 
+extern void xg_set_undecorated (struct frame *f, Lisp_Object undecorated);
+extern void xg_frame_restack (struct frame *f1, struct frame *f2, bool above);
+extern void xg_set_skip_taskbar (struct frame *f, Lisp_Object skip_taskbar);
+extern void xg_set_no_focus_on_map (struct frame *f, Lisp_Object 
no_focus_on_map);
+extern void xg_set_no_accept_focus (struct frame *f, Lisp_Object 
no_accept_focus);
+extern void xg_set_override_redirect (struct frame *f, Lisp_Object 
override_redirect);
+
 extern bool xg_prepare_tooltip (struct frame *f,
                                Lisp_Object string,
                                int *width,
diff --git a/src/nsfns.m b/src/nsfns.m
index 9e904c6..e8f035f 100644
--- a/src/nsfns.m
+++ b/src/nsfns.m
@@ -972,6 +972,13 @@ frame_parm_handler ns_frame_parm_handlers[] =
   0, /* x_set_sticky */
   0, /* x_set_tool_bar_position */
   0, /* x_set_inhibit_double_buffering */
+  0, /* x_set_undecorated */
+  0, /* x_set_parent_frame */
+  0, /* x_set_skip_taskbar */
+  0, /* x_set_no_focus_on_map */
+  0, /* x_set_no_accept_focus */
+  0, /* x_set_z_group */
+  0, /* x_set_override_redirect */
 };
 
 
@@ -1248,6 +1255,12 @@ This function is an internal primitive--use `make-frame' 
instead.  */)
   init_frame_faces (f);
 
   /* Read comment about this code in corresponding place in xfns.c.  */
+  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, 1,
                     Qx_create_frame_1);
diff --git a/src/nsterm.m b/src/nsterm.m
index b03ad52..162980a 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -6288,7 +6288,7 @@ not_in_argv (NSString *arg)
       if (WINDOWP (window)
           && !EQ (window, last_mouse_window)
           && !EQ (window, selected_window)
-          && (focus_follows_mouse
+          && (!NILP (focus_follows_mouse)
               || (EQ (XWINDOW (window)->frame,
                       XWINDOW (selected_window)->frame))))
         {
diff --git a/src/w32fns.c b/src/w32fns.c
index dd16d74..f7d3b72 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);
diff --git a/src/w32font.c b/src/w32font.c
index 37df1bc..ef6eac4 100644
--- a/src/w32font.c
+++ b/src/w32font.c
@@ -2553,11 +2553,22 @@ in the font selection dialog. */)
   SelectObject (hdc, oldobj);
   ReleaseDC (FRAME_W32_WINDOW (f), hdc);
 
-  if (!ChooseFont (&cf)
-      || logfont_to_fcname (&lf, cf.iPointSize, buf, 100) < 0)
-    return Qnil;
+  {
+    int count = SPECPDL_INDEX ();
+    Lisp_Object value = Qnil;
+
+    w32_dialog_in_progress (Qt);
+    specbind (Qinhibit_redisplay, Qt);
+    record_unwind_protect (w32_dialog_in_progress, Qnil);
+
+    if (ChooseFont (&cf)
+       && logfont_to_fcname (&lf, cf.iPointSize, buf, 100) >= 0)
+      value = DECODE_SYSTEM (build_string (buf));
 
-  return DECODE_SYSTEM (build_string (buf));
+    unbind_to (count, Qnil);
+
+    return value;
+  }
 }
 
 static const char *const w32font_booleans [] = {
diff --git a/src/w32term.c b/src/w32term.c
index 31f0b4a..b50f0d3 100644
--- a/src/w32term.c
+++ b/src/w32term.c
@@ -3095,7 +3095,8 @@ construct_mouse_wheel (struct input_event *result, W32Msg 
*msg, struct frame *f)
      coordinates, so cast to short to interpret them correctly.  */
   p.x = (short) LOWORD (msg->msg.lParam);
   p.y = (short) HIWORD (msg->msg.lParam);
-  ScreenToClient (msg->msg.hwnd, &p);
+  /* For the case that F's w32 window is not msg->msg.hwnd.  */
+  ScreenToClient (FRAME_W32_WINDOW (f), &p);
   XSETINT (result->x, p.x);
   XSETINT (result->y, p.y);
   XSETFRAME (result->frame_or_window, f);
@@ -3446,8 +3447,22 @@ w32_mouse_position (struct frame **fp, int insist, 
Lisp_Object *bar_window,
        /* If mouse was grabbed on a frame, give coords for that
           frame even if the mouse is now outside it.  Otherwise
           check for window under mouse on one of our frames.  */
-       f1 = (x_mouse_grabbed (dpyinfo) ? dpyinfo->last_mouse_frame
-             : x_any_window_to_frame (dpyinfo, WindowFromPoint (pt)));
+       if (x_mouse_grabbed (dpyinfo))
+         f1 = dpyinfo->last_mouse_frame;
+       else
+         {
+           HWND wfp = WindowFromPoint (pt);
+
+           if (wfp && (f1 = x_any_window_to_frame (dpyinfo, wfp)))
+             {
+               HWND cwfp = ChildWindowFromPoint (wfp, pt);
+               struct frame *f2;
+
+               /* If cwfp exists it should be one of our windows ...  */
+               if (cwfp && (f2 = x_any_window_to_frame (dpyinfo, cwfp)))
+                 f1 = f2;
+             }
+         }
 
        /* If not, is it one of our scroll bars?  */
        if (! f1)
@@ -3897,7 +3912,10 @@ w32_set_vertical_scroll_bar (struct window *w,
           /* Make sure scroll bar is "visible" before moving, to ensure the
              area of the parent window now exposed will be refreshed.  */
           my_show_window (f, hwnd, SW_HIDE);
-          MoveWindow (hwnd, left, top, width, max (height, 1), TRUE);
+/**           MoveWindow (hwnd, left, top, width, max (height, 1), TRUE); **/
+         /* Try to not draw over child frames.  */
+         SetWindowPos (hwnd, HWND_BOTTOM, left, top, width, max (height, 1),
+                        SWP_FRAMECHANGED);
 
          si.cbSize = sizeof (si);
          si.fMask = SIF_RANGE;
@@ -3995,7 +4013,10 @@ w32_set_horizontal_scroll_bar (struct window *w,
           /* Make sure scroll bar is "visible" before moving, to ensure the
              area of the parent window now exposed will be refreshed.  */
           my_show_window (f, hwnd, SW_HIDE);
-          MoveWindow (hwnd, left, top, width, max (height, 1), TRUE);
+/**           MoveWindow (hwnd, left, top, width, max (height, 1), TRUE); **/
+         /* Try to not draw over child frames.  */
+         SetWindowPos (hwnd, HWND_BOTTOM, left, top, max (width, 1), height,
+                        SWP_FRAMECHANGED);
 
          /* +++ SetScrollInfo +++ */
          si.cbSize = sizeof (si);
@@ -4649,7 +4670,7 @@ w32_read_socket (struct terminal *terminal,
                     in that case expose_frame will do nothing, and if
                     the various redisplay flags happen to be unset,
                     we are left with a blank frame.  */
-                 if (!FRAME_GARBAGED_P (f))
+                 if (!FRAME_GARBAGED_P (f) || FRAME_PARENT_FRAME (f))
                    {
                      HDC hdc = get_frame_dc (f);
 
@@ -4835,8 +4856,15 @@ w32_read_socket (struct terminal *terminal,
 
          if (f)
            {
-             /* Generate SELECT_WINDOW_EVENTs when needed.  */
-             if (!NILP (Vmouse_autoselect_window))
+             /* Maybe generate SELECT_WINDOW_EVENTs for
+                `mouse-autoselect-window'.  */
+             if (!NILP (Vmouse_autoselect_window)
+                 && (f == XFRAME (selected_frame)
+                     /* Switch to f from another frame iff
+                        focus_follows_mouse is set and f accepts
+                        focus.  */
+                     || (!NILP (focus_follows_mouse)
+                         && !FRAME_NO_ACCEPT_FOCUS (f))))
                {
                  static Lisp_Object last_mouse_window;
                  Lisp_Object window = window_from_coordinates
@@ -4848,20 +4876,16 @@ w32_read_socket (struct terminal *terminal,
                     only when it is active.  */
                  if (WINDOWP (window)
                      && !EQ (window, last_mouse_window)
-                     && !EQ (window, selected_window)
-                     /* For click-to-focus window managers
-                        create event iff we don't leave the
-                        selected frame.  */
-                     && (focus_follows_mouse
-                         || (EQ (XWINDOW (window)->frame,
-                                 XWINDOW (selected_window)->frame))))
+                     && !EQ (window, selected_window))
                    {
                      inev.kind = SELECT_WINDOW_EVENT;
                      inev.frame_or_window = window;
                    }
+
                  /* Remember the last window where we saw the mouse.  */
                  last_mouse_window = window;
                }
+
              if (!note_mouse_movement (f, &msg.msg))
                help_echo_string = previous_help_echo_string;
            }
@@ -4927,7 +4951,10 @@ w32_read_socket (struct terminal *terminal,
 
                 if (tool_bar_p
                    || (dpyinfo->w32_focus_frame
-                       && f != dpyinfo->w32_focus_frame))
+                       && f != dpyinfo->w32_focus_frame
+                       /* This does not help when the click happens in
+                          a grand-parent frame.  */
+                       && !frame_ancestor_p (f, dpyinfo->w32_focus_frame)))
                  inev.kind = NO_EVENT;
              }
 
@@ -4964,21 +4991,40 @@ w32_read_socket (struct terminal *terminal,
 
            if (f)
              {
-
                if (!dpyinfo->w32_focus_frame
                    || f == dpyinfo->w32_focus_frame)
+                 /* Emit an Emacs wheel-up/down event.  */
                  {
-                   /* Emit an Emacs wheel-up/down event.  */
                    construct_mouse_wheel (&inev, &msg, f);
+
+                   /* Ignore any mouse motion that happened before this
+                      event; any subsequent mouse-movement Emacs events
+                      should reflect only motion after the ButtonPress.  */
+                   f->mouse_moved = false;
+                   f->last_tool_bar_item = -1;
+                   dpyinfo->last_mouse_frame = f;
+                 }
+               else if (FRAME_NO_ACCEPT_FOCUS (f)
+                        && !x_mouse_grabbed (dpyinfo))
+                 {
+                   Lisp_Object frame1 = get_frame_param (f, 
Qmouse_wheel_frame);
+                   struct frame *f1 = FRAMEP (frame1) ? XFRAME (frame1) : NULL;
+
+                   if (f1 && FRAME_LIVE_P (f1) && FRAME_W32_P (f1))
+                     {
+                       construct_mouse_wheel (&inev, &msg, f1);
+                       f1->mouse_moved = false;
+                       f1->last_tool_bar_item = -1;
+                       dpyinfo->last_mouse_frame = f1;
+                     }
+                   else
+                     dpyinfo->last_mouse_frame = f;
                  }
-               /* Ignore any mouse motion that happened before this
-                  event; any subsequent mouse-movement Emacs events
-                  should reflect only motion after the
-                  ButtonPress.  */
-               f->mouse_moved = false;
-               f->last_tool_bar_item = -1;
+               else
+                 dpyinfo->last_mouse_frame = f;
              }
-           dpyinfo->last_mouse_frame = f;
+           else
+             dpyinfo->last_mouse_frame = f;
          }
          break;
 
@@ -5031,6 +5077,7 @@ w32_read_socket (struct terminal *terminal,
                  w32fullscreen_hook (f);
                }
            }
+
          check_visibility = 1;
          break;
 
@@ -5969,6 +6016,8 @@ x_calc_absolute_position (struct frame *f)
      are computed correctly (Bug#21173).  */
   int display_left = 0;
   int display_top = 0;
+  struct frame *p = FRAME_PARENT_FRAME (f);
+
   if (flags & (XNegative | YNegative))
     {
       Lisp_Object list;
@@ -5997,18 +6046,34 @@ x_calc_absolute_position (struct frame *f)
   /* Treat negative positions as relative to the rightmost bottommost
      position that fits on the screen.  */
   if (flags & XNegative)
-    f->left_pos = (x_display_pixel_width (FRAME_DISPLAY_INFO (f))
-                   + display_left
-                  - FRAME_PIXEL_WIDTH (f)
-                  + f->left_pos
-                  - (left_right_borders_width - 1));
+    {
+      if (p)
+       f->left_pos = (FRAME_PIXEL_WIDTH (p)
+                      - FRAME_PIXEL_WIDTH (f)
+                      + f->left_pos
+                      - (left_right_borders_width - 1));
+      else
+       f->left_pos = (x_display_pixel_width (FRAME_DISPLAY_INFO (f))
+                      + display_left
+                      - FRAME_PIXEL_WIDTH (f)
+                      + f->left_pos
+                      - (left_right_borders_width - 1));
+    }
 
   if (flags & YNegative)
-    f->top_pos = (x_display_pixel_height (FRAME_DISPLAY_INFO (f))
-                  + display_top
-                 - FRAME_PIXEL_HEIGHT (f)
-                 + f->top_pos
-                 - (top_bottom_borders_height - 1));
+    {
+      if (p)
+       f->top_pos = (FRAME_PIXEL_HEIGHT (p)
+                     - FRAME_PIXEL_HEIGHT (f)
+                     + f->top_pos
+                     - (top_bottom_borders_height - 1));
+      else
+       f->top_pos = (x_display_pixel_height (FRAME_DISPLAY_INFO (f))
+                     + display_top
+                     - FRAME_PIXEL_HEIGHT (f)
+                     + f->top_pos
+                     - (top_bottom_borders_height - 1));
+    }
 
   /* The left_pos and top_pos are now relative to the top and left
      screen edges, so the flags should correspond.  */
@@ -6046,11 +6111,16 @@ x_set_offset (struct frame *f, register int xoff, 
register int yoff,
   modified_left = f->left_pos;
   modified_top = f->top_pos;
 
-  my_set_window_pos (FRAME_W32_WINDOW (f),
-                    NULL,
-                    modified_left, modified_top,
-                    0, 0,
-                    SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
+  if (!FRAME_PARENT_FRAME (f))
+    my_set_window_pos (FRAME_W32_WINDOW (f), NULL,
+                      modified_left, modified_top,
+                      0, 0,
+                      SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
+  else
+    my_set_window_pos (FRAME_W32_WINDOW (f), HWND_TOP,
+                      modified_left, modified_top,
+                      0, 0,
+                      SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
   unblock_input ();
 }
 
@@ -6254,11 +6324,18 @@ x_set_window_size (struct frame *f, bool change_gravity,
                Fcons (make_number (rect.right - rect.left),
                       make_number (rect.bottom - rect.top))));
 
-      my_set_window_pos (FRAME_W32_WINDOW (f), NULL,
-                        0, 0,
-                        rect.right - rect.left,
-                        rect.bottom - rect.top,
-                        SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
+      if (!FRAME_PARENT_FRAME (f))
+       my_set_window_pos (FRAME_W32_WINDOW (f), NULL,
+                          0, 0,
+                          rect.right - rect.left,
+                          rect.bottom - rect.top,
+                          SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
+      else
+       my_set_window_pos (FRAME_W32_WINDOW (f), HWND_TOP,
+                          0, 0,
+                          rect.right - rect.left,
+                          rect.bottom - rect.top,
+                          SWP_NOMOVE | SWP_NOACTIVATE);
 
       change_frame_size (f,
                         ((pixelwidth == 0)
@@ -6447,18 +6524,21 @@ x_make_frame_visible (struct frame *f)
       if (! FRAME_ICONIFIED_P (f)
          && ! f->output_data.w32->asked_for_visible)
        {
-         RECT workarea_rect;
-         RECT window_rect;
-
-         /* Adjust vertical window position in order to avoid being
-            covered by a taskbar placed at the bottom of the desktop. */
-         SystemParametersInfo (SPI_GETWORKAREA, 0, &workarea_rect, 0);
-         GetWindowRect (FRAME_W32_WINDOW (f), &window_rect);
-         if (window_rect.bottom > workarea_rect.bottom
-             && window_rect.top > workarea_rect.top)
-           f->top_pos = max (window_rect.top
-                             - window_rect.bottom + workarea_rect.bottom,
-                             workarea_rect.top);
+         if (!FRAME_PARENT_FRAME (f))
+           {
+             RECT workarea_rect;
+             RECT window_rect;
+
+             /* Adjust vertical window position in order to avoid being
+                covered by a taskbar placed at the bottom of the desktop. */
+             SystemParametersInfo (SPI_GETWORKAREA, 0, &workarea_rect, 0);
+             GetWindowRect (FRAME_W32_WINDOW (f), &window_rect);
+             if (window_rect.bottom > workarea_rect.bottom
+                 && window_rect.top > workarea_rect.top)
+               f->top_pos = max (window_rect.top
+                                 - window_rect.bottom + workarea_rect.bottom,
+                                 workarea_rect.top);
+           }
 
          x_set_offset (f, f->left_pos, f->top_pos, 0);
        }
@@ -6473,7 +6553,11 @@ x_make_frame_visible (struct frame *f)
         set for minimized windows that are still visible, so use that to
         determine the appropriate flag to pass ShowWindow.  */
       my_show_window (f, FRAME_W32_WINDOW (f),
-                      FRAME_ICONIFIED_P (f) ? SW_RESTORE : SW_SHOWNORMAL);
+                      FRAME_ICONIFIED_P (f)
+                     ? SW_RESTORE
+                     : FRAME_NO_FOCUS_ON_MAP (f)
+                     ? SW_SHOWNOACTIVATE
+                     : SW_SHOWNORMAL);
     }
 
   /* Synchronize to ensure Emacs knows the frame is visible
diff --git a/src/w32term.h b/src/w32term.h
index 990d379..6896ef4 100644
--- a/src/w32term.h
+++ b/src/w32term.h
@@ -246,6 +246,7 @@ extern void x_set_internal_border_width (struct frame *f,
                                         Lisp_Object value,
                                         Lisp_Object oldval);
 extern void initialize_frame_menubar (struct frame *);
+extern void w32_dialog_in_progress (Lisp_Object in_progress);
 
 /* w32inevt.c */
 extern int w32_kbd_patch_key (KEY_EVENT_RECORD *event, int cpId);
diff --git a/src/xdisp.c b/src/xdisp.c
index af086d1..42a59d6 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -11767,6 +11767,7 @@ x_consider_frame_title (Lisp_Object frame)
              && FRAME_KBOARD (tf) == FRAME_KBOARD (f)
              && !FRAME_MINIBUF_ONLY_P (tf)
              && !EQ (other_frame, tip_frame)
+             && !FRAME_PARENT_FRAME (tf)
              && (FRAME_VISIBLE_P (tf) || FRAME_ICONIFIED_P (tf)))
            break;
        }
@@ -11883,6 +11884,7 @@ prepare_menu_bars (void)
            continue;
 
          if (!EQ (frame, tooltip_frame)
+             && !FRAME_PARENT_FRAME (f)
              && (FRAME_ICONIFIED_P (f)
                  || FRAME_VISIBLE_P (f) == 1
                  /* Exclude TTY frames that are obscured because they
@@ -11929,6 +11931,10 @@ prepare_menu_bars (void)
            continue;
 
          run_window_size_change_functions (frame);
+
+         if (FRAME_PARENT_FRAME (f))
+           continue;
+
          menu_bar_hooks_run = update_menu_bar (f, false, menu_bar_hooks_run);
 #ifdef HAVE_WINDOW_SYSTEM
          update_tool_bar (f, false);
diff --git a/src/xfns.c b/src/xfns.c
index d3e0839..3d66744 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 *) &timestamp, 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);
diff --git a/src/xmenu.c b/src/xmenu.c
index 249cd69..2805249 100644
--- a/src/xmenu.c
+++ b/src/xmenu.c
@@ -140,14 +140,26 @@ menubar_id_to_frame (LWLIB_ID id)
 void
 x_menu_set_in_use (bool in_use)
 {
+  Lisp_Object frames, frame;
+
   menu_items_inuse = in_use ? Qt : Qnil;
   popup_activated_flag = in_use;
 #ifdef USE_X_TOOLKIT
   if (popup_activated_flag)
     x_activate_timeout_atimer ();
 #endif
-}
 
+  /* Don't let frames in `above' z-group obscure popups.  */
+  FOR_EACH_FRAME (frames, frame)
+    {
+      struct frame *f = XFRAME (frame);
+
+      if (in_use && FRAME_Z_GROUP_ABOVE (f))
+       x_set_z_group (f, Qabove_suspended, Qabove);
+      else if (!in_use && FRAME_Z_GROUP_ABOVE_SUSPENDED (f))
+       x_set_z_group (f, Qabove, Qabove_suspended);
+    }
+}
 #endif
 
 /* Wait for an X event to arrive or for a timer to expire.  */
diff --git a/src/xterm.c b/src/xterm.c
index 1d14407..4444a5c 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -945,11 +945,14 @@ x_set_frame_alpha (struct frame *f)
      Do this unconditionally as this function is called on reparent when
      alpha has not changed on the frame.  */
 
-  parent = x_find_topmost_parent (f);
-  if (parent != None)
-    XChangeProperty (dpy, parent, dpyinfo->Xatom_net_wm_window_opacity,
-                     XA_CARDINAL, 32, PropModeReplace,
-                     (unsigned char *) &opac, 1);
+  if (!FRAME_PARENT_FRAME (f))
+    {
+      parent = x_find_topmost_parent (f);
+      if (parent != None)
+       XChangeProperty (dpy, parent, dpyinfo->Xatom_net_wm_window_opacity,
+                        XA_CARDINAL, 32, PropModeReplace,
+                        (unsigned char *) &opac, 1);
+    }
 
   /* return unless necessary */
   {
@@ -4964,6 +4967,9 @@ XTmouse_position (struct frame **fp, int insist, 
Lisp_Object *bar_window,
         containing the pointer.  */
       {
        Window win, child;
+#ifdef USE_GTK
+       Window first_win = 0;
+#endif
        int win_x, win_y;
        int parent_x = 0, parent_y = 0;
 
@@ -5010,20 +5016,37 @@ XTmouse_position (struct frame **fp, int insist, 
Lisp_Object *bar_window,
                                       &child);
 
                if (child == None || child == win)
-                 break;
+                 {
+#ifdef USE_GTK
+                   /* On GTK we have not inspected WIN yet.  If it has
+                      a frame and that frame has a parent, use it.  */
+                   struct frame *f = x_window_to_frame (dpyinfo, win);
+
+                   if (f && FRAME_PARENT_FRAME (f))
+                     first_win = win;
+#endif
+                   break;
+                 }
 #ifdef USE_GTK
                /* We don't wan't to know the innermost window.  We
                   want the edit window.  For non-Gtk+ the innermost
                   window is the edit window.  For Gtk+ it might not
                   be.  It might be the tool bar for example.  */
                if (x_window_to_frame (dpyinfo, win))
-                 break;
+                 /* But don't hurry.  We might find a child frame
+                    beneath.  */
+                 first_win = win;
 #endif
                win = child;
                parent_x = win_x;
                parent_y = win_y;
              }
 
+#ifdef USE_GTK
+           if (first_win)
+             win = first_win;
+#endif
+
            /* Now we know that:
               win is the innermost window containing the pointer
               (XTC says it has no child containing the pointer),
@@ -6496,10 +6519,14 @@ x_scroll_bar_create (struct window *w, int top, int 
left,
     Widget scroll_bar = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar);
     XtConfigureWidget (scroll_bar, left, top, width, max (height, 1), 0);
     XtMapWidget (scroll_bar);
+    /* Don't obscure any child frames.  */
+    XLowerWindow (FRAME_X_DISPLAY (f), bar->x_window);
 #endif /* not USE_GTK */
     }
 #else /* not USE_TOOLKIT_SCROLL_BARS */
-  XMapRaised (FRAME_X_DISPLAY (f), bar->x_window);
+  XMapWindow (FRAME_X_DISPLAY (f), bar->x_window);
+  /* Don't obscure any child frames.  */
+  XLowerWindow (FRAME_X_DISPLAY (f), bar->x_window);
 #endif /* not USE_TOOLKIT_SCROLL_BARS */
 
   unblock_input ();
@@ -7067,10 +7094,10 @@ x_scroll_bar_expose (struct scroll_bar *bar, const 
XEvent *event)
                  /* x, y, width, height */
                  0, 0, bar->width - 1, bar->height - 1);
 
-   /* Restore the foreground color of the GC if we changed it above.  */
-   if (f->output_data.x->scroll_bar_foreground_pixel != -1)
-     XSetForeground (FRAME_X_DISPLAY (f), gc,
-                    FRAME_FOREGROUND_PIXEL (f));
+  /* Restore the foreground color of the GC if we changed it above.  */
+  if (f->output_data.x->scroll_bar_foreground_pixel != -1)
+    XSetForeground (FRAME_X_DISPLAY (f), gc,
+                   FRAME_FOREGROUND_PIXEL (f));
 
    unblock_input ();
 
@@ -7839,8 +7866,21 @@ handle_one_xevent (struct x_display_info *dpyinfo,
       f = x_top_window_to_frame (dpyinfo, event->xreparent.window);
       if (f)
         {
-          f->output_data.x->parent_desc = event->xreparent.parent;
-          x_real_positions (f, &f->left_pos, &f->top_pos);
+         /* Maybe we shouldn't set this for child frames ??  */
+         f->output_data.x->parent_desc = event->xreparent.parent;
+         if (!FRAME_PARENT_FRAME (f))
+           x_real_positions (f, &f->left_pos, &f->top_pos);
+         else
+           {
+             Window root;
+             unsigned int dummy_uint;
+
+             block_input ();
+             XGetGeometry (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
+                           &root, &f->left_pos, &f->top_pos,
+                           &dummy_uint, &dummy_uint, &dummy_uint, &dummy_uint);
+             unblock_input ();
+           }
 
           /* Perhaps reparented due to a WM restart.  Reset this.  */
           FRAME_DISPLAY_INFO (f)->wm_type = X_WMTYPE_UNKNOWN;
@@ -8000,7 +8040,26 @@ handle_one_xevent (struct x_display_info *dpyinfo,
           /* Check if fullscreen was specified before we where mapped the
              first time, i.e. from the command line.  */
           if (!f->output_data.x->has_been_visible)
-            x_check_fullscreen (f);
+           {
+
+             x_check_fullscreen (f);
+#ifndef USE_GTK
+             /* For systems that cannot synthesize `skip_taskbar' for
+                unmapped windows do the following.  */
+             if (FRAME_SKIP_TASKBAR (f))
+               x_set_skip_taskbar (f, Qt, Qnil);
+#endif /* Not USE_GTK */
+           }
+
+         if (!iconified)
+           {
+             /* The `z-group' is reset every time a frame becomes
+                invisible.  Handle this here.  */
+             if (FRAME_Z_GROUP (f) == z_group_above)
+               x_set_z_group (f, Qabove, Qnil);
+             else if (FRAME_Z_GROUP (f) == z_group_below)
+               x_set_z_group (f, Qbelow, Qnil);
+           }
 
           SET_FRAME_VISIBLE (f, 1);
           SET_FRAME_ICONIFIED (f, false);
@@ -8444,34 +8503,46 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 #endif
         if (f)
           {
-
-            /* Generate SELECT_WINDOW_EVENTs when needed.
-               Don't let popup menus influence things (bug#1261).  */
-            if (!NILP (Vmouse_autoselect_window) && !popup_activated ())
+           /* Maybe generate a SELECT_WINDOW_EVENT for
+              `mouse-autoselect-window' but don't let popup menus
+              interfere with this (Bug#1261).  */
+            if (!NILP (Vmouse_autoselect_window)
+               && !popup_activated ()
+               /* Don't switch if we're currently in the minibuffer.
+                  This tries to work around problems where the
+                  minibuffer gets unselected unexpectedly, and where
+                  you then have to move your mouse all the way down to
+                  the minibuffer to select it.  */
+               && !MINI_WINDOW_P (XWINDOW (selected_window))
+               /* With `focus-follows-mouse' non-nil create an event
+                  also when the target window is on another frame.  */
+               && (f == XFRAME (selected_frame)
+                   || !NILP (focus_follows_mouse)))
              {
                static Lisp_Object last_mouse_window;
                Lisp_Object window = window_from_coordinates
                  (f, event->xmotion.x, event->xmotion.y, 0, false);
 
-               /* Window will be selected only when it is not selected now and
-                  last mouse movement event was not in it.  Minibuffer window
-                  will be selected only when it is active.  */
+               /* A window will be autoselected only when it is not
+                  selected now and the last mouse movement event was
+                  not in it.  The remainder of the code is a bit vague
+                  wrt what a "window" is.  For immediate autoselection,
+                  the window is usually the entire window but for GTK
+                  where the scroll bars don't count.  For delayed
+                  autoselection the window is usually the window's text
+                  area including the margins.  */
                if (WINDOWP (window)
                    && !EQ (window, last_mouse_window)
-                   && !EQ (window, selected_window)
-                   /* For click-to-focus window managers
-                      create event iff we don't leave the
-                      selected frame.  */
-                   && (focus_follows_mouse
-                       || (EQ (XWINDOW (window)->frame,
-                               XWINDOW (selected_window)->frame))))
+                   && !EQ (window, selected_window))
                  {
                    inev.ie.kind = SELECT_WINDOW_EVENT;
                    inev.ie.frame_or_window = window;
                  }
+
                /* Remember the last window where we saw the mouse.  */
                last_mouse_window = window;
              }
+
             if (!note_mouse_movement (f, &event->xmotion))
              help_echo_string = previous_help_echo_string;
           }
@@ -8621,7 +8692,19 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 
              XSETFRAME (frame, f);
 
-             x_real_positions (f, &f->left_pos, &f->top_pos);
+             if (!FRAME_PARENT_FRAME (f))
+               x_real_positions (f, &f->left_pos, &f->top_pos);
+             else
+               {
+                 Window root;
+                 unsigned int dummy_uint;
+
+                 block_input ();
+                 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
+                               &root, &f->left_pos, &f->top_pos,
+                               &dummy_uint, &dummy_uint, &dummy_uint, 
&dummy_uint);
+                 unblock_input ();
+               }
 
              if (old_left != f->left_pos || old_top != f->top_pos)
                {
@@ -8650,8 +8733,35 @@ handle_one_xevent (struct x_display_info *dpyinfo,
        dpyinfo->last_mouse_glyph_frame = NULL;
        x_display_set_last_user_time (dpyinfo, event->xbutton.time);
 
-        f = (x_mouse_grabbed (dpyinfo) ? dpyinfo->last_mouse_frame
-            : x_window_to_frame (dpyinfo, event->xbutton.window));
+       if (x_mouse_grabbed (dpyinfo))
+         f = dpyinfo->last_mouse_frame;
+       else
+         {
+           f = x_window_to_frame (dpyinfo, event->xbutton.window);
+
+           if (f && event->xbutton.type == ButtonPress
+               && !popup_activated ()
+               && !x_window_to_scroll_bar (event->xbutton.display,
+                                           event->xbutton.window, 2)
+               && !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 *hf = dpyinfo->x_highlight_frame;
+
+               if (FRAME_PARENT_FRAME (f) || frame_ancestor_p (f, hf))
+                 {
+                   block_input ();
+                   XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
+                                   RevertToParent, CurrentTime);
+                   if (FRAME_PARENT_FRAME (f))
+                     XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW 
(f));
+                   unblock_input ();
+                 }
+             }
+         }
 
 #ifdef USE_GTK
         if (f && xg_event_is_for_scrollbar (f, event))
@@ -10007,6 +10117,7 @@ static void
 x_calc_absolute_position (struct frame *f)
 {
   int flags = f->size_hint_flags;
+  struct frame *p = FRAME_PARENT_FRAME (f);
 
   /* We have nothing to do if the current position
      is already for the top-left corner.  */
@@ -10015,32 +10126,72 @@ x_calc_absolute_position (struct frame *f)
 
   /* Treat negative positions as relative to the leftmost bottommost
      position that fits on the screen.  */
-  if (flags & XNegative)
-    f->left_pos = x_display_pixel_width (FRAME_DISPLAY_INFO (f))
-      - FRAME_PIXEL_WIDTH (f) + f->left_pos;
+  if ((flags & XNegative) && (f->left_pos <= 0))
+    {
+      int width = FRAME_PIXEL_WIDTH (f);
 
-  {
-    int height = FRAME_PIXEL_HEIGHT (f);
+      /* A frame that has been visible at least once should have outer
+        edges.  */
+      if (f->output_data.x->has_been_visible && !p)
+       {
+         Lisp_Object frame;
+         Lisp_Object edges = Qnil;
+
+         XSETFRAME (frame, f);
+         edges = Fx_frame_edges (frame, Qouter_edges);
+         if (!NILP (edges))
+           width = (XINT (Fnth (make_number (2), edges))
+                    - XINT (Fnth (make_number (0), edges)));
+       }
+
+      if (p)
+       f->left_pos = (FRAME_PIXEL_WIDTH (p) - width - 2 * f->border_width
+                      + f->left_pos);
+      else
+       f->left_pos = (x_display_pixel_width (FRAME_DISPLAY_INFO (f))
+                      - width + f->left_pos);
+
+    }
+
+  if ((flags & YNegative) && (f->top_pos <= 0))
+    {
+      int height = FRAME_PIXEL_HEIGHT (f);
 
 #if defined USE_X_TOOLKIT && defined USE_MOTIF
-    /* Something is fishy here.  When using Motif, starting Emacs with
-       `-g -0-0', the frame appears too low by a few pixels.
+      /* Something is fishy here.  When using Motif, starting Emacs with
+        `-g -0-0', the frame appears too low by a few pixels.
 
-       This seems to be so because initially, while Emacs is starting,
-       the column widget's height and the frame's pixel height are
-       different.  The column widget's height is the right one.  In
-       later invocations, when Emacs is up, the frame's pixel height
-       is right, though.
+        This seems to be so because initially, while Emacs is starting,
+        the column widget's height and the frame's pixel height are
+        different.  The column widget's height is the right one.  In
+        later invocations, when Emacs is up, the frame's pixel height
+        is right, though.
 
-       It's not obvious where the initial small difference comes from.
-       2000-12-01, gerd.  */
+        It's not obvious where the initial small difference comes from.
+        2000-12-01, gerd.  */
 
-    XtVaGetValues (f->output_data.x->column_widget, XtNheight, &height, NULL);
+      XtVaGetValues (f->output_data.x->column_widget, XtNheight, &height, 
NULL);
 #endif
 
-    if (flags & YNegative)
-      f->top_pos = x_display_pixel_height (FRAME_DISPLAY_INFO (f))
-       - height + f->top_pos;
+      if (f->output_data.x->has_been_visible && !p)
+       {
+         Lisp_Object frame;
+         Lisp_Object edges = Qnil;
+
+         XSETFRAME (frame, f);
+         if (NILP (edges))
+           edges = Fx_frame_edges (frame, Qouter_edges);
+         if (!NILP (edges))
+           height = (XINT (Fnth (make_number (3), edges))
+                     - XINT (Fnth (make_number (1), edges)));
+       }
+
+      if (p)
+       f->top_pos = (FRAME_PIXEL_HEIGHT (p) - height - 2 * f->border_width
+                      + f->top_pos);
+      else
+       f->top_pos = (x_display_pixel_height (FRAME_DISPLAY_INFO (f))
+                     - height + f->top_pos);
   }
 
   /* The left_pos and top_pos
@@ -10125,6 +10276,7 @@ x_set_offset (struct frame *f, register int xoff, 
register int yoff, int change_
      need to compute the top/left offset adjustment for this frame.  */
 
   if (change_gravity != 0
+      && !FRAME_PARENT_FRAME (f)
       && (FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN
          || (FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_A
              && (FRAME_X_OUTPUT (f)->move_offset_left == 0
@@ -10255,6 +10407,92 @@ x_set_sticky (struct frame *f, Lisp_Object new_value, 
Lisp_Object old_value)
                 dpyinfo->Xatom_net_wm_state_sticky, None);
 }
 
+/**
+ * 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>.  If nil, lift these restrictions.
+ *
+ * Some window managers may not honor this parameter.
+ */
+void
+x_set_skip_taskbar (struct frame *f, Lisp_Object new_value, Lisp_Object 
old_value)
+{
+  if (!EQ (new_value, old_value))
+    {
+#ifdef USE_GTK
+      xg_set_skip_taskbar (f, new_value);
+#else
+      Lisp_Object frame;
+      struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
+
+      XSETFRAME (frame, f);
+      set_wm_state (frame, !NILP (new_value),
+                   dpyinfo->Xatom_net_wm_state_skip_taskbar, None);
+#endif /* USE_GTK */
+      FRAME_SKIP_TASKBAR (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.
+ */
+void
+x_set_z_group (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
+{
+  /* We don't care about old_value.  The window manager might have
+     reset the value without telling us.  */
+  Lisp_Object frame;
+  struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
+
+  XSETFRAME (frame, f);
+
+  if (NILP (new_value))
+    {
+      set_wm_state (frame, false,
+                   dpyinfo->Xatom_net_wm_state_above, None);
+      set_wm_state (frame, false,
+                   dpyinfo->Xatom_net_wm_state_below, None);
+      FRAME_Z_GROUP (f) = z_group_none;
+    }
+  else if (EQ (new_value, Qabove))
+    {
+      set_wm_state (frame, true,
+                   dpyinfo->Xatom_net_wm_state_above, None);
+      set_wm_state (frame, false,
+                   dpyinfo->Xatom_net_wm_state_below, None);
+      FRAME_Z_GROUP (f) = z_group_above;
+    }
+  else if (EQ (new_value, Qbelow))
+    {
+      set_wm_state (frame, false,
+                   dpyinfo->Xatom_net_wm_state_above, None);
+      set_wm_state (frame, true,
+                   dpyinfo->Xatom_net_wm_state_below, None);
+      FRAME_Z_GROUP (f) = z_group_below;
+    }
+  else if (EQ (new_value, Qabove_suspended))
+    {
+      set_wm_state (frame, false,
+                   dpyinfo->Xatom_net_wm_state_above, None);
+      FRAME_Z_GROUP (f) = z_group_above_suspended;
+    }
+  else
+    error ("Invalid z-group specification");
+}
+
+
 /* Return the current _NET_WM_STATE.
    SIZE_STATE is set to one of the FULLSCREEN_* values.
    Set *STICKY to the sticky state.
@@ -10758,7 +10996,8 @@ x_set_window_size_1 (struct frame *f, bool 
change_gravity,
   int old_height = FRAME_PIXEL_HEIGHT (f);
   Lisp_Object fullscreen = get_frame_param (f, Qfullscreen);
 
-  if (change_gravity) f->win_gravity = NorthWestGravity;
+  if (change_gravity)
+    f->win_gravity = NorthWestGravity;
   x_wm_set_size_hint (f, 0, false);
 
   /* When the frame is fullheight and we only want to change the width
@@ -11047,6 +11286,26 @@ xembed_send_message (struct frame *f, Time t, enum 
xembed_message msg,
 void
 x_make_frame_visible (struct frame *f)
 {
+  if (FRAME_PARENT_FRAME (f))
+    {
+      if (!FRAME_VISIBLE_P (f))
+       {
+         block_input ();
+#ifdef USE_GTK
+         gtk_widget_show_all (FRAME_GTK_OUTER_WIDGET (f));
+         XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
+                      f->left_pos, f->top_pos);
+#else
+         XMapRaised (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f));
+#endif
+         unblock_input ();
+
+         SET_FRAME_VISIBLE (f, true);
+         SET_FRAME_ICONIFIED (f, false);
+       }
+      return;
+    }
+
   block_input ();
 
   x_set_bitmap_icon (f);
@@ -11115,9 +11374,10 @@ x_make_frame_visible (struct frame *f)
        because the window manager may choose the position
        and we don't want to override it.  */
 
-    if (! FRAME_VISIBLE_P (f)
-       && ! FRAME_ICONIFIED_P (f)
-       && ! FRAME_X_EMBEDDED_P (f)
+    if (!FRAME_VISIBLE_P (f)
+       && !FRAME_ICONIFIED_P (f)
+       && !FRAME_X_EMBEDDED_P (f)
+       && !FRAME_PARENT_FRAME (f)
        && f->win_gravity == NorthWestGravity
        && previously_visible)
       {
@@ -11180,15 +11440,15 @@ x_make_frame_invisible (struct frame *f)
     xembed_set_info (f, 0);
   else
 #endif
-  {
 
-  if (! XWithdrawWindow (FRAME_X_DISPLAY (f), window,
-                        DefaultScreen (FRAME_X_DISPLAY (f))))
-    {
-      unblock_input ();
-      error ("Can't notify window manager of window withdrawal");
-    }
-  }
+    if (! XWithdrawWindow (FRAME_X_DISPLAY (f), window,
+                          DefaultScreen (FRAME_X_DISPLAY (f))))
+      {
+       unblock_input ();
+       error ("Can't notify window manager of window withdrawal");
+      }
+
+  x_sync (f);
 
   /* We can't distinguish this from iconification
      just by the event that we get from the server.
@@ -11198,8 +11458,6 @@ x_make_frame_invisible (struct frame *f)
   SET_FRAME_VISIBLE (f, 0);
   SET_FRAME_ICONIFIED (f, false);
 
-  x_sync (f);
-
   unblock_input ();
 }
 
@@ -12355,6 +12613,9 @@ x_term_init (Lisp_Object display_name, char 
*xrm_option, char *resource_name)
       ATOM_REFS_INIT ("SM_CLIENT_ID", Xatom_SM_CLIENT_ID)
       ATOM_REFS_INIT ("_XSETTINGS_SETTINGS", Xatom_xsettings_prop)
       ATOM_REFS_INIT ("MANAGER", Xatom_xsettings_mgr)
+      ATOM_REFS_INIT ("_NET_WM_STATE_SKIP_TASKBAR", 
Xatom_net_wm_state_skip_taskbar)
+      ATOM_REFS_INIT ("_NET_WM_STATE_ABOVE", Xatom_net_wm_state_above)
+      ATOM_REFS_INIT ("_NET_WM_STATE_BELOW", Xatom_net_wm_state_below)
     };
 
     int i;
diff --git a/src/xterm.h b/src/xterm.h
index 32c879b..a752570 100644
--- a/src/xterm.h
+++ b/src/xterm.h
@@ -447,9 +447,9 @@ struct x_display_info
   /* Atoms dealing with EWMH (i.e. _NET_...) */
   Atom Xatom_net_wm_state, Xatom_net_wm_state_fullscreen,
     Xatom_net_wm_state_maximized_horz, Xatom_net_wm_state_maximized_vert,
-    Xatom_net_wm_state_sticky, Xatom_net_wm_state_hidden,
-    Xatom_net_frame_extents,
-    Xatom_net_current_desktop, Xatom_net_workarea;
+    Xatom_net_wm_state_sticky, Xatom_net_wm_state_above, 
Xatom_net_wm_state_below,
+    Xatom_net_wm_state_hidden, Xatom_net_wm_state_skip_taskbar,
+    Xatom_net_frame_extents, Xatom_net_current_desktop, Xatom_net_workarea;
 
   /* XSettings atoms and windows.  */
   Atom Xatom_xsettings_sel, Xatom_xsettings_prop, Xatom_xsettings_mgr;
@@ -1168,6 +1168,8 @@ x_mutable_colormap (Visual *visual)
 }
 
 extern void x_set_sticky (struct frame *, Lisp_Object, Lisp_Object);
+extern void x_set_skip_taskbar (struct frame *, Lisp_Object, Lisp_Object);
+extern void x_set_z_group (struct frame *, Lisp_Object, Lisp_Object);
 extern bool x_wm_supports (struct frame *, Atom);
 extern void x_wait_for_event (struct frame *, int);
 extern void x_clear_under_internal_border (struct frame *f);



reply via email to

[Prev in Thread] Current Thread [Next in Thread]