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

From: Alan Third <[email-masked]>
Date: Sun, 11 Jun 2017 17:35:44 +0100

On Sun, Jun 11, 2017 at 10:10:44AM +0200, martin rudalics wrote:
> > no-accept-focus is done, but no-focus-on-map is harder. I believe I
> > can get a new frame to not be focused on creation, but I don’t see any
> > way to prevent a minimized frame from becoming focused when
> > unminimized.
> 
> Don't worry.  Unminimizing is different from mapping.  The former works
> on already mapped frames only, the latter on invisible frames only.
> "on-map" stands for "on making the frame visible" which might happen
> some time after the frame was created.  Once visible you cannot map the
> frame until you make it invisible again.
> 
> Alt-tabbing and unminimizing OTOH work on visible frames only, you
> cannot really unminimize an invisible window (although the window
> manager might remember the requested fullscreen status somewhere and
> later, when it makes the window visible, apply that state).
> 
> ‘no-focus-on-map’ behaves well for all platforms and builds I tried so
> far.  It would be nice to have it for NS builds too.  So all that is
> afforded by ‘no-focus-on-map’ is that, whenever a frame changes from the
> invisible to the visible state, it does not get focus.

Your explanation made it much clearer what was required. I believe
I’ve got it sorted now. I’ve attached a patch.

> >> And please have a look into the Elisp manual: Maybe you find something
> >> worth mentioning (the fact that removing decorations removes the tool
> >> bar should certainly go there).
> 
> This one still stupefies me because it's a deviation from the other
> builds.  It certainly should be documented.  Did you document that a
> fullscreen NS screen doesn't have a toolbar either?

It actually does, it’s just hidden, along with the title‐bar and
menu‐bar. At least that’s how it works on macOS, I’m unsure how
GNUStep deals with full‐screen as it’s using a different mechanism, if
it handles it at all.

I’m struggling to find where this should be documented. Any ideas
which part of the manual covers full‐screen?

> BTW, I meanwhile wrote some code to resize and move undecorated frames
> with the mouse.  For this purpose I need some mouse pointers indicating
> that a frame corner (not a frame edge) can be dragged.  Under X I use
> XC_top_left_corner, XC_top_right_corner, ...  On Windows I use the
> IDC_SIZENWSE and IDC_SIZENESW arrows.  I have not found any equivalent
> for NS.  How does NS indicate that the corner of a decorated frame can
> be dragged when the mouse is over it?

macOS uses double‐headed diagonal arrows, but they’re undocumented:

    https://stackoverflow.com/questions/27242353/cocoa-predefined-resize-mouse-cursor

GNUStep doesn’t implement them and doesn’t seem to have any
equivalent.

On macOS we can actually make undecorated frames resizable quite
easily just by including the resizable style mask. GNUstep doesn’t
like that, of course.
-- 
Alan Third
>From 72ec4de5701cb3029cb3ae2c4c3262144c4eff76 Mon Sep 17 00:00:00 2001
From: Alan Third <[email-masked]>
Date: Sun, 11 Jun 2017 17:07:28 +0100
Subject: [PATCH] Add no-focus-on-map to NS build (bug#25408)

* src/nsfns.m (ns_frame_parm_handlers): Add x_set_no_focus_on_map.
(x-create-frame): Check for no-focus-on-map.
* src/nsterm.h (x_set_no_focus_on_map): New function.
* src/nsterm.m (x_set_no_focus_on_map): New function.
(ns_raise_frame): Add parameter for specifying whether to focus the
frame.
(ns_frame_raise_lower):
(x_make_frame_visible): Handle new parameter for ns_raise_frame.
---
 src/nsfns.m  |  4 +++-
 src/nsterm.h |  2 ++
 src/nsterm.m | 33 +++++++++++++++++++++++++++++----
 3 files changed, 34 insertions(+), 5 deletions(-)

diff --git a/src/nsfns.m b/src/nsfns.m
index 0c865070fb..dbce279da6 100644
--- a/src/nsfns.m
+++ b/src/nsfns.m
@@ -980,7 +980,7 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side
 #endif
   x_set_parent_frame,
   0, /* x_set_skip_taskbar */
-  0, /* x_set_no_focus_on_map */
+  x_set_no_focus_on_map,
   x_set_no_accept_focus,
   x_set_z_group, /* x_set_z_group */
   0, /* x_set_override_redirect */
@@ -1288,6 +1288,8 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side
   store_frame_param (f, Qparent_frame, parent_frame);
 
   x_default_parameter (f, parms, Qz_group, Qnil, NULL, NULL, RES_TYPE_SYMBOL);
+  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);
 
diff --git a/src/nsterm.h b/src/nsterm.h
index f75e3759e4..bed0b92c79 100644
--- a/src/nsterm.h
+++ b/src/nsterm.h
@@ -1218,6 +1218,8 @@ 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_no_focus_on_map (struct frame *f, Lisp_Object new_value,
+                                   Lisp_Object old_value);
 extern void x_set_no_accept_focus (struct frame *f, Lisp_Object new_value,
                                    Lisp_Object old_value);
 extern void x_set_z_group (struct frame *f, Lisp_Object new_value,
diff --git a/src/nsterm.m b/src/nsterm.m
index 633ca3bf76..b298e4a153 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -1463,7 +1463,7 @@ -(void)remove

 static void
-ns_raise_frame (struct frame *f)
+ns_raise_frame (struct frame *f, BOOL make_key)
 /* --------------------------------------------------------------------------
      Bring window to foreground and make it active
    -------------------------------------------------------------------------- */
@@ -1474,7 +1474,12 @@ -(void)remove
   view = FRAME_NS_VIEW (f);
   block_input ();
   if (FRAME_VISIBLE_P (f))
-    [[view window] makeKeyAndOrderFront: NSApp];
+    {
+      if (make_key)
+        [[view window] makeKeyAndOrderFront: NSApp];
+      else
+        [[view window] orderFront: NSApp];
+    }
   unblock_input ();
 }
 
@@ -1504,7 +1509,7 @@ -(void)remove
   NSTRACE ("ns_frame_raise_lower");
 
   if (raise)
-    ns_raise_frame (f);
+    ns_raise_frame (f, YES);
   else
     ns_lower_frame (f);
 }
@@ -1567,7 +1572,7 @@ -(void)remove
       EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
 
       SET_FRAME_VISIBLE (f, 1);
-      ns_raise_frame (f);
+      ns_raise_frame (f, ! FRAME_NO_FOCUS_ON_MAP (f));
 
       /* Making a new frame from a fullscreen frame will make the new frame
          fullscreen also.  So skip handleFS as this will print an error.  */
@@ -1926,6 +1931,26 @@ so some key presses (TAB) are swallowed by the system. */
     }
 }
 
+/**
+ * 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.
+ */
+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);
+    }
+}
+
 void
 x_set_no_accept_focus (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
 /*  Set frame F's `no-accept-focus' parameter which, if non-nil, hints
-- 
2.12.0