X Tutup
Skip to content

Commit 55ce020

Browse files
CzarekCzarek
authored andcommitted
Implemented javascript callbacks in CEF Python 3.
1 parent 048a47f commit 55ce020

24 files changed

+414
-86
lines changed

cefpython/cef3/DebugLog.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright (c) 2012-2013 The CEF Python authors. All rights reserved.
2+
// License: New BSD License.
3+
// Website: http://code.google.com/p/cefpython/
4+
5+
#pragma once
6+
#include <stdio.h>
7+
8+
// Defined as "inline" to get rid of the "already defined" errors
9+
// when linking.
10+
inline void DebugLog(const char* szString)
11+
{
12+
// TODO: get the log_file option from CefSettings.
13+
printf("cefpython: %s\n", szString);
14+
FILE* pFile = fopen("debug.log", "a");
15+
fprintf(pFile, "cefpython_app: %s\n", szString);
16+
fclose(pFile);
17+
}

cefpython/cef3/client_handler/client_handler.cpp

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,14 @@
44

55
#include "client_handler.h"
66
#include "cefpython_public_api.h"
7-
#include <stdio.h>
8-
9-
// Defined as "inline" to get rid of the "already defined" errors
10-
// when linking.
11-
inline void DebugLog(const char* szString)
12-
{
13-
// TODO: get the log_file option from CefSettings.
14-
printf("cefpython: %s\n", szString);
15-
FILE* pFile = fopen("debug.log", "a");
16-
fprintf(pFile, "cefpython_app: %s\n", szString);
17-
fclose(pFile);
18-
}
7+
#include "DebugLog.h"
198

209
bool ClientHandler::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
2110
CefProcessId source_process,
2211
CefRefPtr<CefProcessMessage> message) {
12+
if (source_process != PID_RENDERER) {
13+
return false;
14+
}
2315
std::string messageName = message->GetName().ToString();
2416
std::string logMessage = "Browser: OnProcessMessageReceived(): ";
2517
logMessage.append(messageName.c_str());

cefpython/cef3/linux/binaries_64bit/wxpython.html

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,5 +73,52 @@ <h3>Javascript bindings</h3>
7373
'python called from js and then js called from python')</a>
7474

7575

76+
77+
<h3>Javascript callbacks</h3>
78+
<script>
79+
function JSCallback(arg1) {
80+
window.alert(arg1)
81+
}
82+
</script>
83+
<pre>
84+
&lt;script&gt;
85+
function JSCallback(arg1) {
86+
window.alert(arg1)
87+
}
88+
&lt;/script&gt;
89+
</pre>
90+
<pre>
91+
def TestJSCallback(self, jsCallback):
92+
print("jsCallback.GetFunctionName() = %s" % jsCallback.GetFunctionName())
93+
print("jsCallback.GetFrame().GetIdentifier() = %s" % \
94+
jsCallback.GetFrame().GetIdentifier())
95+
jsCallback.Call("This message was sent from python using js callback")
96+
</pre>
97+
<a href="javascript:external.TestJSCallback(JSCallback)">
98+
external.TestJSCallback(JSCallback)</a>
99+
<script>
100+
function JSCallback2() {
101+
window.alert(JSON.stringify(arguments))
102+
}
103+
</script>
104+
<pre>
105+
&lt;script&gt;
106+
function JSCallback2() {
107+
window.alert(JSON.stringify(arguments))
108+
}
109+
&lt;/script&gt;
110+
</pre>
111+
<pre>
112+
def TestJSCallbackComplexArguments(self, jsObject):
113+
jsCallback = jsObject["myCallback"];
114+
jsCallback.Call(1, None, 2.14, "string", ["list", ["nested list", \
115+
{"nested object":None}]], \
116+
{"nested list next":[{"deeply nested object":1}]})
117+
</pre>
118+
<a href="javascript:external.TestJSCallbackComplexArguments(
119+
{'myCallback':JSCallback2})">
120+
external.TestJSCallbackComplexArguments({"myCallback": JSCallback2})
121+
</a>
122+
76123
</body>
77124
</html>

cefpython/cef3/linux/binaries_64bit/wxpython.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,18 @@ def TestAllTypes(self, *args):
156156
def ExecuteFunction(self, *args):
157157
self.mainBrowser.GetMainFrame().ExecuteFunction(*args)
158158

159+
def TestJSCallback(self, jsCallback):
160+
print("jsCallback.GetFunctionName() = %s" % jsCallback.GetFunctionName())
161+
print("jsCallback.GetFrame().GetIdentifier() = %s" % \
162+
jsCallback.GetFrame().GetIdentifier())
163+
jsCallback.Call("This message was sent from python using js callback")
164+
165+
def TestJSCallbackComplexArguments(self, jsObject):
166+
jsCallback = jsObject["myCallback"];
167+
jsCallback.Call(1, None, 2.14, "string", ["list", ["nested list", \
168+
{"nested object":None}]], \
169+
{"nested list next":[{"deeply nested object":1}]})
170+
159171
class MyApp(wx.App):
160172
timer = None
161173
timerID = 1

