]> git.eshelyaron.com Git - emacs.git/commitdiff
Add new frame functionality to NS port
authorAlan Third <alan@idiocy.org>
Fri, 14 Apr 2017 09:02:38 +0000 (10:02 +0100)
committerAlan Third <alan@idiocy.org>
Wed, 19 Apr 2017 16:17:35 +0000 (17:17 +0100)
* lisp/frame.el (frame-restack): Call ns-frame-restack.
* src/keyboard.c (kbd_buffer_get_event) [HAVE_NS]: Enable
MOVE_FRAME_EVENT handling.
* src/frame.h:
* src/frame.c: Enable 'z-group', 'undecorated' and 'parent' frame
definitions.
* src/nsfns.m: Add x_set_z_group, x_set_parent_frame and
x_set_undecorated (Cocoa only) to handler struct.
(Fx_create_frame): Handle 'z-group', 'parent-frame' and 'undecorated'
frame parameter.
(Fns_frame_restack): New function.
* 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.
(NS_TOP_POS): Remove defun.
(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): Remove toolbar creation code and handle new
frame parameters.
(x_set_window_size): Remove toolbar height calculation.
(x_set_z_group):
(x_set_parent_frame):
(x_set_undecorated) [NS_IMPL_COCOA]: New function.
(x_destroy_window): Detach parent if child closes.
(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.
(toggleFullScreen): FRAME_TOOLBAR_HEIGHT and FRAME_NS_TITLEBAR_HEIGHT
are no longer variables.
(windowDidMove): Fire MOVE_FRAME_EVENT Emacs event.

lisp/frame.el
src/frame.c
src/frame.h
src/keyboard.c
src/nsfns.m
src/nsmenu.m
src/nsterm.h
src/nsterm.m

index 86a0e26e393c367d29dedc5a748f830d4ba788e1..e632b5943fc945d8bee8e7a47df6f3845a5c048c 100644 (file)
@@ -1548,7 +1548,9 @@ Some window managers may refuse to restack windows. "
          ((eq frame-type 'x)
           (x-frame-restack frame1 frame2 above))
          ((eq frame-type 'w32)
-          (w32-frame-restack frame1 frame2 above))))
+          (w32-frame-restack frame1 frame2 above))
+         ((eq frame-type 'ns)
+          (ns-frame-restack frame1 frame2 above))))
     (error "Cannot restack frames")))
 
 (defun frame-size-changed-p (&optional frame)
index 282b691c277ec3deda24599ecc0a860f9facaaba..681a245ee052363d0c8917e9d681b514a407fc97 100644 (file)
@@ -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
index 36af6e6780413fed2f612244a98560ccd69c99de..4aa7c34a29a636a1f2caf6fd1959456002533083 100644 (file)
@@ -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
index 3e50142f7c198870fd98597ceaa7eb5f40a46601..c9fa2a9f5e1bd579cb8ffa1216be812d303babcb 100644 (file)
@@ -4056,7 +4056,7 @@ kbd_buffer_get_event (KBOARD **kbp,
          kbd_fetch_ptr = event + 1;
        }
 #endif
-#if defined (HAVE_X11) || defined (HAVE_NTGUI)
+#if defined (HAVE_X11) || defined (HAVE_NTGUI) || defined (HAVE_NS)
       else if (event->kind == MOVE_FRAME_EVENT)
        {
          /* Make an event (move-frame (FRAME)).  */
index 8a923dd39333d33d10c5f1a613f8b72de6791f0b..f1a5df8f27e37a6db1484024f1cb30934ce7b212 100644 (file)
@@ -972,12 +972,16 @@ 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 */
+#ifdef NS_IMPL_COCOA
+  x_set_undecorated, /* x_set_undecorated */
+#else
+  0, /*x_set_undecorated */
+#endif
+  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 */
-  0, /* x_set_z_group */
+  x_set_z_group, /* x_set_z_group */
   0, /* x_set_override_redirect */
 };
 
@@ -1087,7 +1091,7 @@ This function is an internal primitive--use `make-frame' instead.  */)
   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 +1269,25 @@ This function is an internal primitive--use `make-frame' instead.  */)
                     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);
+
+  x_default_parameter (f, parms, Qz_group, Qnil, NULL, NULL, RES_TYPE_SYMBOL);
+
   /* The resources controlling the menu-bar and tool-bar are
      processed specially at startup, and reflected in the mode
      variables; ignore them here.  */
@@ -1405,6 +1428,37 @@ x_focus_frame (struct frame *f, bool noactivate)
     }
 }
 
