From 3c9da61bc4c1124825b004b94b4486cd6f221837 Mon Sep 17 00:00:00 2001 From: Nathaniel van Diepen Date: Thu, 26 Jan 2023 15:08:20 -0700 Subject: [PATCH] Feature/notify when screenshot being taken (#286) * Notify when screenshot is being taken --- applications/system-service/notification.cpp | 59 ++----------------- applications/system-service/notification.h | 1 - applications/system-service/notificationapi.h | 35 +++++++++++ applications/system-service/screenapi.cpp | 27 +++++++++ applications/system-service/screenapi.h | 23 +++----- applications/system-service/tarnish.pro | 1 + 6 files changed, 75 insertions(+), 71 deletions(-) create mode 100644 applications/system-service/screenapi.cpp diff --git a/applications/system-service/notification.cpp b/applications/system-service/notification.cpp index d2e794627..08d091956 100644 --- a/applications/system-service/notification.cpp +++ b/applications/system-service/notification.cpp @@ -32,7 +32,7 @@ void Notification::display(){ return; } notificationAPI->lock(); - dispatchToMainThread([=]{ + Oxide::dispatchToMainThread([=]{ qDebug() << "Displaying notification" << identifier(); auto path = appsAPI->currentApplicationNoSecurityCheck(); Application* resumeApp = nullptr; @@ -52,61 +52,10 @@ void Notification::remove(){ emit removed(); } -void Notification::dispatchToMainThread(std::function callback){ - if(this->thread() == qApp->thread()){ - callback(); - return; - } - // any thread - QTimer* timer = new QTimer(); - timer->moveToThread(qApp->thread()); - timer->setSingleShot(true); - QObject::connect(timer, &QTimer::timeout, [=](){ - // main thread - callback(); - timer->deleteLater(); - }); - QMetaObject::invokeMethod(timer, "start", Qt::BlockingQueuedConnection, Q_ARG(int, 0)); -} void Notification::paintNotification(Application* resumeApp){ - auto frameBuffer = EPFrameBuffer::framebuffer(); - qDebug() << "Waiting for other painting to finish..."; - while(frameBuffer->paintingActive()){ - EPFrameBuffer::waitForLastUpdate(); - } qDebug() << "Painting notification" << identifier(); - screenBackup = frameBuffer->copy(); - qDebug() << "Painting to framebuffer..."; - QPainter painter(frameBuffer); - auto size = frameBuffer->size(); - auto fm = painter.fontMetrics(); - auto padding = 10; - auto radius = 10; - QImage icon(m_icon); - auto iconSize = icon.isNull() ? 0 : 50; - auto width = fm.horizontalAdvance(text()) + iconSize + (padding * 3); - auto height = max(fm.height(), iconSize) + (padding * 2); - auto left = size.width() - width; - auto top = size.height() - height; - updateRect = QRect(left, top, width, height); - painter.fillRect(updateRect, Qt::black); - painter.setPen(Qt::black); - painter.drawRoundedRect(updateRect, radius, radius); - painter.setPen(Qt::white); - QRect textRect(left + padding, top + padding, width - iconSize - (padding * 2), height - padding); - painter.drawText(textRect, Qt::AlignCenter, text()); - painter.end(); - qDebug() << "Updating screen " << updateRect << "..."; - EPFrameBuffer::sendUpdate(updateRect, EPFrameBuffer::Mono, EPFrameBuffer::PartialUpdate, true); - if(!icon.isNull()){ - QPainter painter2(frameBuffer); - QRect iconRect(size.width() - iconSize - padding, top + padding, iconSize, iconSize); - painter2.fillRect(iconRect, Qt::white); - painter2.drawImage(iconRect, icon); - painter2.end(); - EPFrameBuffer::sendUpdate(iconRect, EPFrameBuffer::Mono, EPFrameBuffer::PartialUpdate, true); - } - EPFrameBuffer::waitForLastUpdate(); + screenBackup = screenAPI->copy(); + updateRect = notificationAPI->paintNotification(text(), m_icon); qDebug() << "Painted notification" << identifier(); emit displayed(); QTimer::singleShot(2000, [this, resumeApp]{ @@ -117,7 +66,7 @@ void Notification::paintNotification(Application* resumeApp){ qDebug() << "Finished displaying notification" << identifier(); EPFrameBuffer::waitForLastUpdate(); if(!notificationAPI->notificationDisplayQueue.isEmpty()){ - dispatchToMainThread([resumeApp] { + Oxide::dispatchToMainThread([resumeApp] { notificationAPI->notificationDisplayQueue.takeFirst()->paintNotification(resumeApp); }); return; diff --git a/applications/system-service/notification.h b/applications/system-service/notification.h index 7f6c797a6..48b6dd00c 100644 --- a/applications/system-service/notification.h +++ b/applications/system-service/notification.h @@ -130,7 +130,6 @@ class Notification : public QObject{ QImage screenBackup; QRect updateRect; - void dispatchToMainThread(std::function callback); bool hasPermission(QString permission, const char* sender = __builtin_FUNCTION()); }; diff --git a/applications/system-service/notificationapi.h b/applications/system-service/notificationapi.h index 1af8b791d..f1ec8002d 100644 --- a/applications/system-service/notificationapi.h +++ b/applications/system-service/notificationapi.h @@ -106,6 +106,41 @@ class NotificationAPI : public APIBase { } return m_notifications.value(identifier); } + QRect paintNotification(const QString& text, const QString& iconPath){ + qDebug() << "Painting to framebuffer..."; + auto frameBuffer = EPFrameBuffer::framebuffer(); + QPainter painter(frameBuffer); + auto size = frameBuffer->size(); + auto fm = painter.fontMetrics(); + auto padding = 10; + auto radius = 10; + QImage icon(iconPath); + auto iconSize = icon.isNull() ? 0 : 50; + auto width = fm.horizontalAdvance(text) + iconSize + (padding * 3); + auto height = max(fm.height(), iconSize) + (padding * 2); + auto left = size.width() - width; + auto top = size.height() - height; + QRect updateRect(left, top, width, height); + painter.fillRect(updateRect, Qt::black); + painter.setPen(Qt::black); + painter.drawRoundedRect(updateRect, radius, radius); + painter.setPen(Qt::white); + QRect textRect(left + padding, top + padding, width - iconSize - (padding * 2), height - padding); + painter.drawText(textRect, Qt::AlignCenter, text); + painter.end(); + qDebug() << "Updating screen " << updateRect << "..."; + EPFrameBuffer::sendUpdate(updateRect, EPFrameBuffer::Mono, EPFrameBuffer::PartialUpdate, true); + if(!icon.isNull()){ + QPainter painter2(frameBuffer); + QRect iconRect(size.width() - iconSize - padding, top + padding, iconSize, iconSize); + painter2.fillRect(iconRect, Qt::white); + painter2.drawImage(iconRect, icon); + painter2.end(); + EPFrameBuffer::sendUpdate(iconRect, EPFrameBuffer::Mono, EPFrameBuffer::PartialUpdate, true); + } + EPFrameBuffer::waitForLastUpdate(); + return updateRect; + } public slots: QDBusObjectPath add(const QString& identifier, const QString& application, const QString& text, const QString& icon, QDBusMessage message){ diff --git a/applications/system-service/screenapi.cpp b/applications/system-service/screenapi.cpp new file mode 100644 index 000000000..6d3d7de39 --- /dev/null +++ b/applications/system-service/screenapi.cpp @@ -0,0 +1,27 @@ +#include "screenapi.h" +#include "notificationapi.h" + +QDBusObjectPath ScreenAPI::screenshot(){ + if(!hasPermission("screen")){ + return QDBusObjectPath("/"); + } + qDebug() << "Taking screenshot"; + auto filePath = getNextPath(); +#ifdef DEBUG + qDebug() << "Using path" << filePath; +#endif + QImage screen = copy(); + QRect rect = notificationAPI->paintNotification("Taking Screenshot...", ""); + EPFrameBuffer::sendUpdate(rect, EPFrameBuffer::Mono, EPFrameBuffer::PartialUpdate, true); + QDBusObjectPath path("/"); + if(!screen.save(filePath)){ + qDebug() << "Failed to take screenshot"; + }else{ + path = addScreenshot(filePath)->qPath(); + } + QPainter painter(EPFrameBuffer::framebuffer()); + painter.drawImage(rect, screen, rect); + painter.end(); + EPFrameBuffer::sendUpdate(rect, EPFrameBuffer::HighQualityGrayscale, EPFrameBuffer::PartialUpdate, true); + return path; +} diff --git a/applications/system-service/screenapi.h b/applications/system-service/screenapi.h index 6a9f3edd1..430a3e7ff 100644 --- a/applications/system-service/screenapi.h +++ b/applications/system-service/screenapi.h @@ -103,8 +103,7 @@ class ScreenAPI : public APIBase { } Oxide::Sentry::sentry_transaction("screen", "drawFullscrenImage", [img, path](Oxide::Sentry::Transaction* t){ Q_UNUSED(t); - auto size = EPFrameBuffer::framebuffer()->size(); - QRect rect(0, 0, size.width(), size.height()); + QRect rect = EPFrameBuffer::framebuffer()->rect(); QPainter painter(EPFrameBuffer::framebuffer()); painter.drawImage(rect, img); painter.end(); @@ -114,20 +113,14 @@ class ScreenAPI : public APIBase { return true; } - Q_INVOKABLE QDBusObjectPath screenshot(){ - if(!hasPermission("screen")){ - return QDBusObjectPath("/"); - } - qDebug() << "Taking screenshot"; - auto filePath = getNextPath(); -#ifdef DEBUG - qDebug() << "Using path" << filePath; -#endif - if(!EPFrameBuffer::framebuffer()->save(filePath)){ - qDebug() << "Failed to take screenshot"; - return QDBusObjectPath("/"); + Q_INVOKABLE QDBusObjectPath screenshot(); + QImage copy(){ + auto frameBuffer = EPFrameBuffer::framebuffer(); + qDebug() << "Waiting for other painting to finish..."; + while(frameBuffer->paintingActive()){ + EPFrameBuffer::waitForLastUpdate(); } - return addScreenshot(filePath)->qPath(); + return frameBuffer->copy(); } public slots: diff --git a/applications/system-service/tarnish.pro b/applications/system-service/tarnish.pro index 1f57e0657..c49db7e42 100644 --- a/applications/system-service/tarnish.pro +++ b/applications/system-service/tarnish.pro @@ -19,6 +19,7 @@ SOURCES += \ event_device.cpp \ network.cpp \ notification.cpp \ + screenapi.cpp \ screenshot.cpp \ systemapi.cpp \ wlan.cpp \