From 4df37c035f123f99b8438826c1b4cfe8ea0b910f Mon Sep 17 00:00:00 2001 From: tsujan Date: Thu, 23 Apr 2020 02:24:49 +0430 Subject: [PATCH] Added an option for single window mode (#1097) With the option enabled, folders will be opened in new tabs of an existing window (the last focused or created window) if an external app calls pcmanfm-qt, the command-line is used, or folders are clicked on desktop. The option is disabled by default. The user could still open folders in new windows by using the context menu or adding the `-n/--new-window` command-line option. Actually, `-n/--new-window` makes sense only after this change. Also, the pointer to the last active window is changed to a guarded pointer. An ordinary pointer was a potential cause of crash but, luckily, it couldn't cause a crash before this feature. Closes https://github.com/lxqt/pcmanfm-qt/issues/1094 and fixes https://github.com/lxqt/pcmanfm-qt/issues/1096 --- pcmanfm/application.cpp | 23 +++++++++++++-- pcmanfm/launcher.cpp | 1 + pcmanfm/launcher.h | 4 +++ pcmanfm/mainwindow.cpp | 2 +- pcmanfm/mainwindow.h | 3 +- pcmanfm/preferences.ui | 12 +++++++- pcmanfm/preferencesdialog.cpp | 2 ++ pcmanfm/settings.cpp | 3 ++ pcmanfm/settings.h | 9 ++++++ pcmanfm/view.cpp | 53 +++++++++++++++++++++++++---------- pcmanfm/view.h | 1 + 11 files changed, 93 insertions(+), 20 deletions(-) diff --git a/pcmanfm/application.cpp b/pcmanfm/application.cpp index 96c1192d..feeefb5d 100644 --- a/pcmanfm/application.cpp +++ b/pcmanfm/application.cpp @@ -505,7 +505,7 @@ void Application::connectToServer() { dlg->show(); } -void Application::launchFiles(QString cwd, QStringList paths, bool /*inNewWindow*/) { +void Application::launchFiles(QString cwd, QStringList paths, bool inNewWindow) { Fm::FilePathList pathList; Fm::FilePath cwd_path; QStringList::iterator it; @@ -530,7 +530,26 @@ void Application::launchFiles(QString cwd, QStringList paths, bool /*inNewWindow pathList.push_back(std::move(path)); } - Launcher(nullptr).launchPaths(nullptr, pathList); + if(!inNewWindow && settings_.singleWindowMode()) { + MainWindow* window = MainWindow::lastActive(); + // if there is no last active window, find the last created window + if(window == nullptr) { + QWidgetList windows = topLevelWidgets(); + for(int i = 0; i < windows.size(); ++i) { + auto win = windows.at(windows.size() - 1 - i); + if(win->inherits("PCManFM::MainWindow")) { + window = static_cast(win); + break; + } + } + } + auto launcher = Launcher(window); + launcher.openInNewTab(); + launcher.launchPaths(nullptr, pathList); + } + else { + Launcher(nullptr).launchPaths(nullptr, pathList); + } } void Application::openFolders(Fm::FileInfoList files) { diff --git a/pcmanfm/launcher.cpp b/pcmanfm/launcher.cpp index 94d51855..f2ab6c7d 100644 --- a/pcmanfm/launcher.cpp +++ b/pcmanfm/launcher.cpp @@ -67,6 +67,7 @@ bool Launcher::openFolder(GAppLaunchContext* /*ctx*/, const Fm::FileInfoList& fo } mainWindow->show(); mainWindow->raise(); + mainWindow->activateWindow(); openInNewTab_ = false; return true; } diff --git a/pcmanfm/launcher.h b/pcmanfm/launcher.h index b499f7c1..6a4e6adf 100644 --- a/pcmanfm/launcher.h +++ b/pcmanfm/launcher.h @@ -32,6 +32,10 @@ class Launcher : public Fm::FileLauncher { Launcher(MainWindow* mainWindow = nullptr); ~Launcher(); + bool hasMainWindow() const { + return mainWindow_ != nullptr; + } + void openInNewTab() { openInNewTab_ = true; } diff --git a/pcmanfm/mainwindow.cpp b/pcmanfm/mainwindow.cpp index ed995f84..b3666d40 100644 --- a/pcmanfm/mainwindow.cpp +++ b/pcmanfm/mainwindow.cpp @@ -117,7 +117,7 @@ void ViewFrame::removeTopBar() { //====================================================================== // static -MainWindow* MainWindow::lastActive_ = nullptr; +QPointer MainWindow::lastActive_; MainWindow::MainWindow(Fm::FilePath path): QMainWindow(), diff --git a/pcmanfm/mainwindow.h b/pcmanfm/mainwindow.h index 20f981c8..90c78217 100644 --- a/pcmanfm/mainwindow.h +++ b/pcmanfm/mainwindow.h @@ -21,6 +21,7 @@ #define FM_MAIN_WINDOW_H #include "ui_main-win.h" +#include #include #include #include @@ -268,7 +269,7 @@ protected Q_SLOTS: // not from another window. So, we get the mode at the start and keep it. bool splitView_; - static MainWindow* lastActive_; + static QPointer lastActive_; }; } diff --git a/pcmanfm/preferences.ui b/pcmanfm/preferences.ui index 74df0a45..5130cf5b 100644 --- a/pcmanfm/preferences.ui +++ b/pcmanfm/preferences.ui @@ -214,6 +214,16 @@ + + + + Open folders in new tabs as far as possible + + + Single window mode + + + @@ -469,7 +479,7 @@ A space is also reserved for 3 lines of text. - + diff --git a/pcmanfm/preferencesdialog.cpp b/pcmanfm/preferencesdialog.cpp index cd7c9132..95179c5c 100644 --- a/pcmanfm/preferencesdialog.cpp +++ b/pcmanfm/preferencesdialog.cpp @@ -224,6 +224,7 @@ void PreferencesDialog::initBehaviorPage(Settings& settings) { ui.confirmTrash->setChecked(settings.confirmTrash()); ui.quickExec->setChecked(settings.quickExec()); ui.selectNewFiles->setChecked(settings.selectNewFiles()); + ui.singleWindowMode->setChecked(settings.singleWindowMode()); // app restart warning connect(ui.quickExec, &QAbstractButton::toggled, [this, &settings] (bool checked) { @@ -338,6 +339,7 @@ void PreferencesDialog::applyBehaviorPage(Settings& settings) { settings.setConfirmTrash(ui.confirmTrash->isChecked()); settings.setQuickExec(ui.quickExec->isChecked()); settings.setSelectNewFiles(ui.selectNewFiles->isChecked()); + settings.setSingleWindowMode(ui.singleWindowMode->isChecked()); } void PreferencesDialog::applyThumbnailPage(Settings& settings) { diff --git a/pcmanfm/settings.cpp b/pcmanfm/settings.cpp index 1217e122..5f02f9de 100644 --- a/pcmanfm/settings.cpp +++ b/pcmanfm/settings.cpp @@ -55,6 +55,7 @@ Settings::Settings(): supportTrash_(Fm::uriExists("trash:///")), // check if trash:/// is supported fallbackIconThemeName_(), useFallbackIconTheme_(QIcon::themeName().isEmpty() || QIcon::themeName() == QLatin1String("hicolor")), + singleWindowMode_(false), bookmarkOpenMethod_(OpenInCurrentTab), suCommand_(), terminal_(), @@ -212,6 +213,7 @@ bool Settings::loadFile(QString filePath) { settings.endGroup(); settings.beginGroup(QStringLiteral("Behavior")); + singleWindowMode_ = settings.value(QStringLiteral("SingleWindowMode"), false).toBool(); bookmarkOpenMethod_ = bookmarkOpenMethodFromString(settings.value(QStringLiteral("BookmarkOpenMethod")).toString()); // settings for use with libfm useTrash_ = settings.value(QStringLiteral("UseTrash"), true).toBool(); @@ -360,6 +362,7 @@ bool Settings::saveFile(QString filePath) { settings.endGroup(); settings.beginGroup(QStringLiteral("Behavior")); + settings.setValue(QStringLiteral("SingleWindowMode"), singleWindowMode_); settings.setValue(QStringLiteral("BookmarkOpenMethod"), QString::fromUtf8(bookmarkOpenMethodToString(bookmarkOpenMethod_))); // settings for use with libfm settings.setValue(QStringLiteral("UseTrash"), useTrash_); diff --git a/pcmanfm/settings.h b/pcmanfm/settings.h index dc333af5..0df86714 100644 --- a/pcmanfm/settings.h +++ b/pcmanfm/settings.h @@ -175,6 +175,14 @@ class Settings : public QObject { fallbackIconThemeName_ = iconThemeName; } + bool singleWindowMode() const { + return singleWindowMode_; + } + + void setSingleWindowMode(bool singleWindowMode) { + singleWindowMode_ = singleWindowMode; + } + OpenDirTargetType bookmarkOpenMethod() { return bookmarkOpenMethod_; } @@ -986,6 +994,7 @@ class Settings : public QObject { QString fallbackIconThemeName_; bool useFallbackIconTheme_; + bool singleWindowMode_; OpenDirTargetType bookmarkOpenMethod_; QString suCommand_; QString terminal_; diff --git a/pcmanfm/view.cpp b/pcmanfm/view.cpp index 51c4c040..45e66275 100644 --- a/pcmanfm/view.cpp +++ b/pcmanfm/view.cpp @@ -42,15 +42,12 @@ View::~View() { void View::onFileClicked(int type, const std::shared_ptr& fileInfo) { if(type == MiddleClick) { - if(fileInfo->isDir() && fileLauncher()) { + if(fileInfo->isDir()) { // fileInfo->path() shouldn't be used directly because // it won't work in places like computer:/// or network:/// Fm::FileInfoList files; files.emplace_back(fileInfo); - if(auto launcher = dynamic_cast(fileLauncher())) { - launcher->openInNewTab(); - } - fileLauncher()->launchFiles(nullptr, std::move(files)); + launchFiles(std::move(files), true); } } else { @@ -68,7 +65,7 @@ void View::onFileClicked(int type, const std::shared_ptr& fi return; } } - fileLauncher()->launchFiles(nullptr, std::move(files)); + launchFiles(std::move(files)); } } } @@ -80,20 +77,14 @@ void View::onFileClicked(int type, const std::shared_ptr& fi void View::onNewWindow() { Fm::FileMenu* menu = static_cast(sender()->parent()); - // FIXME: open the files in a new window Application* app = static_cast(qApp); app->openFolders(menu->files()); } void View::onNewTab() { - if(fileLauncher()) { - Fm::FileMenu* menu = static_cast(sender()->parent()); - auto files = menu->files(); - if(auto launcher = dynamic_cast(fileLauncher())) { - launcher->openInNewTab(); - } - fileLauncher()->launchFiles(nullptr, std::move(files)); - } + Fm::FileMenu* menu = static_cast(sender()->parent()); + auto files = menu->files(); + launchFiles(std::move(files), true); } void View::onOpenInTerminal() { @@ -179,4 +170,36 @@ void View::updateFromSettings(Settings& settings) { } } +void View::launchFiles(Fm::FileInfoList files, bool inNewTabs) { + if(fileLauncher()) { + if(auto launcher = dynamic_cast(fileLauncher())) { + // this happens on desktop + if(!launcher->hasMainWindow() + && (inNewTabs + || static_cast(qApp)->settings().singleWindowMode())) { + MainWindow* window = MainWindow::lastActive(); + // if there is no last active window, find the last created window + if(window == nullptr) { + QWidgetList windows = qApp->topLevelWidgets(); + for(int i = 0; i < windows.size(); ++i) { + auto win = windows.at(windows.size() - 1 - i); + if(win->inherits("PCManFM::MainWindow")) { + window = static_cast(win); + break; + } + } + } + auto tempLauncher = Launcher(window); + tempLauncher.openInNewTab(); + tempLauncher.launchFiles(nullptr, std::move(files)); + return; + } + if(inNewTabs) { + launcher->openInNewTab(); + } + } + fileLauncher()->launchFiles(nullptr, std::move(files)); + } +} + } // namespace PCManFM diff --git a/pcmanfm/view.h b/pcmanfm/view.h index 677683a6..35ca7264 100644 --- a/pcmanfm/view.h +++ b/pcmanfm/view.h @@ -62,6 +62,7 @@ protected Q_SLOTS: virtual void prepareFolderMenu(Fm::FolderMenu* menu); private: + void launchFiles(Fm::FileInfoList files, bool inNewTabs = false); };