diff --git a/Gui/Gui.pro b/Gui/Gui.pro index 4ffe3a2177..8d2b7a174b 100644 --- a/Gui/Gui.pro +++ b/Gui/Gui.pro @@ -203,6 +203,7 @@ SOURCES += \ TabGroup.cpp \ TabWidget.cpp \ TableModelView.cpp \ + TaskBar.cpp \ TextRenderer.cpp \ TimeLineGui.cpp \ ToolButton.cpp \ @@ -347,6 +348,7 @@ HEADERS += \ TabGroup.h \ TabWidget.h \ TableModelView.h \ + TaskBar.h \ TextRenderer.h \ TimeLineGui.h \ ToolButton.h \ @@ -411,6 +413,8 @@ OTHER_FILES += \ Resources/Images/splashscreen.svg macx { +HEADERS += TaskBarMac.h OBJECTIVE_SOURCES += \ - $$PWD/../Gui/QtMac.mm + $$PWD/../Gui/QtMac.mm \ + $$PWD/../Gui/TaskBarMac.mm } diff --git a/Gui/ProgressPanel.cpp b/Gui/ProgressPanel.cpp index 2ec25e15f0..60a97d8565 100644 --- a/Gui/ProgressPanel.cpp +++ b/Gui/ProgressPanel.cpp @@ -147,7 +147,10 @@ ProgressPanel::ProgressPanel(Gui* gui) : QWidget(gui) , PanelWidget(this, gui) , _imp( new ProgressPanelPrivate() ) + , _taskbar(0) { + _taskbar = new TaskBar(this); + _imp->mainLayout = new QVBoxLayout(this); _imp->mainLayout->setContentsMargins(0, 0, 0, 0); _imp->mainLayout->setSpacing(0); @@ -466,6 +469,7 @@ ProgressPanel::startTask(const NodePtr& node, canCancel, message, process) ); + task->setTaskBar(_taskbar); if ( canPause || node->getEffectInstance()->isOutput() ) { task->createItems(); diff --git a/Gui/ProgressPanel.h b/Gui/ProgressPanel.h index 762d80653b..c521df1b21 100644 --- a/Gui/ProgressPanel.h +++ b/Gui/ProgressPanel.h @@ -42,6 +42,7 @@ CLANG_DIAG_ON(uninitialized) #include "Gui/PanelWidget.h" #include "Gui/GuiFwd.h" +#include "Gui/TaskBar.h" NATRON_NAMESPACE_ENTER @@ -146,6 +147,7 @@ public Q_SLOTS: virtual void enterEvent(QEvent* e) OVERRIDE FINAL; virtual void leaveEvent(QEvent* e) OVERRIDE FINAL; boost::scoped_ptr _imp; + TaskBar *_taskbar; }; NATRON_NAMESPACE_EXIT diff --git a/Gui/ProgressTaskInfo.cpp b/Gui/ProgressTaskInfo.cpp index 95b3295af4..f92cc91a31 100644 --- a/Gui/ProgressTaskInfo.cpp +++ b/Gui/ProgressTaskInfo.cpp @@ -188,6 +188,7 @@ ProgressTaskInfo::ProgressTaskInfo(ProgressPanel* panel, const ProcessHandlerPtr& process) : QObject() , _imp( new ProgressTaskInfoPrivate(panel, node, this, firstFrame, lastFrame, frameStep, canPause, canCancel, message, process) ) + , _taskbar(0) { //We compute the time remaining automatically based on a timer if this is not a render but a general progress dialog _imp->timer.reset(new TimeLapse); @@ -250,9 +251,11 @@ ProgressTaskInfo::cancelTask(bool calledFromRenderEngine, if (_imp->canBePaused) { _imp->statusItem->setText( tr("Paused") ); _imp->status = eProgressTaskStatusPaused; + updateTaskBarState(retCode == 1 ? TaskBar::PausedProgress : TaskBar::NoProgress); } else { _imp->statusItem->setText( tr("Canceled") ); _imp->status = eProgressTaskStatusCanceled; + updateTaskBarState(TaskBar::NoProgress); } } else { if (retCode == 0) { @@ -262,10 +265,12 @@ ProgressTaskInfo::cancelTask(bool calledFromRenderEngine, if (_imp->progressBar) { _imp->progressBar->setValue(100); } + updateTaskBarState(TaskBar::NormalProgress); } else { _imp->statusItem->setTextColor(Qt::red); _imp->statusItem->setText( tr("Failed") ); _imp->status = eProgressTaskStatusFinished; + updateTaskBarState(TaskBar::ErrorProgress); } } _imp->refreshButtons(); @@ -275,6 +280,7 @@ ProgressTaskInfo::cancelTask(bool calledFromRenderEngine, node->getApp()->removeRenderFromQueue(effect); if ( ( _imp->panel->isRemoveTasksAfterFinishChecked() && (retCode == 0) ) || (!_imp->canBePaused && !calledFromRenderEngine) ) { _imp->panel->removeTaskFromTable( shared_from_this() ); + updateTaskBarState(TaskBar::NoProgress); } if (!calledFromRenderEngine) { Q_EMIT taskCanceled(); @@ -397,6 +403,45 @@ ProgressTaskInfo::getProcess() const return _imp->process; } +void +ProgressTaskInfo::setTaskBar(TaskBar *taskbar) +{ + if (!taskbar) { + return; + } + _taskbar = taskbar; +} + +void +ProgressTaskInfo::updateTaskBarProgress(ProgressTaskInfo::ProgressTaskStatusEnum status, + double progress) +{ + if (!_taskbar) { + return; + } + switch(status) { + case eProgressTaskStatusPaused: + _taskbar->setProgressState(TaskBar::PausedProgress); + break; + case eProgressTaskStatusRunning: + _taskbar->setProgressState(TaskBar::NormalProgress); + break; + default: + _taskbar->setProgressState(TaskBar::NoProgress); + break; + } + _taskbar->setProgressValue(progress); +} + +void +ProgressTaskInfo::updateTaskBarState(TaskBar::ProgressState state) +{ + if (!_taskbar) { + return; + } + _taskbar->setProgressState(state); +} + bool ProgressTaskInfo::wasCanceled() const { @@ -559,6 +604,8 @@ ProgressTaskInfo::updateProgressBar(double totalProgress, _imp->statusItem->setText( tr("Running") ); _imp->refreshButtons(); } + + updateTaskBarProgress(_imp->status, _imp->progressPercent); } void @@ -683,6 +730,8 @@ ProgressTaskInfo::onCancelTriggered() cancelTask(false, 0); _imp->panel->removeTaskFromTable(thisShared); + + updateTaskBarState(TaskBar::NoProgress); } void diff --git a/Gui/ProgressTaskInfo.h b/Gui/ProgressTaskInfo.h index fa1a83860d..ddbec063ad 100644 --- a/Gui/ProgressTaskInfo.h +++ b/Gui/ProgressTaskInfo.h @@ -38,6 +38,7 @@ #include "Gui/GuiFwd.h" +#include "Gui/TaskBar.h" NATRON_NAMESPACE_ENTER @@ -122,6 +123,12 @@ GCC_DIAG_SUGGEST_OVERRIDE_ON ProcessHandlerPtr getProcess() const; + void setTaskBar(TaskBar *taskbar); + + void updateTaskBarProgress(ProgressTaskStatusEnum status, double progress); + + void updateTaskBarState(TaskBar::ProgressState state); + public Q_SLOTS: void onShowProgressPanelTimerTimeout(); @@ -170,6 +177,7 @@ public Q_SLOTS: void clearItems(); boost::scoped_ptr _imp; + TaskBar *_taskbar; }; NATRON_NAMESPACE_EXIT diff --git a/Gui/TaskBar.cpp b/Gui/TaskBar.cpp new file mode 100644 index 0000000000..95f739aed6 --- /dev/null +++ b/Gui/TaskBar.cpp @@ -0,0 +1,181 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * This file is part of Natron , + * (C) 2018-2021 The Natron developers + * (C) 2013-2018 INRIA and Alexandre Gauthier-Foichat + * + * Natron is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Natron is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Natron. If not, see + * ***** END LICENSE BLOCK ***** */ + +#include "TaskBar.h" + +NATRON_NAMESPACE_ENTER + +#ifdef Q_OS_WIN +// MINGW workaround +const GUID nIID_ITaskbarList3 = {0xea1afb91, 0x9e28, 0x4b86, {0x90,0xe9,0x9e,0x9f,0x8a,0x5e,0xef,0xaf}}; +#endif + +TaskBar::TaskBar(QWidget *parent) + : QObject(parent) +#ifdef Q_OS_WIN + , _wtask(0) +#elif defined(Q_OS_MAC) + , _mtask(0) +#endif + , _min(0.0) + , _max(100.0) + , _val(0.0) + , _state(NoProgress) +{ +#ifdef Q_OS_WIN + _wid = parent->window()->winId(); + CoInitialize(NULL); + HRESULT hres = CoCreateInstance(CLSID_TaskbarList, + NULL, + CLSCTX_INPROC_SERVER, + nIID_ITaskbarList3, + (LPVOID*)&_wtask); + if ( FAILED(hres) ) { + _wtask = NULL; + CoUninitialize(); + } else { + _wtask->HrInit(); + } +#elif defined(Q_OS_MAC) + _mtask = new TaskBarMac(this); +#endif +} + +TaskBar::~TaskBar() +{ +#ifdef Q_OS_WIN + if (_wtask) { + _wtask->Release(); + _wtask = NULL; + CoUninitialize(); + } +#endif +} + +void +TaskBar::setProgressMinimum(double value) +{ + if (_min < 0.0) { + return; + } + _min = value; +} + +void +TaskBar::setProgressMaximum(double value) +{ + if (_max < 0.0) { + return; + } + _max = value; +} + +void +TaskBar::setProgressRange(double minVal, + double maxVal) +{ + if (minVal >= 0.0 && minVal < maxVal) { + setProgressMinimum(minVal); + setProgressMaximum(maxVal); + } +} + +void +TaskBar::setProgressValue(double value) +{ + if (_val == value) { + return; + } + + double currentVal = value - _min; + double totalVal = _max - _min; + if (currentVal < 0.0 || totalVal <= 0.0) { + return; + } +#ifdef Q_OS_WIN + if (!_wtask) { + return; + } + if (_wtask->SetProgressValue(_wid, currentVal, totalVal) == S_OK) { + _val = value; + } +#elif defined(Q_OS_MAC) + if (!_mtask) { + return; + } + _mtask->setProgress(currentVal / totalVal); + _val = value; +#endif +} + +void +TaskBar::setProgressState(TaskBar::ProgressState state) +{ + if (_state == state) { + return; + } + +#ifdef Q_OS_WIN + if (!_wtask) { + return; + } + TBPFLAG flag; + switch(state) { + case NoProgress: + flag = TBPF_NOPROGRESS; + break; + case IndeterminateProgress: + flag = TBPF_INDETERMINATE; + break; + case PausedProgress: + flag = TBPF_PAUSED; + break; + case ErrorProgress: + flag = TBPF_ERROR; + break; + default: + flag = TBPF_NORMAL; + break; + } + if (_wtask->SetProgressState(_wid, flag) == S_OK) { + _state = state; + } +#elif defined(Q_OS_MAC) + if (!_mtask) { + return; + } + if (state == NoProgress) { + _mtask->setProgressVisible(false); + } + _state = state; +#endif +} + +void +TaskBar::clearProgress() +{ + setProgressRange(0, 100.0); + setProgressValue(0.0); + setProgressState(NoProgress); +} + +NATRON_NAMESPACE_EXIT + +NATRON_NAMESPACE_USING +#include "moc_TaskBar.cpp" diff --git a/Gui/TaskBar.h b/Gui/TaskBar.h new file mode 100644 index 0000000000..8c637de2af --- /dev/null +++ b/Gui/TaskBar.h @@ -0,0 +1,86 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * This file is part of Natron , + * (C) 2018-2021 The Natron developers + * (C) 2013-2018 INRIA and Alexandre Gauthier-Foichat + * + * Natron is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Natron is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Natron. If not, see + * ***** END LICENSE BLOCK ***** */ + +#ifndef TASKBAR_H +#define TASKBAR_H + +#include "Global/Macros.h" + +CLANG_DIAG_OFF(deprecated) +CLANG_DIAG_OFF(uninitialized) +#include +CLANG_DIAG_ON(deprecated) +CLANG_DIAG_ON(uninitialized) + +#ifdef Q_OS_WIN +#include +#elif defined(Q_OS_MAC) +#include "TaskBarMac.h" +#endif + +NATRON_NAMESPACE_ENTER + +#ifdef Q_OS_WIN +// MINGW workaround +extern const GUID nIID_ITaskbarList3; +#endif + +class TaskBar : public QObject +{ + Q_OBJECT + +public: + + enum ProgressState { + NoProgress, + IndeterminateProgress, + PausedProgress, + ErrorProgress, + NormalProgress + }; + + explicit TaskBar(QWidget *parent = 0); + ~TaskBar(); + +public Q_SLOTS: + + void setProgressMinimum(double value); + void setProgressMaximum(double value); + void setProgressRange(double minVal, double maxVal); + void setProgressValue(double value); + void setProgressState(TaskBar::ProgressState state); + void clearProgress(); + +private: + +#ifdef Q_OS_WIN + ITaskbarList3 *_wtask; + WId _wid; +#elif defined(Q_OS_MAC) + TaskBarMac *_mtask; +#endif + double _min; + double _max; + double _val; + TaskBar::ProgressState _state; +}; + +NATRON_NAMESPACE_EXIT + +#endif // TASKBAR_H diff --git a/Gui/TaskBarMac.h b/Gui/TaskBarMac.h new file mode 100644 index 0000000000..4cff8d6597 --- /dev/null +++ b/Gui/TaskBarMac.h @@ -0,0 +1,53 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * This file is part of Natron , + * (C) 2018-2021 The Natron developers + * (C) 2013-2018 INRIA and Alexandre Gauthier-Foichat + * + * Natron is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Natron is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Natron. If not, see + * ***** END LICENSE BLOCK ***** */ + +#ifndef TASKBARMAC_H +#define TASKBARMAC_H + +#include "Global/Macros.h" + +CLANG_DIAG_OFF(deprecated) +CLANG_DIAG_OFF(uninitialized) +#include +CLANG_DIAG_ON(deprecated) +CLANG_DIAG_ON(uninitialized) + +NATRON_NAMESPACE_ENTER + +class TaskBarMac : public QObject +{ + Q_OBJECT + +public: + + explicit TaskBarMac(QObject *parent = 0); + ~TaskBarMac(); + + void setProgress(double value); + void setProgressVisible(bool visible); + +private: + + struct TB; + TB *_tb; +}; + +NATRON_NAMESPACE_EXIT + +#endif // TASKBARMAC_H diff --git a/Gui/TaskBarMac.mm b/Gui/TaskBarMac.mm new file mode 100644 index 0000000000..cb15e4ac6f --- /dev/null +++ b/Gui/TaskBarMac.mm @@ -0,0 +1,121 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * This file is part of Natron , + * (C) 2018-2021 The Natron developers + * (C) 2013-2018 INRIA and Alexandre Gauthier-Foichat + * + * Natron is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Natron is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Natron. If not, see + * ***** END LICENSE BLOCK ***** */ + +#include "TaskBarMac.h" + +#import +#import +#import +#import +#import +#import +#import +#import + +@interface TaskBarView : NSView { + double _progress; +} +- (void)setProgress:(double)value; +@end + +@implementation TaskBarView + +- (void)setProgress:(double)value +{ + _progress = value; + [[NSApp dockTile] display]; +} +- (void)drawRect:(NSRect)rect +{ + Q_UNUSED(rect) + + NSRect boundary = [self bounds]; + [[NSApp applicationIconImage] drawInRect:boundary + fromRect:NSZeroRect + operation:NSCompositingOperationCopy + fraction:1.0]; + + if (_progress <= 0.0 || _progress >= 1.0) { + return; + } + + NSRect progressBoundary = boundary; + progressBoundary.size.height *= 0.15; + progressBoundary.size.width *= 0.75; + progressBoundary.origin.x = ( NSWidth(boundary) - NSWidth(progressBoundary) ) / 2.0; + progressBoundary.origin.y = (NSHeight(boundary) / 2.0) - (NSHeight(progressBoundary) / 2.0); + + NSRect currentProgress = progressBoundary; + currentProgress.size.width *= _progress; + + [[NSColor blackColor] setFill]; + [NSBezierPath fillRect:progressBoundary]; + + [[NSColor systemBlueColor] setFill]; + [NSBezierPath fillRect:currentProgress]; + + [[NSColor blackColor] setStroke]; + [NSBezierPath strokeRect:progressBoundary]; +} +@end + +NATRON_NAMESPACE_ENTER + +struct TaskBarMac::TB +{ + TaskBarView *view; +}; + +TaskBarMac::TaskBarMac(QObject *parent) + : QObject(parent) + , _tb(new TB) +{ + _tb->view = [[TaskBarView alloc] init]; + [[NSApp dockTile] setContentView:_tb->view]; +} + +TaskBarMac::~TaskBarMac() +{ + [[NSApp dockTile] setContentView:nil]; + [_tb->view release]; + delete _tb; +} + +void +TaskBarMac::setProgress(double value) +{ + [_tb->view setProgress:value]; + + if (value == 1.0) { + [NSApp requestUserAttention: NSInformationalRequest]; + } +} + +void +TaskBarMac::setProgressVisible(bool visible) +{ + if (!visible) { + setProgress(0.0); + } +} + +NATRON_NAMESPACE_EXIT + +NATRON_NAMESPACE_USING +#include "moc_TaskBarMac.cpp" diff --git a/global.pri b/global.pri index af818ec280..815a3f515c 100644 --- a/global.pri +++ b/global.pri @@ -283,9 +283,12 @@ macx { } } - #link against the CoreFoundation framework for the StandardPaths functionnality + # link against the CoreFoundation framework for the StandardPaths functionality LIBS += -framework CoreServices + # link against the AppKit framework for taskbar support + LIBS += -framework AppKit + #// Disable availability macros on macOS #// because we may be using libc++ on an older macOS, #// so that std::locale::numeric may be available @@ -345,7 +348,8 @@ win32 { # Natron requires a link to opengl32.dll and Gdi32 for offscreen rendering LIBS += -lopengl32 -lGdi32 - + # taskbar support + LIBS += -lole32 } win32-g++ {