Skip to content

Commit 18c4a58

Browse files
committed
Further changes to message loop issues on Mac (cztomczak#442).
Minor fix to CefAppProtocol implementation, see CEF Forum topic for details. Updated Qt example so that message loop work is not called in a timer when message pump is enabled. This is not required. In wxPython apps it is still required to enable both message pump and message looper timer work.
1 parent d32f4b6 commit 18c4a58

File tree

8 files changed

+73
-38
lines changed

8 files changed

+73
-38
lines changed

api/ApplicationSettings.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,8 +201,10 @@ on these platforms. See [Issue #246](https://github.com/cztomczak/cefpython/issu
201201
for more details.
202202

203203
IMPORTANT: Currently there are issues on Mac with both message loop work
204-
and external message pump. The working solution is to call
205-
a message loop work in a timer and enable external message pump
204+
and external message pump. In Qt apps calling message loop
205+
work in a timer doesn't work anymore, you have to use external
206+
message pump. In wxPython apps it is required to call a message
207+
loop work in a timer and enable external message pump
206208
both at the same time (an incorrect approach, but it works).
207209
This is just a temporary solution and how this affects
208210
performance was not tested. See [Issue #442](../../../issues/442)

docs/Migration-guide.md

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ Table of contents:
4545
* [v66+ Threads removed: TID_DB, TID_PROCESS_LAUNCHER, TID_CACHE](#v66-threads-removed-tid_db-tid_process_launcher-tid_cache)
4646
* [v66+ cef.Request.Flags changed](#v66-cefrequestflags-changed)
4747
* [v66+ RequestHandler.GetCookieManager not getting called in some cases](#v66-requesthandlergetcookiemanager-not-getting-called-in-some-cases)
48-
* [v66+ Changes to Mac apps that integrate into existing message loops (Qt, wxPython)](#v66-changes-to-mac-apps-that-integrate-into-existing-message-loops-qt-wxpython)
48+
* [v66+ Changes to Mac apps that integrate into existing message loop (Qt, wxPython)](#v66-changes-to-mac-apps-that-integrate-into-existing-message-loop-qt-wxpython)
4949

5050

5151

@@ -386,18 +386,24 @@ callback is not getting called due to a race condition.
386386
This bug is to be fixed in Issue [#429](../../../issues/429).
387387

388388

389-
## v66+ Changes to Mac apps that integrate into existing message loops (Qt, wxPython)
389+
## v66+ Changes to Mac apps that integrate into existing message loop (Qt, wxPython)
390390

391-
The `qt.py` and `wxpython.py` examples were modified to set
391+
In Qt apps calling message loop work in a timer doesn't work anymore.
392+
You have to enable external message pump by setting
392393
ApplicationSettings.[external_message_pump](../api/ApplicationSettings.md#external_message_pump)
393-
to `True`. Due to Issue [#442](../../../issues/442) it is required
394-
to implement both approaches to integrating with existing message
395-
loops at the same time:
394+
to `True`. The `qt.py` example was updated to disable calling
395+
message loop work in a timer. External message pump
396+
is a recommended way over calling message loop work in a timer on Mac,
397+
so this should make Qt apps work smoothly.
398+
399+
In wxPython apps you have to implement both approaches for
400+
integrating with existing message loop at the same time:
396401
1. Call `cef.DoMessageLoopWork` in a 10ms timer
397402
2. Set `ApplicationSettings.external_message_pump` to True
398403

399-
This is not a correct approach and is only a temporary fix. More
400-
testing is required to check if that resolves all the issues with message
401-
loop freezing. Only basic testing was performed. It was not tested of
402-
how this change affects performance.
404+
This is not a correct approach and is only a temporary fix for wxPython
405+
apps. More testing is required to check if that resolves all the issues
406+
with message loop freezing. Only basic testing was performed. It was not
407+
tested of how this change affects performance.
403408

409+
See Issue [#442](../../../issues/442) for more details on the issues.

examples/qt.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,18 +79,19 @@ def main():
7979
settings = {}
8080
if MAC:
8181
# Issue #442 requires enabling message pump on Mac
82-
# and calling message loop work in a timer both at
83-
# the same time. This is an incorrect approach
84-
# and only a temporary solution.
82+
# in Qt example. Calling cef.DoMessageLoopWork in a timer
83+
# doesn't work anymore.
8584
settings["external_message_pump"] = True
85+
8686
cef.Initialize(settings)
8787
app = CefApplication(sys.argv)
8888
main_window = MainWindow()
8989
main_window.show()
9090
main_window.activateWindow()
9191
main_window.raise_()
9292
app.exec_()
93-
app.stopTimer()
93+
if not cef.GetAppSetting("external_message_pump"):
94+
app.stopTimer()
9495
del main_window # Just to be safe, similarly to "del app"
9596
del app # Must destroy app object before calling Shutdown
9697
cef.Shutdown()
@@ -266,7 +267,8 @@ def resizeEvent(self, event):
266267
class CefApplication(QApplication):
267268
def __init__(self, args):
268269
super(CefApplication, self).__init__(args)
269-
self.timer = self.createTimer()
270+
if not cef.GetAppSetting("external_message_pump"):
271+
self.timer = self.createTimer()
270272
self.setupIcon()
271273

272274
def createTimer(self):

examples/wxpython.py

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,17 @@
2121
LINUX = (platform.system() == "Linux")
2222
MAC = (platform.system() == "Darwin")
2323

24+
if MAC:
25+
try:
26+
# noinspection PyUnresolvedReferences
27+
from AppKit import NSApp
28+
except ImportError:
29+
print("[wxpython.py] Error: PyObjC package is missing, "
30+
"cannot fix Issue #371")
31+
print("[wxpython.py] To install PyObjC type: "
32+
"pip install -U pyobjc")
33+
sys.exit(1)
34+
2435
# Configuration
2536
WIDTH = 800
2637
HEIGHT = 600
@@ -37,7 +48,7 @@ def main():
3748
# Issue #442 requires enabling message pump on Mac
3849
# and calling message loop work in a timer both at
3950
# the same time. This is an incorrect approach
40-
# and only a temporary solution.
51+
# and only a temporary fix.
4152
settings["external_message_pump"] = True
4253
if WINDOWS:
4354
# noinspection PyUnresolvedReferences, PyArgumentList
@@ -87,20 +98,12 @@ def __init__(self):
8798
self.browser_panel.Bind(wx.EVT_SIZE, self.OnSize)
8899

89100
if MAC:
90-
try:
91-
# noinspection PyUnresolvedReferences
92-
from AppKit import NSApp
93-
# Make the content view for the window have a layer.
94-
# This will make all sub-views have layers. This is
95-
# necessary to ensure correct layer ordering of all
96-
# child views and their layers. This fixes Window
97-
# glitchiness during initial loading on Mac (Issue #371).
98-
NSApp.windows()[0].contentView().setWantsLayer_(True)
99-
except ImportError:
100-
print("[wxpython.py] Warning: PyObjC package is missing, "
101-
"cannot fix Issue #371")
102-
print("[wxpython.py] To install PyObjC type: "
103-
"pip install -U pyobjc")
101+
# Make the content view for the window have a layer.
102+
# This will make all sub-views have layers. This is
103+
# necessary to ensure correct layer ordering of all
104+
# child views and their layers. This fixes Window
105+
# glitchiness during initial loading on Mac (Issue #371).
106+
NSApp.windows()[0].contentView().setWantsLayer_(True)
104107

105108
if LINUX:
106109
# On Linux must show before embedding browser, so that handle

src/cefpython.pyx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -499,9 +499,7 @@ def Initialize(applicationSettings=None, commandLineSwitches=None, **kwargs):
499499

500500
Debug("Initialize() called")
501501

502-
# Mac initialization. Need to call NSApplication.sharedApplication()
503-
# and do NSApplication methods swizzling to implement
504-
# CrAppControlProtocol. See Issue 156.
502+
# Additional initialization on Mac, see util_mac.mm.
505503
IF UNAME_SYSNAME == "Darwin":
506504
MacInitialize()
507505

@@ -944,6 +942,10 @@ def Shutdown():
944942
with nogil:
945943
CefShutdown()
946944

945+
# Additional cleanup on Mac, see util_mac.mm.
946+
IF UNAME_SYSNAME == "Darwin":
947+
MacShutdown()
948+
947949
def SetOsModalLoop(py_bool modalLoop):
948950
cdef cpp_bool cefModalLoop = bool(modalLoop)
949951
with nogil:

src/client_handler/util_mac.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "include/cef_browser.h"
1212

1313
void MacInitialize();
14+
void MacShutdown();
1415
void MacSetWindowTitle(CefRefPtr<CefBrowser> browser, char* title);
1516

1617
#endif // CEFPYTHON_UTIL_MAC_H_

src/client_handler/util_mac.mm

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,16 @@
22
// reserved. Use of this source code is governed by a BSD-style license that
33
// can be found in the LICENSE file.
44

5+
// Copyright (c) 2015 CEF Python, see the Authors file.
6+
// All rights reserved. Licensed under BSD 3-clause license.
7+
// Project website: https://github.com/cztomczak/cefpython
8+
9+
// Some code was copied from here:
10+
// java-cef: src/master/native/util_mac.mm
11+
// upstream cef: src/tests/ceftests/run_all_unittests_mac.mm
12+
// upstream cef: src/tests/cefclient/cefclient_mac.mm
13+
// upstream cef: src/tests/cefsimple/cefsimple_mac.mm
14+
515
#import "util_mac.h"
616
#import <Cocoa/Cocoa.h>
717
#include <objc/runtime.h>
@@ -11,13 +21,14 @@
1121

1222
namespace {
1323

24+
// static NSAutoreleasePool* g_autopool = nil;
1425
BOOL g_handling_send_event = false;
1526

1627
} // namespace
1728

18-
// Add the necessary CrAppControlProtocol
19-
// functionality to NSApplication using categories and swizzling.
20-
@interface NSApplication (CEFPythonApplication)
29+
// Add the necessary CefAppProtocol functionality to NSApplication
30+
// using categories and swizzling (Issue #442, Issue #156).
31+
@interface NSApplication (CEFPythonApplication)<CefAppProtocol>
2132

2233
- (BOOL)isHandlingSendEvent;
2334
- (void)setHandlingSendEvent:(BOOL)handlingSendEvent;
@@ -63,9 +74,16 @@ - (void)_swizzled_terminate:(id)sender {
6374
@end
6475

6576
void MacInitialize() {
77+
// OFF: it's causing a crash during shutdown release
78+
// g_autopool = [[NSAutoreleasePool alloc] init];
6679
[NSApplication sharedApplication];
6780
}
6881

82+
void MacShutdown() {
83+
// OFF: it's causing a crash during shutdown release
84+
// [g_autopool release];
85+
}
86+
6987
void MacSetWindowTitle(CefRefPtr<CefBrowser> browser, char* title) {
7088
NSView* view = browser->GetHost()->GetWindowHandle();
7189
NSString* nstitle = [NSString stringWithFormat:@"%s" , title];

src/extern/mac.pxd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ from cef_browser cimport CefBrowser
77

88
cdef extern from "client_handler/util_mac.h":
99
void MacInitialize()
10+
void MacShutdown()
1011
void MacSetWindowTitle(CefRefPtr[CefBrowser] browser, char* title)

0 commit comments

Comments
 (0)