23 ** |
23 ** |
24 ****************************************************************************/ |
24 ****************************************************************************/ |
25 |
25 |
26 #include "hbsplashgenerator_p.h" |
26 #include "hbsplashgenerator_p.h" |
27 #include "hbsplashdirs_p.h" |
27 #include "hbsplashdirs_p.h" |
|
28 #include "hbsplashdefs_p.h" |
28 #include "hbmainwindow.h" |
29 #include "hbmainwindow.h" |
29 #include "hbmainwindow_p.h" |
30 #include "hbmainwindow_p.h" |
30 #include "hbinstance.h" |
31 #include "hbinstance.h" |
31 #include "hbtheme.h" |
32 #include "hbtheme.h" |
32 #include "hbeffectinternal_p.h" |
33 #include "hbeffectinternal_p.h" |
43 #include <QPainter> |
44 #include <QPainter> |
44 #include <QDir> |
45 #include <QDir> |
45 #include <QFile> |
46 #include <QFile> |
46 #include <QFileInfo> |
47 #include <QFileInfo> |
47 #include <QSet> |
48 #include <QSet> |
|
49 #include <QSettings> |
48 #include <QTranslator> |
50 #include <QTranslator> |
49 #include <QLocale> |
51 #include <QLocale> |
50 #include <QTimer> |
52 #include <QTimer> |
|
53 |
|
54 #if defined(Q_OS_SYMBIAN) |
|
55 #include <f32file.h> |
|
56 #include <coemain.h> |
|
57 #endif |
51 |
58 |
52 const char *last_theme_key = "lasttheme"; |
59 const char *last_theme_key = "lasttheme"; |
53 const char *last_lang_key = "lastlang"; |
60 const char *last_lang_key = "lastlang"; |
54 const char *last_file_count_key = "lastfilecount"; |
61 const char *last_file_count_key = "lastfilecount"; |
55 const char *last_output_dir_key = "lastoutdir"; |
62 const char *last_output_dir_key = "lastoutdir"; |
56 |
63 |
57 HbSplashGenerator::HbSplashGenerator() |
64 HbSplashGenerator::HbSplashGenerator() |
58 : mBusy(false), mForceRegen(false), mMainWindow(0), mFirstRegenerate(true), |
65 : mBusy(false), mForceRegen(false), mMainWindow(0), mFirstRegenerate(true) |
59 mSettings("Nokia", "HbSplash") |
66 { |
60 { |
67 #if defined(Q_OS_SYMBIAN) |
|
68 CCoeEnv::Static()->FsSession().CreatePrivatePath(EDriveC); |
|
69 QString iniFileName = QString("c:/private/%1/hbsplashgen.ini") |
|
70 .arg(QString::number(hbsplash_server_uid3.iUid, 16)); |
|
71 mSettings = new QSettings(iniFileName, QSettings::IniFormat, this); |
|
72 #else |
|
73 mSettings = new QSettings("Nokia", "HbSplash", this); |
|
74 #endif |
61 // Effects on decorators (started when they are shown) would ruin |
75 // Effects on decorators (started when they are shown) would ruin |
62 // the screenshot. So disable everything (except the orientation |
76 // the screenshot. So disable everything (except the orientation |
63 // switch effect which is needed for a proper rotated image). |
77 // switch effect which is needed for a proper rotated image). |
64 HbEffectInternal::setEffectsEnabled(false); |
78 HbEffectInternal::setEffectsEnabled(false); |
65 } |
79 } |
127 |
141 |
128 // Regenerate screens on startup only when the theme, the language, the |
142 // Regenerate screens on startup only when the theme, the language, the |
129 // number of files in the splash screen directory, or the splash screen |
143 // number of files in the splash screen directory, or the splash screen |
130 // directory path is different than the recorded values. (or when |
144 // directory path is different than the recorded values. (or when |
131 // regeneration is forced via command line arg) |
145 // regeneration is forced via command line arg) |
132 QString lastTheme = mSettings.value(QLatin1String(last_theme_key)).toString(); |
146 QString lastTheme = mSettings->value(QLatin1String(last_theme_key)).toString(); |
133 QString lastLang = mSettings.value(QLatin1String(last_lang_key)).toString(); |
147 QString lastLang = mSettings->value(QLatin1String(last_lang_key)).toString(); |
134 int lastFileCount = mSettings.value(QLatin1String(last_file_count_key)).toInt(); |
148 int lastFileCount = mSettings->value(QLatin1String(last_file_count_key)).toInt(); |
135 QString lastOutputDir = mSettings.value(QLatin1String(last_output_dir_key)).toString(); |
149 QString lastOutputDir = mSettings->value(QLatin1String(last_output_dir_key)).toString(); |
136 QString currentTheme = theme->name(); |
150 QString currentTheme = theme->name(); |
137 QString currentLang = QLocale::system().name(); |
151 QString currentLang = QLocale::system().name(); |
138 QString currentOutputDir = hbsplash_output_dir(); |
152 QString currentOutputDir = hbsplash_output_dir(); |
139 int currentFileCount = updateOutputDirContents(currentOutputDir); |
153 int currentFileCount = updateOutputDirContents(currentOutputDir); |
140 qDebug() << PRE << "last regen:" << lastTheme << lastLang << lastFileCount << lastOutputDir |
154 qDebug() << PRE << "last regen:" << lastTheme << lastLang << lastFileCount << lastOutputDir |
161 { |
175 { |
162 QString themeName = hbInstance->theme()->name(); |
176 QString themeName = hbInstance->theme()->name(); |
163 qDebug() << PRE << "regenerate() theme:" << themeName; |
177 qDebug() << PRE << "regenerate() theme:" << themeName; |
164 if (!themeName.isEmpty()) { |
178 if (!themeName.isEmpty()) { |
165 try { |
179 try { |
|
180 emit regenerateStarted(); |
166 QTime queuePrepTime; |
181 QTime queuePrepTime; |
167 queuePrepTime.start(); |
182 queuePrepTime.start(); |
168 // Delete existing splash screens. This is important because apps |
183 // Delete existing splash screens. This is important because apps |
169 // should never pick up a screen with the previous theme or |
184 // should never pick up a screen with the previous theme or |
170 // language. If the generation of the new screens (at least the |
185 // language. If the generation of the new screens (at least the |
200 cleanup(); |
215 cleanup(); |
201 } |
216 } |
202 } |
217 } |
203 } |
218 } |
204 |
219 |
205 void HbSplashGenerator::regenerateOne(const QString &splashmlFileName) |
220 void HbSplashGenerator::regenerateOne(const QString &splashmlFileName, const QString &customTrDir) |
206 { |
221 { |
207 mQueue.clear(); |
222 mQueue.clear(); |
208 QueueItem item(hbInstance->theme()->name(), Qt::Vertical); |
223 QueueItem item(hbInstance->theme()->name(), Qt::Vertical); |
209 item.mWorkDirForSingleFileRegen = QFileInfo(splashmlFileName).path(); // e.g. for translations |
224 QString path = QFileInfo(splashmlFileName).path(); |
|
225 item.mCustomTrDirs.append(path); |
|
226 if (!customTrDir.isEmpty()) { |
|
227 item.mCustomTrDirs.append(customTrDir); |
|
228 } |
210 parseSplashml(splashmlFileName, item); |
229 parseSplashml(splashmlFileName, item); |
211 item.mDocmlFileName = QDir(item.mWorkDirForSingleFileRegen).filePath(item.mDocmlFileName); |
230 item.mDocmlFileName = QDir(path).filePath(item.mDocmlFileName); |
212 mQueue.enqueue(item); // generate it regardless of the fixed orientation setting |
231 mQueue.enqueue(item); // generate it regardless of the fixed orientation setting |
213 item.mOrientation = Qt::Horizontal; |
232 item.mOrientation = Qt::Horizontal; |
214 mQueue.enqueue(item); |
233 mQueue.enqueue(item); |
215 QMetaObject::invokeMethod(this, "processQueue", Qt::QueuedConnection); |
234 QMetaObject::invokeMethod(this, "processQueue", Qt::QueuedConnection); |
216 } |
235 } |
243 // If the queue is empty then the splash regeneraton is complete so store |
262 // If the queue is empty then the splash regeneraton is complete so store |
244 // the current theme and language names as the last fully processed ones in |
263 // the current theme and language names as the last fully processed ones in |
245 // the settings and stop. |
264 // the settings and stop. |
246 if (mQueue.isEmpty()) { |
265 if (mQueue.isEmpty()) { |
247 qDebug() << PRE << "queue is empty regen finished"; |
266 qDebug() << PRE << "queue is empty regen finished"; |
248 mSettings.setValue(last_theme_key, hbInstance->theme()->name()); |
267 mSettings->setValue(last_theme_key, hbInstance->theme()->name()); |
249 mSettings.setValue(last_lang_key, QLocale::system().name()); |
268 mSettings->setValue(last_lang_key, QLocale::system().name()); |
250 QString outDir = hbsplash_output_dir(); |
269 QString outDir = hbsplash_output_dir(); |
251 mSettings.setValue(last_file_count_key, updateOutputDirContents(outDir)); |
270 mSettings->setValue(last_file_count_key, updateOutputDirContents(outDir)); |
252 mSettings.setValue(last_output_dir_key, outDir); |
271 mSettings->setValue(last_output_dir_key, outDir); |
253 emit finished(); |
272 emit finished(); |
254 qDebug() << PRE << "processQueue() over"; |
273 qDebug() << PRE << "processQueue() over"; |
255 return; |
274 return; |
256 } |
275 } |
257 // If a previous splash generation is still in progress then do nothing. |
276 // If a previous splash generation is still in progress then do nothing. |
263 mBusy = true; |
282 mBusy = true; |
264 mItem = mQueue.dequeue(); |
283 mItem = mQueue.dequeue(); |
265 mItemTime.start(); |
284 mItemTime.start(); |
266 log("generating splash screen", mItem.mThemeName, mItem.mOrientation); |
285 log("generating splash screen", mItem.mThemeName, mItem.mOrientation); |
267 |
286 |
268 if (!mMainWindow) { |
287 ensureMainWindow(); |
269 // The FixedVertical flag is used just to disable the sensor-based |
|
270 // orientation switching. |
|
271 mMainWindow = new HbMainWindow(0, Hb::WindowFlagFixedVertical); |
|
272 // Make sure that at least the 1st phase of the delayed |
|
273 // construction is done right now. |
|
274 HbMainWindowPrivate::d_ptr(mMainWindow)->_q_delayedConstruction(); |
|
275 } |
|
276 mMainWindow->setOrientation(mItem.mOrientation, false); |
288 mMainWindow->setOrientation(mItem.mOrientation, false); |
277 qDebug() << PRE << "mainwindow init time (ms):" << mItemTime.elapsed(); |
289 qDebug() << PRE << "mainwindow init time (ms):" << mItemTime.elapsed(); |
278 |
290 |
279 QTime setupTime; |
291 QTime setupTime; |
280 setupTime.start(); |
292 setupTime.start(); |
286 |
298 |
287 } catch (const std::bad_alloc &) { |
299 } catch (const std::bad_alloc &) { |
288 cleanup(); |
300 cleanup(); |
289 } |
301 } |
290 qDebug() << PRE << "processQueue() over"; |
302 qDebug() << PRE << "processQueue() over"; |
|
303 } |
|
304 |
|
305 void HbSplashGenerator::ensureMainWindow() |
|
306 { |
|
307 if (!mMainWindow) { |
|
308 // The FixedVertical flag is used just to disable the sensor-based |
|
309 // orientation switching. |
|
310 mMainWindow = new HbMainWindow(0, Hb::WindowFlagFixedVertical); |
|
311 // Make sure that at least the 1st phase of the delayed |
|
312 // construction is done right now. |
|
313 HbMainWindowPrivate::d_ptr(mMainWindow)->_q_delayedConstruction(); |
|
314 } |
291 } |
315 } |
292 |
316 |
293 void HbSplashGenerator::processWindow() |
317 void HbSplashGenerator::processWindow() |
294 { |
318 { |
295 // Take the screenshot, remove content, and move on to the next request in the queue. |
319 // Take the screenshot, remove content, and move on to the next request in the queue. |
323 QImage image = renderView(); |
347 QImage image = renderView(); |
324 QTime t; |
348 QTime t; |
325 t.start(); |
349 t.start(); |
326 QString splashFile = splashFileName(); |
350 QString splashFile = splashFileName(); |
327 qDebug() << PRE << "saving to" << splashFile; |
351 qDebug() << PRE << "saving to" << splashFile; |
328 if (saveSpl(splashFile, image)) { |
352 if (saveSpl(splashFile, image, mItem.mFlagsToStore)) { |
329 #if !defined(Q_OS_SYMBIAN) && defined(QT_DEBUG) |
353 #if !defined(Q_OS_SYMBIAN) && defined(QT_DEBUG) |
330 image.save(splashFile + QLatin1String(".png")); |
354 image.save(splashFile + QLatin1String(".png")); |
331 #endif |
355 #endif |
332 } else { |
356 } else { |
333 qWarning() << PRE << "file write failed for" << splashFile; |
357 qWarning() << PRE << "file write failed for" << splashFile; |
366 inline const uchar *imageBits(const QImage &image) |
390 inline const uchar *imageBits(const QImage &image) |
367 { |
391 { |
368 return image.bits(); |
392 return image.bits(); |
369 } |
393 } |
370 |
394 |
371 bool HbSplashGenerator::saveSpl(const QString &nameWithoutExt, const QImage &image) |
395 bool HbSplashGenerator::saveSpl(const QString &nameWithoutExt, const QImage &image, quint32 extra) |
372 { |
396 { |
373 QString fn(nameWithoutExt); |
397 QString fn(nameWithoutExt); |
374 fn.append(".spl"); |
398 fn.append(".spl"); |
375 QFile f(fn); |
399 QFile f(fn); |
376 if (f.open(QIODevice::WriteOnly | QIODevice::Truncate)) { |
400 if (f.open(QIODevice::WriteOnly | QIODevice::Truncate)) { |
377 int w = image.width(); |
401 quint32 w = (quint32) image.width(); |
378 int h = image.height(); |
402 quint32 h = (quint32) image.height(); |
379 int bpl = image.bytesPerLine(); |
403 quint32 bpl = (quint32) image.bytesPerLine(); |
380 QImage::Format fmt = image.format(); |
404 qint32 fmt = (qint32) image.format(); |
381 f.write((char *) &w, sizeof(int)); |
405 f.write((char *) &w, sizeof(quint32)); |
382 f.write((char *) &h, sizeof(int)); |
406 f.write((char *) &h, sizeof(quint32)); |
383 f.write((char *) &bpl, sizeof(int)); |
407 f.write((char *) &bpl, sizeof(quint32)); |
384 f.write((char *) &fmt, sizeof(QImage::Format)); |
408 f.write((char *) &fmt, sizeof(qint32)); |
|
409 f.write((char *) &extra, sizeof(quint32)); |
385 f.write((const char *) imageBits(image), bpl * h); |
410 f.write((const char *) imageBits(image), bpl * h); |
386 f.close(); |
411 f.close(); |
387 return true; |
412 return true; |
388 } |
413 } |
389 return false; |
414 return false; |
412 return dbg; |
437 return dbg; |
413 } |
438 } |
414 |
439 |
415 HbSplashGenerator::QueueItem::QueueItem() |
440 HbSplashGenerator::QueueItem::QueueItem() |
416 : mOrientation(Qt::Vertical), |
441 : mOrientation(Qt::Vertical), |
417 mHideBackground(false) |
442 mHideBackground(false), |
|
443 mFlagsToStore(0) |
418 { |
444 { |
419 } |
445 } |
420 |
446 |
421 HbSplashGenerator::QueueItem::QueueItem(const QString &themeName, Qt::Orientation orientation) |
447 HbSplashGenerator::QueueItem::QueueItem(const QString &themeName, Qt::Orientation orientation) |
422 : mThemeName(themeName), mOrientation(orientation), |
448 : mThemeName(themeName), |
423 mHideBackground(false) |
449 mOrientation(orientation), |
|
450 mHideBackground(false), |
|
451 mFlagsToStore(0) |
424 { |
452 { |
425 } |
453 } |
426 |
454 |
427 void HbSplashGenerator::addSplashmlItemToQueue(const QueueItem &item) |
455 void HbSplashGenerator::addSplashmlItemToQueue(const QueueItem &item) |
428 { |
456 { |
715 } |
743 } |
716 } |
744 } |
717 |
745 |
718 void HbSplashGenerator::finishWindow() |
746 void HbSplashGenerator::finishWindow() |
719 { |
747 { |
720 // Process additional settings. |
748 // There must be a view always in order to support view-specific settings. |
721 if (mMainWindow->views().isEmpty()) { |
749 if (mMainWindow->views().isEmpty()) { |
722 // There must be a view always in order to support view-specific settings. |
|
723 mMainWindow->addView(new HbWidget); |
750 mMainWindow->addView(new HbWidget); |
724 } |
751 } |
725 |
752 |
726 QList<HbView *> views = mMainWindow->views(); |
753 QList<HbView *> views = mMainWindow->views(); |
727 if (!views.isEmpty()) { |
754 if (!views.isEmpty()) { |
728 HbView *view = views.at(0); |
755 HbView *view = views.at(0); |
729 |
756 |
730 // view-flags |
757 // view-flags |
731 HbView::HbViewFlags viewFlags = HbView::ViewFlagNone; |
758 HbView::HbViewFlags viewFlags = view->viewFlags(); |
732 if (mItem.mViewFlags.contains("tb-minimizable")) { |
759 if (mItem.mViewFlags.contains("tb-minimizable")) { |
733 viewFlags |= HbView::ViewTitleBarMinimizable; |
760 viewFlags |= HbView::ViewTitleBarMinimizable; |
734 } |
761 } |
735 if (mItem.mViewFlags.contains("tb-minimized")) { |
762 if (mItem.mViewFlags.contains("tb-minimized")) { |
736 viewFlags |= HbView::ViewTitleBarMinimized; |
763 viewFlags |= HbView::ViewTitleBarMinimized; |
752 } |
779 } |
753 if (mItem.mViewFlags.contains("sb-floating")) { |
780 if (mItem.mViewFlags.contains("sb-floating")) { |
754 viewFlags |= HbView::ViewStatusBarFloating; |
781 viewFlags |= HbView::ViewStatusBarFloating; |
755 } |
782 } |
756 view->setViewFlags(viewFlags); |
783 view->setViewFlags(viewFlags); |
|
784 if (viewFlags.testFlag(HbView::ViewStatusBarHidden) |
|
785 || viewFlags.testFlag(HbView::ViewStatusBarTransparent)) |
|
786 { |
|
787 mItem.mFlagsToStore |= 1; |
|
788 } |
757 |
789 |
758 // navi-action-icon |
790 // navi-action-icon |
759 if (!mItem.mNaviActionIcon.isEmpty()) { |
791 if (!mItem.mNaviActionIcon.isEmpty()) { |
760 view->setNavigationAction(new HbAction(HbIcon(mItem.mNaviActionIcon), QString(), view)); |
792 view->setNavigationAction(new HbAction(HbIcon(mItem.mNaviActionIcon), QString(), view)); |
761 } // else will use the default navigation action (e.g. quit) |
793 } // else will use the default navigation action (e.g. quit) |
790 mMainWindow->setBackgroundImageName(mItem.mOrientation, backgroundImageName); |
822 mMainWindow->setBackgroundImageName(mItem.mOrientation, backgroundImageName); |
791 } |
823 } |
792 } |
824 } |
793 |
825 |
794 // Hide dynamic content from status bar (clock, indicators). |
826 // Hide dynamic content from status bar (clock, indicators). |
|
827 setStatusBarElementsVisible(false); |
|
828 } |
|
829 |
|
830 void HbSplashGenerator::setStatusBarElementsVisible(bool visible) |
|
831 { |
|
832 HbMainWindowPrivate *mwd = HbMainWindowPrivate::d_ptr(mMainWindow); |
795 HbStatusBar *statusBar = mwd->mStatusBar; |
833 HbStatusBar *statusBar = mwd->mStatusBar; |
796 if (statusBar) { |
834 if (statusBar) { |
797 foreach (QGraphicsItem *item, statusBar->childItems()) { |
835 foreach (QGraphicsItem *item, statusBar->childItems()) { |
798 QString name = HbStyle::itemName(item); |
836 QString name = HbStyle::itemName(item); |
799 bool hideItem = name == QLatin1String("signal") |
837 bool knownItem = |
|
838 name == QLatin1String("signal") |
800 || name == QLatin1String("battery") |
839 || name == QLatin1String("battery") |
801 || name == QLatin1String("notificationindicators") |
840 || name == QLatin1String("notificationindicators") |
802 || name == QLatin1String("settingsindicators") |
841 || name == QLatin1String("settingsindicators") |
803 || name == QLatin1String("timetext"); |
842 || name == QLatin1String("timetext"); |
804 if (hideItem) { |
843 if (knownItem) { |
805 item->setVisible(false); |
844 item->setVisible(visible); |
806 } |
845 } |
807 } |
846 } |
808 } |
847 } |
809 } |
848 } |
810 |
849 |
812 { |
851 { |
813 QString lang = QLocale::system().name(); |
852 QString lang = QLocale::system().name(); |
814 QTranslator *translator = new QTranslator; |
853 QTranslator *translator = new QTranslator; |
815 bool ok = false; |
854 bool ok = false; |
816 QStringList dirNames(hbsplash_translation_dirs()); |
855 QStringList dirNames(hbsplash_translation_dirs()); |
817 if (!mItem.mWorkDirForSingleFileRegen.isEmpty()) { |
856 dirNames.append(mItem.mCustomTrDirs); |
818 dirNames.append(mItem.mWorkDirForSingleFileRegen); |
|
819 } |
|
820 foreach (const QString &dirName, dirNames) { |
857 foreach (const QString &dirName, dirNames) { |
821 QDir dir(dirName); |
858 QDir dir(dirName); |
822 QString fullName = dir.filePath(name + '_' + lang); |
859 QString fullName = dir.filePath(name + '_' + lang); |
823 // fullName is not necessarily an existing file, however the translator |
860 // fullName is not necessarily an existing file, however the translator |
824 // may still pick up another suitable file based on this name. |
861 // may still pick up another suitable file based on this name. |