Subject: Re: bug#25408: Remove Decorations Around Emacs Frame (NS port)

From: Alan Third <[email-masked]>
Date: Mon, 17 Apr 2017 19:55:37 +0100

On Mon, Apr 17, 2017 at 07:20:20PM +0200, martin rudalics wrote:
> > I’m not sure about the decoration stuff, but I think, from a quick
> > glance at the GNUStep docs, the parent/child window stuff should work.
> >
> > I’ll try and build it under GNUStep at some point to check it works.
> > I’ve got a GNU/Linux virtual machine around here somewhere...
> 
> Here, building with GNUStep currently fails as follows:
> 
<snip>
> 
> No good idea what made it choke.  The plethora of warnings is terribly
> confusing.

I think it was the use of the ‘visible’ method on NSToolbar, which it
appears I’ve made up, but which works on Cocoa. I’ve changed it to
look directly at the ‘isVisible’ instance variable.

I also noticed that it doesn’t like NSWindow:setStyleMask, so I’ve
changed that to directly update the relevant instance variable too.

I think some of the warnings are related to comparing an Objective C
object to NULL instead of nil, or vice versa. I can’t see any
difference between them here, and I don’t get any warnings from clang.

New patch attached.
-- 
Alan Third
>From 7456d41a9aeac4f252cc98a5396fd7cf38451a38 Mon Sep 17 00:00:00 2001
From: Alan Third <[email-masked]>
Date: Fri, 14 Apr 2017 10:02:38 +0100
Subject: [PATCH] Add undecorated and parent frames to NS port
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* src/frame.h:
* src/frame.c: Enable ‘undecorated’ and ‘parent’ frame definitions.
* src/nsfns.m: Add x_set_parent_frame and x_set_undecorated to handler
struct.
(Fx-create_frame): Handle ‘parent-frame’ and ‘undecorated’ frame
parameter.
* src/nsmenu.m (free_frame_tool_bar, update_frame_tool_bar):
FRAME_TOOLBAR_HEIGHT is no longer a variable.
* src/nsterm.h (NS_PARENT_WINDOW_LEFT_POS, NS_PARENT_WINDOW_TOP_POS):
Add #defines to find the screen position of the parent frame.
(EmacsView): Remove redundant toolbar variables and add createToolbar
method.
(FRAME_NS_TITLEBAR_HEIGHT, FRAME_TOOLBAR_HEIGHT): Always calculate the
values instead of storing them in a variable.
* src/nsterm.m (x_set_offset, windowDidMove): Take parent frame
position into account when positioning frames.
(initFrameFromEmacs): Link parent frame, and take position into
account when creating new frame.
(x_set_window_size): Remove toolbar height calculation.
(x_set_parent_frame):
(x_set_undecorated): New function.
(updateFrameSize): Change NSTRACE message to reflect new reality and
no longer reset frame size.
(windowWillResize): Don’t change NS window name when the titlebar
is invisible.
(createToolbar): Move toolbar creation code into it’s own method.
(initFrameFromEmacs): Handle case where frame is created without a
titlebar and remove toolbar creation code.
(toggleFullScreen): FRAME_TOOLBAR_HEIGHT and FRAME_NS_TITLEBAR_HEIGHT
are no longer variables.
---
 src/frame.c  |   2 -
 src/frame.h  |  14 ++--
 src/nsfns.m  |  23 ++++++-
 src/nsmenu.m |   8 ---
 src/nsterm.h |  40 ++++++++++-
 src/nsterm.m | 217 +++++++++++++++++++++++++++++++++++++++++++----------------
 6 files changed, 222 insertions(+), 82 deletions(-)

diff --git a/src/frame.c b/src/frame.c
index 282b691c27..681a245ee0 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -683,7 +683,6 @@ 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;
@@ -692,7 +691,6 @@ make_frame (bool mini_p)
   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
diff --git a/src/frame.h b/src/frame.h
index 36af6e6780..4aa7c34a29 100644
--- a/src/frame.h
+++ b/src/frame.h
@@ -75,10 +75,10 @@ struct frame
      Usually it is nil.  */
   Lisp_Object title;
 
-#if defined (HAVE_WINDOW_SYSTEM) && !defined (HAVE_NS)
+#if defined (HAVE_WINDOW_SYSTEM)
   /* This frame's parent frame, if it has one.  */
   Lisp_Object parent_frame;
