[Python-checkins] bpo-37039: Make IDLE's Zoom Height adjust to users' screens (GH-13678)

Terry Jan Reedy webhook-mailer at python.org
Mon Jun 17 15:41:22 EDT 2019


https://github.com/python/cpython/commit/5bff3c86ab77e9d831b3cd19b45654c7eef22931
commit: 5bff3c86ab77e9d831b3cd19b45654c7eef22931
branch: master
author: Tal Einat <taleinat+github at gmail.com>
committer: Terry Jan Reedy <tjreedy at udel.edu>
date: 2019-06-17T15:41:00-04:00
summary:

bpo-37039: Make IDLE's Zoom Height adjust to users' screens (GH-13678)

Measure required height by quickly maximizing once per screen.
A search for a better method failed.

files:
A Misc/NEWS.d/next/IDLE/2019-06-04-23-27-33.bpo-37039.FN_fBf.rst
M Doc/library/idle.rst
M Lib/idlelib/NEWS.txt
M Lib/idlelib/help.html
M Lib/idlelib/zoomheight.py

diff --git a/Doc/library/idle.rst b/Doc/library/idle.rst
index bd24695c7282..d494c9766eb7 100644
--- a/Doc/library/idle.rst
+++ b/Doc/library/idle.rst
@@ -289,7 +289,10 @@ Show/Hide Code Context (Editor Window only)
 Zoom/Restore Height
    Toggles the window between normal size and maximum height. The initial size
    defaults to 40 lines by 80 chars unless changed on the General tab of the
-   Configure IDLE dialog.
+   Configure IDLE dialog.  The maximum height for a screen is determined by
+   momentarily maximizing a window the first time one is zoomed on the screen.
+   Changing screen settings may invalidate the saved height.  This toogle has
+   no effect when a window is maximized.
 
 Window menu (Shell and Editor)
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt
index 982af7767251..7646aed59364 100644
--- a/Lib/idlelib/NEWS.txt
+++ b/Lib/idlelib/NEWS.txt
@@ -3,6 +3,14 @@ Released on 2019-10-20?
 ======================================
 
 
+bpo-37039: Adjust "Zoom Height" to individual screens by momemtarily
+maximizing the window on first use with a particular screen.  Changing
+screen settings may invalidate the saved height.  While a window is
+maximized, "Zoom Height" has no effect.
+
+bpo-35763: Make calltip reminder about '/' meaning positional-only less
+obtrusive by only adding it when there is room on the first line.
+
 bpo-35610: Replace now redundant editor.context_use_ps1 with
 .prompt_last_line.  This finishes change started in bpo-31858.
 
diff --git a/Lib/idlelib/help.html b/Lib/idlelib/help.html
index 228b3195cf92..e27ec8d6e173 100644
--- a/Lib/idlelib/help.html
+++ b/Lib/idlelib/help.html
@@ -6,7 +6,7 @@
   <head>
     <meta http-equiv="X-UA-Compatible" content="IE=Edge" />
     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-    <title>IDLE — Python 3.8.0a4 documentation</title>
+    <title>IDLE — Python 3.9.0a0 documentation</title>
     <link rel="stylesheet" href="../_static/pydoctheme.css" type="text/css" />
     <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 
@@ -19,7 +19,7 @@
     <script type="text/javascript" src="../_static/sidebar.js"></script>
 
     <link rel="search" type="application/opensearchdescription+xml"
-          title="Search within Python 3.8.0a4 documentation"
+          title="Search within Python 3.9.0a0 documentation"
           href="../_static/opensearch.xml"/>
     <link rel="author" title="About these documents" href="../about.html" />
     <link rel="index" title="Index" href="../genindex.html" />
@@ -50,6 +50,7 @@
 
 
   </head><body>
+
     <div class="related" role="navigation" aria-label="related navigation">
       <h3>Navigation</h3>
       <ul>
@@ -72,7 +73,7 @@ <h3>Navigation</h3>
 
 
     <li>
-      <a href="../index.html">3.8.0a4 Documentation</a> »
+      <a href="../index.html">3.9.0a0 Documentation</a> »
     </li>
 
           <li class="nav-item nav-item-1"><a href="index.html" >The Python Standard Library</a> »</li>
@@ -320,7 +321,10 @@ <h3>Options menu (Shell and Editor)<a class="headerlink" href="#options-menu-she
 <dt>Zoom/Restore Height</dt>
 <dd>Toggles the window between normal size and maximum height. The initial size
 defaults to 40 lines by 80 chars unless changed on the General tab of the
-Configure IDLE dialog.</dd>
+Configure IDLE dialog.  The maximum height for a screen is determined by
+momentarily maximizing a window the first time one is zoomed on the screen.
+Changing screen settings may invalidate the saved height.  This toogle has
+no effect when a window is maximized.</dd>
 </dl>
 </div>
 <div class="section" id="window-menu-shell-and-editor">
@@ -912,7 +916,7 @@ <h3>Navigation</h3>
 
 
     <li>
-      <a href="../index.html">3.8.0a4 Documentation</a> »
+      <a href="../index.html">3.9.0a0 Documentation</a> »
     </li>
 
           <li class="nav-item nav-item-1"><a href="index.html" >The Python Standard Library</a> »</li>
@@ -943,7 +947,7 @@ <h3>Navigation</h3>
 <br />
     <br />
 
-    Last updated on May 25, 2019.
+    Last updated on Jun 17, 2019.
     <a href="https://docs.python.org/3/bugs.html">Found a bug</a>?
     <br />
 
diff --git a/Lib/idlelib/zoomheight.py b/Lib/idlelib/zoomheight.py
index 523f5d51e02f..cd50c91c183e 100644
--- a/Lib/idlelib/zoomheight.py
+++ b/Lib/idlelib/zoomheight.py
@@ -2,42 +2,119 @@
 
 import re
 import sys