cefpython/cef3/subprocess/Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,5 @@ LIB = -L./../linux/setup/lib_64bit -L./../linux/setup/lib_32bit \
1717
subprocess:
1818
# -fPIC is required only for libraries included by Cython.
1919
g++ -Wall -Werror $(INC) $(LIB) main.cpp cefpython_app.cpp \
20-
v8function_handler.cpp v8utils.cpp -lcef_dll_wrapper -lcef \
21-
-o subprocess -Wl,-rpath,.
20+
v8function_handler.cpp v8utils.cpp javascript_callback.cpp \
21+
python_callback.cpp -lcef_dll_wrapper -lcef -o subprocess -Wl,-rpath,.

cefpython/cef3/subprocess/Makefile-libcefpythonapp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
CC = g++
1212
CCFLAGS = -g -fPIC -Wall -Werror
1313

14-
SRC = cefpython_app.cpp v8function_handler.cpp v8utils.cpp
14+
SRC = cefpython_app.cpp v8function_handler.cpp v8utils.cpp \
15+
javascript_callback.cpp python_callback.cpp
1516
OBJ = $(SRC:.cpp=.o)
1617
OUT = libcefpythonapp.a
1718

cefpython/cef3/subprocess/cefpython_app.cpp

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,11 @@
55
#include "cefpython_app.h"
66
#include "util.h"
77
#include "include/cef_runnable.h"
8-
#include <stdio.h>
8+
#include "DebugLog.h"
99
#include <vector>
1010
#include "v8utils.h"
11-
12-
// Defined as "inline" to get rid of the "already defined" errors
13-
// when linking.
14-
inline void DebugLog(const char* szString)
15-
{
16-
// TODO: get the log_file option from CefSettings.
17-
printf("cefpython: %s\n", szString);
18-
FILE* pFile = fopen("debug.log", "a");
19-
fprintf(pFile, "cefpython_app: %s\n", szString);
20-
fclose(pFile);
21-
}
11+
#include "javascript_callback.h"
12+
#include "python_callback.h"
2213

2314
// -----------------------------------------------------------------------------
2415
// CefApp
@@ -168,6 +159,9 @@ void CefPythonApp::OnContextReleased(CefRefPtr<CefBrowser> browser,
168159
// casting it to int for now.
169160
args->SetInt(0, (int)(frame->GetIdentifier()));
170161
browser->SendProcessMessage(PID_BROWSER, message);
162+
// Clear javascript callbacks.
163+
RemoveJavascriptCallbacksForFrame(frame);
164+
RemovePythonCallbacksForFrame(frame);
171165
}
172166

173167
void CefPythonApp::OnUncaughtException(CefRefPtr<CefBrowser> browser,
@@ -194,8 +188,8 @@ bool CefPythonApp::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
194188
std::string logMessage = "Renderer: OnProcessMessageReceived(): ";
195189
logMessage.append(messageName.c_str());
196190
DebugLog(logMessage.c_str());
191+
CefRefPtr<CefListValue> args = message->GetArgumentList();
197192
if (messageName == "DoJavascriptBindings") {
198-
CefRefPtr<CefListValue> args = message->GetArgumentList();
199193
if (args->GetSize() == 1
200194
&& args->GetType(0) == VTYPE_DICTIONARY
201195
&& args->GetDictionary(0)->IsValid()) {
@@ -208,8 +202,26 @@ bool CefPythonApp::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
208202
" messageName=DoJavascriptBindings");
209203
return false;
210204
}
205+
} else if (messageName == "ExecuteJavascriptCallback") {
206+
if (args->GetType(0) == VTYPE_INT) {
207+
int jsCallbackId = args->GetInt(0);
208+
CefRefPtr<CefListValue> jsArgs;
209+
if (args->IsReadOnly()) {
210+
jsArgs = args->Copy();
211+
} else {
212+
jsArgs = args;
213+
}
214+
// Remove jsCallbackId.
215+
jsArgs->Remove(0);
216+
ExecuteJavascriptCallback(jsCallbackId, jsArgs);
217+
} else {
218+
DebugLog("Renderer: OnProcessMessageReceived: invalid arguments," \
219+
"expected first argument to be a javascript callback " \
220+
"(int)");
221+
return false;
222+
}
211223
}
212-
return false;
224+
return true;
213225
}
214226