+DEFUN ("ns-frame-restack", Fns_frame_restack, Sns_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.
+
+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_NS_VIEW (f1) && FRAME_NS_VIEW (f2))
+    {
+      NSWindow *window = [FRAME_NS_VIEW (f1) window];
+      NSInteger window2 = [[FRAME_NS_VIEW (f2) window] windowNumber];
+      NSWindowOrderingMode flag = NILP (above) ? NSWindowBelow : NSWindowAbove;
+
+      [window orderWindow: flag
+               relativeTo: window2];
+
+      return Qt;
+    }
+  else
+    {
+      error ("Cannot restack frames");
+      return Qnil;
+    }
+}
 
 DEFUN ("ns-popup-font-panel", Fns_popup_font_panel, Sns_popup_font_panel,
        0, 1, "",
@@ -3134,6 +3188,7 @@ be used as the image of the icon representing the frame.  */);
   defsubr (&Sns_display_monitor_attributes_list);
   defsubr (&Sns_frame_geometry);
   defsubr (&Sns_frame_edges);
+  defsubr (&Sns_frame_restack);
   defsubr (&Sx_display_mm_width);
   defsubr (&Sx_display_mm_height);
   defsubr (&Sx_display_screens);
index 59ea3855ed116bd88cce61ae2efc96b7319adc3b..1262c9cb4d6315cebef37b84134f0aec2bfb7af6 100644 (file)
@@ -995,8 +995,6 @@ free_frame_tool_bar (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 @@ update_frame_tool_bar (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)
index 53d9344cc78ccb51ff189f2fd8cc613e5fb38d39..2f8c4269b0bd8dd5272b1550977df2857cdc2918 100644 (file)
@@ -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)                                  \
@@ -1059,12 +1077,17 @@ struct x_output
    (FRAME_SCROLL_BAR_LINES (f) * FRAME_LINE_HEIGHT (f) \
     - NS_SCROLL_BAR_HEIGHT (f)) : 0)
 
-/* XXX: fix for GNUstep inconsistent accounting for titlebar */
-#ifdef NS_IMPL_GNUSTEP
-#define NS_TOP_POS(f) ((f)->top_pos + 18)
-#else
-#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)
 
@@ -1185,6 +1208,12 @@ 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 void x_set_z_group (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);
index 4725991aff443531d3a5f2ff2af32d262f5e1a42..fbbcdbe4bc2b8b05b79d9b2c413f40597ad84d9a 100644 (file)
@@ -1668,6 +1668,17 @@ x_destroy_window (struct frame *f)
    -------------------------------------------------------------------------- */
 {
   NSTRACE ("x_destroy_window");
+
+  /* If this frame has a parent window, detach it as not doing so can
+     cause a crash in GNUStep. */
+  if (FRAME_PARENT_FRAME (f) != NULL)
+    {
+      NSWindow *child = [FRAME_NS_VIEW (f) window];
+      NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
+
+      [parent removeChildWindow: child];
+    }
+
   check_window_system (f);
   x_free_frame_resources (f);
   ns_window_num--;
@@ -1706,14 +1717,18 @@ x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
            - FRAME_TOOLBAR_HEIGHT (f))
         : f->top_pos;
 #ifdef NS_IMPL_GNUSTEP
-      if (f->left_pos < 100)
-        f->left_pos = 100;  /* don't overlap menu */
+      if (FRAME_PARENT_FRAME (f) == NULL)
+       {
+         if (f->left_pos < 100)
+           f->left_pos = 100;  /* don't overlap menu */
+       }
 #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
-                                                - NS_TOP_POS (f)));
+      NSPoint pt = NSMakePoint (SCREENMAXBOUND (f->left_pos
+                                                + NS_PARENT_WINDOW_LEFT_POS (f)),
+                                SCREENMAXBOUND (NS_PARENT_WINDOW_TOP_POS (f)
+                                                - f->top_pos));
       NSTRACE_POINT ("setFrameTopLeftPoint", pt);
       [[view window] setFrameTopLeftPoint: pt];
       f->size_hint_flags &= ~(XNegative|YNegative);
