Repository: matplotlib/matplotlib
Pull request: ENH: macosx allow figures to be opened in tabs or windows
## PR summary

Allow users to select how new figures are created when opening new windows. The default is to keep using the system preferences, but one can also select "tab" or "window" to override the default system preferences. I've called the new rcParam `figure.window_mode`, but definitely open to other suggestions. This is currently only enabled on macosx backend, but I could see it being possible on others in the future as well which is why I put it under `figure.*` and not under the more specific `macosx.*`, but I could also see how this would lead to confusion when users set this and don't get the desired result.

closes #13164

Example of the first figure opening in a new window, and the next two figures opening in a separate window with tabs.
```python
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np

x = np.linspace(0, 2, 100)

mpl.rcParams["macosx.window_mode"] = "window"
f1 = plt.figure(1)
plt.plot(x,x**2)

mpl.rcParams["macosx.window_mode"] = "tab"
f2 = plt.figure(2)
plt.plot(x,x**2)

f3 = plt.figure(3)
plt.plot(x,x**2)

plt.show()
```

## PR checklist
<!-- Please mark any checkboxes that do not apply to this PR as [N/A].-->

- [x] "closes #0000" is in the body of the PR description to [link the related issue](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue)
- [n/a] new and changed code is [tested](https://matplotlib.org/devdocs/devel/testing.html)
- [n/a] *Plotting related* features are demonstrated in an [example](https://matplotlib.org/devdocs/devel/documenting_mpl.html#writing-examples-and-tutorials)
- [x] *New Features* and *API Changes* are noted with a [directive and release note](https://matplotlib.org/devdocs/devel/coding_guide.html#new-features-and-api-changes)
- [x] Documentation complies with [general](https://matplotlib.org/devdocs/devel/documenting_mpl.html#writing-rest-pages) and [docstring](https://matplotlib.org/devdocs/devel/documenting_mpl.html#writing-docstrings) guidelines

<!--
Thank you so much for your PR!  To help us review your contribution, please
consider the following points:

- A development guide is available at https://matplotlib.org/devdocs/devel/index.html.

- Help with git and github is available at https://matplotlib.org/devdocs/devel/development_workflow.html

- Create a separate branch for your changes and open the PR from this branch. Please avoid working on `main`.

- The PR title should summarize the changes, for example "Raise ValueError on
  non-numeric input to set_xlim".  Avoid non-descriptive titles such as
  "Addresses issue #8576".

- The summary should provide at least 1-2 sentences describing the pull request
  in detail (Why is this change required?  What problem does it solve?) and
  link to any relevant issues.

- If you are contributing fixes to docstrings, please pay attention to
  https://matplotlib.org/stable/devel/documenting_mpl.html#formatting-conventions.  In particular,
  note the difference between using single backquotes, double backquotes, and
  asterisks in the markup.

We understand that PRs can sometimes be overwhelming, especially as the
reviews start coming in.  Please let us know if the reviews are unclear or
the recommended next step seems overly demanding, if you would like help in
addressing a reviewer's comments, or if you have been waiting too long to hear
back on your PR.
-->


Problem statement:
Figures in windows not tabs
I want to create multiple figure with Matplotlib in python, using the macosx backend. Currently, my code looks something like this:

```python
import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(0, 2, 100)

f1 = plt.figure(1)
plt.plot(x,x**2)

f2 = plt.figure(2)
plt.plot(x,x**2)
plt.show()
```

This creates a single window, with two tabs. One for figure 1, and one for figure 2. I suggest an option to open them in separate windows.

Note that the tabs likely come from the automatic tab-support built into the OS since macOS 10.12
**Matplotlib version**
<!--Please specify your platform and versions of the relevant libraries you are using:-->
  * Operating system: macOS 10.14.3
  * Matplotlib version: 3.0.2
  * Matplotlib backend (`print(matplotlib.get_backend())`): MacOSX
  * Python version: 3.7.1
  * Jupyter version (if applicable): -
  * Other libraries: -
  * Installed via: pip
  * Python installation via pyenv

Hints from issue discussion:
It seems this an OS "feature". Is [this](https://discussions.apple.com/thread/7852724) of any help?

Kind of. Changing that setting does help, however it affects *all* applications. I *generally* prefer things opening in new tabs, but in this case I don't. Applications can override this system-wide setting. Seems like none of the backends override it (or give the option to override it)
@hutattedonmyarm I think we are :+1:  adding that feature to atleast the OSX backend (as it is clearly mac-specific) if you are interested in implementing it.

For the other backends, it would need to be done in a way that does not affect non-OSX users.
I played with the source a bit. I managed to change the behavior, but it should be optional. I'm assuming this would be set using rcParams, or maybe as a backend function? I'm very new to using Matplotlib, so not sure what the best way is
We do have precedence for GUI specific rcparams (`osx.figure_mode` ?), I do not think we have precedence for backend specific static methods.

It may also be that this is best done as a documentation PR showing how to change the application settings.
Alright, will use rcparams then. I'll have to find how to read the params, and then update the docs

Commit message: ENH: macosx allow figures can be opened in tabs or windows

Allow users to select how new figures are created when opening
new windows. The default is to keep using the system preferences,
but one can also select "tab" or "window" to override the default
system preferences.

Patch to review:
diff --git a/doc/users/next_whats_new/macosx_windows_tabs.rst b/doc/users/next_whats_new/macosx_windows_tabs.rst
new file mode 100644
index 000000000000..85fd76b6cb6d
--- /dev/null
+++ b/doc/users/next_whats_new/macosx_windows_tabs.rst
@@ -0,0 +1,7 @@
+macosx: New figures can be opened in either windows or tabs
+-----------------------------------------------------------
+
+There is a new :rc:`macosx.window_mode`` rcParam to control how
+new figures are opened with the macosx backend. The default is
+**system** which uses the system settings, or one can specify either
+**tab** or **window** to explicitly choose the mode used to open new figures.
diff --git a/lib/matplotlib/backends/backend_macosx.py b/lib/matplotlib/backends/backend_macosx.py
index b4cfcd480250..695667dc48c3 100644
--- a/lib/matplotlib/backends/backend_macosx.py
+++ b/lib/matplotlib/backends/backend_macosx.py
@@ -145,6 +145,7 @@ def __init__(self, canvas, num):
         icon_path = str(cbook._get_data_path('images/matplotlib.pdf'))
         _macosx.FigureManager.set_icon(icon_path)
         FigureManagerBase.__init__(self, canvas, num)
+        self._set_window_mode(mpl.rcParams.get("macosx.window_mode", "system"))
         if self.toolbar is not None:
             self.toolbar.update()
         if mpl.is_interactive():
diff --git a/lib/matplotlib/mpl-data/matplotlibrc b/lib/matplotlib/mpl-data/matplotlibrc
index d951bfca3dc3..7b1ee1467a2e 100644
--- a/lib/matplotlib/mpl-data/matplotlibrc
+++ b/lib/matplotlib/mpl-data/matplotlibrc
@@ -701,6 +701,10 @@
                                 # background by default
 #savefig.orientation: portrait  # orientation of saved figure, for PostScript output only
 
+### macosx backend params
+#macosx.window_mode : system   # How to open new figures (system, tab, window)
+                               # system uses the MacOS system preferences
+
 ### tk backend params
 #tk.window_focus:   False  # Maintain shell focus for TkAgg
 
diff --git a/lib/matplotlib/rcsetup.py b/lib/matplotlib/rcsetup.py
index e628692eae8a..3a7fcbb15ab2 100644
--- a/lib/matplotlib/rcsetup.py
+++ b/lib/matplotlib/rcsetup.py
@@ -1214,6 +1214,7 @@ def _convert_validator_spec(key, conv):
     "figure.autolayout":       validate_bool,
     "figure.max_open_warning": validate_int,
     "figure.raise_window":     validate_bool,
+    "macosx.window_mode":      ["system", "tab", "window"],
 
     "figure.subplot.left":   validate_float,
     "figure.subplot.right":  validate_float,
diff --git a/src/_macosx.m b/src/_macosx.m
index 0b9dc593e614..5f8a4763322b 100755
--- a/src/_macosx.m
+++ b/src/_macosx.m
@@ -689,6 +689,25 @@ int mpl_check_modifier(
     return 0;
 }
 
+static PyObject*
+FigureManager__set_window_mode(FigureManager* self, PyObject* args)
+{
+    const char* window_mode;
+    if (!PyArg_ParseTuple(args, "s", &window_mode) || !self->window) {
+        return NULL;
+    }
+
+    NSString* window_mode_str = [NSString stringWithUTF8String: window_mode];
+    if ([window_mode_str isEqualToString: @"tab"]) {
+        [self->window setTabbingMode: NSWindowTabbingModePreferred];
+    } else if ([window_mode_str isEqualToString: @"window"]) {
+        [self->window setTabbingMode: NSWindowTabbingModeDisallowed];
+    } else { // system settings
+        [self->window setTabbingMode: NSWindowTabbingModeAutomatic];
+    }
+    Py_RETURN_NONE;
+}
+
 static PyObject*
 FigureManager_repr(FigureManager* self)
 {
@@ -832,6 +851,10 @@ int mpl_check_modifier(
         {"destroy",
          (PyCFunction)FigureManager_destroy,
          METH_NOARGS},
+        {"_set_window_mode",
+         (PyCFunction)FigureManager__set_window_mode,
+         METH_VARARGS,
+         "Set the window open mode (auto, tab, window)"},
         {"set_icon",
          (PyCFunction)FigureManager_set_icon,
          METH_STATIC | METH_VARARGS,


Code review comments:
diff_hunk: @@ -832,6 +851,10 @@ int mpl_check_modifier(
         {"destroy",
          (PyCFunction)FigureManager_destroy,
          METH_NOARGS},
+        {"_set_window_mode",
+         (PyCFunction)FigureManager__set_window_mode,
+         METH_VARARGS,
+         "Set the window open mode (auto, tab, window)"},
path: src/_macosx.m
text: @user1:
```suggestion
         "Set the window open mode (system, tab, window)"},
```

Looks like one more missed `s/auto/system/`

@author:
Oops, thanks! I just committed that via the website, so feel free to squash this down to get rid of that commit.