Compare commits
8 Commits
0-1-5
...
803d6edd41
| Author | SHA1 | Date | |
|---|---|---|---|
| 803d6edd41 | |||
| 35b7bfe2e9 | |||
| c6db000d26 | |||
| 85b5a29192 | |||
| b53597396c | |||
| be980dbffd | |||
| 8165ee20cc | |||
| cacffbcc2a |
@@ -43,6 +43,9 @@ add_executable(rktwebview_prg
|
||||
rkt_protocol.h
|
||||
rktwebview_types.h
|
||||
utils.cpp utils.h
|
||||
|
||||
build_menu_from_json.cpp
|
||||
build_menu_from_json.h
|
||||
)
|
||||
|
||||
add_executable(rktwebview_test
|
||||
@@ -53,6 +56,7 @@ target_link_libraries(rktwebview_prg PRIVATE Qt${QT_VERSION_MAJOR}::Widgets)
|
||||
target_link_libraries(rktwebview_prg PRIVATE Qt${QT_VERSION_MAJOR}::WebEngineWidgets)
|
||||
|
||||
target_compile_definitions(rktwebview PRIVATE RKTWEBVIEW_LIBRARY)
|
||||
target_compile_definitions(rktwebview_prg PRIVATE RKTWEBVIEW_PRG_EXE)
|
||||
|
||||
target_link_Libraries(rktwebview_test PRIVATE rktwebview)
|
||||
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
#include <QJsonArray>
|
||||
#include <QJsonParseError>
|
||||
#include <QJsonObject>
|
||||
#include <QMenu>
|
||||
#include "rktwebview_qt.h"
|
||||
#include "utils.h"
|
||||
|
||||
static QAction *addMenuItemFromJson(Rktwebview_qt *owner,
|
||||
QMenu *menu,
|
||||
const QJsonObject &item,
|
||||
int source_handle);
|
||||
|
||||
static QMenu *buildMenuObjectFromJson(Rktwebview_qt *owner,
|
||||
const QJsonArray &items,
|
||||
int source_handle,
|
||||
QWidget *parent = nullptr)
|
||||
{
|
||||
QMenu *menu = new QMenu(parent);
|
||||
|
||||
for (const QJsonValue &v : items) {
|
||||
if (!v.isObject()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
QJsonObject item = v.toObject();
|
||||
|
||||
if (item.value("separator").toBool(false)) {
|
||||
menu->addSeparator();
|
||||
continue;
|
||||
}
|
||||
|
||||
addMenuItemFromJson(owner, menu, item, source_handle);
|
||||
}
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
static QAction *addMenuItemFromJson(Rktwebview_qt *owner,
|
||||
QMenu *menu,
|
||||
const QJsonObject &item,
|
||||
int source_handle)
|
||||
{
|
||||
QString id = item.value("id").toString();
|
||||
QString name = item.value("name").toString();
|
||||
QString icon_file = item.value("icon").toString();
|
||||
|
||||
QAction *action = nullptr;
|
||||
|
||||
QJsonValue submenu_value = item.value("submenu");
|
||||
if (submenu_value.isObject()) {
|
||||
QJsonObject submenu_obj = submenu_value.toObject();
|
||||
QJsonArray submenu_items = submenu_obj.value("menu").toArray();
|
||||
|
||||
QMenu *submenu = buildMenuObjectFromJson(owner,
|
||||
submenu_items,
|
||||
source_handle,
|
||||
menu);
|
||||
|
||||
if (!icon_file.isEmpty()) {
|
||||
submenu->setIcon(QIcon(icon_file));
|
||||
}
|
||||
|
||||
submenu->setTitle(name);
|
||||
action = menu->addMenu(submenu);
|
||||
} else {
|
||||
if (icon_file.isEmpty()) {
|
||||
action = menu->addAction(name);
|
||||
} else {
|
||||
action = menu->addAction(QIcon(icon_file), name);
|
||||
}
|
||||
|
||||
QObject::connect(action, &QAction::triggered,
|
||||
owner, [owner, source_handle, id]() {
|
||||
EventContainer e("tray-menu-item-chosen");
|
||||
e["id"] = id;
|
||||
e["menu_item"] = id;
|
||||
owner->triggerEvent(source_handle, e);
|
||||
});
|
||||
}
|
||||
|
||||
action->setData(id);
|
||||
return action;
|
||||
}
|
||||
|
||||
QMenu *buildMenuFromJson(Rktwebview_qt *self, const QString &menu_json, int source_handle)
|
||||
{
|
||||
QJsonParseError err;
|
||||
QJsonDocument doc = QJsonDocument::fromJson(menu_json.toUtf8(), &err);
|
||||
|
||||
if (err.error != QJsonParseError::NoError || !doc.isObject()) {
|
||||
ERROR2("Json parse error for menu: %d, '%s'\n", err.error, err.errorString().toUtf8().constData());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QJsonObject root = doc.object();
|
||||
QJsonArray items = root.value("menu").toArray();
|
||||
|
||||
return buildMenuObjectFromJson(self, items, source_handle);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#ifndef BUILD_MENU_FROM_JSON_H
|
||||
#define BUILD_MENU_FROM_JSON_H
|
||||
|
||||
class QMenu;
|
||||
class Rktwebview_qt;
|
||||
class QString;
|
||||
|
||||
QMenu *buildMenuFromJson(Rktwebview_qt *self, const QString &menu_json, int source_handle);
|
||||
|
||||
#endif // BUILD_MENU_FROM_JSON_H
|
||||
@@ -29,6 +29,11 @@
|
||||
#define COMMAND_NEW_CONTEXT 23
|
||||
#define COMMAND_MESSAGE 24
|
||||
#define COMMAND_SET_ICON 25
|
||||
#define COMMAND_CREATE_TRAY 26
|
||||
#define COMMAND_TRAY_SET_ICON 27
|
||||
#define COMMAND_TRAY_SET_TOOLTIP 28
|
||||
#define COMMAND_TRAY_SHOW_MESSAGE 29
|
||||
#define COMMAND_TRAY_SET_MENU 30
|
||||
|
||||
class Command
|
||||
{
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,48 @@
|
||||
[
|
||||
{
|
||||
"name": "qtbase",
|
||||
"repositories": ["qtbase", "qtactiveqt", "qtimageformats"]
|
||||
},
|
||||
{
|
||||
"name": "qtdeclarative",
|
||||
"repositories": ["qtdeclarative"]
|
||||
},
|
||||
{
|
||||
"name": "qtmultimedia",
|
||||
"repositories": ["qtmultimedia"]
|
||||
},
|
||||
{
|
||||
"name": "qtconnectivity",
|
||||
"repositories": ["qtconnectivity"]
|
||||
},
|
||||
{
|
||||
"name": "qtlocation",
|
||||
"repositories": ["qtlocation"]
|
||||
},
|
||||
{
|
||||
"name": "qtwebsockets",
|
||||
"repositories": ["qtwebsockets"]
|
||||
},
|
||||
{
|
||||
"name": "qtserialport",
|
||||
"repositories": ["qtserialport"]
|
||||
},
|
||||
{
|
||||
"name": "qtwebengine",
|
||||
"repositories": ["qtwebengine"]
|
||||
},
|
||||
{
|
||||
"name": "designer",
|
||||
"modules": ["Designer"]
|
||||
},
|
||||
{
|
||||
"name": "linguist"
|
||||
},
|
||||
{
|
||||
"name": "assistant"
|
||||
},
|
||||
{
|
||||
"name": "qt_help",
|
||||
"modules": ["Help"]
|
||||
}
|
||||
]
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -13,6 +13,13 @@
|
||||
|
||||
#include "rktwebview_qt.h"
|
||||
|
||||
|
||||
#ifdef DEBUG_RKT_WEBVIEW
|
||||
#define WAIT_TIME (300 * 1000)
|
||||
#else
|
||||
#define WAIT_TIME (10 * 1000)
|
||||
#endif
|
||||
|
||||
static void free_data(rkt_data_t *d)
|
||||
{
|
||||
do_free_data(d);
|
||||
@@ -163,7 +170,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
void Handler::run()
|
||||
{
|
||||
int wait_ms = 10 * 1000; // 10 seconds.
|
||||
int wait_ms = WAIT_TIME; // 10 seconds.
|
||||
while (!quit) {
|
||||
int cmd;
|
||||
std::string data;
|
||||
@@ -339,6 +346,60 @@ void Handler::run()
|
||||
result_queue->enqueue(r);
|
||||
}
|
||||
break;
|
||||
case CMD_CREATE_TRAY: {
|
||||
QString icon_file = data_obj["icon"].toString();
|
||||
QString tooltip = data_obj["tooltip"].toString();
|
||||
|
||||
int tray = webview_handler->rktTrayCreate(icon_file.toUtf8().constData(),
|
||||
tooltip.toUtf8().constData(),
|
||||
event_cb);
|
||||
result_queue->enqueue(tray);
|
||||
}
|
||||
break;
|
||||
case CMD_TRAY_SET_ICON: {
|
||||
int tray = data_obj["wv"].toInt();
|
||||
QString icon_file = data_obj["icon"].toString();
|
||||
|
||||
result_t r = webview_handler->rktTraySetIcon(tray,
|
||||
icon_file.toUtf8().constData());
|
||||
result_queue->enqueue(r);
|
||||
}
|
||||
break;
|
||||
case CMD_TRAY_SET_TOOLTIP: {
|
||||
int tray = data_obj["wv"].toInt();
|
||||
QString tooltip = data_obj["tooltip"].toString();
|
||||
|
||||
result_t r = webview_handler->rktTraySetTooltip(tray,
|
||||
tooltip.toUtf8().constData());
|
||||
result_queue->enqueue(r);
|
||||
}
|
||||
break;
|
||||
case CMD_TRAY_SHOW_MESSAGE: {
|
||||
int tray = data_obj["wv"].toInt();
|
||||
QString title = data_obj["title"].toString();
|
||||
QString message = data_obj["message"].toString();
|
||||
|
||||
result_t r = webview_handler->rktTrayShowMessage(tray,
|
||||
title.toUtf8().constData(),
|
||||
message.toUtf8().constData());
|
||||
result_queue->enqueue(r);
|
||||
}
|
||||
break;
|
||||
case CMD_TRAY_CLEAR_MENU: {
|
||||
int tray = data_obj["wv"].toInt();
|
||||
result_t r = webview_handler->rktTraySetMenu(tray, nullptr);
|
||||
result_queue->enqueue(r);
|
||||
}
|
||||
break;
|
||||
case CMD_TRAY_SET_MENU: {
|
||||
int tray = data_obj["wv"].toInt();
|
||||
QString menu_json = data_obj["menu_json"].toString();
|
||||
|
||||
result_t r = webview_handler->rktTraySetMenu(tray,
|
||||
menu_json.toUtf8().constData());
|
||||
result_queue->enqueue(r);
|
||||
}
|
||||
break;
|
||||
case CMD_CHOOSE_DIR: {
|
||||
int wv = data_obj["wv"].toInt();
|
||||
QString title = data_obj["title"].toString();
|
||||
@@ -407,7 +468,7 @@ void Handler::run()
|
||||
|
||||
void Alive::run()
|
||||
{
|
||||
int wait_ms = 10 * 1000;
|
||||
int wait_ms = WAIT_TIME;
|
||||
int ping_no;
|
||||
std::string data;
|
||||
bool go_on = true;
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 60 KiB |
@@ -29,6 +29,13 @@
|
||||
#define CMD_SET_LOGLEVEL 26 // arguments: ll: int
|
||||
#define CMD_INFO 27 // arguments: none
|
||||
#define CMD_SET_ICON 28 // arguments: wv: int, icon:string (absolute filename to icon in png/jpg/svg)
|
||||
#define CMD_CREATE_TRAY 29 // arguments: icon: string (path to icon file), tooltip: string -> tray: int
|
||||
#define CMD_TRAY_SET_ICON 30 // arguments: tray: int, icon: string -> result_t: int
|
||||
#define CMD_TRAY_SET_TOOLTIP 31 // arguments: tray: int, tooltip: string -> result_t: int
|
||||
#define CMD_TRAY_SHOW_MESSAGE 32 // arguments: tray: int, title: string, message: string -> result_t: int
|
||||
#define CMD_TRAY_SET_MENU 33 // arguments: tray: int, menu_json: string -> result_t: int
|
||||
#define CMD_TRAY_CLEAR_MENU 34 // arguments: tray: int
|
||||
|
||||
|
||||
#define CMD_NOOP 33621
|
||||
#define RESULT_QUIT 36379
|
||||
|
||||
+124
-28
@@ -38,8 +38,6 @@
|
||||
#define sleep_ms(ms) Sleep(static_cast<DWORD>(ms))
|
||||
#endif
|
||||
|
||||
//#define DEBUG
|
||||
|
||||
#ifdef __linux
|
||||
static int sleep_ms(long msec)
|
||||
{
|
||||
@@ -232,7 +230,12 @@ bool runRktWebview(Handle_t *handler)
|
||||
#define WAIT_ON_EVENT_MS (2 * 1000)
|
||||
#define ALIVE_MESSAGE_INTERVAL_S 5 // Should be smaller than 10 seconds
|
||||
#define MAX_WAIT_RESULT (2 * 1000) // Maximum wait in milliseconds for a result per time
|
||||
|
||||
#ifdef DEBUG_RKT_WEBVIEW
|
||||
#define MAX_ALIVE_ACK_TIME (300 * 1000)
|
||||
#else
|
||||
#define MAX_ALIVE_ACK_TIME (10 * 1000)
|
||||
#endif
|
||||
|
||||
void rkt_evt_guard(void)
|
||||
{
|
||||
@@ -248,10 +251,9 @@ void rkt_evt_guard(void)
|
||||
handler->evt_queue->enqueue(wv, data);
|
||||
handler->evt_cb_mutex.lock();
|
||||
if (handler->evt_cb != nullptr) { // evt_cb could be cleared to null
|
||||
INFO2("Calling evt_cb with %d, %s\n", wv, data.c_str());
|
||||
|
||||
//INFO2("Calling evt_cb with %d, %s\n", wv, data.c_str());
|
||||
handler->evt_cb(1);
|
||||
INFO0("done\n");
|
||||
//INFO0("done\n");
|
||||
} else {
|
||||
INFO0("evt_cb = null\n");
|
||||
}
|
||||
@@ -397,7 +399,7 @@ void rkt_webview_init(const char *from)
|
||||
INFO1("rkt_webview_init called from %s\n", from);
|
||||
|
||||
char buf[1024];
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_RKT_WEBVIEW
|
||||
sprintf(buf, "rktwebview-dbg");
|
||||
#else
|
||||
#ifdef _WIN32
|
||||
@@ -427,7 +429,7 @@ void rkt_webview_init(const char *from)
|
||||
handler->alive_ack_queue = new ShmQueue(handler->shm, ALIVE_ACK_SLOT, true);
|
||||
|
||||
// Start rktwebview_prg application with the right information
|
||||
#ifndef DEBUG
|
||||
#ifndef DEBUG_RKT_WEBVIEW
|
||||
handler->rkt_webview_prg_started = runRktWebview(handler);
|
||||
if (!handler->rkt_webview_prg_started) { handler->valid = false; }
|
||||
#endif
|
||||
@@ -552,28 +554,70 @@ void rkt_webview_close(rktwebview_t wv)
|
||||
handler->command_queue->enqueue(CMD_CLOSE_WV, j.dump());
|
||||
}
|
||||
|
||||
#define CMDRES4(cmd, wv, key, val, key2, val2, key3, val3, key4, val4) \
|
||||
RKT_WEBVIEW_INIT; \
|
||||
FAIL_HANDLE \
|
||||
JSON j; \
|
||||
j["wv"] = wv; \
|
||||
j[key] = val; \
|
||||
j[key2] = val2; \
|
||||
j[key3] = val3; \
|
||||
j[key4] = val4; \
|
||||
handler->command_queue->enqueue(cmd, j.dump()); \
|
||||
int result; \
|
||||
std::string json_result; \
|
||||
while (!handler->command_result_queue->dequeue(result, json_result, MAX_WAIT_RESULT)) { \
|
||||
if (handler->alive_error) { \
|
||||
return result_t::failed; \
|
||||
} \
|
||||
} \
|
||||
result_t r = static_cast<result_t>(result); \
|
||||
static inline result_t DO_CMDRES(int cmd, rktwebview_t wv, const JSON &j)
|
||||
{
|
||||
RKT_WEBVIEW_INIT;
|
||||
FAIL_HANDLE
|
||||
std::string json_str = j.dump();
|
||||
handler->command_queue->enqueue(cmd, json_str);
|
||||
int result;
|
||||
std::string json_result;
|
||||
while (!handler->command_result_queue->dequeue(result, json_result, MAX_WAIT_RESULT)) {
|
||||
if (handler->alive_error) {
|
||||
return result_t::failed;
|
||||
}
|
||||
}
|
||||
result_t r = static_cast<result_t>(result);
|
||||
return r;
|
||||
}
|
||||
|
||||
static inline result_t CMDRES4(int cmd, rktwebview_t wv,
|
||||
const char *key, const char *val,
|
||||
const char *key2, const char *val2,
|
||||
const char *key3, const char *val3,
|
||||
const char *key4, const char *val4)
|
||||
{
|
||||
JSON j;
|
||||
j["wv"] = wv;
|
||||
j[key] = val;
|
||||
j[key2] = val2;
|
||||
j[key3] = val3;
|
||||
j[key4] = val4;
|
||||
return DO_CMDRES(cmd, wv, j);
|
||||
}
|
||||
|
||||
static inline result_t CMDRES4(int cmd, rktwebview_t wv,
|
||||
const char *key, int val,
|
||||
const char *key2, int val2,
|
||||
const char *key3, const char *val3,
|
||||
const char *key4, const char *val4)
|
||||
{
|
||||
JSON j;
|
||||
j["wv"] = wv;
|
||||
j[key] = val;
|
||||
j[key2] = val2;
|
||||
j[key3] = val3;
|
||||
j[key4] = val4;
|
||||
return DO_CMDRES(cmd, wv, j);
|
||||
}
|
||||
|
||||
static inline result_t CMDRES4(int cmd, rktwebview_t wv,
|
||||
const char *key, const char *val,
|
||||
const char *key2, const char *val2,
|
||||
const char *key3, const char *val3,
|
||||
const char *key4, int val4)
|
||||
{
|
||||
JSON j;
|
||||
j["wv"] = wv;
|
||||
j[key] = val;
|
||||
j[key2] = val2;
|
||||
j[key3] = val3;
|
||||
j[key4] = val4;
|
||||
return DO_CMDRES(cmd, wv, j);
|
||||
}
|
||||
|
||||
#define CMDRES3(cmd, wv, key, val, key2, val2, key3, val3) \
|
||||
CMDRES4(cmd, wv, key, val, key2, val2, key3, val3, "nil3", "none")
|
||||
return CMDRES4(cmd, wv, key, val, key2, val2, key3, val3, "nil3", "none");
|
||||
|
||||
#define CMDRES2(cmd, wv, key, val, key2, val2) \
|
||||
CMDRES3(cmd, wv, key, val, key2, val2, "nil2", "none")
|
||||
@@ -586,7 +630,7 @@ void rkt_webview_close(rktwebview_t wv)
|
||||
|
||||
result_t rkt_webview_set_url(rktwebview_t wv, const char *url)
|
||||
{
|
||||
CMDRES(CMD_SET_URL, wv, "url", url)
|
||||
CMDRES(CMD_SET_URL, wv, "url", url);
|
||||
}
|
||||
|
||||
result_t rkt_webview_set_html(rktwebview_t wv, const char *html)
|
||||
@@ -765,7 +809,7 @@ rkt_data_t *rkt_webview_version()
|
||||
|
||||
result_t rkt_webview_message_box(rktwebview_t w, const char *title, const char *message, const char *submessage, rkt_messagetype_t type)
|
||||
{
|
||||
CMDRES4(CMD_MSG_BOX, w, "title", title, "message", message, "submessage", submessage, "type", static_cast<int>(type))
|
||||
return CMDRES4(CMD_MSG_BOX, w, "title", title, "message", message, "submessage", submessage, "type", static_cast<int>(type));
|
||||
}
|
||||
|
||||
int rkt_webview_events_waiting()
|
||||
@@ -877,3 +921,55 @@ void rkt_webview_exit_done(int done)
|
||||
ERROR0("rkt_webview_exit_done called with 'false', i.e. this library did not have a cleanup call\n");
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// Tray specific functions
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
rktwebview_t rkt_webview_tray_create(const char *icon_file,
|
||||
const char *tooltip)
|
||||
{
|
||||
RKT_WEBVIEW_INIT;
|
||||
FAIL_WV
|
||||
|
||||
JSON j;
|
||||
j["icon"] = icon_file;
|
||||
j["tooltip"] = tooltip;
|
||||
|
||||
handler->command_queue->enqueue(CMD_CREATE_TRAY, j.dump());
|
||||
|
||||
int result;
|
||||
std::string json_result;
|
||||
while (!handler->command_result_queue->dequeue(result, json_result, MAX_WAIT_RESULT)) {
|
||||
if (handler->alive_error) {
|
||||
return result_t::failed;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
result_t rkt_webview_tray_set_icon(rktwebview_t tray, const char *icon_file)
|
||||
{
|
||||
CMDRES(CMD_TRAY_SET_ICON, tray, "icon", icon_file)
|
||||
}
|
||||
|
||||
result_t rkt_webview_tray_set_tooltip(rktwebview_t tray, const char *tooltip)
|
||||
{
|
||||
CMDRES(CMD_TRAY_SET_TOOLTIP, tray, "tooltip", tooltip)
|
||||
}
|
||||
|
||||
result_t rkt_webview_tray_show_message(rktwebview_t tray, const char *title, const char *message)
|
||||
{
|
||||
CMDRES2(CMD_TRAY_SHOW_MESSAGE, tray, "title", title, "message", message)
|
||||
}
|
||||
|
||||
result_t rkt_webview_tray_set_menu(rktwebview_t tray, const char *menu_json)
|
||||
{
|
||||
if (menu_json == nullptr) {
|
||||
CMDRES0(CMD_TRAY_CLEAR_MENU, tray)
|
||||
} else {
|
||||
CMDRES(CMD_TRAY_SET_MENU, tray, "menu_json", menu_json)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -58,6 +58,13 @@ RKTWEBVIEW_EXPORT result_t rkt_webview_file_save(rktwebview_t w, const char *tit
|
||||
|
||||
RKTWEBVIEW_EXPORT result_t rkt_webview_message_box(rktwebview_t w, const char *title, const char *message, const char *submessage, rkt_messagetype_t type);
|
||||
|
||||
// Tray Icon functions (note, also hide/show/close can be used).
|
||||
RKTWEBVIEW_EXPORT rktwebview_t rkt_webview_tray_create(const char *icon_file, const char *tooltip);
|
||||
RKTWEBVIEW_EXPORT result_t rkt_webview_tray_set_icon(rktwebview_t tray, const char *icon_file);
|
||||
RKTWEBVIEW_EXPORT result_t rkt_webview_tray_set_tooltip(rktwebview_t tray, const char *tooltip);
|
||||
RKTWEBVIEW_EXPORT result_t rkt_webview_tray_show_message(rktwebview_t tray, const char *title, const char *message);
|
||||
RKTWEBVIEW_EXPORT result_t rkt_webview_tray_set_menu(rktwebview_t tray, const char *menu_json);
|
||||
|
||||
}
|
||||
|
||||
#endif // RKTWEBVIEW_H
|
||||
|
||||
+287
-1
@@ -18,15 +18,36 @@
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
#include <QAbstractButton>
|
||||
#include <QSystemTrayIcon>
|
||||
#include <QMenu>
|
||||
#include <QAction>
|
||||
#include "build_menu_from_json.h"
|
||||
|
||||
static inline char *copyString(const char *s)
|
||||
{
|
||||
int l = strlen(s);
|
||||
int l = static_cast<int>(strlen(s));
|
||||
char *cpy = static_cast<char *>(malloc(l + 1));
|
||||
memcpy(cpy, s, l + 1);
|
||||
return cpy;
|
||||
}
|
||||
|
||||
static QString activationReasonToString(QSystemTrayIcon::ActivationReason r)
|
||||
{
|
||||
switch (r) {
|
||||
case QSystemTrayIcon::Context:
|
||||
return "context-menu"; // rechtsklik / menu openen
|
||||
case QSystemTrayIcon::DoubleClick:
|
||||
return "double-click";
|
||||
case QSystemTrayIcon::Trigger:
|
||||
return "click"; // meestal linkerklik
|
||||
case QSystemTrayIcon::MiddleClick:
|
||||
return "middle-click";
|
||||
case QSystemTrayIcon::Unknown:
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
void Rktwebview_qt::processCommand(Command *cmd)
|
||||
{
|
||||
switch(cmd->cmd) {
|
||||
@@ -168,6 +189,20 @@ void Rktwebview_qt::processCommand(Command *cmd)
|
||||
}
|
||||
_view_js_callbacks.remove(wv);
|
||||
delete w;
|
||||
} else if (_trays.contains(wv)) {
|
||||
QSystemTrayIcon *tray = _trays[wv];
|
||||
_trays.remove(wv);
|
||||
|
||||
if (_tray_menus.contains(wv)) {
|
||||
QMenu *menu = _tray_menus[wv];
|
||||
_tray_menus.remove(wv);
|
||||
delete menu;
|
||||
}
|
||||
|
||||
tray->hide();
|
||||
_view_js_callbacks.remove(wv);
|
||||
delete tray;
|
||||
cmd->result = true;
|
||||
} else {
|
||||
cmd->result = false;
|
||||
}
|
||||
@@ -306,6 +341,18 @@ void Rktwebview_qt::processCommand(Command *cmd)
|
||||
w->activateWindow();
|
||||
}
|
||||
cmd->result = true;
|
||||
} else if (_trays.contains(wv)) {
|
||||
QSystemTrayIcon *tray = _trays[wv];
|
||||
|
||||
if (cmd->cmd == COMMAND_SHOW_WIN) {
|
||||
tray->show();
|
||||
cmd->result = true;
|
||||
} else if (cmd->cmd == COMMAND_HIDE_WIN) {
|
||||
tray->hide();
|
||||
cmd->result = true;
|
||||
} else {
|
||||
cmd->result = false;
|
||||
}
|
||||
} else {
|
||||
cmd->result = false;
|
||||
}
|
||||
@@ -449,6 +496,118 @@ void Rktwebview_qt::processCommand(Command *cmd)
|
||||
}
|
||||
cmd->done = true;
|
||||
}
|
||||
case COMMAND_CREATE_TRAY: {
|
||||
QString icon_file = cmd->args[0].toString();
|
||||
QString tooltip = cmd->args[1].toString();
|
||||
|
||||
void *f = cmd->args[2].value<void *>();
|
||||
event_cb_t js_event_cb = reinterpret_cast <event_cb_t>(f);
|
||||
|
||||
int id = nextHandle();
|
||||
|
||||
QSystemTrayIcon *tray = new QSystemTrayIcon(this);
|
||||
tray->setIcon(QIcon(icon_file));
|
||||
tray->setToolTip(tooltip);
|
||||
tray->setProperty("tray-id", id);
|
||||
|
||||
connect(tray, &QSystemTrayIcon::activated, this, &Rktwebview_qt::handleTrayActivation);
|
||||
connect(tray, &QSystemTrayIcon::messageClicked, this, &Rktwebview_qt::handleTrayMessageClick);
|
||||
|
||||
_trays[id] = tray;
|
||||
_view_js_callbacks[id] = js_event_cb;
|
||||
|
||||
tray->show();
|
||||
|
||||
cmd->result = id;
|
||||
cmd->done = true;
|
||||
}
|
||||
break;
|
||||
case COMMAND_TRAY_SET_ICON: {
|
||||
int tray_id = cmd->args[0].toInt();
|
||||
QString icon_file = cmd->args[1].toString();
|
||||
|
||||
if (_trays.contains(tray_id)) {
|
||||
_trays[tray_id]->setIcon(QIcon(icon_file));
|
||||
cmd->result = true;
|
||||
} else {
|
||||
cmd->result = false;
|
||||
}
|
||||
|
||||
cmd->done = true;
|
||||
}
|
||||
break;
|
||||
case COMMAND_TRAY_SET_TOOLTIP: {
|
||||
int tray_id = cmd->args[0].toInt();
|
||||
QString tooltip = cmd->args[1].toString();
|
||||
|
||||
if (_trays.contains(tray_id)) {
|
||||
_trays[tray_id]->setToolTip(tooltip);
|
||||
cmd->result = true;
|
||||
} else {
|
||||
cmd->result = false;
|
||||
}
|
||||
|
||||
cmd->done = true;
|
||||
}
|
||||
break;
|
||||
case COMMAND_TRAY_SHOW_MESSAGE: {
|
||||
int tray_id = cmd->args[0].toInt();
|
||||
QString title = cmd->args[1].toString();
|
||||
QString message = cmd->args[2].toString();
|
||||
|
||||
if (_trays.contains(tray_id)) {
|
||||
_trays[tray_id]->showMessage(title, message);
|
||||
cmd->result = true;
|
||||
} else {
|
||||
cmd->result = false;
|
||||
}
|
||||
|
||||
cmd->done = true;
|
||||
}
|
||||
break;
|
||||
case COMMAND_TRAY_SET_MENU: {
|
||||
int tray_id = cmd->args[0].toInt();
|
||||
int has_menu = cmd->args[1].toInt();
|
||||
QString menu_json = cmd->args[2].toString();
|
||||
|
||||
if (!_trays.contains(tray_id)) {
|
||||
cmd->result = false;
|
||||
cmd->done = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (_tray_menus.contains(tray_id)) {
|
||||
QMenu *old = _tray_menus[tray_id];
|
||||
_tray_menus.remove(tray_id);
|
||||
delete old;
|
||||
}
|
||||
|
||||
QMenu *menu = (has_menu) ? buildMenuFromJson(this, menu_json, tray_id) : nullptr;
|
||||
_tray_menus[tray_id] = menu;
|
||||
|
||||
/*
|
||||
if (menu == nullptr) {
|
||||
if (!has_menu) {
|
||||
INFO1("null menu, setting null menu on tray %d\n", tray_id);
|
||||
_trays[tray_id]->setContextMenu(nullptr);
|
||||
INFO0("Done setting tray menu to null menu\n");
|
||||
WARN0("Note: on Linux, this will not clear the context menu\n");
|
||||
cmd->result = true;
|
||||
cmd->done = true;
|
||||
} else {
|
||||
ERROR2("menu json '%s' for tray %d is not oke\n", menu_json.toUtf8().constData(), tray_id);
|
||||
cmd->result = false;
|
||||
cmd->done = true;
|
||||
}
|
||||
} else {
|
||||
_tray_menus[tray_id] = menu;
|
||||
_trays[tray_id]->setContextMenu(menu);
|
||||
}
|
||||
*/
|
||||
|
||||
cmd->result = true;
|
||||
cmd->done = true;
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
cmd->result = false;
|
||||
@@ -458,6 +617,50 @@ void Rktwebview_qt::processCommand(Command *cmd)
|
||||
}
|
||||
}
|
||||
|
||||
void Rktwebview_qt::handleTrayActivation(QSystemTrayIcon::ActivationReason reason)
|
||||
{
|
||||
QObject *obj = sender();
|
||||
int tray_wv = obj->property("tray-id").toInt();
|
||||
|
||||
QSystemTrayIcon *icn = qobject_cast<QSystemTrayIcon *>(obj);
|
||||
|
||||
// If a context menu has been set, pop it up and leave.
|
||||
if (reason == QSystemTrayIcon::ActivationReason::Context) {
|
||||
QMenu *mnu = nullptr;
|
||||
if (_tray_menus.contains(tray_wv)) {
|
||||
mnu = _tray_menus[tray_wv];
|
||||
}
|
||||
if (mnu != nullptr) {
|
||||
mnu->popup(QCursor::pos());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
QString evt = "tray-activated";
|
||||
QString reason_str = activationReasonToString(reason);
|
||||
|
||||
//INFO3("triggering event: %s for tray %d with reason %s\n",
|
||||
// evt.toUtf8().constData(), tray_wv, reason_str.toUtf8().constData());
|
||||
|
||||
EventContainer e(evt);
|
||||
e["reason"] = reason_str;
|
||||
|
||||
this->triggerEvent(tray_wv, e);
|
||||
}
|
||||
|
||||
void Rktwebview_qt::handleTrayMessageClick()
|
||||
{
|
||||
QObject *obj = sender();
|
||||
|
||||
//INFO0("triggering message click\n");
|
||||
|
||||
int tray_wv = obj->property("tray-id").toInt();
|
||||
QString evt = "tray-message-clicked";
|
||||
|
||||
EventContainer e(evt);
|
||||
this->triggerEvent(tray_wv, e);
|
||||
}
|
||||
|
||||
void Rktwebview_qt::removeView(int id)
|
||||
{
|
||||
if (_views.contains(id)) {
|
||||
@@ -888,6 +1091,76 @@ result_t Rktwebview_qt::rktMessageBox(rktwebview_t w, const char *title, const c
|
||||
return r ? result_t::oke : result_t::failed;
|
||||
}
|
||||
|
||||
rktwebview_t Rktwebview_qt::rktTrayCreate(const char *icon_file, const char *tooltip, event_cb_t evt_cb)
|
||||
{
|
||||
Command c(COMMAND_CREATE_TRAY);
|
||||
c.args.push_back(icon_file);
|
||||
c.args.push_back(tooltip);
|
||||
|
||||
void *function = reinterpret_cast<void *>(evt_cb);
|
||||
QVariant f(QVariant::fromValue(function));
|
||||
c.args.push_back(f);
|
||||
|
||||
postCommand(&c);
|
||||
while(!c.done) { doEvents(); }
|
||||
|
||||
return c.result.toInt();
|
||||
}
|
||||
|
||||
result_t Rktwebview_qt::rktTraySetIcon(rktwebview_t tray, const char *icon_file)
|
||||
{
|
||||
Command c(COMMAND_TRAY_SET_ICON);
|
||||
c.args.push_back(tray);
|
||||
c.args.push_back(icon_file);
|
||||
|
||||
postCommand(&c);
|
||||
while(!c.done) { doEvents(); }
|
||||
|
||||
return c.result.toBool() ? result_t::oke : result_t::failed;
|
||||
}
|
||||
|
||||
result_t Rktwebview_qt::rktTraySetTooltip(rktwebview_t tray, const char *tooltip)
|
||||
{
|
||||
//INFO2("rktTraySetTooltip: %d %s\n", tray, tooltip);
|
||||
|
||||
Command c(COMMAND_TRAY_SET_TOOLTIP);
|
||||
c.args.push_back(tray);
|
||||
c.args.push_back(tooltip);
|
||||
|
||||
postCommand(&c);
|
||||
while(!c.done) { doEvents(); }
|
||||
|
||||
//INFO1("rktTraySetTooltip done: %s\n", tooltip);
|
||||
|
||||
return c.result.toBool() ? result_t::oke : result_t::failed;
|
||||
}
|
||||
|
||||
result_t Rktwebview_qt::rktTrayShowMessage(rktwebview_t tray, const char *title, const char *message)
|
||||
{
|
||||
Command c(COMMAND_TRAY_SHOW_MESSAGE);
|
||||
c.args.push_back(tray);
|
||||
c.args.push_back(title);
|
||||
c.args.push_back(message);
|
||||
|
||||
postCommand(&c);
|
||||
while(!c.done) { doEvents(); }
|
||||
|
||||
return c.result.toBool() ? result_t::oke : result_t::failed;
|
||||
}
|
||||
|
||||
result_t Rktwebview_qt::rktTraySetMenu(rktwebview_t tray, const char *menu_json)
|
||||
{
|
||||
Command c(COMMAND_TRAY_SET_MENU);
|
||||
c.args.push_back(tray);
|
||||
c.args.push_back(menu_json != nullptr);
|
||||
c.args.push_back((menu_json == nullptr) ? "" : menu_json);
|
||||
|
||||
postCommand(&c);
|
||||
while(!c.done) { doEvents(); }
|
||||
|
||||
return c.result.toBool() ? result_t::oke : result_t::failed;
|
||||
}
|
||||
|
||||
result_t Rktwebview_qt::doWindow(rktwebview_t w, int cmd, result_t on_error)
|
||||
{
|
||||
Command c(cmd);
|
||||
@@ -1085,5 +1358,18 @@ Rktwebview_qt::~Rktwebview_qt()
|
||||
delete p;
|
||||
}
|
||||
|
||||
QList<int> tray_keys = _trays.keys();
|
||||
for(i = 0, N = tray_keys.size(); i < N; i++) {
|
||||
QSystemTrayIcon *tray = _trays[tray_keys[i]];
|
||||
tray->hide();
|
||||
delete tray;
|
||||
}
|
||||
|
||||
QList<int> menu_keys = _tray_menus.keys();
|
||||
for(i = 0, N = menu_keys.size(); i < N; i++) {
|
||||
QMenu *menu = _tray_menus[menu_keys[i]];
|
||||
delete menu;
|
||||
}
|
||||
|
||||
delete _app;
|
||||
}
|
||||
|
||||
@@ -13,12 +13,15 @@
|
||||
#include <QTimer>
|
||||
#include <QEventLoop>
|
||||
#include <QFileDialog>
|
||||
#include <QSystemTrayIcon>
|
||||
|
||||
|
||||
class WebViewQt;
|
||||
class WebviewWindow;
|
||||
class Command;
|
||||
class CommandEvent;
|
||||
class QSystemTrayIcon;
|
||||
class QMenu;
|
||||
|
||||
class Rktwebview_qt : public QObject
|
||||
{
|
||||
@@ -30,6 +33,8 @@ private:
|
||||
int _context_counter;
|
||||
QHash<int, QWebEngineProfile *> _contexts;
|
||||
QHash<int, WebviewWindow *> _views;
|
||||
QHash<int, QSystemTrayIcon *> _trays;
|
||||
QHash<int, QMenu *> _tray_menus;
|
||||
QHash<int, event_cb_t> _view_js_callbacks;
|
||||
|
||||
QTimer _process_events;
|
||||
@@ -46,6 +51,8 @@ private:
|
||||
|
||||
private slots:
|
||||
void stopEventloop();
|
||||
void handleTrayActivation(QSystemTrayIcon::ActivationReason reason);
|
||||
void handleTrayMessageClick();
|
||||
|
||||
private:
|
||||
void postCommand(Command *cmd);
|
||||
@@ -114,6 +121,13 @@ public:
|
||||
|
||||
bool rktValid(rktwebview_t wv);
|
||||
|
||||
public: // Tray
|
||||
rktwebview_t rktTrayCreate(const char *icon_file, const char *tooltip, event_cb_t evt_cb);
|
||||
result_t rktTraySetIcon(rktwebview_t tray, const char *icon_file);
|
||||
result_t rktTraySetTooltip(rktwebview_t tray, const char *tooltip);
|
||||
result_t rktTrayShowMessage(rktwebview_t tray, const char *title, const char *message);
|
||||
result_t rktTraySetMenu(rktwebview_t tray, const char *menu_json);
|
||||
|
||||
public:
|
||||
// Events for the backend
|
||||
void pageLoaded(rktwebview_t w, bool ok);
|
||||
|
||||
+20
-3
@@ -20,7 +20,7 @@ int main(int argc, char *argv[])
|
||||
std::string loc = basedir(me);
|
||||
#ifdef _WIN32
|
||||
std::string prg = loc + "\\rktwebview_prg.exe";
|
||||
SetDllDirectoryA("C:\\Qt\\6.10.2\\msvc2022_64\\bin");
|
||||
SetDllDirectoryA("C:\\Qt\\6.11.1\\msvc2022_64\\bin");
|
||||
#else
|
||||
std::string prg = loc + "/rktwebview_prg";
|
||||
#endif
|
||||
@@ -35,9 +35,21 @@ int main(int argc, char *argv[])
|
||||
setenv("LD_LIBRARY_PATH", loc.c_str(), true);
|
||||
#endif
|
||||
|
||||
rkt_webview_init(__FUNCTION__);
|
||||
|
||||
int context = rkt_webview_new_context("", nullptr);
|
||||
rkt_webview_set_loglevel(rkt_webview_loglevel_t::log_debug);
|
||||
|
||||
const char *icon_file = "../../resource/rktplayer.png";
|
||||
FILE *f = fopen(icon_file, "rb");
|
||||
if (f == nullptr) {
|
||||
WARN1("Cannot find icon file %s\n", icon_file);
|
||||
} else {
|
||||
fclose(f);
|
||||
}
|
||||
int tray_wv = rkt_webview_tray_create(icon_file, "This is a test tray icon");
|
||||
INFO1("tray_wv = %d\n", tray_wv);
|
||||
|
||||
rkt_webview_register_evt_callback(evt_cb);
|
||||
|
||||
int wv = rkt_webview_create(context, 0);
|
||||
@@ -49,7 +61,8 @@ int main(int argc, char *argv[])
|
||||
|
||||
rkt_webview_move(wv, 100, 200);
|
||||
rkt_webview_resize(wv, 800, 600);
|
||||
rkt_webview_set_url(wv, "https://wikipedia.org");
|
||||
//rkt_webview_set_url(wv, "https://wikipedia.org");
|
||||
rkt_webview_set_html(wv, "<html><head><title>Hi!</title></head><body><h1>Oke test</h1><select id=\"sel-lang\"><option value=\"nl\" selected>Nederlands</option><option value=\"en\">English</option></select><p>Ja</p></body></html>");
|
||||
|
||||
d = rkt_webview_info();
|
||||
fprintf(stderr, "%s\n", d->data.metrics.log_file);
|
||||
@@ -60,7 +73,9 @@ int main(int argc, char *argv[])
|
||||
rkt_webview_free_data(d);
|
||||
}
|
||||
#ifdef _WIN32
|
||||
Sleep(30000);
|
||||
Sleep(15000);
|
||||
rkt_webview_tray_show_message(tray_wv, "This is a title", "This is a message to display<br><b>Hopefully</b> it does display.");
|
||||
Sleep(15000);
|
||||
#else
|
||||
sleep(30
|
||||
);
|
||||
@@ -73,5 +88,7 @@ int main(int argc, char *argv[])
|
||||
d = rkt_webview_info();
|
||||
rkt_webview_free_data(d);
|
||||
|
||||
rkt_webview_close(tray_wv);
|
||||
|
||||
rkt_webview_cleanup();
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ static timer *_timer = nullptr;
|
||||
|
||||
|
||||
|
||||
extern "C" {
|
||||
int logLevel()
|
||||
{
|
||||
return _log_level;
|
||||
@@ -49,3 +50,4 @@ void logElapsed()
|
||||
.count();
|
||||
fprintf(stderr, "%8.3lf: ", milliseconds/ 1000.0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
#ifndef UTILS_H
|
||||
#define UTILS_H
|
||||
|
||||
//#define DEBUG_RKT_WEBVIEW
|
||||
|
||||
#include <string>
|
||||
#include "rktwebview_global.h"
|
||||
#include "rktwebview_types.h"
|
||||
|
||||
inline std::string basedir(const std::string &path)
|
||||
@@ -26,11 +29,17 @@ inline std::string basedir(const std::string &path)
|
||||
}
|
||||
return r;
|
||||
}
|
||||
extern "C" {
|
||||
#ifdef RKTWEBVIEW_PRG_EXE
|
||||
#undef RKTWEBVIEW_EXPORT
|
||||
#define RKTWEBVIEW_EXPORT
|
||||
#endif
|
||||
|
||||
int logLevel();
|
||||
void setLogLevel(int l);
|
||||
void logElapsed();
|
||||
const char *logIndicator(int l);
|
||||
RKTWEBVIEW_EXPORT int logLevel();
|
||||
RKTWEBVIEW_EXPORT void setLogLevel(int l);
|
||||
RKTWEBVIEW_EXPORT void logElapsed();
|
||||
RKTWEBVIEW_EXPORT const char *logIndicator(int l);
|
||||
}
|
||||
|
||||
#define LOG_ERROR 1
|
||||
#define LOG_WARNING 2
|
||||
@@ -41,6 +50,7 @@ const char *logIndicator(int l);
|
||||
#define MKL0(level, msg) MKLOGSTMT(level, fprintf(stderr, msg))
|
||||
#define MKL1(level, msg, a) MKLOGSTMT(level, fprintf(stderr, msg, a))
|
||||
#define MKL2(level, msg, a, b) MKLOGSTMT(level, fprintf(stderr, msg, a, b))
|
||||
#define MKL3(level, msg, a, b, c) MKLOGSTMT(level, fprintf(stderr, msg, a, b, c))
|
||||
|
||||
#define ERROR0(msg) MKL0(LOG_ERROR, msg)
|
||||
#define WARN0(msg) MKL0(LOG_WARNING, msg)
|
||||
@@ -57,6 +67,8 @@ const char *logIndicator(int l);
|
||||
#define INFO2(msg, a, b) MKL2(LOG_INFO, msg, a, b)
|
||||
#define DEBUG2(msg, a, b) MKL2(LOG_DEBUG, msg, a, b)
|
||||
|
||||
#define INFO3(msg, a, b, c) MKL3(LOG_INFO, msg, a, b, c)
|
||||
|
||||
inline void do_free_data(rkt_data_t *d)
|
||||
{
|
||||
if (d == nullptr) { return; }
|
||||
|
||||
Reference in New Issue
Block a user