@@ -1738,7 +1753,6 @@ x_set_window_size (struct frame *f,
   EmacsView *view = FRAME_NS_VIEW (f);
   NSWindow *window = [view window];
   NSRect wr = [window frame];
-  int tb = FRAME_EXTERNAL_TOOL_BAR (f);
   int pixelwidth, pixelheight;
   int orig_height = wr.size.height;
 
@@ -1764,25 +1778,6 @@ x_set_window_size (struct frame *f,
       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 +1806,150 @@ x_set_window_size (struct frame *f,
   unblock_input ();
 }
 
+#ifdef NS_IMPL_COCOA
+void
+x_set_undecorated (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
+/* --------------------------------------------------------------------------
+     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.
+
+     GNUStep cannot change an existing window's style.
+   -------------------------------------------------------------------------- */
+{
+  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 setStyleMask: ((window.styleMask
+                                  | NSWindowStyleMaskTitled
+                                  | NSWindowStyleMaskResizable
+                                  | NSWindowStyleMaskMiniaturizable
+                                  | NSWindowStyleMaskClosable)
+                                 ^ NSWindowStyleMaskBorderless)];
+
+          [view createToolbar: f];
+        }
+      else
+        {
+          [window setToolbar: nil];
+          /* Do I need to release the toolbar here? */
+
+          FRAME_UNDECORATED (f) = true;
+          [window setStyleMask: ((window.styleMask | NSWindowStyleMaskBorderless)
+                                 ^ (NSWindowStyleMaskTitled
+                                    | NSWindowStyleMaskResizable
+                                    | NSWindowStyleMaskMiniaturizable
+                                    | NSWindowStyleMaskClosable))];
+        }
+
+      /* 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 ();
+    }
+}
+#endif /* NS_IMPL_COCOA */
+
+void
+x_set_parent_frame (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
+/* --------------------------------------------------------------------------
+     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.  On macOS 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.
+   -------------------------------------------------------------------------- */
+{
+  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);
+    }
+}
+
+void
+x_set_z_group (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
+/* 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.
+
+   Some window managers may not honor this parameter. */
+{
+  EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
+  NSWindow *window = [view window];
+
+  if (NILP (new_value))
+    {
+      window.level = NSNormalWindowLevel;
+      FRAME_Z_GROUP (f) = z_group_none;
+    }
+  else if (EQ (new_value, Qabove))
+    {
+      window.level = NSNormalWindowLevel + 1;
+      FRAME_Z_GROUP (f) = z_group_above;
+    }
+  else if (EQ (new_value, Qabove_suspended))
+    {
+      /* Not sure what level this should be. */
+      window.level = NSNormalWindowLevel + 1;
+      FRAME_Z_GROUP (f) = z_group_above_suspended;
+    }
+  else if (EQ (new_value, Qbelow))
+    {
+      window.level = NSNormalWindowLevel - 1;
+      FRAME_Z_GROUP (f) = z_group_below;
+    }
+  else
+    error ("Invalid z-group specification");
+}
 
 static void
 ns_fullscreen_hook (struct frame *f)
@@ -2683,7 +2822,7 @@ ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
 
           for (i = 0; i < full_height; i++)
             cbits[i] = bits[i];
-          img = [[EmacsImage alloc] initFromXBM: cbits width: 8
+          img = [[EmacsImage alloc] XBM: cbits width: 8
                                          height: full_height
                                              fg: 0 bg: 0];
           bimgs[p->which - 1] = img;
@@ -6399,7 +6538,8 @@ not_in_argv (NSString *arg)
   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 +6564,11 @@ not_in_argv (NSString *arg)
       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 +6631,8 @@ not_in_argv (NSString *arg)
             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 +6835,34 @@ not_in_argv (NSString *arg)
 }
 
 
+- (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]];
+  [toolbar setVisible: NO];
+  [window setToolbar: toolbar];
+
+  /* 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,14 +6900,14 @@ not_in_argv (NSString *arg)
   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 |
-#endif
-                                  NSWindowStyleMaskMiniaturizable |
-                                  NSWindowStyleMaskClosable)
+                      styleMask: (FRAME_UNDECORATED (f)
+                                  ? NSWindowStyleMaskBorderless
+                                  : NSWindowStyleMaskTitled
+                                  | NSWindowStyleMaskResizable
+                                  | NSWindowStyleMaskMiniaturizable
+                                  NSWindowStyleMaskClosable)
                         backing: NSBackingStoreBuffered
                           defer: YES];
 
@@ -6746,7 +6917,6 @@ not_in_argv (NSString *arg)
 
   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 +6936,36 @@ not_in_argv (NSString *arg)
   [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];
+    }
+
+  if (!NILP (FRAME_Z_GROUP (f)))
+      win.level = NSNormalWindowLevel
+        + (FRAME_Z_GROUP_BELOW (f) ? -1 : 1);
+
   {
     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) - f->top_pos,
+                     SCREENMAX));
 
         [win setFrameTopLeftPoint: pt];
 
@@ -6843,9 +7007,15 @@ not_in_argv (NSString *arg)
     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);
+
+      if (emacs_event)
+        {
+          emacs_event->kind = MOVE_FRAME_EVENT;
+          EV_TRAILER ((id)nil);
+        }
     }
 }
 
@@ -7262,9 +7432,6 @@ not_in_argv (NSString *arg)
         [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 +7465,6 @@ not_in_argv (NSString *arg)
         [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.