8
res/doc
8
res/doc
@@ -62,10 +62,18 @@
|
|||||||
# cmd_output - the timeout in milliseconds (0 < t < 10000), a colon, then the command line to pass to /bin/sh -c (started in /)
|
# cmd_output - the timeout in milliseconds (0 < t < 10000), a colon, then the command line to pass to /bin/sh -c (started in /)
|
||||||
#
|
#
|
||||||
# chain:<action>:<arg>
|
# chain:<action>:<arg>
|
||||||
|
# chain_failure:<action>:<arg>
|
||||||
|
# chain_always:<action>:<arg>
|
||||||
# Adds an action to the chain that began with the preceding menu_item.
|
# Adds an action to the chain that began with the preceding menu_item.
|
||||||
# Actions are performed in the order they are written.
|
# Actions are performed in the order they are written.
|
||||||
# Each chain entry MUST follow the menu_item it is attached to. Another
|
# Each chain entry MUST follow the menu_item it is attached to. Another
|
||||||
# menu_item marks the start of the next chain.
|
# menu_item marks the start of the next chain.
|
||||||
|
# By default, each action only executes if the previous one was successful.
|
||||||
|
# If chain_failure is used, the action is only executed if the last one
|
||||||
|
# failed. If chain_always is used, the action is executed no matter what.
|
||||||
|
# Any error message is only displayed if the action is the last one which
|
||||||
|
# was executed in the chain (not necessarily the last one in the config
|
||||||
|
# file).
|
||||||
#
|
#
|
||||||
# For example, you might have a configuration file in KOBOeReader/.adds/nm/mystuff like:
|
# For example, you might have a configuration file in KOBOeReader/.adds/nm/mystuff like:
|
||||||
#
|
#
|
||||||
|
|||||||
23
src/config.c
23
src/config.c
@@ -108,8 +108,8 @@ nm_config_t *nm_config_parse(char **err_out) {
|
|||||||
// field 1: type
|
// field 1: type
|
||||||
char *c_typ = strtrim(strsep(&cur, ":"));
|
char *c_typ = strtrim(strsep(&cur, ":"));
|
||||||
if (!strcmp(c_typ, "menu_item")) {
|
if (!strcmp(c_typ, "menu_item")) {
|
||||||
if (it) nm_config_push_menu_item(&cfg, it);
|
|
||||||
// type: menu_item
|
// type: menu_item
|
||||||
|
if (it) nm_config_push_menu_item(&cfg, it);
|
||||||
it = calloc(1, sizeof(nm_menu_item_t));
|
it = calloc(1, sizeof(nm_menu_item_t));
|
||||||
cur_act = NULL;
|
cur_act = NULL;
|
||||||
// type: menu_item - field 2: location
|
// type: menu_item - field 2: location
|
||||||
@@ -124,8 +124,10 @@ nm_config_t *nm_config_parse(char **err_out) {
|
|||||||
if (!c_lbl) RETERR("file %s: line %d: field 3: expected label, got end of line", fn, line_n);
|
if (!c_lbl) RETERR("file %s: line %d: field 3: expected label, got end of line", fn, line_n);
|
||||||
else it->lbl = strdup(c_lbl);
|
else it->lbl = strdup(c_lbl);
|
||||||
|
|
||||||
nm_menu_action_t *action = calloc(1, sizeof(nm_menu_action_t));
|
|
||||||
// type: menu_item - field 4: action
|
// type: menu_item - field 4: action
|
||||||
|
nm_menu_action_t *action = calloc(1, sizeof(nm_menu_action_t));
|
||||||
|
action->on_failure = true;
|
||||||
|
action->on_success = true;
|
||||||
char *c_act = strtrim(strsep(&cur, ":"));
|
char *c_act = strtrim(strsep(&cur, ":"));
|
||||||
if (!c_act) RETERR("file %s: line %d: field 4: expected action, got end of line", fn, line_n);
|
if (!c_act) RETERR("file %s: line %d: field 4: expected action, got end of line", fn, line_n);
|
||||||
#define X(name) else if (!strcmp(c_act, #name)) action->act = NM_ACTION(name);
|
#define X(name) else if (!strcmp(c_act, #name)) action->act = NM_ACTION(name);
|
||||||
@@ -139,10 +141,22 @@ nm_config_t *nm_config_parse(char **err_out) {
|
|||||||
else action->arg = strdup(c_arg);
|
else action->arg = strdup(c_arg);
|
||||||
nm_config_push_action(&cur_act, action);
|
nm_config_push_action(&cur_act, action);
|
||||||
it->action = cur_act;
|
it->action = cur_act;
|
||||||
} else if (!strcmp(c_typ, "chain")) {
|
} else if (!strncmp(c_typ, "chain", 5)) {
|
||||||
|
// type: chain
|
||||||
if (!it) RETERR("file %s: line %d: unexpected chain, no menu_item to link to", fn, line_n);
|
if (!it) RETERR("file %s: line %d: unexpected chain, no menu_item to link to", fn, line_n);
|
||||||
nm_menu_action_t *action = calloc(1, sizeof(nm_menu_action_t));
|
nm_menu_action_t *action = calloc(1, sizeof(nm_menu_action_t));
|
||||||
|
|
||||||
|
if (!strcmp(c_typ, "chain")) {
|
||||||
|
action->on_failure = false;
|
||||||
|
action->on_success = true;
|
||||||
|
} else if (!strcmp(c_typ, "chain_always")) {
|
||||||
|
action->on_failure = true;
|
||||||
|
action->on_success = true;
|
||||||
|
} else if (!strcmp(c_typ, "chain_failure")) {
|
||||||
|
action->on_failure = true;
|
||||||
|
action->on_success = false;
|
||||||
|
} else RETERR("file %s: line %d: field 1: unknown type '%s'", fn, line_n, c_typ);
|
||||||
|
|
||||||
// type: chain - field 2: action
|
// type: chain - field 2: action
|
||||||
char *c_act = strtrim(strsep(&cur, ":"));
|
char *c_act = strtrim(strsep(&cur, ":"));
|
||||||
if (!c_act) RETERR("file %s: line %d: field 2: expected action, got end of line", fn, line_n);
|
if (!c_act) RETERR("file %s: line %d: field 2: expected action, got end of line", fn, line_n);
|
||||||
@@ -187,8 +201,9 @@ nm_config_t *nm_config_parse(char **err_out) {
|
|||||||
size_t mm = 0, rm = 0;
|
size_t mm = 0, rm = 0;
|
||||||
for (nm_config_t *cur = cfg; cur; cur = cur->next) {
|
for (nm_config_t *cur = cfg; cur; cur = cur->next) {
|
||||||
if (cur->type == NM_CONFIG_TYPE_MENU_ITEM) {
|
if (cur->type == NM_CONFIG_TYPE_MENU_ITEM) {
|
||||||
|
NM_LOG("cfg(NM_CONFIG_TYPE_MENU_ITEM) : %d:%s", cur->value.menu_item->loc, cur->value.menu_item->lbl);
|
||||||
for (nm_menu_action_t *cur_act = cur->value.menu_item->action; cur_act; cur_act = cur_act->next)
|
for (nm_menu_action_t *cur_act = cur->value.menu_item->action; cur_act; cur_act = cur_act->next)
|
||||||
NM_LOG("cfg(NM_CONFIG_TYPE_MENU_ITEM) : %d:%s:%p:%s", cur->value.menu_item->loc, cur->value.menu_item->lbl, cur_act->act, cur_act->arg);
|
NM_LOG("...cfg(NM_CONFIG_TYPE_MENU_ITEM) (%s%s%s) : %p:%s", cur_act->on_success ? "on_success" : "", (cur_act->on_success && cur_act->on_failure) ? ", " : "", cur_act->on_failure ? "on_failure" : "", cur_act->act, cur_act->arg);
|
||||||
switch (cur->value.menu_item->loc) {
|
switch (cur->value.menu_item->loc) {
|
||||||
case NM_MENU_LOCATION_MAIN_MENU: mm++; break;
|
case NM_MENU_LOCATION_MAIN_MENU: mm++; break;
|
||||||
case NM_MENU_LOCATION_READER_MENU: rm++; break;
|
case NM_MENU_LOCATION_READER_MENU: rm++; break;
|
||||||
|
|||||||
66
src/menu.cc
66
src/menu.cc
@@ -143,40 +143,50 @@ extern "C" MenuTextItem* _nm_menu_hook(void* _this, QMenu* menu, QString const&
|
|||||||
|
|
||||||
// note: we're capturing by value, i.e. the pointer to the global variable, rather then the stack variable, so this is safe
|
// note: we're capturing by value, i.e. the pointer to the global variable, rather then the stack variable, so this is safe
|
||||||
QObject::connect(action, &QAction::triggered, std::function<void(bool)>([it](bool){
|
QObject::connect(action, &QAction::triggered, std::function<void(bool)>([it](bool){
|
||||||
NM_LOG("Item '%s' pressed...", it->lbl);
|
NM_LOG("item '%s' pressed...", it->lbl);
|
||||||
char *err;
|
char *err = NULL;
|
||||||
|
bool success = true;
|
||||||
for (nm_menu_action_t *cur = it->action; cur; cur = cur->next) {
|
for (nm_menu_action_t *cur = it->action; cur; cur = cur->next) {
|
||||||
NM_LOG("running action %p with argument %s : ", cur->act, cur->arg);
|
NM_LOG("action %p with argument %s : ", cur->act, cur->arg);
|
||||||
|
NM_LOG("...success=%d ; on_success=%d on_failure=%d", success, cur->on_success, cur->on_failure);
|
||||||
|
if (!((success && cur->on_success) || (!success && cur->on_failure))) {
|
||||||
|
NM_LOG("...skipping action due to condition flags");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
free(err);
|
||||||
nm_action_result_t *res = cur->act(cur->arg, &err);
|
nm_action_result_t *res = cur->act(cur->arg, &err);
|
||||||
if (err) {
|
if (!(success = err == NULL)) {
|
||||||
NM_LOG("Got error: '%s', displaying...", err);
|
NM_LOG("...error: '%s'", err);
|
||||||
ConfirmationDialogFactory_showOKDialog(QString::fromUtf8(it->lbl), QString::fromUtf8(err));
|
continue;
|
||||||
free(err);
|
} else if (!res) {
|
||||||
return;
|
NM_LOG("...warning: you should have returned a result with type silent, not null, upon success");
|
||||||
} else if (res) {
|
continue;
|
||||||
NM_LOG("Got result: type=%d msg='%s', handling...", res->type, res->msg);
|
}
|
||||||
MainWindowController *mwc;
|
NM_LOG("...result: type=%d msg='%s', handling...", res->type, res->msg);
|
||||||
switch (res->type) {
|
MainWindowController *mwc;
|
||||||
case NM_ACTION_RESULT_TYPE_SILENT:
|
switch (res->type) {
|
||||||
break;
|
case NM_ACTION_RESULT_TYPE_SILENT:
|
||||||
case NM_ACTION_RESULT_TYPE_MSG:
|
break;
|
||||||
ConfirmationDialogFactory_showOKDialog(QString::fromUtf8(it->lbl), QLatin1String(res->msg));
|
case NM_ACTION_RESULT_TYPE_MSG:
|
||||||
break;
|
ConfirmationDialogFactory_showOKDialog(QString::fromUtf8(it->lbl), QLatin1String(res->msg));
|
||||||
case NM_ACTION_RESULT_TYPE_TOAST:
|
break;
|
||||||
mwc = MainWindowController_sharedInstance();
|
case NM_ACTION_RESULT_TYPE_TOAST:
|
||||||
if (!mwc) {
|
mwc = MainWindowController_sharedInstance();
|
||||||
NM_LOG("toast: could not get shared main window controller pointer");
|
if (!mwc) {
|
||||||
break;
|
NM_LOG("toast: could not get shared main window controller pointer");
|
||||||
}
|
|
||||||
MainWindowController_toast(mwc, QLatin1String(res->msg), QStringLiteral(""), 1500);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
nm_action_result_free(res);
|
MainWindowController_toast(mwc, QLatin1String(res->msg), QStringLiteral(""), 1500);
|
||||||
} else {
|
break;
|
||||||
NM_LOG("warning: you should have returned a result with type silent, not null, upon success");
|
|
||||||
}
|
}
|
||||||
|
nm_action_result_free(res);
|
||||||
}
|
}
|
||||||
NM_LOG("Success!");
|
if (err) {
|
||||||
|
NM_LOG("last action returned error %s", err);
|
||||||
|
ConfirmationDialogFactory_showOKDialog(QString::fromUtf8(it->lbl), QString::fromUtf8(err));
|
||||||
|
free(err);
|
||||||
|
}
|
||||||
|
NM_LOG("done");
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
#include "action.h"
|
#include "action.h"
|
||||||
@@ -15,6 +16,8 @@ typedef enum {
|
|||||||
|
|
||||||
typedef struct nm_menu_action_t {
|
typedef struct nm_menu_action_t {
|
||||||
char *arg;
|
char *arg;
|
||||||
|
bool on_success;
|
||||||
|
bool on_failure;
|
||||||
nm_action_fn_t act; // can block, must return 0 on success, nonzero with out_err set to the malloc'd error message on error
|
nm_action_fn_t act; // can block, must return 0 on success, nonzero with out_err set to the malloc'd error message on error
|
||||||
struct nm_menu_action_t *next;
|
struct nm_menu_action_t *next;
|
||||||
} nm_menu_action_t;
|
} nm_menu_action_t;
|
||||||
|
|||||||
Reference in New Issue
Block a user