12
res/doc
12
res/doc
@@ -34,6 +34,10 @@
|
||||
# nickel_misc - other stuff which isn't significant enough for its own category
|
||||
# nickel_open - opens a view
|
||||
# nickel_wifi - controls wifi (note: it doesn't wait for it to connect or disconnect, neither does it check for success)
|
||||
# nickel_orientation - controls screen orientation
|
||||
# (devices without an orientation sensor need to use the kobopatch patch "Allow rotation on all devices" or set [DeveloperSettings] ForceAllowLandscape=true)
|
||||
# (devices with an orientation sensor don't need to do anything, but can set the config setting to make this work on all views)
|
||||
# (this will override the rotation icon/popup until it is set to something different or the device is rebooted)
|
||||
# power - gracefully controls the power state
|
||||
# skip - skips a number of actions after the current one (mainly useful for more complex conditional chains) (this action will not update the success/failure flag)
|
||||
# <arg> the argument passed to the action:
|
||||
@@ -99,6 +103,13 @@
|
||||
# enable - enables WiFi (but doesn't necessarily connect to it)
|
||||
# disable - disables WiFi
|
||||
# toggle - toggles WiFi (but doesn't necessarily connect to it)
|
||||
# nickel_orientation - one of:
|
||||
# portrait (4.13.12638+)
|
||||
# landscape (4.13.12638+)
|
||||
# inverted_portrait (4.13.12638+)
|
||||
# inverted_landscape (4.13.12638+)
|
||||
# invert (4.13.12638+) - Toggles between inverted/non-inverted (preserves side) (this will not work if used in a chain with swap)
|
||||
# swap (4.13.12638+) - Toggles between portrait/landscape (preserves inversion) (this will not work if used in a chain with invert)
|
||||
# power - one of:
|
||||
# shutdown (4.13.12638+)
|
||||
# reboot (4.13.12638+)
|
||||
@@ -143,6 +154,7 @@
|
||||
# menu_item :main :Plato :kfmon :plato.png
|
||||
# generator :main :kfmon
|
||||
# menu_item :reader :Invert Screen :nickel_setting :toggle :invert
|
||||
# menu_item :reader :Invert Orientation :nickel_orientation :invert
|
||||
# menu_item :main :IP Address :cmd_output :500:/sbin/ifconfig | /usr/bin/awk '/inet addr/{print substr($2,6)}'
|
||||
# menu_item :main :Telnet :cmd_spawn :quiet:/bin/mount -t devpts | /bin/grep -q /dev/pts || { /bin/mkdir -p /dev/pts && /bin/mount -t devpts devpts /dev/pts; }
|
||||
# chain_success :cmd_spawn :quiet:/usr/bin/pkill -f "^/usr/bin/tcpsvd -E 0.0.0.0 1023" || true && exec /usr/bin/tcpsvd -E 0.0.0.0 1023 /usr/sbin/telnetd -i -l /bin/login
|
||||
|
||||
@@ -50,6 +50,7 @@ void nm_action_result_free(nm_action_result_t *res);
|
||||
X(nickel_misc) \
|
||||
X(nickel_open) \
|
||||
X(nickel_wifi) \
|
||||
X(nickel_orientation) \
|
||||
X(power) \
|
||||
X(skip)
|
||||
|
||||
|
||||
173
src/action_cc.cc
173
src/action_cc.cc
@@ -1,5 +1,6 @@
|
||||
#include <QApplication>
|
||||
#include <QProcess>
|
||||
#include <QScreen>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QUrl>
|
||||
@@ -51,6 +52,7 @@ typedef void BrowserWorkflowManager;
|
||||
typedef void N3SettingsExtrasController;
|
||||
typedef void N3PowerWorkflowManager;
|
||||
typedef void WirelessWorkflowManager;
|
||||
typedef void StatusBarView;
|
||||
|
||||
NM_ACTION_(nickel_open) {
|
||||
char *tmp1 = strdupa(arg); // strsep and strtrim will modify it
|
||||
@@ -552,6 +554,177 @@ NM_ACTION_(nickel_wifi) {
|
||||
return nm_action_result_silent();
|
||||
}
|
||||
|
||||
NM_ACTION_(nickel_orientation) {
|
||||
Qt::ScreenOrientation o;
|
||||
if (!strcmp(arg, "portrait")) o = Qt::PortraitOrientation;
|
||||
else if (!strcmp(arg, "landscape")) o = Qt::LandscapeOrientation;
|
||||
else if (!strcmp(arg, "inverted_portrait")) o = Qt::InvertedPortraitOrientation;
|
||||
else if (!strcmp(arg, "inverted_landscape")) o = Qt::InvertedLandscapeOrientation;
|
||||
else if (!strcmp(arg, "invert") || !strcmp(arg, "swap")) {
|
||||
switch ((o = QGuiApplication::primaryScreen()->orientation())) {
|
||||
case Qt::PrimaryOrientation: NM_ERR_RET(nullptr, "could not get current screen orientation"); break;
|
||||
case Qt::PortraitOrientation: o = !strcmp(arg, "invert") ? Qt::InvertedPortraitOrientation : Qt::LandscapeOrientation; break;
|
||||
case Qt::LandscapeOrientation: o = !strcmp(arg, "invert") ? Qt::InvertedLandscapeOrientation : Qt::PortraitOrientation; break;
|
||||
case Qt::InvertedPortraitOrientation: o = !strcmp(arg, "invert") ? Qt::PortraitOrientation : Qt::InvertedLandscapeOrientation; break;
|
||||
case Qt::InvertedLandscapeOrientation: o = !strcmp(arg, "invert") ? Qt::LandscapeOrientation : Qt::InvertedPortraitOrientation; break;
|
||||
default: NM_ERR_RET(nullptr, "unknown screen orientation %d", o); break;
|
||||
}
|
||||
}
|
||||
else NM_ERR_RET(nullptr, "unknown nickel_orientation action '%s'", arg);
|
||||
|
||||
// ---
|
||||
|
||||
//libnickel 4.6 * _ZN22QWindowSystemInterface29handleScreenOrientationChangeEP7QScreenN2Qt17ScreenOrientationE
|
||||
void (*QWindowSystemInterface_handleScreenOrientationChange)(QScreen*, Qt::ScreenOrientation);
|
||||
reinterpret_cast<void*&>(QWindowSystemInterface_handleScreenOrientationChange) = dlsym(RTLD_DEFAULT, "_ZN22QWindowSystemInterface29handleScreenOrientationChangeEP7QScreenN2Qt17ScreenOrientationE");
|
||||
NM_CHECK(nullptr, QWindowSystemInterface_handleScreenOrientationChange, "could not dlsym QWindowSystemInterface::handleScreenOrientationChange (did the way Nickel handles the screen orientation sensor change?)");
|
||||
|
||||
//libnickel 4.6 * _ZN6Device16getCurrentDeviceEv
|
||||
Device *(*Device_getCurrentDevice)();
|
||||
reinterpret_cast<void*&>(Device_getCurrentDevice) = dlsym(RTLD_DEFAULT, "_ZN6Device16getCurrentDeviceEv");
|
||||
NM_CHECK(nullptr, Device_getCurrentDevice, "could not dlsym Device::getCurrentDevice");
|
||||
|
||||
//libnickel 4.11.11911 * _ZNK6Device20hasOrientationSensorEv
|
||||
bool (*Device_hasOrientationSensor)(Device*);
|
||||
reinterpret_cast<void*&>(Device_hasOrientationSensor) = dlsym(RTLD_DEFAULT, "_ZNK6Device20hasOrientationSensorEv");
|
||||
NM_CHECK(nullptr, Device_getCurrentDevice, "could not dlsym Device::hasOrientationSensor");
|
||||
|
||||
//libnickel 4.6 * _ZN8SettingsC2ERK6Deviceb _ZN8SettingsC2ERK6Device
|
||||
void *(*Settings_Settings)(Settings*, Device*, bool);
|
||||
void *(*Settings_SettingsLegacy)(Settings*, Device*);
|
||||
reinterpret_cast<void*&>(Settings_Settings) = dlsym(RTLD_DEFAULT, "_ZN8SettingsC2ERK6Deviceb");
|
||||
reinterpret_cast<void*&>(Settings_SettingsLegacy) = dlsym(RTLD_DEFAULT, "_ZN8SettingsC2ERK6Device");
|
||||
NM_CHECK(nullptr, Settings_Settings || Settings_SettingsLegacy, "could not dlsym Settings constructor (new and/or old)");
|
||||
|
||||
//libnickel 4.6 * _ZN8SettingsD2Ev
|
||||
void *(*Settings_SettingsD)(Settings*);
|
||||
reinterpret_cast<void*&>(Settings_SettingsD) = dlsym(RTLD_DEFAULT, "_ZN8SettingsD2Ev");
|
||||
NM_CHECK(nullptr, Settings_SettingsD, "could not dlsym Settings destructor");
|
||||
|
||||
void *ApplicationSettings_vtable = dlsym(RTLD_DEFAULT, "_ZTV19ApplicationSettings");
|
||||
NM_CHECK(nullptr, ApplicationSettings_vtable, "could not dlsym the vtable for ApplicationSettings");
|
||||
|
||||
//libnickel 4.13.12638 * _ZN19ApplicationSettings20setLockedOrientationE6QFlagsIN2Qt17ScreenOrientationEE
|
||||
bool (*ApplicationSettings_setLockedOrientation)(Settings*, Qt::ScreenOrientation);
|
||||
reinterpret_cast<void*&>(ApplicationSettings_setLockedOrientation) = dlsym(RTLD_DEFAULT, "_ZN19ApplicationSettings20setLockedOrientationE6QFlagsIN2Qt17ScreenOrientationEE");
|
||||
NM_CHECK(nullptr, ApplicationSettings_setLockedOrientation, "could not dlsym ApplicationSettings::setLockedOrientation");
|
||||
|
||||
//libnickel 4.13.12638 * _ZN19ApplicationSettings17lockedOrientationEv
|
||||
int (*ApplicationSettings_lockedOrientation)(Settings*);
|
||||
reinterpret_cast<void*&>(ApplicationSettings_lockedOrientation) = dlsym(RTLD_DEFAULT, "_ZN19ApplicationSettings17lockedOrientationEv");
|
||||
NM_CHECK(nullptr, ApplicationSettings_lockedOrientation, "could not dlsym ApplicationSettings::lockedOrientation");
|
||||
|
||||
Device *dev = Device_getCurrentDevice();
|
||||
NM_CHECK(nullptr, dev, "could not get shared nickel device pointer");
|
||||
|
||||
Settings *settings = alloca(128); // way larger than it is, but better to be safe
|
||||
if (Settings_Settings)
|
||||
Settings_Settings(settings, dev, false);
|
||||
else if (Settings_SettingsLegacy)
|
||||
Settings_SettingsLegacy(settings, dev);
|
||||
|
||||
#define vtable_ptr(x) *reinterpret_cast<void**&>(x)
|
||||
#define vtable_target(x) reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(x)+8)
|
||||
|
||||
// ---
|
||||
|
||||
// note: these notes were last updated for 4.22.15268, but should remain
|
||||
// correct for the forseeable future and should be relevant for all
|
||||
// supported versions (4.13.12638+).
|
||||
|
||||
// Prevent the sensor (if active) from changing to a different orientation
|
||||
// behind our backs.
|
||||
//
|
||||
// Without this, the orientation sensor may override our orientation if the
|
||||
// sensor is in auto mode, and may invert our orientation if the sensor is
|
||||
// in portrait/landscape mode. This would happen the moment the sensor
|
||||
// reading is updated, which would be essentially instantly if the device
|
||||
// isn't on a perfectly still surface.
|
||||
|
||||
QGuiApplication::primaryScreen()->setOrientationUpdateMask(o);
|
||||
|
||||
// Set the current locked orientation to the new one to ensure our new
|
||||
// orientation will be allowed.
|
||||
//
|
||||
// Without this, our orientation may not have any effect since the
|
||||
// orientation set by QWindowSystemInterface::handleScreenOrientationChange
|
||||
// is limited by if the orientation's bit is set in [ApplicationSettings]
|
||||
// LockedOrientation (note that auto is all of them, and portrait/landscape
|
||||
// is the normal and inverted variants) (it's a bitmask of
|
||||
// Qt::ScreenOrientation).
|
||||
|
||||
vtable_ptr(settings) = vtable_target(ApplicationSettings_vtable);
|
||||
int icon_mask = ApplicationSettings_lockedOrientation(settings);
|
||||
|
||||
vtable_ptr(settings) = vtable_target(ApplicationSettings_vtable);
|
||||
ApplicationSettings_setLockedOrientation(settings, o);
|
||||
|
||||
// If the device doesn't have an orientation sensor, the user needs to set
|
||||
// the [DeveloperSettings] ForceAllowLandscape setting to true or apply the
|
||||
// "Allow rotation on all devices" patch (the patch will also show the
|
||||
// built-in rotation menu in the reader and other views). If this is not
|
||||
// done, this action will silently fail to work. We can't really check this
|
||||
// specifically since kobopatch only changes a few places which call
|
||||
// Device::hasOrientationSensor, not the function itself.
|
||||
//
|
||||
// If the device has an orientation sensor, the user can optionally set the
|
||||
// [DeveloperSettings] ForceAllowLandscape setting to true or apply the
|
||||
// "Allow rotation on all devices" patch to make the rotation take effect
|
||||
// even if the current view doesn't normally allow it.
|
||||
//
|
||||
// This is because in addition to the previous limitation, if
|
||||
// [DeveloperSettings] ForceAllowLandscape if not true, the orientation is
|
||||
// limited based on if Device::hasOrientationSensor and the allowed
|
||||
// orientations for the current view.
|
||||
|
||||
NM_LOG(Device_hasOrientationSensor(dev)
|
||||
? "nickel_orientation: if this didn't do anything, you may need to set [DeveloperSettings] ForceAllowLandscape=true to allow landscape orientations on all views"
|
||||
: "nickel_orientation: if this didn't do anything, ensure you have applied the 'Allow rotation on all devices' kobopatch patch, or that you have set [DeveloperSettings] ForceAllowLandscape=true");
|
||||
|
||||
// Set the orientation.
|
||||
//
|
||||
// This is the only thing which is really required here, but if used alone,
|
||||
// the orientation sensor may override it, and the orientation will only be
|
||||
// set if it is within the constraints of the current rotation mode of
|
||||
// auto/portrait/landscape.
|
||||
//
|
||||
// Note that this function is actually part of the private Qt QPA API, and
|
||||
// Nickel really should be doing this part of the rotation logic (including
|
||||
// the sensors) from the libkobo QPA plugin. But, this is how Nickel does
|
||||
// it, so we need to do it the same way (this does make it easier for both
|
||||
// us and Kobo, I guess, due to how intertwined the orientation stuff is).
|
||||
//
|
||||
// This is the same function which is called by Nickel's handler for the
|
||||
// orientation sensor's reading.
|
||||
|
||||
QWindowSystemInterface_handleScreenOrientationChange(QGuiApplication::primaryScreen(), o);
|
||||
|
||||
// We don't update the status bar rotation icon, since we would need to get
|
||||
// ahold of the StatusBarView, and I don't like the current options for
|
||||
// doing that in a version-agnostic way: walking the entire QObject tree,
|
||||
// hooking the constructor, or using offsets directly to get ahold of the
|
||||
// StatusBarView from the StatusBarController from the MainWindowController.
|
||||
// I might reconsider this in the future if there is demand for it.
|
||||
|
||||
if ((icon_mask&o) == 0)
|
||||
NM_LOG("nickel_orientation: the status bar rotate icon may be out of date (this is expected)");
|
||||
|
||||
// If we ever wanted to add an option for setting to rotation to auto/locked
|
||||
// portrait/locked landscape, we'd need to call RotatePopupController
|
||||
// ::on{Auto,Portrait,Landscape} on StatusBarView::rotatePopupController.
|
||||
// This is how the rotate popup and the dropdown in the reading settings
|
||||
// does it.
|
||||
|
||||
// ---
|
||||
|
||||
#undef vtable_ptr
|
||||
#undef vtable_target
|
||||
|
||||
Settings_SettingsD(settings);
|
||||
|
||||
return nm_action_result_silent();
|
||||
}
|
||||
|
||||
NM_ACTION_(cmd_spawn) {
|
||||
char *tmp = strdup(arg); // strsep and strtrim will modify it
|
||||
char *tmp1 = tmp; // so we can still free tmp later
|
||||
|
||||
Reference in New Issue
Block a user