1d5ef985eSStephan Aßmus /* 2d5ef985eSStephan Aßmus * Copyright 2014, Stephan Aßmus <superstippi@gmx.de>. 339f99591SJulian Harnath * Copyright 2017, Julian Harnath <julian.harnath@rwth-aachen.de>. 4d5ef985eSStephan Aßmus * All rights reserved. Distributed under the terms of the MIT License. 5d5ef985eSStephan Aßmus */ 6d5ef985eSStephan Aßmus 7d5ef985eSStephan Aßmus #include "ScreenshotWindow.h" 8d5ef985eSStephan Aßmus 9d5ef985eSStephan Aßmus #include <algorithm> 10d5ef985eSStephan Aßmus #include <stdio.h> 11d5ef985eSStephan Aßmus 12d5ef985eSStephan Aßmus #include <Autolock.h> 13d5ef985eSStephan Aßmus #include <Catalog.h> 14d5ef985eSStephan Aßmus #include <LayoutBuilder.h> 15*c210060fSJulian Harnath #include <StringView.h> 16d5ef985eSStephan Aßmus 17*c210060fSJulian Harnath #include "BarberPole.h" 18d5ef985eSStephan Aßmus #include "BitmapView.h" 19d5ef985eSStephan Aßmus #include "WebAppInterface.h" 20d5ef985eSStephan Aßmus 21d5ef985eSStephan Aßmus 22d5ef985eSStephan Aßmus #undef B_TRANSLATION_CONTEXT 23d5ef985eSStephan Aßmus #define B_TRANSLATION_CONTEXT "ScreenshotWindow" 24d5ef985eSStephan Aßmus 25d5ef985eSStephan Aßmus 2639f99591SJulian Harnath static const rgb_color kBackgroundColor = { 51, 102, 152, 255 }; 2739f99591SJulian Harnath // Drawn as a border around the screenshots and also what's behind their 2839f99591SJulian Harnath // transparent regions 2939f99591SJulian Harnath 3039f99591SJulian Harnath 31d5ef985eSStephan Aßmus ScreenshotWindow::ScreenshotWindow(BWindow* parent, BRect frame) 32d5ef985eSStephan Aßmus : 33d5ef985eSStephan Aßmus BWindow(frame, B_TRANSLATE("Screenshot"), 34d5ef985eSStephan Aßmus B_FLOATING_WINDOW_LOOK, B_FLOATING_SUBSET_WINDOW_FEEL, 35d5ef985eSStephan Aßmus B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS), 36*c210060fSJulian Harnath fNumScreenshots(0), 37d5ef985eSStephan Aßmus fDownloadPending(false), 38d5ef985eSStephan Aßmus fWorkerThread(-1) 39d5ef985eSStephan Aßmus { 40d5ef985eSStephan Aßmus AddToSubset(parent); 41d5ef985eSStephan Aßmus 42*c210060fSJulian Harnath atomic_set(&fCurrentScreenshotIndex, 0); 43*c210060fSJulian Harnath 44*c210060fSJulian Harnath fBarberPole = new BarberPole("barber pole"); 45*c210060fSJulian Harnath fBarberPole->SetExplicitMaxSize(BSize(200, B_SIZE_UNLIMITED)); 46*c210060fSJulian Harnath 47*c210060fSJulian Harnath fIndexView = new BStringView("screenshot index", NULL); 48*c210060fSJulian Harnath 49*c210060fSJulian Harnath fToolBar = new BToolBar(); 50*c210060fSJulian Harnath fToolBar->AddAction(MSG_PREVIOUS_SCREENSHOT, this, NULL /* todo: icon */, 51*c210060fSJulian Harnath B_TRANSLATE("Show previous screenshot"), 52*c210060fSJulian Harnath B_TRANSLATE("Previous")); 53*c210060fSJulian Harnath fToolBar->AddAction(MSG_NEXT_SCREENSHOT, this, NULL /* todo: icon */, 54*c210060fSJulian Harnath B_TRANSLATE("Show next screenshot"), 55*c210060fSJulian Harnath B_TRANSLATE("Next")); 56*c210060fSJulian Harnath fToolBar->AddGlue(); 57*c210060fSJulian Harnath fToolBar->AddView(fIndexView); 58*c210060fSJulian Harnath fToolBar->AddGlue(); 59*c210060fSJulian Harnath fToolBar->AddView(fBarberPole); 60*c210060fSJulian Harnath 61d5ef985eSStephan Aßmus fScreenshotView = new BitmapView("screenshot view"); 62d5ef985eSStephan Aßmus fScreenshotView->SetExplicitMaxSize( 63d5ef985eSStephan Aßmus BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED)); 64d5ef985eSStephan Aßmus 652afa3f3bSStephan Aßmus BGroupView* groupView = new BGroupView(B_VERTICAL); 6639f99591SJulian Harnath groupView->SetViewColor(kBackgroundColor); 672afa3f3bSStephan Aßmus 68d5ef985eSStephan Aßmus // Build layout 69*c210060fSJulian Harnath BLayoutBuilder::Group<>(this, B_VERTICAL, 0) 70*c210060fSJulian Harnath .SetInsets(0, 5, 0, 0) 71*c210060fSJulian Harnath .Add(fToolBar) 72*c210060fSJulian Harnath .AddStrut(5) 732afa3f3bSStephan Aßmus .AddGroup(groupView) 74d5ef985eSStephan Aßmus .Add(fScreenshotView) 75d5ef985eSStephan Aßmus .SetInsets(B_USE_WINDOW_INSETS) 762afa3f3bSStephan Aßmus .End() 77d5ef985eSStephan Aßmus ; 78d5ef985eSStephan Aßmus 7939f99591SJulian Harnath fScreenshotView->SetLowColor(kBackgroundColor); 8039f99591SJulian Harnath // Set after attaching all views to prevent it from being overriden 8139f99591SJulian Harnath // again by BitmapView::AllAttached() 8239f99591SJulian Harnath 832afa3f3bSStephan Aßmus CenterOnScreen(); 84d5ef985eSStephan Aßmus } 85d5ef985eSStephan Aßmus 86d5ef985eSStephan Aßmus 87d5ef985eSStephan Aßmus ScreenshotWindow::~ScreenshotWindow() 88d5ef985eSStephan Aßmus { 89d5ef985eSStephan Aßmus BAutolock locker(&fLock); 90d5ef985eSStephan Aßmus 91d5ef985eSStephan Aßmus if (fWorkerThread >= 0) 92d5ef985eSStephan Aßmus wait_for_thread(fWorkerThread, NULL); 93d5ef985eSStephan Aßmus } 94d5ef985eSStephan Aßmus 95d5ef985eSStephan Aßmus 96d5ef985eSStephan Aßmus bool 97d5ef985eSStephan Aßmus ScreenshotWindow::QuitRequested() 98d5ef985eSStephan Aßmus { 99d5ef985eSStephan Aßmus if (fOnCloseTarget.IsValid() && fOnCloseMessage.what != 0) 100d5ef985eSStephan Aßmus fOnCloseTarget.SendMessage(&fOnCloseMessage); 101d5ef985eSStephan Aßmus 102d5ef985eSStephan Aßmus Hide(); 103d5ef985eSStephan Aßmus return false; 104d5ef985eSStephan Aßmus } 105d5ef985eSStephan Aßmus 106d5ef985eSStephan Aßmus 107d5ef985eSStephan Aßmus void 108d5ef985eSStephan Aßmus ScreenshotWindow::MessageReceived(BMessage* message) 109d5ef985eSStephan Aßmus { 110d5ef985eSStephan Aßmus switch (message->what) { 111*c210060fSJulian Harnath case MSG_NEXT_SCREENSHOT: 112*c210060fSJulian Harnath { 113*c210060fSJulian Harnath atomic_add(&fCurrentScreenshotIndex, 1); 114*c210060fSJulian Harnath _UpdateToolBar(); 115*c210060fSJulian Harnath _DownloadScreenshot(); 116*c210060fSJulian Harnath break; 117*c210060fSJulian Harnath } 118*c210060fSJulian Harnath 119*c210060fSJulian Harnath case MSG_PREVIOUS_SCREENSHOT: 120*c210060fSJulian Harnath atomic_add(&fCurrentScreenshotIndex, -1); 121*c210060fSJulian Harnath _UpdateToolBar(); 122*c210060fSJulian Harnath _DownloadScreenshot(); 123*c210060fSJulian Harnath break; 124*c210060fSJulian Harnath 125*c210060fSJulian Harnath case MSG_DOWNLOAD_START: 126*c210060fSJulian Harnath fBarberPole->Start(); 127*c210060fSJulian Harnath break; 128*c210060fSJulian Harnath 129*c210060fSJulian Harnath case MSG_DOWNLOAD_STOP: 130*c210060fSJulian Harnath fBarberPole->Stop(); 131*c210060fSJulian Harnath break; 132*c210060fSJulian Harnath 133d5ef985eSStephan Aßmus default: 134d5ef985eSStephan Aßmus BWindow::MessageReceived(message); 135d5ef985eSStephan Aßmus break; 136d5ef985eSStephan Aßmus } 137d5ef985eSStephan Aßmus } 138d5ef985eSStephan Aßmus 139d5ef985eSStephan Aßmus 140d5ef985eSStephan Aßmus void 141d5ef985eSStephan Aßmus ScreenshotWindow::SetOnCloseMessage( 142d5ef985eSStephan Aßmus const BMessenger& messenger, const BMessage& message) 143d5ef985eSStephan Aßmus { 144d5ef985eSStephan Aßmus fOnCloseTarget = messenger; 145d5ef985eSStephan Aßmus fOnCloseMessage = message; 146d5ef985eSStephan Aßmus } 147d5ef985eSStephan Aßmus 148d5ef985eSStephan Aßmus 149d5ef985eSStephan Aßmus void 150d5ef985eSStephan Aßmus ScreenshotWindow::SetPackage(const PackageInfoRef& package) 151d5ef985eSStephan Aßmus { 152d5ef985eSStephan Aßmus if (fPackage == package) 153d5ef985eSStephan Aßmus return; 154d5ef985eSStephan Aßmus 155d5ef985eSStephan Aßmus fPackage = package; 156d5ef985eSStephan Aßmus 157d5ef985eSStephan Aßmus BString title = B_TRANSLATE("Screenshot"); 158d5ef985eSStephan Aßmus if (package.Get() != NULL) { 159d5ef985eSStephan Aßmus title = package->Title(); 160d5ef985eSStephan Aßmus _DownloadScreenshot(); 161d5ef985eSStephan Aßmus } 162d5ef985eSStephan Aßmus SetTitle(title); 163*c210060fSJulian Harnath 164*c210060fSJulian Harnath atomic_set(&fCurrentScreenshotIndex, 0); 165*c210060fSJulian Harnath fNumScreenshots = fPackage->ScreenshotInfos().CountItems(); 166*c210060fSJulian Harnath 167*c210060fSJulian Harnath _UpdateToolBar(); 168d5ef985eSStephan Aßmus } 169d5ef985eSStephan Aßmus 170d5ef985eSStephan Aßmus 171d5ef985eSStephan Aßmus // #pragma mark - private 172d5ef985eSStephan Aßmus 173d5ef985eSStephan Aßmus 174d5ef985eSStephan Aßmus void 175d5ef985eSStephan Aßmus ScreenshotWindow::_DownloadScreenshot() 176d5ef985eSStephan Aßmus { 177d5ef985eSStephan Aßmus BAutolock locker(&fLock); 178d5ef985eSStephan Aßmus 179d5ef985eSStephan Aßmus if (fWorkerThread >= 0) { 180d5ef985eSStephan Aßmus fDownloadPending = true; 181d5ef985eSStephan Aßmus return; 182d5ef985eSStephan Aßmus } 183d5ef985eSStephan Aßmus 184d5ef985eSStephan Aßmus thread_id thread = spawn_thread(&_DownloadThreadEntry, 185d5ef985eSStephan Aßmus "Screenshot Loader", B_NORMAL_PRIORITY, this); 186d5ef985eSStephan Aßmus if (thread >= 0) 187d5ef985eSStephan Aßmus _SetWorkerThread(thread); 188d5ef985eSStephan Aßmus } 189d5ef985eSStephan Aßmus 190d5ef985eSStephan Aßmus 191d5ef985eSStephan Aßmus void 192d5ef985eSStephan Aßmus ScreenshotWindow::_SetWorkerThread(thread_id thread) 193d5ef985eSStephan Aßmus { 194d5ef985eSStephan Aßmus if (!Lock()) 195d5ef985eSStephan Aßmus return; 196d5ef985eSStephan Aßmus 197d5ef985eSStephan Aßmus // bool enabled = thread < 0; 198d5ef985eSStephan Aßmus // 199d5ef985eSStephan Aßmus // fPreviewsButton->SetEnabled(enabled); 200d5ef985eSStephan Aßmus // fNextButton->SetEnabled(enabled); 201d5ef985eSStephan Aßmus // fCloseButton->SetEnabled(enabled); 202d5ef985eSStephan Aßmus 203d5ef985eSStephan Aßmus if (thread >= 0) { 204d5ef985eSStephan Aßmus fWorkerThread = thread; 205d5ef985eSStephan Aßmus resume_thread(fWorkerThread); 206d5ef985eSStephan Aßmus } else { 207d5ef985eSStephan Aßmus fWorkerThread = -1; 208d5ef985eSStephan Aßmus 209d5ef985eSStephan Aßmus if (fDownloadPending) { 210d5ef985eSStephan Aßmus _DownloadScreenshot(); 211d5ef985eSStephan Aßmus fDownloadPending = false; 212d5ef985eSStephan Aßmus } 213d5ef985eSStephan Aßmus } 214d5ef985eSStephan Aßmus 215d5ef985eSStephan Aßmus Unlock(); 216d5ef985eSStephan Aßmus } 217d5ef985eSStephan Aßmus 218d5ef985eSStephan Aßmus 219d5ef985eSStephan Aßmus int32 220d5ef985eSStephan Aßmus ScreenshotWindow::_DownloadThreadEntry(void* data) 221d5ef985eSStephan Aßmus { 222d5ef985eSStephan Aßmus ScreenshotWindow* window 223d5ef985eSStephan Aßmus = reinterpret_cast<ScreenshotWindow*>(data); 224d5ef985eSStephan Aßmus window->_DownloadThread(); 225d5ef985eSStephan Aßmus window->_SetWorkerThread(-1); 226d5ef985eSStephan Aßmus return 0; 227d5ef985eSStephan Aßmus } 228d5ef985eSStephan Aßmus 229d5ef985eSStephan Aßmus 230d5ef985eSStephan Aßmus void 231d5ef985eSStephan Aßmus ScreenshotWindow::_DownloadThread() 232d5ef985eSStephan Aßmus { 233d5ef985eSStephan Aßmus printf("_DownloadThread()\n"); 234d5ef985eSStephan Aßmus if (!Lock()) { 235d5ef985eSStephan Aßmus printf(" failed to lock screenshot window\n"); 236d5ef985eSStephan Aßmus return; 237d5ef985eSStephan Aßmus } 238d5ef985eSStephan Aßmus 2392a36368bSMichael Lotz fScreenshotView->UnsetBitmap(); 240d5ef985eSStephan Aßmus 241d5ef985eSStephan Aßmus ScreenshotInfoList screenshotInfos; 242d5ef985eSStephan Aßmus if (fPackage.Get() != NULL) 243d5ef985eSStephan Aßmus screenshotInfos = fPackage->ScreenshotInfos(); 244d5ef985eSStephan Aßmus 245d5ef985eSStephan Aßmus Unlock(); 246d5ef985eSStephan Aßmus 247d5ef985eSStephan Aßmus if (screenshotInfos.CountItems() == 0) { 248d5ef985eSStephan Aßmus printf(" package has no screenshots\n"); 249d5ef985eSStephan Aßmus return; 250d5ef985eSStephan Aßmus } 251d5ef985eSStephan Aßmus 252d5ef985eSStephan Aßmus // Obtain the correct code for the screenshot to display 253d5ef985eSStephan Aßmus // TODO: Once navigation buttons are added, we could use the 254d5ef985eSStephan Aßmus // ScreenshotInfo at the "current" index. 255*c210060fSJulian Harnath const ScreenshotInfo& info = screenshotInfos.ItemAtFast( 256*c210060fSJulian Harnath atomic_get(&fCurrentScreenshotIndex)); 257d5ef985eSStephan Aßmus 258d5ef985eSStephan Aßmus BMallocIO buffer; 259d5ef985eSStephan Aßmus WebAppInterface interface; 260d5ef985eSStephan Aßmus 261*c210060fSJulian Harnath BMessenger messenger(this); 262*c210060fSJulian Harnath messenger.SendMessage(MSG_DOWNLOAD_START); 263*c210060fSJulian Harnath 264d5ef985eSStephan Aßmus // Retrieve screenshot from web-app 265d5ef985eSStephan Aßmus status_t status = interface.RetrieveScreenshot(info.Code(), 266d5ef985eSStephan Aßmus info.Width(), info.Height(), &buffer); 267*c210060fSJulian Harnath 268*c210060fSJulian Harnath messenger.SendMessage(MSG_DOWNLOAD_STOP); 269*c210060fSJulian Harnath 270d5ef985eSStephan Aßmus if (status == B_OK && Lock()) { 271d5ef985eSStephan Aßmus printf("got screenshot"); 272d5ef985eSStephan Aßmus fScreenshot = BitmapRef(new(std::nothrow)SharedBitmap(buffer), true); 2732a36368bSMichael Lotz fScreenshotView->SetBitmap(fScreenshot); 2742afa3f3bSStephan Aßmus _ResizeToFitAndCenter(); 275d5ef985eSStephan Aßmus Unlock(); 276d5ef985eSStephan Aßmus } else { 277d5ef985eSStephan Aßmus printf(" failed to download screenshot\n"); 278d5ef985eSStephan Aßmus } 279d5ef985eSStephan Aßmus } 2802afa3f3bSStephan Aßmus 2812afa3f3bSStephan Aßmus 2822afa3f3bSStephan Aßmus void 2832afa3f3bSStephan Aßmus ScreenshotWindow::_ResizeToFitAndCenter() 2842afa3f3bSStephan Aßmus { 2852afa3f3bSStephan Aßmus float minWidth; 2862afa3f3bSStephan Aßmus float minHeight; 2872afa3f3bSStephan Aßmus GetSizeLimits(&minWidth, NULL, &minHeight, NULL); 2882afa3f3bSStephan Aßmus ResizeTo(minWidth, minHeight); 2892afa3f3bSStephan Aßmus CenterOnScreen(); 2902afa3f3bSStephan Aßmus } 291*c210060fSJulian Harnath 292*c210060fSJulian Harnath 293*c210060fSJulian Harnath void 294*c210060fSJulian Harnath ScreenshotWindow::_UpdateToolBar() 295*c210060fSJulian Harnath { 296*c210060fSJulian Harnath int32 currentIndex = atomic_get(&fCurrentScreenshotIndex); 297*c210060fSJulian Harnath fToolBar->SetActionEnabled(MSG_PREVIOUS_SCREENSHOT, 298*c210060fSJulian Harnath currentIndex > 0); 299*c210060fSJulian Harnath fToolBar->SetActionEnabled(MSG_NEXT_SCREENSHOT, 300*c210060fSJulian Harnath currentIndex < fNumScreenshots - 2); 301*c210060fSJulian Harnath 302*c210060fSJulian Harnath BString text; 303*c210060fSJulian Harnath text << currentIndex + 1; 304*c210060fSJulian Harnath text << " / "; 305*c210060fSJulian Harnath text << fNumScreenshots; 306*c210060fSJulian Harnath fIndexView->SetText(text); 307*c210060fSJulian Harnath } 308