215227
void CefPythonApp::SetJavascriptBindings(CefRefPtr<CefBrowser> browser,
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
// Copyright (c) 2012-2013 The CEF Python authors. All rights reserved.
2+
// License: New BSD License.
3+
// Website: http://code.google.com/p/cefpython/
4+
5+
#include "javascript_callback.h"
6+
#include <map>
7+
#include <sstream>
8+
#include "DebugLog.h"
9+
#include "v8utils.h"
10+
11+
template<typename T>
12+
std::string AnyToString(const T& value)
13+
{
14+
std::ostringstream oss;
15+
oss << value;
16+
return oss.str();
17+
}
18+
19+
typedef std::map<int,
20+
std::pair<CefRefPtr<CefFrame>, CefRefPtr<CefV8Value> > >
21+
JavascriptCallbackMap;
22+
23+
JavascriptCallbackMap g_jsCallbackMap;
24+
int g_jsCallbackMaxId = 0;
25+
26+
CefString PutJavascriptCallback(
27+
CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Value> jsCallback) {
28+
// Returns a "####cefpython####" string followed by json encoded data.
29+
// {"what":"javascript-callback","callbackId":123,
30+
// "frameId":123,"functionName":"xx"}
31+
int callbackId = ++g_jsCallbackMaxId;
32+
int64 frameId = frame->GetIdentifier();
33+
CefString functionName = jsCallback->GetFunctionName();
34+
std::string strCallbackId = "####cefpython####";
35+
strCallbackId.append("{");
36+
// JSON format allows only for double quotes.
37+
strCallbackId.append("\"what\":\"javascript-callback\"");
38+
strCallbackId.append(",\"callbackId\":").append(AnyToString(callbackId));
39+
strCallbackId.append(",\"frameId\":").append(AnyToString(frameId));
40+
strCallbackId.append(",\"functionName\":\"").append(functionName) \
41+
.append("\"");
42+
strCallbackId.append("}");
43+
g_jsCallbackMap.insert(std::make_pair(
44+
callbackId,
45+
std::make_pair(frame, jsCallback)));
46+
return strCallbackId;
47+
}
48+
49+
bool ExecuteJavascriptCallback(int callbackId, CefRefPtr<CefListValue> args) {
50+
if (g_jsCallbackMap.empty()) {
51+
DebugLog("Renderer: ExecuteJavascriptCallback() FAILED: " \
52+
"callback map is empty");
53+
return false;
54+
}
55+
JavascriptCallbackMap::const_iterator it = g_jsCallbackMap.find(
56+
callbackId);
57+
if (it == g_jsCallbackMap.end()) {
58+
std::string logMessage = "Renderer: ExecuteJavascriptCallback() "
59+
"FAILED: callback not found, id=";
60+
logMessage.append(AnyToString(callbackId));
61+
DebugLog(logMessage.c_str());
62+
return false;
63+
}
64+
CefRefPtr<CefFrame> frame = it->second.first;
65+
CefRefPtr<CefV8Value> callback = it->second.second;
66+
CefRefPtr<CefV8Context> context = frame->GetV8Context();
67+
context->Enter();
68+
CefV8ValueList v8Arguments = CefListValueToCefV8ValueList(args);
69+
CefRefPtr<CefV8Value> v8ReturnValue = callback->ExecuteFunction(
70+
NULL, v8Arguments);
71+
if (v8ReturnValue.get()) {
72+
return true;
73+
} else {
74+
DebugLog("Renderer: ExecuteJavascriptCallback() FAILED: " \
75+
"callback->ExecuteFunction() FAILED");
76+
return false;
77+
}
78+
}
79+
80+
void RemoveJavascriptCallbacksForFrame(CefRefPtr<CefFrame> frame) {
81+
if (g_jsCallbackMap.empty()) {
82+
return;
83+
}
84+
JavascriptCallbackMap::iterator it = g_jsCallbackMap.begin();
85+
int64 frameId = frame->GetIdentifier();
86+
while (it != g_jsCallbackMap.end()) {
87+
if (it->second.first->GetIdentifier() == frameId) {
88+
g_jsCallbackMap.erase(it);
89+
DebugLog("Renderer: RemoveJavascriptCallbacksForFrame(): " \
90+
"removed js callback from the map");
91+
}
92+
++it;
93+
}
94+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Copyright (c) 2012-2013 The CEF Python authors. All rights reserved.
2+
// License: New BSD License.
3+
// Website: http://code.google.com/p/cefpython/
4+
5+
#include "include/cef_v8.h"
6+
7+
CefString PutJavascriptCallback(
8+
CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Value> jsCallback);
9+
10+
bool ExecuteJavascriptCallback(int callbackId, CefRefPtr<CefListValue> args);
11+
12+
void RemoveJavascriptCallbacksForFrame(CefRefPtr<CefFrame> frame);

cefpython/cef3/subprocess/main.cpp

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,6 @@
44

55
#include "cefpython_app.h"
66

7-
/*
8-
// Defined as "inline" to get rid of the "already defined" errors
9-
// when linking.
10-
inline void DebugLog(const char* szString)
11-
{
12-
// TODO: get the log_file option from CefSettings.
13-
printf("cefpython: %s\n", szString);
14-
FILE* pFile = fopen("debug.log", "a");
15-
fprintf(pFile, "cefpython_app: %s\n", szString);
16-
fclose(pFile);
17-
}
18-
*/
19-
207
#if defined(OS_WIN)
218

229
#include <windows.h>

0 commit comments

Comments
 (0)
X Tutup