summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormarc_culler <marc.culler@gmail.com>2020-09-27 19:14:42 (GMT)
committermarc_culler <marc.culler@gmail.com>2020-09-27 19:14:42 (GMT)
commit9a2585491c7164eb5d4de469786d3c935ab3dcf0 (patch)
tree9ab8d246a62adf2f02f673fe9f2f881af1bcec02
parent09cadff7abbce69fb5d07b88b20f6461a05a0541 (diff)
downloadtk-9a2585491c7164eb5d4de469786d3c935ab3dcf0.zip
tk-9a2585491c7164eb5d4de469786d3c935ab3dcf0.tar.gz
tk-9a2585491c7164eb5d4de469786d3c935ab3dcf0.tar.bz2
Cherrypick the fixes for macOS MapNotify and UnmapNotify from mac_styles
-rw-r--r--generic/tkWindow.c6
-rw-r--r--macosx/tkMacOSXPort.h8
-rw-r--r--macosx/tkMacOSXSubwindows.c78
-rw-r--r--macosx/tkMacOSXWindowEvent.c3
-rw-r--r--macosx/tkMacOSXWm.c96
-rw-r--r--unix/tkUnixPort.h6
-rw-r--r--win/tkWinPort.h6
7 files changed, 140 insertions, 63 deletions
diff --git a/generic/tkWindow.c b/generic/tkWindow.c
index 5e5e836..92c4018 100644
--- a/generic/tkWindow.c
+++ b/generic/tkWindow.c
@@ -13,7 +13,7 @@
*/
#include "tkInt.h"
-
+#include "tkPort.h"
#ifdef _WIN32
#include "tkWinInt.h"
#elif !defined(MAC_OSX_TK)
@@ -1648,7 +1648,7 @@ Tk_MapWindow(
event.xmap.event = winPtr->window;
event.xmap.window = winPtr->window;
event.xmap.override_redirect = winPtr->atts.override_redirect;
- Tk_HandleEvent(&event);
+ TkpHandleMapOrUnmap((Tk_Window)winPtr, &event);
}
/*
@@ -1810,7 +1810,7 @@ Tk_UnmapWindow(
event.xunmap.event = winPtr->window;
event.xunmap.window = winPtr->window;
event.xunmap.from_configure = False;
- Tk_HandleEvent(&event);
+ TkpHandleMapOrUnmap((Tk_Window)winPtr, &event);
}
}
diff --git a/macosx/tkMacOSXPort.h b/macosx/tkMacOSXPort.h
index ba47566..76dd974 100644
--- a/macosx/tkMacOSXPort.h
+++ b/macosx/tkMacOSXPort.h
@@ -177,4 +177,12 @@ MODULE_SCOPE unsigned long TkMacOSXRGBPixel(unsigned long red, unsigned long gre
unsigned long blue);
#define TkpGetPixel(p) (TkMacOSXRGBPixel(p->red >> 8, p->green >> 8, p->blue >> 8))
+/*
+ * Used by tkWindow.c
+ */
+
+MODULE_SCOPE void TkMacOSXHandleMapOrUnmap(Tk_Window tkwin, XEvent *event);
+
+#define TkpHandleMapOrUnmap(tkwin, event) TkMacOSXHandleMapOrUnmap(tkwin, event)
+
#endif /* _TKMACPORT */
diff --git a/macosx/tkMacOSXSubwindows.c b/macosx/tkMacOSXSubwindows.c
index 6ac766c..e840cea 100644
--- a/macosx/tkMacOSXSubwindows.c
+++ b/macosx/tkMacOSXSubwindows.c
@@ -119,14 +119,18 @@ XDestroyWindow(
*
* XMapWindow --
*
- * Map the given X Window to the screen. See X window documentation for
- * more details.
+ * This X11 stub maps the given X11 Window but does not update any of
+ * the Tk structures describing the window. Tk applications should
+ * never call this directly, but it is called by Tk_MapWindow and
+ * Tk_WmMapWindow.
*
* Results:
- * None.
+ * Returns Success or BadWindow.
*
* Side effects:
- * The subwindow or toplevel may appear on the screen.
+ * The subwindow or toplevel may appear on the screen. VisibilityNotify
+ * events are generated.
+ *
*
*----------------------------------------------------------------------
*/
@@ -142,7 +146,6 @@ XMapWindow(
MacDrawable *macWin = (MacDrawable *)window;
TkWindow *winPtr = macWin->winPtr;
NSWindow *win = TkMacOSXGetNSWindowForDrawable(window);
- XEvent event;
static Bool initialized = NO;
/*
@@ -158,7 +161,6 @@ XMapWindow(
}
display->request++;
- winPtr->flags |= TK_MAPPED;
if (Tk_IsTopLevel(winPtr)) {
if (!Tk_IsEmbedded(winPtr)) {
TKContentView *view = [win contentView];
@@ -193,30 +195,7 @@ XMapWindow(
TkMacOSXInvalClipRgns((Tk_Window)contWinPtr);
TkMacOSXInvalidateWindow(macWin, TK_PARENT_WINDOW);
}
-
TkMacOSXInvalClipRgns((Tk_Window)winPtr);
-
- /*
- * We only need to send the MapNotify event for toplevel windows.
- */
-
- event.xany.serial = LastKnownRequestProcessed(display);
- event.xany.send_event = False;
- event.xany.display = display;
-
- event.xmap.window = window;
- event.xmap.type = MapNotify;
- event.xmap.event = window;
- event.xmap.override_redirect = winPtr->atts.override_redirect;
-
- /*
- * To update the mapped status of packed or placed subwindows
- * we handle this event immediately and then process the idle
- * events that it generates.
- */
-
- Tk_HandleEvent(&event);
- while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {}
} else {
/*
@@ -227,6 +206,11 @@ XMapWindow(
TkMacOSXInvalClipRgns((Tk_Window)winPtr->parentPtr);
}
+ /*
+ * Mark the toplevel as needing to be redrawn, unless the window is being
+ * mapped while drawing is taking place.
+ */
+
TKContentView *view = [win contentView];
if (view != [NSView focusView]) {
[view addTkDirtyRect:[view bounds]];
@@ -237,6 +221,7 @@ XMapWindow(
*/
if (initialized) {
+ XEvent event;
event.xany.send_event = False;
event.xany.display = display;
event.xvisibility.type = VisibilityNotify;
@@ -287,11 +272,13 @@ NotifyVisibility(
*
* XUnmapWindow --
*
- * Unmap the given X Window to the screen. See X window documentation for
- * more details.
+ * This X11 stub maps the given X11 Window but does not update any of
+ * The Tk structures describing the window. Tk applications should
+ * never call this directly, but it is called by Tk_UnmapWindow and
+ * Tk_WmUnmapWindow.
*
* Results:
- * None.
+ * Always returns Success or BadWindow.
*
* Side effects:
* The subwindow or toplevel may be removed from the screen.
@@ -308,8 +295,10 @@ XUnmapWindow(
TkWindow *winPtr = macWin->winPtr;
TkWindow *parentPtr = winPtr->parentPtr;
NSWindow *win = TkMacOSXGetNSWindowForDrawable(window);
- XEvent event;
+ if (!window) {
+ return BadWindow;
+ }
display->request++;
if (Tk_IsTopLevel(winPtr)) {
if (!Tk_IsEmbedded(winPtr) &&
@@ -318,28 +307,6 @@ XUnmapWindow(
[win setExcludedFromWindowsMenu:YES];
}
TkMacOSXInvalClipRgns((Tk_Window)winPtr);
-
- /*
- * We only need to send the UnmapNotify event for toplevel windows.
- */
-
- event.xany.serial = LastKnownRequestProcessed(display);
- event.xany.send_event = False;
- event.xany.display = display;
-
- event.xunmap.type = UnmapNotify;
- event.xunmap.window = window;
- event.xunmap.event = window;
- event.xunmap.from_configure = false;
-
- /*
- * To update the mapped status of packed or placed subwindows
- * we handle this event immediately and then process the idle
- * events that it generates.
- */
-
- Tk_HandleEvent(&event);
- while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {}
} else {
/*
* Rebuild the visRgn clip region for the parent so it will be allowed
@@ -355,7 +322,6 @@ XUnmapWindow(
TkMacOSXInvalClipRgns((Tk_Window)parentPtr);
TkMacOSXUpdateClipRgn(parentPtr);
}
- winPtr->flags &= ~TK_MAPPED;
TKContentView *view = [win contentView];
if (view != [NSView focusView]) {
[view addTkDirtyRect:[view bounds]];
diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c
index fcbd134..5a2809c 100644
--- a/macosx/tkMacOSXWindowEvent.c
+++ b/macosx/tkMacOSXWindowEvent.c
@@ -1086,7 +1086,7 @@ ConfigureRestrictProc(
}
/*
- * In macOS 10.14 and later his method is called when a user changes between
+ * In macOS 10.14 and later this method is called when a user changes between
* light and dark mode or changes the accent color. The implementation
* generates two virtual events. The first is either <<LightAqua>> or
* <<DarkAqua>>, depending on the view's current effective appearance. The
@@ -1134,6 +1134,7 @@ static const char *const accentNames[] = {
}
if (!defaultColor) {
defaultColor = [NSApp macOSVersion] < 110000 ? "Blue" : "Multicolor";
+ preferences = [[NSUserDefaults standardUserDefaults] retain];
/*
* AppKit calls this method when the user changes the Accent Color
diff --git a/macosx/tkMacOSXWm.c b/macosx/tkMacOSXWm.c
index 705648d..4a3f561 100644
--- a/macosx/tkMacOSXWm.c
+++ b/macosx/tkMacOSXWm.c
@@ -746,6 +746,74 @@ TkWmNewWindow(
/*
*----------------------------------------------------------------------
*
+ * TkMacOSXHandleMapOrUnmap --
+ *
+ * The mechanism used by a geometry manager to propogate the information
+ * about which of its content widgets are mapped is to call Tk_MapWindow
+ * or Tk_UnmapNotify. Those functions generate MapNotify or UnmapNotify
+ * events and then handle them immediately. Other platforms use
+ * Tk_HandleEvent to do this. But that does not work correctly on macOS
+ * due to the fact that the calls to Tk_MapNotify or Tk_UnmapNotify can
+ * occur in display procedures which are being run in the drawRect method
+ * of a TKContentView. The events will be processed after drawRect
+ * returns, but they need to be processed immediately in some cases.
+
+ * This function operates as a macOS alternative to Tk_HandleEvent, for
+ * processing MapNotify or UnmapNotify events only. It is called by
+ * Tk_MapWindow, Tk_UnmapWindow, TkWmMapWindow and TkWmUnmapWindow.
+ * Rather than using Tk_HandleEvent it installs a filter which restricts
+ * to the MapNotify or UnmapNotify events, it queues the event and then
+ * processes window events with the filter installed. This allows the
+ * event to be handled immediately even from within the drawRect method.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Handles a MapNotify or UnMapNotify event.
+ *
+ *----------------------------------------------------------------------
+ */
+static Tk_RestrictAction
+MapUnmapRestrictProc(
+ ClientData arg,
+ XEvent *eventPtr)
+{
+ return (eventPtr->type==MapNotify || eventPtr->type==UnmapNotify ?
+ TK_PROCESS_EVENT : TK_DEFER_EVENT);
+}
+
+MODULE_SCOPE
+void TkMacOSXHandleMapOrUnmap(
+ Tk_Window tkwin,
+ XEvent *event)
+{
+ ClientData oldArg;
+ Tk_RestrictProc *oldProc;
+ TkWindow *winPtr = (TkWindow *) tkwin;
+ const Tk_GeomMgr *geomMgrPtr = winPtr->geomMgrPtr;
+
+ /*
+ * Sadly, this approach does not work with the "text" geometry manager.
+ * The mysterious unexplained crash elicited by textDisp-5.2 occurs. So we
+ * have to check for the "text" manager and revert to using Tk_HandleEvent
+ * in that case. Hopefully this can be removed when the revised text
+ * widget is in place.
+ */
+
+ if (geomMgrPtr && strcmp(geomMgrPtr->name, "text") == 0) {
+ Tk_HandleEvent(event);
+ return;
+ }
+ oldProc = Tk_RestrictEvents(MapUnmapRestrictProc, NULL, &oldArg);
+ Tk_QueueWindowEvent(event, TCL_QUEUE_TAIL);
+ while (Tcl_DoOneEvent(TCL_WINDOW_EVENTS|TCL_DONT_WAIT)) {}
+ Tk_RestrictEvents(oldProc, oldArg, &oldArg);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* TkWmMapWindow --
*
* This procedure is invoked to map a top-level window. This module gets
@@ -772,6 +840,8 @@ TkWmMapWindow(
* mapped. */
{
WmInfo *wmPtr = winPtr->wmInfoPtr;
+ XEvent event;
+
if (wmPtr->flags & WM_NEVER_MAPPED) {
/*
* Create the underlying Mac window for this Tk window.
@@ -835,10 +905,19 @@ TkWmMapWindow(
wmPtr->flags &= ~WM_ABOUT_TO_MAP;
/*
- * Map the window.
+ * Map the window and process a MapNotify event for it.
*/
+ winPtr->flags |= TK_MAPPED;
XMapWindow(winPtr->display, winPtr->window);
+ event.xany.serial = LastKnownRequestProcessed(winPtr->display);
+ event.xany.send_event = False;
+ event.xany.display = winPtr->display;
+ event.xmap.window = winPtr->window;
+ event.xmap.type = MapNotify;
+ event.xmap.event = winPtr->window;
+ event.xmap.override_redirect = winPtr->atts.override_redirect;
+ TkpHandleMapOrUnmap((Tk_Window)winPtr, &event);
}
/*
@@ -863,7 +942,18 @@ TkWmUnmapWindow(
TkWindow *winPtr) /* Top-level window that's about to be
* unmapped. */
{
+ XEvent event;
+
+ event.xany.serial = LastKnownRequestProcessed(winPtr->display);
+ event.xany.send_event = False;
+ event.xany.display = winPtr->display;
+ event.xunmap.type = UnmapNotify;
+ event.xunmap.window = winPtr->window;
+ event.xunmap.event = winPtr->window;
+ event.xunmap.from_configure = false;
+ winPtr->flags &= ~TK_MAPPED;
XUnmapWindow(winPtr->display, winPtr->window);
+ TkpHandleMapOrUnmap((Tk_Window)winPtr, &event);
}
/*
@@ -6969,9 +7059,9 @@ ApplyContainerOverrideChanges(
if (parentWindow && parentWindow != containerMacWin) {
[parentWindow removeChildWindow:macWindow];
}
-
+ [macWindow orderFront:NSApp];
[containerMacWin addChildWindow:macWindow
- ordered:NSWindowAbove];
+ ordered:NSWindowAbove];
}
}
} else {
diff --git a/unix/tkUnixPort.h b/unix/tkUnixPort.h
index 09ff558..7c6177e 100644
--- a/unix/tkUnixPort.h
+++ b/unix/tkUnixPort.h
@@ -191,4 +191,10 @@
sprintf((buf), "%#08lx", (unsigned long) (w))
#endif
+/*
+ * Used by tkWindow.c
+ */
+
+#define TkpHandleMapOrUnmap(tkwin, event) Tk_HandleEvent(event)
+
#endif /* _UNIXPORT */
diff --git a/win/tkWinPort.h b/win/tkWinPort.h
index 4311b09..337a866 100644
--- a/win/tkWinPort.h
+++ b/win/tkWinPort.h
@@ -121,6 +121,12 @@
| ((p)->green & 0xff00) | (((p)->blue << 8) & 0xff0000)) | 0x20000000)
/*
+ * Used by tkWindow.c
+ */
+
+#define TkpHandleMapOrUnmap(tkwin, event) Tk_HandleEvent(event)
+
+/*
* These calls implement native bitmaps which are not currently
* supported under Windows. The macros eliminate the calls.
*/