-#endif /* HAVE_WINDOW_SYSTEM and not HAVE_NS */
+#endif /* HAVE_WINDOW_SYSTEM */
 
   /* The frame which should receive keystrokes that occur in this
      frame, or nil if they should go to the frame itself.  This is
@@ -332,7 +332,7 @@ struct frame
   bool_bf horizontal_scroll_bars : 1;
 #endif /* HAVE_WINDOW_SYSTEM */
 
-#if defined (HAVE_WINDOW_SYSTEM) && !defined (HAVE_NS)
+#if defined (HAVE_WINDOW_SYSTEM)
   /* True if this is an undecorated frame.  */
   bool_bf undecorated : 1;
 
@@ -570,7 +570,7 @@ fset_face_alist (struct frame *f, Lisp_Object val)
 {
   f->face_alist = val;
 }
-#if defined (HAVE_WINDOW_SYSTEM) && !defined (HAVE_NS)
+#if defined (HAVE_WINDOW_SYSTEM)
 INLINE void
 fset_parent_frame (struct frame *f, Lisp_Object val)
 {
@@ -914,7 +914,7 @@ default_pixels_per_inch_y (void)
 #define FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT(f) ((void) f, 0)
 #endif /* HAVE_WINDOW_SYSTEM */
 
-#if defined (HAVE_WINDOW_SYSTEM) && !defined (HAVE_NS)
+#if defined (HAVE_WINDOW_SYSTEM)
 #define FRAME_UNDECORATED(f) ((f)->undecorated)
 #ifdef HAVE_NTGUI
 #define FRAME_OVERRIDE_REDIRECT(f) ((void) f, 0)
@@ -934,7 +934,7 @@ default_pixels_per_inch_y (void)
 #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 */
+#else /* not HAVE_WINDOW_SYSTEM */
 #define FRAME_UNDECORATED(f) ((void) f, 0)
 #define FRAME_OVERRIDE_REDIRECT(f) ((void) f, 0)
 #define FRAME_PARENT_FRAME(f) ((void) f, NULL)
@@ -945,7 +945,7 @@ default_pixels_per_inch_y (void)
 #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 */
+#endif /* HAVE_WINDOW_SYSTEM */
 
 /* Whether horizontal scroll bars are currently enabled for frame F.  */
 #if USE_HORIZONTAL_SCROLL_BARS
diff --git a/src/nsfns.m b/src/nsfns.m
index 8a923dd393..6dddc64cb4 100644
--- a/src/nsfns.m
+++ b/src/nsfns.m
@@ -972,8 +972,8 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side
   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 */
+  x_set_undecorated, /* x_set_undecorated */
+  x_set_parent_frame, /* x_set_parent_frame */
   0, /* x_set_skip_taskbar */
   0, /* x_set_no_focus_on_map */
   0, /* x_set_no_accept_focus */
@@ -1087,7 +1087,7 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side
   ptrdiff_t count = specpdl_ptr - specpdl;
   Lisp_Object display;
   struct ns_display_info *dpyinfo = NULL;
-  Lisp_Object parent;
+  Lisp_Object parent, parent_frame;
   struct kboard *kb;
   static int desc_ctr = 1;
   int x_width = 0, x_height = 0;
@@ -1265,6 +1265,23 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side
 		     FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 5, 1,
 		     Qx_create_frame_1);
 
+  tem = x_get_arg (dpyinfo, parms, Qundecorated, NULL, NULL, RES_TYPE_BOOLEAN);
+  FRAME_UNDECORATED (f) = !NILP (tem) && !EQ (tem, Qunbound);
+  store_frame_param (f, Qundecorated, FRAME_UNDECORATED (f) ? Qt : Qnil);
+
+  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)))
+    parent_frame = Qnil;
+
+  fset_parent_frame (f, parent_frame);
+  store_frame_param (f, Qparent_frame, parent_frame);
+
   /* The resources controlling the menu-bar and tool-bar are
      processed specially at startup, and reflected in the mode
      variables; ignore them here.  */
diff --git a/src/nsmenu.m b/src/nsmenu.m
index 59ea3855ed..1262c9cb4d 100644
--- a/src/nsmenu.m
+++ b/src/nsmenu.m
@@ -995,8 +995,6 @@ - (Lisp_Object)runMenuAt: (NSPoint)p forFrame: (struct frame *)f
   block_input ();
   view->wait_for_tool_bar = NO;
 