+import tkinter
 
-from idlelib import macosx
+
+class WmInfoGatheringError(Exception):
+    pass
 
 
 class ZoomHeight:
+    # Cached values for maximized window dimensions, one for each set
+    # of screen dimensions.
+    _max_height_and_y_coords = {}
 
     def __init__(self, editwin):
         self.editwin = editwin
+        self.top = self.editwin.top
 
     def zoom_height_event(self, event=None):
-        top = self.editwin.top
-        zoomed = zoom_height(top)
-        menu_status = 'Restore' if zoomed else 'Zoom'
-        self.editwin.update_menu_label(menu='options', index='* Height',
-                                       label=f'{menu_status} Height')
+        zoomed = self.zoom_height()
+
+        if zoomed is None:
+            self.top.bell()
+        else:
+            menu_status = 'Restore' if zoomed else 'Zoom'
+            self.editwin.update_menu_label(menu='options', index='* Height',
+                                           label=f'{menu_status} Height')
+
         return "break"
 
+    def zoom_height(self):
+        top = self.top
+
+        width, height, x, y = get_window_geometry(top)
+
+        if top.wm_state() != 'normal':
+            # Can't zoom/restore window height for windows not in the 'normal'
+            # state, e.g. maximized and full-screen windows.
+            return None
+
+        try:
+            maxheight, maxy = self.get_max_height_and_y_coord()
+        except WmInfoGatheringError:
+            return None
+
+        if height != maxheight:
+            # Maximize the window's height.
+            set_window_geometry(top, (width, maxheight, x, maxy))
+            return True
+        else:
+            # Restore the window's height.
+            #
+            # .wm_geometry('') makes the window revert to the size requested
+            # by the widgets it contains.
+            top.wm_geometry('')
+            return False
+
+    def get_max_height_and_y_coord(self):
+        top = self.top
+
+        screen_dimensions = (top.winfo_screenwidth(),
+                             top.winfo_screenheight())
+        if screen_dimensions not in self._max_height_and_y_coords:
+            orig_state = top.wm_state()
 
-def zoom_height(top):
+            # Get window geometry info for maximized windows.
+            try:
+                top.wm_state('zoomed')
+            except tkinter.TclError:
+                # The 'zoomed' state is not supported by some esoteric WMs,
+                # such as Xvfb.
+                raise WmInfoGatheringError(
+                    'Failed getting geometry of maximized windows, because ' +
+                    'the "zoomed" window state is unavailable.')
+            top.update()
+            maxwidth, maxheight, maxx, maxy = get_window_geometry(top)
+            if sys.platform == 'win32':
+                # On Windows, the returned Y coordinate is the one before
+                # maximizing, so we use 0 which is correct unless a user puts
+                # their dock on the top of the screen (very rare).
+                maxy = 0
+            maxrooty = top.winfo_rooty()
+
+            # Get the "root y" coordinate for non-maximized windows with their
+            # y coordinate set to that of maximized windows.  This is needed
+            # to properly handle different title bar heights for non-maximized
+            # vs. maximized windows, as seen e.g. in Windows 10.
+            top.wm_state('normal')
+            top.update()
+            orig_geom = get_window_geometry(top)
+            max_y_geom = orig_geom[:3] + (maxy,)
+            set_window_geometry(top, max_y_geom)
+            top.update()
+            max_y_geom_rooty = top.winfo_rooty()
+
+            # Adjust the maximum window height to account for the different
+            # title bar heights of non-maximized vs. maximized windows.
+            maxheight += maxrooty - max_y_geom_rooty
+
+            self._max_height_and_y_coords[screen_dimensions] = maxheight, maxy
+
+            set_window_geometry(top, orig_geom)
+            top.wm_state(orig_state)
+
+        return self._max_height_and_y_coords[screen_dimensions]
+
+
+def get_window_geometry(top):
     geom = top.wm_geometry()
     m = re.match(r"(\d+)x(\d+)\+(-?\d+)\+(-?\d+)", geom)
-    if not m:
-        top.bell()
-        return
-    width, height, x, y = map(int, m.groups())
-    newheight = top.winfo_screenheight()
-
-    # The constants below for Windows and Mac Aqua are visually determined
-    # to avoid taskbar or menubar and app icons.
-    newy, bot_y = ((0, 72) if sys.platform == 'win32' else
-                   (22, 88) if macosx.isAquaTk() else
-                   (0, 88) ) # Guess for anything else.
-    newheight = newheight - newy - bot_y
-    newgeom = '' if height >= newheight else f"{width}x{newheight}+{x}+{newy}"
-    top.wm_geometry(newgeom)
-    return newgeom != ""
+    return tuple(map(int, m.groups()))
+
+
+def set_window_geometry(top, geometry):
+    top.wm_geometry("{:d}x{:d}+{:d}+{:d}".format(*geometry))
 
 
 if __name__ == "__main__":
diff --git a/Misc/NEWS.d/next/IDLE/2019-06-04-23-27-33.bpo-37039.FN_fBf.rst b/Misc/NEWS.d/next/IDLE/2019-06-04-23-27-33.bpo-37039.FN_fBf.rst
new file mode 100644
index 000000000000..71c8c892ba6a
--- /dev/null
+++ b/Misc/NEWS.d/next/IDLE/2019-06-04-23-27-33.bpo-37039.FN_fBf.rst
@@ -0,0 +1,4 @@
+Adjust "Zoom Height" to individual screens by momemtarily maximizing the
+window on first use with a particular screen.  Changing screen settings
+may invalidate the saved height.  While a window is maximized,
+"Zoom Height" has no effect.



More information about the Python-checkins mailing list