diff --git a/.gitmodules b/.gitmodules index b9337d594..7e19cdfab 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,8 @@ -[submodule "ext/KDDockWidgets"] - path = ext/KDDockWidgets - url = https://github.com/olive-editor/KDDockWidgets.git [submodule "ext/core"] path = ext/core - url = https://github.com/olive-editor/core + url = https://github.com/OliveCommunity/core.git + branch = dev +[submodule "ext/KDDockWidgets"] + path = ext/KDDockWidgets + url = https://github.com/OliveCommunity/KDDockWidgets.git + branch = main diff --git a/0001-Fix-include-path-for-Window_p.h-in-qtcommon-director.patch b/0001-Fix-include-path-for-Window_p.h-in-qtcommon-director.patch new file mode 100644 index 000000000..e51c8ee8a --- /dev/null +++ b/0001-Fix-include-path-for-Window_p.h-in-qtcommon-director.patch @@ -0,0 +1,25 @@ +From 6b0ef44eb189411d36c739ccde8a081a3e62034a Mon Sep 17 00:00:00 2001 +From: Mike Solar +Date: Mon, 24 Nov 2025 20:57:12 +0800 +Subject: [PATCH] Fix include path for Window_p.h in qtcommon directory + +--- + src/qtcommon/Window_p.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/qtcommon/Window_p.h b/src/qtcommon/Window_p.h +index f29b209a5..d1d6b47ad 100644 +--- a/src/qtcommon/Window_p.h ++++ b/src/qtcommon/Window_p.h +@@ -11,7 +11,7 @@ + + #pragma once + +-#include "core/Window_p.h" ++#include "../core/Window_p.h" + #include "Screen_p.h" + + #include +-- +2.52.0 + diff --git a/CMakeLists.txt b/CMakeLists.txt index 6de42b934..296b10a91 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,16 +14,14 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -cmake_minimum_required(VERSION 3.30 FATAL_ERROR) +cmake_minimum_required(VERSION 3.13 FATAL_ERROR) project(olive-editor VERSION 0.2.0 LANGUAGES CXX) - -set(CMAKE_CXX_STANDARD 23) - -set(CMAKE_CXX_SCAN_FOR_MODULES ON) -set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD ON) -find_package(expat REQUIRED) - +if(${CMAKE_BUILD_TYPE} EQUAL Debug) +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=memory -g") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=memory -g") +set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} -fsanitize=memory) +endif () option(BUILD_QT6 "Build with Qt 6 over 5 (experimental)" ON) option(BUILD_DOXYGEN "Build Doxygen documentation" OFF) option(BUILD_TESTS "Build unit tests" OFF) @@ -37,11 +35,10 @@ set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTORCC ON) - # Generates a compile_commands.json in the build dir, link that to the repo # root to enrich your IDE with clangd language server protocol functionalities set(CMAKE_EXPORT_COMPILE_COMMANDS ON) -add_subdirectory(third_party/openfx/HostSupport) + # Sanitizers add_library(olive-sanitizers INTERFACE) include(cmake/Sanitizers.cmake) @@ -110,6 +107,7 @@ list(APPEND OLIVE_INCLUDE_DIRS ${OPENEXR_INCLUDES}) list(APPEND OLIVE_LIBRARIES olivecore) list(APPEND OLIVE_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/ext/core/include) + # Link Qt set(QT_LIBRARIES Core @@ -175,7 +173,7 @@ list(APPEND OLIVE_LIBRARIES ) # Link FFmpeg -find_package(FFMPEG 7.0 REQUIRED +find_package(FFMPEG REQUIRED COMPONENTS avutil avcodec diff --git a/app/codec/ffmpeg/ffmpegdecoder.cpp b/app/codec/ffmpeg/ffmpegdecoder.cpp index 0c5e43de8..db322b385 100644 --- a/app/codec/ffmpeg/ffmpegdecoder.cpp +++ b/app/codec/ffmpeg/ffmpegdecoder.cpp @@ -26,6 +26,7 @@ extern "C" { #include #include #include +#include } #include @@ -137,7 +138,7 @@ TexturePtr FFmpegDecoder::ProcessFrameIntoTexture(AVFramePtr f, break; } - AVFrame *hw_in = f.get(); + AVFramePtr hw_in = f; VideoParams plane_params = vp; plane_params.set_channel_count(1); @@ -145,7 +146,7 @@ TexturePtr FFmpegDecoder::ProcessFrameIntoTexture(AVFramePtr f, TexturePtr y_plane = p.renderer->CreateTexture( plane_params, hw_in->data[0], hw_in->linesize[0] / px_size); - + y_plane->handleFrame(hw_in); switch (f->format) { case AV_PIX_FMT_YUV420P: case AV_PIX_FMT_YUV422P: @@ -167,8 +168,11 @@ TexturePtr FFmpegDecoder::ProcessFrameIntoTexture(AVFramePtr f, TexturePtr u_plane = p.renderer->CreateTexture( plane_params, hw_in->data[1], hw_in->linesize[1] / px_size); + u_plane->handleFrame(hw_in); + TexturePtr v_plane = p.renderer->CreateTexture( plane_params, hw_in->data[2], hw_in->linesize[2] / px_size); + v_plane->handleFrame(hw_in); ShaderJob job; job.Insert(QStringLiteral("y_channel"), @@ -204,6 +208,7 @@ TexturePtr FFmpegDecoder::ProcessFrameIntoTexture(AVFramePtr f, case AV_PIX_FMT_RGBA: case AV_PIX_FMT_RGBA64LE: // RGBA can be uploaded directly to the texture + tex->handleFrame(f); tex->Upload(f->data[0], f->linesize[0] / vp.GetBytesPerPixel()); break; } @@ -279,14 +284,17 @@ TexturePtr FFmpegDecoder::RetrieveVideoInternal(const RetrieveVideoParams &p) AVCOL_RANGE_MPEG; // Perform any CPU processing required - f = PreProcessFrame(f, p); + AVFramePtr ptr = PreProcessFrame(f, p); + f=std::move(ptr); if (!f) { // Error occurred while software scaling return nullptr; } // Finally, perform any GPU processing required - return ProcessFrameIntoTexture(f, p, original); + TexturePtr texture = ProcessFrameIntoTexture(f, p, original); + + return texture; } return nullptr; @@ -380,116 +388,77 @@ FootageDescription FFmpegDecoder::Probe(const QString &filename, VideoParams::kInterlaceNone; { - // Read at least two frames to get more information about this video stream - AVPacket *pkt = av_packet_alloc(); - AVFrame *frame = av_frame_alloc(); + // Read at least two frames to get more information about this video stream + AVPacket *pkt = av_packet_alloc(); + AVFrame *frame = av_frame_alloc(); - { - Instance instance; - instance.Open(filename_c, avstream->index); + VideoParams::Interlacing interlacing = VideoParams::kInterlaceNone; + AVRational pixel_aspect_ratio = {1, 1}; + AVRational frame_rate = avstream->avg_frame_rate; + AVPixelFormat compatible_pix_fmt = + FFmpegUtils::GetCompatiblePixelFormat( + static_cast(avstream->codecpar->format)); + bool image_is_still = false; - // Read first frame and retrieve some metadata - if (instance.GetFrame(pkt, frame) >= 0) { - // Check if video is interlaced and what field dominance it has if so - if (frame->interlaced_frame) { - if (frame->top_field_first) { - interlacing = - VideoParams::kInterlacedTopFirst; - } else { - interlacing = - VideoParams::kInterlacedBottomFirst; - } - } + { + Instance instance; + if (instance.Open(filename_c, avstream->index) != 0) + goto cleanup; - pixel_aspect_ratio = - av_guess_sample_aspect_ratio( - instance.fmt_ctx(), instance.avstream(), - frame); + AVCodecContext *avctx = instance.codec_ctx(); + interlacing = FFmpegFieldOrderToOlive(avctx->field_order); - frame_rate = av_guess_frame_rate( - instance.fmt_ctx(), instance.avstream(), - frame); + if (instance.GetFrame(pkt, frame) >= 0) { + pixel_aspect_ratio = + av_guess_sample_aspect_ratio(instance.fmt_ctx(), + instance.avstream(), frame); + frame_rate = + av_guess_frame_rate(instance.fmt_ctx(), + instance.avstream(), frame); + } - compatible_pix_fmt = - FFmpegUtils::GetCompatiblePixelFormat( - static_cast( - avstream->codecpar->format)); - } + int ret = instance.GetFrame(pkt, frame); + if (ret == AVERROR_EOF) { + image_is_still = true; + } else if (avstream->duration == AV_NOPTS_VALUE || + duration_guessed_from_bitrate) { + int64_t last_ts = frame->best_effort_timestamp; + while (instance.GetFrame(pkt, frame) >= 0 && + (!cancelled || !cancelled->IsCancelled())) + last_ts = frame->best_effort_timestamp; + avstream->duration = last_ts; + } - // Read second frame - int ret = instance.GetFrame(pkt, frame); + instance.Close(); + } - if (ret >= 0) { - // Check if we need a manual duration - if (avstream->duration == AV_NOPTS_VALUE || - duration_guessed_from_bitrate) { - if (footage_duration == AV_NOPTS_VALUE || - duration_guessed_from_bitrate) { - // Manually read through file for duration - int64_t new_dur; + cleanup: + av_frame_free(&frame); + av_packet_free(&pkt); - do { - new_dur = - frame->best_effort_timestamp; - } while (instance.GetFrame( - pkt, frame) >= 0 && - (!cancelled || - !cancelled->IsCancelled())); + VideoParams stream; + stream.set_stream_index(i); + stream.set_width(avstream->codecpar->width); + stream.set_height(avstream->codecpar->height); + stream.set_video_type(image_is_still ? VideoParams::kVideoTypeStill + : VideoParams::kVideoTypeVideo); + stream.set_format(GetNativePixelFormat(compatible_pix_fmt)); + stream.set_channel_count(GetNativeChannelCount(compatible_pix_fmt)); + stream.set_interlacing(interlacing); // <-- 已正确填充 + stream.set_pixel_aspect_ratio(pixel_aspect_ratio); + stream.set_frame_rate(frame_rate); + stream.set_start_time(avstream->start_time); + stream.set_time_base(avstream->time_base); + stream.set_duration(avstream->duration); + stream.set_color_range(avstream->codecpar->color_range == AVCOL_RANGE_JPEG + ? VideoParams::kColorRangeFull + : VideoParams::kColorRangeLimited); + stream.set_premultiplied_alpha(false); - avstream->duration = new_dur; - - } else { - // Fallback to footage duration - avstream->duration = - Timecode::rescale_timestamp_ceil( - footage_duration, - rational(1, AV_TIME_BASE), - avstream->time_base); - } - } - } else if (ret == AVERROR_EOF) { - // Video has only one frame in it, treat it like a still image - image_is_still = true; - } - - instance.Close(); - } - - av_frame_free(&frame); - av_packet_free(&pkt); + desc.AddVideoStream(stream); + image_is_still ? still_streams++ : video_streams++; } - VideoParams stream; - stream.set_stream_index(i); - stream.set_width(avstream->codecpar->width); - stream.set_height(avstream->codecpar->height); - stream.set_video_type((image_is_still) ? - VideoParams::kVideoTypeStill : - VideoParams::kVideoTypeVideo); - stream.set_format(GetNativePixelFormat(compatible_pix_fmt)); - stream.set_channel_count( - GetNativeChannelCount(compatible_pix_fmt)); - stream.set_interlacing(interlacing); - stream.set_pixel_aspect_ratio(pixel_aspect_ratio); - stream.set_frame_rate(frame_rate); - stream.set_start_time(avstream->start_time); - stream.set_time_base(avstream->time_base); - stream.set_duration(avstream->duration); - stream.set_color_range(avstream->codecpar->color_range == - AVCOL_RANGE_JPEG ? - VideoParams::kColorRangeFull : - VideoParams::kColorRangeLimited); - - // Defaults to false, requires user intervention if incorrect - stream.set_premultiplied_alpha(false); - - desc.AddVideoStream(stream); - - if (image_is_still) { - still_streams++; - } else { - video_streams++; - } } else if (avstream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { @@ -627,7 +596,7 @@ bool FFmpegDecoder::ConformAudioInternal(const QVector &filenames, } // Create resampling context AVChannelLayout layout = params.channel_layout(); - SwrContext *resampler; + SwrContext *resampler=NULL; swr_alloc_set_opts2( &resampler, &layout, FFmpegUtils::GetFFmpegSampleFormat(params.format()), @@ -835,7 +804,7 @@ AVFramePtr FFmpegDecoder::PreProcessFrame(AVFramePtr f, dest->format = f->format; dest->color_range = f->color_range; dest->colorspace = f->colorspace; - + dest->hw_frames_ctx = nullptr; if (p.divider > 1) { dest->width = VideoParams::GetScaledDimension(dest->width, p.divider); dest->height = VideoParams::GetScaledDimension(dest->height, p.divider); @@ -888,8 +857,8 @@ AVFramePtr FFmpegDecoder::PreProcessFrame(AVFramePtr f, dest->color_range == AVCOL_RANGE_JPEG ? 1 : 0, 0, 0x10000, 0x10000); } - r = sws_scale(sws_ctx_, f->data, f->linesize, 0, f->height, dest->data, - dest->linesize); + r = sws_scale_frame(sws_ctx_, dest.get(), f.get()); + if (r < 0) { FFmpegError(r); return nullptr; diff --git a/app/codec/ffmpeg/ffmpegdecoder.h b/app/codec/ffmpeg/ffmpegdecoder.h index 98c2a53b6..5bc8d4a7d 100644 --- a/app/codec/ffmpeg/ffmpegdecoder.h +++ b/app/codec/ffmpeg/ffmpegdecoder.h @@ -40,6 +40,20 @@ extern "C" { namespace olive { +// 头文件里先备好枚举映射 +static VideoParams::Interlacing FFmpegFieldOrderToOlive(AVFieldOrder fo) +{ + switch (fo) { + case AV_FIELD_TT: // 隔行,顶场在前 + return VideoParams::kInterlacedTopFirst; + case AV_FIELD_BB: // 隔行,底场在前 + return VideoParams::kInterlacedBottomFirst; + case AV_FIELD_PROGRESSIVE: + default: + return VideoParams::kInterlaceNone; + } +} + /** * @brief A Decoder derivative that wraps FFmpeg functions as on Olive decoder */ @@ -122,6 +136,10 @@ private: { return avstream_; } + AVCodecContext *codec_ctx() + { + return codec_ctx_; + } private: AVFormatContext *fmt_ctx_; diff --git a/app/codec/ffmpeg/ffmpegencoder.cpp b/app/codec/ffmpeg/ffmpegencoder.cpp index d5813fd05..92a6e0f70 100644 --- a/app/codec/ffmpeg/ffmpegencoder.cpp +++ b/app/codec/ffmpeg/ffmpegencoder.cpp @@ -22,6 +22,7 @@ extern "C" { #include #include #include +#include } #include @@ -866,7 +867,7 @@ void FFmpegEncoder::FlushEncoders() } if (fmt_ctx_) { - if (fmt_ctx_->oformat->flags & AVFMT_ALLOW_FLUSH) { + if (fmt_ctx_->oformat->flags) { int r = av_interleaved_write_frame(fmt_ctx_, nullptr); if (r < 0) { FFmpegError(tr("Failed to write interleaved packet"), r); diff --git a/app/common/ffmpegutils.h b/app/common/ffmpegutils.h index b5634278c..ae30c1986 100644 --- a/app/common/ffmpegutils.h +++ b/app/common/ffmpegutils.h @@ -85,7 +85,7 @@ public: using AVFramePtr = std::shared_ptr; inline AVFramePtr CreateAVFramePtr(AVFrame *f) { - return std::shared_ptr(f, [](AVFrame *g) { av_frame_free(&g); }); + return std::shared_ptr(f, [](AVFrame *g) { av_frame_free(&g); }); } inline AVFramePtr CreateAVFramePtr() { diff --git a/app/core.cpp b/app/core.cpp index 4a2eb6cea..105e93da5 100644 --- a/app/core.cpp +++ b/app/core.cpp @@ -774,6 +774,7 @@ void Core::StartGUI(bool full_screen) connect(qApp, &QApplication::focusChanged, PanelManager::instance(), &PanelManager::FocusChanged); + KDDockWidgets::initFrontend(KDDockWidgets::FrontendType::QtWidgets); // Set KDDockWidgets flags auto &config = KDDockWidgets::Config::self(); auto flags = config.flags(); diff --git a/app/main.cpp b/app/main.cpp index 90f5e28a2..e6cb7bfb5 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -143,6 +143,7 @@ int decompress_project(const QString &project) int main(int argc, char *argv[]) { + // Set up debug handler qInstallMessageHandler(olive::DebugHandler); diff --git a/app/panel/panel.cpp b/app/panel/panel.cpp index fc0b078e5..9495e9378 100644 --- a/app/panel/panel.cpp +++ b/app/panel/panel.cpp @@ -25,23 +25,26 @@ #include #include #include +#include "Window_p.h" #include "panel/panelmanager.h" +#include + namespace olive { -#define super KDDockWidgets::DockWidget +#define super KDDockWidgets::QtWidgets::DockWidget PanelWidget::PanelWidget(const QString &object_name) : super(object_name) , border_visible_(false) , signal_instead_of_close_(false) { - setFocusPolicy(Qt::ClickFocus); + View::setFocusPolicy(Qt::ClickFocus); connect(this, &PanelWidget::shown, this, - static_cast(&PanelWidget::setFocus)); + reinterpret_cast(&PanelWidget::setFocus)); PanelManager::instance()->RegisterPanel(this); } @@ -123,6 +126,15 @@ void PanelWidget::changeEvent(QEvent *e) if (e->type() == QEvent::LanguageChange) { Retranslate(); } + + if (e->type() == QEvent::WindowStateChange) { + if (isVisible() && !isMinimized()) { + emit shown(Qt::OtherFocusReason); + } + else { + emit hidden(); + } + } super::changeEvent(e); } diff --git a/app/panel/panel.h b/app/panel/panel.h index 306883129..a8839081b 100644 --- a/app/panel/panel.h +++ b/app/panel/panel.h @@ -19,18 +19,23 @@ #ifndef PANEL_WIDGET_H #define PANEL_WIDGET_H +#include "KDDockWidgets/src/core/Window_p.h" +#include "KDDockWidgets/src/qtwidgets/views/TabBar.h" + #include #include #include "common/define.h" +#include + namespace olive { /** * @brief A widget that is always dockable within the MainWindow. */ -class PanelWidget : public KDDockWidgets::DockWidget { +class PanelWidget : public KDDockWidgets::QtWidgets::DockWidget { Q_OBJECT public: /** @@ -277,7 +282,8 @@ public: signals: void CloseRequested(); - + void shown(Qt::FocusReason reason); + void hidden(); protected: /** * @brief paintEvent @@ -321,7 +327,7 @@ protected slots: * String to set the subtitle to */ void SetSubtitle(const QString &t); - +protected slots: private: /** * @brief Internal function that sets the QDockWidget's window title whenever the title/subtitle change. @@ -337,6 +343,10 @@ private: bool border_visible_; bool signal_instead_of_close_; + + QMetaObject::Connection m_tabBarConnection; + QMetaObject::Connection m_windowConnection; + bool m_lastVisibleState = false; }; } diff --git a/app/panel/project/project.cpp b/app/panel/project/project.cpp index 3852beb08..9303c89a8 100644 --- a/app/panel/project/project.cpp +++ b/app/panel/project/project.cpp @@ -178,7 +178,7 @@ void ProjectPanel::ItemDoubleClickSlot(Node *item) PanelManager::instance()->MostRecentlyFocused(); panel->ConnectViewerNode(static_cast(item)); panel->raise(); - panel->setFocus(); + panel->setFocus(Qt::FocusReason::MouseFocusReason); } else if (dynamic_cast(item)) { // Open this sequence in the Timeline Core::instance()->main_window()->OpenSequence( diff --git a/app/render/texture.h b/app/render/texture.h index 7968a5354..c0481dcb4 100644 --- a/app/render/texture.h +++ b/app/render/texture.h @@ -19,6 +19,8 @@ #ifndef RENDERTEXTURE_H #define RENDERTEXTURE_H +#include "common/ffmpegutils.h" + #include #include @@ -148,7 +150,10 @@ public: { return job_; } - + void handleFrame(AVFramePtr ptr) + { + frame_=ptr; + } private: Renderer *renderer_; @@ -157,6 +162,8 @@ private: QVariant id_; AcceleratedJob *job_; + + AVFramePtr frame_; }; } diff --git a/app/widget/timebased/timescaledobject.cpp b/app/widget/timebased/timescaledobject.cpp index a9b204cfd..6e7f6620a 100644 --- a/app/widget/timebased/timescaledobject.cpp +++ b/app/widget/timebased/timescaledobject.cpp @@ -56,6 +56,9 @@ const double &TimeScaledObject::timebase_dbl() const rational TimeScaledObject::SceneToTime(const double &x, const double &x_scale, const rational &timebase, bool round) { + if (timebase.isNull()) { + return rational(); + } double unscaled_time = x / x_scale / timebase.toDouble(); // Adjust screen point by scale and timebase @@ -85,16 +88,25 @@ rational TimeScaledObject::SceneToTimeNoGrid(const double &x, double TimeScaledObject::TimeToScene(const rational &time) const { + if (timebase_.isNull()) { + return 0.0; + } return time.toDouble() * scale_; } rational TimeScaledObject::SceneToTime(const double &x, bool round) const { + if (timebase_.isNull()) { + return rational(); + } return SceneToTime(x, scale_, timebase_, round); } rational TimeScaledObject::SceneToTimeNoGrid(const double &x) const { + if (timebase_.isNull()) { + return rational::fromDouble(x / scale_); + } return SceneToTimeNoGrid(x, scale_); } diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index 9da6a0ed5..5d057d77e 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -1201,8 +1201,11 @@ void ViewerWidget::UpdateMinimumScale() // Avoids divide by zero SetMinimumScale(0); } else { - SetMinimumScale(static_cast(ruler()->width()) / - GetConnectedNode()->GetLength().toDouble()); + double min_scale = static_cast(ruler()->width()) / + GetConnectedNode()->GetLength().toDouble(); + // Ensure min_scale doesn't exceed max_scale to prevent crash + min_scale = qMin(min_scale, GetMaximumScale()); + SetMinimumScale(min_scale); } } diff --git a/app/widget/viewer/viewerdisplay.cpp b/app/widget/viewer/viewerdisplay.cpp index 32fe596f1..eafae8da5 100644 --- a/app/widget/viewer/viewerdisplay.cpp +++ b/app/widget/viewer/viewerdisplay.cpp @@ -372,7 +372,7 @@ bool ViewerDisplayWidget::eventFilter(QObject *o, QEvent *e) void ViewerDisplayWidget::OnPaint() { // Clear background to empty - QColor bg_color = show_widget_background_ ? palette().window().color() : + QColor bg_color = show_widget_background_ ? palette().window().color() : Qt::black; renderer()->ClearDestination(nullptr, bg_color.redF(), bg_color.greenF(), bg_color.blueF()); diff --git a/app/window/mainwindow/mainwindow.cpp b/app/window/mainwindow/mainwindow.cpp index 825d707b4..15e7a4487 100644 --- a/app/window/mainwindow/mainwindow.cpp +++ b/app/window/mainwindow/mainwindow.cpp @@ -27,15 +27,17 @@ #include #endif +#include "KDDockWidgets/src/qtwidgets/Window_p.h" #include "dialog/about/about.h" #include "mainmenu.h" #include "mainstatusbar.h" +#include "KDDockWidgets/src/LayoutSaver.h" #include "timeline/timelineundoworkarea.h" namespace olive { -#define super KDDockWidgets::MainWindow +#define super KDDockWidgets::QtWidgets::MainWindow MainWindow::MainWindow(QWidget *parent) : super(QStringLiteral("OliveMain"), KDDockWidgets::MainWindowOption_None, @@ -93,7 +95,7 @@ MainWindow::MainWindow(QWidget *parent) // emit the "shown" signal before emitting the "hidden" signals, resulting // in Core thinking there are -1 pixel samplers open. To mitigate that, // we force "shown" to emit ourselves here. - emit pixel_sampler_panel_->shown(); + emit pixel_sampler_panel_->shown(Qt::OtherFocusReason); // Make node-related connections connect(node_panel_, &NodePanel::NodeSelectionChangedWithContexts, @@ -380,7 +382,7 @@ void MainWindow::ToggleMaximizedPanel() premaximized_state_.clear(); currently_focused_panel->raise(); - currently_focused_panel->setFocus(); + currently_focused_panel->setFocus(Qt::ActiveWindowFocusReason); PanelManager::instance()->SetSuppressChangedSignal(false); } @@ -428,7 +430,7 @@ void MainWindow::SetProject(Project *p) project_panel_->set_project(p); if (project_) { - project_panel_->setFocus(); + project_panel_->setFocus(Qt::OtherFocusReason); } } diff --git a/app/window/mainwindow/mainwindow.h b/app/window/mainwindow/mainwindow.h index 54978211d..5c4a5272a 100644 --- a/app/window/mainwindow/mainwindow.h +++ b/app/window/mainwindow/mainwindow.h @@ -51,7 +51,7 @@ namespace olive /** * @brief Olive's main window responsible for docking widgets and the main menu bar. */ -class MainWindow : public KDDockWidgets::MainWindow { +class MainWindow : public KDDockWidgets::QtWidgets::MainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); diff --git a/ext/KDDockWidgets b/ext/KDDockWidgets index 8d2d0a576..0e9723b96 160000 --- a/ext/KDDockWidgets +++ b/ext/KDDockWidgets @@ -1 +1 @@ -Subproject commit 8d2d0a5764f8393cc148a2296d511276a8ffe559 +Subproject commit 0e9723b96b100deeb03977db0f587ad207d0bef4 diff --git a/ext/core b/ext/core index 08eeee5fa..50caae473 160000 --- a/ext/core +++ b/ext/core @@ -1 +1 @@ -Subproject commit 08eeee5fa90bed55442f2be9e324482f0be0a73c +Subproject commit 50caae473d6de11d129f1fb6a14d2c73dac83f51