-  FRAME_TOOLBAR_HEIGHT (f) = 0;
-
   /* Note: This trigger an animation, which calls windowDidResize
      repeatedly. */
   f->output_data.ns->in_animation = 1;
@@ -1129,12 +1127,6 @@ - (Lisp_Object)runMenuAt: (NSPoint)p forFrame: (struct frame *)f
     }
 #endif
 
-  FRAME_TOOLBAR_HEIGHT (f) =
-    NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
-    - FRAME_NS_TITLEBAR_HEIGHT (f);
-  if (FRAME_TOOLBAR_HEIGHT (f) < 0) // happens if frame is fullscreen.
-    FRAME_TOOLBAR_HEIGHT (f) = 0;
-
   if (oldh != FRAME_TOOLBAR_HEIGHT (f))
     [view updateFrameSize:YES];
   if (view->wait_for_tool_bar && FRAME_TOOLBAR_HEIGHT (f) > 0)
diff --git a/src/nsterm.h b/src/nsterm.h
index 53d9344cc7..03cf399aad 100644
--- a/src/nsterm.h
+++ b/src/nsterm.h
@@ -430,7 +430,7 @@ char const * nstrace_fullscreen_type_name (int);
    NSString *workingText;
    BOOL processingCompose;
    int fs_state, fs_before_fs, next_maximized;
-   int tibar_height, tobar_height, bwidth;
+   int bwidth;
    int maximized_width, maximized_height;
    NSWindow *nonfs_window;
    BOOL fs_is_native;
@@ -454,6 +454,7 @@ char const * nstrace_fullscreen_type_name (int);
 
 /* Emacs-side interface */
 - initFrameFromEmacs: (struct frame *) f;
+- (void) createToolbar: (struct frame *)f;
 - (void) setRows: (int) r andColumns: (int) c;
 - (void) setWindowClosing: (BOOL)closing;
 - (EmacsToolbar *) toolbar;
@@ -1012,8 +1013,6 @@ struct x_output
 
 #define NS_FACE_FOREGROUND(f) ((f)->foreground)
 #define NS_FACE_BACKGROUND(f) ((f)->background)
-#define FRAME_NS_TITLEBAR_HEIGHT(f) ((f)->output_data.ns->titlebar_height)
-#define FRAME_TOOLBAR_HEIGHT(f) ((f)->output_data.ns->toolbar_height)
 
 #define FRAME_DEFAULT_FACE(f) FACE_FROM_ID_OR_NULL (f, DEFAULT_FACE_ID)
 
@@ -1029,6 +1028,25 @@ struct x_output
 #define XNS_SCROLL_BAR(vec) XSAVE_POINTER (vec, 0)
 #endif
 
