1 /*
2 Gwenview: an image viewer
3 Copyright 2007-2012 Aurélien Gâteau <agateau@kde.org>
4 
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 
19 */
20 #include <config-gwenview.h>
21 
22 // Qt
23 #include <QApplication>
24 #include <QCommandLineParser>
25 #include <QPointer>
26 #include <QScopedPointer>
27 #include <QStringList>
28 #include <QTemporaryDir>
29 #include <QUrl>
30 
31 // KF
32 #include <KAboutData>
33 #include <KActionCollection>
34 #include <KIO/CopyJob>
35 #include <KLocalizedString>
36 
37 // Local
38 #include "mainwindow.h"
39 #include <lib/about.h>
40 #include <lib/gwenviewconfig.h>
41 
42 #ifdef HAVE_FITS
43 // This hack is needed to include the fitsplugin moc file in main.cpp
44 // Otherwise the linker complains about: undefined reference to `qt_static_plugin_FitsPlugin()'
45 // This symbol is defined in the moc file, but it is not a visible symbol after libgwenview is linked.
46 // If Q_IMPORT_PLUGIN(FitsPlugin) is moved to the library, gwenview crashes on the first call to FitsPlugin()
47 // when the vtable is looked up in the plugin registration.
48 #include <../lib/imageformats/moc_fitsplugin.cpp>
49 #endif
50 
51 // To shut up libtiff
52 #ifdef HAVE_TIFF
53 #include <QLoggingCategory>
54 #include <tiffio.h>
55 
56 namespace
57 {
58 Q_DECLARE_LOGGING_CATEGORY(LibTiffLog)
59 Q_LOGGING_CATEGORY(LibTiffLog, "gwenview.libtiff", QtWarningMsg)
60 
handleTiffWarning(const char * mod,const char * fmt,va_list ap)61 static void handleTiffWarning(const char *mod, const char *fmt, va_list ap)
62 {
63     qCDebug(LibTiffLog) << "Warning:" << mod << QString::vasprintf(fmt, ap);
64 }
65 
handleTiffError(const char * mod,const char * fmt,va_list ap)66 static void handleTiffError(const char *mod, const char *fmt, va_list ap)
67 {
68     // Since we're doing thumbnails, we don't really care about warnings by default either
69     qCWarning(LibTiffLog) << "Error" << mod << QString::vasprintf(fmt, ap);
70 }
71 
72 } // namespace
73 #endif
74 
75 class StartHelper
76 {
77 public:
StartHelper(const QStringList & args,bool fullscreen,bool slideshow)78     StartHelper(const QStringList &args, bool fullscreen, bool slideshow)
79         : mFullScreen(false)
80         , mSlideShow(false)
81     {
82         if (!args.isEmpty()) {
83             parseArgs(args, fullscreen, slideshow);
84         }
85     }
86 
parseArgs(const QStringList & args,bool fullscreen,bool slideshow)87     void parseArgs(const QStringList &args, bool fullscreen, bool slideshow)
88     {
89         if (args.count() > 1) {
90             // Create a temp dir containing links to url args
91             mMultipleUrlsDir.reset(new QTemporaryDir);
92             mUrl = QUrl::fromLocalFile(mMultipleUrlsDir->path());
93             QList<QUrl> list;
94             QStringList tmpArgs = args;
95             tmpArgs.removeDuplicates();
96             QStringList fileNames;
97             for (const QString &url : qAsConst(tmpArgs)) {
98                 QUrl fileUrl = QUrl::fromUserInput(url, QDir::currentPath(), QUrl::AssumeLocalFile);
99                 if (!fileNames.contains(fileUrl.fileName())) {
100                     fileNames << fileUrl.fileName();
101                     list << fileUrl;
102                 }
103             }
104 
105             KIO::CopyJob *job = KIO::link(list, mUrl);
106             job->exec();
107         } else {
108             QString tmpArg = args.first();
109             mUrl = QUrl::fromUserInput(tmpArg, QDir::currentPath(), QUrl::AssumeLocalFile);
110         }
111 
112         if (mUrl.isValid() && (fullscreen || slideshow)) {
113             mFullScreen = true;
114             if (slideshow) {
115                 mSlideShow = true;
116             }
117         }
118     }
119 
createMainWindow()120     void createMainWindow()
121     {
122         mMainWindow = new Gwenview::MainWindow();
123         if (mUrl.isValid()) {
124             mMainWindow->setInitialUrl(mUrl);
125         } else {
126             mMainWindow->showStartMainPage();
127         }
128 
129         mMainWindow->show();
130         if (mFullScreen) {
131             mMainWindow->actionCollection()->action(QStringLiteral("fullscreen"))->trigger();
132         } else {
133             mMainWindow->show();
134         }
135 
136         if (mSlideShow) {
137             mMainWindow->startSlideShow();
138         }
139     }
140 
141 private:
142     QUrl mUrl;
143     bool mFullScreen;
144     bool mSlideShow;
145     QScopedPointer<QTemporaryDir> mMultipleUrlsDir;
146     QPointer<Gwenview::MainWindow> mMainWindow;
147 };
148 
main(int argc,char * argv[])149 int main(int argc, char *argv[])
150 {
151 #ifdef HAVE_TIFF
152     TIFFSetWarningHandler(handleTiffWarning);
153     TIFFSetErrorHandler(handleTiffError);
154 #endif
155 
156     /**
157      * enable high dpi support
158      */
159     QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps, true);
160     QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling, true);
161     QCoreApplication::setAttribute(Qt::AA_CompressHighFrequencyEvents, true);
162 
163     QApplication app(argc, argv);
164     KLocalizedString::setApplicationDomain("gwenview");
165     QScopedPointer<KAboutData> aboutData(Gwenview::createAboutData(QStringLiteral("gwenview"), /* component name */
166                                                                    i18n("Gwenview") /* display name */
167                                                                    ));
168     aboutData->setShortDescription(i18n("An Image Viewer"));
169 
170     aboutData->setOrganizationDomain(QByteArray("kde.org"));
171     KAboutData::setApplicationData(*aboutData);
172     QApplication::setWindowIcon(QIcon::fromTheme(QStringLiteral("gwenview"), app.windowIcon()));
173 
174     QCommandLineParser parser;
175     aboutData.data()->setupCommandLine(&parser);
176     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("f") << QStringLiteral("fullscreen"), i18n("Start in fullscreen mode")));
177     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("s") << QStringLiteral("slideshow"), i18n("Start in slideshow mode")));
178     parser.addPositionalArgument("url", i18n("A starting file or folders"));
179     parser.process(app);
180     aboutData.data()->processCommandLine(&parser);
181 
182     // startHelper must live for the whole life of the application
183     StartHelper startHelper(parser.positionalArguments(),
184                             parser.isSet(QStringLiteral("f")) ? true : Gwenview::GwenviewConfig::fullScreenModeActive(),
185                             parser.isSet(QStringLiteral("s")));
186     if (app.isSessionRestored()) {
187         kRestoreMainWindows<Gwenview::MainWindow>();
188     } else {
189         startHelper.createMainWindow();
190     }
191 
192     // Workaround for QTBUG-38613
193     // Another solution would be to port BalooSemanticInfoBackend::refreshAllTags
194     // to be async rather than using exec().
195     qApp->sendPostedEvents(nullptr, QEvent::DeferredDelete);
196 
197     return app.exec();
198 }
199 
200 #ifdef HAVE_FITS
201 Q_IMPORT_PLUGIN(FitsPlugin)
202 #endif
203