From dcba1fb60a1da9eb2398c65a0945fc36fa10fa09 Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Mon, 19 Mar 2012 22:21:35 -0400 Subject: [PATCH 1/3] Windows 7 taskbar goodies Update the Windows 7 taskbarlist progress bar on plOperationProgress callbacks. It's not totally nesecary, but it adds a nice bit of polish to the experience. --- Sources/Plasma/Apps/plClient/plClient.cpp | 19 ++++++++++ Sources/Plasma/Apps/plClient/winmain.cpp | 43 +++++++++++++++-------- 2 files changed, 48 insertions(+), 14 deletions(-) diff --git a/Sources/Plasma/Apps/plClient/plClient.cpp b/Sources/Plasma/Apps/plClient/plClient.cpp index ce487eb7..ec04183a 100644 --- a/Sources/Plasma/Apps/plClient/plClient.cpp +++ b/Sources/Plasma/Apps/plClient/plClient.cpp @@ -168,6 +168,10 @@ static plDispatchBase* gDisp = nil; static plTimerCallbackManager* gTimerMgr = nil; static plAudioSystem* gAudio = nil; +#ifdef HS_BUILD_FOR_WIN32 +extern ITaskbarList3* gTaskbarList; +#endif + hsBool plClient::fDelayMS = false; plClient* plClient::fInstance=nil; @@ -1291,6 +1295,21 @@ void plClient::IProgressMgrCallbackProc(plOperationProgress * progress) if(!fInstance) return; + // Increments the taskbar progress [Windows 7+] +#ifdef HS_BUILD_FOR_WIN32 + if (gTaskbarList) + { + HWND hwnd = fInstance->GetWindowHandle(); // lazy + if (progress->IsLastUpdate()) + gTaskbarList->SetProgressState(hwnd, TBPF_NOPROGRESS); + else if (progress->GetMax() == 0.f) + gTaskbarList->SetProgressState(hwnd, TBPF_INDETERMINATE); + else + // This will set TBPF_NORMAL for us + gTaskbarList->SetProgressValue(hwnd, (ULONGLONG)progress->GetProgress(), (ULONGLONG)progress->GetMax()); + } +#endif + fInstance->fMessagePumpProc(); // HACK HACK HACK HACK! diff --git a/Sources/Plasma/Apps/plClient/winmain.cpp b/Sources/Plasma/Apps/plClient/winmain.cpp index 94bcdd5b..3ac8b6ed 100644 --- a/Sources/Plasma/Apps/plClient/winmain.cpp +++ b/Sources/Plasma/Apps/plClient/winmain.cpp @@ -92,6 +92,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com // Globals // hsBool gHasMouse = false; +ITaskbarList3* gTaskbarList = nil; // NT 6.1+ taskbar stuff extern hsBool gDataServerLocal; @@ -121,6 +122,7 @@ bool gPendingActivateFlag = false; static bool s_loginDlgRunning = false; static CEvent s_statusEvent(kEventManualReset); +static UINT s_WmTaskbarList = RegisterWindowMessage("TaskbarButtonCreated"); FILE *errFP = nil; HINSTANCE gHInst = NULL; // Instance of this app @@ -361,7 +363,7 @@ void DebugMsgF(const char* format, ...); // Handles all the windows messages we might receive LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) -{ +{ static bool gDragging = false; static uint32_t keyState=0; @@ -401,12 +403,12 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) gClient->GetInputManager()->HandleWin32ControlEvent(message, wParam, lParam, hWnd); } } - break; + return TRUE; #if 0 case WM_KILLFOCUS: SetForegroundWindow(hWnd); - break; + return TRUE; #endif case WM_SYSKEYUP: @@ -418,7 +420,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) } //DefWindowProc(hWnd, message, wParam, lParam); } - break; + return TRUE; case WM_SYSCOMMAND: switch (wParam) { @@ -434,9 +436,9 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) if (plNetClientMgr * mgr = plNetClientMgr::GetInstance()) mgr->QueueDisableNet(false, nil); DestroyWindow(gClient->GetWindowHandle()); - break; + return TRUE; } - break; + return TRUE; case WM_ACTIVATE: { @@ -477,7 +479,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) gPendingActivateFlag = active; } } - break; + return TRUE; // Let go of the mouse if the window is being moved. case WM_ENTERSIZEMOVE: @@ -485,7 +487,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) gDragging = true; if( gClient ) gClient->WindowActivate(false); - break; + return TRUE; // Redo the mouse capture if the window gets moved case WM_EXITSIZEMOVE: @@ -493,7 +495,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) gDragging = false; if( gClient ) gClient->WindowActivate(true); - break; + return TRUE; // Redo the mouse capture if the window gets moved (special case for Colin // and his cool program that bumps windows out from under the taskbar) @@ -505,7 +507,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) } else DebugMsgF("Got WM_MOVE, but ignoring"); - break; + return TRUE; /// Resize the window // (we do WM_SIZING here instead of WM_SIZE because, for some reason, WM_SIZE is @@ -520,7 +522,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) ::GetClientRect(hWnd, &r); gClient->GetPipeline()->Resize(r.right - r.left, r.bottom - r.top); } - break; + return TRUE; case WM_SIZE: // Let go of the mouse if the window is being minimized @@ -537,7 +539,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) if (gClient) gClient->WindowActivate(true); } - break; + return TRUE; case WM_CLOSE: gClient->SetDone(TRUE); @@ -553,9 +555,22 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) return TRUE; case WM_CREATE: // Create renderer - break; + return TRUE; } - return DefWindowProc(hWnd, message, wParam, lParam); + + // Messages we registered for manually (no const value) + if (message == s_WmTaskbarList) + { + // Grab the Windows 7 taskbar list stuff + if (gTaskbarList) + gTaskbarList->Release(); + HRESULT result = CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_ALL, IID_ITaskbarList3, (void**)&gTaskbarList); + if (FAILED(result)) + gTaskbarList = nil; + return TRUE; + } + else + return DefWindowProc(hWnd, message, wParam, lParam); } void PumpMessageQueueProc( void ) From 6039d62bc23d38e90c312618131a0a639bbbb09c Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Tue, 20 Mar 2012 01:08:21 -0400 Subject: [PATCH 2/3] Implement progress failures I took the liberty to improve the obvious failure cases where a red progress bar would be useful. --- Sources/Plasma/Apps/plClient/plClient.cpp | 21 ++++++++++++++++--- Sources/Plasma/Apps/plClient/plClient.h | 3 ++- .../pfSecurePreloader/pfSecurePreloader.cpp | 1 + .../PubUtilLib/plAgeLoader/plResPatcher.cpp | 3 +++ .../plNetClient/plNetLinkingMgr.cpp | 6 ++---- .../plProgressMgr/plProgressMgr.cpp | 1 - .../PubUtilLib/plProgressMgr/plProgressMgr.h | 1 + 7 files changed, 27 insertions(+), 9 deletions(-) diff --git a/Sources/Plasma/Apps/plClient/plClient.cpp b/Sources/Plasma/Apps/plClient/plClient.cpp index ec04183a..f95701b1 100644 --- a/Sources/Plasma/Apps/plClient/plClient.cpp +++ b/Sources/Plasma/Apps/plClient/plClient.cpp @@ -868,8 +868,8 @@ hsBool plClient::MsgReceive(plMessage* msg) // plResPatcherMsg //============================================================================ if (plResPatcherMsg * resMsg = plResPatcherMsg::ConvertNoRef(msg)) { - plgDispatch::Dispatch()->UnRegisterForExactType(plResPatcherMsg::Index(), GetKey()); - IOnAsyncInitComplete(); + IHandlePatcherMsg(resMsg); + return true; } return hsKeyedObject::MsgReceive(msg); @@ -1300,7 +1300,10 @@ void plClient::IProgressMgrCallbackProc(plOperationProgress * progress) if (gTaskbarList) { HWND hwnd = fInstance->GetWindowHandle(); // lazy - if (progress->IsLastUpdate()) + if (progress->IsAborting()) + // We'll assume this is fatal + gTaskbarList->SetProgressState(hwnd, TBPF_ERROR); + else if (progress->IsLastUpdate()) gTaskbarList->SetProgressState(hwnd, TBPF_NOPROGRESS); else if (progress->GetMax() == 0.f) gTaskbarList->SetProgressState(hwnd, TBPF_INDETERMINATE); @@ -2550,6 +2553,18 @@ void plClient::IHandlePreloaderMsg (plPreloaderMsg * msg) { IPatchGlobalAgeFiles(); } +//============================================================================ +void plClient::IHandlePatcherMsg (plResPatcherMsg * msg) { + plgDispatch::Dispatch()->UnRegisterForExactType(plResPatcherMsg::Index(), GetKey()); + + if (!msg->Success()) { + plNetClientApp::GetInstance()->QueueDisableNet(true, msg->GetError()); + return; + } + + IOnAsyncInitComplete(); +} + //============================================================================ void plClient::IHandleNetCommAuthMsg (plNetCommAuthMsg * msg) { diff --git a/Sources/Plasma/Apps/plClient/plClient.h b/Sources/Plasma/Apps/plClient/plClient.h index 459ae84f..0def1745 100644 --- a/Sources/Plasma/Apps/plClient/plClient.h +++ b/Sources/Plasma/Apps/plClient/plClient.h @@ -82,7 +82,7 @@ class plBinkPlayer; class plPreloaderMsg; class plNetCommAuthMsg; class plAgeLoaded2Msg; - +class plResPatcherMsg; typedef void (*plMessagePumpProc)( void ); @@ -179,6 +179,7 @@ protected: void ICompleteInit (); void IOnAsyncInitComplete (); + void IHandlePatcherMsg (plResPatcherMsg * msg); void IHandlePreloaderMsg (plPreloaderMsg * msg); void IHandleNetCommAuthMsg (plNetCommAuthMsg * msg); bool IHandleAgeLoaded2Msg (plAgeLoaded2Msg * msg); diff --git a/Sources/Plasma/FeatureLib/pfSecurePreloader/pfSecurePreloader.cpp b/Sources/Plasma/FeatureLib/pfSecurePreloader/pfSecurePreloader.cpp index f242afe4..9ae2fea9 100644 --- a/Sources/Plasma/FeatureLib/pfSecurePreloader/pfSecurePreloader.cpp +++ b/Sources/Plasma/FeatureLib/pfSecurePreloader/pfSecurePreloader.cpp @@ -300,6 +300,7 @@ void pfSecurePreloader::Start() void pfSecurePreloader::Terminate() { FATAL("pfSecurePreloader failure"); + fProgress->SetAborting(); plPreloaderMsg* msg = new plPreloaderMsg; msg->fSuccess = false; diff --git a/Sources/Plasma/PubUtilLib/plAgeLoader/plResPatcher.cpp b/Sources/Plasma/PubUtilLib/plAgeLoader/plResPatcher.cpp index 44b9e7d3..af8b488e 100644 --- a/Sources/Plasma/PubUtilLib/plAgeLoader/plResPatcher.cpp +++ b/Sources/Plasma/PubUtilLib/plAgeLoader/plResPatcher.cpp @@ -277,7 +277,10 @@ void plResPatcher::Finish(bool success) if (success) PatcherLog(kHeader, "--- Patch Completed Successfully ---"); else + { PatcherLog(kHeader, "--- Patch Killed by Error ---"); + fProgress->SetAborting(); + } plResPatcherMsg* pMsg = new plResPatcherMsg(success, sLastError); pMsg->Send(); // whoosh... off it goes diff --git a/Sources/Plasma/PubUtilLib/plNetClient/plNetLinkingMgr.cpp b/Sources/Plasma/PubUtilLib/plNetClient/plNetLinkingMgr.cpp index 03112b49..2a243ac3 100644 --- a/Sources/Plasma/PubUtilLib/plNetClient/plNetLinkingMgr.cpp +++ b/Sources/Plasma/PubUtilLib/plNetClient/plNetLinkingMgr.cpp @@ -165,11 +165,9 @@ void plNetLinkingMgr::NCAgeJoinerCallback ( // Tell the user we failed to link. // In the future, we might want to try graceful recovery (link back to Relto?) if (!params->success) { - plNetClientMgr::StaticErrorMsg(params->msg); - hsMessageBox(params->msg, "Linking Error", hsMessageBoxNormal, hsMessageBoxIconError); + plNetClientApp::GetInstance()->ErrorMsg(params->msg); #ifdef PLASMA_EXTERNAL_RELEASE - plClientMsg* clientMsg = new plClientMsg(plClientMsg::kQuit); - clientMsg->Send(hsgResMgr::ResMgr()->FindKey(kClient_KEY)); + plNetClientApp::GetInstance()->QueueDisableNet(true, params->msg); #endif return; } diff --git a/Sources/Plasma/PubUtilLib/plProgressMgr/plProgressMgr.cpp b/Sources/Plasma/PubUtilLib/plProgressMgr/plProgressMgr.cpp index d874a55c..d98d813b 100644 --- a/Sources/Plasma/PubUtilLib/plProgressMgr/plProgressMgr.cpp +++ b/Sources/Plasma/PubUtilLib/plProgressMgr/plProgressMgr.cpp @@ -389,7 +389,6 @@ void plOperationProgress::SetAborting() hsSetBits(fFlags, kAborting); plProgressMgr::GetInstance()->IUpdateCallbackProc(this); fMax = fValue = 0.f; - hsClearBits(fFlags, kAborting); } void plOperationProgress::SetRetry() diff --git a/Sources/Plasma/PubUtilLib/plProgressMgr/plProgressMgr.h b/Sources/Plasma/PubUtilLib/plProgressMgr/plProgressMgr.h index 061d4a77..b3dc11f1 100644 --- a/Sources/Plasma/PubUtilLib/plProgressMgr/plProgressMgr.h +++ b/Sources/Plasma/PubUtilLib/plProgressMgr/plProgressMgr.h @@ -153,6 +153,7 @@ class plOperationProgress // progress bars above this one know to adjust their totals to not include any amount // that wasn't completed, and will set this progress bar to zero void SetAborting(); + bool IsAborting() { return hsCheckBits(fFlags, kAborting); } // If you're reusing an existing progress bar to retry a failed operation, call this. // It will set the retry flag, and reset the progress bar so the next update will // count as the first. If you set retry in RegisterOperation, don't use this too. From 5beda0ab87e69d41f713644e7667e88979537d38 Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Tue, 20 Mar 2012 00:00:39 -0400 Subject: [PATCH 3/3] Implement client window flashing This will be used in python to grab the player's attention on PMs or other interesting events. --- Sources/Plasma/Apps/plClient/plClient.cpp | 16 ++++++++++++++++ Sources/Plasma/Apps/plClient/plClient.h | 1 + Sources/Plasma/FeatureLib/pfPython/cyMisc.cpp | 7 +++++++ Sources/Plasma/FeatureLib/pfPython/cyMisc.h | 9 +++++++++ .../Plasma/FeatureLib/pfPython/cyMiscGlue.cpp | 4 ++++ .../Plasma/NucleusLib/pnMessage/plClientMsg.h | 2 ++ 6 files changed, 39 insertions(+) diff --git a/Sources/Plasma/Apps/plClient/plClient.cpp b/Sources/Plasma/Apps/plClient/plClient.cpp index f95701b1..d4bbe01c 100644 --- a/Sources/Plasma/Apps/plClient/plClient.cpp +++ b/Sources/Plasma/Apps/plClient/plClient.cpp @@ -772,6 +772,11 @@ hsBool plClient::MsgReceive(plMessage* msg) } break; + case plClientMsg::kFlashWindow: + { + FlashWindow(); + } + break; } return true; } @@ -2437,6 +2442,17 @@ void plClient::WindowActivate(bool active) fWindowActive = active; } +void plClient::FlashWindow() +{ +#ifdef HS_BUILD_FOR_WIN32 + FLASHWINFO info; + info.cbSize = sizeof(info); + info.dwFlags = FLASHW_TIMERNOFG | FLASHW_ALL; + info.hwnd = fWindowHndl; + info.uCount = -1; + FlashWindowEx(&info); +#endif +} //============================================================================ void plClient::IOnAsyncInitComplete () { diff --git a/Sources/Plasma/Apps/plClient/plClient.h b/Sources/Plasma/Apps/plClient/plClient.h index 0def1745..b529f5bf 100644 --- a/Sources/Plasma/Apps/plClient/plClient.h +++ b/Sources/Plasma/Apps/plClient/plClient.h @@ -290,6 +290,7 @@ public: virtual void WindowActivate(bool active); virtual hsBool WindowActive() const { return fWindowActive; } + void FlashWindow(); void SetMessagePumpProc( plMessagePumpProc proc ) { fMessagePumpProc = proc; } void ResetDisplayDevice(int Width, int Height, int ColorDepth, hsBool Windowed, int NumAASamples, int MaxAnisotropicSamples, hsBool VSync = false); void ResizeDisplayDevice(int Width, int Height, hsBool Windowed); diff --git a/Sources/Plasma/FeatureLib/pfPython/cyMisc.cpp b/Sources/Plasma/FeatureLib/pfPython/cyMisc.cpp index 257a52d6..4da2e109 100644 --- a/Sources/Plasma/FeatureLib/pfPython/cyMisc.cpp +++ b/Sources/Plasma/FeatureLib/pfPython/cyMisc.cpp @@ -721,6 +721,13 @@ void cyMisc::ExcludeRegionSetNow(pyKey& sender, pyKey& exKey, uint16_t state) plgDispatch::MsgSend( msg ); // whoosh... off it goes } +void cyMisc::FlashWindow() +{ + plKey clientKey = hsgResMgr::ResMgr()->FindKey(kClient_KEY); + plClientMsg* pMsg = new plClientMsg(plClientMsg::kFlashWindow); + pMsg->Send(clientKey); // whoosh... off it goes +} + #include "hsTimer.h" ///////////////////////////////////////////////////////////////////////////// // diff --git a/Sources/Plasma/FeatureLib/pfPython/cyMisc.h b/Sources/Plasma/FeatureLib/pfPython/cyMisc.h index 2d1c25f6..4cc5385d 100644 --- a/Sources/Plasma/FeatureLib/pfPython/cyMisc.h +++ b/Sources/Plasma/FeatureLib/pfPython/cyMisc.h @@ -244,6 +244,15 @@ public: // static hsBool WasLocallyNotified(pyKey &selfkey); + ///////////////////////////////////////////////////////////////////////////// + // + // Function : FlashWindow + // PARAMETERS : + // + // PURPOSE : Flashes the client window if it is not focused + // + static void FlashWindow(); + ///////////////////////////////////////////////////////////////////////////// // // Function : GetClientName diff --git a/Sources/Plasma/FeatureLib/pfPython/cyMiscGlue.cpp b/Sources/Plasma/FeatureLib/pfPython/cyMiscGlue.cpp index 57740e98..9f7ff0c8 100644 --- a/Sources/Plasma/FeatureLib/pfPython/cyMiscGlue.cpp +++ b/Sources/Plasma/FeatureLib/pfPython/cyMiscGlue.cpp @@ -48,6 +48,8 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include +PYTHON_BASIC_GLOBAL_METHOD_DEFINITION(PtFlashWindow, cyMisc::FlashWindow, "Flashes the client window if it is not focused"); + PYTHON_GLOBAL_METHOD_DEFINITION_NOARGS(PtGetAgeName, "DEPRECIATED - use ptDniInfoSource instead") { return PyString_FromString(cyMisc::GetAgeName()); @@ -514,6 +516,8 @@ PYTHON_GLOBAL_METHOD_DEFINITION(PtDumpLogs, args, "Params: folder\nDumps all cur void cyMisc::AddPlasmaMethods(std::vector &methods) { + PYTHON_GLOBAL_METHOD_NOARGS(methods, PtFlashWindow); + PYTHON_GLOBAL_METHOD_NOARGS(methods, PtGetAgeName); PYTHON_GLOBAL_METHOD_NOARGS(methods, PtGetAgeInfo); PYTHON_GLOBAL_METHOD_NOARGS(methods, PtGetAgeTime); diff --git a/Sources/Plasma/NucleusLib/pnMessage/plClientMsg.h b/Sources/Plasma/NucleusLib/pnMessage/plClientMsg.h index b4932694..196a09cc 100644 --- a/Sources/Plasma/NucleusLib/pnMessage/plClientMsg.h +++ b/Sources/Plasma/NucleusLib/pnMessage/plClientMsg.h @@ -94,6 +94,8 @@ public: kEnableRenderScene, kResetGraphicsDevice, kSetGraphicsDefaults, + + kFlashWindow, }; // graphics settings fields