+/* Compute pixel height of the frame's titlebar. */
+#define FRAME_NS_TITLEBAR_HEIGHT(f)                                     \
+  (NSHeight([FRAME_NS_VIEW (f) frame]) == 0 ?                           \
+   0                                                                    \
+   : (int)(NSHeight([FRAME_NS_VIEW (f) window].frame)                   \
+           - NSHeight([NSWindow contentRectForFrameRect:                \
+                       [[FRAME_NS_VIEW (f) window] frame]               \
+                       styleMask:[[FRAME_NS_VIEW (f) window] styleMask]])))
+
+/* Compute pixel height of the toolbar. */
+#define FRAME_TOOLBAR_HEIGHT(f)                                         \
+  (([[FRAME_NS_VIEW (f) window] toolbar] == nil                         \
+    || ! [[FRAME_NS_VIEW (f) window] toolbar].isVisible) ?                \
+   0                                                                    \
+   : (int)(NSHeight([NSWindow contentRectForFrameRect:                  \
+                     [[FRAME_NS_VIEW (f) window] frame]                 \
+                     styleMask:[[FRAME_NS_VIEW (f) window] styleMask]]) \
+           - NSHeight([[[FRAME_NS_VIEW (f) window] contentView] frame])))
+
 /* Compute pixel size for vertical scroll bars */
 #define NS_SCROLL_BAR_WIDTH(f)						\
   (FRAME_HAS_VERTICAL_SCROLL_BARS (f)					\
@@ -1066,6 +1084,18 @@ struct x_output
 #define NS_TOP_POS(f) ((f)->top_pos)
 #endif
 
+/* Calculate system coordinates of the left and top of the parent
+   window or, if there is no parent window, the screen. */
+#define NS_PARENT_WINDOW_LEFT_POS(f)                                    \
+  (FRAME_PARENT_FRAME (f) != NULL                                       \
+   ? [[FRAME_NS_VIEW (f) window] parentWindow].frame.origin.x : 0)
+#define NS_PARENT_WINDOW_TOP_POS(f)                                     \
+  (FRAME_PARENT_FRAME (f) != NULL                                       \
+   ? ([[FRAME_NS_VIEW (f) window] parentWindow].frame.origin.y          \
+      + [[FRAME_NS_VIEW (f) window] parentWindow].frame.size.height     \
+      - FRAME_NS_TITLEBAR_HEIGHT (FRAME_PARENT_FRAME (f)))              \
+   : [[[FRAME_NS_VIEW (f) window] screen] frame].size.height)
+
 #define FRAME_NS_FONT_TABLE(f) (FRAME_DISPLAY_INFO (f)->font_table)
 
 #define FRAME_FONTSET(f) ((f)->output_data.ns->fontset)
@@ -1185,6 +1215,10 @@ extern int x_display_pixel_width (struct ns_display_info *);
 /* This in nsterm.m */
 extern float ns_antialias_threshold;
 extern void x_destroy_window (struct frame *f);
+extern void x_set_undecorated (struct frame *f, Lisp_Object new_value,
+                               Lisp_Object old_value);
+extern void x_set_parent_frame (struct frame *f, Lisp_Object new_value,
+                                Lisp_Object old_value);
 extern int ns_select (int nfds, fd_set *readfds, fd_set *writefds,
 		      fd_set *exceptfds, struct timespec const *timeout,
 		      sigset_t const *sigmask);
diff --git a/src/nsterm.m b/src/nsterm.m
index 162980a651..07c48bc0e3 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -1711,8 +1711,9 @@ -(void)remove
 #endif
       /* Constrain the setFrameTopLeftPoint so we don't move behind the
          menu bar.  */
-      NSPoint pt = NSMakePoint (SCREENMAXBOUND (f->left_pos),
-                                SCREENMAXBOUND ([fscreen frame].size.height
+      NSPoint pt = NSMakePoint (SCREENMAXBOUND (f->left_pos
+                                                + NS_PARENT_WINDOW_LEFT_POS (f)),
+                                SCREENMAXBOUND (NS_PARENT_WINDOW_TOP_POS (f)
                                                 - NS_TOP_POS (f)));
       NSTRACE_POINT ("setFrameTopLeftPoint", pt);
       [[view window] setFrameTopLeftPoint: pt];
@@ -1764,25 +1765,6 @@ -(void)remove
       pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height);
     }
 
-  /* If we have a toolbar, take its height into account. */
-  if (tb && ! [view isFullscreen])
-    {
-    /* NOTE: previously this would generate wrong result if toolbar not
-             yet displayed and fixing toolbar_height=32 helped, but
-             now (200903) seems no longer needed */
-    FRAME_TOOLBAR_HEIGHT (f) =
-      NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
-        - FRAME_NS_TITLEBAR_HEIGHT (f);
-#if 0
-      /* Only breaks things here, removed by martin 2015-09-30.  */
-#ifdef NS_IMPL_GNUSTEP
-      FRAME_TOOLBAR_HEIGHT (f) -= 3;
-#endif
-#endif
-    }
-  else
-    FRAME_TOOLBAR_HEIGHT (f) = 0;
-
   wr.size.width = pixelwidth + f->border_width;
   wr.size.height = pixelheight;
   if (! [view isFullscreen])
@@ -1811,6 +1793,106 @@ -(void)remove
   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.
+ */
+void
+x_set_undecorated (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
+{
+  EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
+  NSWindow *window = [view window];
+
+  if (!EQ (new_value, old_value))
+    {
+      block_input ();
+
+      if (NILP (new_value))
+        {
+          FRAME_UNDECORATED (f) = false;
+          window.styleMask = ((window.styleMask | NSWindowStyleMaskTitled)
+                              ^ NSWindowStyleMaskBorderless);
+
+          [view createToolbar: f];
+        }
+      else
+        {
+          [window setToolbar: nil];
+          /* Do I need to release the toolbar here? */
+
+          FRAME_UNDECORATED (f) = true;
+          window.styleMask = ((window.styleMask | NSWindowStyleMaskBorderless)
+                              ^ NSWindowStyleMaskTitled);
+        }
+
+      /* At this point it seems we don't have an active NSResponder,
+         so some key presses (TAB) are swallowed by the system. */
+      [window makeFirstResponder: view];
+
+      [view updateFrameSize: NO];
+      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's `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.
+ *
+ * Whether a child frame has a tool bar may be window-system or window
+ * manager dependent.  It's advisable to disable it via the frame
+ * parameter settings.
+ *
+ * Some window managers may not honor this parameter.
+ */
+void
+x_set_parent_frame (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
+{
+  struct frame *p = NULL;
+  NSWindow *parent, *child;
+
+  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))
+    {
+      parent = [FRAME_NS_VIEW (p) window];
+      child = [FRAME_NS_VIEW (f) window];
+
+      block_input ();
+      [parent addChildWindow: child
+                     ordered: NSWindowAbove];
+      unblock_input ();
+
+      fset_parent_frame (f, new_value);
+    }
+}
 
 static void
 ns_fullscreen_hook (struct frame *f)
@@ -6399,7 +6481,8 @@ - (void) updateFrameSize: (BOOL) delay;
   newh = (int)wr.size.height - extra;
 
   NSTRACE_SIZE ("New size", NSMakeSize (neww, newh));
-  NSTRACE_MSG ("tool_bar_height: %d", emacsframe->tool_bar_height);
+  NSTRACE_MSG ("FRAME_TOOLBAR_HEIGHT: %d", FRAME_TOOLBAR_HEIGHT (emacsframe));
+  NSTRACE_MSG ("FRAME_NS_TITLEBAR_HEIGHT: %d", FRAME_NS_TITLEBAR_HEIGHT (emacsframe));
 
   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, neww);
   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, newh);
@@ -6424,9 +6507,11 @@ - (void) updateFrameSize: (BOOL) delay;
       SET_FRAME_GARBAGED (emacsframe);
       cancel_mouse_face (emacsframe);
 
-      wr = NSMakeRect (0, 0, neww, newh);
+      /* The next two lines appear to be setting the frame to the same
+         size as it already is.  Why are they there? */
+      // wr = NSMakeRect (0, 0, neww, newh);
 
-      [view setFrame: wr];
+      // [view setFrame: wr];
 
       // to do: consider using [NSNotificationCenter postNotificationName:].
       [self windowDidMove: // Update top/left.
@@ -6489,7 +6574,8 @@ - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
             old_title = 0;
           }
       }
