mirror of
https://github.com/chenasraf/webview_cef.git
synced 2026-05-17 17:48:07 +00:00
fix some bug. support js console message, cursor change and show tooltip
This commit is contained in:
@@ -11,6 +11,7 @@ This project is under heavy development, and the APIs are not stable yet.
|
||||
- [Setting Up](#setting-up)
|
||||
- [Windows <img align="center" src="https://upload.wikimedia.org/wikipedia/commons/thumb/8/87/Windows_logo_-_2021.svg/1200px-Windows_logo_-_2021.svg.png" width="12">](#windows)
|
||||
- [macOS <img align="center" src="https://seeklogo.com/images/A/apple-logo-52C416BDDD-seeklogo.com.png" width="12">](#macos)
|
||||
- [Linux <img align="center" src="https://1000logos.net/wp-content/uploads/2017/03/LINUX-LOGO.png" width="14">](#linux)
|
||||
- [TODOs](#todos)
|
||||
- [Demo](#demo)
|
||||
- [Screenshots](#screenshots)
|
||||
@@ -30,7 +31,7 @@ Inside your application folder, you need to add two lines in your `windows\runne
|
||||
|
||||
```cpp
|
||||
#include "webview_cef/webview_cef_plugin_c_api.h"
|
||||
#包括“webview_cef/webview_cef_plugin_c_api.h”
|
||||
#include "webview_cef/webview_cef_plugin_c_api.h"
|
||||
|
||||
int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
|
||||
_In_ wchar_t *command_line, _In_ int show_command) {
|
||||
@@ -74,7 +75,7 @@ Then follow the below steps inside the `macos/` folder <b>of the cloned reposito
|
||||
|
||||
### Linux <img src="https://1000logos.net/wp-content/uploads/2017/03/LINUX-LOGO.png" width="16">
|
||||
|
||||
This part of the content needs to be summarized. You can refer to the methods in the example first. In addition, you need to modify the method of copying resources in the linux/CMakeLists.txt under your own project to be consistent with that in windows. Otherwise, the resource files cannot be copied properly under linux.
|
||||
This part of the content needs to be summarized. You can refer to the methods in the example first(Very similar to on the Windows). In addition, you need to modify the method of copying resources in the linux/CMakeLists.txt under your own project to be consistent with that in windows. Otherwise, the resource files cannot be copied properly under linux.
|
||||

|
||||
|
||||
## TODOs
|
||||
|
||||
@@ -82,18 +82,16 @@ WebviewApp::WebviewApp(CefRefPtr<WebviewHandler> handler) {
|
||||
|
||||
void WebviewApp::OnContextInitialized() {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
|
||||
|
||||
// Specify CEF browser settings here.
|
||||
CefBrowserSettings browser_settings;
|
||||
browser_settings.windowless_frame_rate = 60;
|
||||
|
||||
std::string url = "https://www.flutter.dev/";
|
||||
|
||||
|
||||
CefWindowInfo window_info;
|
||||
window_info.SetAsWindowless(0);
|
||||
|
||||
// Create the first browser window.
|
||||
CefBrowserHost::CreateBrowser(window_info, m_handler, url, browser_settings,
|
||||
CefBrowserHost::CreateBrowser(window_info, m_handler, "", browser_settings,
|
||||
nullptr, nullptr);
|
||||
}
|
||||
|
||||
|
||||
@@ -70,19 +70,49 @@ bool WebviewHandler::OnProcessMessageReceived(
|
||||
void WebviewHandler::OnTitleChange(CefRefPtr<CefBrowser> browser,
|
||||
const CefString& title) {
|
||||
//todo: title change
|
||||
if(onTitleChangedCb) {
|
||||
onTitleChangedCb(title);
|
||||
if(onTitleChangedEvent) {
|
||||
onTitleChangedEvent(title);
|
||||
}
|
||||
}
|
||||
|
||||
void WebviewHandler::OnAddressChange(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
const CefString& url) {
|
||||
if(onUrlChangedCb) {
|
||||
onUrlChangedCb(url);
|
||||
if(onUrlChangedEvent) {
|
||||
onTitleChangedEvent(url);
|
||||
}
|
||||
}
|
||||
|
||||
bool WebviewHandler::OnCursorChange(CefRefPtr<CefBrowser> browser,
|
||||
CefCursorHandle cursor,
|
||||
cef_cursor_type_t type,
|
||||
const CefCursorInfo& custom_cursor_info){
|
||||
if(onCursorChangedEvent) {
|
||||
onCursorChangedEvent(type);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WebviewHandler::OnTooltip(CefRefPtr<CefBrowser> browser, CefString& text) {
|
||||
if(onTooltipEvent) {
|
||||
onTooltipEvent(text);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WebviewHandler::OnConsoleMessage(CefRefPtr<CefBrowser> browser,
|
||||
cef_log_severity_t level,
|
||||
const CefString& message,
|
||||
const CefString& source,
|
||||
int line){
|
||||
if(onConsoleMessageEvent){
|
||||
onConsoleMessageEvent(level, message, source, line);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void WebviewHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
|
||||
|
||||
@@ -18,9 +18,15 @@ public CefLifeSpanHandler,
|
||||
public CefLoadHandler,
|
||||
public CefRenderHandler{
|
||||
public:
|
||||
//Paint callback
|
||||
std::function<void(const void*, int32_t width, int32_t height)> onPaintCallback;
|
||||
std::function<void(std::string url)> onUrlChangedCb;
|
||||
std::function<void(std::string title)> onTitleChangedCb;
|
||||
//cef message event
|
||||
std::function<void(std::string url)> onUrlChangedEvent;
|
||||
std::function<void(std::string title)> onTitleChangedEvent;
|
||||
std::function<void(int type)>onCursorChangedEvent;
|
||||
std::function<void(std::string text)> onTooltipEvent;
|
||||
std::function<void(int level, std::string message, std::string source, int line)>onConsoleMessageEvent;
|
||||
//custom action callback or webpage event
|
||||
std::function<void(std::map<std::string, std::map<std::string, std::string>>)> onAllCookieVisitedCb;
|
||||
std::function<void(std::map<std::string, std::map<std::string, std::string>>)> onUrlCookieVisitedCb;
|
||||
std::function<void(std::string, std::string, std::string, std::string)> onJavaScriptChannelMessage;
|
||||
@@ -54,6 +60,16 @@ public:
|
||||
virtual void OnAddressChange(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
const CefString& url) override;
|
||||
virtual bool OnCursorChange(CefRefPtr<CefBrowser> browser,
|
||||
CefCursorHandle cursor,
|
||||
cef_cursor_type_t type,
|
||||
const CefCursorInfo& custom_cursor_info) override;
|
||||
virtual bool OnTooltip(CefRefPtr<CefBrowser> browser, CefString& text) override;
|
||||
virtual bool OnConsoleMessage(CefRefPtr<CefBrowser> browser,
|
||||
cef_log_severity_t level,
|
||||
const CefString& message,
|
||||
const CefString& source,
|
||||
int line) override;
|
||||
|
||||
// CefLifeSpanHandler methods:
|
||||
virtual void OnAfterCreated(CefRefPtr<CefBrowser> browser) override;
|
||||
|
||||
@@ -16,8 +16,8 @@ namespace webview_cef {
|
||||
bool isFocused = false;
|
||||
std::function<void(std::string, WValue*)> invokeFunc;
|
||||
|
||||
CefRefPtr<WebviewHandler> handler(new WebviewHandler());
|
||||
CefRefPtr<WebviewApp> app(new WebviewApp(handler));
|
||||
CefRefPtr<WebviewHandler> handler;
|
||||
CefRefPtr<WebviewApp> app;
|
||||
CefMainArgs mainArgs;
|
||||
|
||||
static int cursorAction(WValue *args, std::string name) {
|
||||
@@ -46,7 +46,7 @@ namespace webview_cef {
|
||||
|
||||
void initCEFProcesses(CefMainArgs args){
|
||||
mainArgs = args;
|
||||
CefExecuteProcess(mainArgs, app, nullptr);
|
||||
initCEFProcesses();
|
||||
}
|
||||
|
||||
void initCEFProcesses(){
|
||||
@@ -56,6 +56,8 @@ namespace webview_cef {
|
||||
printf("load cef err");
|
||||
}
|
||||
#endif
|
||||
handler = new WebviewHandler();
|
||||
app = new WebviewApp(handler);
|
||||
CefExecuteProcess(mainArgs, app, nullptr);
|
||||
}
|
||||
|
||||
@@ -70,18 +72,17 @@ namespace webview_cef {
|
||||
#ifndef OS_MAC
|
||||
cefs.no_sandbox = true;
|
||||
#endif
|
||||
|
||||
#ifdef OS_MAC
|
||||
|
||||
#ifdef OS_WIN
|
||||
//cef message loop run in another thread on windows
|
||||
cefs.multi_threaded_message_loop = true;
|
||||
#else
|
||||
//cef message loop handle by MainApplication
|
||||
cefs.external_message_pump = true;
|
||||
//CefString(&cefs.browser_subprocess_path) = "/Library/Chaches";
|
||||
//CefString(&cefs.browser_subprocess_path) = "/Library/Chaches"; //the helper Program path
|
||||
#endif
|
||||
|
||||
CefInitialize(mainArgs, cefs, app.get(), nullptr);
|
||||
|
||||
#ifdef OS_WIN
|
||||
CefRunMessageLoop();
|
||||
CefShutdown();
|
||||
#endif
|
||||
}
|
||||
|
||||
void doMessageLoopWork()
|
||||
@@ -91,7 +92,13 @@ namespace webview_cef {
|
||||
|
||||
int HandleMethodCall(std::string name, WValue* values, WValue* response) {
|
||||
int result = -1;
|
||||
if (name.compare("loadUrl") == 0) {
|
||||
if(name.compare("dispose") == 0){
|
||||
// we don't need to dispose the texture, texture will be disposed by flutter engine
|
||||
// int64_t textureId = webview_value_get_int(values);
|
||||
CefShutdown();
|
||||
result = 1;
|
||||
}
|
||||
else if (name.compare("loadUrl") == 0) {
|
||||
if (const auto url = webview_value_get_string(values)) {
|
||||
handler.get()->loadUrl(url);
|
||||
result = 1;
|
||||
@@ -213,26 +220,68 @@ namespace webview_cef {
|
||||
if (!init)
|
||||
{
|
||||
handler.get()->onPaintCallback = callback;
|
||||
handler.get()->onUrlChangedCb = [](std::string url)
|
||||
handler.get()->onUrlChangedEvent = [](std::string url)
|
||||
{
|
||||
if (invokeFunc)
|
||||
{
|
||||
WValue *wUrl = webview_value_new_string(const_cast<char *>(url.c_str()));
|
||||
invokeFunc("urlChanged", wUrl);
|
||||
invokeFunc("onUrlChangedEvent", wUrl);
|
||||
webview_value_unref(wUrl);
|
||||
}
|
||||
};
|
||||
|
||||
handler.get()->onTitleChangedCb = [](std::string title)
|
||||
handler.get()->onTitleChangedEvent = [](std::string title)
|
||||
{
|
||||
if (invokeFunc)
|
||||
{
|
||||
WValue *wTitle = webview_value_new_string(const_cast<char *>(title.c_str()));
|
||||
invokeFunc("titleChanged", wTitle);
|
||||
invokeFunc("onTitleChangedEvent", wTitle);
|
||||
webview_value_unref(wTitle);
|
||||
}
|
||||
};
|
||||
|
||||
handler.get()->onTooltipEvent = [](std::string text) {
|
||||
if (invokeFunc) {
|
||||
WValue* wText = webview_value_new_string(const_cast<char*>(text.c_str()));
|
||||
WValue* retMap = webview_value_new_map();
|
||||
webview_value_set_string(retMap, "text", wText);
|
||||
invokeFunc("onTooltipEvent", retMap);
|
||||
webview_value_unref(wText);
|
||||
webview_value_unref(retMap);
|
||||
}
|
||||
};
|
||||
|
||||
handler.get()->onCursorChangedEvent = [](int type) {
|
||||
if(invokeFunc){
|
||||
WValue* wType = webview_value_new_int(type);
|
||||
WValue* retMap = webview_value_new_map();
|
||||
webview_value_set_string(retMap, "type", wType);
|
||||
invokeFunc("onCursorChangedEvent", retMap);
|
||||
webview_value_unref(wType);
|
||||
webview_value_unref(retMap);
|
||||
}
|
||||
};
|
||||
|
||||
handler.get()->onConsoleMessageEvent = [](int level, std::string message, std::string source, int line){
|
||||
if(invokeFunc){
|
||||
WValue* wLevel = webview_value_new_int(level);
|
||||
WValue* wMessage = webview_value_new_string(const_cast<char*>(message.c_str()));
|
||||
WValue* wSource = webview_value_new_string(const_cast<char*>(source.c_str()));
|
||||
WValue* wLine = webview_value_new_int(line);
|
||||
WValue* retMap = webview_value_new_map();
|
||||
webview_value_set_string(retMap, "level", wLevel);
|
||||
webview_value_set_string(retMap, "message", wMessage);
|
||||
webview_value_set_string(retMap, "source", wSource);
|
||||
webview_value_set_string(retMap, "line", wLine);
|
||||
invokeFunc("onConsoleMessageEvent", retMap);
|
||||
webview_value_unref(wLevel);
|
||||
webview_value_unref(wMessage);
|
||||
webview_value_unref(wSource);
|
||||
webview_value_unref(wLine);
|
||||
webview_value_unref(retMap);
|
||||
}
|
||||
};
|
||||
|
||||
handler.get()->onAllCookieVisitedCb = [](std::map<std::string, std::map<std::string, std::string>> cookies)
|
||||
{
|
||||
if (invokeFunc)
|
||||
@@ -298,14 +347,7 @@ namespace webview_cef {
|
||||
webview_value_unref(fId);
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(OS_WIN)
|
||||
//windows run in multi thread
|
||||
new std::thread(startCEF);
|
||||
#else
|
||||
//mac、linux run in main thread
|
||||
startCEF();
|
||||
#endif
|
||||
init = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'webview_events_listener.dart';
|
||||
import 'webview_javascript.dart';
|
||||
import 'webview_tooltip.dart';
|
||||
|
||||
const MethodChannel _pluginChannel = MethodChannel("webview_cef");
|
||||
|
||||
@@ -45,10 +46,10 @@ class WebViewController extends ValueNotifier<bool> {
|
||||
Future<void> _methodCallhandler(MethodCall call) async {
|
||||
if (_listener == null) return;
|
||||
switch (call.method) {
|
||||
case "urlChanged":
|
||||
case "onUrlChangedEvent":
|
||||
_listener?.onUrlChanged?.call(call.arguments);
|
||||
return;
|
||||
case "titleChanged":
|
||||
case "onTitleChangedEvent":
|
||||
_listener?.onTitleChanged?.call(call.arguments);
|
||||
return;
|
||||
case "allCookiesVisited":
|
||||
@@ -64,6 +65,19 @@ class WebViewController extends ValueNotifier<bool> {
|
||||
call.arguments['callbackId'],
|
||||
call.arguments['frameId']);
|
||||
break;
|
||||
case 'onTooltipEvent':
|
||||
onToolTip?.call(call.arguments['text']);
|
||||
break;
|
||||
case 'onCursorChangedEvent':
|
||||
onCursorChanged?.call(call.arguments['type']);
|
||||
break;
|
||||
case 'onConsoleMessageEvent':
|
||||
_listener?.onConsoleMessage?.call(
|
||||
call.arguments['level'],
|
||||
call.arguments['message'],
|
||||
call.arguments['source'],
|
||||
call.arguments['line']);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
@@ -274,6 +288,9 @@ class WebViewController extends ValueNotifier<bool> {
|
||||
}
|
||||
assert(_extractJavascriptChannelNames(channels).length == channels.length);
|
||||
}
|
||||
|
||||
Function(String)? onToolTip;
|
||||
Function(int)? onCursorChanged;
|
||||
}
|
||||
|
||||
class WebView extends StatefulWidget {
|
||||
@@ -288,12 +305,44 @@ class WebView extends StatefulWidget {
|
||||
class WebViewState extends State<WebView> {
|
||||
final GlobalKey _key = GlobalKey();
|
||||
late final _focusNode = FocusNode();
|
||||
WebviewTooltip? _tooltip;
|
||||
MouseCursor _mouseType = SystemMouseCursors.basic;
|
||||
|
||||
WebViewController get _controller => widget.controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
_controller.onToolTip = (final String text) {
|
||||
_tooltip ??= WebviewTooltip(_key.currentContext!);
|
||||
_tooltip?.showToolTip(text);
|
||||
};
|
||||
|
||||
_controller.onCursorChanged = (int type) {
|
||||
switch (type) {
|
||||
case 0:
|
||||
_mouseType = SystemMouseCursors.basic;
|
||||
break;
|
||||
case 1:
|
||||
_mouseType = SystemMouseCursors.precise;
|
||||
break;
|
||||
case 2:
|
||||
_mouseType = SystemMouseCursors.click;
|
||||
break;
|
||||
case 3:
|
||||
_mouseType = SystemMouseCursors.text;
|
||||
break;
|
||||
case 4:
|
||||
_mouseType = SystemMouseCursors.wait;
|
||||
break;
|
||||
default:
|
||||
_mouseType = SystemMouseCursors.basic;
|
||||
break;
|
||||
}
|
||||
setState(() {});
|
||||
};
|
||||
|
||||
// Report initial surface size
|
||||
WidgetsBinding.instance
|
||||
.addPostFrameCallback((_) => _reportSurfaceSize(context));
|
||||
@@ -323,6 +372,7 @@ class WebViewState extends State<WebView> {
|
||||
child: Listener(
|
||||
onPointerHover: (ev) {
|
||||
_controller._cursorMove(ev.localPosition);
|
||||
_tooltip?.cursorOffset = ev.position;
|
||||
},
|
||||
onPointerDown: (ev) {
|
||||
if (!_focusNode.hasFocus) {
|
||||
@@ -351,7 +401,10 @@ class WebViewState extends State<WebView> {
|
||||
_controller._setScrollDelta(event.localPosition,
|
||||
event.panDelta.dx.round(), event.panDelta.dy.round());
|
||||
},
|
||||
child: Texture(textureId: _controller._textureId),
|
||||
child: MouseRegion(
|
||||
cursor: _mouseType,
|
||||
child: Texture(textureId: _controller._textureId),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -2,16 +2,30 @@ typedef TitleChangeCb = void Function(String title);
|
||||
typedef UrlChangeCb = void Function(String url);
|
||||
typedef AllCookieVisitedCb = void Function(Map<String, dynamic> cookies);
|
||||
typedef UrlCookieVisitedCb = void Function(Map<String, dynamic> cookies);
|
||||
/* Log severity levels. from CEF include/internal/cef_types.h
|
||||
0:default logging (currently info logging)
|
||||
1:verbose logging or debug logging
|
||||
2:info logging
|
||||
3:warning logging
|
||||
4:error logging
|
||||
5:fatal logging
|
||||
99:disable logging to file for all messages, and to stderr for messages with severity less than fatal
|
||||
*/
|
||||
typedef OnConsoleMessage = void Function(
|
||||
int level, String message, String source, int line);
|
||||
|
||||
class WebviewEventsListener {
|
||||
TitleChangeCb? onTitleChanged;
|
||||
UrlChangeCb? onUrlChanged;
|
||||
AllCookieVisitedCb? onAllCookiesVisited;
|
||||
UrlCookieVisitedCb? onUrlCookiesVisited;
|
||||
OnConsoleMessage? onConsoleMessage;
|
||||
|
||||
WebviewEventsListener(
|
||||
{this.onTitleChanged,
|
||||
this.onUrlChanged,
|
||||
this.onAllCookiesVisited,
|
||||
this.onUrlCookiesVisited});
|
||||
WebviewEventsListener({
|
||||
this.onTitleChanged,
|
||||
this.onUrlChanged,
|
||||
this.onAllCookiesVisited,
|
||||
this.onUrlCookiesVisited,
|
||||
this.onConsoleMessage,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -4,8 +4,7 @@ class JavascriptMessage {
|
||||
/// Constructs a JavaScript message object.
|
||||
///
|
||||
/// The `message` parameter must not be null.
|
||||
const JavascriptMessage(this.message, this.callbackId, this.frameId)
|
||||
: assert(message != null && frameId != null);
|
||||
const JavascriptMessage(this.message, this.callbackId, this.frameId);
|
||||
|
||||
/// The contents of the message that was sent by the JavaScript code.
|
||||
final String message;
|
||||
|
||||
100
lib/src/webview_tooltip.dart
Normal file
100
lib/src/webview_tooltip.dart
Normal file
@@ -0,0 +1,100 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class WebviewTooltip {
|
||||
WebviewTooltip(BuildContext context) {
|
||||
_overlayState = Overlay.of(context);
|
||||
_box = context.findRenderObject() as RenderBox;
|
||||
}
|
||||
late OverlayState _overlayState;
|
||||
OverlayEntry? _overlayEntry;
|
||||
Timer? _timer;
|
||||
TooltipStatus _eStatus = TooltipStatus.hide;
|
||||
Offset cursorOffset = Offset.zero;
|
||||
late RenderBox _box;
|
||||
final TextStyle _textStyle =
|
||||
const TextStyle(color: Colors.black, fontSize: 14);
|
||||
|
||||
void _buildOverlayEntry(String text) {
|
||||
//往Overlay中插入插入OverlayEntry
|
||||
_timer = Timer(const Duration(milliseconds: 500), () {
|
||||
_overlayEntry = OverlayEntry(builder: (context) {
|
||||
double height = _box.size.height;
|
||||
double width = _box.size.width;
|
||||
TextPainter textPainter = TextPainter(
|
||||
locale: Localizations.localeOf(context),
|
||||
textDirection: TextDirection.ltr,
|
||||
text: TextSpan(text: text, style: _textStyle),
|
||||
)..layout(maxWidth: 500, minWidth: 1);
|
||||
if (cursorOffset.dy + textPainter.height + 25 > height) {
|
||||
cursorOffset =
|
||||
Offset(cursorOffset.dx, height - textPainter.height - 10);
|
||||
if (cursorOffset.dy < 0) {
|
||||
cursorOffset = Offset(cursorOffset.dx, 0);
|
||||
}
|
||||
} else {
|
||||
cursorOffset = Offset(cursorOffset.dx, cursorOffset.dy + 15);
|
||||
}
|
||||
|
||||
if (cursorOffset.dx + textPainter.width + 40 > width) {
|
||||
cursorOffset =
|
||||
Offset(width - textPainter.width - 25, cursorOffset.dy);
|
||||
if (cursorOffset.dx < 0) {
|
||||
cursorOffset = Offset(0, cursorOffset.dy);
|
||||
}
|
||||
} else {
|
||||
cursorOffset = Offset(cursorOffset.dx + 15, cursorOffset.dy);
|
||||
}
|
||||
return Positioned(
|
||||
top: cursorOffset.dy,
|
||||
left: cursorOffset.dx,
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
child: Container(
|
||||
width: textPainter.width + 16,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: const BorderRadius.all(Radius.circular(4)),
|
||||
boxShadow: [
|
||||
BoxShadow(blurRadius: 2, color: Colors.black.withOpacity(.2))
|
||||
],
|
||||
),
|
||||
child: Text(
|
||||
text,
|
||||
style: _textStyle,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
_overlayState.insert(_overlayEntry!);
|
||||
_eStatus = TooltipStatus.shown;
|
||||
});
|
||||
}
|
||||
|
||||
void showToolTip(String text) {
|
||||
if (text.isEmpty) {
|
||||
if (_eStatus == TooltipStatus.prepare) {
|
||||
_timer?.cancel();
|
||||
} else {
|
||||
_overlayEntry?.remove();
|
||||
}
|
||||
_eStatus = TooltipStatus.hide;
|
||||
return;
|
||||
} else if (_eStatus == TooltipStatus.hide) {
|
||||
_eStatus = TooltipStatus.prepare;
|
||||
_buildOverlayEntry(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum TooltipStatus {
|
||||
//Tooltip is prepare to show, Timer is running
|
||||
prepare,
|
||||
//Tooltip is alreay shown
|
||||
shown,
|
||||
//Tooltip is hide or uninitialized
|
||||
hide
|
||||
}
|
||||
@@ -74,6 +74,11 @@ add_subdirectory(${CEF_LIBCEF_DLL_WRAPPER_PATH} libcef_dll_wrapper)
|
||||
# Find required libraries and update compiler/linker variables.
|
||||
FIND_LINUX_LIBRARIES("gmodule-2.0 gtk+-3.0 gthread-2.0 gtk+-unix-print-3.0 xi")
|
||||
|
||||
find_program(XCLIP_EXECUTABLE xclip)
|
||||
if(NOT XCLIP_EXECUTABLE)
|
||||
message(AUTHOR_WARNING "xclip executable not found. Users need it to paste text into CEF Area.")
|
||||
endif()
|
||||
|
||||
# Executable target.
|
||||
# add_executable(${CEF_TARGET} ${CEFCLIENT_SRCS})
|
||||
SET_EXECUTABLE_TARGET_PROPERTIES(${CEF_TARGET})
|
||||
@@ -89,7 +94,7 @@ set_target_properties(${CEF_TARGET} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CEF_TA
|
||||
add_definitions("-DGTK_DISABLE_DEPRECATED")
|
||||
|
||||
# Set SUID permissions on the chrome-sandbox target.
|
||||
SET_LINUX_SUID_PERMISSIONS("${CEF_TARGET}" "${CEF_TARGET_OUT_DIR}/chrome-sandbox")
|
||||
# SET_LINUX_SUID_PERMISSIONS("${CEF_TARGET}" "${CEF_TARGET_OUT_DIR}/chrome-sandbox")
|
||||
|
||||
#set CEF binary and resource files which need to copy to the target output directory
|
||||
set(cef_library_list "")
|
||||
|
||||
@@ -64,7 +64,7 @@ static FlValue* encode_wavlue_to_flvalue(WValue *args){
|
||||
FlValue * ret = fl_value_new_list();
|
||||
size_t len = webview_value_get_len(args);
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
FlValue * val = encode_wavlue_to_flvalue(webview_value_get_value(args, i));
|
||||
FlValue * val = encode_wavlue_to_flvalue(webview_value_get_list_value(args, i));
|
||||
fl_value_append(ret, val);
|
||||
fl_value_unref(val);
|
||||
}
|
||||
@@ -167,6 +167,7 @@ static void webview_cef_plugin_handle_method_call(
|
||||
texture->width = width;
|
||||
texture->height = height;
|
||||
const auto size = width * height * 4;
|
||||
delete texture->buffer;
|
||||
texture->buffer = new uint8_t[size];
|
||||
webview_cef::SwapBufferFromBgraToRgba((void*)texture->buffer, buffer, width, height);
|
||||
fl_texture_registrar_mark_texture_frame_available(texture_register, FL_TEXTURE(texture));
|
||||
@@ -274,7 +275,15 @@ FLUTTER_PLUGIN_EXPORT gboolean processKeyEventForCEF(GtkWidget *widget, GdkEvent
|
||||
// We need to treat the enter key as a key press of character \r. This
|
||||
// is apparently just how webkit handles it and what it expects.
|
||||
key_event.unmodified_character = '\r';
|
||||
} else {
|
||||
}
|
||||
else if(windows_key_code == VKEY_V && EVENTFLAG_CONTROL_DOWN && event->type == GDK_KEY_PRESS){
|
||||
//try to fix copy request freeze process problem,(flutter engine will send a copy request when ctrl+v pressed)
|
||||
int res = 0;
|
||||
if(system("xclip -o -sel clipboard | xclip -i -sel clipboard &>/dev/null") == 0){
|
||||
res = system("xclip -o -sel clipboard | xclip -i &>/dev/null");
|
||||
}
|
||||
}
|
||||
else {
|
||||
// FIXME: fix for non BMP chars
|
||||
key_event.unmodified_character =
|
||||
static_cast<int>(gdk_keyval_to_unicode(event->keyval));
|
||||
|
||||
@@ -58,7 +58,7 @@ FlutterMethodChannel* f_channel;
|
||||
int len = webview_value_get_len(args);
|
||||
NSMutableArray* array = [NSMutableArray arrayWithCapacity:len];
|
||||
for(int i = 0; i < len; i++) {
|
||||
WValue* item = webview_value_get_value(args, i);
|
||||
WValue* item = webview_value_get_list_value(args, i);
|
||||
[array addObject:[self encode_wvalue_to_flvalue:item]];
|
||||
}
|
||||
return array;
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
message(STATUS "current system is Linux")
|
||||
message(WARNING "current system is Linux")
|
||||
if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "aarch64")
|
||||
set(cef_prebuilt_path "https://github.com/hlwhl/webview_cef/releases/download/prebuilt_cef_bin_linux/cef_binary_114.2.9+g1a97a28+chromium-114.0.5735.91_linuxarm64.zip")
|
||||
else()
|
||||
set(cef_prebuilt_path "https://github.com/hlwhl/webview_cef/releases/download/prebuilt_cef_bin_linux/cef_binary_114.2.9+g1a97a28+chromium-114.0.5735.91_linux64.zip")
|
||||
endif()
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
||||
message(STATUS "current system is Windows")
|
||||
message(WARNING "current system is Windows")
|
||||
set(cef_prebuilt_path "https://github.com/hlwhl/webview_cef/releases/download/prebuilt_cef_bin_linux/webview_cef_bin_0.0.2_101.0.18+chromium-101.0.4951.67_windows64.zip")
|
||||
# elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
||||
# message(STATUS "current system is MacOS")
|
||||
@@ -16,7 +16,7 @@ set(cef_prebuilt_version_path "https://github.com/hlwhl/webview_cef/releases/dow
|
||||
|
||||
|
||||
function(extract_file filename extract_dir)
|
||||
message(STATUS "${filename} will extract to ${extract_dir} ...")
|
||||
message(WARNING "${filename} will extract to ${extract_dir} ...")
|
||||
|
||||
set(temp_dir ${CMAKE_BINARY_DIR}/tmp_for_extract.dir)
|
||||
if(EXISTS ${temp_dir})
|
||||
@@ -40,7 +40,7 @@ function(extract_file filename extract_dir)
|
||||
endfunction()
|
||||
|
||||
function(download_file url filename)
|
||||
message(STATUS "Downloading ${filename} from ${url}")
|
||||
message(WARNING "Downloading ${filename} from ${url}")
|
||||
file(DOWNLOAD ${url} ${filename} STATUS SHOW_PROGRESS)
|
||||
endfunction(download_file)
|
||||
|
||||
@@ -48,16 +48,18 @@ function(prepare_prebuilt_files filepath)
|
||||
set(need_download FALSE)
|
||||
|
||||
if(NOT EXISTS ${filepath})
|
||||
message(WARNING "No ${filepath} found")
|
||||
set(need_download TRUE)
|
||||
else()
|
||||
if(NOT EXISTS ${filepath}/version.txt)
|
||||
message(WARNING "No ${filepath}/version.txt found")
|
||||
set(need_download TRUE)
|
||||
else()
|
||||
download_file(${cef_prebuilt_version_path} ${filepath}/new_version.txt)
|
||||
file(READ ${filepath}/version.txt local_version)
|
||||
file(READ ${filepath}/new_version.txt new_version)
|
||||
if(local_version STREQUAL new_version)
|
||||
message(STATUS "No need to update ${filepath}")
|
||||
message(WARNING "No need to update ${filepath}")
|
||||
else()
|
||||
set(need_download TRUE)
|
||||
endif()
|
||||
@@ -66,7 +68,7 @@ function(prepare_prebuilt_files filepath)
|
||||
endif()
|
||||
|
||||
if(need_download)
|
||||
message(STATUS "Need to update ${filepath}")
|
||||
message(WARNING "Need to update ${filepath}")
|
||||
file(REMOVE_RECURSE ${filepath}/cmake ${filepath}/Debug ${filepath}/Release ${filepath}/Resources ${filepath}/libcef_dll ${filepath}/libcef_dll_wrapper)
|
||||
download_file(${cef_prebuilt_path} ${CMAKE_CURRENT_SOURCE_DIR}/prebuilt.zip)
|
||||
file(MAKE_DIRECTORY ${filepath})
|
||||
|
||||
@@ -66,7 +66,7 @@ namespace webview_cef {
|
||||
flutter::EncodableList ret;
|
||||
size_t len = webview_value_get_len(args);
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
ret.push_back(encode_wvalue_to_flvalue(webview_value_get_value(args, i)));
|
||||
ret.push_back(encode_wvalue_to_flvalue(webview_value_get_list_value(args, i)));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user