forked from mirrors/gecko-dev
		
	 2afd829d0f
			
		
	
	
		2afd829d0f
		
	
	
	
	
		
			
			This patch is an automatic replacement of s/NS_NOTREACHED/MOZ_ASSERT_UNREACHABLE/. Reindenting long lines and whitespace fixups follow in patch 6b. MozReview-Commit-ID: 5UQVHElSpCr --HG-- extra : rebase_source : 4c1b2fc32b269342f07639266b64941e2270e9c4 extra : source : 907543f6eae716f23a6de52b1ffb1c82908d158a
		
			
				
	
	
		
			357 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			357 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* vim: se cin sw=2 ts=2 et : */
 | |
| /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 | |
|  *
 | |
|  * This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| 
 | |
| #include "TaskbarTabPreview.h"
 | |
| #include "nsWindowGfx.h"
 | |
| #include "nsUXThemeData.h"
 | |
| #include "WinUtils.h"
 | |
| #include <nsITaskbarPreviewController.h>
 | |
| 
 | |
| #define TASKBARPREVIEW_HWNDID L"TaskbarTabPreviewHwnd"
 | |
| 
 | |
| namespace mozilla {
 | |
| namespace widget {
 | |
| 
 | |
| NS_IMPL_ISUPPORTS(TaskbarTabPreview, nsITaskbarTabPreview)
 | |
| 
 | |
| const wchar_t *const kWindowClass = L"MozillaTaskbarPreviewClass";
 | |
| 
 | |
| TaskbarTabPreview::TaskbarTabPreview(ITaskbarList4 *aTaskbar, nsITaskbarPreviewController *aController, HWND aHWND, nsIDocShell *aShell)
 | |
|   : TaskbarPreview(aTaskbar, aController, aHWND, aShell),
 | |
|     mProxyWindow(nullptr),
 | |
|     mIcon(nullptr),
 | |
|     mRegistered(false)
 | |
| {
 | |
|   WindowHook &hook = GetWindowHook();
 | |
|   hook.AddMonitor(WM_WINDOWPOSCHANGED, MainWindowHook, this);
 | |
| }
 | |
| 
 | |
| TaskbarTabPreview::~TaskbarTabPreview() {
 | |
|   if (mIcon) {
 | |
|     ::DestroyIcon(mIcon);
 | |
|     mIcon = nullptr;
 | |
|   }
 | |
| 
 | |
|   // We need to ensure that proxy window disappears or else Bad Things happen.
 | |
|   if (mProxyWindow)
 | |
|     Disable();
 | |
| 
 | |
|   NS_ASSERTION(!mProxyWindow, "Taskbar proxy window was not destroyed!");
 | |
| 
 | |
|   if (IsWindowAvailable()) {
 | |
|     DetachFromNSWindow();
 | |
|   } else {
 | |
|     mWnd = nullptr;
 | |
|   }
 | |
| }
 | |
| 
 | |
| nsresult
 | |
| TaskbarTabPreview::ShowActive(bool active) {
 | |
|   NS_ASSERTION(mVisible && CanMakeTaskbarCalls(), "ShowActive called on invisible window or before taskbar calls can be made for this window");
 | |
|   return FAILED(mTaskbar->SetTabActive(active ? mProxyWindow : nullptr,
 | |
|                                        mWnd, 0)) ? NS_ERROR_FAILURE : NS_OK;
 | |
| }
 | |
| 
 | |
| HWND &
 | |
| TaskbarTabPreview::PreviewWindow() {
 | |
|   return mProxyWindow;
 | |
| }
 | |
| 
 | |
| nativeWindow
 | |
| TaskbarTabPreview::GetHWND() {
 | |
|   return mProxyWindow;
 | |
| }
 | |
| 
 | |
| void
 | |
| TaskbarTabPreview::EnsureRegistration() {
 | |
|   NS_ASSERTION(mVisible && CanMakeTaskbarCalls(), "EnsureRegistration called when it is not safe to do so");
 | |
| 
 | |
|   (void) UpdateTaskbarProperties();
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| TaskbarTabPreview::GetTitle(nsAString &aTitle) {
 | |
|   aTitle = mTitle;
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| TaskbarTabPreview::SetTitle(const nsAString &aTitle) {
 | |
|   mTitle = aTitle;
 | |
|   return mVisible ? UpdateTitle() : NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| TaskbarTabPreview::SetIcon(imgIContainer *icon) {
 | |
|   HICON hIcon = nullptr;
 | |
|   if (icon) {
 | |
|     nsresult rv;
 | |
|     rv = nsWindowGfx::CreateIcon(icon, false, 0, 0,
 | |
|                                  nsWindowGfx::GetIconMetrics(nsWindowGfx::kSmallIcon),
 | |
|                                  &hIcon);
 | |
|     NS_ENSURE_SUCCESS(rv, rv);
 | |
|   }
 | |
| 
 | |
|   if (mIcon)
 | |
|     ::DestroyIcon(mIcon);
 | |
|   mIcon = hIcon;
 | |
|   mIconImage = icon;
 | |
|   return mVisible ? UpdateIcon() : NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| TaskbarTabPreview::GetIcon(imgIContainer **icon) {
 | |
|   NS_IF_ADDREF(*icon = mIconImage);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| TaskbarTabPreview::Move(nsITaskbarTabPreview *aNext) {
 | |
|   if (aNext == this)
 | |
|     return NS_ERROR_INVALID_ARG;
 | |
|   mNext = aNext;
 | |
|   return CanMakeTaskbarCalls() ? UpdateNext() : NS_OK;
 | |
| }
 | |
| 
 | |
| nsresult
 | |
| TaskbarTabPreview::UpdateTaskbarProperties() {
 | |
|   if (mRegistered)
 | |
|     return NS_OK;
 | |
| 
 | |
|   if (FAILED(mTaskbar->RegisterTab(mProxyWindow, mWnd)))
 | |
|     return NS_ERROR_FAILURE;
 | |
| 
 | |
|   nsresult rv = UpdateNext();
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
|   rv = TaskbarPreview::UpdateTaskbarProperties();
 | |
|   mRegistered = true;
 | |
|   return rv;
 | |
| }
 | |
| 
 | |
| LRESULT
 | |
| TaskbarTabPreview::WndProc(UINT nMsg, WPARAM wParam, LPARAM lParam) {
 | |
|   RefPtr<TaskbarTabPreview> kungFuDeathGrip(this);
 | |
|   switch (nMsg) {
 | |
|     case WM_CREATE:
 | |
|       TaskbarPreview::EnableCustomDrawing(mProxyWindow, true);
 | |
|       return 0;
 | |
|     case WM_CLOSE:
 | |
|       mController->OnClose();
 | |
|       return 0;
 | |
|     case WM_ACTIVATE:
 | |
|       if (LOWORD(wParam) == WA_ACTIVE) {
 | |
|         // Activate the tab the user selected then restore the main window,
 | |
|         // keeping normal/max window state intact.
 | |
|         bool activateWindow;
 | |
|         nsresult rv = mController->OnActivate(&activateWindow);
 | |
|         if (NS_SUCCEEDED(rv) && activateWindow) {
 | |
|           nsWindow* win = WinUtils::GetNSWindowPtr(mWnd);
 | |
|           if (win) {
 | |
|             nsWindow * parent = win->GetTopLevelWindow(true);
 | |
|             if (parent) {
 | |
|               parent->Show(true);
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|       return 0;
 | |
|     case WM_GETICON:
 | |
|       return (LRESULT)mIcon;
 | |
|     case WM_SYSCOMMAND:
 | |
|       // Send activation events to the top level window and select the proper
 | |
|       // tab through the controller.
 | |
|       if (wParam == SC_RESTORE || wParam == SC_MAXIMIZE) {
 | |
|         bool activateWindow;
 | |
|         nsresult rv = mController->OnActivate(&activateWindow);
 | |
|         if (NS_SUCCEEDED(rv) && activateWindow) {
 | |
|           // Note, restoring an iconic, maximized window here will only
 | |
|           // activate the maximized window. This is not a bug, it's default
 | |
|           // windows behavior.
 | |
|           ::SendMessageW(mWnd, WM_SYSCOMMAND, wParam, lParam);
 | |
|         }
 | |
|         return 0;
 | |
|       }
 | |
|       // Forward everything else to the top level window. Do not forward
 | |
|       // close since that's intended for the tab. When the preview proxy
 | |
|       // closes, we'll close the tab above.
 | |
|       return wParam == SC_CLOSE
 | |
|            ? ::DefWindowProcW(mProxyWindow, WM_SYSCOMMAND, wParam, lParam)
 | |
|            : ::SendMessageW(mWnd, WM_SYSCOMMAND, wParam, lParam);
 | |
|       return 0;
 | |
|   }
 | |
|   return TaskbarPreview::WndProc(nMsg, wParam, lParam);
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| LRESULT CALLBACK
 | |
| TaskbarTabPreview::GlobalWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam) {
 | |
|   TaskbarTabPreview *preview(nullptr);
 | |
|   if (nMsg == WM_CREATE) {
 | |
|     CREATESTRUCT *cs = reinterpret_cast<CREATESTRUCT*>(lParam);
 | |
|     preview = reinterpret_cast<TaskbarTabPreview*>(cs->lpCreateParams);
 | |
|     if (!::SetPropW(hWnd, TASKBARPREVIEW_HWNDID, preview))
 | |
|       NS_ERROR("Could not associate native window with tab preview");
 | |
|     preview->mProxyWindow = hWnd;
 | |
|   } else {
 | |
|     preview = reinterpret_cast<TaskbarTabPreview*>(::GetPropW(hWnd, TASKBARPREVIEW_HWNDID));
 | |
|     if (nMsg == WM_DESTROY)
 | |
|       ::RemovePropW(hWnd, TASKBARPREVIEW_HWNDID);
 | |
|   }
 | |
| 
 | |
|   if (preview)
 | |
|     return preview->WndProc(nMsg, wParam, lParam);
 | |
|   return ::DefWindowProcW(hWnd, nMsg, wParam, lParam);
 | |
| }
 | |
| 
 | |
| nsresult
 | |
| TaskbarTabPreview::Enable() {
 | |
|   WNDCLASSW wc;
 | |
|   HINSTANCE module = GetModuleHandle(nullptr);
 | |
| 
 | |
|   if (!GetClassInfoW(module, kWindowClass, &wc)) {
 | |
|     wc.style         = 0;
 | |
|     wc.lpfnWndProc   = GlobalWndProc;
 | |
|     wc.cbClsExtra    = 0;
 | |
|     wc.cbWndExtra    = 0;
 | |
|     wc.hInstance     = module;
 | |
|     wc.hIcon         = nullptr;
 | |
|     wc.hCursor       = nullptr;
 | |
|     wc.hbrBackground = (HBRUSH) nullptr;
 | |
|     wc.lpszMenuName  = (LPCWSTR) nullptr;
 | |
|     wc.lpszClassName = kWindowClass;
 | |
|     RegisterClassW(&wc);
 | |
|   }
 | |
|   ::CreateWindowW(kWindowClass, L"TaskbarPreviewWindow",
 | |
|                   WS_CAPTION | WS_SYSMENU, 0, 0, 200, 60,
 | |
|                   nullptr, nullptr, module, this);
 | |
|   // GlobalWndProc will set mProxyWindow so that WM_CREATE can have a valid HWND
 | |
|   if (!mProxyWindow)
 | |
|     return NS_ERROR_INVALID_ARG;
 | |
| 
 | |
|   UpdateProxyWindowStyle();
 | |
| 
 | |
|   nsresult rv = TaskbarPreview::Enable();
 | |
|   nsresult rvUpdate;
 | |
|   rvUpdate = UpdateTitle();
 | |
|   if (NS_FAILED(rvUpdate))
 | |
|     rv = rvUpdate;
 | |
| 
 | |
|   rvUpdate = UpdateIcon();
 | |
|   if (NS_FAILED(rvUpdate))
 | |
|     rv = rvUpdate;
 | |
| 
 | |
|   return rv;
 | |
| }
 | |
| 
 | |
| nsresult
 | |
| TaskbarTabPreview::Disable() {
 | |
|   // TaskbarPreview::Disable assumes that mWnd is valid but this method can be
 | |
|   // called when it is null iff the nsWindow has already been destroyed and we
 | |
|   // are still visible for some reason during object destruction.
 | |
|   if (mWnd)
 | |
|     TaskbarPreview::Disable();
 | |
| 
 | |
|   if (FAILED(mTaskbar->UnregisterTab(mProxyWindow)))
 | |
|     return NS_ERROR_FAILURE;
 | |
|   mRegistered = false;
 | |
| 
 | |
|   // TaskbarPreview::WndProc will set mProxyWindow to null
 | |
|   if (!DestroyWindow(mProxyWindow))
 | |
|     return NS_ERROR_FAILURE;
 | |
|   mProxyWindow = nullptr;
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| void
 | |
| TaskbarTabPreview::DetachFromNSWindow() {
 | |
|   (void) SetVisible(false);
 | |
|   WindowHook &hook = GetWindowHook();
 | |
|   hook.RemoveMonitor(WM_WINDOWPOSCHANGED, MainWindowHook, this);
 | |
| 
 | |
|   TaskbarPreview::DetachFromNSWindow();
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| bool
 | |
| TaskbarTabPreview::MainWindowHook(void *aContext,
 | |
|                                   HWND hWnd, UINT nMsg,
 | |
|                                   WPARAM wParam, LPARAM lParam,
 | |
|                                   LRESULT *aResult) {
 | |
|   if (nMsg == WM_WINDOWPOSCHANGED) {
 | |
|     TaskbarTabPreview *preview = reinterpret_cast<TaskbarTabPreview*>(aContext);
 | |
|     WINDOWPOS *pos = reinterpret_cast<WINDOWPOS*>(lParam);
 | |
|     if (SWP_FRAMECHANGED == (pos->flags & SWP_FRAMECHANGED))
 | |
|       preview->UpdateProxyWindowStyle();
 | |
|   } else {
 | |
|     MOZ_ASSERT_UNREACHABLE("Style changed hook fired on non-style changed "
 | |
|                            "message");
 | |
|   }
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| void
 | |
| TaskbarTabPreview::UpdateProxyWindowStyle() {
 | |
|   if (!mProxyWindow)
 | |
|     return;
 | |
| 
 | |
|   DWORD minMaxMask = WS_MINIMIZE | WS_MAXIMIZE;
 | |
|   DWORD windowStyle = GetWindowLongW(mWnd, GWL_STYLE);
 | |
| 
 | |
|   DWORD proxyStyle = GetWindowLongW(mProxyWindow, GWL_STYLE);
 | |
|   proxyStyle &= ~minMaxMask;
 | |
|   proxyStyle |= windowStyle & minMaxMask;
 | |
|   SetWindowLongW(mProxyWindow, GWL_STYLE, proxyStyle);
 | |
| 
 | |
|   DWORD exStyle = (WS_MAXIMIZE == (windowStyle & WS_MAXIMIZE)) ? WS_EX_TOOLWINDOW : 0;
 | |
|   SetWindowLongW(mProxyWindow, GWL_EXSTYLE, exStyle);
 | |
| }
 | |
| 
 | |
| nsresult
 | |
| TaskbarTabPreview::UpdateTitle() {
 | |
|   NS_ASSERTION(mVisible, "UpdateTitle called on invisible preview");
 | |
| 
 | |
|   if (!::SetWindowTextW(mProxyWindow, mTitle.get()))
 | |
|     return NS_ERROR_FAILURE;
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| nsresult
 | |
| TaskbarTabPreview::UpdateIcon() {
 | |
|   NS_ASSERTION(mVisible, "UpdateIcon called on invisible preview");
 | |
| 
 | |
|   ::SendMessageW(mProxyWindow, WM_SETICON, ICON_SMALL, (LPARAM)mIcon);
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| nsresult
 | |
| TaskbarTabPreview::UpdateNext() {
 | |
|   NS_ASSERTION(CanMakeTaskbarCalls() && mVisible, "UpdateNext called on invisible tab preview");
 | |
|   HWND hNext = nullptr;
 | |
|   if (mNext) {
 | |
|     bool visible;
 | |
|     nsresult rv = mNext->GetVisible(&visible);
 | |
| 
 | |
|     NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|     // Can only move next to enabled previews
 | |
|     if (!visible)
 | |
|       return NS_ERROR_FAILURE;
 | |
| 
 | |
|     hNext = (HWND)mNext->GetHWND();
 | |
| 
 | |
|     // hNext must be registered with the taskbar if the call is to succeed
 | |
|     mNext->EnsureRegistration();
 | |
|   }
 | |
|   if (FAILED(mTaskbar->SetTabOrder(mProxyWindow, hNext)))
 | |
|     return NS_ERROR_FAILURE;
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| 
 | |
| } // namespace widget
 | |
| } // namespace mozilla
 |