-    else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize)
+    else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize
+             && [[self window] titleVisibility])
       {
         char *size_title;
         NSWindow *window = [self window];
@@ -6692,6 +6778,34 @@ - (BOOL)isOpaque
 }

+- (void)createToolbar: (struct frame *)f
+{
+  EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
+  NSWindow *window = [view window];
+
+  toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
+                   [NSString stringWithFormat: @"Emacs Frame %d",
+                             ns_window_num]];
+  [window setToolbar: toolbar];
+  [toolbar setVisible: NO];
+
+  /* Don't set frame garbaged until tool bar is up to date?
+     This avoids an extra clear and redraw (flicker) at frame creation.  */
+  if (FRAME_EXTERNAL_TOOL_BAR (f)) wait_for_tool_bar = YES;
+  else wait_for_tool_bar = NO;
+
+
+#ifdef NS_IMPL_COCOA
+  {
+    NSButton *toggleButton;
+    toggleButton = [window standardWindowButton: NSWindowToolbarButton];
+    [toggleButton setTarget: self];
+    [toggleButton setAction: @selector (toggleToolbar: )];
+  }
+#endif
+}
+
+
 - initFrameFromEmacs: (struct frame *)f
 {
   NSRect r, wr;
@@ -6729,11 +6843,13 @@ - (BOOL)isOpaque
   maximizing_resize = NO;
 #endif
 
-  win = [[EmacsWindow alloc]
+  win = [[EmacsFSWindow alloc]
             initWithContentRect: r
                       styleMask: (NSWindowStyleMaskResizable |
 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
-                                  NSWindowStyleMaskTitled |
+                                  (FRAME_UNDECORATED (f) ?
+                                   NSWindowStyleMaskBorderless :
+                                   NSWindowStyleMaskTitled) |
 #endif
                                   NSWindowStyleMaskMiniaturizable |
                                   NSWindowStyleMaskClosable)
@@ -6746,7 +6862,6 @@ - (BOOL)isOpaque
 
   wr = [win frame];
   bwidth = f->border_width = wr.size.width - r.size.width;
-  tibar_height = FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
 
   [win setAcceptsMouseMovedEvents: YES];
   [win setDelegate: self];
@@ -6766,42 +6881,32 @@ - (BOOL)isOpaque
   [win setTitle: name];
 
   /* toolbar support */
-  toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
-                         [NSString stringWithFormat: @"Emacs Frame %d",
-                                   ns_window_num]];
-  [win setToolbar: toolbar];
-  [toolbar setVisible: NO];
-
-  /* Don't set frame garbaged until tool bar is up to date?
-     This avoids an extra clear and redraw (flicker) at frame creation.  */
-  if (FRAME_EXTERNAL_TOOL_BAR (f)) wait_for_tool_bar = YES;
-  else wait_for_tool_bar = NO;
-
-
-#ifdef NS_IMPL_COCOA
-  {
-    NSButton *toggleButton;
-  toggleButton = [win standardWindowButton: NSWindowToolbarButton];
-  [toggleButton setTarget: self];
-  [toggleButton setAction: @selector (toggleToolbar: )];
-  }
-#endif
-  FRAME_TOOLBAR_HEIGHT (f) = 0;
+  if (! FRAME_UNDECORATED (f))
+    [self createToolbar: f];
 
   tem = f->icon_name;
   if (!NILP (tem))
     [win setMiniwindowTitle:
            [NSString stringWithUTF8String: SSDATA (tem)]];
 
+  if (FRAME_PARENT_FRAME (f) != NULL)
+    {
+      NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
+      [parent addChildWindow: win
+                     ordered: NSWindowAbove];
+    }
+
   {
     NSScreen *screen = [win screen];
 
     if (screen != 0)
       {
         NSPoint pt = NSMakePoint
-          (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
+          (IN_BOUND (-SCREENMAX, f->left_pos
+                     + NS_PARENT_WINDOW_LEFT_POS (f), SCREENMAX),
            IN_BOUND (-SCREENMAX,
-                     [screen frame].size.height - NS_TOP_POS (f), SCREENMAX));
+                     NS_PARENT_WINDOW_TOP_POS (f) - NS_TOP_POS (f),
+                     SCREENMAX));
 
         [win setFrameTopLeftPoint: pt];
 
@@ -6843,9 +6948,9 @@ - (void)windowDidMove: sender
     return;
   if (screen != nil)
     {
-      emacsframe->left_pos = r.origin.x;
+      emacsframe->left_pos = r.origin.x - NS_PARENT_WINDOW_LEFT_POS (emacsframe);
       emacsframe->top_pos =
-        [screen frame].size.height - (r.origin.y + r.size.height);
+        NS_PARENT_WINDOW_TOP_POS (emacsframe) - (r.origin.y + r.size.height);
     }
 }
 
@@ -7262,9 +7367,6 @@ - (void)toggleFullScreen: (id)sender
         [fw setOpaque: NO];
 
       f->border_width = 0;
-      FRAME_NS_TITLEBAR_HEIGHT (f) = 0;
-      tobar_height = FRAME_TOOLBAR_HEIGHT (f);
-      FRAME_TOOLBAR_HEIGHT (f) = 0;
 
       nonfs_window = w;
 
@@ -7298,9 +7400,6 @@ - (void)toggleFullScreen: (id)sender
         [w setOpaque: NO];
 
       f->border_width = bwidth;
-      FRAME_NS_TITLEBAR_HEIGHT (f) = tibar_height;
-      if (FRAME_EXTERNAL_TOOL_BAR (f))
-        FRAME_TOOLBAR_HEIGHT (f) = tobar_height;
 
       // to do: consider using [NSNotificationCenter postNotificationName:] to send notifications.
 
-- 
2.12.0